sqlite-zod-orm 3.19.0 → 3.20.0
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 +203 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
# sqlite-zod-orm
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://www.npmjs.com/package/sqlite-zod-orm)
|
|
6
|
-
[](./LICENSE)
|
|
7
|
-
|
|
8
|
-
## Install
|
|
3
|
+
Type-safe SQLite ORM for Bun — Zod schemas, fluent queries, auto relationships, zero SQL.
|
|
9
4
|
|
|
10
5
|
```bash
|
|
11
6
|
bun add sqlite-zod-orm
|
|
12
7
|
```
|
|
13
8
|
|
|
14
|
-
> **Requires Bun runtime** — uses `bun:sqlite` under the hood.
|
|
15
|
-
|
|
16
9
|
## Quick Start
|
|
17
10
|
|
|
18
11
|
```typescript
|
|
@@ -22,58 +15,224 @@ const db = new Database('app.db', {
|
|
|
22
15
|
users: z.object({
|
|
23
16
|
name: z.string(),
|
|
24
17
|
email: z.string(),
|
|
25
|
-
|
|
18
|
+
score: z.number().default(0),
|
|
26
19
|
}),
|
|
20
|
+
posts: z.object({
|
|
21
|
+
title: z.string(),
|
|
22
|
+
body: z.string(),
|
|
23
|
+
userId: z.number(),
|
|
24
|
+
}),
|
|
25
|
+
}, {
|
|
26
|
+
relations: { posts: { userId: 'users' } },
|
|
27
|
+
timestamps: true,
|
|
28
|
+
softDeletes: true,
|
|
27
29
|
});
|
|
30
|
+
```
|
|
28
31
|
|
|
32
|
+
Tables are auto-created and auto-migrated from your Zod schemas. No SQL required.
|
|
33
|
+
|
|
34
|
+
## CRUD
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
29
37
|
// Insert
|
|
30
|
-
const
|
|
31
|
-
alice.id; // auto-increment ID
|
|
32
|
-
alice.role; // 'member' (from Zod default)
|
|
33
|
-
|
|
34
|
-
// Query
|
|
35
|
-
const admins = db.users.select()
|
|
36
|
-
.where({ role: 'admin' })
|
|
37
|
-
.orderBy('name')
|
|
38
|
-
.all();
|
|
38
|
+
const user = db.users.insert({ name: 'Alice', email: 'alice@co.com' });
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
|
|
40
|
+
// Read
|
|
41
|
+
const all = db.users.select().all();
|
|
42
|
+
const one = db.users.get(1);
|
|
43
|
+
const found = db.users.select().where({ name: 'Alice' }).first();
|
|
44
|
+
|
|
45
|
+
// Update (auto-persists via proxy)
|
|
46
|
+
user.score = 100; // ← saved to DB automatically
|
|
42
47
|
|
|
43
48
|
// Delete
|
|
44
|
-
db.users.delete(
|
|
49
|
+
db.users.delete(1);
|
|
50
|
+
|
|
51
|
+
// Batch
|
|
52
|
+
db.users.insertMany([{ name: 'Bob', email: 'b@co.com' }, { name: 'Charlie', email: 'c@co.com' }]);
|
|
53
|
+
db.users.upsertMany([{ id: 1, name: 'Updated Alice' }], 'id');
|
|
45
54
|
```
|
|
46
55
|
|
|
47
|
-
##
|
|
56
|
+
## Fluent Query Builder
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- **Relationships** — foreign keys, lazy navigation, fluent joins
|
|
56
|
-
- **Reactivity** — `.on('insert' | 'update' | 'delete', callback)` with trigger-based change tracking
|
|
57
|
-
- **Transactions** — `db.transaction(() => { ... })`
|
|
58
|
-
- **Timestamps** — auto `createdAt`/`updatedAt` with `{ timestamps: true }`
|
|
59
|
-
- **Soft deletes** — `{ softDeletes: true }` with `.withTrashed()`, `.onlyTrashed()`, `.restore()`
|
|
60
|
-
- **Unique constraints** — `{ unique: { users: [['email']] } }`
|
|
61
|
-
- **Schema introspection** — `db.tables()`, `db.columns('users')`
|
|
62
|
-
- **Raw SQL** — `db.raw()` / `db.exec()` escape hatch
|
|
63
|
-
- **Debug mode** — `{ debug: true }` logs all SQL to console
|
|
64
|
-
- **Distinct** — `.distinct()` on queries
|
|
65
|
-
- **Proxy queries** — SQL-like DSL with type-safe column references
|
|
58
|
+
```typescript
|
|
59
|
+
db.users.select()
|
|
60
|
+
.where({ score: { $gte: 50 } })
|
|
61
|
+
.orderBy('score', 'DESC')
|
|
62
|
+
.limit(10)
|
|
63
|
+
.all();
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
// Operators: $gt, $gte, $lt, $lte, $ne, $like, $in, $notIn, $between
|
|
66
|
+
db.users.select().where({ name: { $like: '%ali%' } }).all();
|
|
68
67
|
|
|
69
|
-
|
|
68
|
+
// whereIn / whereNotIn (array or subquery)
|
|
69
|
+
db.users.select().whereIn('id', [1, 2, 3]).all();
|
|
70
|
+
const sub = db.orders.select('userId');
|
|
71
|
+
db.users.select().whereIn('id', sub).all();
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
// Raw WHERE fragments
|
|
74
|
+
db.users.select().whereRaw('score > ? AND name != ?', [50, 'Bot']).all();
|
|
75
|
+
```
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
## Relationships
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// Navigation (lazy, proxy-based)
|
|
81
|
+
const post = db.posts.get(1);
|
|
82
|
+
post.user; // → related user object
|
|
83
|
+
const user = db.users.get(1);
|
|
84
|
+
user.posts; // → array of user's posts
|
|
85
|
+
|
|
86
|
+
// Eager loading (no N+1)
|
|
87
|
+
db.posts.select().with('user').all();
|
|
75
88
|
```
|
|
76
89
|
|
|
90
|
+
## Aggregates
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
db.users.count(); // shorthand
|
|
94
|
+
db.users.select().where({ role: 'admin' }).count(); // filtered
|
|
95
|
+
db.users.select().sum('score');
|
|
96
|
+
db.users.select().avg('score');
|
|
97
|
+
db.users.select().min('score');
|
|
98
|
+
db.users.select().max('score');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Batch Mutations
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
db.users.select().where({ role: 'guest' }).updateAll({ role: 'member' }); // → affected count
|
|
105
|
+
db.users.select().where({ role: 'spam' }).deleteAll(); // → deleted count
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Pagination
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const page = db.users.select().orderBy('name').paginate(1, 20);
|
|
112
|
+
// { data: [...], total: 42, page: 1, perPage: 20, pages: 3 }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Select Type Narrowing
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const names = db.users.select('name', 'email').all();
|
|
119
|
+
names[0].name; // ✅ string
|
|
120
|
+
names[0].score; // ❌ TypeScript error — not selected
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Computed Getters
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const db = new Database(':memory:', { users: UserSchema }, {
|
|
127
|
+
computed: {
|
|
128
|
+
users: { fullName: (u) => `${u.first} ${u.last}` },
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
user.fullName; // 'Alice Smith' — recomputes on access
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Cascade Deletes
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const db = new Database(':memory:', { authors: AuthorSchema, books: BookSchema }, {
|
|
138
|
+
relations: { books: { author_id: 'authors' } },
|
|
139
|
+
cascade: { authors: ['books'] },
|
|
140
|
+
});
|
|
141
|
+
db.authors.delete(1); // → books with author_id=1 also deleted
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Transactions
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
db.transaction(() => {
|
|
148
|
+
db.users.insert({ name: 'Alice' });
|
|
149
|
+
db.orders.insert({ userId: 1, amount: 100 });
|
|
150
|
+
}); // auto-commits; rolls back on error
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Data Import / Export
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
const backup = db.dump(); // export all tables as JSON
|
|
157
|
+
db.load(backup); // restore (truncates first)
|
|
158
|
+
db.load(backup, { append: true }); // restore without truncating
|
|
159
|
+
db.seed({ users: [{ name: 'Test User' }] }); // additive fixture seeding
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Schema Diffing
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const diff = db.diff();
|
|
166
|
+
// { users: { added: ['bio'], removed: ['legacy'], typeChanged: [] } }
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Lifecycle Hooks
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
const db = new Database(':memory:', { users: UserSchema }, {
|
|
173
|
+
hooks: {
|
|
174
|
+
users: {
|
|
175
|
+
beforeInsert: (data) => ({ ...data, name: data.name.trim() }),
|
|
176
|
+
afterInsert: (entity) => console.log('Created:', entity.id),
|
|
177
|
+
beforeUpdate: (id, data) => data,
|
|
178
|
+
afterUpdate: (entity) => {},
|
|
179
|
+
beforeDelete: (id) => true, // return false to cancel
|
|
180
|
+
afterDelete: (id) => {},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Soft Deletes & Timestamps
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// With softDeletes: true
|
|
190
|
+
db.users.delete(1); // sets deletedAt
|
|
191
|
+
db.users.select().all(); // excludes deleted
|
|
192
|
+
db.users.select().withTrashed().all(); // includes deleted
|
|
193
|
+
db.users.select().onlyTrashed().all(); // only deleted
|
|
194
|
+
db.users.restore(1); // un-deletes
|
|
195
|
+
|
|
196
|
+
// With timestamps: true
|
|
197
|
+
user.createdAt; // auto-set on insert
|
|
198
|
+
user.updatedAt; // auto-bumped on update
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Raw SQL
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
db.raw<User>('SELECT * FROM users WHERE score > ?', 50);
|
|
205
|
+
db.exec('UPDATE users SET score = 0 WHERE role = ?', 'guest');
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Full Feature List
|
|
209
|
+
|
|
210
|
+
- Zod-powered schema definition & runtime validation
|
|
211
|
+
- Auto table creation & migration (add columns)
|
|
212
|
+
- Fluent query builder with 10+ operators
|
|
213
|
+
- Type-safe select narrowing
|
|
214
|
+
- Relationship navigation (lazy proxy + eager loading)
|
|
215
|
+
- Soft deletes, timestamps, auto-persist proxy
|
|
216
|
+
- Lifecycle hooks (before/after insert/update/delete)
|
|
217
|
+
- Aggregates (sum, avg, min, max, count, countGrouped)
|
|
218
|
+
- Batch mutations (insertMany, upsertMany, updateAll, deleteAll, findOrCreate)
|
|
219
|
+
- Cascade deletes
|
|
220
|
+
- Computed/virtual getters
|
|
221
|
+
- Data import/export (dump, load, seed)
|
|
222
|
+
- Schema diffing
|
|
223
|
+
- Transactions
|
|
224
|
+
- Pagination
|
|
225
|
+
- whereIn/whereNotIn with subquery support
|
|
226
|
+
- JSON column auto-serialization
|
|
227
|
+
- Unique constraints
|
|
228
|
+
- Debug mode (SQL logging)
|
|
229
|
+
- Raw SQL escape hatch
|
|
230
|
+
|
|
231
|
+
## Requirements
|
|
232
|
+
|
|
233
|
+
- **Bun** ≥ 1.0 (uses `bun:sqlite` native bindings)
|
|
234
|
+
- **Zod** ≥ 3.0
|
|
235
|
+
|
|
77
236
|
## License
|
|
78
237
|
|
|
79
238
|
MIT
|