@xwxfox/foxdb 0.1.1 → 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/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,275 +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) 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
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
package/dist/index.d.mts CHANGED
@@ -293,8 +293,18 @@ type ScalarFilter<V> = unknown extends V ? {
293
293
  eq: V;
294
294
  } | {
295
295
  ne: V;
296
+ } | {
297
+ gt: V;
298
+ } | {
299
+ gte: V;
300
+ } | {
301
+ lt: V;
302
+ } | {
303
+ lte: V;
296
304
  } | {
297
305
  like: string;
306
+ } | {
307
+ between: [V, V];
298
308
  } | {
299
309
  in: V[];
300
310
  } | {
@@ -406,7 +416,7 @@ type ArrayFilter<V> = {
406
416
  */
407
417
  type WhereClause<T extends TSchema2 & {
408
418
  properties: Record<string, TSchema2>;
409
- }> = { [K in ScalarKeys<T>]? : ScalarFilter<Static<T["properties"][K]>> } & { [K in ObjectKeys<T>]? : ScalarFilter<Static<T["properties"][K]>> } & { [K in PrimitiveArrayKeys<T>]? : ArrayFilter<Static<UnwrapOptional<T["properties"][K]> extends TArray<infer Item> ? Item : never>> } & { [K in JsonPath<T>]? : PathValue<T, K> extends Array<infer Item> ? ArrayFilter<Item> : ScalarFilter<PathValue<T, K>> } & {
419
+ }> = { [K in ScalarKeys<T>]? : ScalarFilter<Static<T["properties"][K]>> } & { [K in ObjectKeys<T>]? : ScalarFilter<Static<T["properties"][K]>> } & { [K in PrimitiveArrayKeys<T>]? : ArrayFilter<Static<UnwrapOptional<T["properties"][K]> extends TArray<infer Item> ? Item : never>> } & { [K in (JsonPath<T> | SubTableScalarPath<T>)]? : PathValue<T, K> extends Array<infer Item> ? ArrayFilter<Item> : ScalarFilter<PathValue<T, K>> } & {
410
420
  AND?: WhereClause<T>[];
411
421
  OR?: WhereClause<T>[];
412
422
  NOT?: WhereClause<T>;
@@ -958,15 +968,15 @@ type AggregationOp<T extends TSchema2 & {
958
968
  } = TSchema2 & {
959
969
  properties: Record<string, TSchema2>;
960
970
  }> = {
961
- sum?: ScalarKeys<T> | ScalarJsonPath<T>;
971
+ sum?: ScalarKeys<T> | ScalarJsonPath<T> | SubTableScalarPath<T>;
962
972
  } | {
963
- count?: "*" | ScalarKeys<T> | ScalarJsonPath<T>;
973
+ count?: "*" | ScalarKeys<T> | ScalarJsonPath<T> | SubTableScalarPath<T>;
964
974
  } | {
965
- avg?: ScalarKeys<T> | ScalarJsonPath<T>;
975
+ avg?: ScalarKeys<T> | ScalarJsonPath<T> | SubTableScalarPath<T>;
966
976
  } | {
967
- min?: ScalarKeys<T> | ScalarJsonPath<T>;
977
+ min?: ScalarKeys<T> | ScalarJsonPath<T> | SubTableScalarPath<T>;
968
978
  } | {
969
- max?: ScalarKeys<T> | ScalarJsonPath<T>;
979
+ max?: ScalarKeys<T> | ScalarJsonPath<T> | SubTableScalarPath<T>;
970
980
  };
971
981
  /** @category Query Types */
972
982
  interface AggregateOptions<
@@ -980,6 +990,13 @@ interface AggregateOptions<
980
990
  aggregations: A;
981
991
  having?: { [K in keyof A]? : ScalarFilter<unknown> };
982
992
  includeDeleted?: boolean;
993
+ /**
994
+ * Aggregate over a sub-table (array relationship) instead of the main table.
995
+ * Provide the field name of the sub-table (e.g. "PurchaseLineItems").
996
+ * Column references in aggregations/where/groupBy are resolved against the
997
+ * sub-table's item schema.
998
+ */
999
+ subTable?: string;
983
1000
  }
984
1001
  /** @internal */
985
1002
  type AggregationOpResult<
@@ -1279,6 +1296,17 @@ declare class Repository<
1279
1296
  readonly tableName: string;
1280
1297
  /** table metadata - columns, sub-tables, indexes */
1281
1298
  readonly meta: TableMeta;
1299
+ /**
1300
+ * Get the underlying SQLite table name for a sub-table by field name.
1301
+ * Returns undefined if the field is not a sub-table (array relationship).
1302
+ *
1303
+ * @example
1304
+ * ```ts
1305
+ * orm.purchases.getSubTableName("PurchaseLineItems")
1306
+ * // => "archivedPurchases__PurchaseLineItems"
1307
+ * ```
1308
+ */
1309
+ getSubTableName(fieldName: string): string | undefined;
1282
1310
  private readonly validator;
1283
1311
  private readonly db;
1284
1312
  private readonly descriptor;
package/dist/index.mjs CHANGED
@@ -1,15 +1,15 @@
1
1
  // @bun
2
- import{Database as Nt,constants as kt}from"bun:sqlite";class we{timers=new Set;timersByName=new Map;tasks=new Map;schedule(e,t,n){this.clear(e),this.tasks.set(e,n);let r=setInterval(()=>{try{n()}catch(s){console.error(`[foxdb] scheduler task "${e}" failed:`,s)}},t);this.timers.add(r),this.timersByName.set(e,r)}clear(e){let t=this.timersByName.get(e);if(t)clearInterval(t),this.timers.delete(t),this.timersByName.delete(e);this.tasks.delete(e)}clearAll(){for(let e of this.timers)clearInterval(e);this.timers.clear(),this.timersByName.clear(),this.tasks.clear()}}import{existsSync as Ct,unlinkSync as At}from"fs";class K{db;scheduler=new we;constructor(e={}){let t=e.path??":memory:";this.db=new Nt(t,{create:!0}),this.db.run("PRAGMA journal_mode = WAL;");let n=e.synchronous??"NORMAL",r=e.cacheSize??-64000,s=e.busyTimeout??5000,a=e.mmapSize??268435456;this.db.run(`PRAGMA synchronous = ${n};`),this.db.run(`PRAGMA cache_size = ${r};`),this.db.run(`PRAGMA busy_timeout = ${s};`),this.db.run(`PRAGMA mmap_size = ${a};`),this.db.run("PRAGMA foreign_keys = ON;"),this.db.run("PRAGMA temp_store = MEMORY;");let o=e.autoVacuum??!1;if(o)this.db.run(`PRAGMA auto_vacuum = ${o.toUpperCase()};`)}exec(e){this.db.run(e)}transaction(e){return this.db.transaction(e)()}close(){this.scheduler.clearAll();for(let e of this._stmtCache.values())try{e.finalize()}catch{}this._stmtCache.clear();try{this.db.fileControl(kt.SQLITE_FCNTL_PERSIST_WAL,0),this.db.run("PRAGMA wal_checkpoint(TRUNCATE);")}catch{}this.db.close()}static _MAX_CACHE_SIZE=256;_stmtCache=new Map;prepare(e){let t=this._stmtCache.get(e);if(!t){if(t=this.db.prepare(e),this._stmtCache.size>=K._MAX_CACHE_SIZE){let n=this._stmtCache.keys().next().value;if(n!==void 0){let r=this._stmtCache.get(n);try{r?.finalize()}catch{}this._stmtCache.delete(n)}}this._stmtCache.set(e,t)}return t}setSynchronous(e){this.db.run(`PRAGMA synchronous = ${e};`)}clearCache(){for(let e of this._stmtCache.values())try{e.finalize()}catch{}this._stmtCache.clear()}}function $t(e){if(e===":memory:")return[];return[e,`${e}-wal`,`${e}-shm`,`${e}-journal`].filter((t)=>Ct(t))}function ae(e){for(let t of $t(e))try{At(t)}catch{}}import{Compile as Ht}from"typebox/compile";class le{db;tableName;metricsHook;stmtCache=new Map;constructor(e){this.db=e.db,this.tableName=e.tableName,this.metricsHook=e.metricsHook}_getStmt(e){let t=this.stmtCache.get(e);if(t)return t;let n=this.db.prepare(e);return this.stmtCache.set(e,n),n}exec(e,t,n="raw"){let r=performance.now(),s=this._getStmt(e).run(...t??[]);return this._emit(n,e,performance.now()-r,s.changes),s}all(e,t,n="read"){let r=performance.now(),s=this._getStmt(e).all(...t??[]);return this._emit(n,e,performance.now()-r,s.length),s}get(e,t,n="read"){let r=performance.now(),s=this._getStmt(e).get(...t??[]);return this._emit(n,e,performance.now()-r,s?1:0),s??null}*iterate(e,t,n="read"){let r=performance.now(),s=this._getStmt(e).iterate(...t??[]),a=0;for(let o of s)a++,yield o;this._emit(n,e,performance.now()-r,a)}_emit(e,t,n,r){if(!this.metricsHook)return;this.metricsHook({table:this.tableName,operation:e,sql:t,durationMs:n,rowCount:r})}}class G extends Error{code;trace;context;constructor(e,t){super(e);this.name="ORMError",this.code=t.code,this.trace=t.trace,this.context=t.context??{}}}var xe=[];function Ee(e,t){xe.push({label:e,time:Date.now(),details:t})}function Oe(){xe.pop()}function _e(){return xe.slice()}function C(e,t,n){Ee(e,t);try{return n()}finally{Oe()}}function O(e,t,n){throw new G(t,{code:e,trace:_e(),context:n})}import{IsObject as W,IsArray as ue,IsString as Je,IsNumber as Xe,IsInteger as Ye,IsBoolean as Ce,IsLiteral as ze,IsOptional as Mt}from"typebox";function Ne(e){if(Mt(e))return{schema:e,optional:!0};return{schema:e,optional:!1}}function Ae(e){let t=e;if(t.anyOf&&Array.isArray(t.anyOf))return t.anyOf;return null}function It(e){return e.const}function vt(e){let t=e;if(t.properties&&typeof t.properties==="object"&&t.properties!==null)return t.properties;return null}function $e(e){let t=Ae(e);if(t)return t.some((n)=>n.type==="null");return!1}function Me(e){if(Ye(e))return"INTEGER";if(Xe(e))return"REAL";if(Ce(e))return"INTEGER";if(Je(e))return"TEXT";if(ze(e)){let t=It(e);if(typeof t==="number")return Number.isInteger(t)?"INTEGER":"REAL";if(typeof t==="boolean")return"INTEGER";return"TEXT"}if($e(e)){let t=Ae(e);if(t){let n=t.find((r)=>r.type!=="null");if(n)return Me(n)}}return"TEXT"}function Ze(e){if(Je(e)||Xe(e)||Ye(e)||Ce(e)||ze(e))return!0;if($e(e)){let t=Ae(e);if(t){let n=t.find((r)=>r.type!=="null");if(!n)return!1;return Ze(n)}}return!1}function Lt(e){if(!W(e))return!1;let t=vt(e);if(!t)return!1;for(let n of Object.values(t)){if(ue(n)||W(n))continue;let{schema:r}=Ne(n);if(ue(r)||W(r))continue;if(Ze(r))continue;return!1}return!0}function ke(e,t=[],n=0,r=!1){let s=[];for(let[a,o]of Object.entries(e)){if(ue(o)){let{optional:c}=Ne(o);if(r&&n===0&&W(o.items))continue;let d=t.length>0?[...t,a].join("__"):a;s.push({name:d,sqlType:"TEXT",nullable:c,optional:c,path:t.length>0?[...t,a]:void 0});continue}if(W(o)&&n<2&&Lt(o)){s.push(...ke(o.properties,[...t,a],n+1,r));continue}let{schema:i,optional:l}=Ne(o),u=l||$e(i),m=t.length>0?[...t,a].join("__"):a;s.push({name:m,sqlType:W(i)?"TEXT":Me(i),nullable:u,optional:u,path:t.length>0?[...t,a]:void 0,isBoolean:Ce(i)})}return s}function ne(e){if(!e)return;let t=[];for(let[n,r]of Object.entries(e))t.push({name:n,expr:r.expr,sqlType:Me(r.type)});return t}function J(e,t,n){let r=[];for(let[i,l]of Object.entries(t.properties))if(ue(l)&&W(l.items)){let u=l.items,m=`${e}__${i}`,c=ke(u.properties,[],0,!1),d=new Map,p=new Map;for(let h of c)if(d.set(h.name,h),h.path)p.set(h.path.join("."),h);r.push({fieldName:i,tableName:m,itemSchema:u,columns:c,columnByName:d,columnByPath:p})}let s=ke(t.properties,[],0,!0);if(n)for(let i of n)s.push({name:i.name,sqlType:i.sqlType??"TEXT",nullable:!0,optional:!0,generated:!0,generatedExpr:i.expr});let a=new Map,o=new Map;for(let i of s)if(o.set(i.name,i),i.path)a.set(i.path.join("."),i);return{tableName:e,columns:s,subTables:r,columnByPath:a,columnByName:o}}function Ie(e,t){let n=[],r=e.columns.map((s)=>{let a=!s.nullable?" NOT NULL":"",o=s.name===t?" PRIMARY KEY":"",i=s.generated&&s.generatedExpr?` GENERATED ALWAYS AS (${s.generatedExpr}) STORED`:"";return` "${s.name}" ${s.sqlType}${o}${a}${i}`});n.push(`CREATE TABLE IF NOT EXISTS "${e.tableName}" (
2
+ import{Database as _t,constants as kt}from"bun:sqlite";class we{timers=new Set;timersByName=new Map;tasks=new Map;schedule(e,t,n){this.clear(e),this.tasks.set(e,n);let r=setInterval(()=>{try{n()}catch(s){console.error(`[foxdb] scheduler task "${e}" failed:`,s)}},t);this.timers.add(r),this.timersByName.set(e,r)}clear(e){let t=this.timersByName.get(e);if(t)clearInterval(t),this.timers.delete(t),this.timersByName.delete(e);this.tasks.delete(e)}clearAll(){for(let e of this.timers)clearInterval(e);this.timers.clear(),this.timersByName.clear(),this.tasks.clear()}}import{existsSync as Ct,unlinkSync as At}from"fs";class K{db;scheduler=new we;constructor(e={}){let t=e.path??":memory:";this.db=new _t(t,{create:!0}),this.db.run("PRAGMA journal_mode = WAL;");let n=e.synchronous??"NORMAL",r=e.cacheSize??-64000,s=e.busyTimeout??5000,a=e.mmapSize??268435456;this.db.run(`PRAGMA synchronous = ${n};`),this.db.run(`PRAGMA cache_size = ${r};`),this.db.run(`PRAGMA busy_timeout = ${s};`),this.db.run(`PRAGMA mmap_size = ${a};`),this.db.run("PRAGMA foreign_keys = ON;"),this.db.run("PRAGMA temp_store = MEMORY;");let o=e.autoVacuum??!1;if(o)this.db.run(`PRAGMA auto_vacuum = ${o.toUpperCase()};`)}exec(e){this.db.run(e)}transaction(e){return this.db.transaction(e)()}close(){this.scheduler.clearAll();for(let e of this._stmtCache.values())try{e.finalize()}catch{}this._stmtCache.clear();try{this.db.fileControl(kt.SQLITE_FCNTL_PERSIST_WAL,0),this.db.run("PRAGMA wal_checkpoint(TRUNCATE);")}catch{}this.db.close()}static _MAX_CACHE_SIZE=256;_stmtCache=new Map;prepare(e){let t=this._stmtCache.get(e);if(!t){if(t=this.db.prepare(e),this._stmtCache.size>=K._MAX_CACHE_SIZE){let n=this._stmtCache.keys().next().value;if(n!==void 0){let r=this._stmtCache.get(n);try{r?.finalize()}catch{}this._stmtCache.delete(n)}}this._stmtCache.set(e,t)}return t}setSynchronous(e){this.db.run(`PRAGMA synchronous = ${e};`)}clearCache(){for(let e of this._stmtCache.values())try{e.finalize()}catch{}this._stmtCache.clear()}}function $t(e){if(e===":memory:")return[];return[e,`${e}-wal`,`${e}-shm`,`${e}-journal`].filter((t)=>Ct(t))}function ie(e){for(let t of $t(e))try{At(t)}catch{}}import{Compile as Vt}from"typebox/compile";class le{db;tableName;metricsHook;stmtCache=new Map;constructor(e){this.db=e.db,this.tableName=e.tableName,this.metricsHook=e.metricsHook}_getStmt(e){let t=this.stmtCache.get(e);if(t)return t;let n=this.db.prepare(e);return this.stmtCache.set(e,n),n}exec(e,t,n="raw"){let r=performance.now(),s=this._getStmt(e).run(...t??[]);return this._emit(n,e,performance.now()-r,s.changes),s}all(e,t,n="read"){let r=performance.now(),s=this._getStmt(e).all(...t??[]);return this._emit(n,e,performance.now()-r,s.length),s}get(e,t,n="read"){let r=performance.now(),s=this._getStmt(e).get(...t??[]);return this._emit(n,e,performance.now()-r,s?1:0),s??null}*iterate(e,t,n="read"){let r=performance.now(),s=this._getStmt(e).iterate(...t??[]),a=0;for(let o of s)a++,yield o;this._emit(n,e,performance.now()-r,a)}_emit(e,t,n,r){if(!this.metricsHook)return;this.metricsHook({table:this.tableName,operation:e,sql:t,durationMs:n,rowCount:r})}}class G extends Error{code;trace;context;constructor(e,t){super(e);this.name="ORMError",this.code=t.code,this.trace=t.trace,this.context=t.context??{}}}var xe=[];function Ee(e,t){xe.push({label:e,time:Date.now(),details:t})}function Oe(){xe.pop()}function Ne(){return xe.slice()}function C(e,t,n){Ee(e,t);try{return n()}finally{Oe()}}function N(e,t,n){throw new G(t,{code:e,trace:Ne(),context:n})}import{IsObject as W,IsArray as ue,IsString as Je,IsNumber as Xe,IsInteger as Ye,IsBoolean as Ce,IsLiteral as ze,IsOptional as Mt}from"typebox";function _e(e){if(Mt(e))return{schema:e,optional:!0};return{schema:e,optional:!1}}function Ae(e){let t=e;if(t.anyOf&&Array.isArray(t.anyOf))return t.anyOf;return null}function It(e){return e.const}function vt(e){let t=e;if(t.properties&&typeof t.properties==="object"&&t.properties!==null)return t.properties;return null}function $e(e){let t=Ae(e);if(t)return t.some((n)=>{return n.type==="null"});return!1}function Me(e){if(Ye(e))return"INTEGER";if(Xe(e))return"REAL";if(Ce(e))return"INTEGER";if(Je(e))return"TEXT";if(ze(e)){let t=It(e);if(typeof t==="number")return Number.isInteger(t)?"INTEGER":"REAL";if(typeof t==="boolean")return"INTEGER";return"TEXT"}if($e(e)){let t=Ae(e);if(t){let n=t.find((r)=>{return r.type!=="null"});if(n)return Me(n)}}return"TEXT"}function Ze(e){if(Je(e)||Xe(e)||Ye(e)||Ce(e)||ze(e))return!0;if($e(e)){let t=Ae(e);if(t){let n=t.find((r)=>{return r.type!=="null"});if(!n)return!1;return Ze(n)}}return!1}function Bt(e){if(!W(e))return!1;let t=vt(e);if(!t)return!1;for(let n of Object.values(t)){if(ue(n)||W(n))continue;let{schema:r}=_e(n);if(ue(r)||W(r))continue;if(Ze(r))continue;return!1}return!0}function ke(e,t=[],n=0,r=!1){let s=[];for(let[a,o]of Object.entries(e)){if(ue(o)){let{optional:c}=_e(o);if(r&&n===0&&W(o.items))continue;let m=t.length>0?[...t,a].join("__"):a;s.push({name:m,sqlType:"TEXT",nullable:c,optional:c,path:t.length>0?[...t,a]:void 0});continue}if(W(o)&&n<2&&Bt(o)){s.push(...ke(o.properties,[...t,a],n+1,r));continue}let{schema:i,optional:l}=_e(o),u=l||$e(i),d=t.length>0?[...t,a].join("__"):a;s.push({name:d,sqlType:W(i)?"TEXT":Me(i),nullable:u,optional:u,path:t.length>0?[...t,a]:void 0,isBoolean:Ce(i)})}return s}function ne(e){if(!e)return;let t=[];for(let[n,r]of Object.entries(e))t.push({name:n,expr:r.expr,sqlType:Me(r.type)});return t}function J(e,t,n){let r=[];for(let[i,l]of Object.entries(t.properties))if(ue(l)&&W(l.items)){let u=l.items,d=`${e}__${i}`,c=ke(u.properties,[],0,!1),m=new Map,f=new Map;for(let h of c)if(m.set(h.name,h),h.path)f.set(h.path.join("."),h);r.push({fieldName:i,tableName:d,itemSchema:u,columns:c,columnByName:m,columnByPath:f})}let s=ke(t.properties,[],0,!0);if(n)for(let i of n)s.push({name:i.name,sqlType:i.sqlType??"TEXT",nullable:!0,optional:!0,generated:!0,generatedExpr:i.expr});let a=new Map,o=new Map;for(let i of s)if(o.set(i.name,i),i.path)a.set(i.path.join("."),i);return{tableName:e,columns:s,subTables:r,columnByPath:a,columnByName:o}}function Ie(e,t){let n=[],r=e.columns.map((s)=>{let a=!s.nullable?" NOT NULL":"",o=s.name===t?" PRIMARY KEY":"",i=s.generated&&s.generatedExpr?` GENERATED ALWAYS AS (${s.generatedExpr}) STORED`:"";return` "${s.name}" ${s.sqlType}${o}${a}${i}`});n.push(`CREATE TABLE IF NOT EXISTS "${e.tableName}" (
3
3
  ${r.join(`,
4
4
  `)}
5
5
  )`);for(let s of e.subTables){let a=[' "_id" INTEGER PRIMARY KEY AUTOINCREMENT',` "_owner_id" ${e.columns.find((o)=>o.name===t)?.sqlType??"TEXT"} NOT NULL`,' "_index" INTEGER NOT NULL',...s.columns.map((o)=>{let i=!o.nullable?" NOT NULL":"";return` "${o.name}" ${o.sqlType}${i}`})];n.push(`CREATE TABLE IF NOT EXISTS "${s.tableName}" (
6
6
  ${a.join(`,
7
7
  `)}
8
- )`),n.push(`CREATE INDEX IF NOT EXISTS "idx_${s.tableName}__owner" ON "${s.tableName}" ("_owner_id")`)}return n}function et(e,t,n,r,s,a){let o=r??`idx_${e}__${t.join("_")}`,i=n?"UNIQUE ":"",l=t.map((m)=>`"${m}"`).join(", "),u=s?` WHERE ${s}`:"";return`CREATE ${i}INDEX IF NOT EXISTS "${o}" ON "${e}" (${l})${u}`}function ee(e,t){if(e===void 0||e===null)return null;if(t==="TEXT"&&typeof e==="object")return JSON.stringify(e);if(t==="INTEGER"&&typeof e==="boolean")return e?1:0;return Bt(e)}function te(e,t){let n=e;for(let r of t){if(n===null||n===void 0)return;if(typeof n!=="object")return;n=n[r]}return n}function Z(e,t,n){let r=e;for(let s=0;s<t.length-1;s++){let a=t[s];if(!(a in r))r[a]={};r=r[a]}r[t[t.length-1]]=n}function U(e,t,n){let r={};if(!n?.size)for(let s of t.columns){if(s.generated)continue;let a=s.path?te(e,s.path):e[s.name];r[s.name]=ee(a,s.sqlType)}else for(let s of t.columns){if(s.generated)continue;let a=s.path?te(e,s.path):e[s.name],o=ee(a,s.sqlType),i=n.get(s.name);if(i)o=i.encode(o);r[s.name]=o}return r}function tt(e,t,n){let r={};for(let s of t.columns){if(s.generated)continue;if(!(s.name in e)&&!s.path)continue;let a;if(s.path)a=te(e,s.path);else a=e[s.name];if(a===void 0)continue;let o=ee(a,s.sqlType),i=n?.get(s.name);if(i)o=i.encode(o);r[s.name]=o}return r}function X(e,t,n,r){let s=Array(t.length);if(!r?.size)for(let a=0;a<t.length;a++){let o=t[a];if(o===null||typeof o!=="object")throw TypeError("Sub-table item must be an object");let i=o,l={_owner_id:e,_index:a};for(let u of n.columns){let m=u.path?te(i,u.path):i[u.name];l[u.name]=ee(m,u.sqlType)}s[a]=l}else for(let a=0;a<t.length;a++){let o=t[a];if(o===null||typeof o!=="object")throw TypeError("Sub-table item must be an object");let i=o,l={_owner_id:e,_index:a};for(let u of n.columns){let m=u.path?te(i,u.path):i[u.name],c=ee(m,u.sqlType),d=r.get(u.name);if(d)c=d.encode(c);l[u.name]=c}s[a]=l}return s}function Bt(e){if(e===null||e===void 0)return null;if(typeof e==="string"||typeof e==="number"||typeof e==="boolean"||typeof e==="bigint")return e;if(typeof e==="object")return JSON.stringify(e);return String(e)}function ce(e,t,n){if(t==="TEXT"&&typeof e==="string"){let r=e.charCodeAt(0);if(r===123||r===91)try{let s=JSON.parse(e);return typeof s==="object"?s:e}catch{return e}return e}if(t==="INTEGER"&&typeof e==="number")return n?e===1:e;return e??null}function Dt(e,t){let n={};for(let r of t.columns){let s=ce(e[r.name],r.sqlType,r.isBoolean);if(r.path)if(r.path.length===1)n[r.path[0]]=s;else Z(n,r.path,s);else n[r.name]=s}return n}function de(e,t,n,r,s,a){if(!r?.size&&!s&&!t.subTables.length)return Dt(e,t);let o={};if(!s)if(!r?.size)for(let i of t.columns){let l=ce(e[i.name],i.sqlType,i.isBoolean);if(i.path)if(i.path.length===1)o[i.path[0]]=l;else Z(o,i.path,l);else o[i.name]=l}else for(let i of t.columns){let l=e[i.name],u=r.get(i.name);if(u)l=u.decode(l);let m=ce(l,i.sqlType,i.isBoolean);if(i.path)if(i.path.length===1)o[i.path[0]]=m;else Z(o,i.path,m);else o[i.name]=m}else{let i=new Set;for(let l of s)if(i.add(l),!l.includes(".")){for(let u of t.columns)if(u.path&&u.path[0]===l)i.add(u.name)}else{let u=t.columnByPath.get(l);if(u)i.add(u.name)}for(let l of t.columns){if(!i.has(l.name))continue;let u=e[l.name],m=r?.get(l.name);if(m)u=m.decode(u);let c=ce(u,l.sqlType,l.isBoolean);if(l.path)if(l.path.length===1)o[l.path[0]]=c;else Z(o,l.path,c);else o[l.name]=c}for(let l of Object.keys(e)){if(i.has(l))continue;if(l.includes("__")){let u=l.split("__"),m=e[l];if(typeof m==="string"){let c=m.charCodeAt(0);if(c===123||c===91)try{let d=JSON.parse(m);if(typeof d==="object")m=d}catch{}}Z(o,u,m)}}}for(let i of t.subTables)if(a&&!a.includes(i.fieldName))o[i.fieldName]=[];else o[i.fieldName]=n.get(i.tableName)??[];return o}var nt={encode(e){if(typeof e!=="string")return e;let t=new TextEncoder().encode(e);return Bun.gzipSync(t.buffer)},decode(e){if(!(e instanceof Uint8Array))return e;return new TextDecoder().decode(Bun.gunzipSync(e.buffer))}};function Pt(e){return typeof e==="object"&&e!==null}function ve(e){return e.replace(/'/g,"''")}function Qt(e,t){let n=e.split(".");if(n.length<2)return null;if(t){let o=t.columnByPath.get(e);if(o)return{sql:`"${o.name}"`};for(let i=n.length-1;i>=1;i--){let l=n.slice(0,i).join("."),u=n.slice(i).join("."),m=t.columnByPath.get(l);if(m&&m.sqlType==="TEXT")return{sql:`JSON_EXTRACT("${m.name.replace(/"/g,'""')}", '$.${ve(u)}')`}}}let r=n[0],s=n.slice(1).join(".");return{sql:`JSON_EXTRACT("${r.replace(/"/g,'""')}", '$.${ve(s)}')`}}function B(e){if(e!==null&&typeof e==="object")return JSON.stringify(e);return e}function Le(e,t,n){let r=Qt(e,n),s=r?r.sql:`"${e}"`,a=[],o=[];if("eq"in t)a.push(`${s} = ?`),o.push(B(t.eq));if("ne"in t)a.push(`${s} != ?`),o.push(B(t.ne));if("gt"in t)a.push(`${s} > ?`),o.push(B(t.gt));if("gte"in t)a.push(`${s} >= ?`),o.push(B(t.gte));if("lt"in t)a.push(`${s} < ?`),o.push(B(t.lt));if("lte"in t)a.push(`${s} <= ?`),o.push(B(t.lte));if("like"in t)a.push(`${s} LIKE ?`),o.push(B(t.like));if("between"in t){let[i,l]=t.between;a.push(`${s} BETWEEN ? AND ?`),o.push(B(i),B(l))}if("in"in t){let i=t.in,l=i.map(()=>"?").join(", ");a.push(`${s} IN (${l})`),o.push(...i.map(B))}if("notIn"in t){let i=t.notIn,l=i.map(()=>"?").join(", ");a.push(`${s} NOT IN (${l})`),o.push(...i.map(B))}if("isNull"in t)a.push(`${s} IS NULL`);if("isNotNull"in t)a.push(`${s} IS NOT NULL`);if("arraySome"in t)a.push(`EXISTS (SELECT 1 FROM json_each(${s}) WHERE value = ?)`),o.push(B(t.arraySome));if("arrayNot"in t)a.push(`NOT EXISTS (SELECT 1 FROM json_each(${s}) WHERE value = ?)`),o.push(B(t.arrayNot));if("isEmpty"in t)if(t.isEmpty)a.push(`(json_array_length(${s}) = 0 OR ${s} IS NULL)`);else a.push(`json_array_length(${s}) > 0`);if("fastArrayIsEmpty"in t)if(t.fastArrayIsEmpty)a.push(`(${s} = '[]' OR ${s} IS NULL)`);else a.push(`(${s} != '[]' AND ${s} IS NOT NULL)`);if("fastArraySome"in t){let i=JSON.stringify([t.fastArraySome]),l=i.substring(1,i.length-1);a.push(`(',' || REPLACE(REPLACE(${s}, '[', ''), ']', '') || ',') LIKE ?`),o.push(`%,${l},%`)}if("fastArrayNot"in t){let i=JSON.stringify([t.fastArrayNot]),l=i.substring(1,i.length-1);a.push(`(',' || REPLACE(REPLACE(${s}, '[', ''), ']', '') || ',') NOT LIKE ?`),o.push(`%,${l},%`)}if(a.length===0)O("UNKNOWN_FILTER",`foxdb: unknown filter operator for column "${e}"`,{column:e});return{sql:a.join(" AND "),params:o}}function jt(e){if(typeof e!=="object"||e===null)return!1;let t=e;if("AND"in t&&Array.isArray(t.AND))return!0;if("OR"in t&&Array.isArray(t.OR))return!0;if("NOT"in t&&typeof t.NOT==="object"&&t.NOT!==null)return!0;return!1}function Y(e){if(!e||typeof e!=="object"||Object.keys(e).length===0)return!0;let t=e,n=Object.keys(t);if(n.length===1&&n[0]==="AND"&&Array.isArray(t.AND)&&t.AND.length===0)return!0;if(n.length===1&&n[0]==="OR"&&Array.isArray(t.OR)&&t.OR.some(Y))return!0;if(n.length===1&&n[0]==="NOT"&&re(t.NOT))return!0;return!1}function re(e){if(!e||typeof e!=="object")return!1;let t=e,n=Object.keys(t);if(n.length===1&&n[0]==="OR"&&Array.isArray(t.OR)&&t.OR.length===0)return!0;if(n.length===1&&n[0]==="AND"&&Array.isArray(t.AND)&&t.AND.some(re))return!0;if(n.length===1&&n[0]==="NOT"&&Y(t.NOT))return!0;return!1}function me(e,t,n){let r=[],s=[];if(t)r.push(`"${t}" IS NULL`);if(!e||Object.keys(e).length===0){if(r.length===0)return{sql:"",params:[]};return{sql:`WHERE ${r.join(" AND ")}`,params:s}}if(jt(e)){let o=e;if(o.AND)for(let i of o.AND){if(Y(i))continue;if(re(i)){if(r.push("1=0"),r.length===1)return{sql:"WHERE 1=0",params:[]};return{sql:`WHERE ${r.join(" AND ")}`,params:s}}let l=me(i,void 0,n);if(l.sql)r.push(`(${l.sql.replace(/^WHERE\s+/,"")})`),s.push(...l.params)}if(o.OR){let i=[],l=[];for(let u of o.OR){if(Y(u)){i.length=0;break}if(re(u))continue;let m=me(u,void 0,n);if(m.sql)i.push(m.sql.replace(/^WHERE\s+/,"")),l.push(...m.params)}if(i.length>0)r.push(`(${i.join(" OR ")})`),s.push(...l);else if(!o.OR.some(Y))r.push("1=0")}if(o.NOT){if(Y(o.NOT))r.push("1=0");else if(!re(o.NOT)){let i=me(o.NOT,void 0,n);if(i.sql)r.push(`NOT (${i.sql.replace(/^WHERE\s+/,"")})`),s.push(...i.params)}}}let a=e._raw;if(a&&typeof a==="object"&&"sql"in a){let o=a;r.push(`(${o.sql})`),s.push(...o.params??[])}for(let[o,i]of Object.entries(e)){if(o==="AND"||o==="OR"||o==="NOT"||o==="_raw")continue;if(!Pt(i))continue;let l=Le(o,i,n);r.push(l.sql),s.push(...l.params)}if(r.length===0)return{sql:"",params:[]};return{sql:`WHERE ${r.join(" AND ")}`,params:s}}function P(e,t,n){return me(e,t,n)}function Q(e,t){if(!t)return`"${e}"`;let n=t.columnByPath.get(e);if(n)return`"${n.name}"`;let r=e.split(".");for(let s=r.length-1;s>=1;s--){let a=r.slice(0,s).join("."),o=r.slice(s).join("."),i=t.columnByPath.get(a);if(i&&i.sqlType==="TEXT")return`JSON_EXTRACT("${i.name.replace(/"/g,'""')}", '$.${ve(o)}')`}return`"${e}"`}function qt(e,t){if(!e)return"";let n=globalThis.Array.isArray(e)?e:[e];if(n.length===0)return"";return`ORDER BY ${n.map((s)=>`${Q(s.column,t)} ${s.direction??"ASC"}`).join(", ")}`}function Ft(e,t){let n=[],r=[];if(e!==void 0)n.push("LIMIT ?"),r.push(e);if(t!==void 0)n.push("OFFSET ?"),r.push(t);return{sql:n.join(" "),params:r}}function Kt(e,t){let n=t.columnByName.get(e)||t.columnByPath.get(e);if(n)return[`"${n.name}"`];let r=[];for(let a of t.columns)if(a.path&&a.path[0]===e)r.push(`"${a.name}"`);if(r.length>0)return r;let s=e.split(".");for(let a=s.length-1;a>=1;a--){let o=s.slice(0,a).join("."),i=s.slice(a).join("."),l=t.columnByPath.get(o);if(l&&l.sqlType==="TEXT"){let u=s.join("__");return[`JSON_EXTRACT("${l.name}", '$.${i.replace(/'/g,"''")}') as "${u}"`]}}return[`"${e}"`]}function Be(e,t,n,r){let{sql:s,params:a}=P(t.where,t.includeDeleted?void 0:n,r),o=qt(t.orderBy,r),{sql:i,params:l}=Ft(t.limit,t.offset),u=t.select&&r?t.select.flatMap((p)=>Kt(p,r)).join(", "):"*";if(t.distinctOn&&t.distinctOn.length>0){let p=t.distinctOn.map((k)=>Q(k,r)).join(", "),h=[`SELECT ${u} FROM "${e}"`,s,`GROUP BY ${p}`,o,i].filter(Boolean).join(" "),T=[`SELECT COUNT(*) as "_count" FROM (SELECT 1 FROM "${e}"`,s,`GROUP BY ${p})`].filter(Boolean).join(" ");return{sql:h,params:[...a,...l],countSql:T,countParams:a}}let c=[`SELECT ${t.distinct?"DISTINCT ":""}${u} FROM "${e}"`,s,o,i].filter(Boolean).join(" "),d;if(t.distinct)d=[`SELECT COUNT(*) as "_count" FROM (SELECT DISTINCT ${u} FROM "${e}"`,s,")"];else d=[`SELECT COUNT(*) as "_count" FROM "${e}"`,s];return{sql:c,params:[...a,...l],countSql:d.filter(Boolean).join(" "),countParams:a}}function se(e,t,n,r){return Be(e,t,n,r)}function H(e,t){let n=Object.keys(t),r=n.map((a)=>`"${a}"`).join(", "),s=n.map(()=>"?").join(", ");return{sql:`INSERT INTO "${e}" (${r}) VALUES (${s})`,params:n.map((a)=>t[a])}}function pe(e,t,n=999){if(t.length===0)return[];let r=t[0],s=Object.keys(r),a=s.length,o=Math.floor(n/a);if(o<=0)O("TOO_MANY_COLUMNS",`foxdb: table "${e}" has too many columns for multi-value insert`);let i=[];for(let l=0;l<t.length;l+=o){let u=t.slice(l,l+o),m=s.map((p)=>`"${p}"`).join(", "),c=u.map(()=>`(${s.map(()=>"?").join(", ")})`).join(", "),d=u.flatMap((p)=>s.map((h)=>p[h]));i.push({sql:`INSERT INTO "${e}" (${m}) VALUES ${c}`,params:d})}return i}function rt(e,t,n,r){let s=Object.keys(t),a=s.map((u)=>`"${u}"`).join(", "),o=s.map(()=>"?").join(", "),i=n.map((u)=>`"${u}"`).join(", "),l=r.map((u)=>`"${u}" = excluded."${u}"`).join(", ");return{sql:`INSERT INTO "${e}" (${a}) VALUES (${o}) ON CONFLICT (${i}) DO UPDATE SET ${l}`,params:s.map((u)=>t[u])}}function st(e,t,n,r,s=999){if(t.length===0)return[];let a=t[0],o=Object.keys(a),i=o.length,l=Math.floor(s/i);if(l<=0)O("TOO_MANY_COLUMNS",`foxdb: table "${e}" has too many columns for multi-value upsert`);let u=n.map((d)=>`"${d}"`).join(", "),m=r.map((d)=>`"${d}" = excluded."${d}"`).join(", "),c=[];for(let d=0;d<t.length;d+=l){let p=t.slice(d,d+l),h=o.map((D)=>`"${D}"`).join(", "),T=p.map(()=>`(${o.map(()=>"?").join(", ")})`).join(", "),k=p.flatMap((D)=>o.map((oe)=>D[oe]));c.push({sql:`INSERT INTO "${e}" (${h}) VALUES ${T} ON CONFLICT (${u}) DO UPDATE SET ${m}`,params:k})}return c}function ot(e,t,n,r){let s=Object.entries(r).filter(([o])=>o!==t);if(s.length===0)O("NO_COLUMNS_TO_UPDATE","foxdb: no columns to update",{table:e});let a=s.map(([o])=>`"${o}" = ?`).join(", ");return{sql:`UPDATE "${e}" SET ${a} WHERE "${t}" = ?`,params:[...s.map(([,o])=>o),n]}}function it(e,t,n,r,s){let a=Object.entries(t);if(a.length===0)O("NO_COLUMNS_TO_UPDATE","foxdb: no columns to update",{table:e});let o=a.map(([u])=>`"${u}" = ?`).join(", "),{sql:i,params:l}=P(n,r,s);return{sql:`UPDATE "${e}" SET ${o} ${i}`.trim(),params:[...a.map(([,u])=>u),...l]}}function Wt(e){return e.replace(/'/g,"''")}function V(e,t){if(!t)return`"${e}"`;let n=t.columnByPath.get(e);if(n)return`"${n.name}"`;let r=e.split(".");for(let s=r.length-1;s>=1;s--){let a=r.slice(0,s).join("."),o=r.slice(s).join("."),i=t.columnByPath.get(a);if(i&&i.sqlType==="TEXT")return`JSON_EXTRACT("${i.name.replace(/"/g,'""')}", '$.${Wt(o)}')`}return`"${e}"`}function at(e,t,n,r){let{sql:s,params:a}=P(t.where,t.includeDeleted?void 0:n,r),o=[];if(t.groupBy)for(let d of t.groupBy){let p=V(d,r);o.push(`${p} as "${d.replace(/"/g,'""')}"`)}for(let[d,p]of Object.entries(t.aggregations))if("sum"in p&&p.sum)o.push(`SUM(${V(p.sum,r)}) as "${d}"`);else if("count"in p&&p.count)o.push(`COUNT(${p.count==="*"?"*":V(p.count,r)}) as "${d}"`);else if("avg"in p&&p.avg)o.push(`AVG(${V(p.avg,r)}) as "${d}"`);else if("min"in p&&p.min)o.push(`MIN(${V(p.min,r)}) as "${d}"`);else if("max"in p&&p.max)o.push(`MAX(${V(p.max,r)}) as "${d}"`);let i=t.groupBy?`GROUP BY ${t.groupBy.map((d)=>V(d,r)).join(", ")}`:"",l=[],u=[];if(t.having){for(let[d,p]of Object.entries(t.having))if(p&&typeof p==="object"&&!Array.isArray(p)){let h=Le(d,p,r);l.push(h.sql),u.push(...h.params)}}let m=l.length>0?`HAVING ${l.join(" AND ")}`:"";return{sql:`SELECT ${o.join(", ")} FROM "${e}" ${s} ${i} ${m}`.trim(),params:[...a,...u]}}function Ut(e,t,n,r){if("rowNumber"in t)return`ROW_NUMBER() OVER (${n}) as "${e}"`;if("rank"in t)return`RANK() OVER (${n}) as "${e}"`;if("denseRank"in t)return`DENSE_RANK() OVER (${n}) as "${e}"`;if("lead"in t){let s=Q(t.lead,r),a=t.offset??1;return`LEAD(${s}, ${a}) OVER (${n}) as "${e}"`}if("lag"in t){let s=Q(t.lag,r),a=t.offset??1;return`LAG(${s}, ${a}) OVER (${n}) as "${e}"`}return`"${e}"`}function lt(e,t,n,r){let{sql:s,params:a}=P(t.where,n,r),o=t.partitionBy&&t.partitionBy.length>0?`PARTITION BY ${t.partitionBy.map((h)=>Q(h,r)).join(", ")}`:"",i=t.orderBy?(Array.isArray(t.orderBy)?t.orderBy:[t.orderBy]).map((h)=>`${Q(h.column,r)} ${h.direction??"ASC"}`):[],l=i.length>0?`ORDER BY ${i.join(", ")}`:"",u=[o,l].filter(Boolean).join(" "),m=u?u:"ORDER BY (SELECT NULL)",c=[];for(let[h,T]of Object.entries(t.select))c.push(Ut(h,T,m,r));let d=t.limit!==void 0?`LIMIT ${t.limit}`:"";return{sql:[`SELECT ${c.join(", ")} FROM "${e}"`,s,d].filter(Boolean).join(" "),params:a}}class fe{buffer=[];maxBuffer;tableName;db;prepare;onFlush;timer;constructor(e,t,n={},r){if(this.tableName=e,this.db=t,this.maxBuffer=n.maxBuffer??1000,this.prepare=r.prepare,this.onFlush=r.onFlush,n.flushIntervalMs)this.timer=setInterval(()=>this.flush(),n.flushIntervalMs)}insert(e){let t=this.prepare(e);if(this.buffer.push(t),this.buffer.length>=this.maxBuffer)this.flush()}flush(){if(this.buffer.length===0)return;let e=this.buffer.splice(0,this.buffer.length);this.db.transaction(()=>{let t=pe(this.tableName,e);for(let{sql:n,params:r}of t)this.db.prepare(n).run(...r)}),this.onFlush?.(e)}close(){if(this.timer)clearInterval(this.timer);this.flush()}}var De={createdAt:"createdAt",updatedAt:"updatedAt"};function Pe(e,t){if(e===!1||!e)return{createdAt:null,updatedAt:null};let n=typeof e==="object"&&e.createdAt!==void 0?e.createdAt:De.createdAt,r=typeof e==="object"&&e.updatedAt!==void 0?e.updatedAt:De.updatedAt,s=new Set(t.columns.map((a)=>a.name));return{createdAt:s.has(n)?n:null,updatedAt:s.has(r)?r:null}}class he{tableName;meta;validator;db;descriptor;_entityProto=null;_timestampNames;_materialize;_materializeMany;_events;_executor;_codecs;setEventBus(e){this._events=e}setMetricsHook(e){this._executor=new le({db:this.db,tableName:this.tableName,metricsHook:e})}constructor(e,t,n){this.tableName=e,this.descriptor=t,this.db=n,this._executor=new le({db:n,tableName:this.tableName}),this.meta=J(e,t.schema,ne(t.generated)),this._timestampNames=Pe(t.timestamps,this.meta),this.validator=Ht(t.schema);let r=new Map;if(t.compression?.algorithm==="gzip")for(let s of t.compression.columns)r.set(s.name,nt);this._codecs=r;for(let s of this.meta.columns)if(this._codecs.has(s.name))s.sqlType="BLOB";if(this._migrate(),t.eviction){if(n.scheduler.schedule(`evict:${e}`,30000,()=>this._runEviction()),t.eviction.maxRows&&!t.eviction.lruColumn)console.warn(`[foxdb] table "${e}" has eviction.maxRows without lruColumn. Eviction will use PK order, which is not true LRU.`)}}_ensureSelectPk(e){let t=this.descriptor.primaryKey.name;if(e.select&&e.include&&!e.select.includes(t))return{...e,select:[...e.select,t]};return e}_fetchRows(e,t){let n=this.descriptor.primaryKey.name,r=this.descriptor.softDelete?.column;if(!(!e.select&&e.where&&Object.keys(e.where).length>0)){let{sql:h,params:T}=se(this.tableName,e,r,this.meta);return this._executor.all(h,T,t)}let a={...e,select:[n],include:void 0},{sql:o,params:i}=se(this.tableName,a,r,this.meta),u=this._executor.all(o,i,t).map((h)=>h[n]).filter((h)=>typeof h==="string"||typeof h==="number");if(u.length===0)return[];if(u.length>500){let{sql:h,params:T}=se(this.tableName,e,r,this.meta);return this._executor.all(h,T,t)}let m=u.map(()=>"?").join(", "),c=`SELECT * FROM "${this.tableName}" WHERE "${n}" IN (${m})`,d=this._executor.all(c,u,t),p=new Map(u.map((h,T)=>[h,T]));return d.sort((h,T)=>{let k=h[n],D=T[n],oe=p.get(k)??0,ie=p.get(D)??0;return oe-ie}),d}setMaterializer(e,t){this._materialize=e,this._materializeMany=t;let n=Object.create(null);Object.defineProperty(n,"materialize",{value:function(){return e(this)},writable:!1,enumerable:!1,configurable:!1}),this._entityProto=n}_wrap(e){if(!this._entityProto)return e;let t=Object.create(this._entityProto);return Object.assign(t,e),t}_record(e){return Object.fromEntries(Object.entries(e))}_assertPk(e){if(e===null||typeof e==="string"||typeof e==="number"||typeof e==="boolean"||typeof e==="bigint")return e;O("INSERT_INVALID_PK",`Primary key must be a scalar, got ${typeof e}`,{table:this.tableName})}_emit(e,t){if(!this._events)return;let n=Date.now(),s={...{table:this.tableName,operation:e,timestamp:n},...t},a=`${this.tableName}.${e}`;if(this._events.has(a))this._events.emit(a,s);let o;if(e.startsWith("find")||e==="count")o="read";else if(e==="delete"||e==="deleteWhere"||e==="flush")o="delete";else o="write";let i=`${this.tableName}.${o}`;if(this._events.has(i))this._events.emit(i,{...s,operation:o})}_migrate(){let e=this.descriptor.primaryKey.name,t=Ie(this.meta,e);this.db.transaction(()=>{for(let n of t)this.db.exec(n);for(let n of this.descriptor.indexes??[])this.db.exec(et(this.tableName,n.columns.map((r)=>r.name),n.unique??!1,n.name,n.where,n.include?.map((r)=>r.name)))}),this.db.clearCache()}_runEviction(){let e=this.descriptor.eviction;if(!e)return;let t=Date.now();if(e.ttlColumn&&e.ttlMs){let n=t-e.ttlMs;this._executor.exec(`DELETE FROM "${this.tableName}" WHERE "${e.ttlColumn}" < ?`,[n],"evict")}if(e.maxRows){let n=e.lruColumn??this.descriptor.primaryKey.name,s=this.db.prepare(`SELECT COUNT(*) as c FROM "${this.tableName}"`).get().c;if(s<=e.maxRows)return;let a=s-e.maxRows;this._executor.exec(`DELETE FROM "${this.tableName}" WHERE "${this.descriptor.primaryKey.name}" IN (
8
+ )`),n.push(`CREATE INDEX IF NOT EXISTS "idx_${s.tableName}__owner" ON "${s.tableName}" ("_owner_id")`)}return n}function et(e,t,n,r,s,a){let o=r??`idx_${e}__${t.join("_")}`,i=n?"UNIQUE ":"",l=t.map((d)=>`"${d}"`).join(", "),u=s?` WHERE ${s}`:"";return`CREATE ${i}INDEX IF NOT EXISTS "${o}" ON "${e}" (${l})${u}`}function ee(e,t){if(e===void 0||e===null)return null;if(t==="TEXT"&&typeof e==="object")return JSON.stringify(e);if(t==="INTEGER"&&typeof e==="boolean")return e?1:0;return Lt(e)}function te(e,t){let n=e;for(let r of t){if(n===null||n===void 0)return;if(typeof n!=="object")return;n=n[r]}return n}function Z(e,t,n){let r=e;for(let s=0;s<t.length-1;s++){let a=t[s];if(!(a in r))r[a]={};r=r[a]}r[t[t.length-1]]=n}function U(e,t,n){let r={};if(!n?.size)for(let s of t.columns){if(s.generated)continue;let a=s.path?te(e,s.path):e[s.name];r[s.name]=ee(a,s.sqlType)}else for(let s of t.columns){if(s.generated)continue;let a=s.path?te(e,s.path):e[s.name],o=ee(a,s.sqlType),i=n.get(s.name);if(i)o=i.encode(o);r[s.name]=o}return r}function tt(e,t,n){let r={};for(let s of t.columns){if(s.generated)continue;if(!(s.name in e)&&!s.path)continue;let a;if(s.path)a=te(e,s.path);else a=e[s.name];if(a===void 0)continue;let o=ee(a,s.sqlType),i=n?.get(s.name);if(i)o=i.encode(o);r[s.name]=o}return r}function X(e,t,n,r){let s=Array(t.length);if(!r?.size)for(let a=0;a<t.length;a++){let o=t[a];if(o===null||typeof o!=="object")throw TypeError("Sub-table item must be an object");let i=o,l={_owner_id:e,_index:a};for(let u of n.columns){let d=u.path?te(i,u.path):i[u.name];l[u.name]=ee(d,u.sqlType)}s[a]=l}else for(let a=0;a<t.length;a++){let o=t[a];if(o===null||typeof o!=="object")throw TypeError("Sub-table item must be an object");let i=o,l={_owner_id:e,_index:a};for(let u of n.columns){let d=u.path?te(i,u.path):i[u.name],c=ee(d,u.sqlType),m=r.get(u.name);if(m)c=m.encode(c);l[u.name]=c}s[a]=l}return s}function Lt(e){if(e===null||e===void 0)return null;if(typeof e==="string"||typeof e==="number"||typeof e==="boolean"||typeof e==="bigint")return e;if(typeof e==="object")return JSON.stringify(e);return String(e)}function ce(e,t,n){if(t==="TEXT"&&typeof e==="string"){let r=e.charCodeAt(0);if(r===123||r===91)try{let s=JSON.parse(e);return typeof s==="object"?s:e}catch{return e}return e}if(t==="INTEGER"&&typeof e==="number")return n?e===1:e;return e??null}function Dt(e,t){let n={};for(let r of t.columns){let s=ce(e[r.name],r.sqlType,r.isBoolean);if(r.path)if(r.path.length===1)n[r.path[0]]=s;else Z(n,r.path,s);else n[r.name]=s}return n}function de(e,t,n,r,s,a){if(!r?.size&&!s&&!t.subTables.length)return Dt(e,t);let o={};if(!s)if(!r?.size)for(let i of t.columns){let l=ce(e[i.name],i.sqlType,i.isBoolean);if(i.path)if(i.path.length===1)o[i.path[0]]=l;else Z(o,i.path,l);else o[i.name]=l}else for(let i of t.columns){let l=e[i.name],u=r.get(i.name);if(u)l=u.decode(l);let d=ce(l,i.sqlType,i.isBoolean);if(i.path)if(i.path.length===1)o[i.path[0]]=d;else Z(o,i.path,d);else o[i.name]=d}else{let i=new Set;for(let l of s)if(i.add(l),!l.includes(".")){for(let u of t.columns)if(u.path&&u.path[0]===l)i.add(u.name)}else{let u=t.columnByPath.get(l);if(u)i.add(u.name)}for(let l of t.columns){if(!i.has(l.name))continue;let u=e[l.name],d=r?.get(l.name);if(d)u=d.decode(u);let c=ce(u,l.sqlType,l.isBoolean);if(l.path)if(l.path.length===1)o[l.path[0]]=c;else Z(o,l.path,c);else o[l.name]=c}for(let l of Object.keys(e)){if(i.has(l))continue;if(l.includes("__")){let u=l.split("__"),d=e[l];if(typeof d==="string"){let c=d.charCodeAt(0);if(c===123||c===91)try{let m=JSON.parse(d);if(typeof m==="object")d=m}catch{}}Z(o,u,d)}}}for(let i of t.subTables)if(a&&!a.includes(i.fieldName))o[i.fieldName]=[];else o[i.fieldName]=n.get(i.tableName)??[];return o}var nt={encode(e){if(typeof e!=="string")return e;let t=new TextEncoder().encode(e);return Bun.gzipSync(t.buffer)},decode(e){if(!(e instanceof Uint8Array))return e;return new TextDecoder().decode(Bun.gunzipSync(e.buffer))}};function Pt(e){return typeof e==="object"&&e!==null}function ve(e){return e.replace(/'/g,"''")}function Qt(e,t){let n=e.split(".");if(n.length<2)return null;if(t){let o=t.columnByPath.get(e);if(o)return{sql:`"${o.name}"`};for(let i=n.length-1;i>=1;i--){let l=n.slice(0,i).join("."),u=n.slice(i).join("."),d=t.columnByPath.get(l);if(d&&d.sqlType==="TEXT")return{sql:`JSON_EXTRACT("${d.name.replace(/"/g,'""')}", '$.${ve(u)}')`}}}let r=n[0],s=n.slice(1).join(".");return{sql:`JSON_EXTRACT("${r.replace(/"/g,'""')}", '$.${ve(s)}')`}}function D(e){if(e!==null&&typeof e==="object")return JSON.stringify(e);return e}function Be(e,t,n){let r=Qt(e,n),s=r?r.sql:`"${e}"`,a=[],o=[];if("eq"in t)a.push(`${s} = ?`),o.push(D(t.eq));if("ne"in t)a.push(`${s} != ?`),o.push(D(t.ne));if("gt"in t)a.push(`${s} > ?`),o.push(D(t.gt));if("gte"in t)a.push(`${s} >= ?`),o.push(D(t.gte));if("lt"in t)a.push(`${s} < ?`),o.push(D(t.lt));if("lte"in t)a.push(`${s} <= ?`),o.push(D(t.lte));if("like"in t)a.push(`${s} LIKE ?`),o.push(D(t.like));if("between"in t){let[i,l]=t.between;a.push(`${s} BETWEEN ? AND ?`),o.push(D(i),D(l))}if("in"in t){let i=t.in,l=i.map(()=>"?").join(", ");a.push(`${s} IN (${l})`),o.push(...i.map(D))}if("notIn"in t){let i=t.notIn,l=i.map(()=>"?").join(", ");a.push(`${s} NOT IN (${l})`),o.push(...i.map(D))}if("isNull"in t)a.push(`${s} IS NULL`);if("isNotNull"in t)a.push(`${s} IS NOT NULL`);if("arraySome"in t)a.push(`EXISTS (SELECT 1 FROM json_each(${s}) WHERE value = ?)`),o.push(D(t.arraySome));if("arrayNot"in t)a.push(`NOT EXISTS (SELECT 1 FROM json_each(${s}) WHERE value = ?)`),o.push(D(t.arrayNot));if("isEmpty"in t)if(t.isEmpty)a.push(`(json_array_length(${s}) = 0 OR ${s} IS NULL)`);else a.push(`json_array_length(${s}) > 0`);if("fastArrayIsEmpty"in t)if(t.fastArrayIsEmpty)a.push(`(${s} = '[]' OR ${s} IS NULL)`);else a.push(`(${s} != '[]' AND ${s} IS NOT NULL)`);if("fastArraySome"in t){let i=JSON.stringify([t.fastArraySome]),l=i.substring(1,i.length-1);a.push(`(',' || REPLACE(REPLACE(${s}, '[', ''), ']', '') || ',') LIKE ?`),o.push(`%,${l},%`)}if("fastArrayNot"in t){let i=JSON.stringify([t.fastArrayNot]),l=i.substring(1,i.length-1);a.push(`(',' || REPLACE(REPLACE(${s}, '[', ''), ']', '') || ',') NOT LIKE ?`),o.push(`%,${l},%`)}if(a.length===0)N("UNKNOWN_FILTER",`foxdb: unknown filter operator for column "${e}"`,{column:e});return{sql:a.join(" AND "),params:o}}function jt(e){if(typeof e!=="object"||e===null)return!1;let t=e;if("AND"in t&&Array.isArray(t.AND))return!0;if("OR"in t&&Array.isArray(t.OR))return!0;if("NOT"in t&&typeof t.NOT==="object"&&t.NOT!==null)return!0;return!1}function Y(e){if(!e||typeof e!=="object"||Object.keys(e).length===0)return!0;let t=e,n=Object.keys(t);if(n.length===1&&n[0]==="AND"&&Array.isArray(t.AND)&&t.AND.length===0)return!0;if(n.length===1&&n[0]==="OR"&&Array.isArray(t.OR)&&t.OR.some(Y))return!0;if(n.length===1&&n[0]==="NOT"&&re(t.NOT))return!0;return!1}function re(e){if(!e||typeof e!=="object")return!1;let t=e,n=Object.keys(t);if(n.length===1&&n[0]==="OR"&&Array.isArray(t.OR)&&t.OR.length===0)return!0;if(n.length===1&&n[0]==="AND"&&Array.isArray(t.AND)&&t.AND.some(re))return!0;if(n.length===1&&n[0]==="NOT"&&Y(t.NOT))return!0;return!1}function me(e,t,n){let r=[],s=[];if(t)r.push(`"${t}" IS NULL`);if(!e||Object.keys(e).length===0){if(r.length===0)return{sql:"",params:[]};return{sql:`WHERE ${r.join(" AND ")}`,params:s}}if(jt(e)){let o=e;if(o.AND)for(let i of o.AND){if(Y(i))continue;if(re(i)){if(r.push("1=0"),r.length===1)return{sql:"WHERE 1=0",params:[]};return{sql:`WHERE ${r.join(" AND ")}`,params:s}}let l=me(i,void 0,n);if(l.sql)r.push(`(${l.sql.replace(/^WHERE\s+/,"")})`),s.push(...l.params)}if(o.OR){let i=[],l=[];for(let u of o.OR){if(Y(u)){i.length=0;break}if(re(u))continue;let d=me(u,void 0,n);if(d.sql)i.push(d.sql.replace(/^WHERE\s+/,"")),l.push(...d.params)}if(i.length>0)r.push(`(${i.join(" OR ")})`),s.push(...l);else if(!o.OR.some(Y))r.push("1=0")}if(o.NOT){if(Y(o.NOT))r.push("1=0");else if(!re(o.NOT)){let i=me(o.NOT,void 0,n);if(i.sql)r.push(`NOT (${i.sql.replace(/^WHERE\s+/,"")})`),s.push(...i.params)}}}let a=e._raw;if(a&&typeof a==="object"&&"sql"in a){let o=a;r.push(`(${o.sql})`),s.push(...o.params??[])}for(let[o,i]of Object.entries(e)){if(o==="AND"||o==="OR"||o==="NOT"||o==="_raw")continue;if(!Pt(i))continue;let l=Be(o,i,n);r.push(l.sql),s.push(...l.params)}if(r.length===0)return{sql:"",params:[]};return{sql:`WHERE ${r.join(" AND ")}`,params:s}}function P(e,t,n){return me(e,t,n)}function Q(e,t){if(!t)return`"${e}"`;let n=t.columnByPath.get(e);if(n)return`"${n.name}"`;let r=e.split(".");for(let s=r.length-1;s>=1;s--){let a=r.slice(0,s).join("."),o=r.slice(s).join("."),i=t.columnByPath.get(a);if(i&&i.sqlType==="TEXT")return`JSON_EXTRACT("${i.name.replace(/"/g,'""')}", '$.${ve(o)}')`}return`"${e}"`}function qt(e,t){if(!e)return"";let n=globalThis.Array.isArray(e)?e:[e];if(n.length===0)return"";return`ORDER BY ${n.map((s)=>{return`${Q(s.column,t)} ${s.direction??"ASC"}`}).join(", ")}`}function Ft(e,t){let n=[],r=[];if(e!==void 0)n.push("LIMIT ?"),r.push(e);if(t!==void 0)n.push("OFFSET ?"),r.push(t);return{sql:n.join(" "),params:r}}function Kt(e,t){let n=t.columnByName.get(e)||t.columnByPath.get(e);if(n)return[`"${n.name}"`];let r=[];for(let a of t.columns)if(a.path&&a.path[0]===e)r.push(`"${a.name}"`);if(r.length>0)return r;let s=e.split(".");for(let a=s.length-1;a>=1;a--){let o=s.slice(0,a).join("."),i=s.slice(a).join("."),l=t.columnByPath.get(o);if(l&&l.sqlType==="TEXT"){let u=s.join("__");return[`JSON_EXTRACT("${l.name}", '$.${i.replace(/'/g,"''")}') as "${u}"`]}}return[`"${e}"`]}function Le(e,t,n,r){let{sql:s,params:a}=P(t.where,t.includeDeleted?void 0:n,r),o=qt(t.orderBy,r),{sql:i,params:l}=Ft(t.limit,t.offset),u=t.select&&r?t.select.flatMap((f)=>Kt(f,r)).join(", "):"*";if(t.distinctOn&&t.distinctOn.length>0){let f=t.distinctOn.map((S)=>Q(S,r)).join(", "),h=[`SELECT ${u} FROM "${e}"`,s,`GROUP BY ${f}`,o,i].filter(Boolean).join(" "),T=[`SELECT COUNT(*) as "_count" FROM (SELECT 1 FROM "${e}"`,s,`GROUP BY ${f})`].filter(Boolean).join(" ");return{sql:h,params:[...a,...l],countSql:T,countParams:a}}let c=[`SELECT ${t.distinct?"DISTINCT ":""}${u} FROM "${e}"`,s,o,i].filter(Boolean).join(" "),m;if(t.distinct)m=[`SELECT COUNT(*) as "_count" FROM (SELECT DISTINCT ${u} FROM "${e}"`,s,")"];else m=[`SELECT COUNT(*) as "_count" FROM "${e}"`,s];return{sql:c,params:[...a,...l],countSql:m.filter(Boolean).join(" "),countParams:a}}function se(e,t,n,r){return Le(e,t,n,r)}function H(e,t){let n=Object.keys(t),r=n.map((a)=>`"${a}"`).join(", "),s=n.map(()=>"?").join(", ");return{sql:`INSERT INTO "${e}" (${r}) VALUES (${s})`,params:n.map((a)=>t[a])}}function pe(e,t,n=999){if(t.length===0)return[];let r=t[0],s=Object.keys(r),a=s.length,o=Math.floor(n/a);if(o<=0)N("TOO_MANY_COLUMNS",`foxdb: table "${e}" has too many columns for multi-value insert`);let i=[];for(let l=0;l<t.length;l+=o){let u=t.slice(l,l+o),d=s.map((f)=>`"${f}"`).join(", "),c=u.map(()=>{return`(${s.map(()=>"?").join(", ")})`}).join(", "),m=u.flatMap((f)=>s.map((h)=>f[h]));i.push({sql:`INSERT INTO "${e}" (${d}) VALUES ${c}`,params:m})}return i}function rt(e,t,n,r){let s=Object.keys(t),a=s.map((u)=>`"${u}"`).join(", "),o=s.map(()=>"?").join(", "),i=n.map((u)=>`"${u}"`).join(", "),l=r.map((u)=>`"${u}" = excluded."${u}"`).join(", ");return{sql:`INSERT INTO "${e}" (${a}) VALUES (${o}) ON CONFLICT (${i}) DO UPDATE SET ${l}`,params:s.map((u)=>t[u])}}function st(e,t,n,r,s=999){if(t.length===0)return[];let a=t[0],o=Object.keys(a),i=o.length,l=Math.floor(s/i);if(l<=0)N("TOO_MANY_COLUMNS",`foxdb: table "${e}" has too many columns for multi-value upsert`);let u=n.map((m)=>`"${m}"`).join(", "),d=r.map((m)=>`"${m}" = excluded."${m}"`).join(", "),c=[];for(let m=0;m<t.length;m+=l){let f=t.slice(m,m+l),h=o.map((v)=>`"${v}"`).join(", "),T=f.map(()=>{return`(${o.map(()=>"?").join(", ")})`}).join(", "),S=f.flatMap((v)=>o.map((oe)=>v[oe]));c.push({sql:`INSERT INTO "${e}" (${h}) VALUES ${T} ON CONFLICT (${u}) DO UPDATE SET ${d}`,params:S})}return c}function ot(e,t,n,r){let s=Object.entries(r).filter(([o])=>o!==t);if(s.length===0)N("NO_COLUMNS_TO_UPDATE","foxdb: no columns to update",{table:e});let a=s.map(([o])=>`"${o}" = ?`).join(", ");return{sql:`UPDATE "${e}" SET ${a} WHERE "${t}" = ?`,params:[...s.map(([,o])=>o),n]}}function at(e,t,n,r,s){let a=Object.entries(t);if(a.length===0)N("NO_COLUMNS_TO_UPDATE","foxdb: no columns to update",{table:e});let o=a.map(([u])=>`"${u}" = ?`).join(", "),{sql:i,params:l}=P(n,r,s);return{sql:`UPDATE "${e}" SET ${o} ${i}`.trim(),params:[...a.map(([,u])=>u),...l]}}function Wt(e){return e.replace(/'/g,"''")}function V(e,t,n){if(!t)return`"${e}"`;if(n&&e.startsWith(n+".")){let a=e.slice(n.length+1),o=t.columnByPath.get(a);if(o)return`"${o.name}"`;return`"${a}"`}let r=t.columnByPath.get(e);if(r)return`"${r.name}"`;let s=e.split(".");for(let a=s.length-1;a>=1;a--){let o=s.slice(0,a).join("."),i=s.slice(a).join("."),l=t.columnByPath.get(o);if(l&&l.sqlType==="TEXT")return`JSON_EXTRACT("${l.name.replace(/"/g,'""')}", '$.${Wt(i)}')`}return`"${e}"`}function Ut(e,t){let n=e.subTables.find((r)=>r.fieldName===t);if(!n)return;return{tableName:n.tableName,columnByPath:n.columnByPath}}function it(e,t,n,r){let s=t.subTable&&r?Ut(r,t.subTable):void 0,a=s?.tableName??e,o=s?{...r,columnByPath:s.columnByPath}:r,{sql:i,params:l}=P(t.where,t.subTable?void 0:t.includeDeleted?void 0:n,o),u=[];if(t.groupBy)for(let T of t.groupBy){let S=V(T,o,s?.tableName);u.push(`${S} as "${T.replace(/"/g,'""')}"`)}for(let[T,S]of Object.entries(t.aggregations))if("sum"in S&&S.sum)u.push(`SUM(${V(S.sum,o,s?.tableName)}) as "${T}"`);else if("count"in S&&S.count)u.push(`COUNT(${S.count==="*"?"*":V(S.count,o,s?.tableName)}) as "${T}"`);else if("avg"in S&&S.avg)u.push(`AVG(${V(S.avg,o,s?.tableName)}) as "${T}"`);else if("min"in S&&S.min)u.push(`MIN(${V(S.min,o,s?.tableName)}) as "${T}"`);else if("max"in S&&S.max)u.push(`MAX(${V(S.max,o,s?.tableName)}) as "${T}"`);let d=t.groupBy?`GROUP BY ${t.groupBy.map((T)=>V(T,o,s?.tableName)).join(", ")}`:"",c=[],m=[];if(t.having){for(let[T,S]of Object.entries(t.having))if(S&&typeof S==="object"&&!Array.isArray(S)){let v=Be(T,S,o);c.push(v.sql),m.push(...v.params)}}let f=c.length>0?`HAVING ${c.join(" AND ")}`:"";return{sql:`SELECT ${u.join(", ")} FROM "${a}" ${i} ${d} ${f}`.trim(),params:[...l,...m]}}function Ht(e,t,n,r){if("rowNumber"in t)return`ROW_NUMBER() OVER (${n}) as "${e}"`;if("rank"in t)return`RANK() OVER (${n}) as "${e}"`;if("denseRank"in t)return`DENSE_RANK() OVER (${n}) as "${e}"`;if("lead"in t){let s=Q(t.lead,r),a=t.offset??1;return`LEAD(${s}, ${a}) OVER (${n}) as "${e}"`}if("lag"in t){let s=Q(t.lag,r),a=t.offset??1;return`LAG(${s}, ${a}) OVER (${n}) as "${e}"`}return`"${e}"`}function lt(e,t,n,r){let{sql:s,params:a}=P(t.where,n,r),o=t.partitionBy&&t.partitionBy.length>0?`PARTITION BY ${t.partitionBy.map((h)=>Q(h,r)).join(", ")}`:"",i=t.orderBy?(Array.isArray(t.orderBy)?t.orderBy:[t.orderBy]).map((h)=>{return`${Q(h.column,r)} ${h.direction??"ASC"}`}):[],l=i.length>0?`ORDER BY ${i.join(", ")}`:"",u=[o,l].filter(Boolean).join(" "),d=u?u:"ORDER BY (SELECT NULL)",c=[];for(let[h,T]of Object.entries(t.select))c.push(Ht(h,T,d,r));let m=t.limit!==void 0?`LIMIT ${t.limit}`:"";return{sql:[`SELECT ${c.join(", ")} FROM "${e}"`,s,m].filter(Boolean).join(" "),params:a}}class fe{buffer=[];maxBuffer;tableName;db;prepare;onFlush;timer;constructor(e,t,n={},r){if(this.tableName=e,this.db=t,this.maxBuffer=n.maxBuffer??1000,this.prepare=r.prepare,this.onFlush=r.onFlush,n.flushIntervalMs)this.timer=setInterval(()=>this.flush(),n.flushIntervalMs)}insert(e){let t=this.prepare(e);if(this.buffer.push(t),this.buffer.length>=this.maxBuffer)this.flush()}flush(){if(this.buffer.length===0)return;let e=this.buffer.splice(0,this.buffer.length);this.db.transaction(()=>{let t=pe(this.tableName,e);for(let{sql:n,params:r}of t)this.db.prepare(n).run(...r)}),this.onFlush?.(e)}close(){if(this.timer)clearInterval(this.timer);this.flush()}}var De={createdAt:"createdAt",updatedAt:"updatedAt"};function Pe(e,t){if(e===!1||!e)return{createdAt:null,updatedAt:null};let n=typeof e==="object"&&e.createdAt!==void 0?e.createdAt:De.createdAt,r=typeof e==="object"&&e.updatedAt!==void 0?e.updatedAt:De.updatedAt,s=new Set(t.columns.map((a)=>a.name));return{createdAt:s.has(n)?n:null,updatedAt:s.has(r)?r:null}}class he{tableName;meta;getSubTableName(e){return this.meta.subTables.find((t)=>t.fieldName===e)?.tableName}validator;db;descriptor;_entityProto=null;_timestampNames;_materialize;_materializeMany;_events;_executor;_codecs;setEventBus(e){this._events=e}setMetricsHook(e){this._executor=new le({db:this.db,tableName:this.tableName,metricsHook:e})}constructor(e,t,n){this.tableName=e,this.descriptor=t,this.db=n,this._executor=new le({db:n,tableName:this.tableName}),this.meta=J(e,t.schema,ne(t.generated)),this._timestampNames=Pe(t.timestamps,this.meta),this.validator=Vt(t.schema);let r=new Map;if(t.compression?.algorithm==="gzip")for(let s of t.compression.columns)r.set(s.name,nt);this._codecs=r;for(let s of this.meta.columns)if(this._codecs.has(s.name))s.sqlType="BLOB";if(this._migrate(),t.eviction){if(n.scheduler.schedule(`evict:${e}`,30000,()=>this._runEviction()),t.eviction.maxRows&&!t.eviction.lruColumn)console.warn(`[foxdb] table "${e}" has eviction.maxRows without lruColumn. Eviction will use PK order, which is not true LRU.`)}}_ensureSelectPk(e){let t=this.descriptor.primaryKey.name;if(e.select&&e.include&&!e.select.includes(t))return{...e,select:[...e.select,t]};return e}_fetchRows(e,t){let n=this.descriptor.primaryKey.name,r=this.descriptor.softDelete?.column;if(!(!e.select&&e.where&&Object.keys(e.where).length>0)){let{sql:h,params:T}=se(this.tableName,e,r,this.meta);return this._executor.all(h,T,t)}let a={...e,select:[n],include:void 0},{sql:o,params:i}=se(this.tableName,a,r,this.meta),u=this._executor.all(o,i,t).map((h)=>h[n]).filter((h)=>typeof h==="string"||typeof h==="number");if(u.length===0)return[];if(u.length>500){let{sql:h,params:T}=se(this.tableName,e,r,this.meta);return this._executor.all(h,T,t)}let d=u.map(()=>"?").join(", "),c=`SELECT * FROM "${this.tableName}" WHERE "${n}" IN (${d})`,m=this._executor.all(c,u,t),f=new Map(u.map((h,T)=>[h,T]));return m.sort((h,T)=>{let S=h[n],v=T[n],oe=f.get(S)??0,ae=f.get(v)??0;return oe-ae}),m}setMaterializer(e,t){this._materialize=e,this._materializeMany=t;let n=Object.create(null);Object.defineProperty(n,"materialize",{value:function(){return e(this)},writable:!1,enumerable:!1,configurable:!1}),this._entityProto=n}_wrap(e){if(!this._entityProto)return e;let t=Object.create(this._entityProto);return Object.assign(t,e),t}_record(e){return Object.fromEntries(Object.entries(e))}_assertPk(e){if(e===null||typeof e==="string"||typeof e==="number"||typeof e==="boolean"||typeof e==="bigint")return e;N("INSERT_INVALID_PK",`Primary key must be a scalar, got ${typeof e}`,{table:this.tableName})}_emit(e,t){if(!this._events)return;let n=Date.now(),s={...{table:this.tableName,operation:e,timestamp:n},...t},a=`${this.tableName}.${e}`;if(this._events.has(a))this._events.emit(a,s);let o;if(e.startsWith("find")||e==="count")o="read";else if(e==="delete"||e==="deleteWhere"||e==="flush")o="delete";else o="write";let i=`${this.tableName}.${o}`;if(this._events.has(i))this._events.emit(i,{...s,operation:o})}_migrate(){let e=this.descriptor.primaryKey.name,t=Ie(this.meta,e);this.db.transaction(()=>{for(let n of t)this.db.exec(n);for(let n of this.descriptor.indexes??[])this.db.exec(et(this.tableName,n.columns.map((r)=>r.name),n.unique??!1,n.name,n.where,n.include?.map((r)=>r.name)))}),this.db.clearCache()}_runEviction(){let e=this.descriptor.eviction;if(!e)return;let t=Date.now();if(e.ttlColumn&&e.ttlMs){let n=t-e.ttlMs;this._executor.exec(`DELETE FROM "${this.tableName}" WHERE "${e.ttlColumn}" < ?`,[n],"evict")}if(e.maxRows){let n=e.lruColumn??this.descriptor.primaryKey.name,s=this.db.prepare(`SELECT COUNT(*) as c FROM "${this.tableName}"`).get().c;if(s<=e.maxRows)return;let a=s-e.maxRows;this._executor.exec(`DELETE FROM "${this.tableName}" WHERE "${this.descriptor.primaryKey.name}" IN (
9
9
  SELECT "${this.descriptor.primaryKey.name}" FROM "${this.tableName}"
