@vibeorm/sql 4.1.0 → 4.3.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 +221 -1
- package/dist/codecs.d.ts +2 -0
- package/dist/dialect.d.ts +118 -1
- package/dist/dialects/mysql-check-probe.d.ts +1 -0
- package/dist/dialects/mysql-generated-columns.d.ts +43 -0
- package/dist/dialects/mysql-index-expressions.d.ts +20 -0
- package/dist/dialects/mysql-row-rules.d.ts +8 -0
- package/dist/dialects/postgres-generated-columns.d.ts +30 -0
- package/dist/dialects/postgres-index-expressions.d.ts +10 -0
- package/dist/dialects/postgres-index-keys.d.ts +15 -0
- package/dist/dialects/postgres-row-rules.d.ts +25 -0
- package/dist/dialects/sqlite-generated-columns.d.ts +18 -0
- package/dist/dialects/sqlite-index-expressions.d.ts +23 -0
- package/dist/dialects/sqlite-row-rules.d.ts +8 -0
- package/dist/dialects/sqlite-table-definition.d.ts +25 -5
- package/dist/generated-columns.d.ts +18 -0
- package/dist/index-expressions.d.ts +61 -0
- package/dist/index.d.ts +19 -6
- package/dist/index.js +2358 -1079
- package/dist/index.js.map +32 -18
- package/dist/key-list.d.ts +83 -0
- package/dist/like.d.ts +17 -0
- package/dist/local-date.d.ts +9 -0
- package/dist/pg-array.d.ts +6 -0
- package/dist/predicate.d.ts +21 -7
- package/dist/query/index.js +59 -19
- package/dist/query/index.js.map +7 -7
- package/dist/query/state.d.ts +5 -0
- package/dist/query/types.d.ts +2 -0
- package/dist/row-rules.d.ts +57 -0
- package/dist/timestamp-identity.d.ts +8 -2
- package/package.json +2 -2
package/dist/ast.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { RlsReadinessQuery } from "./dialects/postgres-rls-readiness.ts";
|
|
|
10
10
|
* grows with the runtime in P2/P3. Every shape added here needs a catalog case
|
|
11
11
|
* (tests/catalog/cases.ts) in the same change.
|
|
12
12
|
*/
|
|
13
|
-
import type { AdvisoryLockMode, RlsContextIR, RowLockStrength, RowLockWaitPolicy, SchemaIR, SqlFragmentSpec } from "@vibeorm/schema";
|
|
13
|
+
import type { AdvisoryLockMode, RlsContextIR, RowLockStrength, RowLockWaitPolicy, ScalarType, SchemaIR, SqlFragmentSpec } from "@vibeorm/schema";
|
|
14
14
|
/** A column reference, optionally table-qualified. */
|
|
15
15
|
export type ColRef = {
|
|
16
16
|
readonly table?: string;
|
|
@@ -88,6 +88,33 @@ export type AggSelect = {
|
|
|
88
88
|
*/
|
|
89
89
|
export type JsonFilterOp = "equals" | "string_contains" | "string_starts_with" | "string_ends_with" | "array_contains" | "array_starts_with" | "array_ends_with";
|
|
90
90
|
export type ComparisonOp = "eq" | "ne" | "gt" | "gte" | "lt" | "lte";
|
|
91
|
+
/**
|
|
92
|
+
* The column facts one member of a {@link SqlExpr} `keyList` tuple needs to
|
|
93
|
+
* bind exactly like the equality `"col" = $n` would. Postgres binds each
|
|
94
|
+
* member as ONE typed array (`$n::<element type>[]`), so it needs the
|
|
95
|
+
* column's element type: the declared native type without its modifier
|
|
96
|
+
* (`timestamptz`, never `timestamptz(3)` — a typmod cast would round
|
|
97
|
+
* `.1234` onto a stored `.123` that `=` does not match), `bpchar` for
|
|
98
|
+
* `char(n)`, `citext`, the enum's own type. MySQL needs to know a time-of-day
|
|
99
|
+
* member (`SqlDialect.timeOfDayInStrategy`); SQLite needs nothing.
|
|
100
|
+
*/
|
|
101
|
+
export type KeyListMember = {
|
|
102
|
+
/** The column's scalar type; `"Enum"` for an enum column. */
|
|
103
|
+
readonly type: ScalarType | "Enum";
|
|
104
|
+
/** The declared `@db.*` native type, verbatim (`VarChar(191)`, `Uuid`, `Timestamptz(3)`). */
|
|
105
|
+
readonly nativeType?: string;
|
|
106
|
+
/**
|
|
107
|
+
* A database-stored (native) enum's type: `namespace` qualifies it, absence
|
|
108
|
+
* resolves it through the search path like the statement's table. Absent on
|
|
109
|
+
* a string-stored enum, whose column is text.
|
|
110
|
+
*/
|
|
111
|
+
readonly enumType?: {
|
|
112
|
+
readonly namespace?: string;
|
|
113
|
+
readonly name: string;
|
|
114
|
+
};
|
|
115
|
+
/** A time-of-day column (`@db.Time(n)` / `@db.Timetz(n)`). */
|
|
116
|
+
readonly timeOfDay?: boolean;
|
|
117
|
+
};
|
|
91
118
|
export type SqlExpr = {
|
|
92
119
|
readonly kind: "composed";
|
|
93
120
|
readonly fragment: SqlFragment;
|
|
@@ -133,6 +160,68 @@ export type SqlExpr = {
|
|
|
133
160
|
/** Candidate tuples — every row carries exactly `columns.length` values. */
|
|
134
161
|
readonly rows: readonly (readonly unknown[])[];
|
|
135
162
|
readonly negate?: boolean;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* KEY-LIST membership — the public `where: { IN: [{ a, b }, …] }` filter:
|
|
166
|
+
* rows whose ordered tuple of column values equals one of `rows`, with
|
|
167
|
+
* semi-join semantics (a repeated tuple never repeats a result row). Renders
|
|
168
|
+
* per `SqlDialect.keyListStrategy`: postgres binds one typed ARRAY per
|
|
169
|
+
* member, `("a", "b") IN (SELECT * FROM unnest($1::int8[], $2::text[]))`,
|
|
170
|
+
* so the text and the planning cost stay constant however long the list is
|
|
171
|
+
* (an OR of 1 000 conjunctions planned in 114 ms on PGlite, 2 ms on
|
|
172
|
+
* postgres 18; the unnest form in 0.1–0.2 ms on both). A `DateTime` member
|
|
173
|
+
* without a declared native type switches postgres to the row-constructor
|
|
174
|
+
* list of untyped parameters (`keyListBindsUntypedRows`: the column may be a
|
|
175
|
+
* zone-less `timestamp`). MySQL renders the row-constructor list, SQLite
|
|
176
|
+
* `IN (VALUES …)`. Each member compares under the column's own type and
|
|
177
|
+
* collation, exactly like `"col" = $n`.
|
|
178
|
+
*
|
|
179
|
+
* An empty `rows` renders `1 = 0` (matches nothing, like an empty
|
|
180
|
+
* `inArray`). The runtime emits arity 1 as `inArray` instead, so a
|
|
181
|
+
* one-field key list keeps the scalar `in` SQL.
|
|
182
|
+
*/
|
|
183
|
+
| {
|
|
184
|
+
readonly kind: "keyList";
|
|
185
|
+
/** Ordered tuple columns (compare references); `rows[i][j]` binds to `columns[j]`. */
|
|
186
|
+
readonly columns: readonly ColRef[];
|
|
187
|
+
/** How each member binds, in column order — see {@link KeyListMember}. */
|
|
188
|
+
readonly members: readonly KeyListMember[];
|
|
189
|
+
/** Encoded candidate tuples, each exactly `columns.length` long; may repeat. */
|
|
190
|
+
readonly rows: readonly (readonly unknown[])[];
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* ROW-VALUE comparison: `("a", "b") > ($1, $2)` — the keyset seek (D-01).
|
|
194
|
+
* SQL compares row values left to right, each pair with that column's own
|
|
195
|
+
* operator, affinity and collation, which is exactly the OR expansion
|
|
196
|
+
* `"a" > $1 OR ("a" = $2 AND "b" > $3)` when no member is NULL — and an
|
|
197
|
+
* index on `(a, b)` bounds it as one range (PostgreSQL `Index Cond: ROW(…) >
|
|
198
|
+
* ROW(…)`, SQLite `SEARCH … (a>?)`). A NULL member makes the comparison
|
|
199
|
+
* UNKNOWN as soon as the scan reaches it, so the runtime emits it only over
|
|
200
|
+
* non-null keys and values. Renders on every dialect (each has row
|
|
201
|
+
* constructors); whether the runtime emits it is
|
|
202
|
+
* `SqlDialect.keysetSeekStrategy`.
|
|
203
|
+
*/
|
|
204
|
+
| {
|
|
205
|
+
readonly kind: "rowCompare";
|
|
206
|
+
readonly op: "gt" | "gte" | "lt" | "lte";
|
|
207
|
+
/** Ordered row members (compare references); `values[i]` binds to `columns[i]`. */
|
|
208
|
+
readonly columns: readonly ColRef[];
|
|
209
|
+
/** Encoded values, exactly `columns.length` of them. */
|
|
210
|
+
readonly values: readonly unknown[];
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* SUBQUERY membership: `"id" IN (SELECT …)`, or the row-value form
|
|
214
|
+
* `("a", "b") IN (SELECT …)` for a composite key — the key-first `distinct`
|
|
215
|
+
* page on PostgreSQL (D-04). The subquery projects exactly `columns.length`
|
|
216
|
+
* columns and shares the statement's parameter sequence. MySQL refuses a
|
|
217
|
+
* `LIMIT` directly inside an `IN` subquery (error 1235), so the renderer
|
|
218
|
+
* refuses that pair there with `VIBE_UNSUPPORTED_CAPABILITY`.
|
|
219
|
+
*/
|
|
220
|
+
| {
|
|
221
|
+
readonly kind: "inSelect";
|
|
222
|
+
/** The tested columns, in the subquery's projection order. */
|
|
223
|
+
readonly columns: readonly ColRef[];
|
|
224
|
+
readonly select: SelectStatement;
|
|
136
225
|
} | {
|
|
137
226
|
readonly kind: "like";
|
|
138
227
|
readonly column: ColRef;
|
|
@@ -435,6 +524,37 @@ export type InnerJoin = {
|
|
|
435
524
|
readonly right: ColRef;
|
|
436
525
|
}[];
|
|
437
526
|
};
|
|
527
|
+
/**
|
|
528
|
+
* One `LEFT JOIN (<select>) AS "alias" ON "alias"."k" = "outer"."c" [AND …]`
|
|
529
|
+
* clause — portable, equality ON pairs only. Built for the to-one relation
|
|
530
|
+
* `orderBy` (`orderBy: { author: { email: "asc" } }`): the target's key and
|
|
531
|
+
* sort columns ride a derived table under RESERVED aliases (`__vibe_ok0`,
|
|
532
|
+
* `__vibe_ov0`), so the outer statement's unqualified column names can never
|
|
533
|
+
* become ambiguous, and the outer ORDER BY names `"alias"."__vibe_ov0"`.
|
|
534
|
+
* Every engine merges such a derived table into a plain join (measured:
|
|
535
|
+
* postgres pulls it up into a hash/nested-loop left join, sqlite flattens it,
|
|
536
|
+
* mysql merges it), so the planner may hash-join instead of evaluating a
|
|
537
|
+
* correlated subquery per candidate row.
|
|
538
|
+
*
|
|
539
|
+
* The builder emits it only for links that match AT MOST ONE target row, so
|
|
540
|
+
* the join keeps the parent row count. The derived select must alias every
|
|
541
|
+
* projected column; its parameters (none today) join the statement's single
|
|
542
|
+
* sequence where the clause renders (after `keyTable`, before
|
|
543
|
+
* `lateralJoins`). A statement with a `rowLock` refuses it: postgres rejects
|
|
544
|
+
* FOR UPDATE on the nullable side of an outer join, and mysql would lock the
|
|
545
|
+
* joined rows too.
|
|
546
|
+
*/
|
|
547
|
+
export type LeftJoin = {
|
|
548
|
+
/** Derived-table alias (`__ord1`). */
|
|
549
|
+
readonly alias: string;
|
|
550
|
+
/** The derived table — every projected column carries an `alias`. */
|
|
551
|
+
readonly select: SelectStatement;
|
|
552
|
+
/** Equality pairs ANDed into the ON clause; never empty. */
|
|
553
|
+
readonly on: readonly {
|
|
554
|
+
readonly left: ColRef;
|
|
555
|
+
readonly right: ColRef;
|
|
556
|
+
}[];
|
|
557
|
+
};
|
|
438
558
|
/**
|
|
439
559
|
* How one member of a {@link KeyTableJoin} tuple binds inside the derived
|
|
440
560
|
* table. `value` binds the parameter as it is: it stays COERCIBLE, so a text
|
|
@@ -523,6 +643,57 @@ export type RowNumberProjection = {
|
|
|
523
643
|
readonly orderBy: readonly OrderTerm[];
|
|
524
644
|
readonly alias: string;
|
|
525
645
|
};
|
|
646
|
+
/**
|
|
647
|
+
* A PER-KEY PAGE of one child table as a derived-table FROM
|
|
648
|
+
* (`SelectStatement.keyPage`): for every listed key tuple, the child rows
|
|
649
|
+
* whose key columns equal it, ordered by `select.orderBy` and cut by
|
|
650
|
+
* `select.limit`/`select.offset` — each key's OWN page, plus a rank column
|
|
651
|
+
* (`rankAlias`) that orders the rows inside their key. The paged include's
|
|
652
|
+
* `ROW_NUMBER() OVER (PARTITION BY key …)` window returns the same rows but
|
|
653
|
+
* numbers EVERY child of every listed key first; this form reads one page of
|
|
654
|
+
* primary keys per key through an index on (key columns, order columns),
|
|
655
|
+
* then each page row once by its primary key.
|
|
656
|
+
*
|
|
657
|
+
* Rendered per `SqlDialect.keyPageStrategy`:
|
|
658
|
+
* - `lateral` (postgres): `unnest($1::<type>[], …) AS "__vibe_keys"
|
|
659
|
+
* ("__vibe_k0", …) CROSS JOIN LATERAL (SELECT <identity>, ROW_NUMBER() OVER
|
|
660
|
+
* (PARTITION BY <key> ORDER BY <order>) AS <rank> FROM <table> WHERE <key> =
|
|
661
|
+
* "__vibe_keys"."__vibe_k<i>" … ORDER BY <order> LIMIT … OFFSET …) AS
|
|
662
|
+
* "__vibe_ids" INNER JOIN <table> AS "__vibe_page" ON <identity> pairs`.
|
|
663
|
+
* - `inLimit` (sqlite, which has no LATERAL): the key tuples as `(VALUES …)`
|
|
664
|
+
* (columns `column1`, `column2`, …, as SQLite names a VALUES clause's
|
|
665
|
+
* columns) joined to `<table> AS "__vibe_page"` ON `(<identity>) IN (SELECT
|
|
666
|
+
* <identity> … WHERE <key> = "__vibe_keys"."column<i>" … ORDER BY … LIMIT …)`,
|
|
667
|
+
* the rank re-derived over the fetched page (`ROW_NUMBER() OVER (PARTITION
|
|
668
|
+
* BY <key> ORDER BY <order>)`): its values differ from the window's, its
|
|
669
|
+
* order inside a key does not.
|
|
670
|
+
* - `window` (mysql): refused with `VIBE_UNSUPPORTED_CAPABILITY` — measured
|
|
671
|
+
* no gain there; the runtime keeps the window.
|
|
672
|
+
*
|
|
673
|
+
* The caller guarantees what makes the page equal to the window's: the order
|
|
674
|
+
* is total inside a key (the identity columns are among the key and order
|
|
675
|
+
* columns), the key tuples are distinct and compare exactly (no folding
|
|
676
|
+
* collation). Members bind like the key-list filter's (`KeyListMember`).
|
|
677
|
+
*/
|
|
678
|
+
export type KeyPage = {
|
|
679
|
+
/** How each key member binds, in member order (postgres: one typed array each). */
|
|
680
|
+
readonly members: readonly KeyListMember[];
|
|
681
|
+
/** Encoded, distinct key tuples; never empty, each `members.length` long. */
|
|
682
|
+
readonly rows: readonly (readonly unknown[])[];
|
|
683
|
+
/** The child columns each key member equals, in member order (unqualified). */
|
|
684
|
+
readonly keyColumns: readonly ColRef[];
|
|
685
|
+
/** The child's primary-key columns (unqualified) — each page row is read once by them. */
|
|
686
|
+
readonly identity: readonly ColRef[];
|
|
687
|
+
/**
|
|
688
|
+
* ONE key's page: the child `table` (no alias), the projected `columns`
|
|
689
|
+
* (unqualified; transforms and aliases render as usual), an optional extra
|
|
690
|
+
* `where`, the non-empty `orderBy` (plain column terms), `limit`/`offset`.
|
|
691
|
+
* Any other member is refused.
|
|
692
|
+
*/
|
|
693
|
+
readonly select: SelectStatement;
|
|
694
|
+
/** Output name of the rank column. */
|
|
695
|
+
readonly rankAlias: string;
|
|
696
|
+
};
|
|
526
697
|
export type SelectStatement = {
|
|
527
698
|
readonly kind: "select";
|
|
528
699
|
readonly table: TableRef;
|
|
@@ -548,6 +719,14 @@ export type SelectStatement = {
|
|
|
548
719
|
* guarantees that arrangement.
|
|
549
720
|
*/
|
|
550
721
|
readonly distinctOn?: readonly ColRef[];
|
|
722
|
+
/**
|
|
723
|
+
* Plain `SELECT DISTINCT` over the whole projection — every dialect. The
|
|
724
|
+
* query builder sets it only where it returns exactly the rows its
|
|
725
|
+
* `ROW_NUMBER()` distinct emulation would (sqlite/mysql, value-exact keys,
|
|
726
|
+
* projection equal to the distinct fields); never together with
|
|
727
|
+
* `distinctOn` (the renderer refuses the pair).
|
|
728
|
+
*/
|
|
729
|
+
readonly distinct?: true;
|
|
551
730
|
/**
|
|
552
731
|
* Derived-table FROM: renders `FROM (<fromSelect>) AS "<table.name>"` —
|
|
553
732
|
* `table.name` is the subquery ALIAS and `table.alias` must be unset. Used
|
|
@@ -560,8 +739,29 @@ export type SelectStatement = {
|
|
|
560
739
|
readonly innerJoins?: readonly InnerJoin[];
|
|
561
740
|
/** Key-table join, rendered after `innerJoins` — mysql only, see {@link KeyTableJoin}. */
|
|
562
741
|
readonly keyTable?: KeyTableJoin;
|
|
742
|
+
/** Fix lane Q2 (D-03): derived-table LEFT JOINs, rendered after `keyTable` — see {@link LeftJoin}. */
|
|
743
|
+
readonly leftJoins?: readonly LeftJoin[];
|
|
563
744
|
/** ROW_NUMBER window projection — see {@link RowNumberProjection}. */
|
|
564
745
|
readonly rowNumber?: RowNumberProjection;
|
|
746
|
+
/**
|
|
747
|
+
* Fix lane Q1 (DB-01): derived-table FROM over a per-key page — renders
|
|
748
|
+
* `FROM (<per-key page>) AS "<table.name>"` like `fromSelect` (and never
|
|
749
|
+
* together with it); see {@link KeyPage}.
|
|
750
|
+
*/
|
|
751
|
+
readonly keyPage?: KeyPage;
|
|
752
|
+
/**
|
|
753
|
+
* Fix lane Q2 (round 3, DB-07): derived-table FROM over a `UNION ALL` of
|
|
754
|
+
* branch selects — renders `FROM (SELECT * FROM (<branch 0>) AS
|
|
755
|
+
* "__vibe_u0" UNION ALL SELECT * FROM (<branch 1>) AS "__vibe_u1" …) AS
|
|
756
|
+
* "<table.name>"`. Each branch keeps its own ORDER BY and LIMIT: wrapped in
|
|
757
|
+
* its own derived table, a limited branch is valid on all three engines
|
|
758
|
+
* (SQLite refuses ORDER BY/LIMIT on a bare compound member). At least two
|
|
759
|
+
* branches; each a plain `SELECT <columns> FROM <table> [WHERE] [ORDER BY]
|
|
760
|
+
* [LIMIT]` projecting the same output names in the same order; never
|
|
761
|
+
* together with `fromSelect`, `keyPage` or a `table.alias`. Parameters bind
|
|
762
|
+
* branch by branch, in text order.
|
|
763
|
+
*/
|
|
764
|
+
readonly fromUnion?: readonly SelectStatement[];
|
|
565
765
|
readonly where?: SqlExpr;
|
|
566
766
|
readonly groupBy?: readonly ColRef[];
|
|
567
767
|
/** HAVING predicate — grouped selects; may contain `aggCmp` expressions. */
|
|
@@ -674,6 +874,26 @@ export type InsertStatement = {
|
|
|
674
874
|
readonly onConflict?: OnConflictClause;
|
|
675
875
|
/** Rendered as RETURNING where the dialect supports it, else omitted+flagged. */
|
|
676
876
|
readonly returning?: readonly ReturningColumn[];
|
|
877
|
+
/**
|
|
878
|
+
* Bind the rows as ONE typed array per column instead of one parameter per
|
|
879
|
+
* value (`SqlDialect.bulkInsertForm` `"unnest"`, postgres): `INSERT INTO t
|
|
880
|
+
* ("a", "b") SELECT "c1", "c2" FROM unnest($1::text[], $2::int4[]) WITH
|
|
881
|
+
* ORDINALITY AS "__vibe_rows" ("c1", "c2", "ord") ORDER BY "ord"`. The text
|
|
882
|
+
* is the same for 2 rows and for 3 000, and the statement binds one parameter
|
|
883
|
+
* per column. `ORDER BY "ord"` keeps input order (sequence values, the
|
|
884
|
+
* `ON CONFLICT DO NOTHING` winner).
|
|
885
|
+
*
|
|
886
|
+
* One entry per column, in `columns` order: the column's DECLARED type facts
|
|
887
|
+
* (see {@link KeyListMember}; a `Json` entry names its storage through
|
|
888
|
+
* `nativeType`). Each array binds the BASE type (`varchar`, never
|
|
889
|
+
* `varchar(191)` — an explicit modifier cast truncates silently), so the
|
|
890
|
+
* INSERT's own assignment applies the column's length and precision exactly
|
|
891
|
+
* as it does for a VALUES parameter. `rows` stays row-major: the renderer
|
|
892
|
+
* transposes it. Every cell is a plain value, SQL NULL or a
|
|
893
|
+
* {@link JsonParamCell} — never `DEFAULT` or the database clock (the query
|
|
894
|
+
* builder keeps VALUES for those; the renderer refuses them).
|
|
895
|
+
*/
|
|
896
|
+
readonly unnest?: readonly KeyListMember[];
|
|
677
897
|
};
|
|
678
898
|
/** Conflicting rows are updated with these column values. */
|
|
679
899
|
export type OnConflictUpdate = {
|
package/dist/codecs.d.ts
CHANGED
|
@@ -122,6 +122,8 @@ export declare function parseDateTimeText(params: {
|
|
|
122
122
|
export declare function timeOfDayCodec(params: {
|
|
123
123
|
nativeType: string | undefined;
|
|
124
124
|
}): ScalarCodec | undefined;
|
|
125
|
+
/** Canonical calendar-day text only; a driver Date cannot recover the authored day. */
|
|
126
|
+
export declare const localDateCodec: ScalarCodec;
|
|
125
127
|
/**
|
|
126
128
|
* Parse stored JSON text at the centralized codec boundary. A supplied context
|
|
127
129
|
* marks a bound field: its error contains only that context, never the document
|
package/dist/dialect.d.ts
CHANGED
|
@@ -93,6 +93,19 @@ export type ConflictKeyEquality = {
|
|
|
93
93
|
*/
|
|
94
94
|
readonly duplicatesInOneStatement: "reject" | "lastWriteWins";
|
|
95
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* How an INSERT that names no column renders, when every value is its column
|
|
98
|
+
* default. `defaultValues`: `INSERT INTO t DEFAULT VALUES`, exactly one row per
|
|
99
|
+
* statement; `conflictClause` says whether a conflict clause may follow it
|
|
100
|
+
* (postgres: yes; sqlite's grammar has no upsert clause after DEFAULT VALUES).
|
|
101
|
+
* `emptyRow`: `INSERT INTO t () VALUES ()`, any number of rows (mysql).
|
|
102
|
+
*/
|
|
103
|
+
export type EmptyInsertSyntax = {
|
|
104
|
+
readonly form: "defaultValues";
|
|
105
|
+
readonly conflictClause: boolean;
|
|
106
|
+
} | {
|
|
107
|
+
readonly form: "emptyRow";
|
|
108
|
+
};
|
|
96
109
|
export type SqlDialect = {
|
|
97
110
|
readonly name: Dialect;
|
|
98
111
|
/** Frozen feature table — consumed by runtime, migrate, generator, tests. */
|
|
@@ -108,10 +121,101 @@ export type SqlDialect = {
|
|
|
108
121
|
* member, so composite membership always chunks against `paramBudget`.
|
|
109
122
|
*/
|
|
110
123
|
readonly tupleInStrategy: "rowValue" | "expand";
|
|
124
|
+
/**
|
|
125
|
+
* Key-list membership (`SqlExpr` `keyList`, the public `where: { IN }`).
|
|
126
|
+
* `unnest` binds ONE typed array per member — `("a", "b") IN (SELECT * FROM
|
|
127
|
+
* unnest($1::int8[], $2::text[]))` — so the text and its planning cost do
|
|
128
|
+
* not grow with the list (postgres 18.6, 1 000 two-column keys: planning
|
|
129
|
+
* 0.09 ms against 2.0 ms for the OR of conjunctions; 5 000 keys: 0.09 ms
|
|
130
|
+
* against 12.6 ms, and 10 ms against 285 ms execution). `rowValue` renders
|
|
131
|
+
* the row-constructor list `(a, b) IN ((?, ?), …)` (mysql: 3.9 ms for 1 000
|
|
132
|
+
* keys through an index range scan, equal to a VALUES derived table and
|
|
133
|
+
* without its numeric casts; every probed type compared exactly like `=`).
|
|
134
|
+
* `values` renders `("a", "b") IN (VALUES (?, ?), …)` (sqlite 3.51: 0.9 ms
|
|
135
|
+
* prepare + run for 1 000 keys against 1.9 ms for the row list; an OR of
|
|
136
|
+
* 1 000 conjunctions is refused there, "Expression tree is too large").
|
|
137
|
+
* The row forms bind one parameter per member, like scalar `IN (?, …)`.
|
|
138
|
+
*/
|
|
139
|
+
readonly keyListStrategy: "unnest" | "rowValue" | "values";
|
|
140
|
+
/**
|
|
141
|
+
* The keyset seek (`after`, `findPage`, a compound `cursor`, graph pages;
|
|
142
|
+
* D-01). `rowValue`: where every key sorts in one direction and no key or
|
|
143
|
+
* position value is NULL, one row-value comparison `("a", "b") > ($1, $2)`
|
|
144
|
+
* (`SqlExpr` `rowCompare`) that an index on `(a, b)` bounds as a range;
|
|
145
|
+
* with mixed directions the OR expansion ANDed with the inclusive bound on
|
|
146
|
+
* the leading key (`"a" >= $1 AND (…)`). Measured: PostgreSQL 18.6 at
|
|
147
|
+
* 500 000 rows deep 25.4 ms → 0.013 ms, SQLite 3.51 at 490 000 rows 12.9 →
|
|
148
|
+
* 0.007 ms — the OR alone is a full index walk from the first row. `or`:
|
|
149
|
+
* the OR expansion alone — MySQL's range optimizer already turns it into
|
|
150
|
+
* index ranges (22 rows touched at any depth) and SCANS a row-value
|
|
151
|
+
* inequality (194 ms at 490 000 rows deep). Nullable keys keep the OR on
|
|
152
|
+
* every dialect.
|
|
153
|
+
*/
|
|
154
|
+
readonly keysetSeekStrategy: "rowValue" | "or";
|
|
155
|
+
/**
|
|
156
|
+
* Fix lane Q1 (round 3, DB-01): how a paged include (`include: { rel: {
|
|
157
|
+
* orderBy, take, skip } }`) cuts each parent's page when an index proves the
|
|
158
|
+
* per-key form (`SelectStatement.keyPage`, `KeyPage`). `lateral`: one
|
|
159
|
+
* primary-key page per key in a `CROSS JOIN LATERAL` over the unnested key
|
|
160
|
+
* arrays — PostgreSQL 18.6, 1 000 000 children, 50 parents: 59.1 → 1.08 ms
|
|
161
|
+
* (the window sorted every child of every parent); the key-only page keeps
|
|
162
|
+
* an index-only scan the planner prefers at every `skip`, where a lateral
|
|
163
|
+
* fetching whole rows flipped to bitmap + sort and LOST (40 → 64 ms).
|
|
164
|
+
* `inLimit`: SQLite has no LATERAL — `(VALUES …)` keys joined to the child
|
|
165
|
+
* by `IN (SELECT key … LIMIT)`, a correlated list subquery per key (SQLite
|
|
166
|
+
* 3.51, 500 000 children, 50 parents: 75.2 → 0.47 ms). `window`: keep the
|
|
167
|
+
* `ROW_NUMBER()` window (MySQL: a lateral page still read every child).
|
|
168
|
+
*/
|
|
169
|
+
readonly keyPageStrategy: "lateral" | "inLimit" | "window";
|
|
170
|
+
/**
|
|
171
|
+
* Fix lane Q1 (round 3, DB-03): how a positive relation filter that pins ONE
|
|
172
|
+
* related row by a unique key renders. `exists`: the correlated `EXISTS` —
|
|
173
|
+
* PostgreSQL and MySQL turn it into a semi-join. `inSelect`: an uncorrelated
|
|
174
|
+
* `key IN (SELECT key …)` — SQLite runs a correlated `EXISTS` once per outer
|
|
175
|
+
* row (`post where author.email = x`: 134 → 0.15 ms, Post 500 000).
|
|
176
|
+
*/
|
|
177
|
+
readonly relationFilterStrategy: "exists" | "inSelect";
|
|
178
|
+
/**
|
|
179
|
+
* DB-02: when a find with a TOTAL order (it ends with the full primary key)
|
|
180
|
+
* pages with `skip` ≥ `minSkip`, the runtime cuts the page as primary keys
|
|
181
|
+
* in a derived table (`SELECT pk FROM t WHERE … ORDER BY … LIMIT ? OFFSET ?`)
|
|
182
|
+
* and joins the rows back by primary key (`fromSelect` + `innerJoins`; MySQL
|
|
183
|
+
* refuses LIMIT inside `IN (subquery)`). MySQL 26.7 / 8.4 drop the index from
|
|
184
|
+
* skip ≈ 5 000 and sort the table (500 000 rows, skip 5 000: 116.6 → 1.21 ms;
|
|
185
|
+
* 100 000: 144 → 9.3 ms) — there it applies under that rule alone.
|
|
186
|
+
* PostgreSQL gains only when the key page is an index-only scan (`authorId =
|
|
187
|
+
* 1`, skip 4 000: 4.37 → 0.24 ms) and loses up to 15 % when the filter is not
|
|
188
|
+
* covered, so `requiresCoveringIndex` asks for one declared index that serves
|
|
189
|
+
* the filter, the order and the key. `null`: never (SQLite walks an index
|
|
190
|
+
* plus rowid lookups cheaply — skip 100 000: 1.02 ms).
|
|
191
|
+
*/
|
|
192
|
+
readonly deferredJoinPage: {
|
|
193
|
+
readonly minSkip: number;
|
|
194
|
+
readonly requiresCoveringIndex: boolean;
|
|
195
|
+
} | null;
|
|
196
|
+
/**
|
|
197
|
+
* DB-07: where this engine sorts NULL when ORDER BY names no placement —
|
|
198
|
+
* `high`: above every value (postgres: last on ASC, first on DESC), `low`:
|
|
199
|
+
* below (sqlite, mysql: first on ASC, last on DESC). A b-tree stores NULLs in
|
|
200
|
+
* that position, so only the matching `nulls` placement is index order.
|
|
201
|
+
*/
|
|
202
|
+
readonly nativeNullsOrder: "high" | "low";
|
|
203
|
+
/**
|
|
204
|
+
* DB-07: whether a paged find whose LEADING order key is nullable and asks
|
|
205
|
+
* for the non-native placement reads through a `UNION ALL` of two
|
|
206
|
+
* index-ordered branches (`SelectStatement.fromUnion`: the key's non-NULL
|
|
207
|
+
* rows, then its NULL rows, each limited to `skip + take`), re-ordered and
|
|
208
|
+
* paged outside. Today's statement sorts the whole table on every page:
|
|
209
|
+
* PostgreSQL 18 `desc nulls last` 34.8 → 0.075 ms, MySQL 26.7 `asc nulls
|
|
210
|
+
* last` 54.5 → 0.85 ms. SQLite 3.51 already walks the index for either
|
|
211
|
+
* placement (0.005 ms today, 0.020 ms as a union) — `false` there.
|
|
212
|
+
*/
|
|
213
|
+
readonly nullsUnionPage: boolean;
|
|
111
214
|
/**
|
|
112
215
|
* Membership on a time-of-day column (`inArray` with `timeOfDay`): `in`
|
|
113
216
|
* renders like any other membership; `equalities` renders an OR of `=`
|
|
114
|
-
* comparisons
|
|
217
|
+
* comparisons (a key list with a time-of-day member: an OR of complete
|
|
218
|
+
* conjunctions). MySQL 8.4 types a `?` inside a multi-value IN list against a
|
|
115
219
|
* TIME(n) column as TIME(6) and matches nothing unless n is 6 (live on
|
|
116
220
|
* 8.4.11; 26.7 matches); `=` converts the parameter to the column's TIME on
|
|
117
221
|
* every version.
|
|
@@ -230,6 +334,19 @@ export type SqlDialect = {
|
|
|
230
334
|
* rows are grouped by column set into separate statements there (M4).
|
|
231
335
|
*/
|
|
232
336
|
readonly rowDefaultKeyword: boolean;
|
|
337
|
+
/**
|
|
338
|
+
* How a multi-row INSERT whose rows all bind plain values may render
|
|
339
|
+
* (`InsertStatement.unnest`). `unnest` binds ONE typed array per column —
|
|
340
|
+
* `INSERT … SELECT … FROM unnest($1::text[], …) WITH ORDINALITY … ORDER BY`
|
|
341
|
+
* — so the text is constant and a statement binds one parameter per column
|
|
342
|
+
* (postgres and PGlite; the type table, efficiency campaign EPIC C, proved
|
|
343
|
+
* equal stored values and errors on adapter-pg, adapter-bun and PGlite).
|
|
344
|
+
* `values` keeps one parameter per value (mysql and sqlite have no typed
|
|
345
|
+
* array parameters); the renderer refuses an `unnest` statement there.
|
|
346
|
+
*/
|
|
347
|
+
readonly bulkInsertForm: "unnest" | "values";
|
|
348
|
+
/** How an INSERT that names no column renders ({@link EmptyInsertSyntax}). */
|
|
349
|
+
readonly emptyInsert: EmptyInsertSyntax;
|
|
233
350
|
/**
|
|
234
351
|
* How a {@link ChainStatement} (an ordered chain of read and data-modifying
|
|
235
352
|
* steps ending in one SELECT — round-trip campaign EPIC 4/F) renders, or
|
|
@@ -5,6 +5,7 @@ export declare function renderMysqlCheckProbe(params: {
|
|
|
5
5
|
dialect: SqlDialect;
|
|
6
6
|
operation: "clone" | "add" | "read" | "drop";
|
|
7
7
|
probe: string;
|
|
8
|
+
/** Source for clone, or qualified live table for a transient SHOW CREATE comparison. */
|
|
8
9
|
table?: {
|
|
9
10
|
readonly namespace: string;
|
|
10
11
|
readonly name: string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { QualifiedSqlName } from "@vibeorm/schema";
|
|
2
|
+
import type { SqlDialect } from "../dialect.ts";
|
|
3
|
+
import type { ExtractedGeneratedColumn, GeneratedColumnDeclaration } from "../generated-columns.ts";
|
|
4
|
+
import type { RenderedQuery } from "../render.ts";
|
|
5
|
+
/** MySQL stored syntax, placed after complete type/charset/collation information. */
|
|
6
|
+
export declare function renderMysqlGeneratedColumnClause({ generated }: {
|
|
7
|
+
readonly generated: GeneratedColumnDeclaration;
|
|
8
|
+
}): string;
|
|
9
|
+
/** Temporary CREATE/DROP operations avoid ALTER's implicit-commit boundary. */
|
|
10
|
+
export type MysqlGeneratedColumnProbe = {
|
|
11
|
+
readonly operation: "context";
|
|
12
|
+
} | {
|
|
13
|
+
readonly operation: "clone";
|
|
14
|
+
readonly probe: string;
|
|
15
|
+
readonly table: QualifiedSqlName;
|
|
16
|
+
} | {
|
|
17
|
+
readonly operation: "create";
|
|
18
|
+
readonly probe: string;
|
|
19
|
+
readonly definition: string;
|
|
20
|
+
readonly column: string;
|
|
21
|
+
readonly columnDefinition: string;
|
|
22
|
+
readonly backslashEscapes: boolean;
|
|
23
|
+
readonly after?: string;
|
|
24
|
+
} | {
|
|
25
|
+
readonly operation: "read";
|
|
26
|
+
readonly probe: string;
|
|
27
|
+
readonly table?: QualifiedSqlName;
|
|
28
|
+
} | {
|
|
29
|
+
readonly operation: "drop";
|
|
30
|
+
readonly probe: string;
|
|
31
|
+
};
|
|
32
|
+
/** Render scratch SQL from independently provisioned table definitions; migrate owns cleanup. */
|
|
33
|
+
export declare function renderMysqlGeneratedColumnProbe({ dialect, probe }: {
|
|
34
|
+
readonly dialect: SqlDialect;
|
|
35
|
+
readonly probe: MysqlGeneratedColumnProbe;
|
|
36
|
+
}): RenderedQuery;
|
|
37
|
+
/** SHOW CREATE's own escaping rules apply; information_schema uses a different spelling channel. */
|
|
38
|
+
export declare function extractMysqlGeneratedColumn({ definition, column, backslashEscapes }: {
|
|
39
|
+
readonly definition: string;
|
|
40
|
+
readonly column: string;
|
|
41
|
+
readonly backslashEscapes: boolean;
|
|
42
|
+
}): ExtractedGeneratedColumn | undefined;
|
|
43
|
+
//# sourceMappingURL=mysql-generated-columns.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IndexKeyTermIR } from "@vibeorm/schema";
|
|
2
|
+
import type { SqlDialect } from "../dialect.ts";
|
|
3
|
+
import type { IndexExpressionProbeParams, IndexKeyOperand } from "../index-expressions.ts";
|
|
4
|
+
import type { PredicateModel } from "../predicate.ts";
|
|
5
|
+
import type { RenderedQuery } from "../render.ts";
|
|
6
|
+
/** Qualify only expression-bearing keys through schema's shared width rule; never impose new bounds on ordinary indexes. */
|
|
7
|
+
export declare function assertMysqlIndexKeyStorage({ model, terms }: {
|
|
8
|
+
readonly dialect: SqlDialect;
|
|
9
|
+
readonly model: PredicateModel;
|
|
10
|
+
readonly terms: readonly IndexKeyTermIR[];
|
|
11
|
+
}): void;
|
|
12
|
+
/** Recover SHOW CREATE key interiors, including exact CAST/charset/collation bytes. */
|
|
13
|
+
export declare function extractMysqlIndexKeys({ definition, index, backslashEscapes }: {
|
|
14
|
+
readonly definition: string;
|
|
15
|
+
readonly index: string;
|
|
16
|
+
readonly backslashEscapes: boolean;
|
|
17
|
+
}): readonly IndexKeyOperand[] | undefined;
|
|
18
|
+
/** Reuse E's temporary-clone/read/drop operations, extending only CREATE's key replacement seam. */
|
|
19
|
+
export declare function renderMysqlIndexExpressionProbe({ ...params }: IndexExpressionProbeParams): readonly RenderedQuery[];
|
|
20
|
+
//# sourceMappingURL=mysql-index-expressions.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SqlDialect } from "../dialect.ts";
|
|
2
|
+
import type { EventRowRuleContext, RenderedRowRule } from "../row-rules.ts";
|
|
3
|
+
/** Emit mode-safe SIGNAL diagnostics and one unfiltered BEFORE trigger per event. */
|
|
4
|
+
export declare function renderMysqlRowRule({ dialect, context }: {
|
|
5
|
+
readonly dialect: SqlDialect;
|
|
6
|
+
readonly context: EventRowRuleContext;
|
|
7
|
+
}): RenderedRowRule;
|
|
8
|
+
//# sourceMappingURL=mysql-row-rules.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { QualifiedSqlName } from "@vibeorm/schema";
|
|
2
|
+
import type { SqlDialect } from "../dialect.ts";
|
|
3
|
+
import type { GeneratedColumnDeclaration } from "../generated-columns.ts";
|
|
4
|
+
import type { RenderedQuery } from "../render.ts";
|
|
5
|
+
/** PostgreSQL stored syntax; the public dispatcher performs declaration admission. */
|
|
6
|
+
export declare function renderPostgresGeneratedColumnClause({ generated }: {
|
|
7
|
+
readonly generated: GeneratedColumnDeclaration;
|
|
8
|
+
}): string;
|
|
9
|
+
/** The migration owner creates the desired base context inside the private savepoint. */
|
|
10
|
+
export type PostgresGeneratedColumnProbe = {
|
|
11
|
+
readonly operation: "savepoint" | "rollback" | "release";
|
|
12
|
+
readonly savepoint: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly operation: "add";
|
|
15
|
+
readonly table: QualifiedSqlName;
|
|
16
|
+
readonly column: string;
|
|
17
|
+
readonly definition: string;
|
|
18
|
+
};
|
|
19
|
+
/** Render pinned-session scratch statements; this helper never executes or manages a session. */
|
|
20
|
+
export declare function renderPostgresGeneratedColumnProbe({ dialect, probe }: {
|
|
21
|
+
readonly dialect: SqlDialect;
|
|
22
|
+
readonly probe: PostgresGeneratedColumnProbe;
|
|
23
|
+
}): RenderedQuery;
|
|
24
|
+
/** Approved stored-generated to ordinary conversion, retaining the present stored values. */
|
|
25
|
+
export declare function renderPostgresDropGeneratedExpression({ dialect, table, column }: {
|
|
26
|
+
readonly dialect: SqlDialect;
|
|
27
|
+
readonly table: QualifiedSqlName;
|
|
28
|
+
readonly column: string;
|
|
29
|
+
}): RenderedQuery;
|
|
30
|
+
//# sourceMappingURL=postgres-generated-columns.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IndexExpressionProbeParams, IndexKeyOperand } from "../index-expressions.ts";
|
|
2
|
+
import type { RenderedQuery } from "../render.ts";
|
|
3
|
+
/** CREATE INDEX extraction is conservative; structured catalog rows remain authoritative. */
|
|
4
|
+
export declare function extractPostgresIndexKeys({ definition, index }: {
|
|
5
|
+
readonly definition: string;
|
|
6
|
+
readonly index: string;
|
|
7
|
+
}): readonly IndexKeyOperand[] | undefined;
|
|
8
|
+
/** Caller owns a fixed search_path and rollback savepoint; no populated user table is indexed. */
|
|
9
|
+
export declare function renderPostgresIndexExpressionProbe({ ...params }: IndexExpressionProbeParams): readonly RenderedQuery[];
|
|
10
|
+
//# sourceMappingURL=postgres-index-expressions.d.ts.map
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import type { QualifiedSqlName } from "@vibeorm/schema";
|
|
2
2
|
import type { SqlDialect } from "../dialect.ts";
|
|
3
3
|
import type { RenderedQuery } from "../render.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Turn JIT compilation off for the rest of the current transaction and return
|
|
6
|
+
* the previous `jit` value as `previous` (read before the change). The bulk
|
|
7
|
+
* index-key read costs far above `jit_above_cost`, and compiling it takes longer
|
|
8
|
+
* than running it. Transaction-local: outside a transaction block it changes nothing.
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderPostgresJitSuspend(params: {
|
|
11
|
+
dialect: SqlDialect;
|
|
12
|
+
}): RenderedQuery;
|
|
13
|
+
/** Restore the transaction's `jit` value read by {@link renderPostgresJitSuspend}. */
|
|
14
|
+
export declare function renderPostgresJitRestore(params: {
|
|
15
|
+
dialect: SqlDialect;
|
|
16
|
+
previous: string;
|
|
17
|
+
}): RenderedQuery;
|
|
4
18
|
/** Physical operands and unambiguous server-default evidence for actual type/access-method pairs. */
|
|
5
19
|
export declare function renderPostgresIndexKeys(params: {
|
|
6
20
|
dialect: SqlDialect;
|
|
7
21
|
table?: QualifiedSqlName;
|
|
8
22
|
namespaces?: readonly string[];
|
|
23
|
+
expressionMetadata?: boolean;
|
|
9
24
|
}): RenderedQuery;
|
|
10
25
|
//# sourceMappingURL=postgres-index-keys.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FieldIR, QualifiedSqlName, RowRuleIR, SqlObjectIdentity } from "@vibeorm/schema";
|
|
2
|
+
import type { SqlDialect } from "../dialect.ts";
|
|
3
|
+
import type { RenderedRowRule } from "../row-rules.ts";
|
|
4
|
+
/** A finalized PostgreSQL comparison context, supplied by the canonical schema collector. */
|
|
5
|
+
export type PostgresRowRuleContext = {
|
|
6
|
+
readonly model: string;
|
|
7
|
+
readonly table: QualifiedSqlName;
|
|
8
|
+
readonly rule: RowRuleIR;
|
|
9
|
+
readonly functionIdentity: Extract<SqlObjectIdentity, {
|
|
10
|
+
readonly kind: "function";
|
|
11
|
+
}>;
|
|
12
|
+
readonly triggerIdentity: {
|
|
13
|
+
readonly kind: "trigger";
|
|
14
|
+
readonly table: QualifiedSqlName;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
};
|
|
17
|
+
readonly protectedFields: readonly FieldIR[];
|
|
18
|
+
readonly gateField?: FieldIR;
|
|
19
|
+
};
|
|
20
|
+
/** Emit one ordinary invoker function and an unfiltered BEFORE row trigger; no live objects are taken over. */
|
|
21
|
+
export declare function renderPostgresRowRule({ dialect, context }: {
|
|
22
|
+
readonly dialect: SqlDialect;
|
|
23
|
+
readonly context: PostgresRowRuleContext;
|
|
24
|
+
}): RenderedRowRule;
|
|
25
|
+
//# sourceMappingURL=postgres-row-rules.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ExtractedGeneratedColumn, GeneratedColumnDeclaration } from "../generated-columns.ts";
|
|
2
|
+
/** SQLite stored syntax; adding a stored column still requires the migrate rebuild path. */
|
|
3
|
+
export declare function renderSqliteGeneratedColumnClause({ generated }: {
|
|
4
|
+
readonly generated: GeneratedColumnDeclaration;
|
|
5
|
+
}): string;
|
|
6
|
+
/** Shared source-slice extraction for SQLite source and MySQL SHOW CREATE, not SQL equivalence. */
|
|
7
|
+
export declare function extractGenerationFromDefinition({ definition, column, backslashEscapes, mysql }: {
|
|
8
|
+
readonly definition: string;
|
|
9
|
+
readonly column: string;
|
|
10
|
+
readonly backslashEscapes?: boolean;
|
|
11
|
+
readonly mysql?: boolean;
|
|
12
|
+
}): ExtractedGeneratedColumn | undefined;
|
|
13
|
+
/** Recover the exact AS interior; omitted storage means virtual, never inferred stored. */
|
|
14
|
+
export declare function extractSqliteGeneratedColumn({ definition, column }: {
|
|
15
|
+
readonly definition: string;
|
|
16
|
+
readonly column: string;
|
|
17
|
+
}): ExtractedGeneratedColumn | undefined;
|
|
18
|
+
//# sourceMappingURL=sqlite-generated-columns.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IndexKeyOperand } from "../index-expressions.ts";
|
|
2
|
+
import type { TableDefinitionToken } from "./sqlite-table-definition.ts";
|
|
3
|
+
/** Exact outer-key slices shared by CREATE INDEX and MySQL table-key clauses. */
|
|
4
|
+
export declare function extractIndexKeyList({ sql, open, close, tokens, wrapped, removeWrapper }: {
|
|
5
|
+
readonly sql: string;
|
|
6
|
+
readonly open: TableDefinitionToken;
|
|
7
|
+
readonly close: TableDefinitionToken;
|
|
8
|
+
readonly tokens: readonly TableDefinitionToken[];
|
|
9
|
+
readonly wrapped?: boolean;
|
|
10
|
+
readonly removeWrapper?: boolean;
|
|
11
|
+
}): readonly IndexKeyOperand[] | undefined;
|
|
12
|
+
/** Parse the CREATE INDEX header without interpreting any scalar expression. */
|
|
13
|
+
export declare function extractStandaloneIndexKeys({ definition, index, postgres }: {
|
|
14
|
+
readonly definition: string;
|
|
15
|
+
readonly index: string;
|
|
16
|
+
readonly postgres?: boolean;
|
|
17
|
+
}): readonly IndexKeyOperand[] | undefined;
|
|
18
|
+
/** SQLite source spelling is the evidence; CAST alone never proves a plain Decimal key. */
|
|
19
|
+
export declare function extractSqliteIndexKeys({ definition, index }: {
|
|
20
|
+
readonly definition: string;
|
|
21
|
+
readonly index: string;
|
|
22
|
+
}): readonly IndexKeyOperand[] | undefined;
|
|
23
|
+
//# sourceMappingURL=sqlite-index-expressions.d.ts.map
|