@xwxfox/foxdb 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +20 -20
- package/README.md +275 -274
- package/dist/index.d.mts +810 -137
- package/dist/index.mjs +23 -19
- package/package.json +3 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TObject,
|
|
1
|
+
import { TSchema as TSchema6 } from "typebox";
|
|
2
|
+
import { TObject as TObject2, TArray, TSchema as TSchema2, TProperties, TOptional as TOptional2, Static } from "typebox";
|
|
3
|
+
import { TObject, TString, TNumber, TInteger, TBoolean, TLiteral, TSchema, TOptional } from "typebox";
|
|
3
4
|
/** @category Schema */
|
|
4
5
|
type TScalarSchema = TString | TNumber | TInteger | TBoolean | TLiteral<string> | TLiteral<number> | TLiteral<boolean>;
|
|
5
6
|
/**
|
|
@@ -14,11 +15,24 @@ interface ColumnRef<
|
|
|
14
15
|
readonly name: N;
|
|
15
16
|
readonly schema: S;
|
|
16
17
|
}
|
|
18
|
+
type UnwrapOptionalSchema<S extends TSchema> = S extends TOptional<infer U> ? U : S;
|
|
19
|
+
type IsScalarSchema<S extends TSchema> = S extends TString ? true : S extends TNumber ? true : S extends TInteger ? true : S extends TBoolean ? true : S extends TLiteral<string | number | boolean> ? true : false;
|
|
20
|
+
type NestedColumnKeys<T extends TSchema & {
|
|
21
|
+
properties: Record<string, TSchema>;
|
|
22
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptionalSchema<T["properties"][K]> extends TObject<infer P> ? { [K2 in keyof P & string] : IsScalarSchema<UnwrapOptionalSchema<P[K2]>> extends true ? `${K}__${K2}` : UnwrapOptionalSchema<P[K2]> extends TObject<infer P2> ? { [K3 in keyof P2 & string] : IsScalarSchema<UnwrapOptionalSchema<P2[K3]>> extends true ? `${K}__${K2}__${K3}` : never }[keyof P2 & string] : never }[keyof P & string] : never }[keyof T["properties"] & string];
|
|
23
|
+
type NestedColumnRef<
|
|
24
|
+
T extends TSchema & {
|
|
25
|
+
properties: Record<string, TSchema>;
|
|
26
|
+
},
|
|
27
|
+
N extends string
|
|
28
|
+
> = N extends `${infer K}__${infer K2}__${infer K3}` ? K extends keyof T["properties"] & string ? UnwrapOptionalSchema<T["properties"][K]> extends TObject<infer P> ? K2 extends keyof P & string ? UnwrapOptionalSchema<P[K2]> extends TObject<infer P2> ? K3 extends keyof P2 & string ? UnwrapOptionalSchema<P2[K3]> extends infer U ? U extends TScalarSchema ? ColumnRef<N, U> : never : never : never : never : never : never : never : N extends `${infer K}__${infer K2}` ? K extends keyof T["properties"] & string ? UnwrapOptionalSchema<T["properties"][K]> extends TObject<infer P> ? K2 extends keyof P & string ? UnwrapOptionalSchema<P[K2]> extends infer U ? U extends TScalarSchema ? ColumnRef<N, U> : never : never : never : never : never : never;
|
|
17
29
|
/**
|
|
18
30
|
* map of scalar columns to their typed refs
|
|
19
31
|
* @category Schema
|
|
20
32
|
*/
|
|
21
|
-
type ColumnRefs<T extends
|
|
33
|
+
type ColumnRefs<T extends TSchema & {
|
|
34
|
+
properties: Record<string, TSchema>;
|
|
35
|
+
}> = { readonly [K in keyof T["properties"] as T["properties"][K] extends TScalarSchema ? K : never] : T["properties"][K] extends TScalarSchema ? ColumnRef<K & string, T["properties"][K]> : never } & { readonly [K in NestedColumnKeys<T>] : NestedColumnRef<T, K> };
|
|
22
36
|
/**
|
|
23
37
|
* foxdb/src/typed-relation.ts
|
|
24
38
|
* Runtime + compile-time representation of a single relation.
|
|
@@ -39,20 +53,12 @@ interface TypedRelation<
|
|
|
39
53
|
kind: K;
|
|
40
54
|
as: A;
|
|
41
55
|
}
|
|
42
|
-
import { Database,
|
|
56
|
+
import { Database, Statement } from "bun:sqlite";
|
|
43
57
|
/**
|
|
44
58
|
* prepared sqlite statement
|
|
45
59
|
* @category Database
|
|
46
60
|
*/
|
|
47
|
-
|
|
48
|
-
run(...params: SQLQueryBindings[]): {
|
|
49
|
-
changes: number;
|
|
50
|
-
lastInsertRowid: number | bigint;
|
|
51
|
-
};
|
|
52
|
-
all(...params: SQLQueryBindings[]): unknown[];
|
|
53
|
-
get(...params: SQLQueryBindings[]): unknown;
|
|
54
|
-
finalize(): void;
|
|
55
|
-
}
|
|
61
|
+
type BunStatement = Statement;
|
|
56
62
|
/** @category Database */
|
|
57
63
|
interface DatabaseOptions {
|
|
58
64
|
/** Path to the SQLite file. Defaults to ":memory:" */
|
|
@@ -75,6 +81,8 @@ interface DatabaseOptions {
|
|
|
75
81
|
synchronous?: "OFF" | "NORMAL" | "FULL" | "EXTRA";
|
|
76
82
|
/** PRAGMA mmap_size in bytes. 0 disables. Defaults to 256 MB. */
|
|
77
83
|
mmapSize?: number;
|
|
84
|
+
/** PRAGMA auto_vacuum level. "incremental" | "full" | false. Defaults to false. */
|
|
85
|
+
autoVacuum?: "incremental" | "full" | false;
|
|
78
86
|
}
|
|
79
87
|
/**
|
|
80
88
|
* sqlite database with statement caching and pragma tuning
|
|
@@ -83,6 +91,8 @@ interface DatabaseOptions {
|
|
|
83
91
|
declare class BunDatabase {
|
|
84
92
|
/** underlying bun:sqlite database */
|
|
85
93
|
readonly db: Database;
|
|
94
|
+
/** scheduler for table maintenance tasks */
|
|
95
|
+
readonly scheduler;
|
|
86
96
|
constructor(opts?: DatabaseOptions);
|
|
87
97
|
/** execute ddl (create table, index, etc) */
|
|
88
98
|
exec(sql: string): void;
|
|
@@ -94,46 +104,192 @@ declare class BunDatabase {
|
|
|
94
104
|
private readonly _stmtCache;
|
|
95
105
|
/** get or compile a prepared statement */
|
|
96
106
|
prepare(sql: string): BunStatement;
|
|
107
|
+
/** set synchronous pragma for bulk load or normal operation */
|
|
108
|
+
setSynchronous(mode: "OFF" | "NORMAL" | "FULL" | "EXTRA"): void;
|
|
97
109
|
/** clear the statement cache */
|
|
98
110
|
clearCache(): void;
|
|
99
111
|
}
|
|
112
|
+
type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
113
|
+
[key: string]: JsonValue;
|
|
114
|
+
};
|
|
115
|
+
type DBBinary = Uint8Array;
|
|
116
|
+
type DBScalar = string | number | boolean | bigint | null;
|
|
117
|
+
type DBValue = DBScalar | JsonValue | DBBinary;
|
|
118
|
+
type DBRow = Record<string, DBValue | undefined>;
|
|
119
|
+
/** @internal */
|
|
120
|
+
type UnwrapOptional<T> = T extends TOptional2<infer U> ? U : T;
|
|
121
|
+
/** @internal */
|
|
122
|
+
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
123
|
+
/** @internal */
|
|
124
|
+
type IsOptionalKey<
|
|
125
|
+
O,
|
|
126
|
+
K extends keyof O
|
|
127
|
+
> = {} extends Pick<O, K> ? true : false;
|
|
128
|
+
/** @internal */
|
|
129
|
+
type MergePath<
|
|
130
|
+
O,
|
|
131
|
+
P extends string
|
|
132
|
+
> = P extends `${infer K}.${infer Rest}` ? K extends keyof O ? IsOptionalKey<O, K> extends true ? { [k in K]? : MergePath<NonNullable<O[K]>, Rest> } : { [k in K] : MergePath<NonNullable<O[K]>, Rest> } : never : P extends keyof O ? IsOptionalKey<O, P> extends true ? { [k in P]? : O[P] } : { [k in P] : O[P] } : never;
|
|
133
|
+
/** @internal */
|
|
134
|
+
type SelectShape<
|
|
135
|
+
T extends TSchema2 & {
|
|
136
|
+
properties: Record<string, TSchema2>;
|
|
137
|
+
},
|
|
138
|
+
S extends readonly string[]
|
|
139
|
+
> = UnionToIntersection<S[number] extends infer P ? P extends string ? MergePath<Infer<T>, P> : never : never>;
|
|
140
|
+
/**
|
|
141
|
+
* scalar values sqlite can store natively
|
|
142
|
+
* @category Advanced
|
|
143
|
+
*/
|
|
144
|
+
type SqliteScalar = string | number | boolean | null | bigint;
|
|
100
145
|
/**
|
|
101
146
|
* @internal
|
|
102
147
|
* @category Advanced
|
|
103
148
|
*/
|
|
104
|
-
type ScalarProperties<P extends TProperties> = { [K in keyof P as P[K] extends TArray<infer _> ? never : K] : P[K] };
|
|
149
|
+
type ScalarProperties<P extends TProperties> = { [K in keyof P as P[K] extends TArray<infer _> ? never : P[K] extends TObject2 ? never : K] : P[K] };
|
|
105
150
|
/**
|
|
106
151
|
* @internal
|
|
107
152
|
* @category Advanced
|
|
108
153
|
*/
|
|
109
|
-
type ArrayOfObjectProperties<P extends TProperties> = { [K in keyof P as P[K] extends TArray<
|
|
154
|
+
type ArrayOfObjectProperties<P extends TProperties> = { [K in keyof P as P[K] extends TArray<{
|
|
155
|
+
properties: Record<string, TSchema2>;
|
|
156
|
+
}> ? K : never] : P[K] extends TArray<infer Item> ? Item : never };
|
|
110
157
|
/**
|
|
111
158
|
* column names that are scalar (not arrays or nested objects)
|
|
112
159
|
* @category Query Types
|
|
113
160
|
*/
|
|
114
|
-
type ScalarKeys<T extends
|
|
161
|
+
type ScalarKeys<T extends TSchema2 & {
|
|
162
|
+
properties: Record<string, TSchema2>;
|
|
163
|
+
}> = keyof ScalarProperties<T["properties"]> & string;
|
|
164
|
+
/** @internal */
|
|
165
|
+
type ObjectKeys<T extends TSchema2 & {
|
|
166
|
+
properties: Record<string, TSchema2>;
|
|
167
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends TObject2 ? K : never }[keyof T["properties"] & string];
|
|
168
|
+
/** @internal */
|
|
169
|
+
type PrimitiveArrayKeys<T extends TSchema2 & {
|
|
170
|
+
properties: Record<string, TSchema2>;
|
|
171
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends TArray<infer Item> ? Item extends TScalarSchema ? K : never : never }[keyof T["properties"] & string];
|
|
115
172
|
/**
|
|
116
173
|
* @internal
|
|
117
174
|
* @category Query Types
|
|
118
175
|
*/
|
|
119
|
-
type SubTableKeys<T extends
|
|
176
|
+
type SubTableKeys<T extends TSchema2 & {
|
|
177
|
+
properties: Record<string, TSchema2>;
|
|
178
|
+
}> = keyof ArrayOfObjectProperties<T["properties"]> & string;
|
|
120
179
|
/**
|
|
121
180
|
* @internal
|
|
122
181
|
* @category Advanced
|
|
123
182
|
*/
|
|
124
|
-
type SubTableScalarPath<T extends
|
|
183
|
+
type SubTableScalarPath<T extends TSchema2 & {
|
|
184
|
+
properties: Record<string, TSchema2>;
|
|
185
|
+
}> = { [K in SubTableKeys<T>] : T["properties"][K] extends TArray<infer Item> ? Item extends {
|
|
186
|
+
properties: Record<string, TSchema2>;
|
|
187
|
+
} ? `${K}.${ScalarKeys<Item>}` : never : never }[SubTableKeys<T>];
|
|
125
188
|
/**
|
|
126
189
|
* @internal
|
|
127
190
|
* @category Advanced
|
|
128
191
|
*/
|
|
129
|
-
type ScalarPath<T extends
|
|
192
|
+
type ScalarPath<T extends TSchema2 & {
|
|
193
|
+
properties: Record<string, TSchema2>;
|
|
194
|
+
}> = ScalarKeys<T> | SubTableScalarPath<T>;
|
|
195
|
+
/** @internal */
|
|
196
|
+
type JsonPathLevel1<T extends TSchema2 & {
|
|
197
|
+
properties: Record<string, TSchema2>;
|
|
198
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends {
|
|
199
|
+
properties: Record<string, TSchema2>;
|
|
200
|
+
} ? `${K}.${keyof UnwrapOptional<T["properties"][K]>["properties"] & string}` : never }[keyof T["properties"] & string];
|
|
201
|
+
/** @internal */
|
|
202
|
+
type JsonPathLevel2<T extends TSchema2 & {
|
|
203
|
+
properties: Record<string, TSchema2>;
|
|
204
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends {
|
|
205
|
+
properties: Record<string, TSchema2>;
|
|
206
|
+
} ? { [K2 in keyof UnwrapOptional<T["properties"][K]>["properties"] & string] : UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]> extends {
|
|
207
|
+
properties: Record<string, TSchema2>;
|
|
208
|
+
} ? `${K}.${K2}.${keyof UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"] & string}` : never }[keyof UnwrapOptional<T["properties"][K]>["properties"] & string] : never }[keyof T["properties"] & string];
|
|
209
|
+
/** @internal */
|
|
210
|
+
type JsonPathLevel3<T extends TSchema2 & {
|
|
211
|
+
properties: Record<string, TSchema2>;
|
|
212
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends {
|
|
213
|
+
properties: Record<string, TSchema2>;
|
|
214
|
+
} ? { [K2 in keyof UnwrapOptional<T["properties"][K]>["properties"] & string] : UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]> extends {
|
|
215
|
+
properties: Record<string, TSchema2>;
|
|
216
|
+
} ? { [K3 in keyof UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"] & string] : UnwrapOptional<UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"][K3]> extends {
|
|
217
|
+
properties: Record<string, TSchema2>;
|
|
218
|
+
} ? `${K}.${K2}.${K3}.${keyof UnwrapOptional<UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"][K3]>["properties"] & string}` : never }[keyof UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"] & string] : never }[keyof UnwrapOptional<T["properties"][K]>["properties"] & string] : never }[keyof T["properties"] & string];
|
|
219
|
+
/** @internal */
|
|
220
|
+
type JsonPath<T extends TSchema2 & {
|
|
221
|
+
properties: Record<string, TSchema2>;
|
|
222
|
+
}> = JsonPathLevel1<T> | JsonPathLevel2<T> | JsonPathLevel3<T>;
|
|
223
|
+
/** @internal */
|
|
224
|
+
type ScalarJsonPathLevel1<T extends TSchema2 & {
|
|
225
|
+
properties: Record<string, TSchema2>;
|
|
226
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends TObject2<infer P> ? { [K2 in keyof P & string] : UnwrapOptional<P[K2]> extends TScalarSchema ? `${K}.${K2}` : never }[keyof P & string] : never }[keyof T["properties"] & string];
|
|
227
|
+
/** @internal */
|
|
228
|
+
type ScalarJsonPathLevel2<T extends TSchema2 & {
|
|
229
|
+
properties: Record<string, TSchema2>;
|
|
230
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends TObject2<infer P> ? { [K2 in keyof P & string] : UnwrapOptional<P[K2]> extends TObject2<infer P2> ? { [K3 in keyof P2 & string] : UnwrapOptional<P2[K3]> extends TScalarSchema ? `${K}.${K2}.${K3}` : never }[keyof P2 & string] : never }[keyof P & string] : never }[keyof T["properties"] & string];
|
|
231
|
+
/** @internal */
|
|
232
|
+
type ScalarJsonPathLevel3<T extends TSchema2 & {
|
|
233
|
+
properties: Record<string, TSchema2>;
|
|
234
|
+
}> = { [K in keyof T["properties"] & string] : UnwrapOptional<T["properties"][K]> extends TObject2<infer P> ? { [K2 in keyof P & string] : UnwrapOptional<P[K2]> extends TObject2<infer P2> ? { [K3 in keyof P2 & string] : UnwrapOptional<P2[K3]> extends TObject2<infer P3> ? { [K4 in keyof P3 & string] : UnwrapOptional<P3[K4]> extends TScalarSchema ? `${K}.${K2}.${K3}.${K4}` : never }[keyof P3 & string] : never }[keyof P2 & string] : never }[keyof P & string] : never }[keyof T["properties"] & string];
|
|
235
|
+
/** @internal */
|
|
236
|
+
type ScalarJsonPath<T extends TSchema2 & {
|
|
237
|
+
properties: Record<string, TSchema2>;
|
|
238
|
+
}> = ScalarJsonPathLevel1<T> | ScalarJsonPathLevel2<T> | ScalarJsonPathLevel3<T>;
|
|
239
|
+
/** @internal */
|
|
240
|
+
type PathValue<
|
|
241
|
+
T extends TSchema2 & {
|
|
242
|
+
properties: Record<string, TSchema2>;
|
|
243
|
+
},
|
|
244
|
+
P extends string
|
|
245
|
+
> = P extends `${infer K}.${infer Rest}` ? UnwrapOptional<T["properties"][K]> extends {
|
|
246
|
+
properties: Record<string, TSchema2>;
|
|
247
|
+
} ? Rest extends `${infer K2}.${infer Rest2}` ? UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]> extends {
|
|
248
|
+
properties: Record<string, TSchema2>;
|
|
249
|
+
} ? Rest2 extends `${infer K3}.${infer Rest3}` ? UnwrapOptional<UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"][K3]> extends {
|
|
250
|
+
properties: Record<string, TSchema2>;
|
|
251
|
+
} ? UnwrapOptional<UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"][K3]>["properties"][Rest3] extends TSchema2 ? Static<UnwrapOptional<UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"][K3]>["properties"][Rest3]> : never : never : UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"][Rest2] extends TSchema2 ? Static<UnwrapOptional<UnwrapOptional<T["properties"][K]>["properties"][K2]>["properties"][Rest2]> : never : never : UnwrapOptional<T["properties"][K]>["properties"][Rest] extends TSchema2 ? Static<UnwrapOptional<T["properties"][K]>["properties"][Rest]> : never : never : P extends keyof T["properties"] ? Static<T["properties"][P]> : never;
|
|
130
252
|
/**
|
|
131
253
|
* the typescript type that matches a typebox schema
|
|
132
254
|
* @category Query Types
|
|
133
255
|
*/
|
|
134
|
-
type Infer<T extends
|
|
256
|
+
type Infer<T extends TSchema2> = Static<T>;
|
|
257
|
+
/**
|
|
258
|
+
* @internal
|
|
259
|
+
* @category Advanced
|
|
260
|
+
*/
|
|
261
|
+
type SubTableItem<
|
|
262
|
+
T extends TSchema2 & {
|
|
263
|
+
properties: Record<string, TSchema2>;
|
|
264
|
+
},
|
|
265
|
+
K extends SubTableKeys<T>
|
|
266
|
+
> = T["properties"][K] extends TArray<infer Item extends TSchema2> ? Static<Item> : never;
|
|
135
267
|
/** @category Query Types */
|
|
136
|
-
type ScalarFilter<V> =
|
|
268
|
+
type ScalarFilter<V> = unknown extends V ? {
|
|
269
|
+
eq: V;
|
|
270
|
+
} | {
|
|
271
|
+
ne: V;
|
|
272
|
+
} | {
|
|
273
|
+
gt: V;
|
|
274
|
+
} | {
|
|
275
|
+
gte: V;
|
|
276
|
+
} | {
|
|
277
|
+
lt: V;
|
|
278
|
+
} | {
|
|
279
|
+
lte: V;
|
|
280
|
+
} | {
|
|
281
|
+
like: string;
|
|
282
|
+
} | {
|
|
283
|
+
between: [V, V];
|
|
284
|
+
} | {
|
|
285
|
+
in: V[];
|
|
286
|
+
} | {
|
|
287
|
+
notIn: V[];
|
|
288
|
+
} | {
|
|
289
|
+
isNull: true;
|
|
290
|
+
} | {
|
|
291
|
+
isNotNull: true;
|
|
292
|
+
} : V extends string ? {
|
|
137
293
|
eq: V;
|
|
138
294
|
} | {
|
|
139
295
|
ne: V;
|
|
@@ -173,11 +329,57 @@ type ScalarFilter<V> = V extends string ? {
|
|
|
173
329
|
isNull: true;
|
|
174
330
|
} | {
|
|
175
331
|
isNotNull: true;
|
|
332
|
+
} : V extends object ? {
|
|
333
|
+
eq: V;
|
|
334
|
+
} | {
|
|
335
|
+
ne: V;
|
|
336
|
+
} | {
|
|
337
|
+
isNull: true;
|
|
338
|
+
} | {
|
|
339
|
+
isNotNull: true;
|
|
176
340
|
} : {
|
|
177
341
|
isNull: true;
|
|
178
342
|
} | {
|
|
179
343
|
isNotNull: true;
|
|
180
344
|
};
|
|
345
|
+
/** @category Query Types */
|
|
346
|
+
type ArrayFilter<V> = {
|
|
347
|
+
/** matches if at least one element in the array equals this value */
|
|
348
|
+
arraySome?: V;
|
|
349
|
+
/** matches if no element in the array equals this value */
|
|
350
|
+
arrayNot?: V;
|
|
351
|
+
/** matches if the array is empty (length 0 or NULL) */
|
|
352
|
+
isEmpty?: boolean;
|
|
353
|
+
/**
|
|
354
|
+
* HIGH PERFORMANCE: matches if at least one element in the array equals this value.
|
|
355
|
+
* Uses string-based matching which is significantly faster than JSON parsing but
|
|
356
|
+
* sensitive to JSON formatting/whitespace.
|
|
357
|
+
*/
|
|
358
|
+
fastArraySome?: V;
|
|
359
|
+
/**
|
|
360
|
+
* HIGH PERFORMANCE: matches if no element in the array equals this value.
|
|
361
|
+
* Uses string-based matching which is significantly faster than JSON parsing but
|
|
362
|
+
* sensitive to JSON formatting/whitespace.
|
|
363
|
+
*/
|
|
364
|
+
fastArrayNot?: V;
|
|
365
|
+
/**
|
|
366
|
+
* HIGH PERFORMANCE: matches if the array is empty ('[]' or NULL).
|
|
367
|
+
* Significantly faster than isEmpty and can be indexed with a standard index.
|
|
368
|
+
*/
|
|
369
|
+
fastArrayIsEmpty?: boolean;
|
|
370
|
+
/** matches if the entire array equals this value */
|
|
371
|
+
eq?: V[];
|
|
372
|
+
/** matches if the entire array does not equal this value */
|
|
373
|
+
ne?: V[];
|
|
374
|
+
/** matches if the column is NULL */
|
|
375
|
+
isNull?: true;
|
|
376
|
+
/** matches if the column is NOT NULL */
|
|
377
|
+
isNotNull?: true;
|
|
378
|
+
/** matches if the entire array is in the list of arrays */
|
|
379
|
+
in?: V[][];
|
|
380
|
+
/** matches if the entire array is not in the list of arrays */
|
|
381
|
+
notIn?: V[][];
|
|
382
|
+
};
|
|
181
383
|
/**
|
|
182
384
|
* Where filters for queries - only scalar columns are filterable.
|
|
183
385
|
*
|
|
@@ -187,6 +389,10 @@ type ScalarFilter<V> = V extends string ? {
|
|
|
187
389
|
* orm.users.findMany({ where: { name: { like: "%alice%" } } });
|
|
188
390
|
* orm.users.findMany({ where: { email: { in: ["a@x.com", "b@x.com"] } } });
|
|
189
391
|
*
|
|
392
|
+
* // Array filters
|
|
393
|
+
* orm.users.findMany({ where: { tags: { arraySome: "typescript" } } });
|
|
394
|
+
* orm.users.findMany({ where: { scores: { isEmpty: true } } });
|
|
395
|
+
*
|
|
190
396
|
* // Number filters
|
|
191
397
|
* orm.users.findMany({ where: { age: { gte: 18, lte: 65 } } });
|
|
192
398
|
* orm.products.findMany({ where: { price: { between: [10, 100] } } });
|
|
@@ -198,13 +404,25 @@ type ScalarFilter<V> = V extends string ? {
|
|
|
198
404
|
* @category Query Types
|
|
199
405
|
* @category Query Types
|
|
200
406
|
*/
|
|
201
|
-
type WhereClause<T extends
|
|
407
|
+
type WhereClause<T extends TSchema2 & {
|
|
408
|
+
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>> } & {
|
|
410
|
+
AND?: WhereClause<T>[];
|
|
411
|
+
OR?: WhereClause<T>[];
|
|
412
|
+
NOT?: WhereClause<T>;
|
|
413
|
+
_raw?: {
|
|
414
|
+
sql: string;
|
|
415
|
+
params: unknown[];
|
|
416
|
+
};
|
|
417
|
+
};
|
|
202
418
|
/**
|
|
203
419
|
* sort direction for queries
|
|
204
420
|
* @category Query Types
|
|
205
421
|
*/
|
|
206
|
-
type OrderByClause<T extends
|
|
207
|
-
|
|
422
|
+
type OrderByClause<T extends TSchema2 & {
|
|
423
|
+
properties: Record<string, TSchema2>;
|
|
424
|
+
}> = {
|
|
425
|
+
column: ScalarKeys<T> | ScalarJsonPath<T>;
|
|
208
426
|
direction?: "ASC" | "DESC";
|
|
209
427
|
};
|
|
210
428
|
/**
|
|
@@ -215,6 +433,18 @@ interface PaginationOptions {
|
|
|
215
433
|
limit?: number;
|
|
216
434
|
offset?: number;
|
|
217
435
|
}
|
|
436
|
+
interface Cursor {
|
|
437
|
+
column: string;
|
|
438
|
+
value: SqliteScalar;
|
|
439
|
+
}
|
|
440
|
+
interface CursorInput extends Cursor {
|
|
441
|
+
direction: "next" | "prev";
|
|
442
|
+
}
|
|
443
|
+
interface CursorPageResult<T> {
|
|
444
|
+
data: T[];
|
|
445
|
+
nextCursor: Cursor | null;
|
|
446
|
+
prevCursor: Cursor | null;
|
|
447
|
+
}
|
|
218
448
|
/**
|
|
219
449
|
* Options for `findMany`, `findPage`, and `findOne`.
|
|
220
450
|
*
|
|
@@ -241,22 +471,36 @@ interface PaginationOptions {
|
|
|
241
471
|
* @category Query Types
|
|
242
472
|
* @category Query Types
|
|
243
473
|
*/
|
|
244
|
-
|
|
474
|
+
/** @internal */
|
|
475
|
+
type SelectableKeys<T extends TSchema2 & {
|
|
476
|
+
properties: Record<string, TSchema2>;
|
|
477
|
+
}> = ScalarKeys<T> | ObjectKeys<T> | PrimitiveArrayKeys<T> | JsonPath<T>;
|
|
478
|
+
interface FindOptions<T extends TSchema2 & {
|
|
479
|
+
properties: Record<string, TSchema2>;
|
|
480
|
+
}> extends PaginationOptions {
|
|
245
481
|
where?: WhereClause<T>;
|
|
246
482
|
orderBy?: OrderByClause<T> | OrderByClause<T>[];
|
|
247
483
|
include?: SubTableKeys<T>[];
|
|
484
|
+
select?: SelectableKeys<T>[];
|
|
485
|
+
includeDeleted?: boolean;
|
|
486
|
+
distinct?: boolean;
|
|
487
|
+
distinctOn?: (ScalarKeys<T> | ScalarJsonPath<T>)[];
|
|
248
488
|
}
|
|
249
489
|
/**
|
|
250
490
|
* full record to insert
|
|
251
491
|
* @category Query Types
|
|
252
492
|
*/
|
|
253
|
-
type InsertData<T extends
|
|
493
|
+
type InsertData<T extends TSchema2 & {
|
|
494
|
+
properties: Record<string, TSchema2>;
|
|
495
|
+
}> = Infer<T>;
|
|
254
496
|
/**
|
|
255
497
|
* update payload - must include the primary key
|
|
256
498
|
* @category Query Types
|
|
257
499
|
*/
|
|
258
500
|
type UpdateData<
|
|
259
|
-
T extends
|
|
501
|
+
T extends TSchema2 & {
|
|
502
|
+
properties: Record<string, TSchema2>;
|
|
503
|
+
},
|
|
260
504
|
PK extends ScalarKeys<T>
|
|
261
505
|
> = Pick<Infer<T>, PK> & Partial<Omit<Infer<T>, PK>>;
|
|
262
506
|
/**
|
|
@@ -265,8 +509,14 @@ type UpdateData<
|
|
|
265
509
|
*/
|
|
266
510
|
interface IndexDefinition {
|
|
267
511
|
name?: string;
|
|
268
|
-
columns: ColumnRef<string, TScalarSchema>
|
|
512
|
+
columns: Array<ColumnRef<string, TScalarSchema> | {
|
|
513
|
+
name: string;
|
|
514
|
+
}>;
|
|
269
515
|
unique?: boolean;
|
|
516
|
+
where?: string;
|
|
517
|
+
include?: Array<ColumnRef<string, TScalarSchema> | {
|
|
518
|
+
name: string;
|
|
519
|
+
}>;
|
|
270
520
|
}
|
|
271
521
|
/**
|
|
272
522
|
* timestamp configuration for a table
|
|
@@ -318,10 +568,47 @@ type Entity<
|
|
|
318
568
|
* table descriptor passed to createORM
|
|
319
569
|
* @category Schema
|
|
320
570
|
*/
|
|
571
|
+
interface EvictionConfig {
|
|
572
|
+
maxRows?: number;
|
|
573
|
+
ttlColumn?: string;
|
|
574
|
+
ttlMs?: number;
|
|
575
|
+
lruColumn?: string;
|
|
576
|
+
}
|
|
577
|
+
interface CompressionConfig {
|
|
578
|
+
columns: ColumnRef<string, TScalarSchema>[];
|
|
579
|
+
algorithm: "gzip" | "none";
|
|
580
|
+
}
|
|
581
|
+
interface SoftDeleteConfig {
|
|
582
|
+
column: string;
|
|
583
|
+
}
|
|
584
|
+
type GeneratedColumnConfig = {
|
|
585
|
+
[name: string]: {
|
|
586
|
+
expr: string;
|
|
587
|
+
type: TSchema2;
|
|
588
|
+
};
|
|
589
|
+
};
|
|
590
|
+
type GeneratedColumnValues<C extends GeneratedColumnConfig> = { [K in keyof C & string] : Static<C[K]["type"]> };
|
|
591
|
+
type AugmentSchema<
|
|
592
|
+
T extends TSchema2 & {
|
|
593
|
+
properties: Record<string, TSchema2>;
|
|
594
|
+
},
|
|
595
|
+
G extends GeneratedColumnConfig
|
|
596
|
+
> = TObject2<T["properties"] & GeneratedColumnValues<G>>;
|
|
597
|
+
type QuerySchema<
|
|
598
|
+
T extends TSchema2 & {
|
|
599
|
+
properties: Record<string, TSchema2>;
|
|
600
|
+
},
|
|
601
|
+
G extends GeneratedColumnConfig | undefined
|
|
602
|
+
> = [G] extends [undefined] ? T : [G] extends [GeneratedColumnConfig] ? AugmentSchema<T, G> : T;
|
|
321
603
|
interface TableConfig<
|
|
322
|
-
T extends
|
|
604
|
+
T extends TSchema2 & {
|
|
605
|
+
properties: Record<string, TSchema2>;
|
|
606
|
+
} = TSchema2 & {
|
|
607
|
+
properties: Record<string, TSchema2>;
|
|
608
|
+
},
|
|
323
609
|
PK extends string = string,
|
|
324
|
-
TS extends TimestampConfig = undefined
|
|
610
|
+
TS extends TimestampConfig = undefined,
|
|
611
|
+
G extends GeneratedColumnConfig | undefined = undefined
|
|
325
612
|
> {
|
|
326
613
|
schema: T;
|
|
327
614
|
primaryKey: ColumnRef<PK>;
|
|
@@ -330,6 +617,10 @@ interface TableConfig<
|
|
|
330
617
|
indexes?: IndexDefinition[];
|
|
331
618
|
}>>;
|
|
332
619
|
timestamps?: TS;
|
|
620
|
+
eviction?: EvictionConfig;
|
|
621
|
+
compression?: CompressionConfig;
|
|
622
|
+
softDelete?: SoftDeleteConfig;
|
|
623
|
+
generated?: G;
|
|
333
624
|
}
|
|
334
625
|
/**
|
|
335
626
|
* read-only metadata about the current database schema
|
|
@@ -347,7 +638,7 @@ interface MetaAccessors {
|
|
|
347
638
|
* @category Relations
|
|
348
639
|
*/
|
|
349
640
|
interface RelationEntry<
|
|
350
|
-
Tables extends Record<string, TableConfig<any, any, any>>,
|
|
641
|
+
Tables extends Record<string, TableConfig<any, any, any, any>>,
|
|
351
642
|
Owner extends keyof Tables,
|
|
352
643
|
Target extends keyof Tables
|
|
353
644
|
> {
|
|
@@ -359,7 +650,7 @@ interface RelationEntry<
|
|
|
359
650
|
* @internal
|
|
360
651
|
* @category Relations
|
|
361
652
|
*/
|
|
362
|
-
type RelationsConfig<Tables extends Record<string, TableConfig<any, any, any>>> = { [K in keyof Tables & string]? : Array<{ [Target in keyof Tables & string] : RelationEntry<Tables, K, Target> }[keyof Tables & string]> };
|
|
653
|
+
type RelationsConfig<Tables extends Record<string, TableConfig<any, any, any, any>>> = { [K in keyof Tables & string]? : Array<{ [Target in keyof Tables & string] : RelationEntry<Tables, K, Target> }[keyof Tables & string]> };
|
|
363
654
|
/**
|
|
364
655
|
* @internal
|
|
365
656
|
* @category Relations
|
|
@@ -376,7 +667,7 @@ type ScalarMergeNames<
|
|
|
376
667
|
* @category Relations
|
|
377
668
|
*/
|
|
378
669
|
type ScalarMergeType<
|
|
379
|
-
Tables extends Record<string, TableConfig<any, any, any>>,
|
|
670
|
+
Tables extends Record<string, TableConfig<any, any, any, any>>,
|
|
380
671
|
Rels extends readonly TypedRelation[],
|
|
381
672
|
Owner extends string,
|
|
382
673
|
Name extends string
|
|
@@ -390,7 +681,7 @@ type ScalarMergeType<
|
|
|
390
681
|
* @category Relations
|
|
391
682
|
*/
|
|
392
683
|
type ScalarMerge<
|
|
393
|
-
Tables extends Record<string, TableConfig<any, any, any>>,
|
|
684
|
+
Tables extends Record<string, TableConfig<any, any, any, any>>,
|
|
394
685
|
Rels extends readonly TypedRelation[],
|
|
395
686
|
Owner extends string
|
|
396
687
|
> = { [K in ScalarMergeNames<Rels, Owner>] : ScalarMergeType<Tables, Rels, Owner, K> };
|
|
@@ -412,7 +703,7 @@ type SubMergeNames<
|
|
|
412
703
|
* @category Relations
|
|
413
704
|
*/
|
|
414
705
|
type SubMergeType<
|
|
415
|
-
Tables extends Record<string, TableConfig<any, any, any>>,
|
|
706
|
+
Tables extends Record<string, TableConfig<any, any, any, any>>,
|
|
416
707
|
Rels extends readonly TypedRelation[],
|
|
417
708
|
Owner extends string,
|
|
418
709
|
Sub extends string,
|
|
@@ -428,7 +719,7 @@ type SubMergeType<
|
|
|
428
719
|
* @category Relations
|
|
429
720
|
*/
|
|
430
721
|
type SubMerge<
|
|
431
|
-
Tables extends Record<string, TableConfig<any, any, any>>,
|
|
722
|
+
Tables extends Record<string, TableConfig<any, any, any, any>>,
|
|
432
723
|
Rels extends readonly TypedRelation[],
|
|
433
724
|
Owner extends string,
|
|
434
725
|
Sub extends string
|
|
@@ -450,8 +741,10 @@ type SubMerge<
|
|
|
450
741
|
* @category Relations
|
|
451
742
|
*/
|
|
452
743
|
type Materialized<
|
|
453
|
-
T extends
|
|
454
|
-
|
|
744
|
+
T extends TSchema2 & {
|
|
745
|
+
properties: Record<string, TSchema2>;
|
|
746
|
+
},
|
|
747
|
+
Tables extends Record<string, TableConfig<any, any, any, any>>,
|
|
455
748
|
Rels extends readonly TypedRelation[],
|
|
456
749
|
Owner extends string
|
|
457
750
|
> = { [K in keyof Infer<T>] : K extends string ? Infer<T>[K] extends Array<infer Item> ? Array<Item & SubMerge<Tables, Rels, Owner, K>> : Infer<T>[K] : Infer<T>[K] } & ScalarMerge<Tables, Rels, Owner>;
|
|
@@ -470,7 +763,9 @@ interface PageResult<T> {
|
|
|
470
763
|
* @category Query Types
|
|
471
764
|
*/
|
|
472
765
|
interface UpsertOptions<
|
|
473
|
-
T extends
|
|
766
|
+
T extends TSchema2 & {
|
|
767
|
+
properties: Record<string, TSchema2>;
|
|
768
|
+
},
|
|
474
769
|
PK extends ScalarKeys<T>
|
|
475
770
|
> {
|
|
476
771
|
data: InsertData<T>;
|
|
@@ -479,6 +774,35 @@ interface UpsertOptions<
|
|
|
479
774
|
update?: Array<ScalarKeys<T>>;
|
|
480
775
|
}
|
|
481
776
|
/**
|
|
777
|
+
* bulk conditional update
|
|
778
|
+
* @category Query Types
|
|
779
|
+
*/
|
|
780
|
+
interface UpdateWhereOptions<
|
|
781
|
+
T extends TSchema2 & {
|
|
782
|
+
properties: Record<string, TSchema2>;
|
|
783
|
+
},
|
|
784
|
+
PK extends ScalarKeys<T>
|
|
785
|
+
> {
|
|
786
|
+
where: WhereClause<T>;
|
|
787
|
+
data: Partial<Omit<Infer<T>, PK>>;
|
|
788
|
+
includeDeleted?: boolean;
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* bulk upsert with conflict resolution
|
|
792
|
+
* @category Query Types
|
|
793
|
+
*/
|
|
794
|
+
interface UpsertManyOptions<
|
|
795
|
+
T extends TSchema2 & {
|
|
796
|
+
properties: Record<string, TSchema2>;
|
|
797
|
+
},
|
|
798
|
+
PK extends ScalarKeys<T>
|
|
799
|
+
> {
|
|
800
|
+
data: InsertData<T>[];
|
|
801
|
+
conflictTarget: PK | PK[];
|
|
802
|
+
/** columns to update on conflict - defaults to all non-pk columns */
|
|
803
|
+
update?: Array<ScalarKeys<T>>;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
482
806
|
* a single migration step
|
|
483
807
|
* @category Migration
|
|
484
808
|
*/
|
|
@@ -584,11 +908,121 @@ interface SchemaDiff {
|
|
|
584
908
|
* @category Migration
|
|
585
909
|
*/
|
|
586
910
|
type SyncPolicy = "ignore" | "warn" | "error" | "auto" | ((diff: SchemaDiff, db: BunDatabase) => boolean | void);
|
|
911
|
+
/** @category Query Types */
|
|
912
|
+
type WindowFunction<T extends TSchema2 & {
|
|
913
|
+
properties: Record<string, TSchema2>;
|
|
914
|
+
}> = {
|
|
915
|
+
rowNumber: true;
|
|
916
|
+
} | {
|
|
917
|
+
rank: true;
|
|
918
|
+
} | {
|
|
919
|
+
denseRank: true;
|
|
920
|
+
} | {
|
|
921
|
+
lead: ScalarKeys<T> | ScalarJsonPath<T>;
|
|
922
|
+
offset?: number;
|
|
923
|
+
} | {
|
|
924
|
+
lag: ScalarKeys<T> | ScalarJsonPath<T>;
|
|
925
|
+
offset?: number;
|
|
926
|
+
};
|
|
927
|
+
/** @category Query Types */
|
|
928
|
+
interface WindowQueryOptions<T extends TSchema2 & {
|
|
929
|
+
properties: Record<string, TSchema2>;
|
|
930
|
+
}> {
|
|
931
|
+
partitionBy?: (ScalarKeys<T> | ScalarJsonPath<T>)[];
|
|
932
|
+
orderBy?: OrderByClause<T> | OrderByClause<T>[];
|
|
933
|
+
where?: WhereClause<T>;
|
|
934
|
+
limit?: number;
|
|
935
|
+
select: Record<string, WindowFunction<T>>;
|
|
936
|
+
}
|
|
937
|
+
/** @internal */
|
|
938
|
+
type WindowFunctionResult<
|
|
939
|
+
T extends TSchema2 & {
|
|
940
|
+
properties: Record<string, TSchema2>;
|
|
941
|
+
},
|
|
942
|
+
W extends WindowFunction<T>
|
|
943
|
+
> = W extends {
|
|
944
|
+
lead: infer C extends string;
|
|
945
|
+
} ? PathValue<T, C> | null : W extends {
|
|
946
|
+
lag: infer C extends string;
|
|
947
|
+
} ? PathValue<T, C> | null : number;
|
|
948
|
+
/** @category Query Types */
|
|
949
|
+
type WindowResult<
|
|
950
|
+
T extends TSchema2 & {
|
|
951
|
+
properties: Record<string, TSchema2>;
|
|
952
|
+
},
|
|
953
|
+
W extends Record<string, WindowFunction<T>>
|
|
954
|
+
> = Array<{ [K in keyof W] : WindowFunctionResult<T, W[K]> }>;
|
|
955
|
+
/** @category Query Types */
|
|
956
|
+
type AggregationOp<T extends TSchema2 & {
|
|
957
|
+
properties: Record<string, TSchema2>;
|
|
958
|
+
} = TSchema2 & {
|
|
959
|
+
properties: Record<string, TSchema2>;
|
|
960
|
+
}> = {
|
|
961
|
+
sum?: ScalarKeys<T> | ScalarJsonPath<T>;
|
|
962
|
+
} | {
|
|
963
|
+
count?: "*" | ScalarKeys<T> | ScalarJsonPath<T>;
|
|
964
|
+
} | {
|
|
965
|
+
avg?: ScalarKeys<T> | ScalarJsonPath<T>;
|
|
966
|
+
} | {
|
|
967
|
+
min?: ScalarKeys<T> | ScalarJsonPath<T>;
|
|
968
|
+
} | {
|
|
969
|
+
max?: ScalarKeys<T> | ScalarJsonPath<T>;
|
|
970
|
+
};
|
|
971
|
+
/** @category Query Types */
|
|
972
|
+
interface AggregateOptions<
|
|
973
|
+
T extends TSchema2 & {
|
|
974
|
+
properties: Record<string, TSchema2>;
|
|
975
|
+
},
|
|
976
|
+
A extends Record<string, AggregationOp<T>> = Record<string, AggregationOp<T>>
|
|
977
|
+
> {
|
|
978
|
+
where?: WhereClause<T>;
|
|
979
|
+
groupBy?: readonly (ScalarKeys<T> | ScalarJsonPath<T>)[];
|
|
980
|
+
aggregations: A;
|
|
981
|
+
having?: { [K in keyof A]? : ScalarFilter<unknown> };
|
|
982
|
+
includeDeleted?: boolean;
|
|
983
|
+
}
|
|
984
|
+
/** @internal */
|
|
985
|
+
type AggregationOpResult<
|
|
986
|
+
T extends TSchema2 & {
|
|
987
|
+
properties: Record<string, TSchema2>;
|
|
988
|
+
},
|
|
989
|
+
Op extends AggregationOp<T>
|
|
990
|
+
> = Op extends {
|
|
991
|
+
sum: string;
|
|
992
|
+
} ? number | null : Op extends {
|
|
993
|
+
count: string;
|
|
994
|
+
} ? number : Op extends {
|
|
995
|
+
avg: string;
|
|
996
|
+
} ? number | null : Op extends {
|
|
997
|
+
min: infer C extends string;
|
|
998
|
+
} ? PathValue<T, C> | null : Op extends {
|
|
999
|
+
max: infer C extends string;
|
|
1000
|
+
} ? PathValue<T, C> | null : never;
|
|
1001
|
+
/** @category Query Types */
|
|
1002
|
+
type AggregateResult<
|
|
1003
|
+
T extends TSchema2 & {
|
|
1004
|
+
properties: Record<string, TSchema2>;
|
|
1005
|
+
},
|
|
1006
|
+
A extends Record<string, AggregationOp<T>>,
|
|
1007
|
+
G extends readonly string[] | undefined = undefined
|
|
1008
|
+
> = Array<{ [K in keyof A] : AggregationOpResult<T, A[K]> } & (G extends readonly string[] ? { [K in G[number]] : PathValue<T, K> } : {})>;
|
|
1009
|
+
/** @category Observability */
|
|
1010
|
+
interface QueryMetrics {
|
|
1011
|
+
table: string;
|
|
1012
|
+
operation: string;
|
|
1013
|
+
sql: string;
|
|
1014
|
+
durationMs: number;
|
|
1015
|
+
rowCount: number;
|
|
1016
|
+
}
|
|
1017
|
+
/** @category Observability */
|
|
1018
|
+
interface QueryMetricsHook {
|
|
1019
|
+
onQuery: (meta: QueryMetrics) => void;
|
|
1020
|
+
}
|
|
587
1021
|
/**
|
|
588
1022
|
* specific operations that can be listened to per table
|
|
589
1023
|
* @category Events
|
|
590
1024
|
*/
|
|
591
|
-
type TableOperation = "insert" | "insertMany" | "update" | "delete" | "deleteWhere" | "upsert" | "findById" | "findMany" | "findOne" | "findPage" | "count" | "flush";
|
|
1025
|
+
type TableOperation = "insert" | "insertMany" | "update" | "updateWhere" | "delete" | "deleteWhere" | "upsert" | "upsertMany" | "findById" | "findMany" | "findOne" | "findPage" | "findCursorPage" | "iterate" | "count" | "flush" | "aggregate" | "windowQuery";
|
|
592
1026
|
/**
|
|
593
1027
|
* broad categories for event listening
|
|
594
1028
|
* @category Events
|
|
@@ -626,7 +1060,58 @@ type ErrorPolicy = "throw" | "emit" | "emit-swallow" | "crash";
|
|
|
626
1060
|
* @category Setup
|
|
627
1061
|
*/
|
|
628
1062
|
type UnlinkPolicy = true | "onlyGraceful" | "any" | false | undefined;
|
|
629
|
-
import {
|
|
1063
|
+
import { TSchema as TSchema5 } from "typebox";
|
|
1064
|
+
import { TSchema as TSchema3 } from "typebox";
|
|
1065
|
+
/** @category Schema */
|
|
1066
|
+
interface SubTableConfig {
|
|
1067
|
+
indexes?: IndexDefinition[];
|
|
1068
|
+
}
|
|
1069
|
+
interface TableDescriptor<
|
|
1070
|
+
T extends TSchema3 & {
|
|
1071
|
+
properties: Record<string, TSchema3>;
|
|
1072
|
+
},
|
|
1073
|
+
PK extends string,
|
|
1074
|
+
TS extends TimestampConfig = undefined,
|
|
1075
|
+
G extends GeneratedColumnConfig | undefined = undefined
|
|
1076
|
+
> extends TableConfig<T, PK, TS, G> {}
|
|
1077
|
+
interface TableConfigShape<
|
|
1078
|
+
PK extends string,
|
|
1079
|
+
TS extends TimestampConfig,
|
|
1080
|
+
G extends GeneratedColumnConfig | undefined = undefined
|
|
1081
|
+
> {
|
|
1082
|
+
primaryKey: ColumnRef<PK>;
|
|
1083
|
+
indexes?: IndexDefinition[];
|
|
1084
|
+
subTables?: Partial<Record<string, SubTableConfig>>;
|
|
1085
|
+
timestamps?: TS;
|
|
1086
|
+
eviction?: EvictionConfig;
|
|
1087
|
+
compression?: CompressionConfig;
|
|
1088
|
+
softDelete?: SoftDeleteConfig;
|
|
1089
|
+
generated?: G;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Describe a table schema + config for `createORM`.
|
|
1093
|
+
*
|
|
1094
|
+
* @example
|
|
1095
|
+
* ```ts
|
|
1096
|
+
* const UserSchema = Object({ id: String(), name: String(), email: String() });
|
|
1097
|
+
*
|
|
1098
|
+
* const users = table(UserSchema, (s) => ({
|
|
1099
|
+
* primaryKey: s.id,
|
|
1100
|
+
* indexes: [{ columns: [s.email], unique: true }],
|
|
1101
|
+
* timestamps: true, // adds createdAt / updatedAt
|
|
1102
|
+
* }));
|
|
1103
|
+
* ```
|
|
1104
|
+
* @category Schema
|
|
1105
|
+
* @category Schema
|
|
1106
|
+
*/
|
|
1107
|
+
declare function table<
|
|
1108
|
+
T extends TSchema3 & {
|
|
1109
|
+
properties: Record<string, TSchema3>;
|
|
1110
|
+
},
|
|
1111
|
+
PK extends string,
|
|
1112
|
+
TS extends TimestampConfig = undefined,
|
|
1113
|
+
G extends GeneratedColumnConfig | undefined = undefined
|
|
1114
|
+
>(schema: T, configure: (columns: ColumnRefs<T>) => TableConfigShape<PK, TS, G>): TableDescriptor<T, PK, TS, G>;
|
|
630
1115
|
/** @category Events */
|
|
631
1116
|
type Listener = (payload: unknown) => void;
|
|
632
1117
|
/**
|
|
@@ -660,7 +1145,7 @@ interface LifecycleEventMap {
|
|
|
660
1145
|
* typed event listener api
|
|
661
1146
|
* @category Events
|
|
662
1147
|
*/
|
|
663
|
-
interface ORMEvents<Tables extends Record<string,
|
|
1148
|
+
interface ORMEvents<Tables extends Record<string, TableDescriptor<any, any, any, any>>> {
|
|
664
1149
|
/** listen to lifecycle events (start, ready, shutdown, exit, fail) */
|
|
665
1150
|
on<K extends (keyof LifecycleEventMap) & string>(event: K, listener: (payload: LifecycleEventMap[K]) => void): () => void;
|
|
666
1151
|
/** listen to table events (insert, update, findMany, etc) */
|
|
@@ -682,7 +1167,7 @@ declare class EventBus {
|
|
|
682
1167
|
emit(event: string, payload: unknown): void;
|
|
683
1168
|
emitIf(event: string, payload: unknown): void;
|
|
684
1169
|
}
|
|
685
|
-
import {
|
|
1170
|
+
import { TSchema as TSchema4 } from "typebox";
|
|
686
1171
|
/** @category Advanced */
|
|
687
1172
|
type SqliteType = "TEXT" | "INTEGER" | "REAL" | "BLOB";
|
|
688
1173
|
/** @category Advanced */
|
|
@@ -692,6 +1177,14 @@ interface ColumnMeta {
|
|
|
692
1177
|
nullable: boolean;
|
|
693
1178
|
/** True if this is actually an `Optional` wrapper */
|
|
694
1179
|
optional: boolean;
|
|
1180
|
+
/** Path segments for flattened nested columns, e.g. ["Status", "Group"] */
|
|
1181
|
+
path?: string[];
|
|
1182
|
+
/** True if the underlying schema is a boolean (stored as INTEGER) */
|
|
1183
|
+
isBoolean?: boolean;
|
|
1184
|
+
/** True if this is a generated column */
|
|
1185
|
+
generated?: boolean;
|
|
1186
|
+
/** Expression for generated columns */
|
|
1187
|
+
generatedExpr?: string;
|
|
695
1188
|
}
|
|
696
1189
|
/** @category Advanced */
|
|
697
1190
|
interface SubTableMeta {
|
|
@@ -700,20 +1193,57 @@ interface SubTableMeta {
|
|
|
700
1193
|
/** e.g. "sales__lineItems" */
|
|
701
1194
|
tableName: string;
|
|
702
1195
|
/** Schema of a single item in the array */
|
|
703
|
-
itemSchema:
|
|
1196
|
+
itemSchema: TSchema4 & {
|
|
1197
|
+
properties: Record<string, TSchema4>;
|
|
1198
|
+
};
|
|
704
1199
|
/** Columns of the sub-table row (owner PK is prepended automatically) */
|
|
705
1200
|
columns: ColumnMeta[];
|
|
1201
|
+
columnByName: Map<string, ColumnMeta>;
|
|
1202
|
+
columnByPath: Map<string, ColumnMeta>;
|
|
706
1203
|
}
|
|
707
1204
|
/** @category Advanced */
|
|
708
1205
|
interface TableMeta {
|
|
709
1206
|
tableName: string;
|
|
710
1207
|
columns: ColumnMeta[];
|
|
711
1208
|
subTables: SubTableMeta[];
|
|
1209
|
+
/** Map from dotted path → ColumnMeta for O(1) resolution */
|
|
1210
|
+
columnByPath: Map<string, ColumnMeta>;
|
|
1211
|
+
/** Map from column name → ColumnMeta for O(1) resolution */
|
|
1212
|
+
columnByName: Map<string, ColumnMeta>;
|
|
712
1213
|
}
|
|
713
1214
|
/** @category Advanced */
|
|
714
|
-
declare function introspectTable(tableName: string, schema:
|
|
1215
|
+
declare function introspectTable(tableName: string, schema: TSchema4 & {
|
|
1216
|
+
properties: Record<string, TSchema4>;
|
|
1217
|
+
}, generated?: Array<{
|
|
1218
|
+
name: string;
|
|
1219
|
+
expr: string;
|
|
1220
|
+
sqlType?: SqliteType;
|
|
1221
|
+
}>): TableMeta;
|
|
715
1222
|
/** @category Advanced */
|
|
716
1223
|
declare function buildCreateTableSQL(meta: TableMeta, primaryKey: string): string[];
|
|
1224
|
+
interface BatchWriterOptions {
|
|
1225
|
+
maxBuffer?: number;
|
|
1226
|
+
flushIntervalMs?: number;
|
|
1227
|
+
}
|
|
1228
|
+
declare class BatchWriter<
|
|
1229
|
+
TInput,
|
|
1230
|
+
TRow extends Record<string, unknown>
|
|
1231
|
+
> {
|
|
1232
|
+
private buffer;
|
|
1233
|
+
private readonly maxBuffer;
|
|
1234
|
+
private readonly tableName;
|
|
1235
|
+
private readonly db;
|
|
1236
|
+
private readonly prepare;
|
|
1237
|
+
private readonly onFlush?;
|
|
1238
|
+
private timer?;
|
|
1239
|
+
constructor(tableName: string, db: BunDatabase, opts: BatchWriterOptions, callbacks: {
|
|
1240
|
+
prepare: (row: TInput) => TRow;
|
|
1241
|
+
onFlush?: (rows: TRow[]) => void;
|
|
1242
|
+
});
|
|
1243
|
+
insert(row: TInput): void;
|
|
1244
|
+
flush(): void;
|
|
1245
|
+
close(): void;
|
|
1246
|
+
}
|
|
717
1247
|
/**
|
|
718
1248
|
* Typed repository for a single table. Every entry in your `tables` config
|
|
719
1249
|
* becomes one of these on the ORM object, fully typed to its schema.
|
|
@@ -736,8 +1266,13 @@ declare function buildCreateTableSQL(meta: TableMeta, primaryKey: string): strin
|
|
|
736
1266
|
* ```
|
|
737
1267
|
*/
|
|
738
1268
|
declare class Repository<
|
|
739
|
-
|
|
740
|
-
|
|
1269
|
+
TWrite extends TSchema5 & {
|
|
1270
|
+
properties: Record<string, TSchema5>;
|
|
1271
|
+
},
|
|
1272
|
+
TQuery extends TSchema5 & {
|
|
1273
|
+
properties: Record<string, TSchema5>;
|
|
1274
|
+
},
|
|
1275
|
+
PK extends ScalarKeys<TWrite>,
|
|
741
1276
|
Mat = never,
|
|
742
1277
|
TS = {}
|
|
743
1278
|
> {
|
|
@@ -752,17 +1287,31 @@ declare class Repository<
|
|
|
752
1287
|
private _materialize?;
|
|
753
1288
|
private _materializeMany?;
|
|
754
1289
|
private _events?;
|
|
1290
|
+
private _executor;
|
|
1291
|
+
private readonly _codecs;
|
|
755
1292
|
/** @internal */
|
|
756
1293
|
setEventBus(bus: EventBus): void;
|
|
757
|
-
|
|
1294
|
+
/** @internal */
|
|
1295
|
+
setMetricsHook(hook?: (meta: QueryMetrics) => void): void;
|
|
1296
|
+
constructor(tableName: string, config: TableConfig<TWrite, PK & string, TimestampConfig, GeneratedColumnConfig | undefined>, db: BunDatabase);
|
|
1297
|
+
/** Ensure PK is selected when include is requested */
|
|
1298
|
+
private _ensureSelectPk;
|
|
1299
|
+
/**
|
|
1300
|
+
* Two-phase row fetch: first get PKs via index, then fetch full rows.
|
|
1301
|
+
* Avoids reading all columns for rows that don't match the WHERE clause.
|
|
1302
|
+
*/
|
|
1303
|
+
private _fetchRows;
|
|
758
1304
|
/** Inject materializers after ORM two-pass init */
|
|
759
1305
|
setMaterializer(single: (record: Record<string, unknown>) => Record<string, unknown>, many: (records: Record<string, unknown>[]) => Record<string, unknown>[]): void;
|
|
760
1306
|
/** Wrap raw data in an entity object */
|
|
761
1307
|
private _wrap;
|
|
762
1308
|
/** Narrow a parsed schema value to a plain record for dynamic property access */
|
|
763
1309
|
private _record;
|
|
1310
|
+
/** Validate that a value is a valid SQLite scalar for use as a primary key */
|
|
1311
|
+
private _assertPk;
|
|
764
1312
|
private _emit;
|
|
765
1313
|
private _migrate;
|
|
1314
|
+
private _runEviction;
|
|
766
1315
|
/**
|
|
767
1316
|
* Validate and coerce data against the schema. Throws on invalid input.
|
|
768
1317
|
*
|
|
@@ -774,7 +1323,7 @@ declare class Repository<
|
|
|
774
1323
|
* // user is typed as Infer<typeof UserSchema>
|
|
775
1324
|
* ```
|
|
776
1325
|
*/
|
|
777
|
-
parse(data: unknown): Infer<
|
|
1326
|
+
parse(data: unknown): Infer<TWrite>;
|
|
778
1327
|
/**
|
|
779
1328
|
* Type-guard - returns true if data matches the schema.
|
|
780
1329
|
*
|
|
@@ -787,7 +1336,7 @@ declare class Repository<
|
|
|
787
1336
|
* }
|
|
788
1337
|
* ```
|
|
789
1338
|
*/
|
|
790
|
-
check(data: unknown): data is Infer<
|
|
1339
|
+
check(data: unknown): data is Infer<TWrite>;
|
|
791
1340
|
/**
|
|
792
1341
|
* Insert a single record. Returns the inserted entity.
|
|
793
1342
|
*
|
|
@@ -802,7 +1351,7 @@ declare class Repository<
|
|
|
802
1351
|
* });
|
|
803
1352
|
* ```
|
|
804
1353
|
*/
|
|
805
|
-
insert(data: InsertData<
|
|
1354
|
+
insert(data: InsertData<TWrite>): Entity<Infer<TQuery>, Mat, TS>;
|
|
806
1355
|
/**
|
|
807
1356
|
* Insert many records in a single transaction.
|
|
808
1357
|
*
|
|
@@ -816,8 +1365,20 @@ declare class Repository<
|
|
|
816
1365
|
* ]);
|
|
817
1366
|
* ```
|
|
818
1367
|
*/
|
|
819
|
-
insertMany(records: InsertData<
|
|
820
|
-
|
|
1368
|
+
insertMany(records: InsertData<TWrite>[]): Entity<Infer<TQuery>, Mat, TS>[];
|
|
1369
|
+
/**
|
|
1370
|
+
* Create a batch writer for high-throughput insert streaming.
|
|
1371
|
+
*
|
|
1372
|
+
* @group Writing
|
|
1373
|
+
*
|
|
1374
|
+
* @example
|
|
1375
|
+
* ```ts
|
|
1376
|
+
* const writer = orm.users.createBatchWriter({ maxBuffer: 500 });
|
|
1377
|
+
* writer.insert({ id: "u1", name: "alice" });
|
|
1378
|
+
* writer.close();
|
|
1379
|
+
* ```
|
|
1380
|
+
*/
|
|
1381
|
+
createBatchWriter(opts?: BatchWriterOptions): BatchWriter<InsertData<TWrite>, Record<string, unknown>>;
|
|
821
1382
|
/**
|
|
822
1383
|
* Insert or update on conflict. If the record exists (by conflict target),
|
|
823
1384
|
* it updates the specified columns instead.
|
|
@@ -832,7 +1393,25 @@ declare class Repository<
|
|
|
832
1393
|
* });
|
|
833
1394
|
* ```
|
|
834
1395
|
*/
|
|
835
|
-
upsert(opts: UpsertOptions<
|
|
1396
|
+
upsert(opts: UpsertOptions<TWrite, PK>): Entity<Infer<TQuery>, Mat, TS>;
|
|
1397
|
+
/**
|
|
1398
|
+
* Bulk upsert with conflict resolution.
|
|
1399
|
+
* Sub-table rows are reconciled by deleting old rows and re-inserting.
|
|
1400
|
+
*
|
|
1401
|
+
* @group Writing
|
|
1402
|
+
*
|
|
1403
|
+
* @example
|
|
1404
|
+
* ```ts
|
|
1405
|
+
* orm.users.upsertMany({
|
|
1406
|
+
* data: [
|
|
1407
|
+
* { id: "u1", name: "alice" },
|
|
1408
|
+
* { id: "u2", name: "bob" },
|
|
1409
|
+
* ],
|
|
1410
|
+
* conflictTarget: "id",
|
|
1411
|
+
* });
|
|
1412
|
+
* ```
|
|
1413
|
+
*/
|
|
1414
|
+
upsertMany(opts: UpsertManyOptions<TWrite, PK>): number;
|
|
836
1415
|
/**
|
|
837
1416
|
* Find a record by its primary key.
|
|
838
1417
|
*
|
|
@@ -844,7 +1423,7 @@ declare class Repository<
|
|
|
844
1423
|
* if (user) console.log(user.name);
|
|
845
1424
|
* ```
|
|
846
1425
|
*/
|
|
847
|
-
findById(id: Infer<
|
|
1426
|
+
findById(id: Infer<TQuery>[PK]): Entity<Infer<TQuery>, Mat, TS> | null;
|
|
848
1427
|
/** Internal findById without event emission - used by update() */
|
|
849
1428
|
private _findByIdRaw;
|
|
850
1429
|
/**
|
|
@@ -864,7 +1443,17 @@ declare class Repository<
|
|
|
864
1443
|
* const orders = orm.orders.findMany({ include: ["lineItems"] });
|
|
865
1444
|
* ```
|
|
866
1445
|
*/
|
|
867
|
-
findMany
|
|
1446
|
+
findMany<
|
|
1447
|
+
const S extends readonly SelectableKeys<TQuery>[],
|
|
1448
|
+
const I extends readonly SubTableKeys<TQuery>[]
|
|
1449
|
+
>(opts: FindOptions<TQuery> & {
|
|
1450
|
+
select: S;
|
|
1451
|
+
include: I;
|
|
1452
|
+
}): (SelectShape<TQuery, S> & TS & { [K in I[number]] : SubTableItem<TQuery, K>[] })[];
|
|
1453
|
+
findMany<const S extends readonly SelectableKeys<TQuery>[]>(opts: FindOptions<TQuery> & {
|
|
1454
|
+
select: S;
|
|
1455
|
+
}): (SelectShape<TQuery, S> & TS)[];
|
|
1456
|
+
findMany(opts?: FindOptions<TQuery>): Entity<Infer<TQuery>, Mat, TS>[];
|
|
868
1457
|
/**
|
|
869
1458
|
* Find many with total count - useful for pagination.
|
|
870
1459
|
*
|
|
@@ -882,7 +1471,43 @@ declare class Repository<
|
|
|
882
1471
|
* // page.limit, page.offset - what you passed in
|
|
883
1472
|
* ```
|
|
884
1473
|
*/
|
|
885
|
-
findPage
|
|
1474
|
+
findPage<
|
|
1475
|
+
const S extends readonly SelectableKeys<TQuery>[],
|
|
1476
|
+
const I extends readonly SubTableKeys<TQuery>[]
|
|
1477
|
+
>(opts: FindOptions<TQuery> & {
|
|
1478
|
+
select: S;
|
|
1479
|
+
include: I;
|
|
1480
|
+
}): PageResult<SelectShape<TQuery, S> & TS & { [K in I[number]] : SubTableItem<TQuery, K>[] }>;
|
|
1481
|
+
findPage<const S extends readonly SelectableKeys<TQuery>[]>(opts: FindOptions<TQuery> & {
|
|
1482
|
+
select: S;
|
|
1483
|
+
}): PageResult<SelectShape<TQuery, S> & TS>;
|
|
1484
|
+
findPage(opts?: FindOptions<TQuery>): PageResult<Entity<Infer<TQuery>, Mat, TS>>;
|
|
1485
|
+
/**
|
|
1486
|
+
* Cursor-based pagination (seek method). Avoids OFFSET degradation on
|
|
1487
|
+
* large tables by using a boundary value from the previous page.
|
|
1488
|
+
*
|
|
1489
|
+
* @group Reading
|
|
1490
|
+
*
|
|
1491
|
+
* @example
|
|
1492
|
+
* ```ts
|
|
1493
|
+
* const page = orm.orders.findCursorPage({
|
|
1494
|
+
* orderBy: { column: "DocumentDate", direction: "DESC" },
|
|
1495
|
+
* limit: 25,
|
|
1496
|
+
* });
|
|
1497
|
+
*
|
|
1498
|
+
* const next = orm.orders.findCursorPage({
|
|
1499
|
+
* orderBy: { column: "DocumentDate", direction: "DESC" },
|
|
1500
|
+
* cursor: page.nextCursor!,
|
|
1501
|
+
* limit: 25,
|
|
1502
|
+
* });
|
|
1503
|
+
* ```
|
|
1504
|
+
*/
|
|
1505
|
+
findCursorPage(opts: {
|
|
1506
|
+
where?: WhereClause<TQuery>;
|
|
1507
|
+
orderBy: OrderByClause<TQuery>;
|
|
1508
|
+
cursor?: CursorInput;
|
|
1509
|
+
limit?: number;
|
|
1510
|
+
}): CursorPageResult<Entity<Infer<TQuery>, Mat, TS>>;
|
|
886
1511
|
/**
|
|
887
1512
|
* Find a single record matching the given filters. Equivalent to `findMany`
|
|
888
1513
|
* with `limit: 1`, but returns the entity directly (or `null`).
|
|
@@ -896,7 +1521,45 @@ declare class Repository<
|
|
|
896
1521
|
* });
|
|
897
1522
|
* ```
|
|
898
1523
|
*/
|
|
899
|
-
findOne
|
|
1524
|
+
findOne<
|
|
1525
|
+
const S extends readonly SelectableKeys<TQuery>[],
|
|
1526
|
+
const I extends readonly SubTableKeys<TQuery>[]
|
|
1527
|
+
>(opts: FindOptions<TQuery> & {
|
|
1528
|
+
select: S;
|
|
1529
|
+
include: I;
|
|
1530
|
+
}): (SelectShape<TQuery, S> & TS & { [K in I[number]] : SubTableItem<TQuery, K>[] }) | null;
|
|
1531
|
+
findOne<const S extends readonly SelectableKeys<TQuery>[]>(opts: FindOptions<TQuery> & {
|
|
1532
|
+
select: S;
|
|
1533
|
+
}): (SelectShape<TQuery, S> & TS) | null;
|
|
1534
|
+
findOne(opts?: FindOptions<TQuery>): Entity<Infer<TQuery>, Mat, TS> | null;
|
|
1535
|
+
/**
|
|
1536
|
+
* Iterate over records matching the given filters, yielding one row at a time.
|
|
1537
|
+
* Sub-tables are hydrated in windows to keep memory stable.
|
|
1538
|
+
*
|
|
1539
|
+
* @group Reading
|
|
1540
|
+
*
|
|
1541
|
+
* @example
|
|
1542
|
+
* ```ts
|
|
1543
|
+
* for (const user of orm.users.iterate({ where: { active: { eq: true } } })) {
|
|
1544
|
+
* console.log(user.name);
|
|
1545
|
+
* }
|
|
1546
|
+
* ```
|
|
1547
|
+
*/
|
|
1548
|
+
iterate<
|
|
1549
|
+
const S extends readonly SelectableKeys<TQuery>[],
|
|
1550
|
+
const I extends readonly SubTableKeys<TQuery>[]
|
|
1551
|
+
>(opts: FindOptions<TQuery> & {
|
|
1552
|
+
select: S;
|
|
1553
|
+
include: I;
|
|
1554
|
+
}): Generator<SelectShape<TQuery, S> & TS & { [K in I[number]] : SubTableItem<TQuery, K>[] }>;
|
|
1555
|
+
iterate<const I extends readonly SubTableKeys<TQuery>[]>(opts: FindOptions<TQuery> & {
|
|
1556
|
+
include: I;
|
|
1557
|
+
}): Generator<Entity<Infer<TQuery>, Mat, TS> & { [K in I[number]] : SubTableItem<TQuery, K>[] }>;
|
|
1558
|
+
iterate<const S extends readonly SelectableKeys<TQuery>[]>(opts: FindOptions<TQuery> & {
|
|
1559
|
+
select: S;
|
|
1560
|
+
}): Generator<SelectShape<TQuery, S> & TS>;
|
|
1561
|
+
iterate(opts?: FindOptions<TQuery>): Generator<Entity<Infer<TQuery>, Mat, TS>>;
|
|
1562
|
+
private _hydrateWindow;
|
|
900
1563
|
/**
|
|
901
1564
|
* Find many with resolved relations (n+1 safe). If you have cross-table
|
|
902
1565
|
* relations configured, this eagerly loads them in a single batch query.
|
|
@@ -911,7 +1574,7 @@ declare class Repository<
|
|
|
911
1574
|
* }
|
|
912
1575
|
* ```
|
|
913
1576
|
*/
|
|
914
|
-
findManyMaterialized(opts?: FindOptions<
|
|
1577
|
+
findManyMaterialized(opts?: FindOptions<TQuery>): Entity<Infer<TQuery>, Mat, TS>[];
|
|
915
1578
|
/**
|
|
916
1579
|
* Count records matching the given filters.
|
|
917
1580
|
*
|
|
@@ -923,7 +1586,54 @@ declare class Repository<
|
|
|
923
1586
|
* const adults = orm.users.count({ age: { gte: 18 } });
|
|
924
1587
|
* ```
|
|
925
1588
|
*/
|
|
926
|
-
count(where?: WhereClause<
|
|
1589
|
+
count(where?: WhereClause<TQuery>): number;
|
|
1590
|
+
/**
|
|
1591
|
+
* Run aggregate queries (sum, count, avg, min, max) with optional
|
|
1592
|
+
* grouping and filtering.
|
|
1593
|
+
*
|
|
1594
|
+
* @group Reading
|
|
1595
|
+
*
|
|
1596
|
+
* @example
|
|
1597
|
+
* ```ts
|
|
1598
|
+
* orm.orders.aggregate({
|
|
1599
|
+
* aggregations: { total: { sum: "amount" } },
|
|
1600
|
+
* });
|
|
1601
|
+
*
|
|
1602
|
+
* orm.orders.aggregate({
|
|
1603
|
+
* groupBy: ["status"],
|
|
1604
|
+
* aggregations: { count: { count: "*" }, avgAmount: { avg: "amount" } },
|
|
1605
|
+
* });
|
|
1606
|
+
* ```
|
|
1607
|
+
*/
|
|
1608
|
+
aggregate<
|
|
1609
|
+
const A extends Record<string, AggregationOp<TQuery>>,
|
|
1610
|
+
const G extends readonly (ScalarKeys<TQuery> | ScalarJsonPath<TQuery>)[] | undefined = undefined
|
|
1611
|
+
>(opts: AggregateOptions<TQuery, A> & {
|
|
1612
|
+
groupBy?: G;
|
|
1613
|
+
}): AggregateResult<TQuery, A, G>;
|
|
1614
|
+
/**
|
|
1615
|
+
* Run window function queries (rowNumber, rank, denseRank, lead, lag)
|
|
1616
|
+
* with partitioning and ordering.
|
|
1617
|
+
*
|
|
1618
|
+
* @group Reading
|
|
1619
|
+
*
|
|
1620
|
+
* @example
|
|
1621
|
+
* ```ts
|
|
1622
|
+
* orm.orders.windowQuery({
|
|
1623
|
+
* partitionBy: ["Status__Group"],
|
|
1624
|
+
* orderBy: [{ column: "DocumentDate", direction: "DESC" }],
|
|
1625
|
+
* select: {
|
|
1626
|
+
* rowNumber: { rowNumber: true },
|
|
1627
|
+
* rank: { rank: true },
|
|
1628
|
+
* leadTotal: { lead: "TotalTurnover", offset: 1 },
|
|
1629
|
+
* },
|
|
1630
|
+
* limit: 100,
|
|
1631
|
+
* });
|
|
1632
|
+
* ```
|
|
1633
|
+
*/
|
|
1634
|
+
windowQuery<const W extends Record<string, WindowFunction<TQuery>>>(opts: WindowQueryOptions<TQuery> & {
|
|
1635
|
+
select: W;
|
|
1636
|
+
}): WindowResult<TQuery, W>;
|
|
927
1637
|
/**
|
|
928
1638
|
* Update a record - must include the primary key. Returns the updated
|
|
929
1639
|
* entity, or `null` if no record matched.
|
|
@@ -935,7 +1645,22 @@ declare class Repository<
|
|
|
935
1645
|
* orm.users.update({ id: "u1", name: "alice smith" });
|
|
936
1646
|
* ```
|
|
937
1647
|
*/
|
|
938
|
-
update(data: UpdateData<
|
|
1648
|
+
update(data: UpdateData<TWrite, PK>): Entity<Infer<TQuery>, Mat, TS> | null;
|
|
1649
|
+
/**
|
|
1650
|
+
* Update multiple records matching the given filters.
|
|
1651
|
+
* Returns the number of rows changed.
|
|
1652
|
+
*
|
|
1653
|
+
* @group Writing
|
|
1654
|
+
*
|
|
1655
|
+
* @example
|
|
1656
|
+
* ```ts
|
|
1657
|
+
* orm.users.updateWhere({
|
|
1658
|
+
* where: { status: { eq: "pending" } },
|
|
1659
|
+
* data: { status: { group: "completed" } },
|
|
1660
|
+
* });
|
|
1661
|
+
* ```
|
|
1662
|
+
*/
|
|
1663
|
+
updateWhere(opts: UpdateWhereOptions<TWrite, PK>): number;
|
|
939
1664
|
/**
|
|
940
1665
|
* Delete a record by its primary key. Returns `true` if a record was deleted.
|
|
941
1666
|
*
|
|
@@ -946,7 +1671,7 @@ declare class Repository<
|
|
|
946
1671
|
* const deleted = orm.users.deleteById("u1");
|
|
947
1672
|
* ```
|
|
948
1673
|
*/
|
|
949
|
-
deleteById(id: Infer<
|
|
1674
|
+
deleteById(id: Infer<TWrite>[PK]): boolean;
|
|
950
1675
|
/**
|
|
951
1676
|
* Delete records matching the given filters. Returns the number of rows deleted.
|
|
952
1677
|
*
|
|
@@ -957,7 +1682,7 @@ declare class Repository<
|
|
|
957
1682
|
* const removed = orm.users.deleteWhere({ status: { eq: "banned" } });
|
|
958
1683
|
* ```
|
|
959
1684
|
*/
|
|
960
|
-
deleteWhere(where: WhereClause<
|
|
1685
|
+
deleteWhere(where: WhereClause<TQuery>): number;
|
|
961
1686
|
/**
|
|
962
1687
|
* Truncate the table and all sub-tables. Deletes all rows but keeps the schema.
|
|
963
1688
|
*
|
|
@@ -993,9 +1718,9 @@ declare class Repository<
|
|
|
993
1718
|
* );
|
|
994
1719
|
* ```
|
|
995
1720
|
*/
|
|
996
|
-
raw<R =
|
|
1721
|
+
raw<R = DBRow>(sql: string, ...params: DBValue[]): R[];
|
|
997
1722
|
}
|
|
998
|
-
declare class RelationBuilder<Tables extends Record<string,
|
|
1723
|
+
declare class RelationBuilder<Tables extends Record<string, TableDescriptor<any, any, any, any>>> {
|
|
999
1724
|
private readonly tables;
|
|
1000
1725
|
private readonly relations;
|
|
1001
1726
|
constructor(tables: Tables);
|
|
@@ -1025,16 +1750,14 @@ declare class RelationBuilder<Tables extends Record<string, TableConfig<any, any
|
|
|
1025
1750
|
build(): TypedRelation[];
|
|
1026
1751
|
}
|
|
1027
1752
|
/** @category Relations */
|
|
1028
|
-
declare function createRelationBuilder<T extends Record<string,
|
|
1753
|
+
declare function createRelationBuilder<T extends Record<string, TableDescriptor<any, any, any, any>>>(tables: T): RelationBuilder<T>;
|
|
1029
1754
|
import { Static as Static2 } from "typebox";
|
|
1030
1755
|
declare const SchemaHashSchema: unknown;
|
|
1031
|
-
/** @category Database */
|
|
1032
1756
|
declare const SchemaJSONSchema: unknown;
|
|
1033
1757
|
declare const TablesSchema: unknown;
|
|
1034
1758
|
declare const RelationsSchema: unknown;
|
|
1035
1759
|
declare const VersionSchema: unknown;
|
|
1036
1760
|
type SchemaHash = Static2<typeof SchemaHashSchema>;
|
|
1037
|
-
/** @category Database */
|
|
1038
1761
|
type SchemaJSON = Static2<typeof SchemaJSONSchema>;
|
|
1039
1762
|
type TablesList = Static2<typeof TablesSchema>;
|
|
1040
1763
|
type RelationsList = Static2<typeof RelationsSchema>;
|
|
@@ -1051,7 +1774,7 @@ declare class MetaStore {
|
|
|
1051
1774
|
private getRow;
|
|
1052
1775
|
private setRow;
|
|
1053
1776
|
private getValidatedJSON;
|
|
1054
|
-
private
|
|
1777
|
+
private validateAndSetJSON;
|
|
1055
1778
|
getString(key: string): string | null;
|
|
1056
1779
|
setString(key: string, value: string): void;
|
|
1057
1780
|
getJSON<T>(key: string): T | null;
|
|
@@ -1075,7 +1798,7 @@ declare class MetaStore {
|
|
|
1075
1798
|
* @category Lifecycle
|
|
1076
1799
|
*/
|
|
1077
1800
|
interface ORMContext<
|
|
1078
|
-
T extends Record<string,
|
|
1801
|
+
T extends Record<string, TableDescriptor<any, any, any, any>> = Record<string, TableDescriptor<any, any, any, any>>,
|
|
1079
1802
|
Rels extends readonly TypedRelation[] = readonly TypedRelation[]
|
|
1080
1803
|
> {
|
|
1081
1804
|
orm: foxdb<T, Rels>;
|
|
@@ -1093,7 +1816,7 @@ interface ORMContext<
|
|
|
1093
1816
|
* @category Lifecycle
|
|
1094
1817
|
*/
|
|
1095
1818
|
type LifecycleHook<
|
|
1096
|
-
T extends Record<string,
|
|
1819
|
+
T extends Record<string, TableDescriptor<any, any, any, any>> = Record<string, TableDescriptor<any, any, any, any>>,
|
|
1097
1820
|
Rels extends readonly TypedRelation[] = readonly TypedRelation[]
|
|
1098
1821
|
> = (ctx: ORMContext<T, Rels>) => void | Promise<void>;
|
|
1099
1822
|
/**
|
|
@@ -1101,7 +1824,7 @@ type LifecycleHook<
|
|
|
1101
1824
|
* @category Lifecycle
|
|
1102
1825
|
*/
|
|
1103
1826
|
declare class LifecycleManager<
|
|
1104
|
-
T extends Record<string,
|
|
1827
|
+
T extends Record<string, TableDescriptor<any, any, any, any>> = Record<string, TableDescriptor<any, any, any, any>>,
|
|
1105
1828
|
Rels extends readonly TypedRelation[] = readonly TypedRelation[]
|
|
1106
1829
|
> {
|
|
1107
1830
|
private startHooks;
|
|
@@ -1142,6 +1865,10 @@ interface CreateORMBaseOptions {
|
|
|
1142
1865
|
busyTimeout?: number;
|
|
1143
1866
|
synchronous?: "OFF" | "NORMAL" | "FULL" | "EXTRA";
|
|
1144
1867
|
mmapSize?: number;
|
|
1868
|
+
autoVacuum?: "incremental" | "full" | false;
|
|
1869
|
+
vacuumIntervalMs?: number;
|
|
1870
|
+
/** disable fsync during large initial loads */
|
|
1871
|
+
bulkLoadMode?: boolean;
|
|
1145
1872
|
}
|
|
1146
1873
|
/**
|
|
1147
1874
|
* Options passed to `createORM`.
|
|
@@ -1172,7 +1899,7 @@ interface CreateORMBaseOptions {
|
|
|
1172
1899
|
* ```
|
|
1173
1900
|
*/
|
|
1174
1901
|
interface CreateORMOptions<
|
|
1175
|
-
T extends Record<string,
|
|
1902
|
+
T extends Record<string, TableDescriptor<any, any, any, any>> = Record<string, TableDescriptor<any, any, any, any>>,
|
|
1176
1903
|
Rels extends readonly TypedRelation[] = readonly TypedRelation[]
|
|
1177
1904
|
> extends CreateORMBaseOptions {
|
|
1178
1905
|
/** table schemas */
|
|
@@ -1215,6 +1942,8 @@ interface CreateORMOptions<
|
|
|
1215
1942
|
errorPolicy?: ErrorPolicy;
|
|
1216
1943
|
/** delete db files on exit */
|
|
1217
1944
|
unlinkDbFilesOnExit?: UnlinkPolicy;
|
|
1945
|
+
/** observability hooks */
|
|
1946
|
+
hooks?: QueryMetricsHook;
|
|
1218
1947
|
}
|
|
1219
1948
|
/**
|
|
1220
1949
|
* The ORM object returned by `createORM`.
|
|
@@ -1266,15 +1995,19 @@ interface CreateORMOptions<
|
|
|
1266
1995
|
* ```
|
|
1267
1996
|
*/
|
|
1268
1997
|
type foxdb<
|
|
1269
|
-
Tables extends Record<string,
|
|
1998
|
+
Tables extends Record<string, TableDescriptor<any, any, any, any>>,
|
|
1270
1999
|
Rels extends readonly TypedRelation[] = readonly TypedRelation[]
|
|
1271
|
-
> = { [K in keyof Tables] : Tables[K] extends
|
|
2000
|
+
> = { [K in keyof Tables] : Tables[K] extends TableDescriptor<infer TWrite extends TSchema6 & {
|
|
2001
|
+
properties: Record<string, TSchema6>;
|
|
2002
|
+
}, infer PKName extends string, infer Timestamps, infer G extends GeneratedColumnConfig | undefined> ? Repository<TWrite, QuerySchema<TWrite, G>, PKName extends ScalarKeys<TWrite> ? PKName : never, Materialized<TWrite, Tables, Rels, K & string>, TimestampShape<Timestamps>> : never } & {
|
|
1272
2003
|
/** run a transaction */
|
|
1273
2004
|
_transaction<R>(fn: () => R): R;
|
|
1274
2005
|
/** close the database */
|
|
1275
2006
|
_close(): void;
|
|
1276
2007
|
/** read-only metadata */
|
|
1277
2008
|
_meta: MetaAccessors;
|
|
2009
|
+
/** toggle bulk-load mode (disables synchronous fsync) */
|
|
2010
|
+
_setBulkLoadMode(enabled: boolean): void;
|
|
1278
2011
|
/** resolve relations for a single record */
|
|
1279
2012
|
_materialize<Owner extends keyof Tables & string>(ownerTable: Owner, record: Record<string, unknown>): Record<string, unknown>;
|
|
1280
2013
|
/** resolve relations for many records (n+1 safe) */
|
|
@@ -1290,69 +2023,9 @@ type foxdb<
|
|
|
1290
2023
|
};
|
|
1291
2024
|
/** create a typed orm instance backed by sqlite */
|
|
1292
2025
|
declare function createORM<
|
|
1293
|
-
const T extends Record<string,
|
|
2026
|
+
const T extends Record<string, TableDescriptor<any, any, any, any>>,
|
|
1294
2027
|
const Rels extends readonly TypedRelation[] = readonly TypedRelation[]
|
|
1295
2028
|
>(opts: CreateORMOptions<T, Rels>): foxdb<T, Rels>;
|
|
1296
|
-
import { TObject as TObject5 } from "typebox";
|
|
1297
|
-
/** @category Schema */
|
|
1298
|
-
interface SubTableConfig {
|
|
1299
|
-
indexes?: IndexDefinition[];
|
|
1300
|
-
}
|
|
1301
|
-
/** @category Schema */
|
|
1302
|
-
interface TableDescriptor<
|
|
1303
|
-
T extends TObject5,
|
|
1304
|
-
PK extends string,
|
|
1305
|
-
TS extends TimestampConfig = undefined
|
|
1306
|
-
> extends TableConfig<T, PK, TS> {}
|
|
1307
|
-
/** @category Schema */
|
|
1308
|
-
interface TableConfigShape<
|
|
1309
|
-
PK extends string,
|
|
1310
|
-
TS extends TimestampConfig
|
|
1311
|
-
> {
|
|
1312
|
-
primaryKey: ColumnRef<PK>;
|
|
1313
|
-
indexes?: IndexDefinition[];
|
|
1314
|
-
subTables?: Partial<Record<string, SubTableConfig>>;
|
|
1315
|
-
timestamps?: TS;
|
|
1316
|
-
}
|
|
1317
|
-
/**
|
|
1318
|
-
* Describe a table schema + config for `createORM`.
|
|
1319
|
-
*
|
|
1320
|
-
* @example
|
|
1321
|
-
* ```ts
|
|
1322
|
-
* const UserSchema = Object({ id: String(), name: String(), email: String() });
|
|
1323
|
-
*
|
|
1324
|
-
* const users = table(UserSchema, (s) => ({
|
|
1325
|
-
* primaryKey: s.id,
|
|
1326
|
-
* indexes: [{ columns: [s.email], unique: true }],
|
|
1327
|
-
* timestamps: true, // adds createdAt / updatedAt
|
|
1328
|
-
* }));
|
|
1329
|
-
* ```
|
|
1330
|
-
* @category Schema
|
|
1331
|
-
* @category Schema
|
|
1332
|
-
*/
|
|
1333
|
-
declare function table<
|
|
1334
|
-
T extends TObject5,
|
|
1335
|
-
PK extends string,
|
|
1336
|
-
const TS extends boolean
|
|
1337
|
-
>(schema: T, configure: (columns: ColumnRefs<T>) => TableConfigShape<PK, TS> & {
|
|
1338
|
-
timestamps: TS;
|
|
1339
|
-
}): TableDescriptor<T, PK, TS>;
|
|
1340
|
-
/** @category Schema */
|
|
1341
|
-
declare function table<
|
|
1342
|
-
T extends TObject5,
|
|
1343
|
-
PK extends string,
|
|
1344
|
-
const TS extends {
|
|
1345
|
-
createdAt?: string;
|
|
1346
|
-
updatedAt?: string;
|
|
1347
|
-
}
|
|
1348
|
-
>(schema: T, configure: (columns: ColumnRefs<T>) => TableConfigShape<PK, TS> & {
|
|
1349
|
-
timestamps: TS;
|
|
1350
|
-
}): TableDescriptor<T, PK, TS>;
|
|
1351
|
-
/** @category Schema */
|
|
1352
|
-
declare function table<
|
|
1353
|
-
T extends TObject5,
|
|
1354
|
-
PK extends string
|
|
1355
|
-
>(schema: T, configure: (columns: ColumnRefs<T>) => TableConfigShape<PK, undefined>): TableDescriptor<T, PK, undefined>;
|
|
1356
2029
|
declare function migrate(opts: MigrateOptions): Promise<void>;
|
|
1357
2030
|
/** @category Migration */
|
|
1358
2031
|
declare function createMigration(name: string, migrationsDir: string): string;
|
|
@@ -1460,4 +2133,4 @@ interface DesiredTable {
|
|
|
1460
2133
|
declare function computeDiff(desired: DesiredTable[], actual: InspectorTable[]): SchemaDiff;
|
|
1461
2134
|
/** @category Migration */
|
|
1462
2135
|
declare function applySync(diff: SchemaDiff, db: BunDatabase, policy: SyncPolicy, desired: DesiredTable[]): void;
|
|
1463
|
-
export { withTrace, table, resolveTimestampNames, raise, migrate, introspectTable, inspectSchema, inspectAllTables, foxdb, createRelationBuilder, createORM, createMigration, computeDiff, buildCreateTableSQL, applySync, WhereClause, UpsertOptions, UpdateData, UnlinkPolicy, TypedRelation, TraceEntry, TimestampShape, TimestampConfig2 as TimestampNamesConfig, TableOperation, TableMeta, TableEventPayload, TableEventOperation, TableDescriptor, TableConfigShape, TableConfig, TScalarSchema, SyncPolicy, SubTableScalarPath, SubTableMeta, SubTableKeys, SubTableConfig, SubMergeType, SubMergeNames, SubMerge, SqliteType, SchemaJSONSchema, SchemaJSON, SchemaDiff, SchemaChange, ScalarProperties, ScalarPath, ScalarMergeType, ScalarMergeNames, ScalarMerge, ScalarKeys, ScalarFilter, Repository, RelationsConfig, RelationEntry, RelationBuilder, PageResult, OrderByClause, ORMEvents, ORMErrorContext, ORMError, ORMContext, Migration, MigrateOptions, MetaStore, Materialized, Listener, LifecycleManager, LifecycleHook, LifecycleEventMap, InspectorTable, InspectorIndex, InspectorColumn, InsertData, Infer, IndexDefinition, FindOptions, EventBus, ErrorPolicy2 as ErrorPolicy, Entity, DesiredTable, DatabaseOptions, DEFAULT_TIMESTAMP_NAMES, CreateORMOptions, CreateORMBaseOptions, ColumnRefs, ColumnRef, ColumnMeta, BunStatement, BunDatabase, BroadOperation, ArrayOfObjectProperties };
|
|
2136
|
+
export { withTrace, table, resolveTimestampNames, raise, migrate, introspectTable, inspectSchema, inspectAllTables, foxdb, createRelationBuilder, createORM, createMigration, computeDiff, buildCreateTableSQL, applySync, WhereClause, UpsertOptions, UpdateData, UnlinkPolicy, TypedRelation, TraceEntry, TimestampShape, TimestampConfig2 as TimestampNamesConfig, TableOperation, TableMeta, TableEventPayload, TableEventOperation, TableDescriptor, TableConfigShape, TableConfig, TScalarSchema, SyncPolicy, SubTableScalarPath, SubTableMeta, SubTableKeys, SubTableConfig, SubMergeType, SubMergeNames, SubMerge, SqliteType, SchemaJSONSchema, SchemaJSON, SchemaDiff, SchemaChange, ScalarProperties, ScalarPath, ScalarMergeType, ScalarMergeNames, ScalarMerge, ScalarKeys, ScalarFilter, Repository, RelationsConfig, RelationEntry, RelationBuilder, QueryMetricsHook, QueryMetrics, PageResult, OrderByClause, ORMEvents, ORMErrorContext, ORMError, ORMContext, Migration, MigrateOptions, MetaStore, Materialized, Listener, LifecycleManager, LifecycleHook, LifecycleEventMap, InspectorTable, InspectorIndex, InspectorColumn, InsertData, Infer, IndexDefinition, GeneratedColumnConfig, FindOptions, EventBus, ErrorPolicy2 as ErrorPolicy, Entity, DesiredTable, DatabaseOptions, DEFAULT_TIMESTAMP_NAMES, CreateORMOptions, CreateORMBaseOptions, ColumnRefs, ColumnRef, ColumnMeta, BunStatement, BunDatabase, BroadOperation, BatchWriterOptions, BatchWriter, ArrayOfObjectProperties, AggregationOp, AggregateOptions };
|