sqlcx-orm 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +207 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# sqlcx
|
|
2
|
+
|
|
3
|
+
SQL-first, cross-language, type-safe code generator. Write SQL, get typed code.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun add sqlcx-orm
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
You write SQL schemas and annotated queries. sqlcx generates type-safe TypeScript with [TypeBox](https://github.com/sinclairzx81/typebox) validation schemas and typed query functions.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
sql/schema.sql --> src/db/schema.ts (TypeBox schemas + types)
|
|
15
|
+
sql/queries/users.sql --> src/db/users.queries.ts (typed query functions)
|
|
16
|
+
src/db/client.ts (DatabaseClient interface)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
No runtime. No engine. Just codegen.
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Initialize a project
|
|
25
|
+
bunx sqlcx-orm init
|
|
26
|
+
|
|
27
|
+
# Write your SQL, then generate
|
|
28
|
+
bunx sqlcx-orm generate
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 1. Define your schema
|
|
32
|
+
|
|
33
|
+
```sql
|
|
34
|
+
-- sql/schema.sql
|
|
35
|
+
CREATE TABLE users (
|
|
36
|
+
id SERIAL PRIMARY KEY,
|
|
37
|
+
name TEXT NOT NULL,
|
|
38
|
+
email TEXT NOT NULL UNIQUE,
|
|
39
|
+
-- @json({ theme: string, notifications: boolean })
|
|
40
|
+
preferences JSONB,
|
|
41
|
+
-- @enum("admin", "editor", "viewer")
|
|
42
|
+
role TEXT NOT NULL DEFAULT 'viewer',
|
|
43
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
44
|
+
);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Write annotated queries
|
|
48
|
+
|
|
49
|
+
```sql
|
|
50
|
+
-- sql/queries/users.sql
|
|
51
|
+
|
|
52
|
+
-- name: GetUser :one
|
|
53
|
+
SELECT * FROM users WHERE id = $1;
|
|
54
|
+
|
|
55
|
+
-- name: ListUsers :many
|
|
56
|
+
SELECT id, name, email, role FROM users ORDER BY created_at DESC;
|
|
57
|
+
|
|
58
|
+
-- name: CreateUser :one
|
|
59
|
+
INSERT INTO users (name, email, role) VALUES ($1, $2, $3) RETURNING *;
|
|
60
|
+
|
|
61
|
+
-- name: DeleteUser :execresult
|
|
62
|
+
DELETE FROM users WHERE id = $1;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3. Generate
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
bunx sqlcx-orm generate --sql ./sql --out ./src/db
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 4. Use
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { BunSqlClient } from "./src/db/client";
|
|
75
|
+
import { getUser, createUser } from "./src/db/users.queries";
|
|
76
|
+
|
|
77
|
+
const client = new BunSqlClient(Bun.sql);
|
|
78
|
+
|
|
79
|
+
const user = await getUser(client, { id: 1 });
|
|
80
|
+
// user: { id: number, name: string, email: string, ... } | null
|
|
81
|
+
|
|
82
|
+
await createUser(client, { name: "Alice", email: "alice@example.com", role: "admin" });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Features
|
|
86
|
+
|
|
87
|
+
### Inline `@enum` annotations
|
|
88
|
+
|
|
89
|
+
No separate enum objects. Define values right where the column is:
|
|
90
|
+
|
|
91
|
+
```sql
|
|
92
|
+
-- @enum("draft", "published", "archived")
|
|
93
|
+
status TEXT NOT NULL DEFAULT 'draft'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Generates `Type.Union([Type.Literal("draft"), Type.Literal("published"), Type.Literal("archived")])` — not a plain `string`.
|
|
97
|
+
|
|
98
|
+
### Inline `@json` annotations
|
|
99
|
+
|
|
100
|
+
No more `unknown` for JSON columns:
|
|
101
|
+
|
|
102
|
+
```sql
|
|
103
|
+
-- @json({ theme: string, notifications: boolean, font_size: number })
|
|
104
|
+
preferences JSONB
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Generates a fully typed TypeBox object schema. Supports nested objects, arrays (`string[]`), and nullable (`string?`).
|
|
108
|
+
|
|
109
|
+
### Partial column selection
|
|
110
|
+
|
|
111
|
+
Only select the columns you need — the generated type matches exactly what you query:
|
|
112
|
+
|
|
113
|
+
```sql
|
|
114
|
+
-- name: ListUsers :many
|
|
115
|
+
SELECT id, name, email FROM users ORDER BY created_at DESC;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Generates a `ListUsersRow` with only `{ id: number; name: string; email: string }` — not the full table type. No over-fetching in your types.
|
|
119
|
+
|
|
120
|
+
### `RETURNING` clause support
|
|
121
|
+
|
|
122
|
+
```sql
|
|
123
|
+
-- name: CreateUser :one
|
|
124
|
+
INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Return types are inferred from the table schema — works with `RETURNING *` and explicit column lists.
|
|
128
|
+
|
|
129
|
+
### `@param` overrides
|
|
130
|
+
|
|
131
|
+
For ambiguous parameter names:
|
|
132
|
+
|
|
133
|
+
```sql
|
|
134
|
+
-- name: ListByDateRange :many
|
|
135
|
+
-- @param $1 start_date
|
|
136
|
+
-- @param $2 end_date
|
|
137
|
+
SELECT * FROM posts WHERE published_at > $1 AND published_at < $2;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Query commands
|
|
141
|
+
|
|
142
|
+
| Annotation | Returns | Use for |
|
|
143
|
+
|-----------|---------|---------|
|
|
144
|
+
| `:one` | `T \| null` | Single row lookups |
|
|
145
|
+
| `:many` | `T[]` | List queries |
|
|
146
|
+
| `:exec` | `void` | INSERT/UPDATE/DELETE |
|
|
147
|
+
| `:execresult` | `{ rowsAffected: number }` | DELETE/UPDATE with count |
|
|
148
|
+
|
|
149
|
+
### Input/Output type separation
|
|
150
|
+
|
|
151
|
+
Generated schemas separate Select (all columns) from Insert (defaults are optional):
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
// All columns present
|
|
155
|
+
export type SelectUsers = { id: number; name: string; created_at: Date; ... }
|
|
156
|
+
|
|
157
|
+
// Columns with defaults (id, created_at) are Optional
|
|
158
|
+
export type InsertUsers = { name: string; email: string; id?: number; created_at?: Date; ... }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## CLI
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
sqlcx-orm generate [options] # Parse SQL and generate typed code
|
|
165
|
+
sqlcx-orm check [options] # Validate SQL without generating (CI-friendly)
|
|
166
|
+
sqlcx-orm init # Scaffold sql/ directory with examples
|
|
167
|
+
|
|
168
|
+
Options:
|
|
169
|
+
--sql <dir> SQL directory (default: ./sql)
|
|
170
|
+
--out <dir> Output directory (default: ./src/db)
|
|
171
|
+
--cache <dir> Cache directory (default: .sqlcx)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## How it works
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
SQL files --> [PostgreSQL Parser] --> IR (Intermediate Representation)
|
|
178
|
+
|
|
|
179
|
+
+--> [TypeBox Schema Generator] --> schema.ts
|
|
180
|
+
+--> [Bun.sql Driver Generator] --> queries.ts + client.ts
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The IR is language-agnostic and cacheable. Adding new language targets (Python, Go) or schema generators (Zod, Valibot) means implementing a plugin against the IR — the SQL parsing is done once.
|
|
184
|
+
|
|
185
|
+
## Plugin Architecture
|
|
186
|
+
|
|
187
|
+
sqlcx is built on four plugin axes:
|
|
188
|
+
|
|
189
|
+
- **Database Parser** — PostgreSQL (shipped), MySQL/SQLite (planned)
|
|
190
|
+
- **Schema Generator** — TypeBox v1.0 (shipped), Zod/Valibot (planned)
|
|
191
|
+
- **Driver Generator** — Bun.sql (shipped), pg/mysql2 (planned)
|
|
192
|
+
- **Language Plugin** — TypeScript (shipped), Python/Go (planned)
|
|
193
|
+
|
|
194
|
+
## Why sqlcx?
|
|
195
|
+
|
|
196
|
+
| Pain point | Prisma | Drizzle | sqlcx |
|
|
197
|
+
|-----------|--------|---------|-------|
|
|
198
|
+
| JSON columns typed | No (`JsonValue`) | No (`unknown`) | Yes (`@json` annotations) |
|
|
199
|
+
| Inline enums | No (separate block) | No (separate object) | Yes (`@enum` annotations) |
|
|
200
|
+
| Bundle size | ~1.6MB | ~7.4KB | **0 KB** (no runtime) |
|
|
201
|
+
| Multi-language | Dropped Python | TypeScript only | Designed for any language |
|
|
202
|
+
| IDE lag on large schemas | Yes (huge .d.ts) | Yes (deep inference) | No (flat interfaces) |
|
|
203
|
+
| Generated type bloat | Thousands of lines | Complex generics | Simple flat types |
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT
|