tempest-db-js 0.3.0 → 0.5.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 +9 -2
- package/dist/bin.cjs +475 -44
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +2 -2
- package/dist/{chunk-Q32CBI2A.js → chunk-5QQMVTS5.js} +988 -286
- package/dist/chunk-5QQMVTS5.js.map +1 -0
- package/dist/{chunk-OP7FRDI5.js → chunk-EPMLFNFK.js} +448 -37
- package/dist/chunk-EPMLFNFK.js.map +1 -0
- package/dist/index.cjs +993 -283
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +632 -30
- package/dist/index.d.ts +632 -30
- package/dist/index.js +1 -1
- package/dist/migrations/index.cjs +591 -52
- package/dist/migrations/index.cjs.map +1 -1
- package/dist/migrations/index.d.cts +63 -14
- package/dist/migrations/index.d.ts +63 -14
- package/dist/migrations/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-OP7FRDI5.js.map +0 -1
- package/dist/chunk-Q32CBI2A.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,28 @@ interface AggregateTerm {
|
|
|
26
26
|
/** The result alias. */
|
|
27
27
|
readonly alias: string;
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* A row-level locking clause (`SELECT ... FOR UPDATE`).
|
|
31
|
+
*
|
|
32
|
+
* `wait` decides what happens when another transaction already holds the lock:
|
|
33
|
+
* `"block"` waits, `"skipLocked"` skips those rows (the job-queue claim), and
|
|
34
|
+
* `"noWait"` fails immediately.
|
|
35
|
+
*/
|
|
36
|
+
interface LockClause {
|
|
37
|
+
readonly strength: "update" | "share";
|
|
38
|
+
readonly wait: "block" | "skipLocked" | "noWait";
|
|
39
|
+
/** Tables to lock (`FOR UPDATE OF t`); empty locks every table in the query. */
|
|
40
|
+
readonly of: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
/** Options accepted by {@link SelectBuilder.forUpdate} / {@link SelectBuilder.forShare}. */
|
|
43
|
+
interface LockOptions {
|
|
44
|
+
/** Skip rows another transaction has locked instead of waiting for them. */
|
|
45
|
+
readonly skipLocked?: boolean;
|
|
46
|
+
/** Fail immediately instead of waiting for a locked row. */
|
|
47
|
+
readonly noWait?: boolean;
|
|
48
|
+
/** Restrict the lock to these tables (`FOR UPDATE OF ...`). */
|
|
49
|
+
readonly of?: readonly string[];
|
|
50
|
+
}
|
|
29
51
|
/** Serializable AST for a SELECT. Dialects (Phase 4) compile this to SQL. */
|
|
30
52
|
interface SelectNode {
|
|
31
53
|
readonly kind: "select";
|
|
@@ -42,6 +64,10 @@ interface SelectNode {
|
|
|
42
64
|
readonly orderBy: readonly OrderTerm[];
|
|
43
65
|
readonly limit: number | undefined;
|
|
44
66
|
readonly offset: number | undefined;
|
|
67
|
+
/** Row-level locking clause, or `undefined` for none. */
|
|
68
|
+
readonly lock?: LockClause | undefined;
|
|
69
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
70
|
+
readonly names?: NameMap | undefined;
|
|
45
71
|
}
|
|
46
72
|
/** Operators valid on every column type. */
|
|
47
73
|
interface BaseOperators<T> {
|
|
@@ -71,19 +97,41 @@ interface OrderedOperators<T> extends BaseOperators<T> {
|
|
|
71
97
|
}
|
|
72
98
|
/** Extra operators for string-like types. */
|
|
73
99
|
interface StringOperators<T> extends BaseOperators<T> {
|
|
74
|
-
/** `LIKE` pattern (case-sensitive). */
|
|
100
|
+
/** `LIKE` pattern (case-sensitive). `%` and `_` are wildcards. */
|
|
75
101
|
like?: string;
|
|
76
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* `ILIKE` **pattern** (case-insensitive). This is pattern matching, not
|
|
104
|
+
* equality: `%` and `_` in the operand are wildcards, so `{ ilike: "%" }`
|
|
105
|
+
* matches every row. Never feed it unescaped user input — for a
|
|
106
|
+
* case-insensitive *equality* test use {@link StringOperators.ieq}, and to
|
|
107
|
+
* match a literal that may contain wildcards, wrap it in `escapeLike`.
|
|
108
|
+
*/
|
|
77
109
|
ilike?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Case-insensitive equality — compiles to `lower(col) = lower($1)`, with no
|
|
112
|
+
* wildcards. The safe operator for a case-insensitive lookup (login, email),
|
|
113
|
+
* and the one that matches a `lower(col)` functional index.
|
|
114
|
+
*/
|
|
115
|
+
ieq?: T;
|
|
116
|
+
}
|
|
117
|
+
/** Extra operators for array columns (PostgreSQL). */
|
|
118
|
+
interface ArrayOperators<T> extends BaseOperators<T> {
|
|
119
|
+
/** `@>` — the column contains every element of the operand. */
|
|
120
|
+
contains?: T;
|
|
121
|
+
/** `<@` — every element of the column is in the operand. */
|
|
122
|
+
containedBy?: T;
|
|
123
|
+
/** `&&` — the column and the operand share at least one element. */
|
|
124
|
+
overlaps?: T;
|
|
78
125
|
}
|
|
79
126
|
/**
|
|
80
127
|
* The operator object allowed for a column of (non-null) type `T`:
|
|
81
|
-
* - `
|
|
128
|
+
* - `T[]` → equality, `in`, `contains`/`containedBy`/`overlaps` (PostgreSQL)
|
|
129
|
+
* - `string` → equality, `in`, `like`/`ilike`/`ieq`
|
|
82
130
|
* - `number` / `bigint` / `Date` → equality, `in`, ordered comparisons, `between`
|
|
83
131
|
* - `boolean` → equality, `isNull`
|
|
84
132
|
* - anything else (json/blob) → equality and `in` only
|
|
85
133
|
*/
|
|
86
|
-
type OperatorsFor<T> = [T] extends [string] ? StringOperators<T> : [T] extends [number] ? OrderedOperators<T> : [T] extends [bigint] ? OrderedOperators<T> : [T] extends [Date] ? OrderedOperators<T> : [T] extends [boolean] ? BaseOperators<T> : BaseOperators<T>;
|
|
134
|
+
type OperatorsFor<T> = [T] extends [readonly unknown[]] ? ArrayOperators<T> : [T] extends [string] ? StringOperators<T> : [T] extends [number] ? OrderedOperators<T> : [T] extends [bigint] ? OrderedOperators<T> : [T] extends [Date] ? OrderedOperators<T> : [T] extends [boolean] ? BaseOperators<T> : BaseOperators<T>;
|
|
87
135
|
/**
|
|
88
136
|
* `where` shape: each key must be a real column; each value accepts either a
|
|
89
137
|
* bare value (shorthand for `eq`) or an operator object restricted to operators
|
|
@@ -94,7 +142,7 @@ type WhereInput<Row = Record<string, unknown>> = {
|
|
|
94
142
|
[K in keyof Row]?: Row[K] | OperatorsFor<NonNullable<Row[K]>>;
|
|
95
143
|
};
|
|
96
144
|
/** The full set of operator keys, for the dialect compiler to recognize. */
|
|
97
|
-
declare const OPERATORS: readonly ["eq", "ne", "gt", "gte", "lt", "lte", "like", "ilike", "in", "notIn", "between", "isNull"];
|
|
145
|
+
declare const OPERATORS: readonly ["eq", "ne", "gt", "gte", "lt", "lte", "like", "ilike", "ieq", "in", "notIn", "between", "isNull", "contains", "containedBy", "overlaps"];
|
|
98
146
|
/** One supported operator name. */
|
|
99
147
|
type Operator = (typeof OPERATORS)[number];
|
|
100
148
|
/** An aggregate expression carrying its result type `T` as a phantom. */
|
|
@@ -165,6 +213,44 @@ declare class SelectBuilder<Full, Proj = Full> {
|
|
|
165
213
|
limit(n: number): SelectBuilder<Full, Proj>;
|
|
166
214
|
/** Skip the first `n` rows. */
|
|
167
215
|
offset(n: number): SelectBuilder<Full, Proj>;
|
|
216
|
+
/**
|
|
217
|
+
* Lock the selected rows for update (`SELECT ... FOR UPDATE`), à la
|
|
218
|
+
* SQLAlchemy's `with_for_update()`.
|
|
219
|
+
*
|
|
220
|
+
* `{ skipLocked: true }` is the job-queue claim: competing workers each take a
|
|
221
|
+
* disjoint batch instead of blocking on — or worse, double-processing — the
|
|
222
|
+
* same rows.
|
|
223
|
+
*
|
|
224
|
+
* PostgreSQL and MySQL 8.0+ only. SQLite has no row-level locking, and its
|
|
225
|
+
* dialect throws rather than emitting a `SELECT` that silently locks nothing —
|
|
226
|
+
* a lock that does not exist only fails under production concurrency.
|
|
227
|
+
*
|
|
228
|
+
* @param options `skipLocked` / `noWait` wait behavior, and `of` to restrict
|
|
229
|
+
* the lock to specific tables.
|
|
230
|
+
* @returns A builder carrying the locking clause.
|
|
231
|
+
* @throws Error When both `skipLocked` and `noWait` are set.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* const batch = await session.execute(
|
|
236
|
+
* select(Outbound)
|
|
237
|
+
* .where({ status: "queued" })
|
|
238
|
+
* .orderBy("nextAttemptAt")
|
|
239
|
+
* .limit(10)
|
|
240
|
+
* .forUpdate({ skipLocked: true }),
|
|
241
|
+
* ).all();
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
forUpdate(options?: LockOptions): SelectBuilder<Full, Proj>;
|
|
245
|
+
/**
|
|
246
|
+
* Take a shared read lock on the selected rows (`SELECT ... FOR SHARE`), the
|
|
247
|
+
* weaker counterpart of {@link SelectBuilder.forUpdate}.
|
|
248
|
+
*
|
|
249
|
+
* @param options `skipLocked` / `noWait` wait behavior, and `of` tables.
|
|
250
|
+
* @returns A builder carrying the locking clause.
|
|
251
|
+
* @throws Error When both `skipLocked` and `noWait` are set.
|
|
252
|
+
*/
|
|
253
|
+
forShare(options?: LockOptions): SelectBuilder<Full, Proj>;
|
|
168
254
|
}
|
|
169
255
|
/** Build a SELECT over every column of the model. */
|
|
170
256
|
declare function select<C extends ModelClass>(model: C): SelectBuilder<InferModel<C>, InferModel<C>>;
|
|
@@ -235,6 +321,19 @@ declare function not<Row = Record<string, unknown>>(input: WhereArg<NoInfer<Row>
|
|
|
235
321
|
|
|
236
322
|
/** Columns to return from a mutation, or "*" for the whole row. */
|
|
237
323
|
type Returning = readonly string[] | "*" | null;
|
|
324
|
+
/**
|
|
325
|
+
* A write shape over `Row`: every column accepts its own value **or** a
|
|
326
|
+
* {@link SqlExpression}, which the dialect renders inline instead of binding.
|
|
327
|
+
* Optionality is preserved from `Row`, so an insert shape keeps its defaults
|
|
328
|
+
* optional.
|
|
329
|
+
*/
|
|
330
|
+
type WriteValues<Row> = {
|
|
331
|
+
[K in keyof Row]: Row[K] | SqlExpression;
|
|
332
|
+
};
|
|
333
|
+
/** A partial write shape — the `SET` clause of an UPDATE or a `DO UPDATE`. */
|
|
334
|
+
type WritePatch<Row> = {
|
|
335
|
+
[K in keyof Row]?: Row[K] | SqlExpression;
|
|
336
|
+
};
|
|
238
337
|
/**
|
|
239
338
|
* Conflict-resolution clause for an INSERT (`ON CONFLICT`). `target` is the
|
|
240
339
|
* conflicting column(s) (a unique/PK constraint); `update` is `"nothing"` for
|
|
@@ -243,6 +342,28 @@ type Returning = readonly string[] | "*" | null;
|
|
|
243
342
|
interface OnConflict {
|
|
244
343
|
readonly target: readonly string[];
|
|
245
344
|
readonly update: Record<string, unknown> | "nothing";
|
|
345
|
+
/**
|
|
346
|
+
* The predicate of a **partial** unique index. PostgreSQL only matches a
|
|
347
|
+
* partial index as a conflict target when `ON CONFLICT` repeats its predicate,
|
|
348
|
+
* so without this an insert against `... WHERE key IS NOT NULL` is rejected
|
|
349
|
+
* with "there is no unique or exclusion constraint matching the ON CONFLICT
|
|
350
|
+
* specification".
|
|
351
|
+
*/
|
|
352
|
+
readonly targetWhere?: CondNode | undefined;
|
|
353
|
+
/** Extra condition restricting which conflicting rows `DO UPDATE` rewrites. */
|
|
354
|
+
readonly updateWhere?: CondNode | undefined;
|
|
355
|
+
}
|
|
356
|
+
/** Options for the `ON CONFLICT` clause of {@link InsertBuilder.onConflictDoNothing}. */
|
|
357
|
+
interface OnConflictOptions<Full> {
|
|
358
|
+
/** The predicate of the partial unique index used as the conflict target. */
|
|
359
|
+
readonly where?: WhereInput<Full> | Condition;
|
|
360
|
+
}
|
|
361
|
+
/** Options for {@link InsertBuilder.onConflictDoUpdate}. */
|
|
362
|
+
interface OnConflictUpdateOptions<Full> {
|
|
363
|
+
/** The predicate of the partial unique index used as the conflict target. */
|
|
364
|
+
readonly indexWhere?: WhereInput<Full> | Condition;
|
|
365
|
+
/** Extra condition deciding which conflicting rows are actually rewritten. */
|
|
366
|
+
readonly updateWhere?: WhereInput<Full> | Condition;
|
|
246
367
|
}
|
|
247
368
|
/** Serializable AST for an INSERT. */
|
|
248
369
|
interface InsertNode {
|
|
@@ -252,6 +373,8 @@ interface InsertNode {
|
|
|
252
373
|
readonly returning: Returning;
|
|
253
374
|
/** Conflict handling (`ON CONFLICT ...`), or `undefined` for none. */
|
|
254
375
|
readonly onConflict?: OnConflict;
|
|
376
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
377
|
+
readonly names?: NameMap | undefined;
|
|
255
378
|
}
|
|
256
379
|
/**
|
|
257
380
|
* INSERT builder.
|
|
@@ -269,21 +392,46 @@ declare class InsertBuilder<Full, Ins, Ret = number> {
|
|
|
269
392
|
/** The source model, used to coerce returned rows on execution. */
|
|
270
393
|
source: ModelClass);
|
|
271
394
|
private with;
|
|
272
|
-
/**
|
|
273
|
-
|
|
395
|
+
/**
|
|
396
|
+
* Provide one row or many rows to insert, typed by the insert shape.
|
|
397
|
+
*
|
|
398
|
+
* @param rows One row, or an array of rows.
|
|
399
|
+
* @returns A builder carrying the rows.
|
|
400
|
+
* @throws ValidationError When a value is not a column value the dialect can
|
|
401
|
+
* bind (see the `sql` helpers for writing an expression instead).
|
|
402
|
+
*/
|
|
403
|
+
values(rows: WriteValues<Ins> | readonly WriteValues<Ins>[]): InsertBuilder<Full, Ins, Ret>;
|
|
274
404
|
/**
|
|
275
405
|
* On a unique/PK conflict on `target`, do nothing (skip the row).
|
|
276
406
|
*
|
|
277
407
|
* @param target The conflicting column(s) — a unique or primary key.
|
|
408
|
+
* @param options Pass `where` to name the predicate of a **partial** unique
|
|
409
|
+
* index, which PostgreSQL requires in order to match it as a conflict target.
|
|
410
|
+
* @returns A builder carrying the conflict clause.
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* ```ts
|
|
414
|
+
* insert(Outbound)
|
|
415
|
+
* .values(data)
|
|
416
|
+
* .onConflictDoNothing(["consumer", "idempotencyKey"], {
|
|
417
|
+
* where: { idempotencyKey: { isNull: false } },
|
|
418
|
+
* })
|
|
419
|
+
* .returning();
|
|
420
|
+
* ```
|
|
278
421
|
*/
|
|
279
|
-
onConflictDoNothing(target: readonly (keyof Full & string)[]): InsertBuilder<Full, Ins, Ret>;
|
|
422
|
+
onConflictDoNothing(target: readonly (keyof Full & string)[], options?: OnConflictOptions<Full>): InsertBuilder<Full, Ins, Ret>;
|
|
280
423
|
/**
|
|
281
424
|
* On a unique/PK conflict on `target`, overwrite the given columns (upsert).
|
|
282
425
|
*
|
|
283
426
|
* @param target The conflicting column(s) — a unique or primary key.
|
|
284
427
|
* @param set The columns to update with new values.
|
|
428
|
+
* @param options `indexWhere` names the predicate of a partial unique index
|
|
429
|
+
* (the conflict target); `updateWhere` further restricts which conflicting
|
|
430
|
+
* rows are rewritten.
|
|
431
|
+
* @returns A builder carrying the conflict clause.
|
|
432
|
+
* @throws ValidationError When a `set` value cannot be bound.
|
|
285
433
|
*/
|
|
286
|
-
onConflictDoUpdate(target: readonly (keyof Full & string)[], set:
|
|
434
|
+
onConflictDoUpdate(target: readonly (keyof Full & string)[], set: WritePatch<Full>, options?: OnConflictUpdateOptions<Full>): InsertBuilder<Full, Ins, Ret>;
|
|
287
435
|
/** Return the full inserted row(s). */
|
|
288
436
|
returning(): InsertBuilder<Full, Ins, Full>;
|
|
289
437
|
/** Return only the given columns of the inserted row(s). */
|
|
@@ -300,6 +448,8 @@ interface UpdateNode {
|
|
|
300
448
|
/** True once a where-clause or explicit opt-in makes the write safe. */
|
|
301
449
|
readonly guarded: boolean;
|
|
302
450
|
readonly returning: Returning;
|
|
451
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
452
|
+
readonly names?: NameMap | undefined;
|
|
303
453
|
}
|
|
304
454
|
/**
|
|
305
455
|
* UPDATE builder.
|
|
@@ -318,8 +468,26 @@ declare class UpdateBuilder<Full, Guarded extends boolean, Ret = number> {
|
|
|
318
468
|
/** The source model, used to coerce returned rows on execution. */
|
|
319
469
|
source: ModelClass);
|
|
320
470
|
private with;
|
|
321
|
-
/**
|
|
322
|
-
|
|
471
|
+
/**
|
|
472
|
+
* The columns to write. Partial — only the given columns change.
|
|
473
|
+
*
|
|
474
|
+
* A value is bound as a parameter unless it is a {@link sql} expression, which
|
|
475
|
+
* is rendered inline instead — that is how a counter is written without a
|
|
476
|
+
* read-modify-write race.
|
|
477
|
+
*
|
|
478
|
+
* @param values The column → value map.
|
|
479
|
+
* @returns A builder carrying the assignments.
|
|
480
|
+
* @throws ValidationError When a value is not a column value the dialect can
|
|
481
|
+
* bind (a bare object, an array on a scalar column, a function).
|
|
482
|
+
*
|
|
483
|
+
* @example
|
|
484
|
+
* ```ts
|
|
485
|
+
* update(Outbound)
|
|
486
|
+
* .set({ attempts: sql.raw("attempts + 1"), updatedAt: sql.now() })
|
|
487
|
+
* .where({ id });
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
set(values: WritePatch<Full>): UpdateBuilder<Full, Guarded, Ret>;
|
|
323
491
|
/** Restrict the rows to update. Marks the builder safe to execute. */
|
|
324
492
|
where(input: WhereInput<Full> | Condition): UpdateBuilder<Full, true, Ret>;
|
|
325
493
|
/** Explicit opt-in to update EVERY row. Use deliberately. */
|
|
@@ -338,6 +506,8 @@ interface DeleteNode {
|
|
|
338
506
|
readonly where: CondNode | undefined;
|
|
339
507
|
readonly guarded: boolean;
|
|
340
508
|
readonly returning: Returning;
|
|
509
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
510
|
+
readonly names?: NameMap | undefined;
|
|
341
511
|
}
|
|
342
512
|
/**
|
|
343
513
|
* DELETE builder. Starts unguarded — same safety rule as UPDATE.
|
|
@@ -532,6 +702,8 @@ interface JoinNode {
|
|
|
532
702
|
}[];
|
|
533
703
|
readonly limit: number | undefined;
|
|
534
704
|
readonly offset: number | undefined;
|
|
705
|
+
/** Per-alias property → column maps, for the sources that rename columns. */
|
|
706
|
+
readonly names?: Readonly<Record<string, NameMap>> | undefined;
|
|
535
707
|
}
|
|
536
708
|
/** A map of source alias → its (possibly nullable) row type. */
|
|
537
709
|
type Sources = Record<string, object | null>;
|
|
@@ -605,6 +777,16 @@ interface CompiledQuery {
|
|
|
605
777
|
}
|
|
606
778
|
/** Any compilable AST node. */
|
|
607
779
|
type QueryNode = SelectNode | InsertNode | UpdateNode | DeleteNode | JoinNode;
|
|
780
|
+
/**
|
|
781
|
+
* Collects bound parameters and renders placeholders in dialect style. Exposed
|
|
782
|
+
* because dialect subclasses receive it when overriding clause rendering.
|
|
783
|
+
*/
|
|
784
|
+
declare class Params {
|
|
785
|
+
private readonly placeholder;
|
|
786
|
+
readonly values: unknown[];
|
|
787
|
+
constructor(placeholder: (index: number) => string);
|
|
788
|
+
bind(value: unknown): string;
|
|
789
|
+
}
|
|
608
790
|
/**
|
|
609
791
|
* Base SQL compiler shared by every dialect. Subclasses customize only what
|
|
610
792
|
* actually differs between databases (placeholder syntax, `ILIKE` support).
|
|
@@ -623,6 +805,17 @@ declare abstract class BaseDialect {
|
|
|
623
805
|
protected abstract placeholder(index: number): string;
|
|
624
806
|
/** Render a case-insensitive LIKE for the active dialect. */
|
|
625
807
|
protected abstract ilike(column: string, param: string): string;
|
|
808
|
+
/**
|
|
809
|
+
* The SQL operator for an array containment/overlap test.
|
|
810
|
+
*
|
|
811
|
+
* Only PostgreSQL has native arrays; the other dialects throw rather than
|
|
812
|
+
* emitting an operator that means something else there.
|
|
813
|
+
*
|
|
814
|
+
* @param op The array operator name.
|
|
815
|
+
* @returns The SQL operator text.
|
|
816
|
+
* @throws Error On a dialect without native array support.
|
|
817
|
+
*/
|
|
818
|
+
protected arrayOperator(op: "contains" | "containedBy" | "overlaps"): string;
|
|
626
819
|
/**
|
|
627
820
|
* Quote an identifier (column/table) for the active dialect.
|
|
628
821
|
*
|
|
@@ -634,10 +827,70 @@ declare abstract class BaseDialect {
|
|
|
634
827
|
protected quoteId(name: string): string;
|
|
635
828
|
/** Compile any node to `{ sql, params }`. */
|
|
636
829
|
compile(node: QueryNode): CompiledQuery;
|
|
637
|
-
/**
|
|
830
|
+
/**
|
|
831
|
+
* Render a qualified `alias.column` ref as `"alias"."column"`, translating the
|
|
832
|
+
* property name to the real column name for that alias's model.
|
|
833
|
+
*
|
|
834
|
+
* @param ref The `alias.property` reference (a bare name is left unqualified).
|
|
835
|
+
* @param names The node's per-alias name maps, if any source renames columns.
|
|
836
|
+
* @returns The quoted, qualified identifier.
|
|
837
|
+
*/
|
|
638
838
|
private qualify;
|
|
839
|
+
/**
|
|
840
|
+
* Quote a column identifier, translating the model property name to the real
|
|
841
|
+
* database column name first.
|
|
842
|
+
*
|
|
843
|
+
* `names` is `undefined` for a model that renames nothing — the overwhelmingly
|
|
844
|
+
* common case — so this stays a single lookup plus the memoized quote.
|
|
845
|
+
*
|
|
846
|
+
* @param prop The model property name as written in the builder.
|
|
847
|
+
* @param names The node's property → column map, if any.
|
|
848
|
+
* @returns The quoted database identifier.
|
|
849
|
+
*/
|
|
850
|
+
protected columnId(prop: string, names: NameMap | undefined): string;
|
|
851
|
+
/**
|
|
852
|
+
* Render a {@link SqlExpression} inline, binding the parameters it carries.
|
|
853
|
+
*
|
|
854
|
+
* This is what keeps `set({ attempts: sql.raw("attempts + 1") })` an expression
|
|
855
|
+
* instead of a bound object: the fragment goes into the statement text, and
|
|
856
|
+
* only a `sql.expr` template's interpolations become parameters.
|
|
857
|
+
*
|
|
858
|
+
* @param expr The branded expression.
|
|
859
|
+
* @param params The parameter collector for the statement being compiled.
|
|
860
|
+
* @returns The SQL text of the expression.
|
|
861
|
+
*/
|
|
862
|
+
protected renderExpression(expr: SqlExpression, params: Params): string;
|
|
863
|
+
/** Render one write value: a SQL expression inline, anything else as a parameter. */
|
|
864
|
+
protected renderValue(value: unknown, params: Params): string;
|
|
865
|
+
/**
|
|
866
|
+
* Render a row-level locking clause (`FOR UPDATE ...`).
|
|
867
|
+
*
|
|
868
|
+
* Standard on PostgreSQL and MySQL 8.0+; SQLite overrides it to throw.
|
|
869
|
+
*
|
|
870
|
+
* @param lock The locking clause from the node.
|
|
871
|
+
* @returns The SQL text, leading space included.
|
|
872
|
+
*/
|
|
873
|
+
protected renderLock(lock: LockClause): string;
|
|
639
874
|
private compileSelect;
|
|
875
|
+
/**
|
|
876
|
+
* Compile an INSERT.
|
|
877
|
+
*
|
|
878
|
+
* Takes the cached fast path only when the statement text is a pure function of
|
|
879
|
+
* its structure. A SQL expression among the values, or a conflict predicate,
|
|
880
|
+
* makes the text depend on the values themselves — those compile uncached, in
|
|
881
|
+
* SQL order, so placeholder positions stay correct.
|
|
882
|
+
*/
|
|
640
883
|
private compileInsert;
|
|
884
|
+
/**
|
|
885
|
+
* Compile an INSERT without the template cache, rendering clauses in statement
|
|
886
|
+
* order so every parameter is bound at the position it appears.
|
|
887
|
+
*
|
|
888
|
+
* @param node The insert node.
|
|
889
|
+
* @param columns The column keys shared by every row.
|
|
890
|
+
* @param params The parameter collector.
|
|
891
|
+
* @returns The SQL text.
|
|
892
|
+
*/
|
|
893
|
+
private compileInsertDirect;
|
|
641
894
|
/**
|
|
642
895
|
* The INSERT SQL template for a given structure, cached across calls.
|
|
643
896
|
*
|
|
@@ -649,17 +902,24 @@ declare abstract class BaseDialect {
|
|
|
649
902
|
private insertTemplate;
|
|
650
903
|
/**
|
|
651
904
|
* Render the conflict-handling clause. Standard SQL (SQLite/PostgreSQL) uses
|
|
652
|
-
* `ON CONFLICT (...) DO NOTHING | DO UPDATE SET
|
|
905
|
+
* `ON CONFLICT (...) [WHERE predicate] DO NOTHING | DO UPDATE SET ... [WHERE ...]`;
|
|
906
|
+
* MySQL overrides this.
|
|
907
|
+
*
|
|
908
|
+
* The index predicate is rendered before the `DO UPDATE` assignments because
|
|
909
|
+
* that is where it sits in the statement, so its parameters bind first.
|
|
653
910
|
*
|
|
654
911
|
* @param onConflict The conflict clause from the node.
|
|
655
912
|
* @param conflictCols The columns to overwrite on `DO UPDATE` (empty for nothing).
|
|
656
|
-
* @param
|
|
913
|
+
* @param nextValue Yields the SQL for the next `DO UPDATE` assignment value.
|
|
914
|
+
* @param names The node's property → column map, if any.
|
|
915
|
+
* @param params The parameter collector, for the predicates.
|
|
916
|
+
* @returns The SQL text, leading space included.
|
|
657
917
|
*/
|
|
658
|
-
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[],
|
|
918
|
+
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextValue: () => string, names: NameMap | undefined, params: Params): string;
|
|
659
919
|
private compileUpdate;
|
|
660
920
|
private compileDelete;
|
|
661
921
|
private compileJoin;
|
|
662
|
-
protected compileReturning(returning: readonly string[] | "*" | null): string;
|
|
922
|
+
protected compileReturning(returning: readonly string[] | "*" | null, names?: NameMap | undefined): string;
|
|
663
923
|
/**
|
|
664
924
|
* Compile a condition tree (fields / and / or / not) to SQL. `idFor` renders a
|
|
665
925
|
* key to a quoted identifier — `quoteId` for single-table, `qualify` for joins —
|
|
@@ -674,12 +934,19 @@ declare class SqliteDialect extends BaseDialect {
|
|
|
674
934
|
readonly name: "sqlite";
|
|
675
935
|
protected placeholder(): string;
|
|
676
936
|
protected ilike(column: string, param: string): string;
|
|
937
|
+
/**
|
|
938
|
+
* SQLite has no row-level locking, so a lock request is an error rather than a
|
|
939
|
+
* silently unlocked `SELECT` — a lock that does not exist only shows up as
|
|
940
|
+
* duplicated work under production concurrency.
|
|
941
|
+
*/
|
|
942
|
+
protected renderLock(): string;
|
|
677
943
|
}
|
|
678
|
-
/** PostgreSQL dialect: `$1` placeholders; native `ILIKE
|
|
944
|
+
/** PostgreSQL dialect: `$1` placeholders; native `ILIKE`; native array operators. */
|
|
679
945
|
declare class PostgresDialect extends BaseDialect {
|
|
680
946
|
readonly name: "postgresql";
|
|
681
947
|
protected placeholder(index: number): string;
|
|
682
948
|
protected ilike(column: string, param: string): string;
|
|
949
|
+
protected arrayOperator(op: "contains" | "containedBy" | "overlaps"): string;
|
|
683
950
|
}
|
|
684
951
|
/**
|
|
685
952
|
* MySQL dialect: `?` placeholders, backtick identifiers, `ON DUPLICATE KEY
|
|
@@ -691,7 +958,7 @@ declare class MysqlDialect extends BaseDialect {
|
|
|
691
958
|
protected placeholder(): string;
|
|
692
959
|
protected ilike(column: string, param: string): string;
|
|
693
960
|
protected quoteId(name: string): string;
|
|
694
|
-
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[],
|
|
961
|
+
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextValue: () => string, names: NameMap | undefined): string;
|
|
695
962
|
protected compileReturning(returning: readonly string[] | "*" | null): string;
|
|
696
963
|
}
|
|
697
964
|
/** Get a dialect instance by name. */
|
|
@@ -832,6 +1099,40 @@ declare class SyncSession {
|
|
|
832
1099
|
logger?: QueryLogger | undefined);
|
|
833
1100
|
/** Log, run, and error-wrap one raw statement. */
|
|
834
1101
|
private exec;
|
|
1102
|
+
/**
|
|
1103
|
+
* Run a raw, parameterized SQL statement (synchronous) — the runtime counterpart of the
|
|
1104
|
+
* migrations' `Op.execute`.
|
|
1105
|
+
*
|
|
1106
|
+
* A query builder never covers all of SQL, and without an escape hatch a single
|
|
1107
|
+
* unsupported query forces a whole second database stack alongside this one. Use
|
|
1108
|
+
* it for what the builder cannot yet express, and keep everything else typed.
|
|
1109
|
+
*
|
|
1110
|
+
* The statement goes through the same path as a compiled one: it is logged via
|
|
1111
|
+
* `onQuery`, wrapped in {@link QueryExecutionError} on failure, and runs on the
|
|
1112
|
+
* reserved connection inside `transaction()`.
|
|
1113
|
+
*
|
|
1114
|
+
* @param sql The statement text. Placeholders only (`$1` / `?` per dialect) —
|
|
1115
|
+
* never interpolate a value into this string.
|
|
1116
|
+
* @param params The bound parameters, in placeholder order.
|
|
1117
|
+
* @param options Pass `as` to coerce the returned rows with a model's column
|
|
1118
|
+
* types (and its column-name mapping).
|
|
1119
|
+
* @returns The result view over the returned rows.
|
|
1120
|
+
* @throws Error When `params` is not an array — the guard against calling this
|
|
1121
|
+
* with an interpolated string and no parameters by mistake.
|
|
1122
|
+
*
|
|
1123
|
+
* @example
|
|
1124
|
+
* ```ts
|
|
1125
|
+
* const claimed = await session.raw<OutboundRow>(
|
|
1126
|
+
* `UPDATE outbound_messages SET status = 'sending'
|
|
1127
|
+
* WHERE id = ANY($1) RETURNING *`,
|
|
1128
|
+
* [ids],
|
|
1129
|
+
* { as: Outbound },
|
|
1130
|
+
* ).all();
|
|
1131
|
+
* ```
|
|
1132
|
+
*/
|
|
1133
|
+
raw<Row = Record<string, unknown>>(sql: string, params?: readonly unknown[], options?: {
|
|
1134
|
+
readonly as?: ModelClass;
|
|
1135
|
+
}): SyncResult<Row>;
|
|
835
1136
|
/** Compile, run, and coerce a builder into a result. */
|
|
836
1137
|
execute<B extends Executable>(builder: B): SyncResult<RowOf<B>>;
|
|
837
1138
|
/** Run `fn` inside a transaction: commit on success, rollback on throw. */
|
|
@@ -858,6 +1159,40 @@ declare class AsyncSession {
|
|
|
858
1159
|
logger?: QueryLogger | undefined);
|
|
859
1160
|
/** Log, run, and error-wrap one raw statement. */
|
|
860
1161
|
private exec;
|
|
1162
|
+
/**
|
|
1163
|
+
* Run a raw, parameterized SQL statement — the runtime counterpart of the
|
|
1164
|
+
* migrations' `Op.execute`.
|
|
1165
|
+
*
|
|
1166
|
+
* A query builder never covers all of SQL, and without an escape hatch a single
|
|
1167
|
+
* unsupported query forces a whole second database stack alongside this one. Use
|
|
1168
|
+
* it for what the builder cannot yet express, and keep everything else typed.
|
|
1169
|
+
*
|
|
1170
|
+
* The statement goes through the same path as a compiled one: it is logged via
|
|
1171
|
+
* `onQuery`, wrapped in {@link QueryExecutionError} on failure, and runs on the
|
|
1172
|
+
* reserved connection inside `transaction()`.
|
|
1173
|
+
*
|
|
1174
|
+
* @param sql The statement text. Placeholders only (`$1` / `?` per dialect) —
|
|
1175
|
+
* never interpolate a value into this string.
|
|
1176
|
+
* @param params The bound parameters, in placeholder order.
|
|
1177
|
+
* @param options Pass `as` to coerce the returned rows with a model's column
|
|
1178
|
+
* types (and its column-name mapping).
|
|
1179
|
+
* @returns The result view over the returned rows.
|
|
1180
|
+
* @throws Error When `params` is not an array — the guard against calling this
|
|
1181
|
+
* with an interpolated string and no parameters by mistake.
|
|
1182
|
+
*
|
|
1183
|
+
* @example
|
|
1184
|
+
* ```ts
|
|
1185
|
+
* const claimed = await session.raw<OutboundRow>(
|
|
1186
|
+
* `UPDATE outbound_messages SET status = 'sending'
|
|
1187
|
+
* WHERE id = ANY($1) RETURNING *`,
|
|
1188
|
+
* [ids],
|
|
1189
|
+
* { as: Outbound },
|
|
1190
|
+
* ).all();
|
|
1191
|
+
* ```
|
|
1192
|
+
*/
|
|
1193
|
+
raw<Row = Record<string, unknown>>(sql: string, params?: readonly unknown[], options?: {
|
|
1194
|
+
readonly as?: ModelClass;
|
|
1195
|
+
}): AsyncResult<Row>;
|
|
861
1196
|
execute<B extends Executable>(builder: B): AsyncResult<RowOf<B>>;
|
|
862
1197
|
/** Lazily iterate result rows. Uses driver streaming when available. */
|
|
863
1198
|
stream<B extends Executable>(builder: B): AsyncIterableIterator<RowOf<B>>;
|
|
@@ -1157,13 +1492,18 @@ interface ColumnFlags {
|
|
|
1157
1492
|
readonly primaryKey: boolean;
|
|
1158
1493
|
readonly notNull: boolean;
|
|
1159
1494
|
readonly hasDefault: boolean;
|
|
1495
|
+
/**
|
|
1496
|
+
* A `UNIQUE` constraint on the column. Does NOT influence the inferred type —
|
|
1497
|
+
* it is DDL-only metadata (mirrors SQLAlchemy's `mapped_column(unique=True)`).
|
|
1498
|
+
*/
|
|
1499
|
+
readonly unique: boolean;
|
|
1160
1500
|
}
|
|
1161
1501
|
/**
|
|
1162
1502
|
* The canonical, dialect-neutral kind of a column type. Mirrors SQLAlchemy's
|
|
1163
1503
|
* generic types (e.g. `String` → varchar, `Text` → text). Dialect renderers
|
|
1164
1504
|
* (Phase 4/6) map each kind + meta to concrete SQL per database.
|
|
1165
1505
|
*/
|
|
1166
|
-
type ColumnTypeKind = "smallint" | "integer" | "bigint" | "numeric" | "real" | "double" | "varchar" | "text" | "char" | "boolean" | "date" | "time" | "datetime" | "timestamp" | "blob" | "json" | "uuid" | "enum";
|
|
1506
|
+
type ColumnTypeKind = "smallint" | "integer" | "bigint" | "numeric" | "real" | "double" | "varchar" | "text" | "char" | "boolean" | "date" | "time" | "datetime" | "timestamp" | "blob" | "json" | "uuid" | "enum" | "array";
|
|
1167
1507
|
/** Parameters that refine a column type and feed the migration IR / DDL. */
|
|
1168
1508
|
interface ColumnTypeMeta {
|
|
1169
1509
|
/** Max length for `varchar`/`char`. */
|
|
@@ -1178,6 +1518,8 @@ interface ColumnTypeMeta {
|
|
|
1178
1518
|
readonly values?: readonly string[] | undefined;
|
|
1179
1519
|
/** Render as `JSONB` (PostgreSQL) instead of `JSON`. */
|
|
1180
1520
|
readonly jsonb?: boolean | undefined;
|
|
1521
|
+
/** The element type of an `array` column (`text[]`, `integer[]`). */
|
|
1522
|
+
readonly element?: ColumnType | undefined;
|
|
1181
1523
|
}
|
|
1182
1524
|
/** A structured, dialect-neutral column type descriptor. */
|
|
1183
1525
|
interface ColumnType {
|
|
@@ -1188,10 +1530,14 @@ interface ColumnType {
|
|
|
1188
1530
|
* A portable default expression. The token is dialect-neutral; the renderer
|
|
1189
1531
|
* (Phase 4/6) maps it to the right SQL per database — e.g. `"now"` becomes
|
|
1190
1532
|
* `CURRENT_TIMESTAMP` on SQLite and `now()` on PostgreSQL. Use `{ raw }` as an
|
|
1191
|
-
* escape hatch for a verbatim SQL fragment
|
|
1533
|
+
* escape hatch for a verbatim SQL fragment, or `{ parts }` for a parameterized
|
|
1534
|
+
* fragment built by the `sql.expr` tagged template (one bound parameter per gap
|
|
1535
|
+
* between consecutive parts).
|
|
1192
1536
|
*/
|
|
1193
1537
|
type PortableExpression = "now" | "current_date" | "current_time" | "uuidv4" | {
|
|
1194
1538
|
readonly raw: string;
|
|
1539
|
+
} | {
|
|
1540
|
+
readonly parts: readonly string[];
|
|
1195
1541
|
};
|
|
1196
1542
|
/**
|
|
1197
1543
|
* A column default. Either a constant literal value or a server-side expression
|
|
@@ -1205,22 +1551,105 @@ type DefaultValue = {
|
|
|
1205
1551
|
readonly kind: "expression";
|
|
1206
1552
|
readonly expression: PortableExpression;
|
|
1207
1553
|
};
|
|
1208
|
-
/**
|
|
1554
|
+
/**
|
|
1555
|
+
* Brand marking a value as a SQL expression rather than a bound parameter.
|
|
1556
|
+
*
|
|
1557
|
+
* A plain object reaching `set()`/`values()` is a mistake (it would be bound as a
|
|
1558
|
+
* parameter and silently written as JSON or null); an object carrying this symbol
|
|
1559
|
+
* is deliberate, and the dialect renders it inline instead of binding it. Mirrors
|
|
1560
|
+
* how `Condition` is branded, so the check is a symbol lookup, not duck typing.
|
|
1561
|
+
*/
|
|
1562
|
+
declare const EXPRESSION: unique symbol;
|
|
1563
|
+
/**
|
|
1564
|
+
* A SQL expression, usable both as a column default (`.default(sql.now())`) and
|
|
1565
|
+
* as a write value (`.set({ attempts: sql.raw("attempts + 1") })`). The dialect
|
|
1566
|
+
* renders `expression` inline and binds `params` in the order of the fragment's
|
|
1567
|
+
* gaps.
|
|
1568
|
+
*/
|
|
1569
|
+
interface SqlExpression {
|
|
1570
|
+
readonly [EXPRESSION]: true;
|
|
1571
|
+
readonly kind: "expression";
|
|
1572
|
+
readonly expression: PortableExpression;
|
|
1573
|
+
/** Parameters bound into the fragment's gaps, in order (empty for a token). */
|
|
1574
|
+
readonly params: readonly unknown[];
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Runtime guard: is this value a branded {@link SqlExpression}?
|
|
1578
|
+
*
|
|
1579
|
+
* @param value Any value handed to `set()`, `values()` or `.default()`.
|
|
1580
|
+
* @returns True when the value carries the expression brand.
|
|
1581
|
+
*/
|
|
1582
|
+
declare function isSqlExpression(value: unknown): value is SqlExpression;
|
|
1583
|
+
/**
|
|
1584
|
+
* Portable server-side expressions, à la SQLAlchemy's `func`.
|
|
1585
|
+
*
|
|
1586
|
+
* Every entry doubles as a column default and as a write value, so
|
|
1587
|
+
* `.default(sql.now())` and `.set({ updatedAt: sql.now() })` both work.
|
|
1588
|
+
*/
|
|
1209
1589
|
declare const sql: {
|
|
1210
1590
|
/** Current timestamp at insert (`CURRENT_TIMESTAMP` / `now()`). */
|
|
1211
|
-
readonly now: () =>
|
|
1591
|
+
readonly now: () => SqlExpression;
|
|
1212
1592
|
/** Current date. */
|
|
1213
|
-
readonly currentDate: () =>
|
|
1593
|
+
readonly currentDate: () => SqlExpression;
|
|
1214
1594
|
/** Current time. */
|
|
1215
|
-
readonly currentTime: () =>
|
|
1595
|
+
readonly currentTime: () => SqlExpression;
|
|
1216
1596
|
/** A freshly generated UUID v4 (`gen_random_uuid()` / portable fallback). */
|
|
1217
|
-
readonly uuidv4: () =>
|
|
1218
|
-
/**
|
|
1219
|
-
|
|
1597
|
+
readonly uuidv4: () => SqlExpression;
|
|
1598
|
+
/**
|
|
1599
|
+
* Escape hatch: a verbatim SQL expression rendered as-is, with no parameters.
|
|
1600
|
+
*
|
|
1601
|
+
* The fragment is interpolated into the statement untouched, so it must never
|
|
1602
|
+
* carry user input — use {@link sql.expr} when a value has to be bound.
|
|
1603
|
+
*
|
|
1604
|
+
* @param fragment The SQL text (e.g. `"attempts + 1"`).
|
|
1605
|
+
* @returns The expression, usable as a default and as a write value.
|
|
1606
|
+
*/
|
|
1607
|
+
readonly raw: (fragment: string) => SqlExpression;
|
|
1608
|
+
/**
|
|
1609
|
+
* A parameterized SQL expression, written as a tagged template. Static text is
|
|
1610
|
+
* SQL; every `${...}` interpolation becomes a bound parameter, so the fragment
|
|
1611
|
+
* is injection-safe by construction.
|
|
1612
|
+
*
|
|
1613
|
+
* Cannot be used as a column default — a `DEFAULT` clause has nowhere to bind
|
|
1614
|
+
* parameters; use {@link sql.raw} there.
|
|
1615
|
+
*
|
|
1616
|
+
* @param parts The static SQL segments supplied by the template tag.
|
|
1617
|
+
* @param values The interpolated values, bound in order.
|
|
1618
|
+
* @returns The expression, usable as a write value.
|
|
1619
|
+
*
|
|
1620
|
+
* @example
|
|
1621
|
+
* ```ts
|
|
1622
|
+
* update(Account).set({ balance: sql.expr`balance - ${amount}` }).where({ id });
|
|
1623
|
+
* // UPDATE "accounts" SET "balance" = balance - $1 WHERE "id" = $2
|
|
1624
|
+
* ```
|
|
1625
|
+
*/
|
|
1626
|
+
readonly expr: (parts: TemplateStringsArray, ...values: unknown[]) => SqlExpression;
|
|
1220
1627
|
};
|
|
1628
|
+
/**
|
|
1629
|
+
* A referential action for a foreign key's `ON DELETE` / `ON UPDATE` clause.
|
|
1630
|
+
* Dialect-neutral tokens rendered uppercase at the DDL edge (mirrors
|
|
1631
|
+
* SQLAlchemy's `ForeignKey(ondelete=..., onupdate=...)`).
|
|
1632
|
+
*/
|
|
1633
|
+
type FkAction = "cascade" | "restrict" | "set null" | "set default" | "no action";
|
|
1634
|
+
/**
|
|
1635
|
+
* A resolved foreign-key reference: the target `table.column` plus optional
|
|
1636
|
+
* referential actions. Produced by `Column.references("table.column", ...)`.
|
|
1637
|
+
*/
|
|
1638
|
+
interface ForeignKeyRef {
|
|
1639
|
+
readonly table: string;
|
|
1640
|
+
readonly column: string;
|
|
1641
|
+
readonly onDelete?: FkAction | undefined;
|
|
1642
|
+
readonly onUpdate?: FkAction | undefined;
|
|
1643
|
+
}
|
|
1644
|
+
/** Options for a foreign-key reference (referential actions). */
|
|
1645
|
+
interface ForeignKeyOptions {
|
|
1646
|
+
readonly onDelete?: FkAction | undefined;
|
|
1647
|
+
readonly onUpdate?: FkAction | undefined;
|
|
1648
|
+
}
|
|
1221
1649
|
/**
|
|
1222
1650
|
* A typed column builder. Holds runtime metadata (structured `type`, `flags`,
|
|
1223
|
-
* `default`, `onUpdate`) and a phantom static type `T`
|
|
1651
|
+
* `default`, `onUpdate`, foreign-key `reference`) and a phantom static type `T`
|
|
1652
|
+
* used purely for inference.
|
|
1224
1653
|
*/
|
|
1225
1654
|
declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
1226
1655
|
readonly type: ColumnType;
|
|
@@ -1229,13 +1658,23 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1229
1658
|
readonly defaultValue: DefaultValue | null;
|
|
1230
1659
|
/** The value re-applied on update (e.g. `updated_at`), or `null`. */
|
|
1231
1660
|
readonly onUpdateValue: DefaultValue | null;
|
|
1661
|
+
/** The foreign-key reference this column points to, or `null` for none. */
|
|
1662
|
+
readonly reference: ForeignKeyRef | null;
|
|
1663
|
+
/** An explicit database column name overriding the property name, or `null`. */
|
|
1664
|
+
readonly dbName: string | null;
|
|
1232
1665
|
/** Phantom: never read at runtime, only inspected by the type system. */
|
|
1233
1666
|
readonly [TYPE]: T;
|
|
1234
1667
|
constructor(type: ColumnType, flags: F,
|
|
1235
1668
|
/** The default applied on insert, or `null` for none. */
|
|
1236
1669
|
defaultValue?: DefaultValue | null,
|
|
1237
1670
|
/** The value re-applied on update (e.g. `updated_at`), or `null`. */
|
|
1238
|
-
onUpdateValue?: DefaultValue | null
|
|
1671
|
+
onUpdateValue?: DefaultValue | null,
|
|
1672
|
+
/** The foreign-key reference this column points to, or `null` for none. */
|
|
1673
|
+
reference?: ForeignKeyRef | null,
|
|
1674
|
+
/** An explicit database column name overriding the property name, or `null`. */
|
|
1675
|
+
dbName?: string | null);
|
|
1676
|
+
/** Clone this column with one facet replaced, carrying every other over. */
|
|
1677
|
+
private derive;
|
|
1239
1678
|
primaryKey(): Column<T, F & {
|
|
1240
1679
|
primaryKey: true;
|
|
1241
1680
|
hasDefault: true;
|
|
@@ -1243,9 +1682,55 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1243
1682
|
notNull(): Column<T, F & {
|
|
1244
1683
|
notNull: true;
|
|
1245
1684
|
}>;
|
|
1685
|
+
/**
|
|
1686
|
+
* Add a `UNIQUE` constraint to the column (mirrors SQLAlchemy's
|
|
1687
|
+
* `mapped_column(unique=True)`). DDL-only — does not change the inferred type.
|
|
1688
|
+
*/
|
|
1689
|
+
unique(): Column<T, F & {
|
|
1690
|
+
unique: true;
|
|
1691
|
+
}>;
|
|
1692
|
+
/**
|
|
1693
|
+
* Map this property to a differently-named database column, à la SQLAlchemy's
|
|
1694
|
+
* `mapped_column("consumer_name")` (Django's `db_column`, Prisma's `@map`).
|
|
1695
|
+
*
|
|
1696
|
+
* The override applies everywhere the name reaches SQL — select, insert,
|
|
1697
|
+
* update, delete, where, order by, group by, returning, conflict targets, the
|
|
1698
|
+
* migration IR and the drift check — while the TypeScript row keeps the
|
|
1699
|
+
* property name. Use it to keep a `snake_case` schema behind a `camelCase`
|
|
1700
|
+
* model; {@link Model.naming} does the same for a whole table at once.
|
|
1701
|
+
*
|
|
1702
|
+
* @param dbName The real column name in the database.
|
|
1703
|
+
* @returns A new column bound to that name.
|
|
1704
|
+
* @throws Error When `dbName` is empty.
|
|
1705
|
+
*
|
|
1706
|
+
* @example
|
|
1707
|
+
* ```ts
|
|
1708
|
+
* class ApiKey extends Model {
|
|
1709
|
+
* static tablename = "api_keys";
|
|
1710
|
+
* consumerName = column.text().name("consumer_name").notNull();
|
|
1711
|
+
* }
|
|
1712
|
+
* ```
|
|
1713
|
+
*/
|
|
1714
|
+
name(dbName: string): Column<T, F>;
|
|
1715
|
+
/**
|
|
1716
|
+
* Declare a foreign-key reference to another table's column, à la SQLAlchemy's
|
|
1717
|
+
* `mapped_column(ForeignKey("table.column", ondelete=...))`. DDL-only — does
|
|
1718
|
+
* not change the inferred type.
|
|
1719
|
+
*
|
|
1720
|
+
* @param ref The target as `"table.column"` (e.g. `"users.id"`).
|
|
1721
|
+
* @param options Optional `onDelete` / `onUpdate` referential actions.
|
|
1722
|
+
* @returns A new column carrying the reference.
|
|
1723
|
+
* @throws Error When `ref` is not a valid `"table.column"` string.
|
|
1724
|
+
*/
|
|
1725
|
+
references(ref: string, options?: ForeignKeyOptions): Column<T, F>;
|
|
1246
1726
|
/**
|
|
1247
1727
|
* Set the insert-time default: a constant value of type `T`, or a portable
|
|
1248
1728
|
* server-side expression from {@link sql} (e.g. `sql.now()`, `sql.uuidv4()`).
|
|
1729
|
+
*
|
|
1730
|
+
* @param value The literal default, or a {@link sql} expression.
|
|
1731
|
+
* @returns A new column carrying the default.
|
|
1732
|
+
* @throws Error When given a `sql.expr` fragment — a `DEFAULT` clause has
|
|
1733
|
+
* nowhere to bind parameters; use `sql.raw()` for a verbatim expression.
|
|
1249
1734
|
*/
|
|
1250
1735
|
default(value: T | DefaultValue): Column<T, F & {
|
|
1251
1736
|
hasDefault: true;
|
|
@@ -1253,6 +1738,10 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1253
1738
|
/**
|
|
1254
1739
|
* Re-apply a value whenever the row is updated (e.g. an `updated_at` column
|
|
1255
1740
|
* with `sql.now()`). Mirrors SQLAlchemy's `onupdate`.
|
|
1741
|
+
*
|
|
1742
|
+
* @param value The literal value, or a {@link sql} expression.
|
|
1743
|
+
* @returns A new column carrying the on-update value.
|
|
1744
|
+
* @throws Error When given a `sql.expr` fragment (see {@link Column.default}).
|
|
1256
1745
|
*/
|
|
1257
1746
|
onUpdate(value: T | DefaultValue): Column<T, F>;
|
|
1258
1747
|
}
|
|
@@ -1321,10 +1810,95 @@ declare const column: {
|
|
|
1321
1810
|
readonly uuid: () => Column<string, ColumnFlags>;
|
|
1322
1811
|
/** `ENUM(...values)` → a string-literal union of the given values. */
|
|
1323
1812
|
readonly enum: <const E extends string>(...values: E[]) => Column<E, ColumnFlags>;
|
|
1813
|
+
/**
|
|
1814
|
+
* A PostgreSQL array column (`text[]`, `integer[]`) → `T[]`.
|
|
1815
|
+
*
|
|
1816
|
+
* PostgreSQL only: SQLite and MySQL have no native array type, and rendering
|
|
1817
|
+
* one as JSON there would give the same model different semantics per dialect
|
|
1818
|
+
* (`@>` and `&&` work on one and not the other), so the DDL renderer throws
|
|
1819
|
+
* for those dialects instead of falling back silently.
|
|
1820
|
+
*
|
|
1821
|
+
* @param element The element column (its type, not its flags, is what is used).
|
|
1822
|
+
* @returns A column whose inferred type is an array of the element's type.
|
|
1823
|
+
*
|
|
1824
|
+
* @example
|
|
1825
|
+
* ```ts
|
|
1826
|
+
* class ApiKey extends Model {
|
|
1827
|
+
* static tablename = "api_keys";
|
|
1828
|
+
* scopes = column.array(column.text()).notNull().default(["send"]);
|
|
1829
|
+
* }
|
|
1830
|
+
* ```
|
|
1831
|
+
*/
|
|
1832
|
+
readonly array: <T>(element: Column<T, ColumnFlags>) => Column<T[], ColumnFlags>;
|
|
1833
|
+
};
|
|
1834
|
+
/**
|
|
1835
|
+
* A table-level constraint declared via a model's `static tableArgs`. Mirrors
|
|
1836
|
+
* SQLAlchemy's `__table_args__` entries (`UniqueConstraint`, `ForeignKeyConstraint`).
|
|
1837
|
+
* Use the {@link unique} and {@link foreignKey} helpers to build these.
|
|
1838
|
+
*/
|
|
1839
|
+
type TableConstraint = {
|
|
1840
|
+
readonly kind: "unique";
|
|
1841
|
+
readonly name?: string | undefined;
|
|
1842
|
+
readonly columns: readonly string[];
|
|
1843
|
+
} | {
|
|
1844
|
+
readonly kind: "foreignKey";
|
|
1845
|
+
readonly name?: string | undefined;
|
|
1846
|
+
readonly columns: readonly string[];
|
|
1847
|
+
readonly refTable: string;
|
|
1848
|
+
readonly refColumns: readonly string[];
|
|
1849
|
+
readonly onDelete?: FkAction | undefined;
|
|
1850
|
+
readonly onUpdate?: FkAction | undefined;
|
|
1324
1851
|
};
|
|
1852
|
+
/**
|
|
1853
|
+
* Declare a (possibly composite) `UNIQUE` table constraint over the given
|
|
1854
|
+
* columns. Mirrors SQLAlchemy's `UniqueConstraint("a", "b")`.
|
|
1855
|
+
*
|
|
1856
|
+
* @param columns The column names covered by the constraint.
|
|
1857
|
+
* @returns A unique {@link TableConstraint}.
|
|
1858
|
+
* @throws Error When no columns are given.
|
|
1859
|
+
*/
|
|
1860
|
+
declare function unique(...columns: string[]): TableConstraint;
|
|
1861
|
+
/**
|
|
1862
|
+
* Declare a (possibly composite) foreign-key table constraint. Mirrors
|
|
1863
|
+
* SQLAlchemy's `ForeignKeyConstraint([...], [...], ondelete=...)`.
|
|
1864
|
+
*
|
|
1865
|
+
* @param columns The local column names.
|
|
1866
|
+
* @param refTable The referenced table name.
|
|
1867
|
+
* @param refColumns The referenced column names (same length as `columns`).
|
|
1868
|
+
* @param options Optional constraint `name` and referential actions.
|
|
1869
|
+
* @returns A foreign-key {@link TableConstraint}.
|
|
1870
|
+
* @throws Error When the column arrays are empty or mismatched in length.
|
|
1871
|
+
*/
|
|
1872
|
+
declare function foreignKey(columns: string[], refTable: string, refColumns: string[], options?: {
|
|
1873
|
+
name?: string;
|
|
1874
|
+
onDelete?: FkAction;
|
|
1875
|
+
onUpdate?: FkAction;
|
|
1876
|
+
}): TableConstraint;
|
|
1877
|
+
/**
|
|
1878
|
+
* How property names map to database column names when a column declares no
|
|
1879
|
+
* explicit {@link Column.name}.
|
|
1880
|
+
*
|
|
1881
|
+
* - `"preserve"` (default) — the column name is the property name, verbatim.
|
|
1882
|
+
* - `"snake_case"` — `consumerName` becomes `consumer_name`.
|
|
1883
|
+
*/
|
|
1884
|
+
type NamingStrategy = "preserve" | "snake_case";
|
|
1885
|
+
/** Convert a `camelCase` / `PascalCase` identifier to `snake_case`. */
|
|
1886
|
+
declare function toSnakeCase(name: string): string;
|
|
1325
1887
|
/** Base class every model extends, SQLAlchemy-declarative style. */
|
|
1326
1888
|
declare abstract class Model {
|
|
1327
1889
|
static tablename: string;
|
|
1890
|
+
/**
|
|
1891
|
+
* Optional table-level constraints (composite unique / foreign keys), returned
|
|
1892
|
+
* by a thunk so forward references resolve lazily. Mirrors SQLAlchemy's
|
|
1893
|
+
* `__table_args__`.
|
|
1894
|
+
*/
|
|
1895
|
+
static tableArgs?: () => readonly TableConstraint[];
|
|
1896
|
+
/**
|
|
1897
|
+
* How to derive column names from property names (default `"preserve"`). Set
|
|
1898
|
+
* `"snake_case"` to keep a `snake_case` schema behind a `camelCase` model
|
|
1899
|
+
* without annotating every column; {@link Column.name} overrides it per column.
|
|
1900
|
+
*/
|
|
1901
|
+
static naming?: NamingStrategy;
|
|
1328
1902
|
}
|
|
1329
1903
|
/**
|
|
1330
1904
|
* Reflect a model class into its column map at runtime, keyed by column name.
|
|
@@ -1340,6 +1914,32 @@ declare abstract class Model {
|
|
|
1340
1914
|
* @returns A record of column name → `Column` instance (do not mutate).
|
|
1341
1915
|
*/
|
|
1342
1916
|
declare function columnsOf(model: ModelClass): Record<string, Column<unknown>>;
|
|
1917
|
+
/** A mapping between property names and database column names. */
|
|
1918
|
+
type NameMap = Readonly<Record<string, string>>;
|
|
1919
|
+
/**
|
|
1920
|
+
* The property → database-column map for a model, or `null` when every column
|
|
1921
|
+
* keeps its property name.
|
|
1922
|
+
*
|
|
1923
|
+
* `null` is the common case and the fast path: builders and the row coercer skip
|
|
1924
|
+
* translation entirely, so a model that renames nothing costs nothing. The map
|
|
1925
|
+
* is memoized per class, like {@link columnsOf}.
|
|
1926
|
+
*
|
|
1927
|
+
* @param model The model class.
|
|
1928
|
+
* @returns The name map, or `null` when no column is renamed.
|
|
1929
|
+
* @throws Error When two properties resolve to the same column name.
|
|
1930
|
+
*/
|
|
1931
|
+
declare function columnNamesOf(model: ModelClass): NameMap | null;
|
|
1932
|
+
/**
|
|
1933
|
+
* The database-column → property map for a model, or `null` when every column
|
|
1934
|
+
* keeps its property name. The inverse of {@link columnNamesOf}, used to map
|
|
1935
|
+
* driver rows back into property space.
|
|
1936
|
+
*
|
|
1937
|
+
* @param model The model class.
|
|
1938
|
+
* @returns The inverse name map, or `null` when no column is renamed.
|
|
1939
|
+
*/
|
|
1940
|
+
declare function columnPropsOf(model: ModelClass): NameMap | null;
|
|
1941
|
+
/** Resolve one property name to its database column name. */
|
|
1942
|
+
declare function dbColumn(names: NameMap | null | undefined, prop: string): string;
|
|
1343
1943
|
/** Pull the static type out of a Column. */
|
|
1344
1944
|
type ColType<C> = C extends Column<infer T, infer _F> ? T : never;
|
|
1345
1945
|
/** Keys of the model instance whose values are Columns. */
|
|
@@ -1349,6 +1949,8 @@ type ColumnKeys<M> = {
|
|
|
1349
1949
|
/** Constructor type for a Model subclass. */
|
|
1350
1950
|
type ModelClass = (new () => Model) & {
|
|
1351
1951
|
tablename: string;
|
|
1952
|
+
tableArgs?: () => readonly TableConstraint[];
|
|
1953
|
+
naming?: NamingStrategy;
|
|
1352
1954
|
};
|
|
1353
1955
|
/** Flatten an intersection into a single object literal for clean inference. */
|
|
1354
1956
|
type Simplify<T> = {
|
|
@@ -1386,4 +1988,4 @@ type InferInsert<C extends ModelClass> = Simplify<{
|
|
|
1386
1988
|
[K in Exclude<ColumnKeys<InstanceType<C>>, OptionalInsertKeys<InstanceType<C>>>]: ColValue<InstanceType<C>[K]>;
|
|
1387
1989
|
}>;
|
|
1388
1990
|
|
|
1389
|
-
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 HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, Model, type ModelClass, MysqlDialect, NoResultError, NodeSqliteDriver, OPERATORS, type OnConflict, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, 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, SqliteDialect, type SyncDriver, SyncEngine, SyncResult, SyncSession, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, update };
|
|
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 };
|