@xwxfox/foxdb 0.0.1 → 0.1.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/LICENSE.md +20 -20
- package/README.md +275 -274
- package/dist/index.d.mts +810 -137
- package/dist/index.mjs +23 -19
- package/package.json +3 -2
package/LICENSE.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 xwxfox
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xwxfox
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,274 +1,275 @@
|
|
|
1
|
-
# foxdb ~ a typed sqlite orm for bun :3
|
|
2
|
-
|
|
3
|
-
> built on top of [typebox](https://github.com/sinclairzx81/typebox) schemas and `bun:sqlite`. fast, tiny, fully typed :3
|
|
4
|
-
|
|
5
|
-
foxdb gives you a repository-style orm where your database schema *is* your typescript types. no codegen, no decorators, no magic. just plain typebox objects that compile to sqlite tables and give you autocomplete everywhere ~
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
> Credit to [@deadlinecode](https://github.com/deadlinecode) for the original idea and base :3
|
|
9
|
-
|
|
10
|
-
## quick start
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
bun add @xwxfox/foxdb
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
import { Object, String, Number, Integer } from "typebox";
|
|
18
|
-
import { createORM, table } from "@xwxfox/foxdb";
|
|
19
|
-
|
|
20
|
-
const UserSchema = Object({
|
|
21
|
-
id: String(),
|
|
22
|
-
name: String(),
|
|
23
|
-
email: String(),
|
|
24
|
-
age: Integer(),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const orm = createORM({
|
|
28
|
-
tables: {
|
|
29
|
-
users: table(UserSchema, (s) => ({
|
|
30
|
-
primaryKey: s.id,
|
|
31
|
-
indexes: [{ columns: [s.email] }],
|
|
32
|
-
})),
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// insert
|
|
37
|
-
const user = orm.users.insert({
|
|
38
|
-
id: "usr-1",
|
|
39
|
-
name: "alice",
|
|
40
|
-
email: "alice@example.com",
|
|
41
|
-
age: 30,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// find
|
|
45
|
-
const found = orm.users.findById("usr-1");
|
|
46
|
-
|
|
47
|
-
// update
|
|
48
|
-
orm.users.update({ id: "usr-1", name: "alice smith" });
|
|
49
|
-
|
|
50
|
-
// query
|
|
51
|
-
const adults = orm.users.findMany({
|
|
52
|
-
where: { age: { gte: 18 } },
|
|
53
|
-
orderBy: { column: "name", direction: "ASC" },
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// paginate
|
|
57
|
-
const page = orm.users.findPage({
|
|
58
|
-
where: { age: { gte: 18 } },
|
|
59
|
-
limit: 10,
|
|
60
|
-
offset: 0,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
orm._close();
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## why foxdb
|
|
67
|
-
|
|
68
|
-
- **zero codegen** - your typebox schema *is* the source of truth. no `prisma generate`, no migration files to keep in sync :3
|
|
69
|
-
- **fully typed** - every query, insert, update, and relation is typed end-to-end. try passing the wrong column name and typescript will bonk you
|
|
70
|
-
- **tiny** - ~2kb overhead on top of `bun:sqlite`. no external query builder, no connection pool, no bloat
|
|
71
|
-
- **relations** - scalar relations (lazy) and sub-table relations (batch resolved) with a fluent builder
|
|
72
|
-
- **events** - listen to table events (`insert`, `update`, `read`, `write`, etc.) typed to your schema. zero overhead unless you subscribe ~
|
|
73
|
-
- **lifecycle hooks** - `onStart`, `onReady`, `onShutdown`, `onExit` for seeding, migrating, cleaning up
|
|
74
|
-
- **sub-tables** - arrays of objects are automatically split into separate sqlite tables with proper indexing
|
|
75
|
-
|
|
76
|
-
## core concepts
|
|
77
|
-
|
|
78
|
-
### schemas
|
|
79
|
-
|
|
80
|
-
use [typebox](https://github.com/sinclairzx81/typebox) to define your data shape. foxdb supports all scalar types (`String`, `Number`, `Integer`, `Boolean`, `Literal`) plus arrays of objects (sub-tables).
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
import { Object, String, Number, Integer, Array, Optional } from "typebox";
|
|
84
|
-
|
|
85
|
-
const LineItemSchema = Object({
|
|
86
|
-
sku: String(),
|
|
87
|
-
qty: Integer(),
|
|
88
|
-
price: Number(),
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
const OrderSchema = Object({
|
|
92
|
-
id: String(),
|
|
93
|
-
customerId: String(),
|
|
94
|
-
status: String(),
|
|
95
|
-
total: Number(),
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
{ columns: [s.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- `
|
|
121
|
-
- `
|
|
122
|
-
- `
|
|
123
|
-
- `
|
|
124
|
-
- `
|
|
125
|
-
- `
|
|
126
|
-
- `
|
|
127
|
-
- `
|
|
128
|
-
- `
|
|
129
|
-
- `
|
|
130
|
-
- `
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
console.log(e.
|
|
240
|
-
console.log(e.
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
1
|
+
# foxdb ~ a typed sqlite orm for bun :3
|
|
2
|
+
|
|
3
|
+
> built on top of [typebox](https://github.com/sinclairzx81/typebox) schemas and `bun:sqlite`. fast, tiny, fully typed :3
|
|
4
|
+
|
|
5
|
+
foxdb gives you a repository-style orm where your database schema *is* your typescript types. no codegen, no decorators, no magic. just plain typebox objects that compile to sqlite tables and give you autocomplete everywhere ~
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
> Credit to [@deadlinecode](https://github.com/deadlinecode) for the original idea and base :3
|
|
9
|
+
|
|
10
|
+
## quick start
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
bun add @xwxfox/foxdb
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Object, String, Number, Integer } from "typebox";
|
|
18
|
+
import { createORM, table } from "@xwxfox/foxdb";
|
|
19
|
+
|
|
20
|
+
const UserSchema = Object({
|
|
21
|
+
id: String(),
|
|
22
|
+
name: String(),
|
|
23
|
+
email: String(),
|
|
24
|
+
age: Integer(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const orm = createORM({
|
|
28
|
+
tables: {
|
|
29
|
+
users: table(UserSchema, (s) => ({
|
|
30
|
+
primaryKey: s.id,
|
|
31
|
+
indexes: [{ columns: [s.email] }],
|
|
32
|
+
})),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// insert
|
|
37
|
+
const user = orm.users.insert({
|
|
38
|
+
id: "usr-1",
|
|
39
|
+
name: "alice",
|
|
40
|
+
email: "alice@example.com",
|
|
41
|
+
age: 30,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// find
|
|
45
|
+
const found = orm.users.findById("usr-1");
|
|
46
|
+
|
|
47
|
+
// update
|
|
48
|
+
orm.users.update({ id: "usr-1", name: "alice smith" });
|
|
49
|
+
|
|
50
|
+
// query
|
|
51
|
+
const adults = orm.users.findMany({
|
|
52
|
+
where: { age: { gte: 18 } },
|
|
53
|
+
orderBy: { column: "name", direction: "ASC" },
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// paginate
|
|
57
|
+
const page = orm.users.findPage({
|
|
58
|
+
where: { age: { gte: 18 } },
|
|
59
|
+
limit: 10,
|
|
60
|
+
offset: 0,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
orm._close();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## why foxdb
|
|
67
|
+
|
|
68
|
+
- **zero codegen** - your typebox schema *is* the source of truth. no `prisma generate`, no migration files to keep in sync :3
|
|
69
|
+
- **fully typed** - every query, insert, update, and relation is typed end-to-end. try passing the wrong column name and typescript will bonk you
|
|
70
|
+
- **tiny** - ~2kb overhead on top of `bun:sqlite`. no external query builder, no connection pool, no bloat
|
|
71
|
+
- **relations** - scalar relations (lazy) and sub-table relations (batch resolved) with a fluent builder
|
|
72
|
+
- **events** - listen to table events (`insert`, `update`, `read`, `write`, etc.) typed to your schema. zero overhead unless you subscribe ~
|
|
73
|
+
- **lifecycle hooks** - `onStart`, `onReady`, `onShutdown`, `onExit` for seeding, migrating, cleaning up
|
|
74
|
+
- **sub-tables** - arrays of objects are automatically split into separate sqlite tables with proper indexing
|
|
75
|
+
|
|
76
|
+
## core concepts
|
|
77
|
+
|
|
78
|
+
### schemas
|
|
79
|
+
|
|
80
|
+
use [typebox](https://github.com/sinclairzx81/typebox) to define your data shape. foxdb supports all scalar types (`String`, `Number`, `Integer`, `Boolean`, `Literal`) plus arrays of objects (sub-tables) and arrays of scalars (JSON strings).
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { Object, String, Number, Integer, Array, Optional } from "typebox";
|
|
84
|
+
|
|
85
|
+
const LineItemSchema = Object({
|
|
86
|
+
sku: String(),
|
|
87
|
+
qty: Integer(),
|
|
88
|
+
price: Number(),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const OrderSchema = Object({
|
|
92
|
+
id: String(),
|
|
93
|
+
customerId: String(),
|
|
94
|
+
status: String(),
|
|
95
|
+
total: Number(),
|
|
96
|
+
tags: Array(String()), // becomes a JSON string column ~
|
|
97
|
+
lineItems: Array(LineItemSchema), // becomes a sub-table ~
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### tables
|
|
102
|
+
|
|
103
|
+
the `table()` helper turns a schema into a table descriptor. you pick the primary key, add indexes, and optionally enable timestamps.
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
table(OrderSchema, (s) => ({
|
|
107
|
+
primaryKey: s.id,
|
|
108
|
+
indexes: [
|
|
109
|
+
{ columns: [s.customerId] },
|
|
110
|
+
{ columns: [s.status] },
|
|
111
|
+
],
|
|
112
|
+
timestamps: true, // adds createdAt / updatedAt
|
|
113
|
+
}))
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### repositories
|
|
117
|
+
|
|
118
|
+
every table becomes a repository on the orm object. all crud methods are fully typed:
|
|
119
|
+
|
|
120
|
+
- `insert(data)` - insert a record
|
|
121
|
+
- `insertMany(records)` - batch insert in a transaction
|
|
122
|
+
- `findById(id)` - find by primary key
|
|
123
|
+
- `findMany(opts)` - query with where, orderBy, limit, offset
|
|
124
|
+
- `findPage(opts)` - findMany + total count for pagination
|
|
125
|
+
- `findOne(opts)` - findMany with limit 1
|
|
126
|
+
- `update(data)` - merge partial data (must include pk)
|
|
127
|
+
- `upsert(opts)` - insert or update on conflict
|
|
128
|
+
- `deleteById(id)` - delete by pk
|
|
129
|
+
- `deleteWhere(where)` - delete matching records
|
|
130
|
+
- `count(where?)` - count matching records
|
|
131
|
+
- `flush()` - truncate the table and sub-tables
|
|
132
|
+
|
|
133
|
+
### relations
|
|
134
|
+
|
|
135
|
+
define cross-table relations with a fluent builder:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const orm = createORM({
|
|
139
|
+
tables: {
|
|
140
|
+
orders: table(OrderSchema, (s) => ({ primaryKey: s.id })),
|
|
141
|
+
products: table(ProductSchema, (s) => ({ primaryKey: s.sku })),
|
|
142
|
+
},
|
|
143
|
+
relations: (r) => [
|
|
144
|
+
r.from("orders")
|
|
145
|
+
.subTable("lineItems", "sku")
|
|
146
|
+
.to("products", "sku", { as: "product" }),
|
|
147
|
+
],
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// sub-table items now have a .product property
|
|
151
|
+
const order = orm.orders.findById("ord-1");
|
|
152
|
+
for (const item of order.lineItems) {
|
|
153
|
+
console.log(item.product.name); // lazy or batch resolved :3
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### events
|
|
158
|
+
|
|
159
|
+
listen to table or lifecycle events with full type safety:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// table-specific fine-grained event
|
|
163
|
+
const off = orm._events.on("users", "insert", (e) => {
|
|
164
|
+
console.log(`user ${e.data.id} inserted at ${e.timestamp}`);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// broad category - catches all writes (insert, update, upsert)
|
|
168
|
+
orm._events.on("users", "write", (e) => {
|
|
169
|
+
console.log(`write op: ${e.operation}`);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// lifecycle events
|
|
173
|
+
orm._events.on("ready", (e) => {
|
|
174
|
+
console.log("orm is ready ~");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// cleanup
|
|
178
|
+
off();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
events have **zero overhead** unless you subscribe. the event bus only builds payloads when a listener exists.
|
|
182
|
+
|
|
183
|
+
### lifecycle hooks
|
|
184
|
+
|
|
185
|
+
hook into startup and shutdown to seed, migrate, or clean up:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const orm = createORM({
|
|
189
|
+
tables: { /* ... */ },
|
|
190
|
+
|
|
191
|
+
seed: (o) => {
|
|
192
|
+
o.products.insert({ sku: "WIDGET", name: "widget", price: 9.99 });
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
onReady: (ctx) => {
|
|
196
|
+
console.log("tables:", ctx.tables.join(", "));
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
onShutdown: (ctx) => {
|
|
200
|
+
ctx.orm.activity.insert({
|
|
201
|
+
id: "shutdown",
|
|
202
|
+
message: "shutting down",
|
|
203
|
+
level: "info",
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
rebuildOnLaunch: true, // wipe db on every start
|
|
208
|
+
unlinkDbFilesOnExit: true, // delete .db files on close
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### configuration
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
createORM({
|
|
216
|
+
path: "myapp.db", // sqlite file path (default: ":memory:")
|
|
217
|
+
cacheSize: -64000, // sqlite cache size in pages
|
|
218
|
+
busyTimeout: 5000, // ms to wait for write locks
|
|
219
|
+
synchronous: "NORMAL", // pragma synchronous level
|
|
220
|
+
rebuildOnLaunch: false, // wipe and rebuild on start
|
|
221
|
+
flushOnStart: ["logs"], // truncate tables before seeding
|
|
222
|
+
dropOnExit: ["temp"], // drop tables before close
|
|
223
|
+
autoMigrate: true, // run migrations on startup
|
|
224
|
+
migrations: { dir: "./migrations" },
|
|
225
|
+
errorPolicy: "throw", // "throw" | "emit" | "emit-swallow" | "crash"
|
|
226
|
+
unlinkDbFilesOnExit: false, // true | "onlyGraceful" | "any"
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## error handling
|
|
231
|
+
|
|
232
|
+
foxdb uses `ORMError` with invisible trace context. every throw includes the operation name, table, sql, and parameters that led to the error:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
try {
|
|
236
|
+
orm.users.insert({ id: null, name: "oops" });
|
|
237
|
+
} catch (e) {
|
|
238
|
+
if (e instanceof ORMError) {
|
|
239
|
+
console.log(e.code); // "VALIDATION_FAILED"
|
|
240
|
+
console.log(e.trace); // [{ label: "repository.insert", time: ... }]
|
|
241
|
+
console.log(e.context); // { table: "users" }
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
configure the error policy to crash, emit, swallow, or just throw.
|
|
247
|
+
|
|
248
|
+
## migrations
|
|
249
|
+
|
|
250
|
+
foxdb can auto-run migrations on startup. create migration files and point `migrations.dir` at them:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// migrations/001-init.ts
|
|
254
|
+
import type { Migration } from "@xwxfox/foxdb";
|
|
255
|
+
|
|
256
|
+
export default {
|
|
257
|
+
name: "init",
|
|
258
|
+
date: "2024-01-15",
|
|
259
|
+
up(db) {
|
|
260
|
+
// raw sql via db.exec() if needed
|
|
261
|
+
},
|
|
262
|
+
} satisfies Migration;
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
createORM({
|
|
267
|
+
tables: { /* ... */ },
|
|
268
|
+
migrations: { dir: "./migrations" },
|
|
269
|
+
autoMigrate: true,
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## license
|
|
274
|
+
|
|
275
|
+
mit uwu
|