10
10
  ORDER BY "${n}" ASC
11
11
  LIMIT ?
12
- )`,[a],"evict")}}parse(e){return this.validator.Parse(e)}check(e){return this.validator.Check(e)}insert(e){return C("repository.insert",{table:this.tableName},()=>{let t=this.parse(e),n=this._record(t),r=Date.now();if(this._timestampNames.createdAt)n[this._timestampNames.createdAt]=r;if(this._timestampNames.updatedAt)n[this._timestampNames.updatedAt]=r;if(this.db.transaction(()=>{let s=U(n,this.meta,this._codecs),{sql:a,params:o}=H(this.tableName,s);this._executor.exec(a,o,"insert");let i=n[this.descriptor.primaryKey.name];for(let l of this.meta.subTables){let u=n[l.fieldName];if(!globalThis.Array.isArray(u)||u.length===0)continue;let m=X(this._assertPk(i),u,l,this._codecs);for(let c of m){let{sql:d,params:p}=H(l.tableName,c);this._executor.exec(d,p,"insert")}}}),this.descriptor.eviction)this._runEviction();return this._emit("insert",{data:n}),this._wrap(n)})}insertMany(e){return C("repository.insertMany",{table:this.tableName},()=>{let n=e.map((s)=>this.parse(s)).map((s)=>{let a=this._record(s),o=Date.now();if(this._timestampNames.createdAt)a[this._timestampNames.createdAt]=o;if(this._timestampNames.updatedAt)a[this._timestampNames.updatedAt]=o;return a}),r=n.map((s)=>U(s,this.meta,this._codecs));if(this.db.transaction(()=>{let s=pe(this.tableName,r);for(let{sql:a,params:o}of s)this._executor.exec(a,o,"insertMany");for(let a of n){let o=a[this.descriptor.primaryKey.name];for(let i of this.meta.subTables){let l=a[i.fieldName];if(!globalThis.Array.isArray(l)||l.length===0)continue;let u=X(this._assertPk(o),l,i,this._codecs);for(let m of u){let{sql:c,params:d}=H(i.tableName,m);this._executor.exec(c,d,"insertMany")}}}}),this.descriptor.eviction)this._runEviction();return this._emit("insertMany",{data:n}),n.map((s)=>this._wrap(s))})}createBatchWriter(e){let t=this;return new fe(this.tableName,this.db,e,{prepare(n){let r=t.parse(n),s=t._record(r),a=Date.now();if(t._timestampNames.createdAt)s[t._timestampNames.createdAt]=a;if(t._timestampNames.updatedAt)s[t._timestampNames.updatedAt]=a;return U(s,t.meta,t._codecs)},onFlush(n){if(t._emit("insertMany",{data:n}),t.descriptor.eviction&&Math.random()<0.2)t._runEviction()}})}upsert(e){return C("repository.upsert",{table:this.tableName},()=>{let t=this.parse(e.data),n=this._record(t),r=Date.now();if(this._timestampNames.createdAt)n[this._timestampNames.createdAt]=r;if(this._timestampNames.updatedAt)n[this._timestampNames.updatedAt]=r;let s=U(n,this.meta,this._codecs),a=globalThis.Array.isArray(e.conflictTarget)?e.conflictTarget:[e.conflictTarget],o=Object.keys(s),i=e.update??o.filter((l)=>!a.includes(l));if(this.descriptor.softDelete&&!i.includes(this.descriptor.softDelete.column))i.push(this.descriptor.softDelete.column),s[this.descriptor.softDelete.column]=null;if(this.db.transaction(()=>{let{sql:l,params:u}=rt(this.tableName,s,a,i);this._executor.exec(l,u,"upsert");let m=n[this.descriptor.primaryKey.name];for(let c of this.meta.subTables){this._executor.exec(`DELETE FROM "${c.tableName}" WHERE "_owner_id" = ?`,[m],"delete");let d=n[c.fieldName];if(!globalThis.Array.isArray(d)||d.length===0)continue;let p=X(this._assertPk(m),d,c,this._codecs);for(let h of p){let{sql:T,params:k}=H(c.tableName,h);this._executor.exec(T,k,"insert")}}}),this.descriptor.eviction)this._runEviction();return this._emit("upsert",{data:t}),this._wrap(this._record(t))})}upsertMany(e){return C("repository.upsertMany",{table:this.tableName},()=>{let n=e.data.map((l)=>this.parse(l)).map((l)=>{let u=this._record(l),m=Date.now();if(this._timestampNames.createdAt)u[this._timestampNames.createdAt]=m;if(this._timestampNames.updatedAt)u[this._timestampNames.updatedAt]=m;return u}),r=n.map((l)=>U(l,this.meta,this._codecs)),s=globalThis.Array.isArray(e.conflictTarget)?e.conflictTarget:[e.conflictTarget],a=Object.keys(r[0]??{}),o=e.update??a.filter((l)=>!s.includes(l));if(this.descriptor.softDelete&&!o.includes(this.descriptor.softDelete.column)){o.push(this.descriptor.softDelete.column);for(let l of r)l[this.descriptor.softDelete.column]=null}let i=0;if(this.db.transaction(()=>{let l=st(this.tableName,r,s,o);for(let{sql:u,params:m}of l){let c=this._executor.exec(u,m,"upsertMany");i+=c.changes}for(let u of n){let m=u[this.descriptor.primaryKey.name];for(let c of this.meta.subTables){this._executor.exec(`DELETE FROM "${c.tableName}" WHERE "_owner_id" = ?`,[m],"delete");let d=u[c.fieldName];if(!globalThis.Array.isArray(d)||d.length===0)continue;let p=X(this._assertPk(m),d,c,this._codecs);for(let h of p){let{sql:T,params:k}=H(c.tableName,h);this._executor.exec(T,k,"insert")}}}}),this.descriptor.eviction)this._runEviction();return this._emit("upsertMany",{data:n,result:i}),i})}findById(e){return C("repository.findById",{table:this.tableName},()=>{let t=this._findByIdRaw(e);return this._emit("findById",{id:e,result:t}),t})}_findByIdRaw(e){let t=this.descriptor.primaryKey.name,n=this.descriptor.softDelete?`SELECT * FROM "${this.tableName}" WHERE "${t}" = ? AND "${this.descriptor.softDelete.column}" IS NULL LIMIT 1`:`SELECT * FROM "${this.tableName}" WHERE "${t}" = ? LIMIT 1`,r=this._executor.get(n,[e],"findById");if(!r)return null;if(this.descriptor.eviction?.lruColumn&&Math.random()<0.1){let s=this.descriptor.eviction.lruColumn,a=this.descriptor.primaryKey.name;Promise.resolve().then(()=>{try{this._executor.exec(`UPDATE "${this.tableName}" SET "${s}" = ? WHERE "${a}" = ?`,[Date.now(),e])}catch{}})}return this._wrap(this._hydrateOne(r))}findMany(e={}){return C("repository.findMany",{table:this.tableName},()=>{let t=e.select&&e.include?this._ensureSelectPk({...e,select:e.select}):e,n=this._fetchRows(t,"findMany");if(this.descriptor.eviction?.lruColumn){let i=this.descriptor.eviction.lruColumn,l=this.descriptor.primaryKey.name,u=[];for(let m of n)if(Math.random()<0.1){let c=m[l];if(typeof c==="string"||typeof c==="number")u.push(c)}if(u.length>0){let m=Date.now(),c=u.map(()=>"?").join(", ");Promise.resolve().then(()=>{try{this._executor.exec(`UPDATE "${this.tableName}" SET "${i}" = ? WHERE "${l}" IN (${c})`,[m,...u])}catch{}})}}let r=this.descriptor.primaryKey.name,s=n.map((i)=>i[r]).filter((i)=>typeof i==="string"||typeof i==="number"),a=new Map;for(let i of this.meta.subTables){if(!(!e.include||e.include.some((d)=>d===i.fieldName)))continue;if(s.length===0)continue;let u=s.map(()=>"?").join(", "),m=this._executor.all(`SELECT * FROM "${i.tableName}" WHERE "_owner_id" IN (${u}) ORDER BY "_index" ASC`,s,"findMany"),c=new Map;for(let d of m){let p=d._owner_id;if(typeof p!=="string"&&typeof p!=="number")continue;if(!c.has(p))c.set(p,[]);c.get(p).push(d)}a.set(i.tableName,c)}let o=n.map((i)=>{let l=new Map;for(let u of this.meta.subTables){if(!(!e.include||e.include.some((h)=>h===u.fieldName)))continue;let c=a.get(u.tableName),d=i[r],p=typeof d==="string"||typeof d==="number"?d:void 0;l.set(u.tableName,p!==void 0?c?.get(p)??[]:[])}return this._wrap(this._hydrateOne(i,e.include,e.select,l))});return this._emit("findMany",{options:e,result:o}),o})}findPage(e={}){return C("repository.findPage",{table:this.tableName},()=>{let t=e.select&&e.include?this._ensureSelectPk(e):e,{countSql:n,countParams:r}=se(this.tableName,t,this.descriptor.softDelete?.column,this.meta),s=this._fetchRows(t,"findPage").map((i)=>this._wrap(this._hydrateOne(i,e.include,e.select))),a=this._executor.get(n,r,"count"),o={data:s,total:(a??{_count:0})._count,limit:e.limit??s.length,offset:e.offset??0};return this._emit("findPage",{options:e,result:o}),o})}findCursorPage(e){return C("repository.findCursorPage",{table:this.tableName},()=>{let t=e.orderBy.direction??"ASC",n=Q(e.orderBy.column,this.meta),r=e.limit??25,{sql:s,params:a}=P(e.where,this.descriptor.softDelete?.column,this.meta),o=`SELECT * FROM "${this.tableName}"`,i=[...a];if(e.cursor){let h=Q(e.cursor.column,this.meta),T=e.cursor.direction==="next"?t==="ASC"?">":"<":t==="ASC"?"<":">",k=`${h} ${T} ?`;if(i.push(e.cursor.value),s)o+=` ${s} AND ${k}`;else o+=` WHERE ${k}`}else if(s)o+=` ${s}`;let l=e.cursor?.direction==="prev"?t==="ASC"?"DESC":"ASC":t;o+=` ORDER BY ${n} ${l} LIMIT ${r}`;let m=this._executor.all(o,i,"findCursorPage").map((h)=>this._wrap(this._hydrateOne(h)));if(e.cursor?.direction==="prev")m.reverse();let c=m.length===r?{column:e.orderBy.column,value:m[m.length-1][e.orderBy.column]}:null,d=m.length>0?{column:e.orderBy.column,value:m[0][e.orderBy.column]}:null,p={data:m,nextCursor:c,prevCursor:d};return this._emit("findCursorPage",{options:e,result:p}),p})}findOne(e={}){return C("repository.findOne",{table:this.tableName},()=>{let t=e.select&&e.include?this._ensureSelectPk(e):e,n=this._fetchRows({...t,limit:1},"findOne"),r=n.length>0?n[0]:null,s=r?this._wrap(this._hydrateOne(r,e.include,e.select)):null;return this._emit("findOne",{options:e,result:s}),s})}*iterate(e={}){Ee("repository.iterate",{table:this.tableName});try{let t=e.select&&e.include?this._ensureSelectPk(e):e.select?this._ensureSelectPk(e):e,{sql:n,params:r}=Be(this.tableName,t,this.descriptor.softDelete?.column,this.meta),s=this._executor.iterate(n,r,"iterate");if(!e.include||e.include.length===0){for(let l of s)yield this._wrap(this._hydrateOne(l,void 0,e.select));return}let a=this.descriptor.primaryKey.name,o=100,i=[];for(let l of s)if(i.push(l),i.length>=o)yield*this._hydrateWindow(i,e.include,e.select),i=[];if(i.length>0)yield*this._hydrateWindow(i,e.include,e.select)}finally{Oe()}}*_hydrateWindow(e,t,n){let r=this.descriptor.primaryKey.name,s=e.map((o)=>o[r]).filter((o)=>typeof o==="string"||typeof o==="number"),a=new Map;for(let o of this.meta.subTables){if(!t.some((c)=>c===o.fieldName))continue;if(s.length===0)continue;let l=s.map(()=>"?").join(", "),u=this._executor.all(`SELECT * FROM "${o.tableName}" WHERE "_owner_id" IN (${l}) ORDER BY "_index" ASC`,s,"iterate"),m=new Map;for(let c of u){let d=c._owner_id;if(typeof d!=="string"&&typeof d!=="number")continue;if(!m.has(d))m.set(d,[]);m.get(d).push(c)}a.set(o.tableName,m)}for(let o of e){let i=new Map;for(let l of this.meta.subTables){if(!t.some((p)=>p===l.fieldName))continue;let m=a.get(l.tableName),c=o[r],d=typeof c==="string"||typeof c==="number"?c:void 0;i.set(l.tableName,d!==void 0?m?.get(d)??[]:[])}yield this._wrap(this._hydrateOne(o,t,n,i))}}findManyMaterialized(e={}){let t=this.findMany(e);if(!this._materializeMany)return t;let n=this._materializeMany(t);if(this._entityProto){for(let r of n)if(Object.getPrototypeOf(r)!==this._entityProto)Object.setPrototypeOf(r,this._entityProto)}return n}count(e){return C("repository.count",{table:this.tableName},()=>{let{sql:t,params:n}=P(e,this.descriptor.softDelete?.column,this.meta),r=`SELECT COUNT(*) as "_count" FROM "${this.tableName}" ${t}`.trim(),a=(this._executor.get(r,n,"count")??{_count:0})._count;return this._emit("count",{where:e,result:a}),a})}aggregate(e){return C("repository.aggregate",{table:this.tableName},()=>{let{sql:t,params:n}=at(this.tableName,e,this.descriptor.softDelete?.column,this.meta),r=this._executor.all(t,n,"aggregate");return this._emit("aggregate",{options:e,result:r}),r})}windowQuery(e){return C("repository.windowQuery",{table:this.tableName},()=>{let{sql:t,params:n}=lt(this.tableName,e,this.descriptor.softDelete?.column,this.meta),r=this._executor.all(t,n,"windowQuery");return this._emit("windowQuery",{options:e,result:r}),r})}update(e){return C("repository.update",{table:this.tableName},()=>{let t=this._record(e),n=this.descriptor.primaryKey.name,r=t[n];if(r===void 0||r===null)O("UPDATE_MISSING_PK",`foxdb: update() requires primary key "${n}"`,{table:this.tableName,column:n});let s=this._findByIdRaw(this._assertPk(r));if(!s)return null;let a=this.parse({...s,...e}),o=this._record(a);if(this._timestampNames.updatedAt)o[this._timestampNames.updatedAt]=Date.now();let i=U(o,this.meta,this._codecs),l=Object.fromEntries(Object.entries(i).filter(([m])=>m!==n));this.db.transaction(()=>{let{sql:m,params:c}=ot(this.tableName,n,this._assertPk(r),l);this._executor.exec(m,c,"update");for(let d of this.meta.subTables){this._executor.exec(`DELETE FROM "${d.tableName}" WHERE "_owner_id" = ?`,[this._assertPk(r)],"delete");let p=o[d.fieldName];if(!globalThis.Array.isArray(p)||p.length===0)continue;let h=X(this._assertPk(r),p,d,this._codecs);for(let T of h){let{sql:k,params:D}=H(d.tableName,T);this._executor.exec(k,D,"insert")}}});let u=this._wrap(o);return this._emit("update",{id:r,data:{...e}}),u})}updateWhere(e){return C("repository.updateWhere",{table:this.tableName},()=>{let t=this._record(e.data),n=tt(t,this.meta,this._codecs);if(this._timestampNames.updatedAt&&this._timestampNames.updatedAt in n===!1)n[this._timestampNames.updatedAt]=Date.now();let r=e.includeDeleted?void 0:this.descriptor.softDelete?.column,{sql:s,params:a}=it(this.tableName,n,e.where,r,this.meta),o=this._executor.exec(s,a,"updateWhere");return this._emit("updateWhere",{where:e.where,result:o.changes}),o.changes})}deleteById(e){return C("repository.deleteById",{table:this.tableName},()=>{let t=this.descriptor.primaryKey.name;if(this.descriptor.softDelete){let r=this.descriptor.softDelete.column;return this._executor.exec(`UPDATE "${this.tableName}" SET "${r}" = ? WHERE "${t}" = ?`,[Date.now(),e],"delete"),this._emit("delete",{id:e}),!0}let n=this.db.transaction(()=>{for(let s of this.meta.subTables)this._executor.exec(`DELETE FROM "${s.tableName}" WHERE "_owner_id" = ?`,[e],"delete");return this._executor.exec(`DELETE FROM "${this.tableName}" WHERE "${t}" = ?`,[e],"delete").changes>0});return this._emit("delete",{id:e}),n})}deleteWhere(e){return C("repository.deleteWhere",{table:this.tableName},()=>{let t=this.descriptor.primaryKey.name;if(this.descriptor.softDelete){let a=this.descriptor.softDelete.column,{sql:o,params:i}=P(e,a,this.meta),l=`UPDATE "${this.tableName}" SET "${a}" = ? ${o}`.trim(),u=this._executor.exec(l,[Date.now(),...i],"deleteWhere").changes;return this._emit("deleteWhere",{where:e,result:u}),u}let{sql:n,params:r}=P(e,void 0,this.meta),s=this.db.transaction(()=>{for(let i of this.meta.subTables){let l=`DELETE FROM "${i.tableName}" WHERE "_owner_id" IN (SELECT "${t}" FROM "${this.tableName}" ${n})`.trim();this._executor.exec(l,r,"delete")}let a=`DELETE FROM "${this.tableName}" ${n}`.trim();return this._executor.exec(a,r,"delete").changes});return this._emit("deleteWhere",{where:e,result:s}),s})}flush(){C("repository.flush",{table:this.tableName},()=>{this.db.exec(`DELETE FROM "${this.tableName}"`);for(let e of this.meta.subTables)this.db.exec(`DELETE FROM "${e.tableName}"`);this._emit("flush",{})})}drop(){for(let e of this.meta.subTables)this.db.exec(`DROP TABLE IF EXISTS "${e.tableName}"`);this.db.exec(`DROP TABLE IF EXISTS "${this.tableName}"`)}_hydrateOne(e,t,n,r){let s=this.descriptor.primaryKey.name,a=e[s],o=new Map;for(let i of this.meta.subTables){if(t&&!t.includes(i.fieldName)){o.set(i.tableName,[]);continue}let l={tableName:i.tableName,columns:i.columns,subTables:[],columnByName:i.columnByName,columnByPath:i.columnByPath};if(r&&r.has(i.tableName)){let d=r.get(i.tableName).map((p)=>{let h={};for(let T of Object.keys(p))if(T!=="_id"&&T!=="_owner_id"&&T!=="_index")h[T]=p[T];return de(h,l,new Map,this._codecs)});o.set(i.tableName,d);continue}let m=this._executor.all(`SELECT * FROM "${i.tableName}" WHERE "_owner_id" = ? ORDER BY "_index" ASC`,[a],"read").map((c)=>{let d={};for(let p of Object.keys(c))if(p!=="_id"&&p!=="_owner_id"&&p!=="_index")d[p]=c[p];return de(d,l,new Map,this._codecs)});o.set(i.tableName,m)}return de(e,this.meta,o,this._codecs,n,t)}raw(e,...t){return this._executor.all(e,t,"raw")}}class ct{tables;relations=[];constructor(e){this.tables=e}from(e){let t=e;return{scalar:(n)=>({to:(r,s,a)=>{let o={ownerTable:t,ownerField:n,targetTable:r,targetField:s,kind:"scalar",as:a?.as};return this.relations.push(o),o}}),subTable:(n,r)=>({to:(s,a,o)=>{let i={ownerTable:t,ownerField:`${n}.${r}`,targetTable:s,targetField:a,kind:"subTable",as:o?.as};return this.relations.push(i),i}})}}build(){return this.relations}}function Qe(e){return new ct(e)}import{Type as _}from"typebox";import{Compile as z}from"typebox/schema";var Vt=_.Object({key:_.String(),value:_.String(),encoding:_.String(),updatedAt:_.Integer()}),ut=z(Vt),Gt=_.String(),yt=_.Record(_.String(),_.Unknown()),Jt=_.Array(_.String()),Xt=_.Array(_.Object({ownerTable:_.String(),ownerField:_.String(),targetTable:_.String(),targetField:_.String(),kind:_.Union([_.Literal("scalar"),_.Literal("subTable")]),as:_.Optional(_.String())})),Yt=_.String(),br=z(Gt),dt=z(yt),mt=z(Jt),pt=z(Xt),Tr=z(Yt),je="plain",ft="json",ht="deflate-base64";class ${db;static KEY_SCHEMA_HASH="schemaHash";static KEY_SCHEMA_JSON="schemaJSON";static KEY_TABLES="tables";static KEY_RELATIONS="relations";static KEY_VERSION="version";constructor(e){this.db=e,this.db.exec(`
12
+ )`,[a],"evict")}}parse(e){return this.validator.Parse(e)}check(e){return this.validator.Check(e)}insert(e){return C("repository.insert",{table:this.tableName},()=>{let t=this.parse(e),n=this._record(t),r=Date.now();if(this._timestampNames.createdAt)n[this._timestampNames.createdAt]=r;if(this._timestampNames.updatedAt)n[this._timestampNames.updatedAt]=r;if(this.db.transaction(()=>{let s=U(n,this.meta,this._codecs),{sql:a,params:o}=H(this.tableName,s);this._executor.exec(a,o,"insert");let i=n[this.descriptor.primaryKey.name];for(let l of this.meta.subTables){let u=n[l.fieldName];if(!globalThis.Array.isArray(u)||u.length===0)continue;let d=X(this._assertPk(i),u,l,this._codecs);for(let c of d){let{sql:m,params:f}=H(l.tableName,c);this._executor.exec(m,f,"insert")}}}),this.descriptor.eviction)this._runEviction();return this._emit("insert",{data:n}),this._wrap(n)})}insertMany(e){return C("repository.insertMany",{table:this.tableName},()=>{let n=e.map((s)=>this.parse(s)).map((s)=>{let a=this._record(s),o=Date.now();if(this._timestampNames.createdAt)a[this._timestampNames.createdAt]=o;if(this._timestampNames.updatedAt)a[this._timestampNames.updatedAt]=o;return a}),r=n.map((s)=>U(s,this.meta,this._codecs));if(this.db.transaction(()=>{let s=pe(this.tableName,r);for(let{sql:a,params:o}of s)this._executor.exec(a,o,"insertMany");for(let a of n){let o=a[this.descriptor.primaryKey.name];for(let i of this.meta.subTables){let l=a[i.fieldName];if(!globalThis.Array.isArray(l)||l.length===0)continue;let u=X(this._assertPk(o),l,i,this._codecs);for(let d of u){let{sql:c,params:m}=H(i.tableName,d);this._executor.exec(c,m,"insertMany")}}}}),this.descriptor.eviction)this._runEviction();return this._emit("insertMany",{data:n}),n.map((s)=>this._wrap(s))})}createBatchWriter(e){let t=this;return new fe(this.tableName,this.db,e,{prepare(n){let r=t.parse(n),s=t._record(r),a=Date.now();if(t._timestampNames.createdAt)s[t._timestampNames.createdAt]=a;if(t._timestampNames.updatedAt)s[t._timestampNames.updatedAt]=a;return U(s,t.meta,t._codecs)},onFlush(n){if(t._emit("insertMany",{data:n}),t.descriptor.eviction&&Math.random()<0.2)t._runEviction()}})}upsert(e){return C("repository.upsert",{table:this.tableName},()=>{let t=this.parse(e.data),n=this._record(t),r=Date.now();if(this._timestampNames.createdAt)n[this._timestampNames.createdAt]=r;if(this._timestampNames.updatedAt)n[this._timestampNames.updatedAt]=r;let s=U(n,this.meta,this._codecs),a=globalThis.Array.isArray(e.conflictTarget)?e.conflictTarget:[e.conflictTarget],o=Object.keys(s),i=e.update??o.filter((l)=>!a.includes(l));if(this.descriptor.softDelete&&!i.includes(this.descriptor.softDelete.column))i.push(this.descriptor.softDelete.column),s[this.descriptor.softDelete.column]=null;if(this.db.transaction(()=>{let{sql:l,params:u}=rt(this.tableName,s,a,i);this._executor.exec(l,u,"upsert");let d=n[this.descriptor.primaryKey.name];for(let c of this.meta.subTables){this._executor.exec(`DELETE FROM "${c.tableName}" WHERE "_owner_id" = ?`,[d],"delete");let m=n[c.fieldName];if(!globalThis.Array.isArray(m)||m.length===0)continue;let f=X(this._assertPk(d),m,c,this._codecs);for(let h of f){let{sql:T,params:S}=H(c.tableName,h);this._executor.exec(T,S,"insert")}}}),this.descriptor.eviction)this._runEviction();return this._emit("upsert",{data:t}),this._wrap(this._record(t))})}upsertMany(e){return C("repository.upsertMany",{table:this.tableName},()=>{let n=e.data.map((l)=>this.parse(l)).map((l)=>{let u=this._record(l),d=Date.now();if(this._timestampNames.createdAt)u[this._timestampNames.createdAt]=d;if(this._timestampNames.updatedAt)u[this._timestampNames.updatedAt]=d;return u}),r=n.map((l)=>U(l,this.meta,this._codecs)),s=globalThis.Array.isArray(e.conflictTarget)?e.conflictTarget:[e.conflictTarget],a=Object.keys(r[0]??{}),o=e.update??a.filter((l)=>!s.includes(l));if(this.descriptor.softDelete&&!o.includes(this.descriptor.softDelete.column)){o.push(this.descriptor.softDelete.column);for(let l of r)l[this.descriptor.softDelete.column]=null}let i=0;if(this.db.transaction(()=>{let l=st(this.tableName,r,s,o);for(let{sql:u,params:d}of l){let c=this._executor.exec(u,d,"upsertMany");i+=c.changes}for(let u of n){let d=u[this.descriptor.primaryKey.name];for(let c of this.meta.subTables){this._executor.exec(`DELETE FROM "${c.tableName}" WHERE "_owner_id" = ?`,[d],"delete");let m=u[c.fieldName];if(!globalThis.Array.isArray(m)||m.length===0)continue;let f=X(this._assertPk(d),m,c,this._codecs);for(let h of f){let{sql:T,params:S}=H(c.tableName,h);this._executor.exec(T,S,"insert")}}}}),this.descriptor.eviction)this._runEviction();return this._emit("upsertMany",{data:n,result:i}),i})}findById(e){return C("repository.findById",{table:this.tableName},()=>{let t=this._findByIdRaw(e);return this._emit("findById",{id:e,result:t}),t})}_findByIdRaw(e){let t=this.descriptor.primaryKey.name,n=this.descriptor.softDelete?`SELECT * FROM "${this.tableName}" WHERE "${t}" = ? AND "${this.descriptor.softDelete.column}" IS NULL LIMIT 1`:`SELECT * FROM "${this.tableName}" WHERE "${t}" = ? LIMIT 1`,r=this._executor.get(n,[e],"findById");if(!r)return null;if(this.descriptor.eviction?.lruColumn&&Math.random()<0.1){let s=this.descriptor.eviction.lruColumn,a=this.descriptor.primaryKey.name;Promise.resolve().then(()=>{try{this._executor.exec(`UPDATE "${this.tableName}" SET "${s}" = ? WHERE "${a}" = ?`,[Date.now(),e])}catch{}})}return this._wrap(this._hydrateOne(r))}findMany(e={}){return C("repository.findMany",{table:this.tableName},()=>{let t=e.select&&e.include?this._ensureSelectPk({...e,select:e.select}):e,n=this._fetchRows(t,"findMany");if(this.descriptor.eviction?.lruColumn){let i=this.descriptor.eviction.lruColumn,l=this.descriptor.primaryKey.name,u=[];for(let d of n)if(Math.random()<0.1){let c=d[l];if(typeof c==="string"||typeof c==="number")u.push(c)}if(u.length>0){let d=Date.now(),c=u.map(()=>"?").join(", ");Promise.resolve().then(()=>{try{this._executor.exec(`UPDATE "${this.tableName}" SET "${i}" = ? WHERE "${l}" IN (${c})`,[d,...u])}catch{}})}}let r=this.descriptor.primaryKey.name,s=n.map((i)=>i[r]).filter((i)=>typeof i==="string"||typeof i==="number"),a=new Map;for(let i of this.meta.subTables){if(!(!e.include||e.include.some((m)=>m===i.fieldName)))continue;if(s.length===0)continue;let u=s.map(()=>"?").join(", "),d=this._executor.all(`SELECT * FROM "${i.tableName}" WHERE "_owner_id" IN (${u}) ORDER BY "_index" ASC`,s,"findMany"),c=new Map;for(let m of d){let f=m._owner_id;if(typeof f!=="string"&&typeof f!=="number")continue;if(!c.has(f))c.set(f,[]);c.get(f).push(m)}a.set(i.tableName,c)}let o=n.map((i)=>{let l=new Map;for(let u of this.meta.subTables){if(!(!e.include||e.include.some((h)=>h===u.fieldName)))continue;let c=a.get(u.tableName),m=i[r],f=typeof m==="string"||typeof m==="number"?m:void 0;l.set(u.tableName,f!==void 0?c?.get(f)??[]:[])}return this._wrap(this._hydrateOne(i,e.include,e.select,l))});return this._emit("findMany",{options:e,result:o}),o})}findPage(e={}){return C("repository.findPage",{table:this.tableName},()=>{let t=e.select&&e.include?this._ensureSelectPk(e):e,{countSql:n,countParams:r}=se(this.tableName,t,this.descriptor.softDelete?.column,this.meta),s=this._fetchRows(t,"findPage").map((i)=>this._wrap(this._hydrateOne(i,e.include,e.select))),a=this._executor.get(n,r,"count"),o={data:s,total:(a??{_count:0})._count,limit:e.limit??s.length,offset:e.offset??0};return this._emit("findPage",{options:e,result:o}),o})}findCursorPage(e){return C("repository.findCursorPage",{table:this.tableName},()=>{let t=e.orderBy.direction??"ASC",n=Q(e.orderBy.column,this.meta),r=e.limit??25,{sql:s,params:a}=P(e.where,this.descriptor.softDelete?.column,this.meta),o=`SELECT * FROM "${this.tableName}"`,i=[...a];if(e.cursor){let h=Q(e.cursor.column,this.meta),T=e.cursor.direction==="next"?t==="ASC"?">":"<":t==="ASC"?"<":">",S=`${h} ${T} ?`;if(i.push(e.cursor.value),s)o+=` ${s} AND ${S}`;else o+=` WHERE ${S}`}else if(s)o+=` ${s}`;let l=e.cursor?.direction==="prev"?t==="ASC"?"DESC":"ASC":t;o+=` ORDER BY ${n} ${l} LIMIT ${r}`;let d=this._executor.all(o,i,"findCursorPage").map((h)=>this._wrap(this._hydrateOne(h)));if(e.cursor?.direction==="prev")d.reverse();let c=d.length===r?{column:e.orderBy.column,value:d[d.length-1][e.orderBy.column]}:null,m=d.length>0?{column:e.orderBy.column,value:d[0][e.orderBy.column]}:null,f={data:d,nextCursor:c,prevCursor:m};return this._emit("findCursorPage",{options:e,result:f}),f})}findOne(e={}){return C("repository.findOne",{table:this.tableName},()=>{let t=e.select&&e.include?this._ensureSelectPk(e):e,n=this._fetchRows({...t,limit:1},"findOne"),r=n.length>0?n[0]:null,s=r?this._wrap(this._hydrateOne(r,e.include,e.select)):null;return this._emit("findOne",{options:e,result:s}),s})}*iterate(e={}){Ee("repository.iterate",{table:this.tableName});try{let t=e.select&&e.include?this._ensureSelectPk(e):e.select?this._ensureSelectPk(e):e,{sql:n,params:r}=Le(this.tableName,t,this.descriptor.softDelete?.column,this.meta),s=this._executor.iterate(n,r,"iterate");if(!e.include||e.include.length===0){for(let l of s)yield this._wrap(this._hydrateOne(l,void 0,e.select));return}let a=this.descriptor.primaryKey.name,o=100,i=[];for(let l of s)if(i.push(l),i.length>=o)yield*this._hydrateWindow(i,e.include,e.select),i=[];if(i.length>0)yield*this._hydrateWindow(i,e.include,e.select)}finally{Oe()}}*_hydrateWindow(e,t,n){let r=this.descriptor.primaryKey.name,s=e.map((o)=>o[r]).filter((o)=>typeof o==="string"||typeof o==="number"),a=new Map;for(let o of this.meta.subTables){if(!t.some((c)=>c===o.fieldName))continue;if(s.length===0)continue;let l=s.map(()=>"?").join(", "),u=this._executor.all(`SELECT * FROM "${o.tableName}" WHERE "_owner_id" IN (${l}) ORDER BY "_index" ASC`,s,"iterate"),d=new Map;for(let c of u){let m=c._owner_id;if(typeof m!=="string"&&typeof m!=="number")continue;if(!d.has(m))d.set(m,[]);d.get(m).push(c)}a.set(o.tableName,d)}for(let o of e){let i=new Map;for(let l of this.meta.subTables){if(!t.some((f)=>f===l.fieldName))continue;let d=a.get(l.tableName),c=o[r],m=typeof c==="string"||typeof c==="number"?c:void 0;i.set(l.tableName,m!==void 0?d?.get(m)??[]:[])}yield this._wrap(this._hydrateOne(o,t,n,i))}}findManyMaterialized(e={}){let t=this.findMany(e);if(!this._materializeMany)return t;let n=this._materializeMany(t);if(this._entityProto){for(let r of n)if(Object.getPrototypeOf(r)!==this._entityProto)Object.setPrototypeOf(r,this._entityProto)}return n}count(e){return C("repository.count",{table:this.tableName},()=>{let{sql:t,params:n}=P(e,this.descriptor.softDelete?.column,this.meta),r=`SELECT COUNT(*) as "_count" FROM "${this.tableName}" ${t}`.trim(),a=(this._executor.get(r,n,"count")??{_count:0})._count;return this._emit("count",{where:e,result:a}),a})}aggregate(e){return C("repository.aggregate",{table:this.tableName},()=>{let{sql:t,params:n}=it(this.tableName,e,this.descriptor.softDelete?.column,this.meta),r=this._executor.all(t,n,"aggregate");return this._emit("aggregate",{options:e,result:r}),r})}windowQuery(e){return C("repository.windowQuery",{table:this.tableName},()=>{let{sql:t,params:n}=lt(this.tableName,e,this.descriptor.softDelete?.column,this.meta),r=this._executor.all(t,n,"windowQuery");return this._emit("windowQuery",{options:e,result:r}),r})}update(e){return C("repository.update",{table:this.tableName},()=>{let t=this._record(e),n=this.descriptor.primaryKey.name,r=t[n];if(r===void 0||r===null)N("UPDATE_MISSING_PK",`foxdb: update() requires primary key "${n}"`,{table:this.tableName,column:n});let s=this._findByIdRaw(this._assertPk(r));if(!s)return null;let a=this.parse({...s,...e}),o=this._record(a);if(this._timestampNames.updatedAt)o[this._timestampNames.updatedAt]=Date.now();let i=U(o,this.meta,this._codecs),l=Object.fromEntries(Object.entries(i).filter(([d])=>d!==n));this.db.transaction(()=>{let{sql:d,params:c}=ot(this.tableName,n,this._assertPk(r),l);this._executor.exec(d,c,"update");for(let m of this.meta.subTables){this._executor.exec(`DELETE FROM "${m.tableName}" WHERE "_owner_id" = ?`,[this._assertPk(r)],"delete");let f=o[m.fieldName];if(!globalThis.Array.isArray(f)||f.length===0)continue;let h=X(this._assertPk(r),f,m,this._codecs);for(let T of h){let{sql:S,params:v}=H(m.tableName,T);this._executor.exec(S,v,"insert")}}});let u=this._wrap(o);return this._emit("update",{id:r,data:{...e}}),u})}updateWhere(e){return C("repository.updateWhere",{table:this.tableName},()=>{let t=this._record(e.data),n=tt(t,this.meta,this._codecs);if(this._timestampNames.updatedAt&&this._timestampNames.updatedAt in n===!1)n[this._timestampNames.updatedAt]=Date.now();let r=e.includeDeleted?void 0:this.descriptor.softDelete?.column,{sql:s,params:a}=at(this.tableName,n,e.where,r,this.meta),o=this._executor.exec(s,a,"updateWhere");return this._emit("updateWhere",{where:e.where,result:o.changes}),o.changes})}deleteById(e){return C("repository.deleteById",{table:this.tableName},()=>{let t=this.descriptor.primaryKey.name;if(this.descriptor.softDelete){let r=this.descriptor.softDelete.column;return this._executor.exec(`UPDATE "${this.tableName}" SET "${r}" = ? WHERE "${t}" = ?`,[Date.now(),e],"delete"),this._emit("delete",{id:e}),!0}let n=this.db.transaction(()=>{for(let s of this.meta.subTables)this._executor.exec(`DELETE FROM "${s.tableName}" WHERE "_owner_id" = ?`,[e],"delete");return this._executor.exec(`DELETE FROM "${this.tableName}" WHERE "${t}" = ?`,[e],"delete").changes>0});return this._emit("delete",{id:e}),n})}deleteWhere(e){return C("repository.deleteWhere",{table:this.tableName},()=>{let t=this.descriptor.primaryKey.name;if(this.descriptor.softDelete){let a=this.descriptor.softDelete.column,{sql:o,params:i}=P(e,a,this.meta),l=`UPDATE "${this.tableName}" SET "${a}" = ? ${o}`.trim(),u=this._executor.exec(l,[Date.now(),...i],"deleteWhere").changes;return this._emit("deleteWhere",{where:e,result:u}),u}let{sql:n,params:r}=P(e,void 0,this.meta),s=this.db.transaction(()=>{for(let i of this.meta.subTables){let l=`DELETE FROM "${i.tableName}" WHERE "_owner_id" IN (SELECT "${t}" FROM "${this.tableName}" ${n})`.trim();this._executor.exec(l,r,"delete")}let a=`DELETE FROM "${this.tableName}" ${n}`.trim();return this._executor.exec(a,r,"delete").changes});return this._emit("deleteWhere",{where:e,result:s}),s})}flush(){C("repository.flush",{table:this.tableName},()=>{this.db.exec(`DELETE FROM "${this.tableName}"`);for(let e of this.meta.subTables)this.db.exec(`DELETE FROM "${e.tableName}"`);this._emit("flush",{})})}drop(){for(let e of this.meta.subTables)this.db.exec(`DROP TABLE IF EXISTS "${e.tableName}"`);this.db.exec(`DROP TABLE IF EXISTS "${this.tableName}"`)}_hydrateOne(e,t,n,r){let s=this.descriptor.primaryKey.name,a=e[s],o=new Map;for(let i of this.meta.subTables){if(t&&!t.includes(i.fieldName)){o.set(i.tableName,[]);continue}let l={tableName:i.tableName,columns:i.columns,subTables:[],columnByName:i.columnByName,columnByPath:i.columnByPath};if(r&&r.has(i.tableName)){let m=r.get(i.tableName).map((f)=>{let h={};for(let T of Object.keys(f))if(T!=="_id"&&T!=="_owner_id"&&T!=="_index")h[T]=f[T];return de(h,l,new Map,this._codecs)});o.set(i.tableName,m);continue}let d=this._executor.all(`SELECT * FROM "${i.tableName}" WHERE "_owner_id" = ? ORDER BY "_index" ASC`,[a],"read").map((c)=>{let m={};for(let f of Object.keys(c))if(f!=="_id"&&f!=="_owner_id"&&f!=="_index")m[f]=c[f];return de(m,l,new Map,this._codecs)});o.set(i.tableName,d)}return de(e,this.meta,o,this._codecs,n,t)}raw(e,...t){return this._executor.all(e,t,"raw")}}class ct{tables;relations=[];constructor(e){this.tables=e}from(e){let t=e;return{scalar:(n)=>({to:(r,s,a)=>{let o={ownerTable:t,ownerField:n,targetTable:r,targetField:s,kind:"scalar",as:a?.as};return this.relations.push(o),o}}),subTable:(n,r)=>({to:(s,a,o)=>{let i={ownerTable:t,ownerField:`${n}.${r}`,targetTable:s,targetField:a,kind:"subTable",as:o?.as};return this.relations.push(i),i}})}}build(){return this.relations}}function Qe(e){return new ct(e)}import{Type as _}from"typebox";import{Compile as z}from"typebox/schema";var Gt=_.Object({key:_.String(),value:_.String(),encoding:_.String(),updatedAt:_.Integer()}),ut=z(Gt),Jt=_.String(),yt=_.Record(_.String(),_.Unknown()),Xt=_.Array(_.String()),Yt=_.Array(_.Object({ownerTable:_.String(),ownerField:_.String(),targetTable:_.String(),targetField:_.String(),kind:_.Union([_.Literal("scalar"),_.Literal("subTable")]),as:_.Optional(_.String())})),zt=_.String(),Tr=z(Jt),dt=z(yt),mt=z(Xt),pt=z(Yt),Sr=z(zt),je="plain",ft="json",ht="deflate-base64";class ${db;static KEY_SCHEMA_HASH="schemaHash";static KEY_SCHEMA_JSON="schemaJSON";static KEY_TABLES="tables";static KEY_RELATIONS="relations";static KEY_VERSION="version";constructor(e){this.db=e,this.db.exec(`
13
13
  CREATE TABLE IF NOT EXISTS _foxdb_meta (
14
14
  key TEXT PRIMARY KEY,
15
15
  value TEXT NOT NULL,
@@ -23,23 +23,23 @@ ${a.join(`,
23
23
  value = excluded.value,
24
24
  encoding = excluded.encoding,
25
25
  updatedAt = excluded.updatedAt
26
- `).run(e,t,n,Date.now())}getValidatedJSON(e,t,n){let r=JSON.parse(n);if(!t.Check(r)){let[,s]=t.Errors(r);throw Error(`MetaStore: JSON validation failed for key "${e}". Errors: ${JSON.stringify(s)}`)}return r}validateAndSetJSON(e,t,n){if(!t.Check(n)){let[,r]=t.Errors(n);throw Error(`MetaStore: JSON validation failed for key "${e}" before write. Errors: ${JSON.stringify(r)}`)}this.setRow(e,JSON.stringify(n),ft)}getString(e){let t=this.getRow(e);if(t==null)return null;return t.value}setString(e,t){this.setRow(e,t,je)}getJSON(e){let t=this.getRow(e);if(t==null)return null;try{return JSON.parse(t.value)}catch{return null}}setJSON(e,t){this.setRow(e,JSON.stringify(t),ft)}getCompressed(e){let t=this.getRow(e);if(t==null)return null;if(t.encoding!==ht)return null;let n=Uint8Array.fromBase64(t.value);return Bun.inflateSync(n)}setCompressed(e,t){let n=new Uint8Array(t),s=Bun.deflateSync(n).toBase64();this.setRow(e,s,ht)}delete(e){this.db.prepare("DELETE FROM _foxdb_meta WHERE key = ?").run(e)}getSchemaHash(){let e=this.getRow($.KEY_SCHEMA_HASH);if(e==null)return null;return e.value}setSchemaHash(e){this.setRow($.KEY_SCHEMA_HASH,e,je)}getSchemaJSON(){let e=this.getRow($.KEY_SCHEMA_JSON);if(e==null)return null;return this.getValidatedJSON($.KEY_SCHEMA_JSON,dt,e.value)}setSchemaJSON(e){this.validateAndSetJSON($.KEY_SCHEMA_JSON,dt,e)}getTables(){let e=this.getRow($.KEY_TABLES);if(e==null)return null;return this.getValidatedJSON($.KEY_TABLES,mt,e.value)}setTables(e){this.validateAndSetJSON($.KEY_TABLES,mt,e)}getRelations(){let e=this.getRow($.KEY_RELATIONS);if(e==null)return null;return this.getValidatedJSON($.KEY_RELATIONS,pt,e.value)}setRelations(e){this.validateAndSetJSON($.KEY_RELATIONS,pt,e)}getVersion(){let e=this.getRow($.KEY_VERSION);if(e==null)return null;return e.value}setVersion(e){this.setRow($.KEY_VERSION,e,je)}}function zt(e){return e.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_foxdb_%' ORDER BY name").all().map((r)=>r.name)}function Zt(e,t){return e.prepare(`SELECT name, "unique" AS "unique" FROM sqlite_master WHERE type = 'index' AND tbl_name = ? AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlite_autoindex_%'`).all(t)}function en(e,t){return e.prepare(`PRAGMA index_info("${t}")`).all().map((s)=>s.name).filter((s)=>s!=null)}function gt(e,t){let r=e.prepare(`PRAGMA table_info("${t}")`).all(),s=[];for(let a of Zt(e,t)){let o=en(e,a.name);s.push({name:a.name,unique:a.unique,columns:o})}return{name:t,columns:r,indexes:s}}function qe(e){return zt(e).map((n)=>gt(e,n))}function tn(e){return e.toUpperCase().trim()}function bt(e){let t=tn(e);if(t.includes("INT"))return"INTEGER";if(t.includes("CHAR")||t.includes("CLOB")||t.includes("TEXT"))return"TEXT";if(t.includes("BLOB"))return"BLOB";if(t.includes("REAL")||t.includes("FLOA")||t.includes("DOUB"))return"REAL";return"NUMERIC"}function nn(e){return e==="_id"||e==="_owner_id"||e==="_index"}function rn(e,t){return e.columns.find((n)=>n.name===t)}function sn(e,t,n){let r=[...t].sort().join(",");return e.indexes.find((s)=>{if(Boolean(s.unique)!==n)return!1;return[...s.columns].sort().join(",")===r})}function on(e){return e.columns.filter((t)=>t.pk>0).sort((t,n)=>t.pk-n.pk).map((t)=>t.name)}function Fe(e,t){let n=[],r=[],s=new Map(t.map((o)=>[o.name,o]));for(let o of e){let i=s.get(o.name);if(!i){if(o.name.includes("__"))n.push({kind:"add-subtable",table:o.name.split("__")[0],subTable:{fieldName:o.name.split("__")[1],tableName:o.name,columns:o.columns.map((c)=>({name:c.name,sqlType:c.sqlType,nullable:c.nullable,optional:c.optional}))}});else n.push({kind:"add-table",table:o.name});continue}for(let c of o.columns){let d=rn(i,c.name);if(!d){if(c.nullable)n.push({kind:"add-column",table:o.name,column:{name:c.name,sqlType:c.sqlType,nullable:c.nullable,optional:c.optional},hasDefault:!1});else r.push({kind:"add-column",table:o.name,column:{name:c.name,sqlType:c.sqlType,nullable:c.nullable,optional:c.optional},hasDefault:!1});continue}if(bt(c.sqlType)!==bt(d.type))r.push({kind:"change-type",table:o.name,column:c.name,from:d.type,to:c.sqlType});let p=!c.nullable,h=d.notnull===1;if(p!==h)if(h&&!p)n.push({kind:"change-nullable",table:o.name,column:c.name,to:!0});else r.push({kind:"change-nullable",table:o.name,column:c.name,to:!1})}for(let c of i.columns){if(nn(c.name))continue;if(!o.columns.find((d)=>d.name===c.name))r.push({kind:"drop-column",table:o.name,column:c.name})}let l=on(i),u=o.primaryKey.split(",").map((c)=>c.trim());if(l.length!==u.length||!l.every((c,d)=>c===u[d]))r.push({kind:"change-pk",table:o.name});let m=i.indexes.filter((c)=>!c.name.startsWith("sqlite_")&&!c.name.startsWith("idx_sqlite_"));for(let c of o.indexes)if(!sn(i,c.columns,c.unique??!1))n.push({kind:"add-index",table:o.name,index:{name:c.name??`idx_${o.name}__${c.columns.join("_")}`,unique:c.unique?1:0,columns:c.columns}});for(let c of m)if(!o.indexes.some((p)=>{let h=[...p.columns].sort().join(","),T=[...c.columns].sort().join(",");return h===T&&Boolean(p.unique)===Boolean(c.unique)}))r.push({kind:"drop-index",table:o.name,index:{name:c.name,unique:c.unique,columns:c.columns}})}let a=new Set(e.map((o)=>o.name));for(let o of t)if(!a.has(o.name))r.push({kind:"drop-table",table:o.name});return{safe:n,unsafe:r}}function We(e,t){return e.find((n)=>n.name===t)}function an(e){let t=e.columns.map((n)=>{let r=!n.nullable?" NOT NULL":"",s=n.name===e.primaryKey?" PRIMARY KEY":"";return` "${n.name}" ${n.sqlType}${s}${r}`});return`CREATE TABLE IF NOT EXISTS "${e.name}" (
26
+ `).run(e,t,n,Date.now())}getValidatedJSON(e,t,n){let r=JSON.parse(n);if(!t.Check(r)){let[,s]=t.Errors(r);throw Error(`MetaStore: JSON validation failed for key "${e}". Errors: ${JSON.stringify(s)}`)}return r}validateAndSetJSON(e,t,n){if(!t.Check(n)){let[,r]=t.Errors(n);throw Error(`MetaStore: JSON validation failed for key "${e}" before write. Errors: ${JSON.stringify(r)}`)}this.setRow(e,JSON.stringify(n),ft)}getString(e){let t=this.getRow(e);if(t==null)return null;return t.value}setString(e,t){this.setRow(e,t,je)}getJSON(e){let t=this.getRow(e);if(t==null)return null;try{return JSON.parse(t.value)}catch{return null}}setJSON(e,t){this.setRow(e,JSON.stringify(t),ft)}getCompressed(e){let t=this.getRow(e);if(t==null)return null;if(t.encoding!==ht)return null;let n=Uint8Array.fromBase64(t.value);return Bun.inflateSync(n)}setCompressed(e,t){let n=new Uint8Array(t),s=Bun.deflateSync(n).toBase64();this.setRow(e,s,ht)}delete(e){this.db.prepare("DELETE FROM _foxdb_meta WHERE key = ?").run(e)}getSchemaHash(){let e=this.getRow($.KEY_SCHEMA_HASH);if(e==null)return null;return e.value}setSchemaHash(e){this.setRow($.KEY_SCHEMA_HASH,e,je)}getSchemaJSON(){let e=this.getRow($.KEY_SCHEMA_JSON);if(e==null)return null;return this.getValidatedJSON($.KEY_SCHEMA_JSON,dt,e.value)}setSchemaJSON(e){this.validateAndSetJSON($.KEY_SCHEMA_JSON,dt,e)}getTables(){let e=this.getRow($.KEY_TABLES);if(e==null)return null;return this.getValidatedJSON($.KEY_TABLES,mt,e.value)}setTables(e){this.validateAndSetJSON($.KEY_TABLES,mt,e)}getRelations(){let e=this.getRow($.KEY_RELATIONS);if(e==null)return null;return this.getValidatedJSON($.KEY_RELATIONS,pt,e.value)}setRelations(e){this.validateAndSetJSON($.KEY_RELATIONS,pt,e)}getVersion(){let e=this.getRow($.KEY_VERSION);if(e==null)return null;return e.value}setVersion(e){this.setRow($.KEY_VERSION,e,je)}}function Zt(e){return e.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_foxdb_%' ORDER BY name").all().map((r)=>r.name)}function en(e,t){return e.prepare(`SELECT name, "unique" AS "unique" FROM sqlite_master WHERE type = 'index' AND tbl_name = ? AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlite_autoindex_%'`).all(t)}function tn(e,t){return e.prepare(`PRAGMA index_info("${t}")`).all().map((s)=>s.name).filter((s)=>s!=null)}function gt(e,t){let r=e.prepare(`PRAGMA table_info("${t}")`).all(),s=[];for(let a of en(e,t)){let o=tn(e,a.name);s.push({name:a.name,unique:a.unique,columns:o})}return{name:t,columns:r,indexes:s}}function qe(e){return Zt(e).map((n)=>gt(e,n))}function nn(e){return e.toUpperCase().trim()}function bt(e){let t=nn(e);if(t.includes("INT"))return"INTEGER";if(t.includes("CHAR")||t.includes("CLOB")||t.includes("TEXT"))return"TEXT";if(t.includes("BLOB"))return"BLOB";if(t.includes("REAL")||t.includes("FLOA")||t.includes("DOUB"))return"REAL";return"NUMERIC"}function rn(e){return e==="_id"||e==="_owner_id"||e==="_index"}function sn(e,t){return e.columns.find((n)=>n.name===t)}function on(e,t,n){let r=[...t].sort().join(",");return e.indexes.find((s)=>{if(Boolean(s.unique)!==n)return!1;return[...s.columns].sort().join(",")===r})}function an(e){return e.columns.filter((t)=>t.pk>0).sort((t,n)=>t.pk-n.pk).map((t)=>t.name)}function Fe(e,t){let n=[],r=[],s=new Map(t.map((o)=>[o.name,o]));for(let o of e){let i=s.get(o.name);if(!i){if(o.name.includes("__"))n.push({kind:"add-subtable",table:o.name.split("__")[0],subTable:{fieldName:o.name.split("__")[1],tableName:o.name,columns:o.columns.map((c)=>({name:c.name,sqlType:c.sqlType,nullable:c.nullable,optional:c.optional}))}});else n.push({kind:"add-table",table:o.name});continue}for(let c of o.columns){let m=sn(i,c.name);if(!m){if(c.nullable)n.push({kind:"add-column",table:o.name,column:{name:c.name,sqlType:c.sqlType,nullable:c.nullable,optional:c.optional},hasDefault:!1});else r.push({kind:"add-column",table:o.name,column:{name:c.name,sqlType:c.sqlType,nullable:c.nullable,optional:c.optional},hasDefault:!1});continue}if(bt(c.sqlType)!==bt(m.type))r.push({kind:"change-type",table:o.name,column:c.name,from:m.type,to:c.sqlType});let f=!c.nullable,h=m.notnull===1;if(f!==h)if(h&&!f)n.push({kind:"change-nullable",table:o.name,column:c.name,to:!0});else r.push({kind:"change-nullable",table:o.name,column:c.name,to:!1})}for(let c of i.columns){if(rn(c.name))continue;if(!o.columns.find((m)=>m.name===c.name))r.push({kind:"drop-column",table:o.name,column:c.name})}let l=an(i),u=o.primaryKey.split(",").map((c)=>c.trim());if(l.length!==u.length||!l.every((c,m)=>c===u[m]))r.push({kind:"change-pk",table:o.name});let d=i.indexes.filter((c)=>!c.name.startsWith("sqlite_")&&!c.name.startsWith("idx_sqlite_"));for(let c of o.indexes)if(!on(i,c.columns,c.unique??!1))n.push({kind:"add-index",table:o.name,index:{name:c.name??`idx_${o.name}__${c.columns.join("_")}`,unique:c.unique?1:0,columns:c.columns}});for(let c of d)if(!o.indexes.some((f)=>{let h=[...f.columns].sort().join(","),T=[...c.columns].sort().join(",");return h===T&&Boolean(f.unique)===Boolean(c.unique)}))r.push({kind:"drop-index",table:o.name,index:{name:c.name,unique:c.unique,columns:c.columns}})}let a=new Set(e.map((o)=>o.name));for(let o of t)if(!a.has(o.name))r.push({kind:"drop-table",table:o.name});return{safe:n,unsafe:r}}function We(e,t){return e.find((n)=>n.name===t)}function ln(e){let t=e.columns.map((n)=>{let r=!n.nullable?" NOT NULL":"",s=n.name===e.primaryKey?" PRIMARY KEY":"";return` "${n.name}" ${n.sqlType}${s}${r}`});return`CREATE TABLE IF NOT EXISTS "${e.name}" (
27
27
  ${t.join(`,
28
28
  `)}
29
- )`}function ln(e,t){let n=!t.nullable?" NOT NULL":"";return`ALTER TABLE "${e}" ADD COLUMN "${t.name}" ${t.sqlType}${n}`}function cn(e,t){let n=t.unique?"UNIQUE ":"",r=t.columns.map((s)=>`"${s}"`).join(", ");return`CREATE ${n}INDEX IF NOT EXISTS "${t.name}" ON "${e}" (${r})`}function un(e,t){let n=`${t.name}_foxdb_temp`,r=t.columns.map((s)=>{let a=!s.nullable?" NOT NULL":"",o=s.name===t.primaryKey?" PRIMARY KEY":"";return` "${s.name}" ${s.sqlType}${o}${a}`});e.transaction(()=>{e.exec(`CREATE TABLE "${n}" (
29
+ )`}function cn(e,t){let n=!t.nullable?" NOT NULL":"";return`ALTER TABLE "${e}" ADD COLUMN "${t.name}" ${t.sqlType}${n}`}function un(e,t){let n=t.unique?"UNIQUE ":"",r=t.columns.map((s)=>`"${s}"`).join(", ");return`CREATE ${n}INDEX IF NOT EXISTS "${t.name}" ON "${e}" (${r})`}function dn(e,t){let n=`${t.name}_foxdb_temp`,r=t.columns.map((s)=>{let a=!s.nullable?" NOT NULL":"",o=s.name===t.primaryKey?" PRIMARY KEY":"";return` "${s.name}" ${s.sqlType}${o}${a}`});e.transaction(()=>{e.exec(`CREATE TABLE "${n}" (
30
30
  ${r.join(`,
31
31
  `)}
32
- )`);let s=t.columns.map((a)=>`"${a.name}"`).join(", ");e.exec(`INSERT INTO "${n}" (${s}) SELECT ${s} FROM "${t.name}"`),e.exec(`DROP TABLE "${t.name}"`),e.exec(`ALTER TABLE "${n}" RENAME TO "${t.name}"`)})}function dn(e,t,n){let{table:r,subTable:s}=n,a=We(t,r);if(!a)throw Error(`foxdb sync: cannot find owner table "${r}" for sub-table "${s.tableName}"`);let l=[' "_id" INTEGER PRIMARY KEY AUTOINCREMENT',` "_owner_id" ${a.columns.find((u)=>u.name===a.primaryKey)?.sqlType??"TEXT"} NOT NULL`,' "_index" INTEGER NOT NULL',...s.columns.map((u)=>{let m=!u.nullable?" NOT NULL":"";return` "${u.name}" ${u.sqlType}${m}`})];e.transaction(()=>{e.exec(`CREATE TABLE IF NOT EXISTS "${s.tableName}" (
32
+ )`);let s=t.columns.map((a)=>`"${a.name}"`).join(", ");e.exec(`INSERT INTO "${n}" (${s}) SELECT ${s} FROM "${t.name}"`),e.exec(`DROP TABLE "${t.name}"`),e.exec(`ALTER TABLE "${n}" RENAME TO "${t.name}"`)})}function mn(e,t,n){let{table:r,subTable:s}=n,a=We(t,r);if(!a)throw Error(`foxdb sync: cannot find owner table "${r}" for sub-table "${s.tableName}"`);let l=[' "_id" INTEGER PRIMARY KEY AUTOINCREMENT',` "_owner_id" ${a.columns.find((u)=>u.name===a.primaryKey)?.sqlType??"TEXT"} NOT NULL`,' "_index" INTEGER NOT NULL',...s.columns.map((u)=>{let d=!u.nullable?" NOT NULL":"";return` "${u.name}" ${u.sqlType}${d}`})];e.transaction(()=>{e.exec(`CREATE TABLE IF NOT EXISTS "${s.tableName}" (
33
33
  ${l.join(`,
34
34
  `)}
35
- )`),e.exec(`CREATE INDEX IF NOT EXISTS "idx_${s.tableName}__owner" ON "${s.tableName}" ("_owner_id")`)})}function Ke(e,t,n){for(let r of e.safe)switch(r.kind){case"add-table":{let s=We(n,r.table);if(!s)throw Error(`foxdb sync: missing desired schema for table "${r.table}"`);t.exec(an(s));break}case"add-subtable":{dn(t,n,r);break}case"add-column":{if(!r.column.nullable)throw Error(`foxdb sync: cannot auto-apply required column "${r.column.name}" without default. Use a migration.`);t.exec(ln(r.table,r.column));break}case"add-index":{t.exec(cn(r.table,r.index));break}case"change-nullable":{if(!r.to)throw Error(`foxdb sync: cannot auto-apply nullable \u2192 NOT NULL change on "${r.table}.${r.column}". Use a migration.`);let s=We(n,r.table);if(!s)throw Error(`foxdb sync: missing desired schema for table "${r.table}"`);un(t,s);break}case"drop-index":{t.exec(`DROP INDEX IF EXISTS "${r.index.name}"`);break}}}function mn(e,t,n){if(e.unsafe.length===0&&e.safe.length===0)return!0;if(n==="ignore")return!0;if(n==="warn"){if(e.unsafe.length>0){console.warn(`[foxdb] ${e.unsafe.length} unsafe schema change(s) detected:`);for(let r of e.unsafe)console.warn(` - ${r.kind}: ${JSON.stringify(r)}`)}return!0}if(n==="error"){if(e.unsafe.length>0||e.safe.length>0)throw Error(`foxdb sync: schema drift detected. Safe=${e.safe.length}, Unsafe=${e.unsafe.length}`);return!0}if(n==="auto")return!0;if(typeof n==="function")return n(e,t)!==!1;return!0}function Ue(e,t,n,r){if(e.safe.length===0&&e.unsafe.length===0)return;if(!mn(e,t,n))return;if(n==="auto"){if(Ke(e,t,r),e.unsafe.length>0)throw Error(`foxdb sync: ${e.unsafe.length} unsafe change(s) cannot be auto-applied. Use migrations.
35
+ )`),e.exec(`CREATE INDEX IF NOT EXISTS "idx_${s.tableName}__owner" ON "${s.tableName}" ("_owner_id")`)})}function Ke(e,t,n){for(let r of e.safe)switch(r.kind){case"add-table":{let s=We(n,r.table);if(!s)throw Error(`foxdb sync: missing desired schema for table "${r.table}"`);t.exec(ln(s));break}case"add-subtable":{mn(t,n,r);break}case"add-column":{if(!r.column.nullable)throw Error(`foxdb sync: cannot auto-apply required column "${r.column.name}" without default. Use a migration.`);t.exec(cn(r.table,r.column));break}case"add-index":{t.exec(un(r.table,r.index));break}case"change-nullable":{if(!r.to)throw Error(`foxdb sync: cannot auto-apply nullable \u2192 NOT NULL change on "${r.table}.${r.column}". Use a migration.`);let s=We(n,r.table);if(!s)throw Error(`foxdb sync: missing desired schema for table "${r.table}"`);dn(t,s);break}case"drop-index":{t.exec(`DROP INDEX IF EXISTS "${r.index.name}"`);break}}}function pn(e,t,n){if(e.unsafe.length===0&&e.safe.length===0)return!0;if(n==="ignore")return!0;if(n==="warn"){if(e.unsafe.length>0){console.warn(`[foxdb] ${e.unsafe.length} unsafe schema change(s) detected:`);for(let r of e.unsafe)console.warn(` - ${r.kind}: ${JSON.stringify(r)}`)}return!0}if(n==="error"){if(e.unsafe.length>0||e.safe.length>0)throw Error(`foxdb sync: schema drift detected. Safe=${e.safe.length}, Unsafe=${e.unsafe.length}`);return!0}if(n==="auto")return!0;if(typeof n==="function")return n(e,t)!==!1;return!0}function Ue(e,t,n,r){if(e.safe.length===0&&e.unsafe.length===0)return;if(!pn(e,t,n))return;if(n==="auto"){if(Ke(e,t,r),e.unsafe.length>0)throw Error(`foxdb sync: ${e.unsafe.length} unsafe change(s) cannot be auto-applied. Use migrations.
36
36
  `+e.unsafe.map((a)=>` - ${a.kind}: ${JSON.stringify(a)}`).join(`
