tempest-db-js 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -3
- package/dist/bin.cjs +604 -250
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +3 -3
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-JR4MLFQN.js → chunk-G7O5DCCC.js} +1347 -289
- package/dist/chunk-G7O5DCCC.js.map +1 -0
- package/dist/{chunk-43XL66JG.js → chunk-KOW3LSWP.js} +209 -86
- package/dist/chunk-KOW3LSWP.js.map +1 -0
- package/dist/index.cjs +1357 -286
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +897 -42
- package/dist/index.d.ts +897 -42
- package/dist/index.js +1 -1
- package/dist/migrations/index.cjs +336 -117
- package/dist/migrations/index.cjs.map +1 -1
- package/dist/migrations/index.d.cts +58 -5
- package/dist/migrations/index.d.ts +58 -5
- package/dist/migrations/index.js +2 -2
- package/package.json +6 -1
- package/dist/chunk-43XL66JG.js.map +0 -1
- package/dist/chunk-JR4MLFQN.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";
|
|
@@ -39,20 +61,44 @@ interface SelectNode {
|
|
|
39
61
|
/** `GROUP BY` columns. */
|
|
40
62
|
readonly groupBy: readonly string[];
|
|
41
63
|
readonly where: CondNode | undefined;
|
|
64
|
+
/** `HAVING` condition, keyed by aggregate alias or grouped column. */
|
|
65
|
+
readonly having?: CondNode | undefined;
|
|
42
66
|
readonly orderBy: readonly OrderTerm[];
|
|
43
67
|
readonly limit: number | undefined;
|
|
44
68
|
readonly offset: number | undefined;
|
|
69
|
+
/** Row-level locking clause, or `undefined` for none. */
|
|
70
|
+
readonly lock?: LockClause | undefined;
|
|
71
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
72
|
+
readonly names?: NameMap | undefined;
|
|
45
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* A SELECT projecting exactly one column of type `T`, usable as the operand of
|
|
76
|
+
* `in` / `notIn`.
|
|
77
|
+
*
|
|
78
|
+
* Build it with {@link SelectBuilder.asSubquery}, which both narrows the
|
|
79
|
+
* projection to one column and gives the operand its element type.
|
|
80
|
+
*/
|
|
81
|
+
interface Subquery<T> {
|
|
82
|
+
/** Phantom: the element type the subquery yields, read only by the type system. */
|
|
83
|
+
readonly __element?: T;
|
|
84
|
+
/** The AST the outer statement embeds. */
|
|
85
|
+
readonly node: SelectNode;
|
|
86
|
+
}
|
|
87
|
+
/** Runtime guard: is this `in`/`notIn` operand a subquery rather than a list? */
|
|
88
|
+
declare function isSubquery(value: unknown): value is Subquery<unknown>;
|
|
46
89
|
/** Operators valid on every column type. */
|
|
47
90
|
interface BaseOperators<T> {
|
|
48
91
|
/** Equal to. */
|
|
49
92
|
eq?: T;
|
|
50
93
|
/** Not equal to. */
|
|
51
94
|
ne?: T;
|
|
52
|
-
/**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
95
|
+
/**
|
|
96
|
+
* One of the given values (`IN`) — a list, or a single-column
|
|
97
|
+
* {@link Subquery} built with `.asSubquery(column)`.
|
|
98
|
+
*/
|
|
99
|
+
in?: readonly T[] | Subquery<T>;
|
|
100
|
+
/** None of the given values (`NOT IN`), as a list or a {@link Subquery}. */
|
|
101
|
+
notIn?: readonly T[] | Subquery<T>;
|
|
56
102
|
/** `IS NULL` (true) / `IS NOT NULL` (false). */
|
|
57
103
|
isNull?: boolean;
|
|
58
104
|
}
|
|
@@ -71,19 +117,41 @@ interface OrderedOperators<T> extends BaseOperators<T> {
|
|
|
71
117
|
}
|
|
72
118
|
/** Extra operators for string-like types. */
|
|
73
119
|
interface StringOperators<T> extends BaseOperators<T> {
|
|
74
|
-
/** `LIKE` pattern (case-sensitive). */
|
|
120
|
+
/** `LIKE` pattern (case-sensitive). `%` and `_` are wildcards. */
|
|
75
121
|
like?: string;
|
|
76
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* `ILIKE` **pattern** (case-insensitive). This is pattern matching, not
|
|
124
|
+
* equality: `%` and `_` in the operand are wildcards, so `{ ilike: "%" }`
|
|
125
|
+
* matches every row. Never feed it unescaped user input — for a
|
|
126
|
+
* case-insensitive *equality* test use {@link StringOperators.ieq}, and to
|
|
127
|
+
* match a literal that may contain wildcards, wrap it in `escapeLike`.
|
|
128
|
+
*/
|
|
77
129
|
ilike?: string;
|
|
130
|
+
/**
|
|
131
|
+
* Case-insensitive equality — compiles to `lower(col) = lower($1)`, with no
|
|
132
|
+
* wildcards. The safe operator for a case-insensitive lookup (login, email),
|
|
133
|
+
* and the one that matches a `lower(col)` functional index.
|
|
134
|
+
*/
|
|
135
|
+
ieq?: T;
|
|
136
|
+
}
|
|
137
|
+
/** Extra operators for array columns (PostgreSQL). */
|
|
138
|
+
interface ArrayOperators<T> extends BaseOperators<T> {
|
|
139
|
+
/** `@>` — the column contains every element of the operand. */
|
|
140
|
+
contains?: T;
|
|
141
|
+
/** `<@` — every element of the column is in the operand. */
|
|
142
|
+
containedBy?: T;
|
|
143
|
+
/** `&&` — the column and the operand share at least one element. */
|
|
144
|
+
overlaps?: T;
|
|
78
145
|
}
|
|
79
146
|
/**
|
|
80
147
|
* The operator object allowed for a column of (non-null) type `T`:
|
|
81
|
-
* - `
|
|
148
|
+
* - `T[]` → equality, `in`, `contains`/`containedBy`/`overlaps` (PostgreSQL)
|
|
149
|
+
* - `string` → equality, `in`, `like`/`ilike`/`ieq`
|
|
82
150
|
* - `number` / `bigint` / `Date` → equality, `in`, ordered comparisons, `between`
|
|
83
151
|
* - `boolean` → equality, `isNull`
|
|
84
152
|
* - anything else (json/blob) → equality and `in` only
|
|
85
153
|
*/
|
|
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>;
|
|
154
|
+
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
155
|
/**
|
|
88
156
|
* `where` shape: each key must be a real column; each value accepts either a
|
|
89
157
|
* bare value (shorthand for `eq`) or an operator object restricted to operators
|
|
@@ -94,7 +162,7 @@ type WhereInput<Row = Record<string, unknown>> = {
|
|
|
94
162
|
[K in keyof Row]?: Row[K] | OperatorsFor<NonNullable<Row[K]>>;
|
|
95
163
|
};
|
|
96
164
|
/** 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"];
|
|
165
|
+
declare const OPERATORS: readonly ["eq", "ne", "gt", "gte", "lt", "lte", "like", "ilike", "ieq", "in", "notIn", "between", "isNull", "contains", "containedBy", "overlaps"];
|
|
98
166
|
/** One supported operator name. */
|
|
99
167
|
type Operator = (typeof OPERATORS)[number];
|
|
100
168
|
/** An aggregate expression carrying its result type `T` as a phantom. */
|
|
@@ -126,20 +194,43 @@ type SimplifyProj<T> = {
|
|
|
126
194
|
* @typeParam Full - the complete row type (constrains where/orderBy keys).
|
|
127
195
|
* @typeParam Proj - the projected result type returned on execution.
|
|
128
196
|
*/
|
|
129
|
-
declare class SelectBuilder<Full, Proj = Full> {
|
|
197
|
+
declare class SelectBuilder<Full, Proj = Full, Grouped extends boolean = false> {
|
|
130
198
|
readonly node: SelectNode;
|
|
131
199
|
/** The source model, used to coerce rows on execution. */
|
|
132
200
|
readonly source: ModelClass;
|
|
133
201
|
/** Phantom: the result element type, read only by the type system. */
|
|
134
202
|
readonly __row: Proj;
|
|
203
|
+
/** Phantom: `true` once `aggregate()` has made `having()` meaningful. */
|
|
204
|
+
readonly __grouped: Grouped;
|
|
135
205
|
constructor(node: SelectNode,
|
|
136
206
|
/** The source model, used to coerce rows on execution. */
|
|
137
207
|
source: ModelClass);
|
|
138
208
|
private with;
|
|
139
209
|
/** Add a WHERE filter: the object form (keys typed) or an `and`/`or`/`not`. */
|
|
140
|
-
where(input: WhereInput<Full> | Condition): SelectBuilder<Full, Proj>;
|
|
210
|
+
where(input: WhereInput<Full> | Condition): SelectBuilder<Full, Proj, Grouped>;
|
|
211
|
+
/**
|
|
212
|
+
* Filter by the result of the aggregation (`HAVING`).
|
|
213
|
+
*
|
|
214
|
+
* Only available on a grouped builder — `.having()` before `.aggregate()` is a
|
|
215
|
+
* compile error, not invalid SQL at runtime. Keys are the aggregate aliases you
|
|
216
|
+
* named plus the grouped columns; `WHERE` still filters rows *before* grouping,
|
|
217
|
+
* which is a different question.
|
|
218
|
+
*
|
|
219
|
+
* @param input The condition, keyed by alias or grouped column.
|
|
220
|
+
* @returns A builder carrying the `HAVING` clause.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* select(Outbound)
|
|
225
|
+
* .where({ status: "queued" })
|
|
226
|
+
* .aggregate(["consumer"], { n: count() })
|
|
227
|
+
* .having({ n: { gt: 100 } });
|
|
228
|
+
* // ... GROUP BY "consumer" HAVING COUNT(*) > $2
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
having(this: SelectBuilder<Full, Proj, true>, input: WhereInput<Proj> | Condition): SelectBuilder<Full, Proj, true>;
|
|
141
232
|
/** Emit `SELECT DISTINCT` — drop duplicate rows. */
|
|
142
|
-
distinct(): SelectBuilder<Full, Proj>;
|
|
233
|
+
distinct(): SelectBuilder<Full, Proj, Grouped>;
|
|
143
234
|
/**
|
|
144
235
|
* Group by columns and compute aggregates. The result row is the grouped
|
|
145
236
|
* columns (typed from the model) plus one field per aggregate alias.
|
|
@@ -158,13 +249,88 @@ declare class SelectBuilder<Full, Proj = Full> {
|
|
|
158
249
|
*/
|
|
159
250
|
aggregate<K extends keyof Full & string, S extends Record<string, Agg<unknown>>>(groupBy: readonly K[], spec: S): SelectBuilder<Full, SimplifyProj<Pick<Full, K> & {
|
|
160
251
|
[A in keyof S]: AggResult<S[A]>;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
|
|
252
|
+
}>, true>;
|
|
253
|
+
/**
|
|
254
|
+
* Order by a column of the model, or — on a grouped query — by an aggregate
|
|
255
|
+
* alias. Unlike `HAVING`, every dialect accepts the output alias in `ORDER BY`,
|
|
256
|
+
* so the alias is emitted as written.
|
|
257
|
+
*
|
|
258
|
+
* @param column A model column, or a projected alias.
|
|
259
|
+
* @param direction `"asc"` (default) or `"desc"`.
|
|
260
|
+
* @returns A builder carrying the ordering term.
|
|
261
|
+
*/
|
|
262
|
+
orderBy(column: (keyof Full & string) | (keyof Proj & string), direction?: SortDirection): SelectBuilder<Full, Proj, Grouped>;
|
|
164
263
|
/** Limit the number of rows. */
|
|
165
|
-
limit(n: number): SelectBuilder<Full, Proj>;
|
|
264
|
+
limit(n: number): SelectBuilder<Full, Proj, Grouped>;
|
|
166
265
|
/** Skip the first `n` rows. */
|
|
167
|
-
offset(n: number): SelectBuilder<Full, Proj>;
|
|
266
|
+
offset(n: number): SelectBuilder<Full, Proj, Grouped>;
|
|
267
|
+
/**
|
|
268
|
+
* Narrow this SELECT to a single column and mark it as a subquery, so it can be
|
|
269
|
+
* the operand of `in` / `notIn`.
|
|
270
|
+
*
|
|
271
|
+
* The whole query — `where`, `orderBy`, `limit`, and a locking clause — is
|
|
272
|
+
* embedded in the outer statement, which is what collapses the claim-a-batch
|
|
273
|
+
* pattern into one round trip instead of selecting ids and sending them back.
|
|
274
|
+
*
|
|
275
|
+
* @param column The single column to project (checked against the model).
|
|
276
|
+
* @returns A subquery carrying that column's type.
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```ts
|
|
280
|
+
* update(Outbound)
|
|
281
|
+
* .set({ status: "sending", attempts: sql.raw("attempts + 1") })
|
|
282
|
+
* .where({
|
|
283
|
+
* id: {
|
|
284
|
+
* in: select(Outbound)
|
|
285
|
+
* .where({ status: "queued" })
|
|
286
|
+
* .orderBy("nextAttemptAt")
|
|
287
|
+
* .limit(10)
|
|
288
|
+
* .forUpdate({ skipLocked: true })
|
|
289
|
+
* .asSubquery("id"),
|
|
290
|
+
* },
|
|
291
|
+
* })
|
|
292
|
+
* .returning();
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
asSubquery<K extends keyof Full & string>(column: K): Subquery<Full[K]>;
|
|
296
|
+
/**
|
|
297
|
+
* Lock the selected rows for update (`SELECT ... FOR UPDATE`), à la
|
|
298
|
+
* SQLAlchemy's `with_for_update()`.
|
|
299
|
+
*
|
|
300
|
+
* `{ skipLocked: true }` is the job-queue claim: competing workers each take a
|
|
301
|
+
* disjoint batch instead of blocking on — or worse, double-processing — the
|
|
302
|
+
* same rows.
|
|
303
|
+
*
|
|
304
|
+
* PostgreSQL and MySQL 8.0+ only. SQLite has no row-level locking, and its
|
|
305
|
+
* dialect throws rather than emitting a `SELECT` that silently locks nothing —
|
|
306
|
+
* a lock that does not exist only fails under production concurrency.
|
|
307
|
+
*
|
|
308
|
+
* @param options `skipLocked` / `noWait` wait behavior, and `of` to restrict
|
|
309
|
+
* the lock to specific tables.
|
|
310
|
+
* @returns A builder carrying the locking clause.
|
|
311
|
+
* @throws Error When both `skipLocked` and `noWait` are set.
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```ts
|
|
315
|
+
* const batch = await session.execute(
|
|
316
|
+
* select(Outbound)
|
|
317
|
+
* .where({ status: "queued" })
|
|
318
|
+
* .orderBy("nextAttemptAt")
|
|
319
|
+
* .limit(10)
|
|
320
|
+
* .forUpdate({ skipLocked: true }),
|
|
321
|
+
* ).all();
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
forUpdate(options?: LockOptions): SelectBuilder<Full, Proj, Grouped>;
|
|
325
|
+
/**
|
|
326
|
+
* Take a shared read lock on the selected rows (`SELECT ... FOR SHARE`), the
|
|
327
|
+
* weaker counterpart of {@link SelectBuilder.forUpdate}.
|
|
328
|
+
*
|
|
329
|
+
* @param options `skipLocked` / `noWait` wait behavior, and `of` tables.
|
|
330
|
+
* @returns A builder carrying the locking clause.
|
|
331
|
+
* @throws Error When both `skipLocked` and `noWait` are set.
|
|
332
|
+
*/
|
|
333
|
+
forShare(options?: LockOptions): SelectBuilder<Full, Proj, Grouped>;
|
|
168
334
|
}
|
|
169
335
|
/** Build a SELECT over every column of the model. */
|
|
170
336
|
declare function select<C extends ModelClass>(model: C): SelectBuilder<InferModel<C>, InferModel<C>>;
|
|
@@ -185,6 +351,25 @@ interface CondFields {
|
|
|
185
351
|
readonly kind: "fields";
|
|
186
352
|
readonly fields: Record<string, unknown>;
|
|
187
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* One side of a comparison: a column reference, a bound value, or a SQL function
|
|
356
|
+
* applied to other expressions.
|
|
357
|
+
*
|
|
358
|
+
* A column reference carries the **property** name, not the database column —
|
|
359
|
+
* the dialect resolves it through the node's name map, so `col()` cannot become a
|
|
360
|
+
* back door around an explicit `.name()` mapping.
|
|
361
|
+
*/
|
|
362
|
+
type ExprNode = {
|
|
363
|
+
readonly kind: "column";
|
|
364
|
+
readonly name: string;
|
|
365
|
+
} | {
|
|
366
|
+
readonly kind: "value";
|
|
367
|
+
readonly value: unknown;
|
|
368
|
+
} | {
|
|
369
|
+
readonly kind: "fn";
|
|
370
|
+
readonly name: string;
|
|
371
|
+
readonly args: readonly ExprNode[];
|
|
372
|
+
};
|
|
188
373
|
/** Logical condition nodes. */
|
|
189
374
|
type CondNode = CondFields | {
|
|
190
375
|
readonly kind: "and";
|
|
@@ -195,6 +380,11 @@ type CondNode = CondFields | {
|
|
|
195
380
|
} | {
|
|
196
381
|
readonly kind: "not";
|
|
197
382
|
readonly part: CondNode;
|
|
383
|
+
} | {
|
|
384
|
+
readonly kind: "compare";
|
|
385
|
+
readonly left: ExprNode;
|
|
386
|
+
readonly op: Operator;
|
|
387
|
+
readonly right: ExprNode;
|
|
198
388
|
};
|
|
199
389
|
declare const CONDITION: unique symbol;
|
|
200
390
|
/** A composed condition produced by `and`/`or`/`not`. */
|
|
@@ -214,6 +404,145 @@ declare function toCondNode(input: Condition | Record<string, unknown>): CondNod
|
|
|
214
404
|
* for full key + operator checking inside combinators.
|
|
215
405
|
*/
|
|
216
406
|
type WhereArg<Row = Record<string, unknown>> = WhereInput<Row> | Condition;
|
|
407
|
+
/** Runtime guard: is this operand a built {@link Expression}? */
|
|
408
|
+
declare function isExpression(value: unknown): value is Expression;
|
|
409
|
+
/**
|
|
410
|
+
* One side of a comparison, built with {@link col}, {@link val} or {@link fn}.
|
|
411
|
+
*
|
|
412
|
+
* The comparison methods mirror the `where` operators, but both sides are
|
|
413
|
+
* expressions — which is what makes `col("total").gt(col("paid"))` and a
|
|
414
|
+
* functional-index lookup like `fn.lower("email").eq(fn.lower(val(probe)))`
|
|
415
|
+
* expressible at all. An operand that is not an `Expression` is bound as a
|
|
416
|
+
* parameter, so `.eq(probe)` stays safe by default.
|
|
417
|
+
*/
|
|
418
|
+
declare class Expression {
|
|
419
|
+
/** The expression AST the dialect renders. */
|
|
420
|
+
readonly node: ExprNode;
|
|
421
|
+
constructor(
|
|
422
|
+
/** The expression AST the dialect renders. */
|
|
423
|
+
node: ExprNode);
|
|
424
|
+
/** Compare this expression against another expression or a bound value. */
|
|
425
|
+
private compare;
|
|
426
|
+
/** `=` (or `IS NULL` for a null value). */
|
|
427
|
+
eq(operand: unknown): Condition;
|
|
428
|
+
/** `<>` (or `IS NOT NULL` for a null value). */
|
|
429
|
+
ne(operand: unknown): Condition;
|
|
430
|
+
/** `>`. */
|
|
431
|
+
gt(operand: unknown): Condition;
|
|
432
|
+
/** `>=`. */
|
|
433
|
+
gte(operand: unknown): Condition;
|
|
434
|
+
/** `<`. */
|
|
435
|
+
lt(operand: unknown): Condition;
|
|
436
|
+
/** `<=`. */
|
|
437
|
+
lte(operand: unknown): Condition;
|
|
438
|
+
/** `LIKE` — `%` and `_` in the operand are wildcards. */
|
|
439
|
+
like(pattern: string | Expression): Condition;
|
|
440
|
+
/** `ILIKE` — case-insensitive **pattern** matching, wildcards included. */
|
|
441
|
+
ilike(pattern: string | Expression): Condition;
|
|
442
|
+
/** Case-insensitive equality (`lower(a) = lower(b)`), with no wildcards. */
|
|
443
|
+
ieq(operand: unknown): Condition;
|
|
444
|
+
/**
|
|
445
|
+
* `IN (...)` over a list of values.
|
|
446
|
+
*
|
|
447
|
+
* @param values The values to test against.
|
|
448
|
+
* @returns The condition.
|
|
449
|
+
* @throws Error When an entry is an {@link Expression} — a list operand is
|
|
450
|
+
* bound, so an expression there would be serialized as a parameter instead of
|
|
451
|
+
* rendered as SQL.
|
|
452
|
+
*/
|
|
453
|
+
in(values: readonly unknown[]): Condition;
|
|
454
|
+
/**
|
|
455
|
+
* `NOT IN (...)` over a list of values.
|
|
456
|
+
*
|
|
457
|
+
* @param values The values to exclude.
|
|
458
|
+
* @returns The condition.
|
|
459
|
+
* @throws Error When an entry is an {@link Expression} (see {@link Expression.in}).
|
|
460
|
+
*/
|
|
461
|
+
notIn(values: readonly unknown[]): Condition;
|
|
462
|
+
/**
|
|
463
|
+
* `BETWEEN lo AND hi` (inclusive).
|
|
464
|
+
*
|
|
465
|
+
* @param lo The lower bound.
|
|
466
|
+
* @param hi The upper bound.
|
|
467
|
+
* @returns The condition.
|
|
468
|
+
* @throws Error When a bound is an {@link Expression} (see {@link Expression.in}).
|
|
469
|
+
*/
|
|
470
|
+
between(lo: unknown, hi: unknown): Condition;
|
|
471
|
+
/** `IS NULL` (true) / `IS NOT NULL` (false). */
|
|
472
|
+
isNull(value?: boolean): Condition;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* A column reference, by **property** name.
|
|
476
|
+
*
|
|
477
|
+
* Pass the row type for key-safety: `col<UserRow>("total")` rejects a name that
|
|
478
|
+
* is not a column. The name is resolved through the model's column-name map at
|
|
479
|
+
* compile time, exactly like the object form of `where`.
|
|
480
|
+
*
|
|
481
|
+
* @param name The model property name.
|
|
482
|
+
* @returns An expression referencing that column.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```ts
|
|
486
|
+
* select(Order).where(col<OrderRow>("total").gt(col<OrderRow>("paid")));
|
|
487
|
+
* // SELECT * FROM "orders" WHERE "total" > "paid"
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
declare function col<Row = Record<string, unknown>>(name: keyof Row & string): Expression;
|
|
491
|
+
/**
|
|
492
|
+
* A bound value, for the places that take an expression and would otherwise read
|
|
493
|
+
* a bare string as a column name (the arguments of {@link fn}).
|
|
494
|
+
*
|
|
495
|
+
* @param value The value to bind as a parameter.
|
|
496
|
+
* @returns An expression that renders as a placeholder.
|
|
497
|
+
*/
|
|
498
|
+
declare function val(value: unknown): Expression;
|
|
499
|
+
/**
|
|
500
|
+
* Build a call to a SQL function.
|
|
501
|
+
*
|
|
502
|
+
* A bare string argument is a **column name** — that is the useful default here
|
|
503
|
+
* (`fn.lower("username")`), and it is why a literal has to be wrapped in
|
|
504
|
+
* {@link val}. The function name is interpolated into the statement, so it is
|
|
505
|
+
* validated as a plain identifier and must never come from user input; the
|
|
506
|
+
* arguments are always rendered through the expression compiler.
|
|
507
|
+
*
|
|
508
|
+
* @param name The SQL function name.
|
|
509
|
+
* @param args Column names or expressions.
|
|
510
|
+
* @returns An expression for the call.
|
|
511
|
+
* @throws Error When `name` is not a plain SQL identifier.
|
|
512
|
+
*/
|
|
513
|
+
declare function call(name: string, ...args: (Expression | string)[]): Expression;
|
|
514
|
+
/**
|
|
515
|
+
* SQL functions usable on either side of a comparison.
|
|
516
|
+
*
|
|
517
|
+
* The named entries are the ones every supported dialect implements. Anything
|
|
518
|
+
* else — `date_trunc`, `strftime`, a custom function — goes through
|
|
519
|
+
* {@link fn.call}, which does not pretend to be portable.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```ts
|
|
523
|
+
* select(AdminUser).where(fn.lower("username").eq(fn.lower(val(probe))));
|
|
524
|
+
* // WHERE lower("username") = lower($1)
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
declare const fn: {
|
|
528
|
+
/** `lower(x)`. */
|
|
529
|
+
readonly lower: (arg: Expression | string) => Expression;
|
|
530
|
+
/** `upper(x)`. */
|
|
531
|
+
readonly upper: (arg: Expression | string) => Expression;
|
|
532
|
+
/** `trim(x)`. */
|
|
533
|
+
readonly trim: (arg: Expression | string) => Expression;
|
|
534
|
+
/** `length(x)`. */
|
|
535
|
+
readonly length: (arg: Expression | string) => Expression;
|
|
536
|
+
/** `abs(x)`. */
|
|
537
|
+
readonly abs: (arg: Expression | string) => Expression;
|
|
538
|
+
/** `coalesce(a, b, ...)`. */
|
|
539
|
+
readonly coalesce: (...args: (Expression | string)[]) => Expression;
|
|
540
|
+
/**
|
|
541
|
+
* Any other SQL function, by name. Portability is the caller's problem —
|
|
542
|
+
* `date_trunc` is PostgreSQL, `strftime` is SQLite.
|
|
543
|
+
*/
|
|
544
|
+
readonly call: typeof call;
|
|
545
|
+
};
|
|
217
546
|
/** Combine conditions with `AND`. */
|
|
218
547
|
declare function and<Row = Record<string, unknown>>(...inputs: WhereArg<NoInfer<Row>>[]): Condition;
|
|
219
548
|
/** Combine conditions with `OR`. */
|
|
@@ -235,6 +564,19 @@ declare function not<Row = Record<string, unknown>>(input: WhereArg<NoInfer<Row>
|
|
|
235
564
|
|
|
236
565
|
/** Columns to return from a mutation, or "*" for the whole row. */
|
|
237
566
|
type Returning = readonly string[] | "*" | null;
|
|
567
|
+
/**
|
|
568
|
+
* A write shape over `Row`: every column accepts its own value **or** a
|
|
569
|
+
* {@link SqlExpression}, which the dialect renders inline instead of binding.
|
|
570
|
+
* Optionality is preserved from `Row`, so an insert shape keeps its defaults
|
|
571
|
+
* optional.
|
|
572
|
+
*/
|
|
573
|
+
type WriteValues<Row> = {
|
|
574
|
+
[K in keyof Row]: Row[K] | SqlExpression;
|
|
575
|
+
};
|
|
576
|
+
/** A partial write shape — the `SET` clause of an UPDATE or a `DO UPDATE`. */
|
|
577
|
+
type WritePatch<Row> = {
|
|
578
|
+
[K in keyof Row]?: Row[K] | SqlExpression;
|
|
579
|
+
};
|
|
238
580
|
/**
|
|
239
581
|
* Conflict-resolution clause for an INSERT (`ON CONFLICT`). `target` is the
|
|
240
582
|
* conflicting column(s) (a unique/PK constraint); `update` is `"nothing"` for
|
|
@@ -243,6 +585,28 @@ type Returning = readonly string[] | "*" | null;
|
|
|
243
585
|
interface OnConflict {
|
|
244
586
|
readonly target: readonly string[];
|
|
245
587
|
readonly update: Record<string, unknown> | "nothing";
|
|
588
|
+
/**
|
|
589
|
+
* The predicate of a **partial** unique index. PostgreSQL only matches a
|
|
590
|
+
* partial index as a conflict target when `ON CONFLICT` repeats its predicate,
|
|
591
|
+
* so without this an insert against `... WHERE key IS NOT NULL` is rejected
|
|
592
|
+
* with "there is no unique or exclusion constraint matching the ON CONFLICT
|
|
593
|
+
* specification".
|
|
594
|
+
*/
|
|
595
|
+
readonly targetWhere?: CondNode | undefined;
|
|
596
|
+
/** Extra condition restricting which conflicting rows `DO UPDATE` rewrites. */
|
|
597
|
+
readonly updateWhere?: CondNode | undefined;
|
|
598
|
+
}
|
|
599
|
+
/** Options for the `ON CONFLICT` clause of {@link InsertBuilder.onConflictDoNothing}. */
|
|
600
|
+
interface OnConflictOptions<Full> {
|
|
601
|
+
/** The predicate of the partial unique index used as the conflict target. */
|
|
602
|
+
readonly where?: WhereInput<Full> | Condition;
|
|
603
|
+
}
|
|
604
|
+
/** Options for {@link InsertBuilder.onConflictDoUpdate}. */
|
|
605
|
+
interface OnConflictUpdateOptions<Full> {
|
|
606
|
+
/** The predicate of the partial unique index used as the conflict target. */
|
|
607
|
+
readonly indexWhere?: WhereInput<Full> | Condition;
|
|
608
|
+
/** Extra condition deciding which conflicting rows are actually rewritten. */
|
|
609
|
+
readonly updateWhere?: WhereInput<Full> | Condition;
|
|
246
610
|
}
|
|
247
611
|
/** Serializable AST for an INSERT. */
|
|
248
612
|
interface InsertNode {
|
|
@@ -252,6 +616,8 @@ interface InsertNode {
|
|
|
252
616
|
readonly returning: Returning;
|
|
253
617
|
/** Conflict handling (`ON CONFLICT ...`), or `undefined` for none. */
|
|
254
618
|
readonly onConflict?: OnConflict;
|
|
619
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
620
|
+
readonly names?: NameMap | undefined;
|
|
255
621
|
}
|
|
256
622
|
/**
|
|
257
623
|
* INSERT builder.
|
|
@@ -269,21 +635,46 @@ declare class InsertBuilder<Full, Ins, Ret = number> {
|
|
|
269
635
|
/** The source model, used to coerce returned rows on execution. */
|
|
270
636
|
source: ModelClass);
|
|
271
637
|
private with;
|
|
272
|
-
/**
|
|
273
|
-
|
|
638
|
+
/**
|
|
639
|
+
* Provide one row or many rows to insert, typed by the insert shape.
|
|
640
|
+
*
|
|
641
|
+
* @param rows One row, or an array of rows.
|
|
642
|
+
* @returns A builder carrying the rows.
|
|
643
|
+
* @throws ValidationError When a value is not a column value the dialect can
|
|
644
|
+
* bind (see the `sql` helpers for writing an expression instead).
|
|
645
|
+
*/
|
|
646
|
+
values(rows: WriteValues<Ins> | readonly WriteValues<Ins>[]): InsertBuilder<Full, Ins, Ret>;
|
|
274
647
|
/**
|
|
275
648
|
* On a unique/PK conflict on `target`, do nothing (skip the row).
|
|
276
649
|
*
|
|
277
650
|
* @param target The conflicting column(s) — a unique or primary key.
|
|
651
|
+
* @param options Pass `where` to name the predicate of a **partial** unique
|
|
652
|
+
* index, which PostgreSQL requires in order to match it as a conflict target.
|
|
653
|
+
* @returns A builder carrying the conflict clause.
|
|
654
|
+
*
|
|
655
|
+
* @example
|
|
656
|
+
* ```ts
|
|
657
|
+
* insert(Outbound)
|
|
658
|
+
* .values(data)
|
|
659
|
+
* .onConflictDoNothing(["consumer", "idempotencyKey"], {
|
|
660
|
+
* where: { idempotencyKey: { isNull: false } },
|
|
661
|
+
* })
|
|
662
|
+
* .returning();
|
|
663
|
+
* ```
|
|
278
664
|
*/
|
|
279
|
-
onConflictDoNothing(target: readonly (keyof Full & string)[]): InsertBuilder<Full, Ins, Ret>;
|
|
665
|
+
onConflictDoNothing(target: readonly (keyof Full & string)[], options?: OnConflictOptions<Full>): InsertBuilder<Full, Ins, Ret>;
|
|
280
666
|
/**
|
|
281
667
|
* On a unique/PK conflict on `target`, overwrite the given columns (upsert).
|
|
282
668
|
*
|
|
283
669
|
* @param target The conflicting column(s) — a unique or primary key.
|
|
284
670
|
* @param set The columns to update with new values.
|
|
671
|
+
* @param options `indexWhere` names the predicate of a partial unique index
|
|
672
|
+
* (the conflict target); `updateWhere` further restricts which conflicting
|
|
673
|
+
* rows are rewritten.
|
|
674
|
+
* @returns A builder carrying the conflict clause.
|
|
675
|
+
* @throws ValidationError When a `set` value cannot be bound.
|
|
285
676
|
*/
|
|
286
|
-
onConflictDoUpdate(target: readonly (keyof Full & string)[], set:
|
|
677
|
+
onConflictDoUpdate(target: readonly (keyof Full & string)[], set: WritePatch<Full>, options?: OnConflictUpdateOptions<Full>): InsertBuilder<Full, Ins, Ret>;
|
|
287
678
|
/** Return the full inserted row(s). */
|
|
288
679
|
returning(): InsertBuilder<Full, Ins, Full>;
|
|
289
680
|
/** Return only the given columns of the inserted row(s). */
|
|
@@ -300,6 +691,8 @@ interface UpdateNode {
|
|
|
300
691
|
/** True once a where-clause or explicit opt-in makes the write safe. */
|
|
301
692
|
readonly guarded: boolean;
|
|
302
693
|
readonly returning: Returning;
|
|
694
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
695
|
+
readonly names?: NameMap | undefined;
|
|
303
696
|
}
|
|
304
697
|
/**
|
|
305
698
|
* UPDATE builder.
|
|
@@ -318,8 +711,26 @@ declare class UpdateBuilder<Full, Guarded extends boolean, Ret = number> {
|
|
|
318
711
|
/** The source model, used to coerce returned rows on execution. */
|
|
319
712
|
source: ModelClass);
|
|
320
713
|
private with;
|
|
321
|
-
/**
|
|
322
|
-
|
|
714
|
+
/**
|
|
715
|
+
* The columns to write. Partial — only the given columns change.
|
|
716
|
+
*
|
|
717
|
+
* A value is bound as a parameter unless it is a {@link sql} expression, which
|
|
718
|
+
* is rendered inline instead — that is how a counter is written without a
|
|
719
|
+
* read-modify-write race.
|
|
720
|
+
*
|
|
721
|
+
* @param values The column → value map.
|
|
722
|
+
* @returns A builder carrying the assignments.
|
|
723
|
+
* @throws ValidationError When a value is not a column value the dialect can
|
|
724
|
+
* bind (a bare object, an array on a scalar column, a function).
|
|
725
|
+
*
|
|
726
|
+
* @example
|
|
727
|
+
* ```ts
|
|
728
|
+
* update(Outbound)
|
|
729
|
+
* .set({ attempts: sql.raw("attempts + 1"), updatedAt: sql.now() })
|
|
730
|
+
* .where({ id });
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
733
|
+
set(values: WritePatch<Full>): UpdateBuilder<Full, Guarded, Ret>;
|
|
323
734
|
/** Restrict the rows to update. Marks the builder safe to execute. */
|
|
324
735
|
where(input: WhereInput<Full> | Condition): UpdateBuilder<Full, true, Ret>;
|
|
325
736
|
/** Explicit opt-in to update EVERY row. Use deliberately. */
|
|
@@ -338,6 +749,8 @@ interface DeleteNode {
|
|
|
338
749
|
readonly where: CondNode | undefined;
|
|
339
750
|
readonly guarded: boolean;
|
|
340
751
|
readonly returning: Returning;
|
|
752
|
+
/** Property → column map, or `undefined` when every name is the identity. */
|
|
753
|
+
readonly names?: NameMap | undefined;
|
|
341
754
|
}
|
|
342
755
|
/**
|
|
343
756
|
* DELETE builder. Starts unguarded — same safety rule as UPDATE.
|
|
@@ -532,6 +945,8 @@ interface JoinNode {
|
|
|
532
945
|
}[];
|
|
533
946
|
readonly limit: number | undefined;
|
|
534
947
|
readonly offset: number | undefined;
|
|
948
|
+
/** Per-alias property → column maps, for the sources that rename columns. */
|
|
949
|
+
readonly names?: Readonly<Record<string, NameMap>> | undefined;
|
|
535
950
|
}
|
|
536
951
|
/** A map of source alias → its (possibly nullable) row type. */
|
|
537
952
|
type Sources = Record<string, object | null>;
|
|
@@ -605,6 +1020,16 @@ interface CompiledQuery {
|
|
|
605
1020
|
}
|
|
606
1021
|
/** Any compilable AST node. */
|
|
607
1022
|
type QueryNode = SelectNode | InsertNode | UpdateNode | DeleteNode | JoinNode;
|
|
1023
|
+
/**
|
|
1024
|
+
* Collects bound parameters and renders placeholders in dialect style. Exposed
|
|
1025
|
+
* because dialect subclasses receive it when overriding clause rendering.
|
|
1026
|
+
*/
|
|
1027
|
+
declare class Params {
|
|
1028
|
+
private readonly placeholder;
|
|
1029
|
+
readonly values: unknown[];
|
|
1030
|
+
constructor(placeholder: (index: number) => string);
|
|
1031
|
+
bind(value: unknown): string;
|
|
1032
|
+
}
|
|
608
1033
|
/**
|
|
609
1034
|
* Base SQL compiler shared by every dialect. Subclasses customize only what
|
|
610
1035
|
* actually differs between databases (placeholder syntax, `ILIKE` support).
|
|
@@ -623,6 +1048,25 @@ declare abstract class BaseDialect {
|
|
|
623
1048
|
protected abstract placeholder(index: number): string;
|
|
624
1049
|
/** Render a case-insensitive LIKE for the active dialect. */
|
|
625
1050
|
protected abstract ilike(column: string, param: string): string;
|
|
1051
|
+
/**
|
|
1052
|
+
* Validate a subquery operand before it is rendered, for dialects that restrict
|
|
1053
|
+
* what an `IN (SELECT ...)` may contain. The default accepts everything.
|
|
1054
|
+
*
|
|
1055
|
+
* @param _node The subquery's AST.
|
|
1056
|
+
* @throws Error When the dialect cannot execute this subquery.
|
|
1057
|
+
*/
|
|
1058
|
+
protected checkSubquery(_node: SelectNode): void;
|
|
1059
|
+
/**
|
|
1060
|
+
* The SQL operator for an array containment/overlap test.
|
|
1061
|
+
*
|
|
1062
|
+
* Only PostgreSQL has native arrays; the other dialects throw rather than
|
|
1063
|
+
* emitting an operator that means something else there.
|
|
1064
|
+
*
|
|
1065
|
+
* @param op The array operator name.
|
|
1066
|
+
* @returns The SQL operator text.
|
|
1067
|
+
* @throws Error On a dialect without native array support.
|
|
1068
|
+
*/
|
|
1069
|
+
protected arrayOperator(op: "contains" | "containedBy" | "overlaps"): string;
|
|
626
1070
|
/**
|
|
627
1071
|
* Quote an identifier (column/table) for the active dialect.
|
|
628
1072
|
*
|
|
@@ -634,10 +1078,83 @@ declare abstract class BaseDialect {
|
|
|
634
1078
|
protected quoteId(name: string): string;
|
|
635
1079
|
/** Compile any node to `{ sql, params }`. */
|
|
636
1080
|
compile(node: QueryNode): CompiledQuery;
|
|
637
|
-
/**
|
|
1081
|
+
/**
|
|
1082
|
+
* Render a qualified `alias.column` ref as `"alias"."column"`, translating the
|
|
1083
|
+
* property name to the real column name for that alias's model.
|
|
1084
|
+
*
|
|
1085
|
+
* @param ref The `alias.property` reference (a bare name is left unqualified).
|
|
1086
|
+
* @param names The node's per-alias name maps, if any source renames columns.
|
|
1087
|
+
* @returns The quoted, qualified identifier.
|
|
1088
|
+
*/
|
|
638
1089
|
private qualify;
|
|
1090
|
+
/**
|
|
1091
|
+
* Quote a column identifier, translating the model property name to the real
|
|
1092
|
+
* database column name first.
|
|
1093
|
+
*
|
|
1094
|
+
* `names` is `undefined` for a model that renames nothing — the overwhelmingly
|
|
1095
|
+
* common case — so this stays a single lookup plus the memoized quote.
|
|
1096
|
+
*
|
|
1097
|
+
* @param prop The model property name as written in the builder.
|
|
1098
|
+
* @param names The node's property → column map, if any.
|
|
1099
|
+
* @returns The quoted database identifier.
|
|
1100
|
+
*/
|
|
1101
|
+
protected columnId(prop: string, names: NameMap | undefined): string;
|
|
1102
|
+
/**
|
|
1103
|
+
* Render a {@link SqlExpression} inline, binding the parameters it carries.
|
|
1104
|
+
*
|
|
1105
|
+
* This is what keeps `set({ attempts: sql.raw("attempts + 1") })` an expression
|
|
1106
|
+
* instead of a bound object: the fragment goes into the statement text, and
|
|
1107
|
+
* only a `sql.expr` template's interpolations become parameters.
|
|
1108
|
+
*
|
|
1109
|
+
* @param expr The branded expression.
|
|
1110
|
+
* @param params The parameter collector for the statement being compiled.
|
|
1111
|
+
* @returns The SQL text of the expression.
|
|
1112
|
+
*/
|
|
1113
|
+
protected renderExpression(expr: SqlExpression, params: Params): string;
|
|
1114
|
+
/** Render one write value: a SQL expression inline, anything else as a parameter. */
|
|
1115
|
+
protected renderValue(value: unknown, params: Params): string;
|
|
1116
|
+
/**
|
|
1117
|
+
* Render a row-level locking clause (`FOR UPDATE ...`).
|
|
1118
|
+
*
|
|
1119
|
+
* Standard on PostgreSQL and MySQL 8.0+; SQLite overrides it to throw.
|
|
1120
|
+
*
|
|
1121
|
+
* @param lock The locking clause from the node.
|
|
1122
|
+
* @returns The SQL text, leading space included.
|
|
1123
|
+
*/
|
|
1124
|
+
protected renderLock(lock: LockClause): string;
|
|
1125
|
+
/**
|
|
1126
|
+
* Compile a SELECT.
|
|
1127
|
+
*
|
|
1128
|
+
* Two alias rules differ between clauses and are handled here: PostgreSQL does
|
|
1129
|
+
* NOT accept a `SELECT` alias in `HAVING`, so an aggregate key is re-emitted as
|
|
1130
|
+
* its expression (`COUNT(*) > $1`), a form every dialect accepts; `ORDER BY`,
|
|
1131
|
+
* by contrast, accepts the output alias everywhere, so it is emitted as
|
|
1132
|
+
* written.
|
|
1133
|
+
*
|
|
1134
|
+
* @param node The select AST.
|
|
1135
|
+
* @param params The parameter collector.
|
|
1136
|
+
* @returns The SQL text.
|
|
1137
|
+
*/
|
|
639
1138
|
private compileSelect;
|
|
1139
|
+
/**
|
|
1140
|
+
* Compile an INSERT.
|
|
1141
|
+
*
|
|
1142
|
+
* Takes the cached fast path only when the statement text is a pure function of
|
|
1143
|
+
* its structure. A SQL expression among the values, or a conflict predicate,
|
|
1144
|
+
* makes the text depend on the values themselves — those compile uncached, in
|
|
1145
|
+
* SQL order, so placeholder positions stay correct.
|
|
1146
|
+
*/
|
|
640
1147
|
private compileInsert;
|
|
1148
|
+
/**
|
|
1149
|
+
* Compile an INSERT without the template cache, rendering clauses in statement
|
|
1150
|
+
* order so every parameter is bound at the position it appears.
|
|
1151
|
+
*
|
|
1152
|
+
* @param node The insert node.
|
|
1153
|
+
* @param columns The column keys shared by every row.
|
|
1154
|
+
* @param params The parameter collector.
|
|
1155
|
+
* @returns The SQL text.
|
|
1156
|
+
*/
|
|
1157
|
+
private compileInsertDirect;
|
|
641
1158
|
/**
|
|
642
1159
|
* The INSERT SQL template for a given structure, cached across calls.
|
|
643
1160
|
*
|
|
@@ -649,24 +1166,74 @@ declare abstract class BaseDialect {
|
|
|
649
1166
|
private insertTemplate;
|
|
650
1167
|
/**
|
|
651
1168
|
* Render the conflict-handling clause. Standard SQL (SQLite/PostgreSQL) uses
|
|
652
|
-
* `ON CONFLICT (...) DO NOTHING | DO UPDATE SET
|
|
1169
|
+
* `ON CONFLICT (...) [WHERE predicate] DO NOTHING | DO UPDATE SET ... [WHERE ...]`;
|
|
1170
|
+
* MySQL overrides this.
|
|
1171
|
+
*
|
|
1172
|
+
* The index predicate is rendered before the `DO UPDATE` assignments because
|
|
1173
|
+
* that is where it sits in the statement, so its parameters bind first.
|
|
653
1174
|
*
|
|
654
1175
|
* @param onConflict The conflict clause from the node.
|
|
655
1176
|
* @param conflictCols The columns to overwrite on `DO UPDATE` (empty for nothing).
|
|
656
|
-
* @param
|
|
1177
|
+
* @param nextValue Yields the SQL for the next `DO UPDATE` assignment value.
|
|
1178
|
+
* @param names The node's property → column map, if any.
|
|
1179
|
+
* @param params The parameter collector, for the predicates.
|
|
1180
|
+
* @returns The SQL text, leading space included.
|
|
657
1181
|
*/
|
|
658
|
-
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[],
|
|
1182
|
+
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextValue: () => string, names: NameMap | undefined, params: Params): string;
|
|
659
1183
|
private compileUpdate;
|
|
660
1184
|
private compileDelete;
|
|
661
1185
|
private compileJoin;
|
|
662
|
-
protected compileReturning(returning: readonly string[] | "*" | null): string;
|
|
1186
|
+
protected compileReturning(returning: readonly string[] | "*" | null, names?: NameMap | undefined): string;
|
|
663
1187
|
/**
|
|
664
1188
|
* Compile a condition tree (fields / and / or / not) to SQL. `idFor` renders a
|
|
665
1189
|
* key to a quoted identifier — `quoteId` for single-table, `qualify` for joins —
|
|
666
1190
|
* so select/update/delete/join all share this one compiler.
|
|
667
1191
|
*/
|
|
668
1192
|
private compileCondition;
|
|
1193
|
+
/**
|
|
1194
|
+
* Render one side of a comparison.
|
|
1195
|
+
*
|
|
1196
|
+
* A column reference goes through `idFor`, so an explicit `.name()` mapping and
|
|
1197
|
+
* join qualification apply here exactly as they do in the object form of
|
|
1198
|
+
* `where` — `col()` is not a way around them. Only a `value` node binds.
|
|
1199
|
+
*
|
|
1200
|
+
* @param node The expression AST.
|
|
1201
|
+
* @param params The parameter collector.
|
|
1202
|
+
* @param idFor The identifier resolver for the enclosing statement.
|
|
1203
|
+
* @returns The SQL text of the expression.
|
|
1204
|
+
*/
|
|
1205
|
+
private renderExpr;
|
|
1206
|
+
/**
|
|
1207
|
+
* Compile a comparison whose right-hand side is another expression rather than
|
|
1208
|
+
* a bound value (`total > paid`, `lower(a) = lower(b)`).
|
|
1209
|
+
*
|
|
1210
|
+
* The list and null operators are excluded: `IN`, `BETWEEN` and `IS NULL` take
|
|
1211
|
+
* a value operand, and accepting an expression there would silently compile to
|
|
1212
|
+
* something else.
|
|
1213
|
+
*
|
|
1214
|
+
* @param left The rendered left-hand side.
|
|
1215
|
+
* @param op The operator name.
|
|
1216
|
+
* @param right The rendered right-hand side.
|
|
1217
|
+
* @returns The SQL text of the predicate.
|
|
1218
|
+
* @throws Error When the operator needs a value operand.
|
|
1219
|
+
*/
|
|
1220
|
+
private compileExprOperator;
|
|
669
1221
|
private compileOperator;
|
|
1222
|
+
/**
|
|
1223
|
+
* Compile `IN` / `NOT IN`, whose operand is either a value list or a
|
|
1224
|
+
* single-column subquery.
|
|
1225
|
+
*
|
|
1226
|
+
* The subquery is rendered at the position it appears in the outer statement
|
|
1227
|
+
* and shares the same parameter collector, so its own placeholders land in the
|
|
1228
|
+
* right order — and it keeps its own `names` map, since the inner model may use
|
|
1229
|
+
* a different naming convention than the outer one.
|
|
1230
|
+
*
|
|
1231
|
+
* @param id The quoted column identifier being tested.
|
|
1232
|
+
* @param operand A list of values, or a {@link Subquery}.
|
|
1233
|
+
* @param params The parameter collector for the statement being compiled.
|
|
1234
|
+
* @param negate True for `NOT IN`.
|
|
1235
|
+
* @returns The SQL text of the predicate.
|
|
1236
|
+
*/
|
|
670
1237
|
private compileIn;
|
|
671
1238
|
}
|
|
672
1239
|
/** SQLite dialect: `?` placeholders; `ILIKE` falls back to `LIKE` (ASCII-insensitive). */
|
|
@@ -674,12 +1241,19 @@ declare class SqliteDialect extends BaseDialect {
|
|
|
674
1241
|
readonly name: "sqlite";
|
|
675
1242
|
protected placeholder(): string;
|
|
676
1243
|
protected ilike(column: string, param: string): string;
|
|
1244
|
+
/**
|
|
1245
|
+
* SQLite has no row-level locking, so a lock request is an error rather than a
|
|
1246
|
+
* silently unlocked `SELECT` — a lock that does not exist only shows up as
|
|
1247
|
+
* duplicated work under production concurrency.
|
|
1248
|
+
*/
|
|
1249
|
+
protected renderLock(): string;
|
|
677
1250
|
}
|
|
678
|
-
/** PostgreSQL dialect: `$1` placeholders; native `ILIKE
|
|
1251
|
+
/** PostgreSQL dialect: `$1` placeholders; native `ILIKE`; native array operators. */
|
|
679
1252
|
declare class PostgresDialect extends BaseDialect {
|
|
680
1253
|
readonly name: "postgresql";
|
|
681
1254
|
protected placeholder(index: number): string;
|
|
682
1255
|
protected ilike(column: string, param: string): string;
|
|
1256
|
+
protected arrayOperator(op: "contains" | "containedBy" | "overlaps"): string;
|
|
683
1257
|
}
|
|
684
1258
|
/**
|
|
685
1259
|
* MySQL dialect: `?` placeholders, backtick identifiers, `ON DUPLICATE KEY
|
|
@@ -691,7 +1265,23 @@ declare class MysqlDialect extends BaseDialect {
|
|
|
691
1265
|
protected placeholder(): string;
|
|
692
1266
|
protected ilike(column: string, param: string): string;
|
|
693
1267
|
protected quoteId(name: string): string;
|
|
694
|
-
|
|
1268
|
+
/**
|
|
1269
|
+
* MySQL rejects `LIMIT` inside an `IN` subquery with
|
|
1270
|
+
* `ER_NOT_SUPPORTED_YET: This version of MySQL doesn't yet support
|
|
1271
|
+
* 'LIMIT & IN/ALL/ANY/SOME subquery'`. Failing at compile time names the fix
|
|
1272
|
+
* instead of surfacing that error from the driver at runtime.
|
|
1273
|
+
*/
|
|
1274
|
+
protected checkSubquery(node: SelectNode): void;
|
|
1275
|
+
protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextValue: () => string, names: NameMap | undefined): string;
|
|
1276
|
+
/**
|
|
1277
|
+
* MySQL has no `RETURNING`, so it cannot be compiled into a statement.
|
|
1278
|
+
*
|
|
1279
|
+
* `session.execute()` still honors `.returning()` on a **single-row INSERT** by
|
|
1280
|
+
* running the insert and reading the row back by key on the same connection —
|
|
1281
|
+
* that is execution, not compilation, so it never reaches here. Compiling a
|
|
1282
|
+
* node with `returning` directly is an error, rather than SQL that silently
|
|
1283
|
+
* returns nothing.
|
|
1284
|
+
*/
|
|
695
1285
|
protected compileReturning(returning: readonly string[] | "*" | null): string;
|
|
696
1286
|
}
|
|
697
1287
|
/** Get a dialect instance by name. */
|
|
@@ -749,7 +1339,7 @@ declare class NodeSqliteDriver implements SyncDriver {
|
|
|
749
1339
|
iterate(sql: string, params: readonly unknown[]): IterableIterator<Record<string, unknown>>;
|
|
750
1340
|
close(): void;
|
|
751
1341
|
}
|
|
752
|
-
type AnySelect = SelectBuilder<any, any>;
|
|
1342
|
+
type AnySelect = SelectBuilder<any, any, any>;
|
|
753
1343
|
type AnyInsert = InsertBuilder<any, any, any>;
|
|
754
1344
|
type GuardedUpdate = UpdateBuilder<any, true, any>;
|
|
755
1345
|
type GuardedDelete = DeleteBuilder<any, true, any>;
|
|
@@ -832,6 +1422,40 @@ declare class SyncSession {
|
|
|
832
1422
|
logger?: QueryLogger | undefined);
|
|
833
1423
|
/** Log, run, and error-wrap one raw statement. */
|
|
834
1424
|
private exec;
|
|
1425
|
+
/**
|
|
1426
|
+
* Run a raw, parameterized SQL statement (synchronous) — the runtime counterpart of the
|
|
1427
|
+
* migrations' `Op.execute`.
|
|
1428
|
+
*
|
|
1429
|
+
* A query builder never covers all of SQL, and without an escape hatch a single
|
|
1430
|
+
* unsupported query forces a whole second database stack alongside this one. Use
|
|
1431
|
+
* it for what the builder cannot yet express, and keep everything else typed.
|
|
1432
|
+
*
|
|
1433
|
+
* The statement goes through the same path as a compiled one: it is logged via
|
|
1434
|
+
* `onQuery`, wrapped in {@link QueryExecutionError} on failure, and runs on the
|
|
1435
|
+
* reserved connection inside `transaction()`.
|
|
1436
|
+
*
|
|
1437
|
+
* @param sql The statement text. Placeholders only (`$1` / `?` per dialect) —
|
|
1438
|
+
* never interpolate a value into this string.
|
|
1439
|
+
* @param params The bound parameters, in placeholder order.
|
|
1440
|
+
* @param options Pass `as` to coerce the returned rows with a model's column
|
|
1441
|
+
* types (and its column-name mapping).
|
|
1442
|
+
* @returns The result view over the returned rows.
|
|
1443
|
+
* @throws Error When `params` is not an array — the guard against calling this
|
|
1444
|
+
* with an interpolated string and no parameters by mistake.
|
|
1445
|
+
*
|
|
1446
|
+
* @example
|
|
1447
|
+
* ```ts
|
|
1448
|
+
* const claimed = await session.raw<OutboundRow>(
|
|
1449
|
+
* `UPDATE outbound_messages SET status = 'sending'
|
|
1450
|
+
* WHERE id = ANY($1) RETURNING *`,
|
|
1451
|
+
* [ids],
|
|
1452
|
+
* { as: Outbound },
|
|
1453
|
+
* ).all();
|
|
1454
|
+
* ```
|
|
1455
|
+
*/
|
|
1456
|
+
raw<Row = Record<string, unknown>>(sql: string, params?: readonly unknown[], options?: {
|
|
1457
|
+
readonly as?: ModelClass;
|
|
1458
|
+
}): SyncResult<Row>;
|
|
835
1459
|
/** Compile, run, and coerce a builder into a result. */
|
|
836
1460
|
execute<B extends Executable>(builder: B): SyncResult<RowOf<B>>;
|
|
837
1461
|
/** Run `fn` inside a transaction: commit on success, rollback on throw. */
|
|
@@ -858,7 +1482,58 @@ declare class AsyncSession {
|
|
|
858
1482
|
logger?: QueryLogger | undefined);
|
|
859
1483
|
/** Log, run, and error-wrap one raw statement. */
|
|
860
1484
|
private exec;
|
|
1485
|
+
/**
|
|
1486
|
+
* Run a raw, parameterized SQL statement — the runtime counterpart of the
|
|
1487
|
+
* migrations' `Op.execute`.
|
|
1488
|
+
*
|
|
1489
|
+
* A query builder never covers all of SQL, and without an escape hatch a single
|
|
1490
|
+
* unsupported query forces a whole second database stack alongside this one. Use
|
|
1491
|
+
* it for what the builder cannot yet express, and keep everything else typed.
|
|
1492
|
+
*
|
|
1493
|
+
* The statement goes through the same path as a compiled one: it is logged via
|
|
1494
|
+
* `onQuery`, wrapped in {@link QueryExecutionError} on failure, and runs on the
|
|
1495
|
+
* reserved connection inside `transaction()`.
|
|
1496
|
+
*
|
|
1497
|
+
* @param sql The statement text. Placeholders only (`$1` / `?` per dialect) —
|
|
1498
|
+
* never interpolate a value into this string.
|
|
1499
|
+
* @param params The bound parameters, in placeholder order.
|
|
1500
|
+
* @param options Pass `as` to coerce the returned rows with a model's column
|
|
1501
|
+
* types (and its column-name mapping).
|
|
1502
|
+
* @returns The result view over the returned rows.
|
|
1503
|
+
* @throws Error When `params` is not an array — the guard against calling this
|
|
1504
|
+
* with an interpolated string and no parameters by mistake.
|
|
1505
|
+
*
|
|
1506
|
+
* @example
|
|
1507
|
+
* ```ts
|
|
1508
|
+
* const claimed = await session.raw<OutboundRow>(
|
|
1509
|
+
* `UPDATE outbound_messages SET status = 'sending'
|
|
1510
|
+
* WHERE id = ANY($1) RETURNING *`,
|
|
1511
|
+
* [ids],
|
|
1512
|
+
* { as: Outbound },
|
|
1513
|
+
* ).all();
|
|
1514
|
+
* ```
|
|
1515
|
+
*/
|
|
1516
|
+
raw<Row = Record<string, unknown>>(sql: string, params?: readonly unknown[], options?: {
|
|
1517
|
+
readonly as?: ModelClass;
|
|
1518
|
+
}): AsyncResult<Row>;
|
|
861
1519
|
execute<B extends Executable>(builder: B): AsyncResult<RowOf<B>>;
|
|
1520
|
+
/**
|
|
1521
|
+
* Honor `.returning()` on a dialect without `RETURNING`, by inserting and then
|
|
1522
|
+
* reading the row back by key.
|
|
1523
|
+
*
|
|
1524
|
+
* Both statements must run on **one** connection, because `LAST_INSERT_ID()` is
|
|
1525
|
+
* per-connection: outside a transaction the pooled driver is reserved for the
|
|
1526
|
+
* pair; inside one, the session already holds a pinned connection (a reserved
|
|
1527
|
+
* driver exposes no `reserve`), so it runs there directly.
|
|
1528
|
+
*
|
|
1529
|
+
* @param builder The insert builder, for its source model.
|
|
1530
|
+
* @param node The insert AST, whose `returning` drives the read-back.
|
|
1531
|
+
* @returns The result view over the read-back row.
|
|
1532
|
+
* @throws Error When the insert writes more than one row — `LAST_INSERT_ID()`
|
|
1533
|
+
* identifies only the first, and the rest are consecutive only under some
|
|
1534
|
+
* auto-increment lock modes.
|
|
1535
|
+
*/
|
|
1536
|
+
private insertAndReadBack;
|
|
862
1537
|
/** Lazily iterate result rows. Uses driver streaming when available. */
|
|
863
1538
|
stream<B extends Executable>(builder: B): AsyncIterableIterator<RowOf<B>>;
|
|
864
1539
|
transaction<T>(fn: (tx: AsyncSession) => Promise<T>): Promise<T>;
|
|
@@ -911,6 +1586,18 @@ declare class AsyncEngine {
|
|
|
911
1586
|
/** `await using engine = createEngine(...)` closes the pool when the scope exits. */
|
|
912
1587
|
[Symbol.asyncDispose](): Promise<void>;
|
|
913
1588
|
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Adapt a sync **or** async driver to the async interface.
|
|
1591
|
+
*
|
|
1592
|
+
* `await` normalizes both: a sync driver returns a plain value, an async one a
|
|
1593
|
+
* promise, and awaiting either yields the result. That is what lets the migration
|
|
1594
|
+
* CLI take one code path instead of branching on a difference it cannot detect
|
|
1595
|
+
* from the object's shape.
|
|
1596
|
+
*
|
|
1597
|
+
* @param driver Either driver flavor.
|
|
1598
|
+
* @returns An async driver delegating to it.
|
|
1599
|
+
*/
|
|
1600
|
+
declare function toAsyncDriver(driver: SyncDriver | AsyncDriver): AsyncDriver;
|
|
914
1601
|
/**
|
|
915
1602
|
* Create a **synchronous** engine from a database URL. SQLite only — PostgreSQL
|
|
916
1603
|
* has no sane synchronous driver in Node, so a Postgres URL throws, pointing at
|
|
@@ -1168,7 +1855,7 @@ interface ColumnFlags {
|
|
|
1168
1855
|
* generic types (e.g. `String` → varchar, `Text` → text). Dialect renderers
|
|
1169
1856
|
* (Phase 4/6) map each kind + meta to concrete SQL per database.
|
|
1170
1857
|
*/
|
|
1171
|
-
type ColumnTypeKind = "smallint" | "integer" | "bigint" | "numeric" | "real" | "double" | "varchar" | "text" | "char" | "boolean" | "date" | "time" | "datetime" | "timestamp" | "blob" | "json" | "uuid" | "enum";
|
|
1858
|
+
type ColumnTypeKind = "smallint" | "integer" | "bigint" | "numeric" | "real" | "double" | "varchar" | "text" | "char" | "boolean" | "date" | "time" | "datetime" | "timestamp" | "blob" | "json" | "uuid" | "enum" | "array";
|
|
1172
1859
|
/** Parameters that refine a column type and feed the migration IR / DDL. */
|
|
1173
1860
|
interface ColumnTypeMeta {
|
|
1174
1861
|
/** Max length for `varchar`/`char`. */
|
|
@@ -1183,6 +1870,8 @@ interface ColumnTypeMeta {
|
|
|
1183
1870
|
readonly values?: readonly string[] | undefined;
|
|
1184
1871
|
/** Render as `JSONB` (PostgreSQL) instead of `JSON`. */
|
|
1185
1872
|
readonly jsonb?: boolean | undefined;
|
|
1873
|
+
/** The element type of an `array` column (`text[]`, `integer[]`). */
|
|
1874
|
+
readonly element?: ColumnType | undefined;
|
|
1186
1875
|
}
|
|
1187
1876
|
/** A structured, dialect-neutral column type descriptor. */
|
|
1188
1877
|
interface ColumnType {
|
|
@@ -1193,10 +1882,14 @@ interface ColumnType {
|
|
|
1193
1882
|
* A portable default expression. The token is dialect-neutral; the renderer
|
|
1194
1883
|
* (Phase 4/6) maps it to the right SQL per database — e.g. `"now"` becomes
|
|
1195
1884
|
* `CURRENT_TIMESTAMP` on SQLite and `now()` on PostgreSQL. Use `{ raw }` as an
|
|
1196
|
-
* escape hatch for a verbatim SQL fragment
|
|
1885
|
+
* escape hatch for a verbatim SQL fragment, or `{ parts }` for a parameterized
|
|
1886
|
+
* fragment built by the `sql.expr` tagged template (one bound parameter per gap
|
|
1887
|
+
* between consecutive parts).
|
|
1197
1888
|
*/
|
|
1198
1889
|
type PortableExpression = "now" | "current_date" | "current_time" | "uuidv4" | {
|
|
1199
1890
|
readonly raw: string;
|
|
1891
|
+
} | {
|
|
1892
|
+
readonly parts: readonly string[];
|
|
1200
1893
|
};
|
|
1201
1894
|
/**
|
|
1202
1895
|
* A column default. Either a constant literal value or a server-side expression
|
|
@@ -1210,18 +1903,79 @@ type DefaultValue = {
|
|
|
1210
1903
|
readonly kind: "expression";
|
|
1211
1904
|
readonly expression: PortableExpression;
|
|
1212
1905
|
};
|
|
1213
|
-
/**
|
|
1906
|
+
/**
|
|
1907
|
+
* Brand marking a value as a SQL expression rather than a bound parameter.
|
|
1908
|
+
*
|
|
1909
|
+
* A plain object reaching `set()`/`values()` is a mistake (it would be bound as a
|
|
1910
|
+
* parameter and silently written as JSON or null); an object carrying this symbol
|
|
1911
|
+
* is deliberate, and the dialect renders it inline instead of binding it. Mirrors
|
|
1912
|
+
* how `Condition` is branded, so the check is a symbol lookup, not duck typing.
|
|
1913
|
+
*/
|
|
1914
|
+
declare const EXPRESSION: unique symbol;
|
|
1915
|
+
/**
|
|
1916
|
+
* A SQL expression, usable both as a column default (`.default(sql.now())`) and
|
|
1917
|
+
* as a write value (`.set({ attempts: sql.raw("attempts + 1") })`). The dialect
|
|
1918
|
+
* renders `expression` inline and binds `params` in the order of the fragment's
|
|
1919
|
+
* gaps.
|
|
1920
|
+
*/
|
|
1921
|
+
interface SqlExpression {
|
|
1922
|
+
readonly [EXPRESSION]: true;
|
|
1923
|
+
readonly kind: "expression";
|
|
1924
|
+
readonly expression: PortableExpression;
|
|
1925
|
+
/** Parameters bound into the fragment's gaps, in order (empty for a token). */
|
|
1926
|
+
readonly params: readonly unknown[];
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* Runtime guard: is this value a branded {@link SqlExpression}?
|
|
1930
|
+
*
|
|
1931
|
+
* @param value Any value handed to `set()`, `values()` or `.default()`.
|
|
1932
|
+
* @returns True when the value carries the expression brand.
|
|
1933
|
+
*/
|
|
1934
|
+
declare function isSqlExpression(value: unknown): value is SqlExpression;
|
|
1935
|
+
/**
|
|
1936
|
+
* Portable server-side expressions, à la SQLAlchemy's `func`.
|
|
1937
|
+
*
|
|
1938
|
+
* Every entry doubles as a column default and as a write value, so
|
|
1939
|
+
* `.default(sql.now())` and `.set({ updatedAt: sql.now() })` both work.
|
|
1940
|
+
*/
|
|
1214
1941
|
declare const sql: {
|
|
1215
1942
|
/** Current timestamp at insert (`CURRENT_TIMESTAMP` / `now()`). */
|
|
1216
|
-
readonly now: () =>
|
|
1943
|
+
readonly now: () => SqlExpression;
|
|
1217
1944
|
/** Current date. */
|
|
1218
|
-
readonly currentDate: () =>
|
|
1945
|
+
readonly currentDate: () => SqlExpression;
|
|
1219
1946
|
/** Current time. */
|
|
1220
|
-
readonly currentTime: () =>
|
|
1947
|
+
readonly currentTime: () => SqlExpression;
|
|
1221
1948
|
/** A freshly generated UUID v4 (`gen_random_uuid()` / portable fallback). */
|
|
1222
|
-
readonly uuidv4: () =>
|
|
1223
|
-
/**
|
|
1224
|
-
|
|
1949
|
+
readonly uuidv4: () => SqlExpression;
|
|
1950
|
+
/**
|
|
1951
|
+
* Escape hatch: a verbatim SQL expression rendered as-is, with no parameters.
|
|
1952
|
+
*
|
|
1953
|
+
* The fragment is interpolated into the statement untouched, so it must never
|
|
1954
|
+
* carry user input — use {@link sql.expr} when a value has to be bound.
|
|
1955
|
+
*
|
|
1956
|
+
* @param fragment The SQL text (e.g. `"attempts + 1"`).
|
|
1957
|
+
* @returns The expression, usable as a default and as a write value.
|
|
1958
|
+
*/
|
|
1959
|
+
readonly raw: (fragment: string) => SqlExpression;
|
|
1960
|
+
/**
|
|
1961
|
+
* A parameterized SQL expression, written as a tagged template. Static text is
|
|
1962
|
+
* SQL; every `${...}` interpolation becomes a bound parameter, so the fragment
|
|
1963
|
+
* is injection-safe by construction.
|
|
1964
|
+
*
|
|
1965
|
+
* Cannot be used as a column default — a `DEFAULT` clause has nowhere to bind
|
|
1966
|
+
* parameters; use {@link sql.raw} there.
|
|
1967
|
+
*
|
|
1968
|
+
* @param parts The static SQL segments supplied by the template tag.
|
|
1969
|
+
* @param values The interpolated values, bound in order.
|
|
1970
|
+
* @returns The expression, usable as a write value.
|
|
1971
|
+
*
|
|
1972
|
+
* @example
|
|
1973
|
+
* ```ts
|
|
1974
|
+
* update(Account).set({ balance: sql.expr`balance - ${amount}` }).where({ id });
|
|
1975
|
+
* // UPDATE "accounts" SET "balance" = balance - $1 WHERE "id" = $2
|
|
1976
|
+
* ```
|
|
1977
|
+
*/
|
|
1978
|
+
readonly expr: (parts: TemplateStringsArray, ...values: unknown[]) => SqlExpression;
|
|
1225
1979
|
};
|
|
1226
1980
|
/**
|
|
1227
1981
|
* A referential action for a foreign key's `ON DELETE` / `ON UPDATE` clause.
|
|
@@ -1258,6 +2012,8 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1258
2012
|
readonly onUpdateValue: DefaultValue | null;
|
|
1259
2013
|
/** The foreign-key reference this column points to, or `null` for none. */
|
|
1260
2014
|
readonly reference: ForeignKeyRef | null;
|
|
2015
|
+
/** An explicit database column name overriding the property name, or `null`. */
|
|
2016
|
+
readonly dbName: string | null;
|
|
1261
2017
|
/** Phantom: never read at runtime, only inspected by the type system. */
|
|
1262
2018
|
readonly [TYPE]: T;
|
|
1263
2019
|
constructor(type: ColumnType, flags: F,
|
|
@@ -1266,7 +2022,11 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1266
2022
|
/** The value re-applied on update (e.g. `updated_at`), or `null`. */
|
|
1267
2023
|
onUpdateValue?: DefaultValue | null,
|
|
1268
2024
|
/** The foreign-key reference this column points to, or `null` for none. */
|
|
1269
|
-
reference?: ForeignKeyRef | null
|
|
2025
|
+
reference?: ForeignKeyRef | null,
|
|
2026
|
+
/** An explicit database column name overriding the property name, or `null`. */
|
|
2027
|
+
dbName?: string | null);
|
|
2028
|
+
/** Clone this column with one facet replaced, carrying every other over. */
|
|
2029
|
+
private derive;
|
|
1270
2030
|
primaryKey(): Column<T, F & {
|
|
1271
2031
|
primaryKey: true;
|
|
1272
2032
|
hasDefault: true;
|
|
@@ -1281,6 +2041,29 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1281
2041
|
unique(): Column<T, F & {
|
|
1282
2042
|
unique: true;
|
|
1283
2043
|
}>;
|
|
2044
|
+
/**
|
|
2045
|
+
* Map this property to a differently-named database column, à la SQLAlchemy's
|
|
2046
|
+
* `mapped_column("consumer_name")` (Django's `db_column`, Prisma's `@map`).
|
|
2047
|
+
*
|
|
2048
|
+
* The override applies everywhere the name reaches SQL — select, insert,
|
|
2049
|
+
* update, delete, where, order by, group by, returning, conflict targets, the
|
|
2050
|
+
* migration IR and the drift check — while the TypeScript row keeps the
|
|
2051
|
+
* property name. Use it to keep a `snake_case` schema behind a `camelCase`
|
|
2052
|
+
* model; {@link Model.naming} does the same for a whole table at once.
|
|
2053
|
+
*
|
|
2054
|
+
* @param dbName The real column name in the database.
|
|
2055
|
+
* @returns A new column bound to that name.
|
|
2056
|
+
* @throws Error When `dbName` is empty.
|
|
2057
|
+
*
|
|
2058
|
+
* @example
|
|
2059
|
+
* ```ts
|
|
2060
|
+
* class ApiKey extends Model {
|
|
2061
|
+
* static tablename = "api_keys";
|
|
2062
|
+
* consumerName = column.text().name("consumer_name").notNull();
|
|
2063
|
+
* }
|
|
2064
|
+
* ```
|
|
2065
|
+
*/
|
|
2066
|
+
name(dbName: string): Column<T, F>;
|
|
1284
2067
|
/**
|
|
1285
2068
|
* Declare a foreign-key reference to another table's column, à la SQLAlchemy's
|
|
1286
2069
|
* `mapped_column(ForeignKey("table.column", ondelete=...))`. DDL-only — does
|
|
@@ -1295,6 +2078,11 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1295
2078
|
/**
|
|
1296
2079
|
* Set the insert-time default: a constant value of type `T`, or a portable
|
|
1297
2080
|
* server-side expression from {@link sql} (e.g. `sql.now()`, `sql.uuidv4()`).
|
|
2081
|
+
*
|
|
2082
|
+
* @param value The literal default, or a {@link sql} expression.
|
|
2083
|
+
* @returns A new column carrying the default.
|
|
2084
|
+
* @throws Error When given a `sql.expr` fragment — a `DEFAULT` clause has
|
|
2085
|
+
* nowhere to bind parameters; use `sql.raw()` for a verbatim expression.
|
|
1298
2086
|
*/
|
|
1299
2087
|
default(value: T | DefaultValue): Column<T, F & {
|
|
1300
2088
|
hasDefault: true;
|
|
@@ -1302,6 +2090,10 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
|
|
|
1302
2090
|
/**
|
|
1303
2091
|
* Re-apply a value whenever the row is updated (e.g. an `updated_at` column
|
|
1304
2092
|
* with `sql.now()`). Mirrors SQLAlchemy's `onupdate`.
|
|
2093
|
+
*
|
|
2094
|
+
* @param value The literal value, or a {@link sql} expression.
|
|
2095
|
+
* @returns A new column carrying the on-update value.
|
|
2096
|
+
* @throws Error When given a `sql.expr` fragment (see {@link Column.default}).
|
|
1305
2097
|
*/
|
|
1306
2098
|
onUpdate(value: T | DefaultValue): Column<T, F>;
|
|
1307
2099
|
}
|
|
@@ -1370,6 +2162,26 @@ declare const column: {
|
|
|
1370
2162
|
readonly uuid: () => Column<string, ColumnFlags>;
|
|
1371
2163
|
/** `ENUM(...values)` → a string-literal union of the given values. */
|
|
1372
2164
|
readonly enum: <const E extends string>(...values: E[]) => Column<E, ColumnFlags>;
|
|
2165
|
+
/**
|
|
2166
|
+
* A PostgreSQL array column (`text[]`, `integer[]`) → `T[]`.
|
|
2167
|
+
*
|
|
2168
|
+
* PostgreSQL only: SQLite and MySQL have no native array type, and rendering
|
|
2169
|
+
* one as JSON there would give the same model different semantics per dialect
|
|
2170
|
+
* (`@>` and `&&` work on one and not the other), so the DDL renderer throws
|
|
2171
|
+
* for those dialects instead of falling back silently.
|
|
2172
|
+
*
|
|
2173
|
+
* @param element The element column (its type, not its flags, is what is used).
|
|
2174
|
+
* @returns A column whose inferred type is an array of the element's type.
|
|
2175
|
+
*
|
|
2176
|
+
* @example
|
|
2177
|
+
* ```ts
|
|
2178
|
+
* class ApiKey extends Model {
|
|
2179
|
+
* static tablename = "api_keys";
|
|
2180
|
+
* scopes = column.array(column.text()).notNull().default(["send"]);
|
|
2181
|
+
* }
|
|
2182
|
+
* ```
|
|
2183
|
+
*/
|
|
2184
|
+
readonly array: <T>(element: Column<T, ColumnFlags>) => Column<T[], ColumnFlags>;
|
|
1373
2185
|
};
|
|
1374
2186
|
/**
|
|
1375
2187
|
* A table-level constraint declared via a model's `static tableArgs`. Mirrors
|
|
@@ -1414,6 +2226,16 @@ declare function foreignKey(columns: string[], refTable: string, refColumns: str
|
|
|
1414
2226
|
onDelete?: FkAction;
|
|
1415
2227
|
onUpdate?: FkAction;
|
|
1416
2228
|
}): TableConstraint;
|
|
2229
|
+
/**
|
|
2230
|
+
* How property names map to database column names when a column declares no
|
|
2231
|
+
* explicit {@link Column.name}.
|
|
2232
|
+
*
|
|
2233
|
+
* - `"preserve"` (default) — the column name is the property name, verbatim.
|
|
2234
|
+
* - `"snake_case"` — `consumerName` becomes `consumer_name`.
|
|
2235
|
+
*/
|
|
2236
|
+
type NamingStrategy = "preserve" | "snake_case";
|
|
2237
|
+
/** Convert a `camelCase` / `PascalCase` identifier to `snake_case`. */
|
|
2238
|
+
declare function toSnakeCase(name: string): string;
|
|
1417
2239
|
/** Base class every model extends, SQLAlchemy-declarative style. */
|
|
1418
2240
|
declare abstract class Model {
|
|
1419
2241
|
static tablename: string;
|
|
@@ -1423,6 +2245,12 @@ declare abstract class Model {
|
|
|
1423
2245
|
* `__table_args__`.
|
|
1424
2246
|
*/
|
|
1425
2247
|
static tableArgs?: () => readonly TableConstraint[];
|
|
2248
|
+
/**
|
|
2249
|
+
* How to derive column names from property names (default `"preserve"`). Set
|
|
2250
|
+
* `"snake_case"` to keep a `snake_case` schema behind a `camelCase` model
|
|
2251
|
+
* without annotating every column; {@link Column.name} overrides it per column.
|
|
2252
|
+
*/
|
|
2253
|
+
static naming?: NamingStrategy;
|
|
1426
2254
|
}
|
|
1427
2255
|
/**
|
|
1428
2256
|
* Reflect a model class into its column map at runtime, keyed by column name.
|
|
@@ -1438,6 +2266,32 @@ declare abstract class Model {
|
|
|
1438
2266
|
* @returns A record of column name → `Column` instance (do not mutate).
|
|
1439
2267
|
*/
|
|
1440
2268
|
declare function columnsOf(model: ModelClass): Record<string, Column<unknown>>;
|
|
2269
|
+
/** A mapping between property names and database column names. */
|
|
2270
|
+
type NameMap = Readonly<Record<string, string>>;
|
|
2271
|
+
/**
|
|
2272
|
+
* The property → database-column map for a model, or `null` when every column
|
|
2273
|
+
* keeps its property name.
|
|
2274
|
+
*
|
|
2275
|
+
* `null` is the common case and the fast path: builders and the row coercer skip
|
|
2276
|
+
* translation entirely, so a model that renames nothing costs nothing. The map
|
|
2277
|
+
* is memoized per class, like {@link columnsOf}.
|
|
2278
|
+
*
|
|
2279
|
+
* @param model The model class.
|
|
2280
|
+
* @returns The name map, or `null` when no column is renamed.
|
|
2281
|
+
* @throws Error When two properties resolve to the same column name.
|
|
2282
|
+
*/
|
|
2283
|
+
declare function columnNamesOf(model: ModelClass): NameMap | null;
|
|
2284
|
+
/**
|
|
2285
|
+
* The database-column → property map for a model, or `null` when every column
|
|
2286
|
+
* keeps its property name. The inverse of {@link columnNamesOf}, used to map
|
|
2287
|
+
* driver rows back into property space.
|
|
2288
|
+
*
|
|
2289
|
+
* @param model The model class.
|
|
2290
|
+
* @returns The inverse name map, or `null` when no column is renamed.
|
|
2291
|
+
*/
|
|
2292
|
+
declare function columnPropsOf(model: ModelClass): NameMap | null;
|
|
2293
|
+
/** Resolve one property name to its database column name. */
|
|
2294
|
+
declare function dbColumn(names: NameMap | null | undefined, prop: string): string;
|
|
1441
2295
|
/** Pull the static type out of a Column. */
|
|
1442
2296
|
type ColType<C> = C extends Column<infer T, infer _F> ? T : never;
|
|
1443
2297
|
/** Keys of the model instance whose values are Columns. */
|
|
@@ -1448,6 +2302,7 @@ type ColumnKeys<M> = {
|
|
|
1448
2302
|
type ModelClass = (new () => Model) & {
|
|
1449
2303
|
tablename: string;
|
|
1450
2304
|
tableArgs?: () => readonly TableConstraint[];
|
|
2305
|
+
naming?: NamingStrategy;
|
|
1451
2306
|
};
|
|
1452
2307
|
/** Flatten an intersection into a single object literal for clean inference. */
|
|
1453
2308
|
type Simplify<T> = {
|
|
@@ -1485,4 +2340,4 @@ type InferInsert<C extends ModelClass> = Simplify<{
|
|
|
1485
2340
|
[K in Exclude<ColumnKeys<InstanceType<C>>, OptionalInsertKeys<InstanceType<C>>>]: ColValue<InstanceType<C>[K]>;
|
|
1486
2341
|
}>;
|
|
1487
2342
|
|
|
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 };
|
|
2343
|
+
export { ActiveRecord, type ActiveRecordManager, Agg, type AggregateTerm, type AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, type BelongsTo, type ColRef, type ColType, Column, type ColumnFlags, type ColumnType, type ColumnTypeKind, type ColumnTypeMeta, type CompiledQuery, type CondNode, type Condition, type DefaultValue, DeleteBuilder, type DeleteNode, type Dialect, type DriverResult, type EngineOptions, type Executable, type ExprNode, Expression, type FkAction, type ForeignKeyOptions, type ForeignKeyRef, type HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, type LockClause, type LockOptions, Model, type ModelClass, MysqlDialect, type NameMap, type NamingStrategy, NoResultError, NodeSqliteDriver, OPERATORS, type OnConflict, type OnConflictOptions, type OnConflictUpdateOptions, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, Params, type ParsedDatabaseUrl, type PoolOptions, type PortableExpression, PostgresDialect, QueryExecutionError, type QueryLogger, type QueryNode, RecordNotFound, type Relation, type RelationValue, type ReservedAsyncDriver, type Returning, type RowOf, SelectBuilder, type SelectNode, type SortDirection, type Sources, type SqlExpression, SqliteDialect, type Subquery, type SyncDriver, SyncEngine, SyncResult, SyncSession, type TableConstraint, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, type WritePatch, type WriteValues, activeRecord, and, avg, belongsTo, col, column, columnNamesOf, columnPropsOf, columnsOf, count, createEngine, createSyncEngine, dbColumn, del, detectDialect, fn, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, isExpression, isSqlExpression, isSubquery, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toAsyncDriver, toCondNode, toDict, toJSON, toSnakeCase, unique, update, val };
|