turbine-orm 0.77.1 → 0.78.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 -9
- package/dist/cjs/cli/config.d.ts +7 -1
- package/dist/cjs/cli/config.js +11 -2
- package/dist/cjs/cli/destructive.d.ts +1 -1
- package/dist/cjs/cli/destructive.js +307 -9
- package/dist/cjs/cli/index.js +252 -42
- package/dist/cjs/cli/mcp.d.ts +23 -0
- package/dist/cjs/cli/mcp.js +190 -152
- package/dist/cjs/cli/migrate.d.ts +243 -3
- package/dist/cjs/cli/migrate.js +432 -43
- package/dist/cjs/cli/sql-statements.js +27 -0
- package/dist/cjs/cli/studio.d.ts +0 -1
- package/dist/cjs/cli/studio.js +9 -7
- package/dist/cjs/client.d.ts +8 -1
- package/dist/cjs/client.js +7 -0
- package/dist/cjs/connection-url.d.ts +82 -0
- package/dist/cjs/connection-url.js +187 -1
- package/dist/cjs/errors.d.ts +112 -12
- package/dist/cjs/errors.js +558 -114
- package/dist/cjs/generate.js +47 -15
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/introspect.d.ts +33 -0
- package/dist/cjs/introspect.js +54 -1
- package/dist/cjs/mssql.js +21 -1
- package/dist/cjs/nested-write.js +85 -14
- package/dist/cjs/pipeline-submittable.d.ts +2 -0
- package/dist/cjs/pipeline-submittable.js +88 -3
- package/dist/cjs/pipeline.js +13 -1
- package/dist/cjs/powdb-introspect.d.ts +5 -1
- package/dist/cjs/powdb-introspect.js +5 -1
- package/dist/cjs/powql.d.ts +14 -0
- package/dist/cjs/powql.js +44 -4
- package/dist/cjs/prisma-compat.js +95 -8
- package/dist/cjs/query/aggregates.js +56 -6
- package/dist/cjs/query/builder.d.ts +76 -13
- package/dist/cjs/query/builder.js +188 -58
- package/dist/cjs/query/compound-unique.d.ts +76 -0
- package/dist/cjs/query/compound-unique.js +129 -0
- package/dist/cjs/query/index.d.ts +1 -1
- package/dist/cjs/query/types.d.ts +65 -11
- package/dist/cjs/query/where.d.ts +85 -19
- package/dist/cjs/query/where.js +262 -47
- package/dist/cjs/query/writes.d.ts +11 -2
- package/dist/cjs/query/writes.js +116 -21
- package/dist/cjs/seed.d.ts +16 -0
- package/dist/cjs/seed.js +16 -0
- package/dist/cli/config.d.ts +7 -1
- package/dist/cli/config.js +11 -2
- package/dist/cli/destructive.d.ts +1 -1
- package/dist/cli/destructive.js +307 -9
- package/dist/cli/index.js +254 -44
- package/dist/cli/mcp.d.ts +23 -0
- package/dist/cli/mcp.js +187 -150
- package/dist/cli/migrate.d.ts +243 -3
- package/dist/cli/migrate.js +423 -45
- package/dist/cli/sql-statements.js +27 -0
- package/dist/cli/studio.d.ts +0 -1
- package/dist/cli/studio.js +10 -7
- package/dist/client.d.ts +8 -1
- package/dist/client.js +7 -0
- package/dist/connection-url.d.ts +82 -0
- package/dist/connection-url.js +183 -0
- package/dist/errors.d.ts +112 -12
- package/dist/errors.js +558 -114
- package/dist/generate.js +47 -15
- package/dist/index.d.ts +1 -1
- package/dist/introspect.d.ts +33 -0
- package/dist/introspect.js +53 -1
- package/dist/mssql.js +21 -1
- package/dist/nested-write.js +85 -14
- package/dist/pipeline-submittable.d.ts +2 -0
- package/dist/pipeline-submittable.js +87 -3
- package/dist/pipeline.js +14 -2
- package/dist/powdb-introspect.d.ts +5 -1
- package/dist/powdb-introspect.js +5 -1
- package/dist/powql.d.ts +14 -0
- package/dist/powql.js +45 -5
- package/dist/prisma-compat.js +96 -9
- package/dist/query/aggregates.js +56 -6
- package/dist/query/builder.d.ts +76 -13
- package/dist/query/builder.js +188 -58
- package/dist/query/compound-unique.d.ts +76 -0
- package/dist/query/compound-unique.js +126 -1
- package/dist/query/index.d.ts +1 -1
- package/dist/query/types.d.ts +65 -11
- package/dist/query/where.d.ts +85 -19
- package/dist/query/where.js +260 -47
- package/dist/query/writes.d.ts +11 -2
- package/dist/query/writes.js +117 -22
- package/dist/seed.d.ts +16 -0
- package/dist/seed.js +16 -0
- package/package.json +3 -3
- package/skills/turbine-orm/SKILL.md +37 -10
|
@@ -1172,9 +1172,11 @@ class QueryInterface {
|
|
|
1172
1172
|
}
|
|
1173
1173
|
/**
|
|
1174
1174
|
* The field names a `cursor` actually seeks on (its own keys with a defined
|
|
1175
|
-
* value), in
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1175
|
+
* value), in canonical sorted order. This is the diagnostic / implicit-
|
|
1176
|
+
* ordering view; the seek itself orders the fields by their `orderBy`
|
|
1177
|
+
* precedence (see {@link cursorSeekEntries}). Empty for a missing cursor or
|
|
1178
|
+
* one whose every value is `undefined` (which emits no seek condition at
|
|
1179
|
+
* all, so it does not paginate).
|
|
1178
1180
|
*/
|
|
1179
1181
|
cursorFields(cursor) {
|
|
1180
1182
|
if (!cursor || typeof cursor !== 'object')
|
|
@@ -1188,18 +1190,20 @@ class QueryInterface {
|
|
|
1188
1190
|
* The ascending ordering implied by a `cursor`, or `undefined` when the shape
|
|
1189
1191
|
* is too ambiguous to order safely.
|
|
1190
1192
|
*
|
|
1191
|
-
* A cursor seek
|
|
1192
|
-
* so the ONLY ordering coherent with it is on
|
|
1193
|
-
* a seek on column X by column Y walks the table in an
|
|
1194
|
-
* follow, which skips and repeats rows just as badly
|
|
1195
|
-
* is why this orders on the cursor field rather than
|
|
1196
|
-
* key when the two differ.
|
|
1193
|
+
* A cursor seek compares against the cursor's own field(s) (`col > $n`, `<`
|
|
1194
|
+
* when the orderBy says desc), so the ONLY ordering coherent with it is on
|
|
1195
|
+
* those fields: ordering a seek on column X by column Y walks the table in an
|
|
1196
|
+
* order the seek does not follow, which skips and repeats rows just as badly
|
|
1197
|
+
* as no order at all. That is why this orders on the cursor field rather than
|
|
1198
|
+
* blindly on the primary key when the two differ.
|
|
1197
1199
|
*
|
|
1198
1200
|
* Returns `undefined` (warn, inject nothing) for two shapes:
|
|
1199
|
-
* - a MULTI-field cursor.
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1201
|
+
* - a MULTI-field cursor. The seek is a proper keyset predicate, but its
|
|
1202
|
+
* column PRECEDENCE comes from the `orderBy` ({@link cursorSeekEntries}),
|
|
1203
|
+
* and with no orderBy there is nothing to derive it from: the cursor
|
|
1204
|
+
* object's key order is canonicalized away, so `(a asc, b asc)` would be a
|
|
1205
|
+
* guess at which key the caller meant to lead. The caller must state the
|
|
1206
|
+
* order, and the unordered-page warning says so.
|
|
1203
1207
|
* - a field that does not resolve to a real column. Column validation belongs
|
|
1204
1208
|
* to the normal build path, which raises a precise error; synthesizing an
|
|
1205
1209
|
* ORDER BY on it here would only change which error the caller sees.
|
|
@@ -1217,6 +1221,83 @@ class QueryInterface {
|
|
|
1217
1221
|
}
|
|
1218
1222
|
return { [field]: 'asc' };
|
|
1219
1223
|
}
|
|
1224
|
+
/**
|
|
1225
|
+
* The fields a `cursor` seeks on, in KEYSET order with their seek direction.
|
|
1226
|
+
* THE single authority the cache fingerprint (`cur=`), the SQL build and the
|
|
1227
|
+
* cache-hit param collect all consume, so the three cannot disagree about
|
|
1228
|
+
* which value binds to which `$n`.
|
|
1229
|
+
*
|
|
1230
|
+
* Keyset order is the `orderBy` precedence: the predicate for
|
|
1231
|
+
* `orderBy: [{ viewCount }, { id }]` must test `view_count` first and `id`
|
|
1232
|
+
* only within equal `view_count`, whatever order the caller wrote the cursor
|
|
1233
|
+
* object in (its keys are canonicalized for the cache anyway). A cursor field
|
|
1234
|
+
* the orderBy does not name trails the named ones in sorted key order and
|
|
1235
|
+
* seeks ascending, the same default a single-field cursor with no orderBy has
|
|
1236
|
+
* always had.
|
|
1237
|
+
*
|
|
1238
|
+
* Directions are indexed by the RESOLVED COLUMN, never the caller's key: both
|
|
1239
|
+
* `cursor` and `orderBy` take either spelling, so a cursor written
|
|
1240
|
+
* `{ created_at }` against `orderBy: { createdAt: 'desc' }` used to miss the
|
|
1241
|
+
* lookup, default to ascending, and seek the wrong side of the page. The
|
|
1242
|
+
* `{ sort, nulls }` spec form is normalized for the same reason. A relation /
|
|
1243
|
+
* JSON-path / vector orderBy key resolves to no column and is skipped.
|
|
1244
|
+
*
|
|
1245
|
+
* An unknown cursor field throws the same E003 here that the build path
|
|
1246
|
+
* threw before this helper existed; the fingerprint simply meets it first.
|
|
1247
|
+
*/
|
|
1248
|
+
cursorSeekEntries(cursor, orderBy) {
|
|
1249
|
+
const orderPos = new Map();
|
|
1250
|
+
const orderDesc = new Map();
|
|
1251
|
+
for (const [ok, od] of (0, filters_js_1.orderByEntries)(orderBy)) {
|
|
1252
|
+
const ocol = (0, utils_js_1.resolveColumnName)(this.tableMeta, ok);
|
|
1253
|
+
if (ocol === undefined)
|
|
1254
|
+
continue;
|
|
1255
|
+
if (!orderPos.has(ocol))
|
|
1256
|
+
orderPos.set(ocol, orderPos.size);
|
|
1257
|
+
// Last wins, matching object-key semantics (duplicates are refused
|
|
1258
|
+
// upstream anyway, so in practice there is exactly one).
|
|
1259
|
+
orderDesc.set(ocol, (0, filters_js_1.isOrderBySpec)(od) ? od.sort === 'desc' : od === 'desc');
|
|
1260
|
+
}
|
|
1261
|
+
const entries = (0, filters_js_1.sortedEntries)(cursor)
|
|
1262
|
+
.filter(([, v]) => v !== undefined)
|
|
1263
|
+
.map(([k, value]) => {
|
|
1264
|
+
const column = this.toColumn(k);
|
|
1265
|
+
return { column, value, desc: orderDesc.get(column) === true };
|
|
1266
|
+
});
|
|
1267
|
+
// Stable sort over the canonical (sorted-key) list: orderBy precedence
|
|
1268
|
+
// first, unnamed fields after it in their sorted order.
|
|
1269
|
+
return entries.sort((a, b) => (orderPos.get(a.column) ?? Number.MAX_SAFE_INTEGER) - (orderPos.get(b.column) ?? Number.MAX_SAFE_INTEGER));
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* The keyset predicate for cursor terms in keyset order.
|
|
1273
|
+
*
|
|
1274
|
+
* One field is the plain `col > $1` (byte-identical to every single-field
|
|
1275
|
+
* cursor ever emitted). Two or more expand to
|
|
1276
|
+
* `(c1 > $1 OR (c1 = $1 AND c2 > $2) OR (c1 = $1 AND c2 = $2 AND c3 > $3))`,
|
|
1277
|
+
* with `<` for a `desc` field: the row-value form `(c1, c2) > ($1, $2)` is
|
|
1278
|
+
* shorter, but it cannot express a MIXED direction at all and SQL Server has
|
|
1279
|
+
* no row-value comparison, so the expanded form is the one path every engine
|
|
1280
|
+
* and every direction set share. Each value is bound ONCE and its `$n` is
|
|
1281
|
+
* referenced by every branch that needs it (legal on every supported
|
|
1282
|
+
* placeholder syntax), which is what keeps the param count equal to the field
|
|
1283
|
+
* count on both the build and the collect side.
|
|
1284
|
+
*
|
|
1285
|
+
* The former `c1 > $1 AND c2 > $2` was a conjunction, not a seek: it skipped
|
|
1286
|
+
* every row whose leading key EQUALED the cursor's, so a table with few
|
|
1287
|
+
* distinct leading values lost most of its rows across a page walk, silently.
|
|
1288
|
+
*/
|
|
1289
|
+
keysetPredicate(terms) {
|
|
1290
|
+
const compare = (t) => `${t.column} ${t.desc ? '<' : '>'} ${t.placeholder}`;
|
|
1291
|
+
if (terms.length === 1)
|
|
1292
|
+
return compare(terms[0]);
|
|
1293
|
+
const branches = terms.map((term, i) => {
|
|
1294
|
+
if (i === 0)
|
|
1295
|
+
return compare(term);
|
|
1296
|
+
const prefix = terms.slice(0, i).map((t) => `${t.column} = ${t.placeholder}`);
|
|
1297
|
+
return `(${[...prefix, compare(term)].join(' AND ')})`;
|
|
1298
|
+
});
|
|
1299
|
+
return `(${branches.join(' OR ')})`;
|
|
1300
|
+
}
|
|
1220
1301
|
/**
|
|
1221
1302
|
* Whether a findMany paginates (`limit` / `take` / `offset` / `cursor`) but
|
|
1222
1303
|
* declares no ordering, which makes the returned page NON-DETERMINISTIC:
|
|
@@ -1701,17 +1782,27 @@ class QueryInterface {
|
|
|
1701
1782
|
// Query-level opt-in threaded onto every follow-up child `buildFindMany`,
|
|
1702
1783
|
// so a batched load excludes/includes PII exactly as the join strategy.
|
|
1703
1784
|
includePii,
|
|
1704
|
-
|
|
1785
|
+
// `ref` is the follow-up query's FROM-item AS THE SQL REFERS TO IT: the
|
|
1786
|
+
// quoted child table for a hasMany `_count`, the bare junction alias `t`
|
|
1787
|
+
// for the m2m one. Compiled through the rendered-reference scope, which
|
|
1788
|
+
// uses it verbatim for the column qualifier and for a nested relation
|
|
1789
|
+
// filter's correlation parent alike. It went through the BARE-alias scope
|
|
1790
|
+
// before, which quotes what it is given, so a `globalFilters` entry that
|
|
1791
|
+
// was itself a relation filter emitted `"""posts"""` into the EXISTS
|
|
1792
|
+
// body and the count failed 42P01. Reproduced live; the plain batched
|
|
1793
|
+
// relation fetch was never affected, because that one goes through the
|
|
1794
|
+
// child's own buildFindMany and merges the filter unqualified.
|
|
1795
|
+
tableGlobalFilter: (table, ref, precedingParams) => {
|
|
1705
1796
|
const gf = this.resolveGlobalFilter(table, resolvedSkip);
|
|
1706
1797
|
if (!gf)
|
|
1707
1798
|
return null;
|
|
1708
1799
|
const meta = this.schema.tables[table];
|
|
1709
1800
|
if (!meta)
|
|
1710
1801
|
return null;
|
|
1711
|
-
// Seed the param array with `precedingParams` placeholders so
|
|
1712
|
-
//
|
|
1802
|
+
// Seed the param array with `precedingParams` placeholders so the
|
|
1803
|
+
// builder numbers the gf params after the already-bound ones.
|
|
1713
1804
|
const seeded = new Array(precedingParams).fill(undefined);
|
|
1714
|
-
const clause = this.
|
|
1805
|
+
const clause = whereMod.buildRenderedRefWhere(this.ctx, table, meta, ref, gf, seeded);
|
|
1715
1806
|
if (!clause)
|
|
1716
1807
|
return null;
|
|
1717
1808
|
return { clause, params: seeded.slice(precedingParams) };
|
|
@@ -2735,10 +2826,12 @@ class QueryInterface {
|
|
|
2735
2826
|
})
|
|
2736
2827
|
.join(',')
|
|
2737
2828
|
: '';
|
|
2829
|
+
// Keyset order AND per-field direction: a multi-field cursor's predicate
|
|
2830
|
+
// is one OR-branch per field in orderBy precedence, and `<` / `>` are SQL
|
|
2831
|
+
// text, so `asc` and `desc` (or two precedences) can never share a template.
|
|
2738
2832
|
const cursorFp = args?.cursor
|
|
2739
|
-
?
|
|
2740
|
-
.
|
|
2741
|
-
.sort()
|
|
2833
|
+
? this.cursorSeekEntries(args.cursor, args.orderBy)
|
|
2834
|
+
.map((e) => `${e.column}:${e.desc ? 'd' : 'a'}`)
|
|
2742
2835
|
.join(',')
|
|
2743
2836
|
: '';
|
|
2744
2837
|
// distinct must fingerprint in USER order: the SQL emits `DISTINCT ON` in
|
|
@@ -2848,39 +2941,16 @@ class QueryInterface {
|
|
|
2848
2941
|
// where → cursor order (the collect path mirrors this exactly).
|
|
2849
2942
|
let tail = freshWhereSql;
|
|
2850
2943
|
if (args?.cursor) {
|
|
2851
|
-
//
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
// Indexed by the RESOLVED COLUMN, never the caller's key: both
|
|
2859
|
-
// `cursor` and `orderBy` take either spelling, so a cursor written
|
|
2860
|
-
// `{ created_at }` against `orderBy: { createdAt: 'desc' }` missed
|
|
2861
|
-
// this lookup, defaulted to ascending, and emitted `created_at > $n`
|
|
2862
|
-
// under `ORDER BY created_at DESC` — the wrong page, silently. Same
|
|
2863
|
-
// failure the `{ sort, nulls }` normalization below prevents, reached
|
|
2864
|
-
// through the spelling instead of the value shape. A relation /
|
|
2865
|
-
// JSON-path / vector key resolves to no column and is skipped.
|
|
2866
|
-
const orderDirByColumn = new Map();
|
|
2867
|
-
for (const [ok, od] of (0, filters_js_1.orderByEntries)(args.orderBy)) {
|
|
2868
|
-
const ocol = (0, utils_js_1.resolveColumnName)(this.tableMeta, ok);
|
|
2869
|
-
if (ocol !== undefined)
|
|
2870
|
-
orderDirByColumn.set(ocol, od);
|
|
2871
|
-
}
|
|
2872
|
-
const cursorConditions = cursorEntries.map(([k, v]) => {
|
|
2873
|
-
const rawCol = this.toColumn(k);
|
|
2874
|
-
const col = this.q(rawCol);
|
|
2875
|
-
// orderBy values can be the { sort, nulls } spec form: normalize
|
|
2876
|
-
// before comparing, or a desc spec would seek the ascending side.
|
|
2877
|
-
const dir = orderDirByColumn.get(rawCol);
|
|
2878
|
-
const desc = (0, filters_js_1.isOrderBySpec)(dir) ? dir.sort === 'desc' : dir === 'desc';
|
|
2879
|
-
const op = desc ? '<' : '>';
|
|
2880
|
-
freshParams.push(v);
|
|
2881
|
-
return `${qt}.${col} ${op} ${this.p(freshParams.length)}`;
|
|
2944
|
+
// Keyset order (orderBy precedence), MUST match cursorFp and the
|
|
2945
|
+
// cache-hit collect below: both go through cursorSeekEntries.
|
|
2946
|
+
const seek = this.cursorSeekEntries(args.cursor, args.orderBy);
|
|
2947
|
+
if (seek.length > 0) {
|
|
2948
|
+
const terms = seek.map((e) => {
|
|
2949
|
+
freshParams.push(e.value);
|
|
2950
|
+
return { column: `${qt}.${this.q(e.column)}`, placeholder: this.p(freshParams.length), desc: e.desc };
|
|
2882
2951
|
});
|
|
2883
|
-
|
|
2952
|
+
const predicate = this.keysetPredicate(terms);
|
|
2953
|
+
tail += freshWhereSql ? ` AND ${predicate}` : ` WHERE ${predicate}`;
|
|
2884
2954
|
}
|
|
2885
2955
|
}
|
|
2886
2956
|
// ORDER BY is built AFTER the cursor pushes (param order
|
|
@@ -2899,10 +2969,40 @@ class QueryInterface {
|
|
|
2899
2969
|
throw new errors_js_1.ValidationError('`distinct` cannot be combined with vector distance ordering.');
|
|
2900
2970
|
}
|
|
2901
2971
|
const userOrder = this.buildOrderBy(args.orderBy, freshParams);
|
|
2902
|
-
|
|
2972
|
+
// The outer level re-orders by the user's columns, which must therefore
|
|
2973
|
+
// exist in the derived table. A NARROWED projection (`select`, `omit`,
|
|
2974
|
+
// or the PII rule, which narrows with no user projection at all) left
|
|
2975
|
+
// them out, so the statement failed with 42703. Every order column the
|
|
2976
|
+
// projection omits is projected into the INNER query under its own
|
|
2977
|
+
// name, and the outer SELECT then lists the projected columns
|
|
2978
|
+
// explicitly instead of `*`, so the extra column orders the result and
|
|
2979
|
+
// never reaches a row (a PII column never even crosses the wire). The
|
|
2980
|
+
// full projection (`columnsList === null`, `"t".*`) and a projection
|
|
2981
|
+
// that already covers the order keeps the `SELECT *` wrapper byte for
|
|
2982
|
+
// byte. The user's order is rendered ONCE (params pushed once, as the
|
|
2983
|
+
// collect path mirrors) and its text reused at both levels.
|
|
2984
|
+
let innerSelect = selectClause;
|
|
2985
|
+
let outerSelect = '*';
|
|
2986
|
+
if (columnsList) {
|
|
2987
|
+
const projected = new Set(columnsList);
|
|
2988
|
+
const extras = [];
|
|
2989
|
+
for (const [key] of (0, filters_js_1.orderByEntries)(args.orderBy)) {
|
|
2990
|
+
// Relation and vector ordering are refused above, so every key
|
|
2991
|
+
// names a column of this table (a JSON-path entry's key is its
|
|
2992
|
+
// column); buildOrderBy has already validated it.
|
|
2993
|
+
const col = this.toColumn(key);
|
|
2994
|
+
if (!projected.has(col) && !extras.includes(col))
|
|
2995
|
+
extras.push(col);
|
|
2996
|
+
}
|
|
2997
|
+
if (extras.length > 0) {
|
|
2998
|
+
innerSelect = `${selectClause}, ${extras.map((c) => `${qt}.${this.q(c)}`).join(', ')}`;
|
|
2999
|
+
outerSelect = this.distinctOuterSelectList(columnsList, args.with).join(', ');
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
const inner = `SELECT ${distinctPrefix}${innerSelect} FROM ${qt}${tail} ORDER BY ${distinctCols
|
|
2903
3003
|
.map((c) => `${c} ASC`)
|
|
2904
3004
|
.join(', ')}, ${userOrder}`;
|
|
2905
|
-
sql = `SELECT
|
|
3005
|
+
sql = `SELECT ${outerSelect} FROM (${inner}) AS ${this.q(`${this.table}_distinct`)} ORDER BY ${userOrder}`;
|
|
2906
3006
|
}
|
|
2907
3007
|
else {
|
|
2908
3008
|
// Pass freshParams so vector KNN ordering binds its `$n::vector` query
|
|
@@ -2937,11 +3037,11 @@ class QueryInterface {
|
|
|
2937
3037
|
if (args?.with) {
|
|
2938
3038
|
this.collectWithParams(args.with, params, undefined, flattenPlan);
|
|
2939
3039
|
}
|
|
2940
|
-
// 3. Cursor params,
|
|
3040
|
+
// 3. Cursor params, keyset order, matching cursorFp and the build path
|
|
3041
|
+
// (each value binds ONCE; the expanded predicate re-references its `$n`).
|
|
2941
3042
|
if (args?.cursor) {
|
|
2942
|
-
const
|
|
2943
|
-
|
|
2944
|
-
params.push(v);
|
|
3043
|
+
for (const e of this.cursorSeekEntries(args.cursor, args.orderBy)) {
|
|
3044
|
+
params.push(e.value);
|
|
2945
3045
|
}
|
|
2946
3046
|
}
|
|
2947
3047
|
// 4. ORDER BY params (vector KNN ordering binds a `$n::vector` query vector).
|
|
@@ -3720,6 +3820,36 @@ class QueryInterface {
|
|
|
3720
3820
|
toSqlColumn(field) {
|
|
3721
3821
|
return this.q(this.toColumn(field));
|
|
3722
3822
|
}
|
|
3823
|
+
/**
|
|
3824
|
+
* The explicit outer SELECT list of the `distinct` + `orderBy` wrapper, used
|
|
3825
|
+
* only when the inner derived table had to carry ORDER BY columns the
|
|
3826
|
+
* projection leaves out (see the distinct branch of {@link buildFindMany}):
|
|
3827
|
+
* the projected base columns, then one column per `with` relation, then one
|
|
3828
|
+
* per counted relation. These are the aliases `buildSelectWithRelations`
|
|
3829
|
+
* (relations.ts) gives the same columns, `AS "<relName>"` per entry in sorted
|
|
3830
|
+
* order and `AS "_count__<rel>"` per counted relation, over the SAME
|
|
3831
|
+
* `resolveCountRelations` it uses, so the two lists name the same columns.
|
|
3832
|
+
* `flatten` never reaches here (the strategy is gated off under `distinct`),
|
|
3833
|
+
* so no prefixed scalar aliases exist to enumerate. A drift between the two
|
|
3834
|
+
* would fail LOUDLY, as a 42703 on the outer list, never as a silently wrong
|
|
3835
|
+
* row, and the live distinct test pins the `with` + `_count` shape.
|
|
3836
|
+
*/
|
|
3837
|
+
distinctOuterSelectList(columnsList, withClause) {
|
|
3838
|
+
const list = columnsList.map((c) => this.q(c));
|
|
3839
|
+
if (!withClause)
|
|
3840
|
+
return list;
|
|
3841
|
+
for (const [relName] of (0, filters_js_1.sortedEntries)(withClause)) {
|
|
3842
|
+
if (relName === '_count')
|
|
3843
|
+
continue;
|
|
3844
|
+
list.push(this.q(relName));
|
|
3845
|
+
}
|
|
3846
|
+
const countSpec = withClause._count;
|
|
3847
|
+
if (countSpec !== undefined) {
|
|
3848
|
+
for (const rel of (0, batched_loader_js_1.resolveCountRelations)(this.tableMeta, countSpec))
|
|
3849
|
+
list.push(this.q(`_count__${rel.name}`));
|
|
3850
|
+
}
|
|
3851
|
+
return list;
|
|
3852
|
+
}
|
|
3723
3853
|
// =========================================================================
|
|
3724
3854
|
// Fingerprinting, value-invariant shape keys for SQL cache lookup
|
|
3725
3855
|
// =========================================================================
|
|
@@ -77,7 +77,70 @@ export declare function expandCompoundUniqueWhere(meta: TableMetadata, where: Re
|
|
|
77
77
|
* person cannot take.
|
|
78
78
|
*/
|
|
79
79
|
export declare function assertWhereIdentifiesOneRow(meta: TableMetadata, table: string, where: Record<string, unknown> | undefined): void;
|
|
80
|
+
/**
|
|
81
|
+
* The same refusal for the single-row WRITE methods, `update` and `delete`, and
|
|
82
|
+
* for `upsert`, whose `where` carries the same one-row contract by a different
|
|
83
|
+
* mechanism.
|
|
84
|
+
*
|
|
85
|
+
* `update` / `delete` emit `... WHERE <predicate> RETURNING *` and hand back
|
|
86
|
+
* `rows[0]`, so a `where` that matches many rows mutates EVERY one of them and
|
|
87
|
+
* reports one: the `findUnique` hazard (an arbitrary one of many) with a write
|
|
88
|
+
* attached. `upsert`'s `where` is not a predicate at all, it IS the conflict
|
|
89
|
+
* target, so a non-unique one has no single row to update on conflict and the
|
|
90
|
+
* emitted `ON CONFLICT (...)` names columns no unique index backs. Same rule,
|
|
91
|
+
* same sources of uniqueness, same null policy as
|
|
92
|
+
* {@link assertWhereIdentifiesOneRow}; only the sentence differs, because the
|
|
93
|
+
* consequence and the fix differ per operation. A reader who meant one row
|
|
94
|
+
* names a key; a reader who meant every matching row has `updateMany` /
|
|
95
|
+
* `deleteMany`, which report `{ count }` and never pretend to have touched one
|
|
96
|
+
* row.
|
|
97
|
+
*
|
|
98
|
+
* Called on the CALLER's where, before any global filter is merged in (a
|
|
99
|
+
* tenancy filter narrows, it does not identify). `update` / `delete` skip it
|
|
100
|
+
* under `allowFullTableScan: UNSAFE`, which already says "every row" in so many
|
|
101
|
+
* words, and their message names that hatch: a predicate CAN identify one row
|
|
102
|
+
* through a constraint this schema's metadata does not carry (a stale generated
|
|
103
|
+
* `metadata.ts`, a `defineSchema` that declares fewer uniques than the database
|
|
104
|
+
* has), and a rule with no way past it turns that into an unreachable method.
|
|
105
|
+
* `upsert` has no such option and its message therefore offers none.
|
|
106
|
+
*/
|
|
107
|
+
export declare function assertMutationWhereIdentifiesOneRow(meta: TableMetadata, table: string, where: Record<string, unknown> | undefined, operation: 'update' | 'delete' | 'upsert'): void;
|
|
80
108
|
export declare function uniqueKeyNames(meta: TableMetadata): string[][];
|
|
109
|
+
/**
|
|
110
|
+
* Brands a predicate Turbine wrote ENTIRELY itself to address the one row a
|
|
111
|
+
* DECLARED to-one relation points at, so the single-row write rule accepts it.
|
|
112
|
+
*
|
|
113
|
+
* A nested `disconnect: true` / `delete: true` on a `hasOne`, and a nested
|
|
114
|
+
* `update` on a `belongsTo` (whose argument is `{ data }`, with no `where` at
|
|
115
|
+
* all), give the caller no selector to write. The engine builds the predicate
|
|
116
|
+
* from the relation's own correlation key, and the thing that makes it one row
|
|
117
|
+
* is the relation's declared CARDINALITY, which is not in `primaryKey` /
|
|
118
|
+
* `uniqueColumns` / `indexes` and so is invisible to
|
|
119
|
+
* {@link whereIdentifiesOneRow}. Without this the rule refused those writes
|
|
120
|
+
* with "Name a unique key", advice the caller cannot take because they never
|
|
121
|
+
* wrote a `where`, on every schema whose `hasOne` FK is not ALSO declared
|
|
122
|
+
* unique: the `defineSchema` code-first path, the PowDB path, and any FK backed
|
|
123
|
+
* only by a partial unique index.
|
|
124
|
+
*
|
|
125
|
+
* Turbine believes a declared `hasOne` everywhere else (it reads the relation
|
|
126
|
+
* as an object rather than an array, and emits `LIMIT 1` for it), so believing
|
|
127
|
+
* it here is consistency, not a hole. The brand is applied at the one place the
|
|
128
|
+
* predicate is synthesized (`scopeWhereToParent` / the belongsTo correlation in
|
|
129
|
+
* nested-write.ts) and never to anything a caller supplied.
|
|
130
|
+
*
|
|
131
|
+
* A distinct Symbol rather than a second meaning for `markInternalCombinator`:
|
|
132
|
+
* that brand exists to keep a fixed-arity wrapper on a NAMED prepared
|
|
133
|
+
* statement, and folding "identifies one row" into it would mean any future
|
|
134
|
+
* fixed-arity wrapper silently switched this rule off. `Symbol.for` for the
|
|
135
|
+
* ESM/CJS cross-copy identity reason `INTERNAL_COMBINATOR` documents, and a
|
|
136
|
+
* SYMBOL so the `Object.keys` every where walker enumerates never sees it and
|
|
137
|
+
* no emitted SQL can change.
|
|
138
|
+
*/
|
|
139
|
+
export declare const INTERNAL_ROW_SELECTOR: unique symbol;
|
|
140
|
+
/** Tag `where` as an engine-written single-row selector, and return it. */
|
|
141
|
+
export declare function markInternalRowSelector<T extends object>(where: T): T;
|
|
142
|
+
/** Did Turbine itself write this predicate to address one declared related row? */
|
|
143
|
+
export declare function isInternalRowSelector(where: unknown): boolean;
|
|
81
144
|
/**
|
|
82
145
|
* True when `where` pins every column of at least one unique key to a single
|
|
83
146
|
* value, so the row it names is the row it gets.
|
|
@@ -91,5 +154,18 @@ export declare function uniqueKeyNames(meta: TableMetadata): string[][];
|
|
|
91
154
|
* A NULL is not an identity. `WHERE email IS NULL` matches every row whose
|
|
92
155
|
* email is null, which a UNIQUE constraint permits any number of, so a null
|
|
93
156
|
* value satisfies no key here even on a unique column.
|
|
157
|
+
*
|
|
158
|
+
* The one combinator it does read through is Turbine's OWN: a nested write
|
|
159
|
+
* scopes a child selector to its parent by merging the parent correlation in,
|
|
160
|
+
* and when the two name the same column the merge is `{ AND: [selector,
|
|
161
|
+
* correlation] }` BRANDED via `markInternalCombinator` (query/utils.ts). That
|
|
162
|
+
* brand is a Symbol no request body can produce, the arity is fixed at two,
|
|
163
|
+
* and each branch only narrows the other, so the wrapper identifies a row
|
|
164
|
+
* exactly when one of its branches does. A caller-written `AND` is not read.
|
|
165
|
+
*
|
|
166
|
+
* The other thing it reads is {@link markInternalRowSelector}: a predicate the
|
|
167
|
+
* ENGINE wrote in full, for which there is no caller `where` this rule could be
|
|
168
|
+
* about. See that function for why the declaration, not the metadata, is the
|
|
169
|
+
* uniqueness source there.
|
|
94
170
|
*/
|
|
95
171
|
export declare function whereIdentifiesOneRow(meta: TableMetadata, where: Record<string, unknown>): boolean;
|
|
@@ -40,9 +40,13 @@
|
|
|
40
40
|
* {@link TableMetadata} in a module-level `WeakMap`.
|
|
41
41
|
*/
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.INTERNAL_ROW_SELECTOR = void 0;
|
|
43
44
|
exports.expandCompoundUniqueWhere = expandCompoundUniqueWhere;
|
|
44
45
|
exports.assertWhereIdentifiesOneRow = assertWhereIdentifiesOneRow;
|
|
46
|
+
exports.assertMutationWhereIdentifiesOneRow = assertMutationWhereIdentifiesOneRow;
|
|
45
47
|
exports.uniqueKeyNames = uniqueKeyNames;
|
|
48
|
+
exports.markInternalRowSelector = markInternalRowSelector;
|
|
49
|
+
exports.isInternalRowSelector = isInternalRowSelector;
|
|
46
50
|
exports.whereIdentifiesOneRow = whereIdentifiesOneRow;
|
|
47
51
|
const errors_js_1 = require("../errors.js");
|
|
48
52
|
const filters_js_1 = require("./filters.js");
|
|
@@ -245,6 +249,70 @@ function assertWhereIdentifiesOneRow(meta, table, where) {
|
|
|
245
249
|
throw new errors_js_1.ValidationError(`findUnique on "${table}" refused: the \`where\` clause does not identify a single row, ` +
|
|
246
250
|
`so this would return an arbitrary one of the rows that match. ${advice}`);
|
|
247
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* The escape hatch sentence, on `update` / `delete` only.
|
|
254
|
+
*
|
|
255
|
+
* Stated with its cost rather than as an option to reach for: the same flag
|
|
256
|
+
* turns off the empty-`where` guard, so a predicate that is merely NARROW today
|
|
257
|
+
* and becomes EMPTY tomorrow (every value `undefined` on a request that omitted
|
|
258
|
+
* them) writes the whole table instead of being refused.
|
|
259
|
+
*/
|
|
260
|
+
const UNSAFE_ESCAPE = 'If this predicate really does identify one row through a constraint this schema does not describe, ' +
|
|
261
|
+
'`allowFullTableScan: UNSAFE` writes it anyway, at the cost of the empty-`where` guard as well: an ' +
|
|
262
|
+
'all-`undefined` `where` then matches every row instead of being refused.';
|
|
263
|
+
/**
|
|
264
|
+
* The same refusal for the single-row WRITE methods, `update` and `delete`, and
|
|
265
|
+
* for `upsert`, whose `where` carries the same one-row contract by a different
|
|
266
|
+
* mechanism.
|
|
267
|
+
*
|
|
268
|
+
* `update` / `delete` emit `... WHERE <predicate> RETURNING *` and hand back
|
|
269
|
+
* `rows[0]`, so a `where` that matches many rows mutates EVERY one of them and
|
|
270
|
+
* reports one: the `findUnique` hazard (an arbitrary one of many) with a write
|
|
271
|
+
* attached. `upsert`'s `where` is not a predicate at all, it IS the conflict
|
|
272
|
+
* target, so a non-unique one has no single row to update on conflict and the
|
|
273
|
+
* emitted `ON CONFLICT (...)` names columns no unique index backs. Same rule,
|
|
274
|
+
* same sources of uniqueness, same null policy as
|
|
275
|
+
* {@link assertWhereIdentifiesOneRow}; only the sentence differs, because the
|
|
276
|
+
* consequence and the fix differ per operation. A reader who meant one row
|
|
277
|
+
* names a key; a reader who meant every matching row has `updateMany` /
|
|
278
|
+
* `deleteMany`, which report `{ count }` and never pretend to have touched one
|
|
279
|
+
* row.
|
|
280
|
+
*
|
|
281
|
+
* Called on the CALLER's where, before any global filter is merged in (a
|
|
282
|
+
* tenancy filter narrows, it does not identify). `update` / `delete` skip it
|
|
283
|
+
* under `allowFullTableScan: UNSAFE`, which already says "every row" in so many
|
|
284
|
+
* words, and their message names that hatch: a predicate CAN identify one row
|
|
285
|
+
* through a constraint this schema's metadata does not carry (a stale generated
|
|
286
|
+
* `metadata.ts`, a `defineSchema` that declares fewer uniques than the database
|
|
287
|
+
* has), and a rule with no way past it turns that into an unreachable method.
|
|
288
|
+
* `upsert` has no such option and its message therefore offers none.
|
|
289
|
+
*/
|
|
290
|
+
function assertMutationWhereIdentifiesOneRow(meta, table, where, operation) {
|
|
291
|
+
if (whereIdentifiesOneRow(meta, where ?? {}))
|
|
292
|
+
return;
|
|
293
|
+
const keys = describeUniqueKeys(meta);
|
|
294
|
+
if (operation === 'upsert') {
|
|
295
|
+
const advice = keys.length > 0
|
|
296
|
+
? `Name a unique key (${keys.join(', ')}).`
|
|
297
|
+
: `Table "${table}" declares no primary key and no unique constraint, so no \`where\` can identify one row ` +
|
|
298
|
+
'here and no upsert is possible on it: insert with `create`, or change matching rows with `updateMany`.';
|
|
299
|
+
throw new errors_js_1.ValidationError(`upsert on "${table}" refused: the \`where\` clause does not identify a single row. An upsert's \`where\` IS ` +
|
|
300
|
+
'its conflict target, so there is no one row to update on conflict, and the `ON CONFLICT` this would emit ' +
|
|
301
|
+
`names columns no unique constraint backs. ${advice}`);
|
|
302
|
+
}
|
|
303
|
+
const many = operation === 'update' ? 'updateMany' : 'deleteMany';
|
|
304
|
+
const advice = keys.length > 0
|
|
305
|
+
? `Name a unique key (${keys.join(', ')}), or use \`${many}\` if you meant "every row matching a filter".`
|
|
306
|
+
: `Table "${table}" declares no primary key and no unique constraint, so no \`where\` can identify one row ` +
|
|
307
|
+
`here. Use \`${many}\`, which reports how many rows it touched.`;
|
|
308
|
+
throw new errors_js_1.ValidationError(`${operation} on "${table}" refused: the \`where\` clause does not identify a single row, ` +
|
|
309
|
+
`so this would ${operation} every row that matches and return only one of them. ${advice} ${UNSAFE_ESCAPE}`);
|
|
310
|
+
}
|
|
311
|
+
/** Each unique key of `meta` rendered in field spelling, for an error message. */
|
|
312
|
+
function describeUniqueKeys(meta) {
|
|
313
|
+
const field = (c) => meta.reverseColumnMap[c] ?? c;
|
|
314
|
+
return uniqueKeyNames(meta).map((cols) => cols.length === 1 ? `\`${field(cols[0])}\`` : `\`{ ${cols.map(field).join(', ')} }\``);
|
|
315
|
+
}
|
|
248
316
|
function uniqueKeyNames(meta) {
|
|
249
317
|
return dedupeColumnSets(uniqueColumnSets(meta));
|
|
250
318
|
}
|
|
@@ -274,6 +342,49 @@ function uniqueColumnSets(meta) {
|
|
|
274
342
|
}
|
|
275
343
|
return sets;
|
|
276
344
|
}
|
|
345
|
+
// ---------------------------------------------------------------------------
|
|
346
|
+
// Engine-addressed row selectors
|
|
347
|
+
// ---------------------------------------------------------------------------
|
|
348
|
+
/**
|
|
349
|
+
* Brands a predicate Turbine wrote ENTIRELY itself to address the one row a
|
|
350
|
+
* DECLARED to-one relation points at, so the single-row write rule accepts it.
|
|
351
|
+
*
|
|
352
|
+
* A nested `disconnect: true` / `delete: true` on a `hasOne`, and a nested
|
|
353
|
+
* `update` on a `belongsTo` (whose argument is `{ data }`, with no `where` at
|
|
354
|
+
* all), give the caller no selector to write. The engine builds the predicate
|
|
355
|
+
* from the relation's own correlation key, and the thing that makes it one row
|
|
356
|
+
* is the relation's declared CARDINALITY, which is not in `primaryKey` /
|
|
357
|
+
* `uniqueColumns` / `indexes` and so is invisible to
|
|
358
|
+
* {@link whereIdentifiesOneRow}. Without this the rule refused those writes
|
|
359
|
+
* with "Name a unique key", advice the caller cannot take because they never
|
|
360
|
+
* wrote a `where`, on every schema whose `hasOne` FK is not ALSO declared
|
|
361
|
+
* unique: the `defineSchema` code-first path, the PowDB path, and any FK backed
|
|
362
|
+
* only by a partial unique index.
|
|
363
|
+
*
|
|
364
|
+
* Turbine believes a declared `hasOne` everywhere else (it reads the relation
|
|
365
|
+
* as an object rather than an array, and emits `LIMIT 1` for it), so believing
|
|
366
|
+
* it here is consistency, not a hole. The brand is applied at the one place the
|
|
367
|
+
* predicate is synthesized (`scopeWhereToParent` / the belongsTo correlation in
|
|
368
|
+
* nested-write.ts) and never to anything a caller supplied.
|
|
369
|
+
*
|
|
370
|
+
* A distinct Symbol rather than a second meaning for `markInternalCombinator`:
|
|
371
|
+
* that brand exists to keep a fixed-arity wrapper on a NAMED prepared
|
|
372
|
+
* statement, and folding "identifies one row" into it would mean any future
|
|
373
|
+
* fixed-arity wrapper silently switched this rule off. `Symbol.for` for the
|
|
374
|
+
* ESM/CJS cross-copy identity reason `INTERNAL_COMBINATOR` documents, and a
|
|
375
|
+
* SYMBOL so the `Object.keys` every where walker enumerates never sees it and
|
|
376
|
+
* no emitted SQL can change.
|
|
377
|
+
*/
|
|
378
|
+
exports.INTERNAL_ROW_SELECTOR = Symbol.for('turbine.internalRowSelector');
|
|
379
|
+
/** Tag `where` as an engine-written single-row selector, and return it. */
|
|
380
|
+
function markInternalRowSelector(where) {
|
|
381
|
+
Object.defineProperty(where, exports.INTERNAL_ROW_SELECTOR, { value: true, enumerable: false, configurable: true });
|
|
382
|
+
return where;
|
|
383
|
+
}
|
|
384
|
+
/** Did Turbine itself write this predicate to address one declared related row? */
|
|
385
|
+
function isInternalRowSelector(where) {
|
|
386
|
+
return (typeof where === 'object' && where !== null && where[exports.INTERNAL_ROW_SELECTOR] === true);
|
|
387
|
+
}
|
|
277
388
|
/**
|
|
278
389
|
* True when `where` pins every column of at least one unique key to a single
|
|
279
390
|
* value, so the row it names is the row it gets.
|
|
@@ -287,8 +398,26 @@ function uniqueColumnSets(meta) {
|
|
|
287
398
|
* A NULL is not an identity. `WHERE email IS NULL` matches every row whose
|
|
288
399
|
* email is null, which a UNIQUE constraint permits any number of, so a null
|
|
289
400
|
* value satisfies no key here even on a unique column.
|
|
401
|
+
*
|
|
402
|
+
* The one combinator it does read through is Turbine's OWN: a nested write
|
|
403
|
+
* scopes a child selector to its parent by merging the parent correlation in,
|
|
404
|
+
* and when the two name the same column the merge is `{ AND: [selector,
|
|
405
|
+
* correlation] }` BRANDED via `markInternalCombinator` (query/utils.ts). That
|
|
406
|
+
* brand is a Symbol no request body can produce, the arity is fixed at two,
|
|
407
|
+
* and each branch only narrows the other, so the wrapper identifies a row
|
|
408
|
+
* exactly when one of its branches does. A caller-written `AND` is not read.
|
|
409
|
+
*
|
|
410
|
+
* The other thing it reads is {@link markInternalRowSelector}: a predicate the
|
|
411
|
+
* ENGINE wrote in full, for which there is no caller `where` this rule could be
|
|
412
|
+
* about. See that function for why the declaration, not the metadata, is the
|
|
413
|
+
* uniqueness source there.
|
|
290
414
|
*/
|
|
291
415
|
function whereIdentifiesOneRow(meta, where) {
|
|
416
|
+
if (isInternalRowSelector(where))
|
|
417
|
+
return true;
|
|
418
|
+
if ((0, utils_js_1.isInternalCombinator)(where) && Array.isArray(where.AND)) {
|
|
419
|
+
return where.AND.some((branch) => typeof branch === 'object' && branch !== null && whereIdentifiesOneRow(meta, branch));
|
|
420
|
+
}
|
|
292
421
|
const pinned = new Set();
|
|
293
422
|
for (const [key, value] of Object.entries(where)) {
|
|
294
423
|
if (!isPinnedToOneValue(value))
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* `import { … } from './query/index.js'` is a drop-in replacement for the
|
|
6
6
|
* former monolithic `import { … } from './query.js'`.
|
|
7
7
|
*/
|
|
8
|
-
export type { AggregateArgs, AggregateResult, ArrayFilter, ColumnRef, ConnectOrCreateOp, CountArgs, CreateArgs, CreateDataInput, CreateManyArgs, DeleteArgs, DeleteManyArgs, FieldResult, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GlobalFilters, GroupByAggregateSpec, GroupByArgs, GroupByDistinctOn, GroupByResult, HavingClause, JsonEncoding, JsonFilter, JsonPathAggregateTarget, JsonPathGroupKey, JsonPathOrderBy, NestedCreateOp, NestedUpdateOp, NestedUpdateOpItem, NestedUpsertOpItem, OmitResult, OrderByClause, OrderByObject, OrderDirection, QueryResult, RelationDescriptor, RelationFilter, RelationLoadStrategy, RelationPickBy, RelationPickOrderBy, ResolvedSkipGlobalFilters, SelectResult, SkipGlobalFilters, TextSearchFilter, TypedWithClause, UpdateArgs, UpdateDataInput, UpdateInput, UpdateManyArgs, UpdateOperatorInput, UpsertArgs, VectorDistanceFilter, VectorFilter, VectorMetric, VectorOrderBy, VectorOrderByDistance, WhereClause, WhereOperator, WhereValue, WithClause, WithOptions, WithOrderByObject, WithResult, } from './types.js';
|
|
8
|
+
export type { AggregateArgs, AggregateResult, ArrayFilter, ColumnRef, ConnectOrCreateOp, CountArgs, CreateArgs, CreateDataInput, CreateManyArgs, DeleteArgs, DeleteManyArgs, FieldResult, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GlobalFilters, GroupByAggregateSpec, GroupByArgs, GroupByDistinctOn, GroupByResult, HavingClause, JsonEncoding, JsonFilter, JsonPathAggregateTarget, JsonPathGroupKey, JsonPathOrderBy, NestedCreateOp, NestedUpdateOp, NestedUpdateOpItem, NestedUpsertOpItem, OmitResult, OrderByClause, OrderByObject, OrderBySpec, OrderDirection, QueryResult, RelationDescriptor, RelationFilter, RelationLoadStrategy, RelationOrderBy, RelationOrderByChain, RelationPickBy, RelationPickOrderBy, ResolvedSkipGlobalFilters, SelectResult, SkipGlobalFilters, TextSearchFilter, TypedWithClause, UpdateArgs, UpdateDataInput, UpdateInput, UpdateManyArgs, UpdateOperatorInput, UpsertArgs, VectorDistanceFilter, VectorFilter, VectorMetric, VectorOrderBy, VectorOrderByDistance, WhereClause, WhereOperator, WhereValue, WithClause, WithOptions, WithOrderByObject, WithResult, } from './types.js';
|
|
9
9
|
export type { BuiltStatement, BulkInsertStatementInput, ColumnDefinitionInput, ColumnTypeInput, CreateIndexStatementInput, CreateTableStatementInput, Dialect, InsertStatementInput, UpsertStatementInput, } from '../dialect.js';
|
|
10
10
|
export { postgresDialect } from '../dialect.js';
|
|
11
11
|
export type { OptionKind, OptionTable } from './option-surface.js';
|