tempest-db-js 0.5.0 → 0.6.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 +7 -3
- 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-G7O5DCCC.js} +478 -44
- package/dist/chunk-G7O5DCCC.js.map +1 -0
- package/dist/{chunk-EPMLFNFK.js → chunk-KOW3LSWP.js} +109 -59
- package/dist/chunk-KOW3LSWP.js.map +1 -0
- package/dist/index.cjs +482 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +368 -16
- package/dist/index.d.ts +368 -16
- 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.cts
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`. */
|
|
@@ -805,6 +1048,14 @@ declare abstract class BaseDialect {
|
|
|
805
1048
|
protected abstract placeholder(index: number): string;
|
|
806
1049
|
/** Render a case-insensitive LIKE for the active dialect. */
|
|
807
1050
|
protected abstract ilike(column: string, param: string): string;
|
|
1051
|
+
/**
|
|
1052
|
+
* Validate a subquery operand before it is rendered, for dialects that restrict
|
|
1053
|
+
* what an `IN (SELECT ...)` may contain. The default accepts everything.
|
|
1054
|
+
*
|
|
1055
|
+
* @param _node The subquery's AST.
|
|
1056
|
+
* @throws Error When the dialect cannot execute this subquery.
|
|
1057
|
+
*/
|
|
1058
|
+
protected checkSubquery(_node: SelectNode): void;
|
|
808
1059
|
/**
|
|
809
1060
|
* The SQL operator for an array containment/overlap test.
|
|
810
1061
|
*
|
|
@@ -871,6 +1122,19 @@ declare abstract class BaseDialect {
|
|
|
871
1122
|
* @returns The SQL text, leading space included.
|
|
872
1123
|
*/
|
|
873
1124
|
protected renderLock(lock: LockClause): string;
|
|
1125
|
+
/**
|
|
1126
|
+
* Compile a SELECT.
|
|
1127
|
+
*
|
|
1128
|
+
* Two alias rules differ between clauses and are handled here: PostgreSQL does
|
|
1129
|
+
* NOT accept a `SELECT` alias in `HAVING`, so an aggregate key is re-emitted as
|
|
1130
|
+
* its expression (`COUNT(*) > $1`), a form every dialect accepts; `ORDER BY`,
|
|
1131
|
+
* by contrast, accepts the output alias everywhere, so it is emitted as
|
|
1132
|
+
* written.
|
|
1133
|
+
*
|
|
1134
|
+
* @param node The select AST.
|
|
1135
|
+
* @param params The parameter collector.
|
|
1136
|
+
* @returns The SQL text.
|
|
1137
|
+
*/
|
|
874
1138
|
private compileSelect;
|
|
875
1139
|
/**
|
|
876
1140
|
* Compile an INSERT.
|
|
@@ -926,7 +1190,50 @@ declare abstract class BaseDialect {
|
|
|
926
1190
|
* so select/update/delete/join all share this one compiler.
|
|
927
1191
|
*/
|
|
928
1192
|
private compileCondition;
|
|
1193
|
+
/**
|
|
1194
|
+
* Render one side of a comparison.
|
|
1195
|
+
*
|
|
1196
|
+
* A column reference goes through `idFor`, so an explicit `.name()` mapping and
|
|
1197
|
+
* join qualification apply here exactly as they do in the object form of
|
|
1198
|
+
* `where` — `col()` is not a way around them. Only a `value` node binds.
|
|
1199
|
+
*
|
|
1200
|
+
* @param node The expression AST.
|
|
1201
|
+
* @param params The parameter collector.
|
|
1202
|
+
* @param idFor The identifier resolver for the enclosing statement.
|
|
1203
|
+
* @returns The SQL text of the expression.
|
|
1204
|
+
*/
|
|
1205
|
+
private renderExpr;
|
|
1206
|
+
/**
|
|
1207
|
+
* Compile a comparison whose right-hand side is another expression rather than
|
|
1208
|
+
* a bound value (`total > paid`, `lower(a) = lower(b)`).
|
|
1209
|
+
*
|
|
1210
|
+
* The list and null operators are excluded: `IN`, `BETWEEN` and `IS NULL` take
|
|
1211
|
+
* a value operand, and accepting an expression there would silently compile to
|
|
1212
|
+
* something else.
|
|
1213
|
+
*
|
|
1214
|
+
* @param left The rendered left-hand side.
|
|
1215
|
+
* @param op The operator name.
|
|
1216
|
+
* @param right The rendered right-hand side.
|
|
1217
|
+
* @returns The SQL text of the predicate.
|
|
1218
|
+
* @throws Error When the operator needs a value operand.
|
|
1219
|
+
*/
|
|
1220
|
+
private compileExprOperator;
|
|
929
1221
|
private compileOperator;
|
|
1222
|
+
/**
|
|
1223
|
+
* Compile `IN` / `NOT IN`, whose operand is either a value list or a
|
|
1224
|
+
* single-column subquery.
|
|
1225
|
+
*
|
|
1226
|
+
* The subquery is rendered at the position it appears in the outer statement
|
|
1227
|
+
* and shares the same parameter collector, so its own placeholders land in the
|
|
1228
|
+
* right order — and it keeps its own `names` map, since the inner model may use
|
|
1229
|
+
* a different naming convention than the outer one.
|
|
1230
|
+
*
|
|
1231
|
+
* @param id The quoted column identifier being tested.
|
|
1232
|
+
* @param operand A list of values, or a {@link Subquery}.
|
|
1233
|
+
* @param params The parameter collector for the statement being compiled.
|
|
1234
|
+
* @param negate True for `NOT IN`.
|
|
1235
|
+
* @returns The SQL text of the predicate.
|
|
1236
|
+
*/
|
|
930
1237
|
private compileIn;
|
|
931
1238
|
}
|
|
932
1239
|
/** SQLite dialect: `?` placeholders; `ILIKE` falls back to `LIKE` (ASCII-insensitive). */
|
|
@@ -958,7 +1265,23 @@ declare class MysqlDialect extends BaseDialect {
|
|
|
958
1265
|
protected placeholder(): string;
|
|
959
1266
|
protected ilike(column: string, param: string): string;
|
|
960
1267
|
protected quoteId(name: string): string;
|
|
1268
|
+
/**
|
|
1269
|
+
* MySQL rejects `LIMIT` inside an `IN` subquery with
|
|
1270
|
+
* `ER_NOT_SUPPORTED_YET: This version of MySQL doesn't yet support
|
|
1271
|
+
* 'LIMIT & IN/ALL/ANY/SOME subquery'`. Failing at compile time names the fix
|
|
1272
|
+
* instead of surfacing that error from the driver at runtime.
|
|
1273
|
+
*/
|
|
1274
|
+
protected checkSubquery(node: SelectNode): void;
|
|
961
1275
|
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextValue: () => string, names: NameMap | undefined): string;
|
|
1276
|
+
/**
|
|
1277
|
+
* MySQL has no `RETURNING`, so it cannot be compiled into a statement.
|
|
1278
|
+
*
|
|
1279
|
+
* `session.execute()` still honors `.returning()` on a **single-row INSERT** by
|
|
1280
|
+
* running the insert and reading the row back by key on the same connection —
|
|
1281
|
+
* that is execution, not compilation, so it never reaches here. Compiling a
|
|
1282
|
+
* node with `returning` directly is an error, rather than SQL that silently
|
|
1283
|
+
* returns nothing.
|
|
1284
|
+
*/
|
|
962
1285
|
protected compileReturning(returning: readonly string[] | "*" | null): string;
|
|
963
1286
|
}
|
|
964
1287
|
/** Get a dialect instance by name. */
|
|
@@ -1016,7 +1339,7 @@ declare class NodeSqliteDriver implements SyncDriver {
|
|
|
1016
1339
|
iterate(sql: string, params: readonly unknown[]): IterableIterator<Record<string, unknown>>;
|
|
1017
1340
|
close(): void;
|
|
1018
1341
|
}
|
|
1019
|
-
type AnySelect = SelectBuilder<any, any>;
|
|
1342
|
+
type AnySelect = SelectBuilder<any, any, any>;
|
|
1020
1343
|
type AnyInsert = InsertBuilder<any, any, any>;
|
|
1021
1344
|
type GuardedUpdate = UpdateBuilder<any, true, any>;
|
|
1022
1345
|
type GuardedDelete = DeleteBuilder<any, true, any>;
|
|
@@ -1194,6 +1517,23 @@ declare class AsyncSession {
|
|
|
1194
1517
|
readonly as?: ModelClass;
|
|
1195
1518
|
}): AsyncResult<Row>;
|
|
1196
1519
|
execute<B extends Executable>(builder: B): AsyncResult<RowOf<B>>;
|
|
1520
|
+
/**
|
|
1521
|
+
* Honor `.returning()` on a dialect without `RETURNING`, by inserting and then
|
|
1522
|
+
* reading the row back by key.
|
|
1523
|
+
*
|
|
1524
|
+
* Both statements must run on **one** connection, because `LAST_INSERT_ID()` is
|
|
1525
|
+
* per-connection: outside a transaction the pooled driver is reserved for the
|
|
1526
|
+
* pair; inside one, the session already holds a pinned connection (a reserved
|
|
1527
|
+
* driver exposes no `reserve`), so it runs there directly.
|
|
1528
|
+
*
|
|
1529
|
+
* @param builder The insert builder, for its source model.
|
|
1530
|
+
* @param node The insert AST, whose `returning` drives the read-back.
|
|
1531
|
+
* @returns The result view over the read-back row.
|
|
1532
|
+
* @throws Error When the insert writes more than one row — `LAST_INSERT_ID()`
|
|
1533
|
+
* identifies only the first, and the rest are consecutive only under some
|
|
1534
|
+
* auto-increment lock modes.
|
|
1535
|
+
*/
|
|
1536
|
+
private insertAndReadBack;
|
|
1197
1537
|
/** Lazily iterate result rows. Uses driver streaming when available. */
|
|
1198
1538
|
stream<B extends Executable>(builder: B): AsyncIterableIterator<RowOf<B>>;
|
|
1199
1539
|
transaction<T>(fn: (tx: AsyncSession) => Promise<T>): Promise<T>;
|
|
@@ -1246,6 +1586,18 @@ declare class AsyncEngine {
|
|
|
1246
1586
|
/** `await using engine = createEngine(...)` closes the pool when the scope exits. */
|
|
1247
1587
|
[Symbol.asyncDispose](): Promise<void>;
|
|
1248
1588
|
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Adapt a sync **or** async driver to the async interface.
|
|
1591
|
+
*
|
|
1592
|
+
* `await` normalizes both: a sync driver returns a plain value, an async one a
|
|
1593
|
+
* promise, and awaiting either yields the result. That is what lets the migration
|
|
1594
|
+
* CLI take one code path instead of branching on a difference it cannot detect
|
|
1595
|
+
* from the object's shape.
|
|
1596
|
+
*
|
|
1597
|
+
* @param driver Either driver flavor.
|
|
1598
|
+
* @returns An async driver delegating to it.
|
|
1599
|
+
*/
|
|
1600
|
+
declare function toAsyncDriver(driver: SyncDriver | AsyncDriver): AsyncDriver;
|
|
1249
1601
|
/**
|
|
1250
1602
|
* Create a **synchronous** engine from a database URL. SQLite only — PostgreSQL
|
|
1251
1603
|
* has no sane synchronous driver in Node, so a Postgres URL throws, pointing at
|
|
@@ -1988,4 +2340,4 @@ type InferInsert<C extends ModelClass> = Simplify<{
|
|
|
1988
2340
|
[K in Exclude<ColumnKeys<InstanceType<C>>, OptionalInsertKeys<InstanceType<C>>>]: ColValue<InstanceType<C>[K]>;
|
|
1989
2341
|
}>;
|
|
1990
2342
|
|
|
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 };
|
|
2343
|
+
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, 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 };
|