@vibeorm/sql 4.3.0 → 5.0.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/dist/ast.d.ts +101 -8
- package/dist/codecs.d.ts +44 -0
- package/dist/dialect.d.ts +52 -4
- package/dist/dialects/migration-inventory.d.ts +58 -1
- package/dist/dialects/migration-objects.d.ts +36 -0
- package/dist/dialects/migration-visibility.d.ts +6 -1
- package/dist/dialects/mysql.d.ts +3 -2
- package/dist/dialects/postgres-rls.d.ts +16 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.js +314 -81
- package/dist/index.js.map +12 -12
- package/package.json +2 -2
package/dist/ast.d.ts
CHANGED
|
@@ -22,7 +22,13 @@ export type ColRef = {
|
|
|
22
22
|
* `castText` renders a dialect text cast and preserves `alias ?? name`,
|
|
23
23
|
* including timestamp identity before driver Date truncation. PostgreSQL
|
|
24
24
|
* uses `"col"::text`; SQLite/MySQL use CAST AS TEXT/CHAR. `encodeBase64`
|
|
25
|
-
* is postgres-only and renders `encode("col", 'base64')`.
|
|
25
|
+
* is postgres-only and renders `encode("col", 'base64')`.
|
|
26
|
+
* `encodeArrayBase64` is postgres-only and renders
|
|
27
|
+
* `encode(array_send("col"), 'base64')` — a `bytea[]` column's binary array
|
|
28
|
+
* form (dimensions, NULL elements, raw element bytes) as base64: faithful
|
|
29
|
+
* whatever the session's `bytea_output`, keeping a NULL column (`NULL`), an
|
|
30
|
+
* empty array and NULL elements distinct (5.0 lane V; the lateral subselect's
|
|
31
|
+
* `Bytes[]` form, decoded by the runtime's JSON-transport plan). Other users:
|
|
26
32
|
* the lateral subselect (SQL review B3: raw `to_jsonb` would ship BigInt/Decimal as float64 JSON
|
|
27
33
|
* numbers and Bytes as `\x` hex text), and every row projection of a
|
|
28
34
|
* `Float[]`/`Json[]` column (bun:sql's array parser refuses float arrays
|
|
@@ -30,7 +36,7 @@ export type ColRef = {
|
|
|
30
36
|
* the runtime parses the array literal text itself). Never set on
|
|
31
37
|
* filter/order refs.
|
|
32
38
|
*/
|
|
33
|
-
readonly transform?: "castText" | "encodeBase64" | "jsonText";
|
|
39
|
+
readonly transform?: "castText" | "encodeBase64" | "encodeArrayBase64" | "jsonText";
|
|
34
40
|
/**
|
|
35
41
|
* Comparison/order/aggregate cast, sqlite Decimal only (SQL review B4):
|
|
36
42
|
* Decimal stores as exact TEXT there and text comparison is lexicographic —
|
|
@@ -456,7 +462,11 @@ export type OrderTerm = OrderByColumn | OrderByAggregate | OrderBySubquery;
|
|
|
456
462
|
/**
|
|
457
463
|
* One `LEFT JOIN LATERAL (…) AS alias ON true` clause aggregating a correlated
|
|
458
464
|
* subquery into a single JSON value per outer row — the "join" relation-loading
|
|
459
|
-
* strategy (postgres/pglite
|
|
465
|
+
* strategy (postgres/pglite, and MySQL 8.0.14+ since lane J; gated on
|
|
466
|
+
* `capabilities.lateralJoin` and rendered through `SqlDialect.lateralJson`).
|
|
467
|
+
* MySQL renders positional rows only (`JSON_ARRAY`, `JSON_ARRAYAGG`, `ON
|
|
468
|
+
* true`); its aggregate cannot order, so an ordered list level carries a
|
|
469
|
+
* `select.rowNumber` without partition — rendered as the row's last slot.
|
|
460
470
|
*
|
|
461
471
|
* Renders (agg `jsonArray`):
|
|
462
472
|
* `LEFT JOIN LATERAL (SELECT COALESCE(json_agg(to_json("__sub".*)), '[]'::json)
|
|
@@ -694,6 +704,31 @@ export type KeyPage = {
|
|
|
694
704
|
/** Output name of the rank column. */
|
|
695
705
|
readonly rankAlias: string;
|
|
696
706
|
};
|
|
707
|
+
/**
|
|
708
|
+
* Statement-count pass EPIC 4 (round-3 ST-07): bound key tuples as the FROM
|
|
709
|
+
* of a select (`SelectStatement.fromKeys`) — a derived table named
|
|
710
|
+
* `table.name` whose columns are `columns`, one row per tuple. The write
|
|
711
|
+
* follow-up puts it where the parent table would be: the find path's laterals
|
|
712
|
+
* correlate to `"<table.name>"."<column>"` exactly as over the table, but read
|
|
713
|
+
* the RETURNED key values instead of the parent row (a deleted row, or a
|
|
714
|
+
* native-RLS parent whose SELECT policy the per-relation loads never met).
|
|
715
|
+
*
|
|
716
|
+
* Renders where `SqlDialect.keyListStrategy` is `unnest` (postgres) as the
|
|
717
|
+
* typed form of a `VALUES` list — one array per column, typed like the
|
|
718
|
+
* key-list filter's members (`postgresKeyListElementType`), so the text does
|
|
719
|
+
* not depend on the tuple count: `FROM unnest($1::text[], $2::int4[]) AS
|
|
720
|
+
* "Post" ("id", "authorId")`. A `DateTime` member without a declared native
|
|
721
|
+
* type (`keyListBindsUntypedRows`) and every other dialect refuse with
|
|
722
|
+
* `VIBE_UNSUPPORTED_CAPABILITY` — those dialects have no lateral joins either.
|
|
723
|
+
*/
|
|
724
|
+
export type KeyRows = {
|
|
725
|
+
/** Output column names of the derived table, in member order. */
|
|
726
|
+
readonly columns: readonly string[];
|
|
727
|
+
/** How each column binds, in column order — see {@link KeyListMember}. */
|
|
728
|
+
readonly members: readonly KeyListMember[];
|
|
729
|
+
/** Encoded tuples; never empty, each exactly `columns.length` long. */
|
|
730
|
+
readonly rows: readonly (readonly unknown[])[];
|
|
731
|
+
};
|
|
697
732
|
export type SelectStatement = {
|
|
698
733
|
readonly kind: "select";
|
|
699
734
|
readonly table: TableRef;
|
|
@@ -733,7 +768,7 @@ export type SelectStatement = {
|
|
|
733
768
|
* by aggregate-over-a-subset shapes (`aggregate({ take, skip, orderBy })`).
|
|
734
769
|
*/
|
|
735
770
|
readonly fromSelect?: SelectStatement;
|
|
736
|
-
/** Lateral JSON-aggregation joins — postgres
|
|
771
|
+
/** Lateral JSON-aggregation joins — postgres and MySQL 8.0.14+, see {@link LateralJoin}. */
|
|
737
772
|
readonly lateralJoins?: readonly LateralJoin[];
|
|
738
773
|
/** Plain equality INNER JOINs — portable, see {@link InnerJoin}. */
|
|
739
774
|
readonly innerJoins?: readonly InnerJoin[];
|
|
@@ -762,6 +797,13 @@ export type SelectStatement = {
|
|
|
762
797
|
* branch by branch, in text order.
|
|
763
798
|
*/
|
|
764
799
|
readonly fromUnion?: readonly SelectStatement[];
|
|
800
|
+
/**
|
|
801
|
+
* Statement-count pass EPIC 4 (ST-07): derived-table FROM over bound key
|
|
802
|
+
* tuples, named `table.name` with the listed column names — see
|
|
803
|
+
* {@link KeyRows}. Never together with `fromSelect`, `keyPage`, `fromUnion`,
|
|
804
|
+
* a `table.alias` or a `rowLock`.
|
|
805
|
+
*/
|
|
806
|
+
readonly fromKeys?: KeyRows;
|
|
765
807
|
readonly where?: SqlExpr;
|
|
766
808
|
readonly groupBy?: readonly ColRef[];
|
|
767
809
|
/** HAVING predicate — grouped selects; may contain `aggCmp` expressions. */
|
|
@@ -797,6 +839,19 @@ export type RowLock = {
|
|
|
797
839
|
export declare const SQL_DEFAULT_CELL: {
|
|
798
840
|
readonly __sqlDefault: true;
|
|
799
841
|
};
|
|
842
|
+
/**
|
|
843
|
+
* Sentinel update-arm cell: the column keeps its current value —
|
|
844
|
+
* `` `col` = `table`.`col` `` (V8, the insert-if-missing upsert). Valid only in
|
|
845
|
+
* an {@link OnConflictUpdate} `update` set, where MySQL's `ON DUPLICATE KEY
|
|
846
|
+
* UPDATE` needs at least one assignment: a self-assignment changes nothing on a
|
|
847
|
+
* duplicate and, unlike `INSERT IGNORE`, leaves every other error an error.
|
|
848
|
+
* Refused in a plain UPDATE's SET list.
|
|
849
|
+
*/
|
|
850
|
+
export declare const SQL_KEEP_CELL: {
|
|
851
|
+
readonly __sqlKeep: true;
|
|
852
|
+
};
|
|
853
|
+
/** Is this update cell the {@link SQL_KEEP_CELL} sentinel? */
|
|
854
|
+
export declare function isSqlKeepCell(value: unknown): boolean;
|
|
800
855
|
/** Is this VALUES cell the {@link SQL_DEFAULT_CELL} sentinel? */
|
|
801
856
|
export declare function isSqlDefaultCell(value: unknown): boolean;
|
|
802
857
|
/**
|
|
@@ -925,11 +980,28 @@ export type OnConflictUpdate = {
|
|
|
925
980
|
};
|
|
926
981
|
/**
|
|
927
982
|
* Conflicting rows are skipped (`createMany({ skipDuplicates: true })`).
|
|
928
|
-
* An empty/absent target means "any conflict" — the mysql form
|
|
929
|
-
*
|
|
930
|
-
*
|
|
983
|
+
* An empty/absent target means "any conflict" — the mysql form
|
|
984
|
+
* (`ON DUPLICATE KEY UPDATE k = t.k`, dialect `doNothingForm:
|
|
985
|
+
* "duplicateKeyKeep"`) can only express that, so it ignores a bare `columns`
|
|
986
|
+
* target (documented degradation) and REFUSES the refined targets below.
|
|
931
987
|
*/
|
|
932
988
|
export type OnConflictDoNothing = {
|
|
989
|
+
/**
|
|
990
|
+
* MySQL form only (`duplicateKeyKeep`): the column the duplicate arm assigns
|
|
991
|
+
* to itself (`` `k` = `t`.`k` ``, a no-op). Absent = the first inserted
|
|
992
|
+
* column; an all-default row (no column) must name one.
|
|
993
|
+
*/
|
|
994
|
+
readonly keepColumn?: string;
|
|
995
|
+
/**
|
|
996
|
+
* MySQL form only, single-row statements: a decimal literal S (digits only).
|
|
997
|
+
* The keep assignment becomes `` `k` = IF(LAST_INSERT_ID(S), `t`.`k`, `t`.`k`) ``,
|
|
998
|
+
* so a skipped duplicate reports S as the statement's insert id (an inserted
|
|
999
|
+
* row reports its own id, or 0) — the exact skipped verdict that the
|
|
1000
|
+
* affected count cannot give with CLIENT_FOUND_ROWS (an unchanged duplicate
|
|
1001
|
+
* counts 1, like an insert). The builder picks S unequal to the row's
|
|
1002
|
+
* explicit AUTO_INCREMENT value.
|
|
1003
|
+
*/
|
|
1004
|
+
readonly duplicateFlag?: string;
|
|
933
1005
|
readonly columns?: readonly string[];
|
|
934
1006
|
/**
|
|
935
1007
|
* Partial-index target predicate, RAW SQL: `ON CONFLICT (cols) WHERE pred
|
|
@@ -947,7 +1019,13 @@ export type OnConflictClause = OnConflictUpdate | OnConflictDoNothing;
|
|
|
947
1019
|
export type UpdateStatement = {
|
|
948
1020
|
readonly kind: "update";
|
|
949
1021
|
readonly table: TableRef;
|
|
950
|
-
/**
|
|
1022
|
+
/**
|
|
1023
|
+
* Column → parameter value, or an atomic {@link SetOperation}. As a
|
|
1024
|
+
* {@link ChainStep} only (statement-maxx lane C3), a value may be a
|
|
1025
|
+
* {@link StepColumnRef} to an EARLIER step: `"col" = (SELECT "c" FROM
|
|
1026
|
+
* "step")` — the step must return at most one row (an owner resolved by a
|
|
1027
|
+
* unique where, or an owner INSERT of one row).
|
|
1028
|
+
*/
|
|
951
1029
|
readonly set: Readonly<Record<string, unknown>>;
|
|
952
1030
|
readonly where?: SqlExpr;
|
|
953
1031
|
readonly returning?: readonly ReturningColumn[];
|
|
@@ -997,6 +1075,12 @@ export type RlsContextStatement = {
|
|
|
997
1075
|
readonly kind: "rlsContext";
|
|
998
1076
|
readonly context: RlsContextIR;
|
|
999
1077
|
readonly values: Readonly<Record<string, string | null>>;
|
|
1078
|
+
/** PGlite: bind this trusted runtime role first, in the same statement. */
|
|
1079
|
+
readonly role?: string;
|
|
1080
|
+
/** Switch the transaction to READ ONLY in the same statement, after the claims. */
|
|
1081
|
+
readonly readOnly?: boolean;
|
|
1082
|
+
/** Report the backend as `"backendPid"` / `"backendStart"` text columns. */
|
|
1083
|
+
readonly backend?: boolean;
|
|
1000
1084
|
};
|
|
1001
1085
|
/** Trusted pre-existing PGlite execution role; never a request-supplied principal. */
|
|
1002
1086
|
export type RlsRoleStatement = {
|
|
@@ -1085,6 +1169,15 @@ export type InsertSelectStatement = {
|
|
|
1085
1169
|
*/
|
|
1086
1170
|
readonly source?: ChainRowSource;
|
|
1087
1171
|
readonly where?: SqlExpr;
|
|
1172
|
+
/**
|
|
1173
|
+
* `ON CONFLICT (<columns>) DO NOTHING` (statement-maxx lane C2): a row whose
|
|
1174
|
+
* conflict target already exists is skipped and not returned — the implicit
|
|
1175
|
+
* many-to-many join INSERT, where re-connecting an existing pair is a no-op.
|
|
1176
|
+
* Postgres form only (the chain renders nowhere else); at least one column.
|
|
1177
|
+
*/
|
|
1178
|
+
readonly conflictDoNothing?: {
|
|
1179
|
+
readonly columns: readonly string[];
|
|
1180
|
+
};
|
|
1088
1181
|
readonly returning?: readonly ReturningColumn[];
|
|
1089
1182
|
};
|
|
1090
1183
|
/**
|
package/dist/codecs.d.ts
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* Database enums ride the String codec. String-backed enums use the field-bound
|
|
21
21
|
* membership codec below; their wire values are still strings on every dialect.
|
|
22
22
|
*/
|
|
23
|
+
import { VibeError } from "@vibeorm/schema";
|
|
23
24
|
import type { Dialect, ScalarType } from "@vibeorm/schema";
|
|
24
25
|
/**
|
|
25
26
|
* One scalar type's transport rules for one dialect. Both directions see only
|
|
@@ -66,6 +67,23 @@ export type WireFidelity = {
|
|
|
66
67
|
readonly json?: "parsed" | "text";
|
|
67
68
|
/** Int/Float columns arrive as JS numbers (`"native"`) or as text (`"text"`). */
|
|
68
69
|
readonly numbers?: "native" | "text";
|
|
70
|
+
/**
|
|
71
|
+
* Bytes columns arrive as Node `Buffer` instances (`"buffer"`: node-postgres,
|
|
72
|
+
* bun:sql); absent means a plain `Uint8Array` (PGlite). Never prunes a
|
|
73
|
+
* decoder: the runtime's JSON-transport plan reads it, so a `"join"`
|
|
74
|
+
* relation child's bytes (base64 on the wire) materialize in the same class
|
|
75
|
+
* the driver hands the `"query"` strategy — value identity (5.0 lane V).
|
|
76
|
+
*/
|
|
77
|
+
readonly bytes?: "buffer";
|
|
78
|
+
/**
|
|
79
|
+
* Zone-less date-time text (MySQL DATETIME / TIMESTAMP / DATE) is read as a
|
|
80
|
+
* UTC instant by the driver (`"utc"`: mysql2 with `timezone: "Z"`). Absent
|
|
81
|
+
* means another or an unknown zone (another `timezone` option, an injected
|
|
82
|
+
* pool). Never prunes a decoder: the runtime reads it to decide whether a
|
|
83
|
+
* dialect default of `"join"` keeps value identity — the JSON transport
|
|
84
|
+
* decodes that text as UTC (`lateralJson.requiresUtcDateTimeWire`, lane J).
|
|
85
|
+
*/
|
|
86
|
+
readonly zoneLessDateTime?: "utc";
|
|
69
87
|
};
|
|
70
88
|
/**
|
|
71
89
|
* Is this scalar type's DECODE a no-op under the declared wire fidelity?
|
|
@@ -113,6 +131,32 @@ export declare function decodeIsNoop(params: {
|
|
|
113
131
|
export declare function parseDateTimeText(params: {
|
|
114
132
|
text: string;
|
|
115
133
|
}): Date | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* PostgreSQL date/time text with a year of five or more digits or a ` BC` era,
|
|
136
|
+
* in the row text form and the JSON form: `12345-06-07 08:09:10.111+00`,
|
|
137
|
+
* `12345-06-07T08:09:10.111` (zone-less), `0044-03-15T12:00:00.5+00:00 BC`,
|
|
138
|
+
* `0044-03-15 BC` (`date`). ECMA-262 parses none of them (an expanded year
|
|
139
|
+
* needs `+012345`), and a value near the end of year 9999 reaches them
|
|
140
|
+
* through the session zone alone (`9999-12-31 23:59+00` prints as
|
|
141
|
+
* `10000-01-01 00:59+01` east of UTC). Built from its fields, by the rules of
|
|
142
|
+
* {@link parseDateTimeText}: the BC year astronomically (`1 BC` = year 0, the
|
|
143
|
+
* reading of node-postgres), zone-less text as UTC, the fraction truncated to
|
|
144
|
+
* milliseconds, an offset with seconds applied exactly.
|
|
145
|
+
*
|
|
146
|
+
* `undefined` for every other text — a 4-digit AD value keeps the parse it
|
|
147
|
+
* had — and for an instant outside the `Date` range. Exported for the adapters
|
|
148
|
+
* whose zone-less driver parsers fall back to it (one rule, rule 6).
|
|
149
|
+
*/
|
|
150
|
+
export declare function parseExtendedDateTimeText(params: {
|
|
151
|
+
text: string;
|
|
152
|
+
}): Date | undefined;
|
|
153
|
+
/**
|
|
154
|
+
* The decode refusal of a non-finite or unparseable DateTime — one error for
|
|
155
|
+
* every DateTime codec. Exported so a statement that refuses such a value
|
|
156
|
+
* itself (the runtime's in-statement value guard, round-trip follow-up D1)
|
|
157
|
+
* reports exactly this error.
|
|
158
|
+
*/
|
|
159
|
+
export declare function decodedDateTimeRefusal(): VibeError;
|
|
116
160
|
/**
|
|
117
161
|
* The time-of-day codec for a DateTime field's native type, or `undefined`
|
|
118
162
|
* when the native type is not `time`/`timetz` (the DateTime table row
|
package/dist/dialect.d.ts
CHANGED
|
@@ -167,6 +167,51 @@ export type SqlDialect = {
|
|
|
167
167
|
* `ROW_NUMBER()` window (MySQL: a lateral page still read every child).
|
|
168
168
|
*/
|
|
169
169
|
readonly keyPageStrategy: "lateral" | "inLimit" | "window";
|
|
170
|
+
/**
|
|
171
|
+
* How the `"join"` relation strategy's lateral subselects build their JSON
|
|
172
|
+
* payload (`LateralJoin`), or `null` where the dialect has no LATERAL
|
|
173
|
+
* (`capabilities.lateralJoin` false). `rowArray` builds one positional row,
|
|
174
|
+
* `arrayAgg` aggregates the rows, `emptyArray` is the payload of a list
|
|
175
|
+
* level without rows. `order` says how a list level keeps its order:
|
|
176
|
+
* `"inAggregate"` — the aggregate takes the ORDER BY itself (postgres
|
|
177
|
+
* `json_agg(… ORDER BY …)`); `"positionSlot"` — the aggregate cannot order
|
|
178
|
+
* (MySQL `JSON_ARRAYAGG` has no ORDER BY and documents its element order as
|
|
179
|
+
* undefined), so an ordered level projects a `ROW_NUMBER()` position as
|
|
180
|
+
* its last positional slot and the runtime sorts the children by it.
|
|
181
|
+
* MySQL needs 8.0.14 or later (LATERAL and outer references in derived
|
|
182
|
+
* tables); MariaDB has no LATERAL.
|
|
183
|
+
*/
|
|
184
|
+
readonly lateralJson: {
|
|
185
|
+
readonly rowArray: string;
|
|
186
|
+
readonly arrayAgg: string;
|
|
187
|
+
readonly emptyArray: string;
|
|
188
|
+
readonly order: "inAggregate" | "positionSlot";
|
|
189
|
+
/**
|
|
190
|
+
* Time-of-day values ride the payload as text (`CAST(… AS CHAR)`, the
|
|
191
|
+
* query path's form): MySQL 8.4.11 prints a TIME beyond a day inside JSON
|
|
192
|
+
* wrapped modulo 24 hours (`838:59:59` → `"06:59:59.000000"`), which would
|
|
193
|
+
* turn the query strategy's refusal into a wrong value.
|
|
194
|
+
*/
|
|
195
|
+
readonly timeOfDayAsText: boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Zone-less date-times (MySQL DATETIME / TIMESTAMP / DATE) ride the
|
|
198
|
+
* payload as the session's zone-less text, which the JSON transport
|
|
199
|
+
* decodes as UTC, while the query strategy's driver reads the same text
|
|
200
|
+
* in ITS configured zone (mysql2 `timezone`). `true`: the dialect default
|
|
201
|
+
* (`relationStrategyDefault`) joins only on an adapter whose wire declares
|
|
202
|
+
* `zoneLessDateTime: "utc"`; an explicit `"join"` is unaffected. `false`
|
|
203
|
+
* where every adapter pins zone-less values to UTC (postgres).
|
|
204
|
+
*/
|
|
205
|
+
readonly requiresUtcDateTimeWire: boolean;
|
|
206
|
+
} | null;
|
|
207
|
+
/**
|
|
208
|
+
* The relation strategy a client uses when neither the call nor the client
|
|
209
|
+
* option names one (5.0 rule D-2). `"join"` only where `lateralJoin` holds.
|
|
210
|
+
* On MySQL (lane J, wave 3b) the runtime still loads `"query"` until the
|
|
211
|
+
* adapter knows its server runs LATERAL and declares a UTC date-time wire
|
|
212
|
+
* (`serverLateralJoins` in the runtime).
|
|
213
|
+
*/
|
|
214
|
+
readonly relationStrategyDefault: "join" | "query";
|
|
170
215
|
/**
|
|
171
216
|
* Fix lane Q1 (round 3, DB-03): how a positive relation filter that pins ONE
|
|
172
217
|
* related row by a unique key renders. `exists`: the correlated `EXISTS` —
|
|
@@ -241,11 +286,14 @@ export type SqlDialect = {
|
|
|
241
286
|
};
|
|
242
287
|
/**
|
|
243
288
|
* Skip-conflicting-rows form. `onConflictDoNothing` appends
|
|
244
|
-
* `ON CONFLICT [(target)] DO NOTHING`; `
|
|
245
|
-
* `
|
|
246
|
-
* duplicate
|
|
289
|
+
* `ON CONFLICT [(target)] DO NOTHING`; `duplicateKeyKeep` appends
|
|
290
|
+
* `ON DUPLICATE KEY UPDATE k = t.k` — a self-assignment that skips ANY
|
|
291
|
+
* duplicate key and, unlike `INSERT IGNORE` (never emitted: it also turns NOT
|
|
292
|
+
* NULL, out-of-range and foreign-key errors into warnings), leaves every other
|
|
293
|
+
* error an error. A duplicate takes the update arm, so the table's UPDATE
|
|
294
|
+
* triggers fire (nothing changes).
|
|
247
295
|
*/
|
|
248
|
-
readonly doNothingForm: "onConflictDoNothing" | "
|
|
296
|
+
readonly doNothingForm: "onConflictDoNothing" | "duplicateKeyKeep";
|
|
249
297
|
/** Case-insensitive LIKE: native ILIKE or LOWER(col) LIKE LOWER(pattern). */
|
|
250
298
|
readonly insensitiveLike: "ilike" | "lower";
|
|
251
299
|
/**
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { SqlDialect } from "../dialect.ts";
|
|
2
2
|
import type { RenderedQuery } from "../render.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Ends a MySQL catalog listing whose row count has no small bound (the
|
|
5
|
+
* migration inventory, the visibility proof). `sql_select_limit` (session or
|
|
6
|
+
* global, e.g. 1 000 under `mysql --safe-updates`) silently cuts the rows of a
|
|
7
|
+
* SELECT without its own LIMIT, and a cut listing reads its last objects (or
|
|
8
|
+
* grants) as missing; an explicit LIMIT takes precedence over it. After the
|
|
9
|
+
* last `UNION` branch (and its ORDER BY) the LIMIT applies to the whole union.
|
|
10
|
+
* The value is MySQL's largest row count, so nothing is ever cut. The batched
|
|
11
|
+
* object readers end the same way (`migration-objects.ts`, LEFTOVERS-01).
|
|
12
|
+
*/
|
|
13
|
+
export declare const MYSQL_NO_ROW_LIMIT: string;
|
|
3
14
|
/** SQLite column metadata includes generated columns omitted by table_info. */
|
|
4
15
|
export declare function renderSqliteColumnInventory(params: {
|
|
5
16
|
dialect: SqlDialect;
|
|
@@ -12,11 +23,57 @@ export declare function renderSqliteForeignKeyInventory(params: {
|
|
|
12
23
|
namespace: string;
|
|
13
24
|
table: string;
|
|
14
25
|
}): RenderedQuery;
|
|
26
|
+
/**
|
|
27
|
+
* {@link renderSqliteColumnInventory} for many tables in one statement. Rows
|
|
28
|
+
* carry `vibe_request` = the table's index in `tables`, then the single query's
|
|
29
|
+
* columns in its order (`cid`). The table-valued pragma runs the same PRAGMA
|
|
30
|
+
* per table, with the same namespace argument. Every table answers at least one
|
|
31
|
+
* row (`LEFT JOIN`): one whose `name` is NULL when its PRAGMA has no rows, so a
|
|
32
|
+
* table missing from the answer was not read.
|
|
33
|
+
*/
|
|
34
|
+
export declare function renderSqliteColumnInventoryBatch(params: {
|
|
35
|
+
dialect: SqlDialect;
|
|
36
|
+
namespace: string;
|
|
37
|
+
tables: readonly string[];
|
|
38
|
+
}): RenderedQuery;
|
|
39
|
+
/** {@link renderSqliteForeignKeyInventory} for many tables in one statement; rows as in {@link renderSqliteColumnInventoryBatch} (no-row marker: `id` NULL), ordered `id, seq` per table. */
|
|
40
|
+
export declare function renderSqliteForeignKeyInventoryBatch(params: {
|
|
41
|
+
dialect: SqlDialect;
|
|
42
|
+
namespace: string;
|
|
43
|
+
tables: readonly string[];
|
|
44
|
+
}): RenderedQuery;
|
|
45
|
+
/** A PRAGMA SQLite introspection reads once per table (`table_xinfo`, `index_list`, `foreign_key_list`) or per index (`index_xinfo`). */
|
|
46
|
+
export type SqliteIntrospectionPragma = "table_xinfo" | "index_list" | "index_xinfo" | "foreign_key_list";
|
|
47
|
+
/**
|
|
48
|
+
* `PRAGMA <pragma>("<name>")` for every name in one statement. Rows carry
|
|
49
|
+
* `vibe_request` = the name's index in `names`, then exactly the PRAGMA's own
|
|
50
|
+
* columns (a table-valued pragma's hidden `arg`/`schema` columns are not in
|
|
51
|
+
* `p.*`), per name in the order the PRAGMA emits them. No schema argument, as
|
|
52
|
+
* in the single statement: the table-valued pragma runs `PRAGMA <pragma>='name'`
|
|
53
|
+
* internally, with the same temp-then-main name lookup.
|
|
54
|
+
*
|
|
55
|
+
* Literal text with no bound values, like every statement SQLite introspection
|
|
56
|
+
* sends (the names list is one quoted string literal): an executor that runs a
|
|
57
|
+
* value-less statement without binding anything reads the same rows.
|
|
58
|
+
*
|
|
59
|
+
* Every name answers at least one row (`LEFT JOIN`): a name whose PRAGMA has no
|
|
60
|
+
* rows answers one row whose PRAGMA columns are all NULL, so a name missing
|
|
61
|
+
* from the answer was not read (and an empty answer is never "no rows").
|
|
62
|
+
*/
|
|
63
|
+
export declare function renderSqliteIntrospectionPragmaBatch(params: {
|
|
64
|
+
dialect: SqlDialect;
|
|
65
|
+
pragma: SqliteIntrospectionPragma;
|
|
66
|
+
names: readonly string[];
|
|
67
|
+
}): RenderedQuery;
|
|
15
68
|
/** Exact SQL needed to restore independently existing indexes and triggers during a rebuild. */
|
|
16
69
|
export declare function renderSqliteRebuildObjects(params: {
|
|
17
70
|
dialect: SqlDialect;
|
|
18
71
|
}): RenderedQuery;
|
|
19
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Enumerate scoped catalog identities, including constraints and their backing
|
|
74
|
+
* indexes. The MySQL listing ends with {@link MYSQL_NO_ROW_LIMIT}, so
|
|
75
|
+
* `sql_select_limit` cannot drop objects from it.
|
|
76
|
+
*/
|
|
20
77
|
export declare function renderMigrationInventory(params: {
|
|
21
78
|
dialect: SqlDialect;
|
|
22
79
|
namespace: string;
|
|
@@ -11,6 +11,42 @@ export declare function renderMysqlObjectMembers(params: {
|
|
|
11
11
|
dialect: SqlDialect;
|
|
12
12
|
identity: SqlObjectIdentity;
|
|
13
13
|
}): RenderedQuery | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* One batched MySQL catalog read. Its rows carry `vibe_position` = i, the
|
|
16
|
+
* branch that answers for request position `positions[i]`; member reads also
|
|
17
|
+
* carry `vibe_ordinal`, the single query's ORDER BY column.
|
|
18
|
+
*/
|
|
19
|
+
export type MysqlObjectBatch = RenderedQuery & {
|
|
20
|
+
readonly positions: readonly number[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* MySQL facts reads in bounded statements, grouped by query shape in request
|
|
24
|
+
* order, 100 objects per statement. Each `UNION ALL` branch is the UNCHANGED
|
|
25
|
+
* single-object query as a derived table, so the server matches names with the
|
|
26
|
+
* single read's own `WHERE` and collation: the rows of a position are exactly the
|
|
27
|
+
* rows {@link renderMigrationObjectQuery} returns for it. An identity MySQL cannot
|
|
28
|
+
* inspect is in no batch; the caller reads it on its own (and gets its refusal).
|
|
29
|
+
* The statement ends with `LIMIT 18446744073709551615`, so `sql_select_limit`
|
|
30
|
+
* cannot cut it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function renderMysqlObjectBatch(params: {
|
|
33
|
+
dialect: SqlDialect;
|
|
34
|
+
identities: readonly SqlObjectIdentity[];
|
|
35
|
+
}): readonly MysqlObjectBatch[];
|
|
36
|
+
/**
|
|
37
|
+
* MySQL member reads (function parameters, index and constraint columns) in
|
|
38
|
+
* bounded statements, grouped by kind in request order, 100 objects per
|
|
39
|
+
* statement. Each branch is the single member query's select list and `WHERE`
|
|
40
|
+
* plus its ORDER BY column as `vibe_ordinal`; MySQL ignores an ORDER BY inside a
|
|
41
|
+
* union branch, so the statement orders by `vibe_position, vibe_ordinal` (then
|
|
42
|
+
* `LIMIT 18446744073709551615`, so `sql_select_limit` cannot cut it). Rows
|
|
43
|
+
* of a position equal {@link renderMysqlObjectMembers}' rows in its order
|
|
44
|
+
* whenever that object's ordinals are distinct; the caller checks that.
|
|
45
|
+
*/
|
|
46
|
+
export declare function renderMysqlObjectMembersBatch(params: {
|
|
47
|
+
dialect: SqlDialect;
|
|
48
|
+
identities: readonly SqlObjectIdentity[];
|
|
49
|
+
}): readonly MysqlObjectBatch[];
|
|
14
50
|
/** PostgreSQL dependency addresses are returned as server-owned strings, never guessed from SQL. */
|
|
15
51
|
export declare function renderMigrationDependencies(params: {
|
|
16
52
|
dialect: SqlDialect;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { SqlDialect } from "../dialect.ts";
|
|
2
2
|
import type { RenderedQuery } from "../render.ts";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Direct grants needed to enumerate MySQL objects without privilege-filtered
|
|
5
|
+
* omissions. Ends with {@link MYSQL_NO_ROW_LIMIT}: a `sql_select_limit` below
|
|
6
|
+
* the grant count would otherwise cut grants and refuse a namespace whose
|
|
7
|
+
* grants are complete.
|
|
8
|
+
*/
|
|
4
9
|
export declare function renderMigrationVisibility(params: {
|
|
5
10
|
dialect: SqlDialect;
|
|
6
11
|
namespace: string;
|
package/dist/dialects/mysql.d.ts
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
* - Upserts use ON DUPLICATE KEY UPDATE (no conflict-target refinement).
|
|
8
8
|
* - OFFSET requires LIMIT → the documented huge-limit idiom.
|
|
9
9
|
* - No NULLS FIRST/LAST → `col IS NULL` emulation terms.
|
|
10
|
-
* - No `ON CONFLICT ... DO NOTHING` → `
|
|
11
|
-
*
|
|
10
|
+
* - No `ON CONFLICT ... DO NOTHING` → `ON DUPLICATE KEY UPDATE k = t.k` (a
|
|
11
|
+
* no-op self-assignment on ANY duplicate key). Never `INSERT IGNORE`, which
|
|
12
|
+
* also downgrades NOT NULL, range and foreign-key errors to warnings.
|
|
12
13
|
*/
|
|
13
14
|
import type { SqlDialect } from "../dialect.ts";
|
|
14
15
|
export declare const mysqlDialect: SqlDialect;
|
|
@@ -57,11 +57,26 @@ export declare function renderRlsPolicy(params: {
|
|
|
57
57
|
policyName?: string;
|
|
58
58
|
targetSchema?: "public" | "pg_temp";
|
|
59
59
|
}): RenderedQuery;
|
|
60
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Every declared setting, parameterized in declaration order and transaction-local.
|
|
62
|
+
*
|
|
63
|
+
* Optional parts travel in the SAME statement (statement-count pass, EPIC 1-2);
|
|
64
|
+
* without them the text is exactly the claims statement:
|
|
65
|
+
* - `role` (PGlite): binds the trusted runtime role FIRST, as {@link renderRlsRole} does;
|
|
66
|
+
* - `readOnly`: switches the transaction to READ ONLY after the claims (`$all` on a
|
|
67
|
+
* verified connection; PostgreSQL accepts this switch at any point of a transaction);
|
|
68
|
+
* - `backend`: reports the backend as `"backendPid"` / `"backendStart"` text columns,
|
|
69
|
+
* the readiness catalog read's own expressions (adapters that name no connection object).
|
|
70
|
+
*
|
|
71
|
+
* A context with zero keys is accepted only when one of these parts is present.
|
|
72
|
+
*/
|
|
61
73
|
export declare function renderRlsContext(params: {
|
|
62
74
|
dialect: SqlDialect;
|
|
63
75
|
context: RlsContextIR;
|
|
64
76
|
values: Readonly<Record<string, string | null>>;
|
|
77
|
+
role?: string;
|
|
78
|
+
readOnly?: boolean;
|
|
79
|
+
backend?: boolean;
|
|
65
80
|
}): RenderedQuery;
|
|
66
81
|
/** First transaction statement on eligible PGlite only; server roles are login roles. */
|
|
67
82
|
export declare function renderRlsRole(params: {
|
package/dist/index.d.ts
CHANGED
|
@@ -40,8 +40,8 @@ export type { ResultDecoder, ResultReadDecoder, ResultParameterEncoder, ResultSc
|
|
|
40
40
|
* lives in this package; see the root sql-catalog.md for the reviewable surface.
|
|
41
41
|
*/
|
|
42
42
|
export { compileExclusion, renderExclusionSetup, renderExclusionDdl, renderExclusionCatalog, renderExclusionProbe } from "./exclusion.ts";
|
|
43
|
-
export type { AdvisoryLockKey, AdvisoryLockStatement, AggFn, AggRef, AggSelect, ChainResult, ChainRowSource, ChainStatement, ChainStep, ChainStepStatement, ChainTally, ChainVeto, ColRef, ComparisonOp, CountSubquery, DeleteStatement, ExcludedRef, InnerJoin, KeyListMember, KeyPage, KeyTableJoin, KeyTableMember, InsertSelectStatement, InsertStatement, ReturningColumn, JsonFilterOp, LateralJoin, LeftJoin, ListSetOperation, OnConflictClause, OnConflictDoNothing, OnConflictUpdate, OrderByAggregate, OrderByColumn, OrderBySubquery, OrderTerm, RowLock, RowNumberProjection, DbNowMarker, JsonParamCell, SelectExpr, SelectStatement, SetOperation, SetOperator, SqlExpr, SqlStatement, StepColumnRef, TableRef, UpdateStatement, } from "./ast.ts";
|
|
44
|
-
export { ADVISORY_LOCK_RESULT_COLUMN, CHAIN_VETO_PREFIX, CHAIN_VETO_TOKEN_PATTERN, SQL_DEFAULT_CELL, chainVetoToken, dbNowMarker, excludedRef, isDbNowMarker, isExcludedRef, isJsonParamCell, isListSetOperation, isSetOperation, isSqlDefaultCell, isStepColumnRef, jsonParamCell, returningColumnName, stepColumnRef, } from "./ast.ts";
|
|
43
|
+
export type { AdvisoryLockKey, AdvisoryLockStatement, AggFn, AggRef, AggSelect, ChainResult, ChainRowSource, ChainStatement, ChainStep, ChainStepStatement, ChainTally, ChainVeto, ColRef, ComparisonOp, CountSubquery, DeleteStatement, ExcludedRef, InnerJoin, KeyListMember, KeyPage, KeyRows, KeyTableJoin, KeyTableMember, InsertSelectStatement, InsertStatement, ReturningColumn, JsonFilterOp, LateralJoin, LeftJoin, ListSetOperation, OnConflictClause, OnConflictDoNothing, OnConflictUpdate, OrderByAggregate, OrderByColumn, OrderBySubquery, OrderTerm, RowLock, RowNumberProjection, DbNowMarker, JsonParamCell, SelectExpr, SelectStatement, SetOperation, SetOperator, SqlExpr, SqlStatement, StepColumnRef, TableRef, UpdateStatement, } from "./ast.ts";
|
|
44
|
+
export { ADVISORY_LOCK_RESULT_COLUMN, CHAIN_VETO_PREFIX, CHAIN_VETO_TOKEN_PATTERN, SQL_DEFAULT_CELL, SQL_KEEP_CELL, chainVetoToken, dbNowMarker, excludedRef, isDbNowMarker, isExcludedRef, isJsonParamCell, isListSetOperation, isSetOperation, isSqlDefaultCell, isSqlKeepCell, isStepColumnRef, jsonParamCell, returningColumnName, stepColumnRef, } from "./ast.ts";
|
|
45
45
|
export type { AdvisoryLockFunctions, AdvisoryLockModeFunctions, RowLockSyntax, EmptyInsertSyntax, SqlDialect, } from "./dialect.ts";
|
|
46
46
|
export { ADVISORY_KEY_BOUNDS, describeRowLock, renderAdvisoryLock, renderRowLockClause } from "./locks.ts";
|
|
47
47
|
export { JSON_TRANSPORT, projectionOutputName } from "./json-transport.ts";
|
|
@@ -64,7 +64,7 @@ export { renderRowRule } from "./row-rules.ts";
|
|
|
64
64
|
export type { RenderedRowRule, RowRuleStatement, RowRuleTriggerPlacement } from "./row-rules.ts";
|
|
65
65
|
export type { PredicateModel, PredicateUsage } from "./predicate.ts";
|
|
66
66
|
export { DIALECT_CAPABILITIES, MYSQL_CAPABILITIES, POSTGRES_CAPABILITIES, SQLITE_CAPABILITIES, } from "./capabilities.ts";
|
|
67
|
-
export { DIALECT_CODECS, MYSQL_CODECS, POSTGRES_CODECS, SQLITE_CODECS, decodeIsNoop, enumMembershipCodec, float32Codec, localDateCodec, parseDateTimeText, parseJsonText, postgresArrayElementFromText, shortestFloat32, timeOfDayCodec, } from "./codecs.ts";
|
|
67
|
+
export { DIALECT_CODECS, MYSQL_CODECS, POSTGRES_CODECS, SQLITE_CODECS, decodeIsNoop, decodedDateTimeRefusal, enumMembershipCodec, float32Codec, localDateCodec, parseDateTimeText, parseExtendedDateTimeText, parseJsonText, postgresArrayElementFromText, shortestFloat32, timeOfDayCodec, } from "./codecs.ts";
|
|
68
68
|
export type { CodecTable, ScalarCodec, WireFidelity } from "./codecs.ts";
|
|
69
69
|
export { renderExpr, renderFragment, renderProjection, renderStatement } from "./render.ts";
|
|
70
70
|
export type { RenderedQuery } from "./render.ts";
|
|
@@ -87,9 +87,10 @@ export { renderMigrationHistoryQuery } from "./dialects/migration-history.ts";
|
|
|
87
87
|
export { sqliteTableConstraints } from "./dialects/sqlite-constraints.ts";
|
|
88
88
|
export type { SqliteConstraintClause } from "./dialects/sqlite-constraints.ts";
|
|
89
89
|
export { renderMigrationVisibility } from "./dialects/migration-visibility.ts";
|
|
90
|
-
export { renderMigrationInventory, renderSqliteColumnInventory, renderSqliteForeignKeyInventory, renderSqliteRebuildObjects } from "./dialects/migration-inventory.ts";
|
|
91
|
-
export { renderMigrationObjectBatch, renderMigrationObjectQuery, renderCheckProbe, renderMigrationNamespace, renderMigrationServerVersion, renderMigrationDependencies, renderMysqlObjectMembers } from "./dialects/migration-objects.ts";
|
|
92
|
-
export type { MigrationObjectBatch } from "./dialects/migration-objects.ts";
|
|
90
|
+
export { renderMigrationInventory, renderSqliteColumnInventory, renderSqliteForeignKeyInventory, renderSqliteRebuildObjects, renderSqliteColumnInventoryBatch, renderSqliteForeignKeyInventoryBatch, renderSqliteIntrospectionPragmaBatch } from "./dialects/migration-inventory.ts";
|
|
91
|
+
export { renderMigrationObjectBatch, renderMigrationObjectQuery, renderCheckProbe, renderMigrationNamespace, renderMigrationServerVersion, renderMigrationDependencies, renderMysqlObjectMembers, renderMysqlObjectBatch, renderMysqlObjectMembersBatch } from "./dialects/migration-objects.ts";
|
|
92
|
+
export type { MigrationObjectBatch, MysqlObjectBatch } from "./dialects/migration-objects.ts";
|
|
93
|
+
export type { SqliteIntrospectionPragma } from "./dialects/migration-inventory.ts";
|
|
93
94
|
export type { DiagnosticStatement, FixedDiagnosticQuery } from "./dialects/diagnostics.ts";
|
|
94
95
|
export { POSTGRES_DIAGNOSTIC_SQL, POSTGRES_WORKLOAD_LIMITS, renderPostgresExplain, renderPostgresWorkload, } from "./dialects/postgres-diagnostics.ts";
|
|
95
96
|
export type { PostgresExplainOptions, PostgresWorkloadQuery } from "./dialects/postgres-diagnostics.ts";
|