37
- `));return}if(n==="ignore")return;if(n==="warn"||n==="error"){if(e.unsafe.length===0)Ke(e,t,r);return}if(typeof n==="function"){if(e.unsafe.length===0)Ke(e,t,r);return}}import{readdirSync as pn,existsSync as fn}from"fs";import{join as hn,resolve as yn}from"path";function gn(e){e.exec(`
37
+ `));return}if(n==="ignore")return;if(n==="warn"||n==="error"){if(e.unsafe.length===0)Ke(e,t,r);return}if(typeof n==="function"){if(e.unsafe.length===0)Ke(e,t,r);return}}import{readdirSync as fn,existsSync as hn}from"fs";import{join as yn,resolve as gn}from"path";function bn(e){e.exec(`
38
38
  CREATE TABLE IF NOT EXISTS "_foxdb_migrations" (
39
39
  "name" TEXT PRIMARY KEY,
40
40
  "appliedAt" INTEGER NOT NULL
41
41
  )
42
- `)}function bn(e){let n=e.prepare('SELECT "name" FROM "_foxdb_migrations"').all();return new Set(n.map((r)=>r.name))}function Tn(e,t){e.prepare('INSERT INTO "_foxdb_migrations" ("name", "appliedAt") VALUES (?, ?)').run(t,Date.now())}function Sn(e){if(!fn(e))return[];return pn(e,{withFileTypes:!0}).filter((r)=>r.isFile()&&r.name.endsWith(".ts")).map((r)=>({name:r.name.slice(0,-3),path:yn(hn(e,r.name))})).sort((r,s)=>r.name.localeCompare(s.name))}async function ye(e){let t=new K({path:e.path});try{gn(t);let n=bn(t),s=Sn(e.migrationsDir).filter((a)=>!n.has(a.name));if(s.length===0)return;for(let a of s){if(e.target&&a.name>e.target)break;let i=(await import(a.path)).default;if(!i)throw Error(`foxdb migrate: file "${a.path}" does not export a default Migration`);if(typeof i.up!=="function")throw Error(`foxdb migrate: migration "${i.name}" is missing an up() function`);t.transaction(()=>{i.up(t),Tn(t,a.name)})}}finally{t.close()}}class ge{listeners=new Map;tableActive=new Set;has(e){let t=this.listeners.get(e);return t!==void 0&&t.size>0}hasAny(e){return this.tableActive.has(e)}on(e,t){if(!this.listeners.has(e))this.listeners.set(e,new Set);this.listeners.get(e).add(t);let n=e.split(".")[0];if(n&&n!=="*")this.tableActive.add(n);return()=>{let r=this.listeners.get(e);if(r){if(r.delete(t),r.size===0)this.listeners.delete(e)}}}emit(e,t){let n=this.listeners.get(e);if(n)for(let s of n)try{s(t)}catch(a){console.error(`[foxdb] event listener error for "${e}":`,a)}let r=e.indexOf(".");if(r>0){let a=`${e.slice(0,r)}.*`,o=this.listeners.get(a);if(o)for(let i of o)try{i(t)}catch(l){console.error(`[foxdb] event listener error for "${a}":`,l)}}}emitIf(e,t){let n=e.indexOf("."),r=n>0&&this.has(`${e.slice(0,n)}.*`);if(this.has(e)||r)this.emit(e,t)}}function Rn(e){return typeof e==="object"&&e!==null&&"then"in e&&typeof e.then==="function"}function be(e,t,n){for(let r of e)try{let s=r(t);if(s&&Rn(s))s.catch((a)=>{console.error(`[foxdb] async ${n} hook error:`,a)})}catch(s){console.error(`[foxdb] ${n} hook error:`,s)}}class Te{startHooks=[];readyHooks=[];shutdownHooks=[];exitHooks=[];_ready=!1;_shutdown=!1;get isReady(){return this._ready}get isShutdown(){return this._shutdown}onStart(e){this.startHooks.push(e)}onReady(e){this.readyHooks.push(e)}onShutdown(e){this.shutdownHooks.push(e)}onExit(e){this.exitHooks.push(e)}runStart(e){be(this.startHooks,e,"onStart")}runReady(e){be(this.readyHooks,e,"onReady"),this._ready=!0}runShutdown(e){if(this._shutdown)return;this._shutdown=!0,be(this.shutdownHooks,e,"onShutdown")}runExit(e){be(this.exitHooks,e,"onExit")}}function wn(e){let t=e.path??":memory:";if(e.rebuildOnLaunch&&t!==":memory:"&&t.length>0)ae(t);let n=new K(e);if(e.autoVacuum==="incremental"&&e.vacuumIntervalMs)n.scheduler.schedule("auto-vacuum",e.vacuumIntervalMs,()=>{try{n.exec("PRAGMA incremental_vacuum(1000);")}catch{}});let r,s=new ge;try{let ie=function(f,b){let w=u.filter((g)=>g.ownerTable===f);if(w.length===0)return b;let y={};for(let[g,S]of Object.entries(b))y[g]=S;let N=w.filter((g)=>g.kind==="scalar");if(N.length>0){let g=new Proxy({},{get(S,R){let x=N.find((E)=>E.as===R||E.ownerField===R);if(!x)return;let M=o.get(x.targetTable);if(!M)return null;let A=b[x.ownerField];if(A==null)return null;return M.raw(`SELECT * FROM "${x.targetTable}" WHERE "${x.targetField}" = ? LIMIT 1`,A)[0]??null}});Object.defineProperty(y,"related",{value:g,writable:!1,enumerable:!1,configurable:!1});for(let S of N)if(S.as)Object.defineProperty(y,S.as,{get(){return y.related[S.as]},enumerable:!1,configurable:!1})}let v=w.filter((g)=>g.kind==="subTable");for(let g of v){let[S,R]=g.ownerField.split("."),x=y[S];if(!globalThis.Array.isArray(x))continue;let M=o.get(g.targetTable);if(!M)continue;let A=x.map((E)=>E[R]).filter((E)=>E!=null),q=new Map;if(A.length>0){let E=A.map(()=>"?").join(", "),I=M.raw(`SELECT * FROM "${g.targetTable}" WHERE "${g.targetField}" IN (${E})`,...A);q=new Map(I.map((L)=>[L[g.targetField],L]))}y[S]=x.map((E)=>{let I=q.get(E[R])??null,L=Object.create(null);Object.assign(L,E);let j=new Proxy({},{get(Re,F){if(F===g.as||F===g.ownerField)return I;return}});if(Object.defineProperty(L,"related",{value:j,writable:!1,enumerable:!1,configurable:!1}),g.as)Object.defineProperty(L,g.as,{value:I,writable:!1,enumerable:!1,configurable:!1});return L})}return y},Ve=function(f,b){if(b.length===0)return[];let w=u.filter((g)=>g.ownerTable===f);if(w.length===0)return b;let y=b.map((g)=>{let S=Object.getPrototypeOf(g),R=S?Object.create(S):{};return Object.assign(R,g),R}),N=w.filter((g)=>g.kind==="scalar"),v=w.filter((g)=>g.kind==="subTable");for(let g of N){let S=o.get(g.targetTable);if(!S)continue;let R=g.ownerField,x=[...new Set(y.map((E)=>E[R]).filter((E)=>E!==null&&E!==void 0))];if(x.length===0)continue;let M=x.map(()=>"?").join(", "),A=S.raw(`SELECT * FROM "${g.targetTable}" WHERE "${g.targetField}" IN (${M})`,...x),q=new Map(A.map((E)=>[E[g.targetField],E]));for(let E of y){let I=q.get(E[R]);if(I)Object.defineProperty(E,`_${R}_resolved`,{value:I,writable:!1,enumerable:!1,configurable:!1})}}for(let g of v){let S=o.get(g.targetTable);if(!S)continue;let[R,x]=g.ownerField.split("."),M=[...new Set(y.flatMap((I)=>{let L=I[R];if(!globalThis.Array.isArray(L))return[];return L.map((j)=>j[x]).filter((j)=>j!==null&&j!==void 0)}))];if(M.length===0)continue;let A=M.map(()=>"?").join(", "),q=S.raw(`SELECT * FROM "${g.targetTable}" WHERE "${g.targetField}" IN (${A})`,...M),E=new Map(q.map((I)=>[I[g.targetField],I]));for(let I of y){let L=I[R];if(!globalThis.Array.isArray(L))continue;I[R]=L.map((j)=>{let Re=E.get(j[x])??null,F=Object.create(null);Object.assign(F,j);let _t=new Proxy({},{get(Dn,Ge){if(Ge===g.as||Ge===g.ownerField)return Re;return}});if(Object.defineProperty(F,"related",{value:_t,writable:!1,enumerable:!1,configurable:!1}),g.as)Object.defineProperty(F,g.as,{value:Re,writable:!1,enumerable:!1,configurable:!1});return F})}}if(N.length>0)for(let g of y){let S=new Proxy({},{get(R,x){let M=N.find((A)=>A.as===x||A.ownerField===x);if(!M)return;return g[`_${M.ownerField}_resolved`]??null}});Object.defineProperty(g,"related",{value:S,writable:!1,enumerable:!1,configurable:!1});for(let R of N)if(R.as)Object.defineProperty(g,R.as,{get(){return g[`_${R.ownerField}_resolved`]??null},enumerable:!1,configurable:!1})}return y},Rt=function(f){for(let b of o.values())b.flush();if(f?.includeMeta)for(let b of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])c.delete(b)},Ot=function(){if(i.runShutdown(l),e.flushOnExit)for(let b of e.flushOnExit)o.get(b)?.flush();if(e.dropOnExit)for(let b of e.dropOnExit)o.get(b)?.drop();if(e.flushMetaOnExit)for(let b of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])c.delete(b);n.close(),i.runExit(l),s.emit("exit",{phase:"exit",timestamp:Date.now()});let f=e.unlinkDbFilesOnExit;if(f===!0||f==="onlyGraceful")ae(t)},a=Object.entries(e.tables);if(a.length===0)O("NO_TABLES","foxdb: at least one table must be defined in `tables`");let o=new Map;for(let[f,b]of a){let w=J(f,b.schema,ne(b.generated)),y=new Set(w.columns.map((g)=>g.name)),N=b.primaryKey.name;if(!y.has(N))O("INVALID_PK",`foxdb: primary key "${N}" is not a scalar column in table "${f}"`,{table:f,column:N});for(let g of b.indexes??[])for(let S of g.columns)if(!y.has(S.name))O("INVALID_INDEX",`foxdb: index column "${S.name}" not found in table "${f}"`,{table:f,column:S.name});let v=new he(f,b,n);o.set(f,v)}for(let[f,b]of o)b.setEventBus(s);if(e.hooks?.onQuery)for(let f of o.values())f.setMetricsHook(e.hooks.onQuery);let i=new Te;if(e.onStart)i.onStart(e.onStart);if(e.onReady)i.onReady(e.onReady);if(e.onShutdown)i.onShutdown(e.onShutdown);if(e.onExit)i.onExit(e.onExit);let l,u=[];if(typeof e.relations==="function"){let f=Qe(e.tables),b=e.relations(f);for(let w of b)u.push(w)}else for(let[f,b]of Object.entries(e.relations??{})){if(!b)continue;let w=o.get(f);if(!w)O("INVALID_RELATION",`foxdb: relation owner table "${f}" not found in tables`,{table:f});for(let y of b){let N=o.get(y.targetTableName);if(!N)O("INVALID_RELATION",`foxdb: relation target table "${y.targetTableName}" not found in tables`,{table:y.targetTableName});let v=y.ownerField.split(".");if(v.length===1){let[S=""]=v;if(!new Set(w.meta.columns.map((x)=>x.name)).has(S))O("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" is not a scalar column in table "${f}"`,{table:f,field:y.ownerField})}else if(v.length===2){let[S="",R=""]=v,x=w.meta.subTables.find((A)=>A.fieldName===S);if(!x)O("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" references unknown sub-table "${S}" in table "${f}"`,{table:f,field:y.ownerField});if(!new Set(x.columns.map((A)=>A.name)).has(R))O("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" references unknown column "${R}" in sub-table "${S}" of table "${f}"`,{table:f,field:y.ownerField})}else O("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" has too many dot segments (max 2 allowed)`,{table:f,field:y.ownerField});if(!new Set(N.meta.columns.map((S)=>S.name)).has(y.targetField))O("INVALID_RELATION",`foxdb: relation targetField "${y.targetField}" is not a scalar column in table "${y.targetTableName}"`,{table:y.targetTableName,field:y.targetField});u.push({ownerTable:f,ownerField:y.ownerField,targetTable:y.targetTableName,targetField:y.targetField,kind:v.length===1?"scalar":"subTable",as:void 0})}}let m=[];for(let[f,b]of a){let w=J(f,b.schema,ne(b.generated));m.push({name:f,columns:w.columns,indexes:(b.indexes??[]).map((y)=>({name:y.name,columns:y.columns.map((N)=>N.name),unique:y.unique})),primaryKey:b.primaryKey.name});for(let y of w.subTables)m.push({name:y.tableName,columns:y.columns,indexes:(b.subTables?.[y.fieldName]?.indexes??[]).map((N)=>({name:N.name,columns:N.columns.map((v)=>v.name),unique:N.unique})),primaryKey:"_id"})}let c=new $(n),d=Object.fromEntries(a.map(([f,b])=>[f,b.schema])),p=JSON.stringify(d),h=Bun.hash(p),T=new TextEncoder().encode(p),k=c.getString("_schema_hash"),D=String(h);if(k!==D&&e.sync&&e.sync!=="ignore"){let f=qe(n),b=Fe(m,f);Ue(b,n,e.sync,m)}c.setString("_schema_hash",D),c.setCompressed("_schema_compressed",T),c.setJSON("_tables",Object.keys(e.tables)),c.setJSON("_relations",u),c.setString("_foxdb_version","0.0.2");let wt={get schemaHash(){return c.getString("_schema_hash")},get schemaJSON(){let f=c.getCompressed("_schema_compressed");return f?new TextDecoder().decode(f):null},get tables(){return c.getJSON("_tables")},get relations(){return c.getJSON("_relations")},get version(){return c.getString("_foxdb_version")}};for(let[f,b]of o){if(u.filter((y)=>y.ownerTable===f).length===0)continue;b.setMaterializer((y)=>ie(f,y),(y)=>Ve(f,y))}r=Object.create(null);for(let f of Object.keys(e.tables))Object.defineProperty(r,f,{get(){return o.get(f)},enumerable:!0,configurable:!0});let xt=async()=>{if(!e.migrations)O("MIGRATIONS_NOT_CONFIGURED","foxdb: migrations dir not configured. Pass `migrations: { dir: ... }` to createORM().");await ye({path:t,migrationsDir:e.migrations.dir})},Et={on(f,b,w){if(typeof b==="string"&&typeof w==="function"){let y=`${f}.${b}`;return s.on(y,w)}if(typeof b==="function")return s.on(f,b);O("INVALID_EVENT_LISTENER","foxdb: invalid event listener arguments")}};if(e.bulkLoadMode)n.setSynchronous("OFF");if(l={orm:r,db:n,meta:c,tables:Object.keys(e.tables),repos:o,logger:{log:(...f)=>{console.log("[foxdb]",...f)},error:(...f)=>{console.error("[foxdb]",...f)}}},e.unlinkDbFilesOnExit==="any"){let f=()=>{try{ae(t)}catch{}},b=()=>{i.runExit(l),f(),process.exit(1)};process.on("exit",f),process.on("SIGINT",b),process.on("SIGTERM",b),process.on("uncaughtException",(w)=>{s.emit("fail",{phase:"fail",error:w,timestamp:Date.now()}),b()})}if(Object.assign(r,{_transaction:n.transaction.bind(n),_close:Ot,_setBulkLoadMode(f){n.setSynchronous(f?"OFF":"NORMAL")},_meta:wt,_materialize:ie,_materializeMany:Ve,_flush:Rt,_migrate:xt,_events:Et}),i.runStart(l),e.flushOnStart)for(let f of e.flushOnStart)o.get(f)?.flush();if(e.dropOnStart)for(let f of e.dropOnStart)o.get(f)?.drop();if(e.flushMetaOnStart)for(let f of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])c.delete(f);if(e.autoMigrate&&e.migrations)ye({path:t,migrationsDir:e.migrations.dir}).catch((f)=>{console.error("[foxdb] autoMigrate failed:",f)});if(e.seed)e.seed(r);i.runReady(l),s.emit("ready",{phase:"ready",timestamp:Date.now()})}catch(a){if(a instanceof G)s.emit("fail",{phase:"fail",error:a,timestamp:Date.now()});else{let o=new G(String(a),{code:"UNEXPECTED",trace:_e()});s.emit("fail",{phase:"fail",error:o,timestamp:Date.now()})}throw a}return r}import{IsString as xn,IsNumber as En,IsInteger as On,IsBoolean as _n,IsLiteral as Nn,IsObject as Tt,IsOptional as kn}from"typebox";function He(e){return xn(e)||En(e)||On(e)||_n(e)||Nn(e)}function Se(e){if(kn(e)){let t=e,n={};for(let r of Object.keys(t)){if(r==="~optional")continue;n[r]=t[r]}return n}return e}function St(e){let t={};for(let n of Object.keys(e.properties)){let r=e.properties[n];if(r&&He(r))t[n]={_tag:"ColumnRef",name:n,schema:r};if(r){let s=Se(r);if(s&&Tt(s)){let o=s.properties;for(let i of Object.keys(o)){let l=o[i];if(l){let u=Se(l);if(He(u)){let c=`${n}__${i}`;t[c]={_tag:"ColumnRef",name:c,schema:u}}let m=Se(l);if(m&&Tt(m)){let d=m.properties;for(let p of Object.keys(d)){let h=d[p];if(h){let T=Se(h);if(He(T)){let k=`${n}__${i}__${p}`;t[k]={_tag:"ColumnRef",name:k,schema:T}}}}}}}}}}return t}function Cn(e,t){let n=St(e),r=t(n);return{schema:e,...r}}import{existsSync as An,mkdirSync as $n,writeFileSync as Mn}from"fs";import{join as In,resolve as vn}from"path";function Ln(e,t){return`import type { Migration } from "@xwxfox/foxdb";
42
+ `)}function Tn(e){let n=e.prepare('SELECT "name" FROM "_foxdb_migrations"').all();return new Set(n.map((r)=>r.name))}function Sn(e,t){e.prepare('INSERT INTO "_foxdb_migrations" ("name", "appliedAt") VALUES (?, ?)').run(t,Date.now())}function Rn(e){if(!hn(e))return[];return fn(e,{withFileTypes:!0}).filter((r)=>r.isFile()&&r.name.endsWith(".ts")).map((r)=>({name:r.name.slice(0,-3),path:gn(yn(e,r.name))})).sort((r,s)=>r.name.localeCompare(s.name))}async function ye(e){let t=new K({path:e.path});try{bn(t);let n=Tn(t),s=Rn(e.migrationsDir).filter((a)=>!n.has(a.name));if(s.length===0)return;for(let a of s){if(e.target&&a.name>e.target)break;let i=(await import(a.path)).default;if(!i)throw Error(`foxdb migrate: file "${a.path}" does not export a default Migration`);if(typeof i.up!=="function")throw Error(`foxdb migrate: migration "${i.name}" is missing an up() function`);t.transaction(()=>{i.up(t),Sn(t,a.name)})}}finally{t.close()}}class ge{listeners=new Map;tableActive=new Set;has(e){let t=this.listeners.get(e);return t!==void 0&&t.size>0}hasAny(e){return this.tableActive.has(e)}on(e,t){if(!this.listeners.has(e))this.listeners.set(e,new Set);this.listeners.get(e).add(t);let n=e.split(".")[0];if(n&&n!=="*")this.tableActive.add(n);return()=>{let r=this.listeners.get(e);if(r){if(r.delete(t),r.size===0)this.listeners.delete(e)}}}emit(e,t){let n=this.listeners.get(e);if(n)for(let s of n)try{s(t)}catch(a){console.error(`[foxdb] event listener error for "${e}":`,a)}let r=e.indexOf(".");if(r>0){let a=`${e.slice(0,r)}.*`,o=this.listeners.get(a);if(o)for(let i of o)try{i(t)}catch(l){console.error(`[foxdb] event listener error for "${a}":`,l)}}}emitIf(e,t){let n=e.indexOf("."),r=n>0&&this.has(`${e.slice(0,n)}.*`);if(this.has(e)||r)this.emit(e,t)}}function wn(e){return typeof e==="object"&&e!==null&&"then"in e&&typeof e.then==="function"}function be(e,t,n){for(let r of e)try{let s=r(t);if(s&&wn(s))s.catch((a)=>{console.error(`[foxdb] async ${n} hook error:`,a)})}catch(s){console.error(`[foxdb] ${n} hook error:`,s)}}class Te{startHooks=[];readyHooks=[];shutdownHooks=[];exitHooks=[];_ready=!1;_shutdown=!1;get isReady(){return this._ready}get isShutdown(){return this._shutdown}onStart(e){this.startHooks.push(e)}onReady(e){this.readyHooks.push(e)}onShutdown(e){this.shutdownHooks.push(e)}onExit(e){this.exitHooks.push(e)}runStart(e){be(this.startHooks,e,"onStart")}runReady(e){be(this.readyHooks,e,"onReady"),this._ready=!0}runShutdown(e){if(this._shutdown)return;this._shutdown=!0,be(this.shutdownHooks,e,"onShutdown")}runExit(e){be(this.exitHooks,e,"onExit")}}function xn(e){let t=e.path??":memory:";if(e.rebuildOnLaunch&&t!==":memory:"&&t.length>0)ie(t);let n=new K(e);if(e.autoVacuum==="incremental"&&e.vacuumIntervalMs)n.scheduler.schedule("auto-vacuum",e.vacuumIntervalMs,()=>{try{n.exec("PRAGMA incremental_vacuum(1000);")}catch{}});let r,s=new ge;try{let ae=function(p,b){let x=u.filter((g)=>g.ownerTable===p);if(x.length===0)return b;let y={};for(let[g,R]of Object.entries(b))y[g]=R;let k=x.filter((g)=>g.kind==="scalar");if(k.length>0){let g=new Proxy({},{get(R,w){let E=k.find((O)=>O.as===w||O.ownerField===w);if(!E)return;let M=o.get(E.targetTable);if(!M)return null;let A=b[E.ownerField];if(A==null)return null;return M.raw(`SELECT * FROM "${E.targetTable}" WHERE "${E.targetField}" = ? LIMIT 1`,A)[0]??null}});Object.defineProperty(y,"related",{value:g,writable:!1,enumerable:!1,configurable:!1});for(let R of k)if(R.as)Object.defineProperty(y,R.as,{get(){return y.related[R.as]},enumerable:!1,configurable:!1})}let B=x.filter((g)=>g.kind==="subTable");for(let g of B){let[R,w]=g.ownerField.split("."),E=y[R];if(!globalThis.Array.isArray(E))continue;let M=o.get(g.targetTable);if(!M)continue;let A=E.map((O)=>O[w]).filter((O)=>O!=null),q=new Map;if(A.length>0){let O=A.map(()=>"?").join(", "),I=M.raw(`SELECT * FROM "${g.targetTable}" WHERE "${g.targetField}" IN (${O})`,...A);q=new Map(I.map((L)=>[L[g.targetField],L]))}y[R]=E.map((O)=>{let I=q.get(O[w])??null,L=Object.create(null);Object.assign(L,O);let j=new Proxy({},{get(Re,F){if(F===g.as||F===g.ownerField)return I;return}});if(Object.defineProperty(L,"related",{value:j,writable:!1,enumerable:!1,configurable:!1}),g.as)Object.defineProperty(L,g.as,{value:I,writable:!1,enumerable:!1,configurable:!1});return L})}return y},Ve=function(p,b){if(b.length===0)return[];let x=u.filter((g)=>g.ownerTable===p);if(x.length===0)return b;let y=b.map((g)=>{let R=Object.getPrototypeOf(g),w=R?Object.create(R):{};return Object.assign(w,g),w}),k=x.filter((g)=>g.kind==="scalar"),B=x.filter((g)=>g.kind==="subTable");for(let g of k){let R=o.get(g.targetTable);if(!R)continue;let w=g.ownerField,E=[...new Set(y.map((O)=>O[w]).filter((O)=>O!==null&&O!==void 0))];if(E.length===0)continue;let M=E.map(()=>"?").join(", "),A=R.raw(`SELECT * FROM "${g.targetTable}" WHERE "${g.targetField}" IN (${M})`,...E),q=new Map(A.map((O)=>[O[g.targetField],O]));for(let O of y){let I=q.get(O[w]);if(I)Object.defineProperty(O,`_${w}_resolved`,{value:I,writable:!1,enumerable:!1,configurable:!1})}}for(let g of B){let R=o.get(g.targetTable);if(!R)continue;let[w,E]=g.ownerField.split("."),M=[...new Set(y.flatMap((I)=>{let L=I[w];if(!globalThis.Array.isArray(L))return[];return L.map((j)=>j[E]).filter((j)=>j!==null&&j!==void 0)}))];if(M.length===0)continue;let A=M.map(()=>"?").join(", "),q=R.raw(`SELECT * FROM "${g.targetTable}" WHERE "${g.targetField}" IN (${A})`,...M),O=new Map(q.map((I)=>[I[g.targetField],I]));for(let I of y){let L=I[w];if(!globalThis.Array.isArray(L))continue;I[w]=L.map((j)=>{let Re=O.get(j[E])??null,F=Object.create(null);Object.assign(F,j);let Nt=new Proxy({},{get(Pn,Ge){if(Ge===g.as||Ge===g.ownerField)return Re;return}});if(Object.defineProperty(F,"related",{value:Nt,writable:!1,enumerable:!1,configurable:!1}),g.as)Object.defineProperty(F,g.as,{value:Re,writable:!1,enumerable:!1,configurable:!1});return F})}}if(k.length>0)for(let g of y){let R=new Proxy({},{get(w,E){let M=k.find((A)=>A.as===E||A.ownerField===E);if(!M)return;return g[`_${M.ownerField}_resolved`]??null}});Object.defineProperty(g,"related",{value:R,writable:!1,enumerable:!1,configurable:!1});for(let w of k)if(w.as)Object.defineProperty(g,w.as,{get(){return g[`_${w.ownerField}_resolved`]??null},enumerable:!1,configurable:!1})}return y},Rt=function(p){for(let b of o.values())b.flush();if(p?.includeMeta)for(let b of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])c.delete(b)},Ot=function(){if(i.runShutdown(l),e.flushOnExit)for(let b of e.flushOnExit)o.get(b)?.flush();if(e.dropOnExit)for(let b of e.dropOnExit)o.get(b)?.drop();if(e.flushMetaOnExit)for(let b of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])c.delete(b);n.close(),i.runExit(l),s.emit("exit",{phase:"exit",timestamp:Date.now()});let p=e.unlinkDbFilesOnExit;if(p===!0||p==="onlyGraceful")ie(t)},a=Object.entries(e.tables);if(a.length===0)N("NO_TABLES","foxdb: at least one table must be defined in `tables`");let o=new Map;for(let[p,b]of a){let x=J(p,b.schema,ne(b.generated)),y=new Set(x.columns.map((g)=>g.name)),k=b.primaryKey.name;if(!y.has(k))N("INVALID_PK",`foxdb: primary key "${k}" is not a scalar column in table "${p}"`,{table:p,column:k});for(let g of b.indexes??[])for(let R of g.columns)if(!y.has(R.name))N("INVALID_INDEX",`foxdb: index column "${R.name}" not found in table "${p}"`,{table:p,column:R.name});let B=new he(p,b,n);o.set(p,B)}for(let[p,b]of o)b.setEventBus(s);if(e.hooks?.onQuery)for(let p of o.values())p.setMetricsHook(e.hooks.onQuery);let i=new Te;if(e.onStart)i.onStart(e.onStart);if(e.onReady)i.onReady(e.onReady);if(e.onShutdown)i.onShutdown(e.onShutdown);if(e.onExit)i.onExit(e.onExit);let l,u=[];if(typeof e.relations==="function"){let p=Qe(e.tables),b=e.relations(p);for(let x of b)u.push(x)}else for(let[p,b]of Object.entries(e.relations??{})){if(!b)continue;let x=o.get(p);if(!x)N("INVALID_RELATION",`foxdb: relation owner table "${p}" not found in tables`,{table:p});for(let y of b){let k=o.get(y.targetTableName);if(!k)N("INVALID_RELATION",`foxdb: relation target table "${y.targetTableName}" not found in tables`,{table:y.targetTableName});let B=y.ownerField.split(".");if(B.length===1){let[R=""]=B;if(!new Set(x.meta.columns.map((E)=>E.name)).has(R))N("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" is not a scalar column in table "${p}"`,{table:p,field:y.ownerField})}else if(B.length===2){let[R="",w=""]=B,E=x.meta.subTables.find((A)=>A.fieldName===R);if(!E)N("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" references unknown sub-table "${R}" in table "${p}"`,{table:p,field:y.ownerField});if(!new Set(E.columns.map((A)=>A.name)).has(w))N("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" references unknown column "${w}" in sub-table "${R}" of table "${p}"`,{table:p,field:y.ownerField})}else N("INVALID_RELATION",`foxdb: relation ownerField "${y.ownerField}" has too many dot segments (max 2 allowed)`,{table:p,field:y.ownerField});if(!new Set(k.meta.columns.map((R)=>R.name)).has(y.targetField))N("INVALID_RELATION",`foxdb: relation targetField "${y.targetField}" is not a scalar column in table "${y.targetTableName}"`,{table:y.targetTableName,field:y.targetField});u.push({ownerTable:p,ownerField:y.ownerField,targetTable:y.targetTableName,targetField:y.targetField,kind:B.length===1?"scalar":"subTable",as:void 0})}}let d=[];for(let[p,b]of a){let x=J(p,b.schema,ne(b.generated));d.push({name:p,columns:x.columns,indexes:(b.indexes??[]).map((y)=>({name:y.name,columns:y.columns.map((k)=>k.name),unique:y.unique})),primaryKey:b.primaryKey.name});for(let y of x.subTables)d.push({name:y.tableName,columns:y.columns,indexes:(b.subTables?.[y.fieldName]?.indexes??[]).map((k)=>({name:k.name,columns:k.columns.map((B)=>B.name),unique:k.unique})),primaryKey:"_id"})}let c=new $(n),m=Object.fromEntries(a.map(([p,b])=>[p,b.schema])),f=JSON.stringify(m),h=Bun.hash(f),T=new TextEncoder().encode(f),S=c.getString("_schema_hash"),v=String(h);if(S!==v&&e.sync&&e.sync!=="ignore"){let p=qe(n),b=Fe(d,p);Ue(b,n,e.sync,d)}c.setString("_schema_hash",v),c.setCompressed("_schema_compressed",T),c.setJSON("_tables",Object.keys(e.tables)),c.setJSON("_relations",u),c.setString("_foxdb_version","0.0.2");let wt={get schemaHash(){return c.getString("_schema_hash")},get schemaJSON(){let p=c.getCompressed("_schema_compressed");return p?new TextDecoder().decode(p):null},get tables(){return c.getJSON("_tables")},get relations(){return c.getJSON("_relations")},get version(){return c.getString("_foxdb_version")}};for(let[p,b]of o){if(u.filter((y)=>y.ownerTable===p).length===0)continue;b.setMaterializer((y)=>ae(p,y),(y)=>Ve(p,y))}r=Object.create(null);for(let p of Object.keys(e.tables))Object.defineProperty(r,p,{get(){return o.get(p)},enumerable:!0,configurable:!0});let xt=async()=>{if(!e.migrations)N("MIGRATIONS_NOT_CONFIGURED","foxdb: migrations dir not configured. Pass `migrations: { dir: ... }` to createORM().");await ye({path:t,migrationsDir:e.migrations.dir})},Et={on(p,b,x){if(typeof b==="string"&&typeof x==="function"){let y=`${p}.${b}`;return s.on(y,x)}if(typeof b==="function")return s.on(p,b);N("INVALID_EVENT_LISTENER","foxdb: invalid event listener arguments")}};if(e.bulkLoadMode)n.setSynchronous("OFF");if(l={orm:r,db:n,meta:c,tables:Object.keys(e.tables),repos:o,logger:{log:(...p)=>{console.log("[foxdb]",...p)},error:(...p)=>{console.error("[foxdb]",...p)}}},e.unlinkDbFilesOnExit==="any"){let p=()=>{try{ie(t)}catch{}},b=()=>{i.runExit(l),p(),process.exit(1)};process.on("exit",p),process.on("SIGINT",b),process.on("SIGTERM",b),process.on("uncaughtException",(x)=>{s.emit("fail",{phase:"fail",error:x,timestamp:Date.now()}),b()})}if(Object.assign(r,{_transaction:n.transaction.bind(n),_close:Ot,_setBulkLoadMode(p){n.setSynchronous(p?"OFF":"NORMAL")},_meta:wt,_materialize:ae,_materializeMany:Ve,_flush:Rt,_migrate:xt,_events:Et}),i.runStart(l),e.flushOnStart)for(let p of e.flushOnStart)o.get(p)?.flush();if(e.dropOnStart)for(let p of e.dropOnStart)o.get(p)?.drop();if(e.flushMetaOnStart)for(let p of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])c.delete(p);if(e.autoMigrate&&e.migrations)ye({path:t,migrationsDir:e.migrations.dir}).catch((p)=>{console.error("[foxdb] autoMigrate failed:",p)});if(e.seed)e.seed(r);i.runReady(l),s.emit("ready",{phase:"ready",timestamp:Date.now()})}catch(a){if(a instanceof G)s.emit("fail",{phase:"fail",error:a,timestamp:Date.now()});else{let o=new G(String(a),{code:"UNEXPECTED",trace:Ne()});s.emit("fail",{phase:"fail",error:o,timestamp:Date.now()})}throw a}return r}import{IsString as En,IsNumber as On,IsInteger as Nn,IsBoolean as _n,IsLiteral as kn,IsObject as Tt,IsOptional as Cn}from"typebox";function He(e){return En(e)||On(e)||Nn(e)||_n(e)||kn(e)}function Se(e){if(Cn(e)){let t=e,n={};for(let r of Object.keys(t)){if(r==="~optional")continue;n[r]=t[r]}return n}return e}function St(e){let t={};for(let n of Object.keys(e.properties)){let r=e.properties[n];if(r&&He(r))t[n]={_tag:"ColumnRef",name:n,schema:r};if(r){let s=Se(r);if(s&&Tt(s)){let o=s.properties;for(let i of Object.keys(o)){let l=o[i];if(l){let u=Se(l);if(He(u)){let c=`${n}__${i}`;t[c]={_tag:"ColumnRef",name:c,schema:u}}let d=Se(l);if(d&&Tt(d)){let m=d.properties;for(let f of Object.keys(m)){let h=m[f];if(h){let T=Se(h);if(He(T)){let S=`${n}__${i}__${f}`;t[S]={_tag:"ColumnRef",name:S,schema:T}}}}}}}}}}return t}function An(e,t){let n=St(e),r=t(n);return{schema:e,...r}}import{existsSync as $n,mkdirSync as Mn,writeFileSync as In}from"fs";import{join as vn,resolve as Bn}from"path";function Ln(e,t){return`import type { Migration } from "@xwxfox/foxdb";
43
43
 
44
44
  export default {
45
45
  name: "${e}",
@@ -49,4 +49,4 @@ export default {
49
49
  // Your migration logic here
50
50
  },
51
51
  } satisfies Migration;
52
- `}function Bn(e,t){if(!An(t))$n(t,{recursive:!0});let n=new Date,r=n.getFullYear(),s=String(n.getMonth()+1).padStart(2,"0"),a=String(n.getDate()).padStart(2,"0"),o=String(n.getHours()).padStart(2,"0"),i=String(n.getMinutes()).padStart(2,"0"),l=String(n.getSeconds()).padStart(2,"0"),m=`${`${r}${s}${a}_${o}${i}${l}`}_${e}.ts`,c=vn(In(t,m)),d=n.toISOString(),p=Ln(e,d);return Mn(c,p,"utf-8"),c}export{C as withTrace,Cn as table,Pe as resolveTimestampNames,O as raise,ye as migrate,J as introspectTable,gt as inspectSchema,qe as inspectAllTables,Qe as createRelationBuilder,wn as createORM,Bn as createMigration,Fe as computeDiff,Ie as buildCreateTableSQL,Ue as applySync,yt as SchemaJSONSchema,he as Repository,G as ORMError,$ as MetaStore,Te as LifecycleManager,ge as EventBus,De as DEFAULT_TIMESTAMP_NAMES,K as BunDatabase,fe as BatchWriter};
52
+ `}function Dn(e,t){if(!$n(t))Mn(t,{recursive:!0});let n=new Date,r=n.getFullYear(),s=String(n.getMonth()+1).padStart(2,"0"),a=String(n.getDate()).padStart(2,"0"),o=String(n.getHours()).padStart(2,"0"),i=String(n.getMinutes()).padStart(2,"0"),l=String(n.getSeconds()).padStart(2,"0"),d=`${`${r}${s}${a}_${o}${i}${l}`}_${e}.ts`,c=Bn(vn(t,d)),m=n.toISOString(),f=Ln(e,m);return In(c,f,"utf-8"),c}export{C as withTrace,An as table,Pe as resolveTimestampNames,N as raise,ye as migrate,J as introspectTable,gt as inspectSchema,qe as inspectAllTables,Qe as createRelationBuilder,xn as createORM,Dn as createMigration,Fe as computeDiff,Ie as buildCreateTableSQL,Ue as applySync,yt as SchemaJSONSchema,he as Repository,G as ORMError,$ as MetaStore,Te as LifecycleManager,ge as EventBus,De as DEFAULT_TIMESTAMP_NAMES,K as BunDatabase,fe as BatchWriter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xwxfox/foxdb",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "itty bitty e2e typed orm for bun :3",
5
5
  "main": "dist/index.mjs",
6
6
  "publishConfig": {
@@ -65,4 +65,4 @@
65
65
  "dependencies": {
66
66
  "typebox": "^1.1.34"
67
67
  }
68
- }
68
+ }