11# effql
22
33[ ![ CI] ( https://github.com/gloomweaver/effql/actions/workflows/ci.yml/badge.svg )] ( https://github.com/gloomweaver/effql/actions/workflows/ci.yml )
4+ [ ![ npm: @effql/cli ] ( https://img.shields.io/npm/v/%40effql%2Fcli?label=%40effql%2Fcli )] ( https://www.npmjs.com/package/@effql/cli )
5+ [ ![ npm: @effql/core ] ( https://img.shields.io/npm/v/%40effql%2Fcore?label=%40effql%2Fcore )] ( https://www.npmjs.com/package/@effql/core )
46
57` effql ` is a ` sqlc ` -style TypeScript code generator for ` effect ` / ` @effect/sql ` .
68
79It keeps a SQL-first workflow, uses Postgres introspection to infer types, and emits Effect-native code built around ` Schema ` and ` SqlSchema.* ` .
810
9- ## Why effql
11+ ## Packages
1012
11- - write raw SQL in ` .sql ` files
12- - keep familiar query annotations like ` -- name: GetUser :one `
13- - use TypeScript / JavaScript config via ` defineConfig() ` instead of YAML
14- - infer result shapes from a real Postgres database
15- - generate executable Effect wrappers instead of plain DTOs
13+ - [ ` @effql/cli ` ] ( https://www.npmjs.com/package/@effql/cli ) — CLI package providing the ` effql ` command
14+ - [ ` @effql/core ` ] ( https://www.npmjs.com/package/@effql/core ) — config loading, SQL parsing, Postgres analysis, and code generation
1615
17- ## Status
16+ ## Installation
1817
19- This is an early ** Postgres-only MVP** .
18+ ``` bash
19+ npm install -D @effql/cli @effql/core
20+ ```
2021
21- What works today:
22+ ``` bash
23+ pnpm add -D @effql/cli @effql/core
24+ ```
2225
23- - TS / JS config via ` defineConfig() `
24- - query annotations: ` :one ` , ` :maybeOne ` , ` :many ` , ` :exec `
25- - named params via ` @param `
26- - Postgres-backed type inference
27- - generated ` Schema ` exports and ` SqlSchema.single/findOne/findAll/void ` wrappers
28- - self-contained CRUD example with Docker Compose and an Effect HTTP API
26+ ## CLI usage
27+
28+ Bootstrap a project:
29+
30+ ``` bash
31+ npx @effql/cli init
32+ npx @effql/cli init --config ./effql.config.ts
33+ ```
34+
35+ This creates:
36+
37+ - ` effql.config.ts `
38+ - ` sql/queries.sql `
39+ - ` package.json ` if one does not already exist
40+
41+ Installed locally:
42+
43+ ``` bash
44+ npx effql init
45+ npx effql generate
46+ npx effql generate --config ./effql.config.ts
47+ ```
48+
49+ One-off without installing:
50+
51+ ``` bash
52+ npx @effql/cli generate
53+ npx @effql/cli generate --config ./effql.config.ts
54+ ```
55+
56+ Also works with pnpm:
57+
58+ ``` bash
59+ pnpm dlx @effql/cli generate
60+ ```
61+
62+ Yes — ` npx ` works because ` @effql/cli ` publishes the ` effql ` bin.
2963
3064## Quick start
3165
@@ -48,19 +82,6 @@ Or run the full smoke test used by CI:
4882pnpm run example:smoke
4983```
5084
51- ## Workspace
52-
53- - ` packages/core ` — config loading, SQL parsing, Postgres analysis, code generation
54- - ` packages/cli ` — ` effql generate `
55- - ` examples/basic ` — self-contained Postgres + generated CRUD module + Effect HTTP API
56-
57- ## CLI
58-
59- ``` bash
60- effql --help
61- effql generate --config ./effql.config.ts
62- ```
63-
6485## Config
6586
6687` effql ` uses code-based config:
@@ -99,15 +120,12 @@ RETURNING id, email, created_at;
99120SELECT id, email, created_at
100121FROM users
101122WHERE id = @id::uuid;
102-
103- -- name: ListUsers :many
104- SELECT id, email, created_at
105- FROM users
106- ORDER BY created_at DESC ;
107123```
108124
109125## Generated output shape
110126
127+ Starter ` sql/queries.sql ` contains a simple ` Healthcheck ` query you can edit right away.
128+
111129Generated modules export:
112130
113131- ` *ParamsSchema `
@@ -116,8 +134,6 @@ Generated modules export:
116134- raw ` *Sql ` strings
117135- executable ` SqlSchema.* ` wrappers
118136
119- Example:
120-
121137``` ts
122138export const CreateUserResultSchema = Schema .Struct ({
123139 id: Schema .UUID ,
@@ -135,58 +151,28 @@ export const createUser = SqlSchema.single({
135151});
136152```
137153
138- ## Direct usage example
139-
140- You can call generated functions by providing a SQL client layer:
141-
142- ``` ts
143- import { PgClient } from " @effect/sql-pg" ;
144- import { Effect , Redacted } from " effect" ;
145- import { createUser , listUsers } from " ./generated/index.ts" ;
146-
147- const program = Effect .gen (function * () {
148- const created = yield * createUser ({
149- id: " 33333333-3333-3333-3333-333333333333" ,
150- email: " grace@example.com" ,
151- });
152-
153- const users = yield * listUsers ({});
154-
155- return { created , users };
156- });
157-
158- const runnable = program .pipe (
159- Effect .provide (
160- PgClient .layer ({
161- url: Redacted .make (" postgres://postgres:postgres@127.0.0.1:54329/postgres" ),
162- }),
163- ),
164- );
165- ```
166-
167- ## Effect HTTP API example
168-
169- ` examples/basic/src/httpApi.ts ` wires generated CRUD queries into an Effect ` HttpApi ` .
154+ ## Example project
170155
171- Routes :
156+ See ` examples/basic ` for the easiest end-to-end demo :
172157
173- - ` POST /users `
174- - ` GET / users`
175- - ` GET /users/:id `
176- - ` PUT /users/:id `
177- - ` DELETE /users/:id `
158+ - ` compose.yaml ` starts Postgres on ` 127.0.0.1:54329 `
159+ - ` schema.sql ` creates and seeds ` users `
160+ - ` sql/queries.sql ` defines CRUD queries
161+ - ` generated/index.ts ` is committed generated output
162+ - ` src/httpApi.ts ` and ` src/server.ts ` show runtime usage
178163
179- Try it:
164+ ## Status
180165
181- ``` bash
182- curl http://127.0.0.1:3000/users
166+ This is an early ** Postgres-only MVP** .
183167
184- curl http://127.0.0.1:3000/users/11111111-1111-1111-1111-111111111111
168+ What works today:
185169
186- curl -X POST http://127.0.0.1:3000/users \
187- -H ' content-type: application/json' \
188- -d ' {"email":"grace@example.com"}'
189- ```
170+ - TS / JS config via ` defineConfig() `
171+ - query annotations: ` :one ` , ` :maybeOne ` , ` :many ` , ` :exec `
172+ - named params via ` @param `
173+ - Postgres-backed type inference
174+ - generated ` Schema ` exports and ` SqlSchema.single/findOne/findAll/void ` wrappers
175+ - self-contained CRUD example with Docker Compose and an Effect HTTP API
190176
191177## Known limitations
192178
@@ -199,26 +185,15 @@ Current MVP limitations:
199185- output is currently a single generated module per target
200186- API / config shape may still evolve before a stable release
201187
202- ## Validation and CI
203-
204- Current checks cover:
205-
206- - formatting and linting
207- - workspace typechecking
208- - unit tests
209- - Postgres integration tests
210- - example generation smoke test in GitHub Actions
211- - example API smoke test via ` pnpm run example:smoke `
212-
213188## Publishing
214189
215190A GitHub Actions release workflow publishes the npm packages when a GitHub release is marked as ` published ` .
216191
217192Before using it:
218193
219- - add an ` NPM_TOKEN ` repository secret
194+ - add an ` NPM_TOKEN ` repository secret if you keep token-based publishing
220195- make sure you own/publish to both ` @effql/cli ` and ` @effql/core ` on npm
221- - create releases with tags that match the package versions, for example ` v0.1.0 `
196+ - create releases with tags that match the package versions, for example ` v0.1.1 `
222197
223198The release workflow:
224199
@@ -228,23 +203,13 @@ The release workflow:
228203- publishes ` @effql/core `
229204- publishes ` @effql/cli `
230205
231- ## Example project
232-
233- See ` examples/basic ` for the easiest end-to-end demo:
234-
235- - ` compose.yaml ` starts Postgres on ` 127.0.0.1:54329 `
236- - ` schema.sql ` creates and seeds ` users `
237- - ` sql/queries.sql ` defines CRUD queries
238- - ` generated/index.ts ` is committed generated output
239- - ` src/httpApi.ts ` and ` src/server.ts ` show runtime usage
240-
241- ## Development commands
206+ ## Development
242207
243208``` bash
244209vp install
245210vp lint
246- vp run -r check
247- vp run -r test
211+ vp fmt
212+ vp test
248213vp run -r build
249214pnpm run example:smoke
250215```
0 commit comments