tempest-db-js 0.4.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 +8 -2
- package/dist/bin.cjs +159 -56
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +2 -2
- package/dist/{chunk-JR4MLFQN.js → chunk-5QQMVTS5.js} +881 -257
- package/dist/chunk-5QQMVTS5.js.map +1 -0
- package/dist/{chunk-43XL66JG.js → chunk-EPMLFNFK.js} +103 -30
- package/dist/chunk-EPMLFNFK.js.map +1 -0
- package/dist/index.cjs +884 -254
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +532 -29
- package/dist/index.d.ts +532 -29
- package/dist/index.js +1 -1
- package/dist/migrations/index.cjs +214 -62
- package/dist/migrations/index.cjs.map +1 -1
- package/dist/migrations/index.d.cts +12 -2
- package/dist/migrations/index.d.ts +12 -2
- package/dist/migrations/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-43XL66JG.js.map +0 -1
- package/dist/chunk-JR4MLFQN.js.map +0 -1
package/dist/index.d.cts
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>>;
|
|
@@ -1168,7 +1503,7 @@ interface ColumnFlags {
|
|
|
1168
1503
|
* generic types (e.g. `String` → varchar, `Text` → text). Dialect renderers
|
|
1169
1504
|
* (Phase 4/6) map each kind + meta to concrete SQL per database.
|
|
1170
1505
|
*/
|
|
1171
|
-
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";
|
|
1172
1507
|
/** Parameters that refine a column type and feed the migration IR / DDL. */
|
|
1173
1508
|
interface ColumnTypeMeta {
|
|
1174
1509
|
/** Max length for `varchar`/`char`. */
|
|
@@ -1183,6 +1518,8 @@ interface ColumnTypeMeta {
|
|
|
1183
1518
|
readonly values?: readonly string[] | undefined;
|
|
1184
1519
|
/** Render as `JSONB` (PostgreSQL) instead of `JSON`. */
|
|
1185
1520
|
readonly jsonb?: boolean | undefined;
|
|
1521
|
+
/** The element type of an `array` column (`text[]`, `integer[]`). */
|
|
1522
|
+
readonly element?: ColumnType | undefined;
|
|
1186
1523
|
}
|
|
1187
1524
|
/** A structured, dialect-neutral column type descriptor. */
|
|
1188
1525
|
interface ColumnType {
|
|
@@ -1193,10 +1530,14 @@ interface ColumnType {
|
|
|
1193
1530
|
* A portable default expression. The token is dialect-neutral; the renderer
|
|
1194
1531
|
* (Phase 4/6) maps it to the right SQL per database — e.g. `"now"` becomes
|
|
1195
1532
|
* `CURRENT_TIMESTAMP` on SQLite and `now()` on PostgreSQL. Use `{ raw }` as an
|
|
1196
|
-
* 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).
|
|
1197
1536
|
*/
|
|
1198
1537
|
type PortableExpression = "now" | "current_date" | "current_time" | "uuidv4" | {
|
|
1199
1538
|
readonly raw: string;
|
|
1539
|
+
} | {
|
|
1540
|
+
readonly parts: readonly string[];
|
|
1200
1541
|
};
|
|
1201
1542
|
/**
|
|
1202
1543
|
* A column default. Either a constant literal value or a server-side expression
|
|
@@ -1210,18 +1551,79 @@ type DefaultValue = {
|
|
|
1210
1551
|
readonly kind: "expression";
|
|
1211
1552
|
readonly expression: PortableExpression;
|
|
1212
1553
|
};
|
|
1213
|
-
/**
|
|
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
|
+
*/
|
|
1214
1589
|
declare const sql: {
|
|
1215
1590
|
/** Current timestamp at insert (`CURRENT_TIMESTAMP` / `now()`). */
|
|
1216
|
-
readonly now: () =>
|
|
1591
|
+
readonly now: () => SqlExpression;
|
|
1217
1592
|
/** Current date. */
|
|
1218
|
-
readonly currentDate: () =>
|
|
1593
|
+
readonly currentDate: () => SqlExpression;
|
|
1219
1594
|
/** Current time. */
|
|
1220
|
-
readonly currentTime: () =>
|
|
1595
|
+
readonly currentTime: () => SqlExpression;
|
|
1221
1596
|
/** A freshly generated UUID v4 (`gen_random_uuid()` / portable fallback). */
|
|
1222
|
-
readonly uuidv4: () =>
|
|
1223
|
-
/**
|
|
1224
|
-
|
|
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;
|
|
1225
1627
|
};
|
|
1226
1628
|
/**
|
|
1227
1629
|
* A referential action for a foreign key's `ON DELETE` / `ON UPDATE` clause.
|
|
@@ -1258,6 +1660,8 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1258
1660
|
readonly onUpdateValue: DefaultValue | null;
|
|
1259
1661
|
/** The foreign-key reference this column points to, or `null` for none. */
|
|
1260
1662
|
readonly reference: ForeignKeyRef | null;
|
|
1663
|
+
/** An explicit database column name overriding the property name, or `null`. */
|
|
1664
|
+
readonly dbName: string | null;
|
|
1261
1665
|
/** Phantom: never read at runtime, only inspected by the type system. */
|
|
1262
1666
|
readonly [TYPE]: T;
|
|
1263
1667
|
constructor(type: ColumnType, flags: F,
|
|
@@ -1266,7 +1670,11 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1266
1670
|
/** The value re-applied on update (e.g. `updated_at`), or `null`. */
|
|
1267
1671
|
onUpdateValue?: DefaultValue | null,
|
|
1268
1672
|
/** The foreign-key reference this column points to, or `null` for none. */
|
|
1269
|
-
reference?: ForeignKeyRef | null
|
|
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;
|
|
1270
1678
|
primaryKey(): Column<T, F & {
|
|
1271
1679
|
primaryKey: true;
|
|
1272
1680
|
hasDefault: true;
|
|
@@ -1281,6 +1689,29 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1281
1689
|
unique(): Column<T, F & {
|
|
1282
1690
|
unique: true;
|
|
1283
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>;
|
|
1284
1715
|
/**
|
|
1285
1716
|
* Declare a foreign-key reference to another table's column, à la SQLAlchemy's
|
|
1286
1717
|
* `mapped_column(ForeignKey("table.column", ondelete=...))`. DDL-only — does
|
|
@@ -1295,6 +1726,11 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1295
1726
|
/**
|
|
1296
1727
|
* Set the insert-time default: a constant value of type `T`, or a portable
|
|
1297
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.
|
|
1298
1734
|
*/
|
|
1299
1735
|
default(value: T | DefaultValue): Column<T, F & {
|
|
1300
1736
|
hasDefault: true;
|
|
@@ -1302,6 +1738,10 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1302
1738
|
/**
|
|
1303
1739
|
* Re-apply a value whenever the row is updated (e.g. an `updated_at` column
|
|
1304
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}).
|
|
1305
1745
|
*/
|
|
1306
1746
|
onUpdate(value: T | DefaultValue): Column<T, F>;
|
|
1307
1747
|
}
|
|
@@ -1370,6 +1810,26 @@ declare const column: {
|
|
|
1370
1810
|
readonly uuid: () => Column<string, ColumnFlags>;
|
|
1371
1811
|
/** `ENUM(...values)` → a string-literal union of the given values. */
|
|
1372
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>;
|
|
1373
1833
|
};
|
|
1374
1834
|
/**
|
|
1375
1835
|
* A table-level constraint declared via a model's `static tableArgs`. Mirrors
|
|
@@ -1414,6 +1874,16 @@ declare function foreignKey(columns: string[], refTable: string, refColumns: str
|
|
|
1414
1874
|
onDelete?: FkAction;
|
|
1415
1875
|
onUpdate?: FkAction;
|
|
1416
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;
|
|
1417
1887
|
/** Base class every model extends, SQLAlchemy-declarative style. */
|
|
1418
1888
|
declare abstract class Model {
|
|
1419
1889
|
static tablename: string;
|
|
@@ -1423,6 +1893,12 @@ declare abstract class Model {
|
|
|
1423
1893
|
* `__table_args__`.
|
|
1424
1894
|
*/
|
|
1425
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;
|
|
1426
1902
|
}
|
|
1427
1903
|
/**
|
|
1428
1904
|
* Reflect a model class into its column map at runtime, keyed by column name.
|
|
@@ -1438,6 +1914,32 @@ declare abstract class Model {
|
|
|
1438
1914
|
* @returns A record of column name → `Column` instance (do not mutate).
|
|
1439
1915
|
*/
|
|
1440
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;
|
|
1441
1943
|
/** Pull the static type out of a Column. */
|
|
1442
1944
|
type ColType<C> = C extends Column<infer T, infer _F> ? T : never;
|
|
1443
1945
|
/** Keys of the model instance whose values are Columns. */
|
|
@@ -1448,6 +1950,7 @@ type ColumnKeys<M> = {
|
|
|
1448
1950
|
type ModelClass = (new () => Model) & {
|
|
1449
1951
|
tablename: string;
|
|
1450
1952
|
tableArgs?: () => readonly TableConstraint[];
|
|
1953
|
+
naming?: NamingStrategy;
|
|
1451
1954
|
};
|
|
1452
1955
|
/** Flatten an intersection into a single object literal for clean inference. */
|
|
1453
1956
|
type Simplify<T> = {
|
|
@@ -1485,4 +1988,4 @@ type InferInsert<C extends ModelClass> = Simplify<{
|
|
|
1485
1988
|
[K in Exclude<ColumnKeys<InstanceType<C>>, OptionalInsertKeys<InstanceType<C>>>]: ColValue<InstanceType<C>[K]>;
|
|
1486
1989
|
}>;
|
|
1487
1990
|
|
|
1488
|
-
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, 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, type TableConstraint, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, unique, 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 };
|