tempest-db-js 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/bin.cjs +580 -329
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +3 -3
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-5QQMVTS5.js → chunk-4AWUP7BM.js} +540 -57
- package/dist/chunk-4AWUP7BM.js.map +1 -0
- package/dist/{chunk-EPMLFNFK.js → chunk-SI4CLSF7.js} +109 -59
- package/dist/chunk-SI4CLSF7.js.map +1 -0
- package/dist/index.cjs +544 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +430 -22
- package/dist/index.d.ts +430 -22
- package/dist/index.js +1 -1
- package/dist/migrations/index.cjs +122 -55
- package/dist/migrations/index.cjs.map +1 -1
- package/dist/migrations/index.d.cts +46 -3
- package/dist/migrations/index.d.ts +46 -3
- package/dist/migrations/index.js +2 -2
- package/package.json +6 -1
- package/dist/chunk-5QQMVTS5.js.map +0 -1
- package/dist/chunk-EPMLFNFK.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,8 @@ interface SelectNode {
|
|
|
61
61
|
/** `GROUP BY` columns. */
|
|
62
62
|
readonly groupBy: readonly string[];
|
|
63
63
|
readonly where: CondNode | undefined;
|
|
64
|
+
/** `HAVING` condition, keyed by aggregate alias or grouped column. */
|
|
65
|
+
readonly having?: CondNode | undefined;
|
|
64
66
|
readonly orderBy: readonly OrderTerm[];
|
|
65
67
|
readonly limit: number | undefined;
|
|
66
68
|
readonly offset: number | undefined;
|
|
@@ -69,16 +71,34 @@ interface SelectNode {
|
|
|
69
71
|
/** Property → column map, or `undefined` when every name is the identity. */
|
|
70
72
|
readonly names?: NameMap | undefined;
|
|
71
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* A SELECT projecting exactly one column of type `T`, usable as the operand of
|
|
76
|
+
* `in` / `notIn`.
|
|
77
|
+
*
|
|
78
|
+
* Build it with {@link SelectBuilder.asSubquery}, which both narrows the
|
|
79
|
+
* projection to one column and gives the operand its element type.
|
|
80
|
+
*/
|
|
81
|
+
interface Subquery<T> {
|
|
82
|
+
/** Phantom: the element type the subquery yields, read only by the type system. */
|
|
83
|
+
readonly __element?: T;
|
|
84
|
+
/** The AST the outer statement embeds. */
|
|
85
|
+
readonly node: SelectNode;
|
|
86
|
+
}
|
|
87
|
+
/** Runtime guard: is this `in`/`notIn` operand a subquery rather than a list? */
|
|
88
|
+
declare function isSubquery(value: unknown): value is Subquery<unknown>;
|
|
72
89
|
/** Operators valid on every column type. */
|
|
73
90
|
interface BaseOperators<T> {
|
|
74
91
|
/** Equal to. */
|
|
75
92
|
eq?: T;
|
|
76
93
|
/** Not equal to. */
|
|
77
94
|
ne?: T;
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
/**
|
|
96
|
+
* One of the given values (`IN`) — a list, or a single-column
|
|
97
|
+
* {@link Subquery} built with `.asSubquery(column)`.
|
|
98
|
+
*/
|
|
99
|
+
in?: readonly T[] | Subquery<T>;
|
|
100
|
+
/** None of the given values (`NOT IN`), as a list or a {@link Subquery}. */
|
|
101
|
+
notIn?: readonly T[] | Subquery<T>;
|
|
82
102
|
/** `IS NULL` (true) / `IS NOT NULL` (false). */
|
|
83
103
|
isNull?: boolean;
|
|
84
104
|
}
|
|
@@ -174,20 +194,43 @@ type SimplifyProj<T> = {
|
|
|
174
194
|
* @typeParam Full - the complete row type (constrains where/orderBy keys).
|
|
175
195
|
* @typeParam Proj - the projected result type returned on execution.
|
|
176
196
|
*/
|
|
177
|
-
declare class SelectBuilder<Full, Proj = Full> {
|
|
197
|
+
declare class SelectBuilder<Full, Proj = Full, Grouped extends boolean = false> {
|
|
178
198
|
readonly node: SelectNode;
|
|
179
199
|
/** The source model, used to coerce rows on execution. */
|
|
180
200
|
readonly source: ModelClass;
|
|
181
201
|
/** Phantom: the result element type, read only by the type system. */
|
|
182
202
|
readonly __row: Proj;
|
|
203
|
+
/** Phantom: `true` once `aggregate()` has made `having()` meaningful. */
|
|
204
|
+
readonly __grouped: Grouped;
|
|
183
205
|
constructor(node: SelectNode,
|
|
184
206
|
/** The source model, used to coerce rows on execution. */
|
|
185
207
|
source: ModelClass);
|
|
186
208
|
private with;
|
|
187
209
|
/** Add a WHERE filter: the object form (keys typed) or an `and`/`or`/`not`. */
|
|
188
|
-
where(input: WhereInput<Full> | Condition): SelectBuilder<Full, Proj>;
|
|
210
|
+
where(input: WhereInput<Full> | Condition): SelectBuilder<Full, Proj, Grouped>;
|
|
211
|
+
/**
|
|
212
|
+
* Filter by the result of the aggregation (`HAVING`).
|
|
213
|
+
*
|
|
214
|
+
* Only available on a grouped builder — `.having()` before `.aggregate()` is a
|
|
215
|
+
* compile error, not invalid SQL at runtime. Keys are the aggregate aliases you
|
|
216
|
+
* named plus the grouped columns; `WHERE` still filters rows *before* grouping,
|
|
217
|
+
* which is a different question.
|
|
218
|
+
*
|
|
219
|
+
* @param input The condition, keyed by alias or grouped column.
|
|
220
|
+
* @returns A builder carrying the `HAVING` clause.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* select(Outbound)
|
|
225
|
+
* .where({ status: "queued" })
|
|
226
|
+
* .aggregate(["consumer"], { n: count() })
|
|
227
|
+
* .having({ n: { gt: 100 } });
|
|
228
|
+
* // ... GROUP BY "consumer" HAVING COUNT(*) > $2
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
having(this: SelectBuilder<Full, Proj, true>, input: WhereInput<Proj> | Condition): SelectBuilder<Full, Proj, true>;
|
|
189
232
|
/** Emit `SELECT DISTINCT` — drop duplicate rows. */
|
|
190
|
-
distinct(): SelectBuilder<Full, Proj>;
|
|
233
|
+
distinct(): SelectBuilder<Full, Proj, Grouped>;
|
|
191
234
|
/**
|
|
192
235
|
* Group by columns and compute aggregates. The result row is the grouped
|
|
193
236
|
* columns (typed from the model) plus one field per aggregate alias.
|
|
@@ -206,13 +249,50 @@ declare class SelectBuilder<Full, Proj = Full> {
|
|
|
206
249
|
*/
|
|
207
250
|
aggregate<K extends keyof Full & string, S extends Record<string, Agg<unknown>>>(groupBy: readonly K[], spec: S): SelectBuilder<Full, SimplifyProj<Pick<Full, K> & {
|
|
208
251
|
[A in keyof S]: AggResult<S[A]>;
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
|
|
252
|
+
}>, true>;
|
|
253
|
+
/**
|
|
254
|
+
* Order by a column of the model, or — on a grouped query — by an aggregate
|
|
255
|
+
* alias. Unlike `HAVING`, every dialect accepts the output alias in `ORDER BY`,
|
|
256
|
+
* so the alias is emitted as written.
|
|
257
|
+
*
|
|
258
|
+
* @param column A model column, or a projected alias.
|
|
259
|
+
* @param direction `"asc"` (default) or `"desc"`.
|
|
260
|
+
* @returns A builder carrying the ordering term.
|
|
261
|
+
*/
|
|
262
|
+
orderBy(column: (keyof Full & string) | (keyof Proj & string), direction?: SortDirection): SelectBuilder<Full, Proj, Grouped>;
|
|
212
263
|
/** Limit the number of rows. */
|
|
213
|
-
limit(n: number): SelectBuilder<Full, Proj>;
|
|
264
|
+
limit(n: number): SelectBuilder<Full, Proj, Grouped>;
|
|
214
265
|
/** Skip the first `n` rows. */
|
|
215
|
-
offset(n: number): SelectBuilder<Full, Proj>;
|
|
266
|
+
offset(n: number): SelectBuilder<Full, Proj, Grouped>;
|
|
267
|
+
/**
|
|
268
|
+
* Narrow this SELECT to a single column and mark it as a subquery, so it can be
|
|
269
|
+
* the operand of `in` / `notIn`.
|
|
270
|
+
*
|
|
271
|
+
* The whole query — `where`, `orderBy`, `limit`, and a locking clause — is
|
|
272
|
+
* embedded in the outer statement, which is what collapses the claim-a-batch
|
|
273
|
+
* pattern into one round trip instead of selecting ids and sending them back.
|
|
274
|
+
*
|
|
275
|
+
* @param column The single column to project (checked against the model).
|
|
276
|
+
* @returns A subquery carrying that column's type.
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```ts
|
|
280
|
+
* update(Outbound)
|
|
281
|
+
* .set({ status: "sending", attempts: sql.raw("attempts + 1") })
|
|
282
|
+
* .where({
|
|
283
|
+
* id: {
|
|
284
|
+
* in: select(Outbound)
|
|
285
|
+
* .where({ status: "queued" })
|
|
286
|
+
* .orderBy("nextAttemptAt")
|
|
287
|
+
* .limit(10)
|
|
288
|
+
* .forUpdate({ skipLocked: true })
|
|
289
|
+
* .asSubquery("id"),
|
|
290
|
+
* },
|
|
291
|
+
* })
|
|
292
|
+
* .returning();
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
asSubquery<K extends keyof Full & string>(column: K): Subquery<Full[K]>;
|
|
216
296
|
/**
|
|
217
297
|
* Lock the selected rows for update (`SELECT ... FOR UPDATE`), à la
|
|
218
298
|
* SQLAlchemy's `with_for_update()`.
|
|
@@ -241,7 +321,7 @@ declare class SelectBuilder<Full, Proj = Full> {
|
|
|
241
321
|
* ).all();
|
|
242
322
|
* ```
|
|
243
323
|
*/
|
|
244
|
-
forUpdate(options?: LockOptions): SelectBuilder<Full, Proj>;
|
|
324
|
+
forUpdate(options?: LockOptions): SelectBuilder<Full, Proj, Grouped>;
|
|
245
325
|
/**
|
|
246
326
|
* Take a shared read lock on the selected rows (`SELECT ... FOR SHARE`), the
|
|
247
327
|
* weaker counterpart of {@link SelectBuilder.forUpdate}.
|
|
@@ -250,7 +330,7 @@ declare class SelectBuilder<Full, Proj = Full> {
|
|
|
250
330
|
* @returns A builder carrying the locking clause.
|
|
251
331
|
* @throws Error When both `skipLocked` and `noWait` are set.
|
|
252
332
|
*/
|
|
253
|
-
forShare(options?: LockOptions): SelectBuilder<Full, Proj>;
|
|
333
|
+
forShare(options?: LockOptions): SelectBuilder<Full, Proj, Grouped>;
|
|
254
334
|
}
|
|
255
335
|
/** Build a SELECT over every column of the model. */
|
|
256
336
|
declare function select<C extends ModelClass>(model: C): SelectBuilder<InferModel<C>, InferModel<C>>;
|
|
@@ -271,6 +351,25 @@ interface CondFields {
|
|
|
271
351
|
readonly kind: "fields";
|
|
272
352
|
readonly fields: Record<string, unknown>;
|
|
273
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* One side of a comparison: a column reference, a bound value, or a SQL function
|
|
356
|
+
* applied to other expressions.
|
|
357
|
+
*
|
|
358
|
+
* A column reference carries the **property** name, not the database column —
|
|
359
|
+
* the dialect resolves it through the node's name map, so `col()` cannot become a
|
|
360
|
+
* back door around an explicit `.name()` mapping.
|
|
361
|
+
*/
|
|
362
|
+
type ExprNode = {
|
|
363
|
+
readonly kind: "column";
|
|
364
|
+
readonly name: string;
|
|
365
|
+
} | {
|
|
366
|
+
readonly kind: "value";
|
|
367
|
+
readonly value: unknown;
|
|
368
|
+
} | {
|
|
369
|
+
readonly kind: "fn";
|
|
370
|
+
readonly name: string;
|
|
371
|
+
readonly args: readonly ExprNode[];
|
|
372
|
+
};
|
|
274
373
|
/** Logical condition nodes. */
|
|
275
374
|
type CondNode = CondFields | {
|
|
276
375
|
readonly kind: "and";
|
|
@@ -281,6 +380,11 @@ type CondNode = CondFields | {
|
|
|
281
380
|
} | {
|
|
282
381
|
readonly kind: "not";
|
|
283
382
|
readonly part: CondNode;
|
|
383
|
+
} | {
|
|
384
|
+
readonly kind: "compare";
|
|
385
|
+
readonly left: ExprNode;
|
|
386
|
+
readonly op: Operator;
|
|
387
|
+
readonly right: ExprNode;
|
|
284
388
|
};
|
|
285
389
|
declare const CONDITION: unique symbol;
|
|
286
390
|
/** A composed condition produced by `and`/`or`/`not`. */
|
|
@@ -300,6 +404,145 @@ declare function toCondNode(input: Condition | Record<string, unknown>): CondNod
|
|
|
300
404
|
* for full key + operator checking inside combinators.
|
|
301
405
|
*/
|
|
302
406
|
type WhereArg<Row = Record<string, unknown>> = WhereInput<Row> | Condition;
|
|
407
|
+
/** Runtime guard: is this operand a built {@link Expression}? */
|
|
408
|
+
declare function isExpression(value: unknown): value is Expression;
|
|
409
|
+
/**
|
|
410
|
+
* One side of a comparison, built with {@link col}, {@link val} or {@link fn}.
|
|
411
|
+
*
|
|
412
|
+
* The comparison methods mirror the `where` operators, but both sides are
|
|
413
|
+
* expressions — which is what makes `col("total").gt(col("paid"))` and a
|
|
414
|
+
* functional-index lookup like `fn.lower("email").eq(fn.lower(val(probe)))`
|
|
415
|
+
* expressible at all. An operand that is not an `Expression` is bound as a
|
|
416
|
+
* parameter, so `.eq(probe)` stays safe by default.
|
|
417
|
+
*/
|
|
418
|
+
declare class Expression {
|
|
419
|
+
/** The expression AST the dialect renders. */
|
|
420
|
+
readonly node: ExprNode;
|
|
421
|
+
constructor(
|
|
422
|
+
/** The expression AST the dialect renders. */
|
|
423
|
+
node: ExprNode);
|
|
424
|
+
/** Compare this expression against another expression or a bound value. */
|
|
425
|
+
private compare;
|
|
426
|
+
/** `=` (or `IS NULL` for a null value). */
|
|
427
|
+
eq(operand: unknown): Condition;
|
|
428
|
+
/** `<>` (or `IS NOT NULL` for a null value). */
|
|
429
|
+
ne(operand: unknown): Condition;
|
|
430
|
+
/** `>`. */
|
|
431
|
+
gt(operand: unknown): Condition;
|
|
432
|
+
/** `>=`. */
|
|
433
|
+
gte(operand: unknown): Condition;
|
|
434
|
+
/** `<`. */
|
|
435
|
+
lt(operand: unknown): Condition;
|
|
436
|
+
/** `<=`. */
|
|
437
|
+
lte(operand: unknown): Condition;
|
|
438
|
+
/** `LIKE` — `%` and `_` in the operand are wildcards. */
|
|
439
|
+
like(pattern: string | Expression): Condition;
|
|
440
|
+
/** `ILIKE` — case-insensitive **pattern** matching, wildcards included. */
|
|
441
|
+
ilike(pattern: string | Expression): Condition;
|
|
442
|
+
/** Case-insensitive equality (`lower(a) = lower(b)`), with no wildcards. */
|
|
443
|
+
ieq(operand: unknown): Condition;
|
|
444
|
+
/**
|
|
445
|
+
* `IN (...)` over a list of values.
|
|
446
|
+
*
|
|
447
|
+
* @param values The values to test against.
|
|
448
|
+
* @returns The condition.
|
|
449
|
+
* @throws Error When an entry is an {@link Expression} — a list operand is
|
|
450
|
+
* bound, so an expression there would be serialized as a parameter instead of
|
|
451
|
+
* rendered as SQL.
|
|
452
|
+
*/
|
|
453
|
+
in(values: readonly unknown[]): Condition;
|
|
454
|
+
/**
|
|
455
|
+
* `NOT IN (...)` over a list of values.
|
|
456
|
+
*
|
|
457
|
+
* @param values The values to exclude.
|
|
458
|
+
* @returns The condition.
|
|
459
|
+
* @throws Error When an entry is an {@link Expression} (see {@link Expression.in}).
|
|
460
|
+
*/
|
|
461
|
+
notIn(values: readonly unknown[]): Condition;
|
|
462
|
+
/**
|
|
463
|
+
* `BETWEEN lo AND hi` (inclusive).
|
|
464
|
+
*
|
|
465
|
+
* @param lo The lower bound.
|
|
466
|
+
* @param hi The upper bound.
|
|
467
|
+
* @returns The condition.
|
|
468
|
+
* @throws Error When a bound is an {@link Expression} (see {@link Expression.in}).
|
|
469
|
+
*/
|
|
470
|
+
between(lo: unknown, hi: unknown): Condition;
|
|
471
|
+
/** `IS NULL` (true) / `IS NOT NULL` (false). */
|
|
472
|
+
isNull(value?: boolean): Condition;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* A column reference, by **property** name.
|
|
476
|
+
*
|
|
477
|
+
* Pass the row type for key-safety: `col<UserRow>("total")` rejects a name that
|
|
478
|
+
* is not a column. The name is resolved through the model's column-name map at
|
|
479
|
+
* compile time, exactly like the object form of `where`.
|
|
480
|
+
*
|
|
481
|
+
* @param name The model property name.
|
|
482
|
+
* @returns An expression referencing that column.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```ts
|
|
486
|
+
* select(Order).where(col<OrderRow>("total").gt(col<OrderRow>("paid")));
|
|
487
|
+
* // SELECT * FROM "orders" WHERE "total" > "paid"
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
declare function col<Row = Record<string, unknown>>(name: keyof Row & string): Expression;
|
|
491
|
+
/**
|
|
492
|
+
* A bound value, for the places that take an expression and would otherwise read
|
|
493
|
+
* a bare string as a column name (the arguments of {@link fn}).
|
|
494
|
+
*
|
|
495
|
+
* @param value The value to bind as a parameter.
|
|
496
|
+
* @returns An expression that renders as a placeholder.
|
|
497
|
+
*/
|
|
498
|
+
declare function val(value: unknown): Expression;
|
|
499
|
+
/**
|
|
500
|
+
* Build a call to a SQL function.
|
|
501
|
+
*
|
|
502
|
+
* A bare string argument is a **column name** — that is the useful default here
|
|
503
|
+
* (`fn.lower("username")`), and it is why a literal has to be wrapped in
|
|
504
|
+
* {@link val}. The function name is interpolated into the statement, so it is
|
|
505
|
+
* validated as a plain identifier and must never come from user input; the
|
|
506
|
+
* arguments are always rendered through the expression compiler.
|
|
507
|
+
*
|
|
508
|
+
* @param name The SQL function name.
|
|
509
|
+
* @param args Column names or expressions.
|
|
510
|
+
* @returns An expression for the call.
|
|
511
|
+
* @throws Error When `name` is not a plain SQL identifier.
|
|
512
|
+
*/
|
|
513
|
+
declare function call(name: string, ...args: (Expression | string)[]): Expression;
|
|
514
|
+
/**
|
|
515
|
+
* SQL functions usable on either side of a comparison.
|
|
516
|
+
*
|
|
517
|
+
* The named entries are the ones every supported dialect implements. Anything
|
|
518
|
+
* else — `date_trunc`, `strftime`, a custom function — goes through
|
|
519
|
+
* {@link fn.call}, which does not pretend to be portable.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```ts
|
|
523
|
+
* select(AdminUser).where(fn.lower("username").eq(fn.lower(val(probe))));
|
|
524
|
+
* // WHERE lower("username") = lower($1)
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
declare const fn: {
|
|
528
|
+
/** `lower(x)`. */
|
|
529
|
+
readonly lower: (arg: Expression | string) => Expression;
|
|
530
|
+
/** `upper(x)`. */
|
|
531
|
+
readonly upper: (arg: Expression | string) => Expression;
|
|
532
|
+
/** `trim(x)`. */
|
|
533
|
+
readonly trim: (arg: Expression | string) => Expression;
|
|
534
|
+
/** `length(x)`. */
|
|
535
|
+
readonly length: (arg: Expression | string) => Expression;
|
|
536
|
+
/** `abs(x)`. */
|
|
537
|
+
readonly abs: (arg: Expression | string) => Expression;
|
|
538
|
+
/** `coalesce(a, b, ...)`. */
|
|
539
|
+
readonly coalesce: (...args: (Expression | string)[]) => Expression;
|
|
540
|
+
/**
|
|
541
|
+
* Any other SQL function, by name. Portability is the caller's problem —
|
|
542
|
+
* `date_trunc` is PostgreSQL, `strftime` is SQLite.
|
|
543
|
+
*/
|
|
544
|
+
readonly call: typeof call;
|
|
545
|
+
};
|
|
303
546
|
/** Combine conditions with `AND`. */
|
|
304
547
|
declare function and<Row = Record<string, unknown>>(...inputs: WhereArg<NoInfer<Row>>[]): Condition;
|
|
305
548
|
/** Combine conditions with `OR`. */
|
|
@@ -398,7 +641,8 @@ declare class InsertBuilder<Full, Ins, Ret = number> {
|
|
|
398
641
|
* @param rows One row, or an array of rows.
|
|
399
642
|
* @returns A builder carrying the rows.
|
|
400
643
|
* @throws ValidationError When a value is not a column value the dialect can
|
|
401
|
-
* bind (see the `sql` helpers for writing an expression instead)
|
|
644
|
+
* bind (see the `sql` helpers for writing an expression instead), or when the
|
|
645
|
+
* rows of a multi-row insert disagree about a column that has a default.
|
|
402
646
|
*/
|
|
403
647
|
values(rows: WriteValues<Ins> | readonly WriteValues<Ins>[]): InsertBuilder<Full, Ins, Ret>;
|
|
404
648
|
/**
|
|
@@ -805,6 +1049,14 @@ declare abstract class BaseDialect {
|
|
|
805
1049
|
protected abstract placeholder(index: number): string;
|
|
806
1050
|
/** Render a case-insensitive LIKE for the active dialect. */
|
|
807
1051
|
protected abstract ilike(column: string, param: string): string;
|
|
1052
|
+
/**
|
|
1053
|
+
* Validate a subquery operand before it is rendered, for dialects that restrict
|
|
1054
|
+
* what an `IN (SELECT ...)` may contain. The default accepts everything.
|
|
1055
|
+
*
|
|
1056
|
+
* @param _node The subquery's AST.
|
|
1057
|
+
* @throws Error When the dialect cannot execute this subquery.
|
|
1058
|
+
*/
|
|
1059
|
+
protected checkSubquery(_node: SelectNode): void;
|
|
808
1060
|
/**
|
|
809
1061
|
* The SQL operator for an array containment/overlap test.
|
|
810
1062
|
*
|
|
@@ -871,6 +1123,19 @@ declare abstract class BaseDialect {
|
|
|
871
1123
|
* @returns The SQL text, leading space included.
|
|
872
1124
|
*/
|
|
873
1125
|
protected renderLock(lock: LockClause): string;
|
|
1126
|
+
/**
|
|
1127
|
+
* Compile a SELECT.
|
|
1128
|
+
*
|
|
1129
|
+
* Two alias rules differ between clauses and are handled here: PostgreSQL does
|
|
1130
|
+
* NOT accept a `SELECT` alias in `HAVING`, so an aggregate key is re-emitted as
|
|
1131
|
+
* its expression (`COUNT(*) > $1`), a form every dialect accepts; `ORDER BY`,
|
|
1132
|
+
* by contrast, accepts the output alias everywhere, so it is emitted as
|
|
1133
|
+
* written.
|
|
1134
|
+
*
|
|
1135
|
+
* @param node The select AST.
|
|
1136
|
+
* @param params The parameter collector.
|
|
1137
|
+
* @returns The SQL text.
|
|
1138
|
+
*/
|
|
874
1139
|
private compileSelect;
|
|
875
1140
|
/**
|
|
876
1141
|
* Compile an INSERT.
|
|
@@ -926,7 +1191,50 @@ declare abstract class BaseDialect {
|
|
|
926
1191
|
* so select/update/delete/join all share this one compiler.
|
|
927
1192
|
*/
|
|
928
1193
|
private compileCondition;
|
|
1194
|
+
/**
|
|
1195
|
+
* Render one side of a comparison.
|
|
1196
|
+
*
|
|
1197
|
+
* A column reference goes through `idFor`, so an explicit `.name()` mapping and
|
|
1198
|
+
* join qualification apply here exactly as they do in the object form of
|
|
1199
|
+
* `where` — `col()` is not a way around them. Only a `value` node binds.
|
|
1200
|
+
*
|
|
1201
|
+
* @param node The expression AST.
|
|
1202
|
+
* @param params The parameter collector.
|
|
1203
|
+
* @param idFor The identifier resolver for the enclosing statement.
|
|
1204
|
+
* @returns The SQL text of the expression.
|
|
1205
|
+
*/
|
|
1206
|
+
private renderExpr;
|
|
1207
|
+
/**
|
|
1208
|
+
* Compile a comparison whose right-hand side is another expression rather than
|
|
1209
|
+
* a bound value (`total > paid`, `lower(a) = lower(b)`).
|
|
1210
|
+
*
|
|
1211
|
+
* The list and null operators are excluded: `IN`, `BETWEEN` and `IS NULL` take
|
|
1212
|
+
* a value operand, and accepting an expression there would silently compile to
|
|
1213
|
+
* something else.
|
|
1214
|
+
*
|
|
1215
|
+
* @param left The rendered left-hand side.
|
|
1216
|
+
* @param op The operator name.
|
|
1217
|
+
* @param right The rendered right-hand side.
|
|
1218
|
+
* @returns The SQL text of the predicate.
|
|
1219
|
+
* @throws Error When the operator needs a value operand.
|
|
1220
|
+
*/
|
|
1221
|
+
private compileExprOperator;
|
|
929
1222
|
private compileOperator;
|
|
1223
|
+
/**
|
|
1224
|
+
* Compile `IN` / `NOT IN`, whose operand is either a value list or a
|
|
1225
|
+
* single-column subquery.
|
|
1226
|
+
*
|
|
1227
|
+
* The subquery is rendered at the position it appears in the outer statement
|
|
1228
|
+
* and shares the same parameter collector, so its own placeholders land in the
|
|
1229
|
+
* right order — and it keeps its own `names` map, since the inner model may use
|
|
1230
|
+
* a different naming convention than the outer one.
|
|
1231
|
+
*
|
|
1232
|
+
* @param id The quoted column identifier being tested.
|
|
1233
|
+
* @param operand A list of values, or a {@link Subquery}.
|
|
1234
|
+
* @param params The parameter collector for the statement being compiled.
|
|
1235
|
+
* @param negate True for `NOT IN`.
|
|
1236
|
+
* @returns The SQL text of the predicate.
|
|
1237
|
+
*/
|
|
930
1238
|
private compileIn;
|
|
931
1239
|
}
|
|
932
1240
|
/** SQLite dialect: `?` placeholders; `ILIKE` falls back to `LIKE` (ASCII-insensitive). */
|
|
@@ -958,7 +1266,23 @@ declare class MysqlDialect extends BaseDialect {
|
|
|
958
1266
|
protected placeholder(): string;
|
|
959
1267
|
protected ilike(column: string, param: string): string;
|
|
960
1268
|
protected quoteId(name: string): string;
|
|
1269
|
+
/**
|
|
1270
|
+
* MySQL rejects `LIMIT` inside an `IN` subquery with
|
|
1271
|
+
* `ER_NOT_SUPPORTED_YET: This version of MySQL doesn't yet support
|
|
1272
|
+
* 'LIMIT & IN/ALL/ANY/SOME subquery'`. Failing at compile time names the fix
|
|
1273
|
+
* instead of surfacing that error from the driver at runtime.
|
|
1274
|
+
*/
|
|
1275
|
+
protected checkSubquery(node: SelectNode): void;
|
|
961
1276
|
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextValue: () => string, names: NameMap | undefined): string;
|
|
1277
|
+
/**
|
|
1278
|
+
* MySQL has no `RETURNING`, so it cannot be compiled into a statement.
|
|
1279
|
+
*
|
|
1280
|
+
* `session.execute()` still honors `.returning()` on a **single-row INSERT** by
|
|
1281
|
+
* running the insert and reading the row back by key on the same connection —
|
|
1282
|
+
* that is execution, not compilation, so it never reaches here. Compiling a
|
|
1283
|
+
* node with `returning` directly is an error, rather than SQL that silently
|
|
1284
|
+
* returns nothing.
|
|
1285
|
+
*/
|
|
962
1286
|
protected compileReturning(returning: readonly string[] | "*" | null): string;
|
|
963
1287
|
}
|
|
964
1288
|
/** Get a dialect instance by name. */
|
|
@@ -1008,15 +1332,21 @@ declare class NodeSqliteDriver implements SyncDriver {
|
|
|
1008
1332
|
*/
|
|
1009
1333
|
private readonly statements;
|
|
1010
1334
|
constructor(database: any);
|
|
1011
|
-
/**
|
|
1012
|
-
|
|
1335
|
+
/**
|
|
1336
|
+
* Open a `node:sqlite` database at the given path (or `:memory:`).
|
|
1337
|
+
*
|
|
1338
|
+
* @param path The database file, or `":memory:"`.
|
|
1339
|
+
* @param options Passed straight to `DatabaseSync` (`readOnly`, `timeout`, …).
|
|
1340
|
+
* @returns A driver over the open handle.
|
|
1341
|
+
*/
|
|
1342
|
+
static open(path: string, options?: Readonly<Record<string, unknown>>): NodeSqliteDriver;
|
|
1013
1343
|
/** Return the cached prepared statement for `sql`, preparing it on first use. */
|
|
1014
1344
|
private prepare;
|
|
1015
1345
|
execute(sql: string, params: readonly unknown[]): DriverResult;
|
|
1016
1346
|
iterate(sql: string, params: readonly unknown[]): IterableIterator<Record<string, unknown>>;
|
|
1017
1347
|
close(): void;
|
|
1018
1348
|
}
|
|
1019
|
-
type AnySelect = SelectBuilder<any, any>;
|
|
1349
|
+
type AnySelect = SelectBuilder<any, any, any>;
|
|
1020
1350
|
type AnyInsert = InsertBuilder<any, any, any>;
|
|
1021
1351
|
type GuardedUpdate = UpdateBuilder<any, true, any>;
|
|
1022
1352
|
type GuardedDelete = DeleteBuilder<any, true, any>;
|
|
@@ -1194,6 +1524,23 @@ declare class AsyncSession {
|
|
|
1194
1524
|
readonly as?: ModelClass;
|
|
1195
1525
|
}): AsyncResult<Row>;
|
|
1196
1526
|
execute<B extends Executable>(builder: B): AsyncResult<RowOf<B>>;
|
|
1527
|
+
/**
|
|
1528
|
+
* Honor `.returning()` on a dialect without `RETURNING`, by inserting and then
|
|
1529
|
+
* reading the row back by key.
|
|
1530
|
+
*
|
|
1531
|
+
* Both statements must run on **one** connection, because `LAST_INSERT_ID()` is
|
|
1532
|
+
* per-connection: outside a transaction the pooled driver is reserved for the
|
|
1533
|
+
* pair; inside one, the session already holds a pinned connection (a reserved
|
|
1534
|
+
* driver exposes no `reserve`), so it runs there directly.
|
|
1535
|
+
*
|
|
1536
|
+
* @param builder The insert builder, for its source model.
|
|
1537
|
+
* @param node The insert AST, whose `returning` drives the read-back.
|
|
1538
|
+
* @returns The result view over the read-back row.
|
|
1539
|
+
* @throws Error When the insert writes more than one row — `LAST_INSERT_ID()`
|
|
1540
|
+
* identifies only the first, and the rest are consecutive only under some
|
|
1541
|
+
* auto-increment lock modes.
|
|
1542
|
+
*/
|
|
1543
|
+
private insertAndReadBack;
|
|
1197
1544
|
/** Lazily iterate result rows. Uses driver streaming when available. */
|
|
1198
1545
|
stream<B extends Executable>(builder: B): AsyncIterableIterator<RowOf<B>>;
|
|
1199
1546
|
transaction<T>(fn: (tx: AsyncSession) => Promise<T>): Promise<T>;
|
|
@@ -1210,6 +1557,12 @@ interface PoolOptions {
|
|
|
1210
1557
|
/** Give up acquiring a connection after this long (ms). */
|
|
1211
1558
|
readonly connectTimeoutMs?: number;
|
|
1212
1559
|
}
|
|
1560
|
+
/**
|
|
1561
|
+
* A server-side notice (a PostgreSQL `NOTICE`). The shape is the driver's own —
|
|
1562
|
+
* passed through untouched rather than normalized, since what is useful in it
|
|
1563
|
+
* differs per database.
|
|
1564
|
+
*/
|
|
1565
|
+
type NoticeLogger = (notice: Record<string, unknown>) => void;
|
|
1213
1566
|
/** Options shared by both engine flavors. */
|
|
1214
1567
|
interface EngineOptions {
|
|
1215
1568
|
/** Override the driver detected from the URL (e.g. `"better-sqlite3"`). */
|
|
@@ -1221,6 +1574,34 @@ interface EngineOptions {
|
|
|
1221
1574
|
* query logging/tracing. Thrown errors are swallowed so it never breaks a query.
|
|
1222
1575
|
*/
|
|
1223
1576
|
readonly onQuery?: QueryLogger;
|
|
1577
|
+
/**
|
|
1578
|
+
* Called for every server-side notice (`CREATE TABLE IF NOT EXISTS` on an
|
|
1579
|
+
* existing table, `DROP ... IF EXISTS` on a missing one, and so on).
|
|
1580
|
+
*
|
|
1581
|
+
* **Without this, notices are silenced.** postgres.js defaults to printing them
|
|
1582
|
+
* with `console.log`, which drops a nine-line object into the host service's
|
|
1583
|
+
* stdout in the middle of its structured log — on every boot, since a migration
|
|
1584
|
+
* runner is usually the first thing to run. Writing to the host's stdout is the
|
|
1585
|
+
* application's decision, not a library's, so the default is to say nothing and
|
|
1586
|
+
* let you route them:
|
|
1587
|
+
*
|
|
1588
|
+
* ```ts
|
|
1589
|
+
* createEngine(url, { onNotice: (n) => logger.debug({ pg: n }, "postgres notice") });
|
|
1590
|
+
* ```
|
|
1591
|
+
*
|
|
1592
|
+
* Thrown errors are swallowed, like `onQuery`.
|
|
1593
|
+
*/
|
|
1594
|
+
readonly onNotice?: NoticeLogger;
|
|
1595
|
+
/**
|
|
1596
|
+
* Options passed straight to the underlying driver, applied **last** so they
|
|
1597
|
+
* win over everything this layer derives (`pool`, `onNotice`).
|
|
1598
|
+
*
|
|
1599
|
+
* The escape hatch for what the typed surface does not model and is not going
|
|
1600
|
+
* to — postgres.js `connection`/`types`/`transform`/`ssl`, mysql2's own
|
|
1601
|
+
* settings, `node:sqlite`'s `readOnly` — so a gap need not become a feature
|
|
1602
|
+
* request.
|
|
1603
|
+
*/
|
|
1604
|
+
readonly driverOptions?: Readonly<Record<string, unknown>>;
|
|
1224
1605
|
}
|
|
1225
1606
|
/** A synchronous engine (SQLite only). */
|
|
1226
1607
|
declare class SyncEngine {
|
|
@@ -1246,6 +1627,18 @@ declare class AsyncEngine {
|
|
|
1246
1627
|
/** `await using engine = createEngine(...)` closes the pool when the scope exits. */
|
|
1247
1628
|
[Symbol.asyncDispose](): Promise<void>;
|
|
1248
1629
|
}
|
|
1630
|
+
/**
|
|
1631
|
+
* Adapt a sync **or** async driver to the async interface.
|
|
1632
|
+
*
|
|
1633
|
+
* `await` normalizes both: a sync driver returns a plain value, an async one a
|
|
1634
|
+
* promise, and awaiting either yields the result. That is what lets the migration
|
|
1635
|
+
* CLI take one code path instead of branching on a difference it cannot detect
|
|
1636
|
+
* from the object's shape.
|
|
1637
|
+
*
|
|
1638
|
+
* @param driver Either driver flavor.
|
|
1639
|
+
* @returns An async driver delegating to it.
|
|
1640
|
+
*/
|
|
1641
|
+
declare function toAsyncDriver(driver: SyncDriver | AsyncDriver): AsyncDriver;
|
|
1249
1642
|
/**
|
|
1250
1643
|
* Create a **synchronous** engine from a database URL. SQLite only — PostgreSQL
|
|
1251
1644
|
* has no sane synchronous driver in Node, so a Postgres URL throws, pointing at
|
|
@@ -1966,9 +2359,22 @@ type ColValue<Col> = Col extends Column<infer T, infer F> ? F extends {
|
|
|
1966
2359
|
type HasDefault<Col> = Col extends Column<unknown, infer F> ? F extends {
|
|
1967
2360
|
hasDefault: true;
|
|
1968
2361
|
} ? true : false : false;
|
|
1969
|
-
/**
|
|
2362
|
+
/** True when a column accepts NULL — neither `notNull` nor a primary key. */
|
|
2363
|
+
type IsNullable<Col> = Col extends Column<unknown, infer F> ? F extends {
|
|
2364
|
+
notNull: true;
|
|
2365
|
+
} | {
|
|
2366
|
+
primaryKey: true;
|
|
2367
|
+
} ? false : true : false;
|
|
2368
|
+
/**
|
|
2369
|
+
* Keys of the model whose columns may be omitted on insert.
|
|
2370
|
+
*
|
|
2371
|
+
* A column is optional when it has a default **or** when it accepts NULL: SQL
|
|
2372
|
+
* applies `NULL` to an omitted column that declares no other default, so
|
|
2373
|
+
* requiring the caller to write `note: null` adds noise that reads like a
|
|
2374
|
+
* deliberate decision to blank the column. Passing `null` explicitly still works.
|
|
2375
|
+
*/
|
|
1970
2376
|
type OptionalInsertKeys<I> = {
|
|
1971
|
-
[K in ColumnKeys<I>]: HasDefault<I[K]> extends true ? K : never;
|
|
2377
|
+
[K in ColumnKeys<I>]: HasDefault<I[K]> extends true ? K : IsNullable<I[K]> extends true ? K : never;
|
|
1972
2378
|
}[ColumnKeys<I>];
|
|
1973
2379
|
/**
|
|
1974
2380
|
* Infer the SELECT row shape from a model class: every column field becomes its
|
|
@@ -1979,7 +2385,9 @@ type InferModel<C extends ModelClass> = {
|
|
|
1979
2385
|
[K in ColumnKeys<InstanceType<C>>]: ColValue<InstanceType<C>[K]>;
|
|
1980
2386
|
};
|
|
1981
2387
|
/**
|
|
1982
|
-
* Infer the INSERT shape:
|
|
2388
|
+
* Infer the INSERT shape: a column is optional when it has a default (or is a PK)
|
|
2389
|
+
* **or** when it is nullable — matching SQL, where an omitted column with no
|
|
2390
|
+
* `DEFAULT` clause is written as `NULL`. Only `notNull` columns without a default
|
|
1983
2391
|
* are required. Nullability is preserved on both sides.
|
|
1984
2392
|
*/
|
|
1985
2393
|
type InferInsert<C extends ModelClass> = Simplify<{
|
|
@@ -1988,4 +2396,4 @@ type InferInsert<C extends ModelClass> = Simplify<{
|
|
|
1988
2396
|
[K in Exclude<ColumnKeys<InstanceType<C>>, OptionalInsertKeys<InstanceType<C>>>]: ColValue<InstanceType<C>[K]>;
|
|
1989
2397
|
}>;
|
|
1990
2398
|
|
|
1991
|
-
export { ActiveRecord, type ActiveRecordManager, Agg, type AggregateTerm, type AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, type BelongsTo, type ColRef, type ColType, Column, type ColumnFlags, type ColumnType, type ColumnTypeKind, type ColumnTypeMeta, type CompiledQuery, type CondNode, type Condition, type DefaultValue, DeleteBuilder, type DeleteNode, type Dialect, type DriverResult, type EngineOptions, type Executable, type FkAction, type ForeignKeyOptions, type ForeignKeyRef, type HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, type LockClause, type LockOptions, Model, type ModelClass, MysqlDialect, type NameMap, type NamingStrategy, NoResultError, NodeSqliteDriver, OPERATORS, type OnConflict, type OnConflictOptions, type OnConflictUpdateOptions, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, Params, type ParsedDatabaseUrl, type PoolOptions, type PortableExpression, PostgresDialect, QueryExecutionError, type QueryLogger, type QueryNode, RecordNotFound, type Relation, type RelationValue, type ReservedAsyncDriver, type Returning, type RowOf, SelectBuilder, type SelectNode, type SortDirection, type Sources, type SqlExpression, SqliteDialect, type SyncDriver, SyncEngine, SyncResult, SyncSession, type TableConstraint, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, type WritePatch, type WriteValues, activeRecord, and, avg, belongsTo, column, columnNamesOf, columnPropsOf, columnsOf, count, createEngine, createSyncEngine, dbColumn, del, detectDialect, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, isSqlExpression, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, toSnakeCase, unique, update };
|
|
2399
|
+
export { ActiveRecord, type ActiveRecordManager, Agg, type AggregateTerm, type AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, type BelongsTo, type ColRef, type ColType, Column, type ColumnFlags, type ColumnType, type ColumnTypeKind, type ColumnTypeMeta, type CompiledQuery, type CondNode, type Condition, type DefaultValue, DeleteBuilder, type DeleteNode, type Dialect, type DriverResult, type EngineOptions, type Executable, type ExprNode, Expression, type FkAction, type ForeignKeyOptions, type ForeignKeyRef, type HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, type LockClause, type LockOptions, Model, type ModelClass, MysqlDialect, type NameMap, type NamingStrategy, NoResultError, NodeSqliteDriver, type NoticeLogger, OPERATORS, type OnConflict, type OnConflictOptions, type OnConflictUpdateOptions, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, Params, type ParsedDatabaseUrl, type PoolOptions, type PortableExpression, PostgresDialect, QueryExecutionError, type QueryLogger, type QueryNode, RecordNotFound, type Relation, type RelationValue, type ReservedAsyncDriver, type Returning, type RowOf, SelectBuilder, type SelectNode, type SortDirection, type Sources, type SqlExpression, SqliteDialect, type Subquery, type SyncDriver, SyncEngine, SyncResult, SyncSession, type TableConstraint, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, type WritePatch, type WriteValues, activeRecord, and, avg, belongsTo, col, column, columnNamesOf, columnPropsOf, columnsOf, count, createEngine, createSyncEngine, dbColumn, del, detectDialect, fn, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, isExpression, isSqlExpression, isSubquery, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toAsyncDriver, toCondNode, toDict, toJSON, toSnakeCase, unique, update, val };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ActiveRecord, Agg, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, Column, DeleteBuilder, InsertBuilder, InvalidDatabaseUrl, JoinBuilder, Model, MysqlDialect, NoResultError, NodeSqliteDriver, OPERATORS, Params, PostgresDialect, QueryExecutionError, RecordNotFound, SelectBuilder, SqliteDialect, SyncEngine, SyncResult, SyncSession, UpdateBuilder, ValidationError, activeRecord, and, avg, belongsTo, column, columnNamesOf, columnPropsOf, columnsOf, count, createEngine, createSyncEngine, dbColumn, del, detectDialect, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, isSqlExpression, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, toSnakeCase, unique, update } from './chunk-
|
|
1
|
+
export { ActiveRecord, Agg, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, Column, DeleteBuilder, Expression, InsertBuilder, InvalidDatabaseUrl, JoinBuilder, Model, MysqlDialect, NoResultError, NodeSqliteDriver, OPERATORS, Params, PostgresDialect, QueryExecutionError, RecordNotFound, SelectBuilder, SqliteDialect, SyncEngine, SyncResult, SyncSession, UpdateBuilder, ValidationError, activeRecord, and, avg, belongsTo, col, column, columnNamesOf, columnPropsOf, columnsOf, count, createEngine, createSyncEngine, dbColumn, del, detectDialect, fn, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, isExpression, isSqlExpression, isSubquery, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toAsyncDriver, toCondNode, toDict, toJSON, toSnakeCase, unique, update, val } from './chunk-4AWUP7BM.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|