turbine-orm 0.28.3 → 0.30.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 +1 -1
- package/dist/cjs/cli/index.js +5 -0
- package/dist/cjs/cli/mcp.js +22 -92
- package/dist/cjs/client.js +69 -5
- package/dist/cjs/generate.js +71 -25
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/introspect.js +350 -120
- package/dist/cjs/mssql.js +18 -133
- package/dist/cjs/mysql.js +16 -129
- package/dist/cjs/optional-peer-import.cjs +122 -0
- package/dist/cjs/powdb.js +440 -81
- package/dist/cjs/powql.js +49 -25
- package/dist/cjs/query/builder.js +290 -23
- package/dist/cjs/query/filters.js +32 -1
- package/dist/cjs/schema-metadata.js +316 -0
- package/dist/cjs/sqlite.js +8 -89
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/mcp.d.ts +18 -0
- package/dist/cli/mcp.js +22 -93
- package/dist/client.d.ts +44 -6
- package/dist/client.js +69 -5
- package/dist/generate.d.ts +16 -4
- package/dist/generate.js +71 -25
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/introspect.d.ts +94 -1
- package/dist/introspect.js +345 -120
- package/dist/mssql.js +16 -101
- package/dist/mysql.js +14 -97
- package/dist/optional-peer-import.cjs +89 -0
- package/dist/optional-peer-import.d.cts +53 -0
- package/dist/powdb.d.ts +94 -26
- package/dist/powdb.js +435 -80
- package/dist/powql.d.ts +6 -0
- package/dist/powql.js +51 -27
- package/dist/query/builder.d.ts +60 -3
- package/dist/query/builder.js +291 -24
- package/dist/query/deferred.d.ts +7 -2
- package/dist/query/filters.d.ts +18 -0
- package/dist/query/filters.js +30 -0
- package/dist/query/types.d.ts +19 -0
- package/dist/schema-metadata.d.ts +77 -0
- package/dist/schema-metadata.js +313 -0
- package/dist/schema.d.ts +10 -0
- package/dist/sqlite.js +9 -90
- package/package.json +3 -3
package/dist/powql.d.ts
CHANGED
|
@@ -156,6 +156,12 @@ export declare class PowqlInterface<T extends object = Record<string, unknown>>
|
|
|
156
156
|
* it and the trailing `returning` reads it back — as is any non-string PK.
|
|
157
157
|
*/
|
|
158
158
|
private applyPkDefault;
|
|
159
|
+
/**
|
|
160
|
+
* The table name as a PowQL type reference — backtick-quoted when it is a
|
|
161
|
+
* reserved word (e.g. a table named `order`). Used in every emitted
|
|
162
|
+
* statement; plain `this.table` stays in error messages.
|
|
163
|
+
*/
|
|
164
|
+
private get qt();
|
|
159
165
|
create(args: CreateArgs<T>): Promise<T>;
|
|
160
166
|
createMany(args: CreateManyArgs<T>): Promise<T[]>;
|
|
161
167
|
update(args: UpdateArgs<T>): Promise<T>;
|
package/dist/powql.js
CHANGED
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
import { randomUUID } from 'node:crypto';
|
|
38
38
|
import { NotFoundError, TimeoutError, UnsupportedFeatureError, ValidationError } from './errors.js';
|
|
39
39
|
import { executeNestedCreate, executeNestedUpdate, hasRelationFields, } from './nested-write.js';
|
|
40
|
-
import { PowdbFloatParam, powqlColumnType, rowToEntity } from './powdb.js';
|
|
40
|
+
import { PowdbFloatParam, powqlColumnType, quotePowqlIdent, rowToEntity } from './powdb.js';
|
|
41
41
|
import { escapeLike } from './query/utils.js';
|
|
42
|
-
import { normalizeKeyColumns, } from './schema.js';
|
|
42
|
+
import { normalizeKeyColumns, snakeToCamel, } from './schema.js';
|
|
43
43
|
/**
|
|
44
44
|
* Max parent keys per relation-loader `in (…)` query. A `with` over a large
|
|
45
45
|
* parent set is split into batches of this size so a single query never exceeds
|
|
@@ -106,7 +106,14 @@ export class PowqlInterface {
|
|
|
106
106
|
}
|
|
107
107
|
this.meta = meta;
|
|
108
108
|
this.defaultLimit = options.defaultLimit;
|
|
109
|
-
|
|
109
|
+
// Same per-table resolution as QueryInterface: an object map accepts BOTH
|
|
110
|
+
// the snake_case table name and the camelCase accessor as keys (snake_case
|
|
111
|
+
// wins on conflict); unlisted tables keep the default (warn on).
|
|
112
|
+
const warnOpt = options.warnOnUnlimited;
|
|
113
|
+
this.warnOnUnlimited =
|
|
114
|
+
typeof warnOpt === 'object' && warnOpt !== null
|
|
115
|
+
? (warnOpt[table] ?? warnOpt[snakeToCamel(table)]) !== false
|
|
116
|
+
: warnOpt !== false;
|
|
110
117
|
this.onQuery = options._onQuery;
|
|
111
118
|
}
|
|
112
119
|
// -------------------------------------------------------------------------
|
|
@@ -411,7 +418,7 @@ export class PowqlInterface {
|
|
|
411
418
|
const chunk = targetPks.slice(i, i + MAX_RELATION_KEYS);
|
|
412
419
|
const params = [];
|
|
413
420
|
const ph = chunk.map((v) => this.param(v, params)).join(', ');
|
|
414
|
-
const { rows } = await this.exec(`${through.table} filter .${targetJCol} in (${ph}) { .${sourceJCol} }`, params, timeout);
|
|
421
|
+
const { rows } = await this.exec(`${quotePowqlIdent(through.table)} filter .${targetJCol} in (${ph}) { .${sourceJCol} }`, params, timeout);
|
|
415
422
|
for (const r of rows) {
|
|
416
423
|
const v = r[sourceJCol];
|
|
417
424
|
if (v != null)
|
|
@@ -563,7 +570,7 @@ export class PowqlInterface {
|
|
|
563
570
|
}
|
|
564
571
|
const limitClause = limit !== undefined ? ` limit ${this.param(limit, params)}` : '';
|
|
565
572
|
const offsetClause = args.offset ? ` offset ${this.param(args.offset, params)}` : '';
|
|
566
|
-
const powql = `${this.
|
|
573
|
+
const powql = `${this.qt}${distinct}${filter}${order}${limitClause}${offsetClause} ${this.projection(cols)}`;
|
|
567
574
|
const { rows } = await this.exec(powql, params, args.timeout);
|
|
568
575
|
return rows;
|
|
569
576
|
}
|
|
@@ -712,7 +719,7 @@ export class PowqlInterface {
|
|
|
712
719
|
const chunk = parentKeys.slice(i, i + MAX_RELATION_KEYS);
|
|
713
720
|
const params = [];
|
|
714
721
|
const placeholders = chunk.map((v) => this.param(v, params)).join(', ');
|
|
715
|
-
const powql = `${through.table} filter .${sourceJCol} in (${placeholders}) { .${sourceJCol}, .${targetJCol} }`;
|
|
722
|
+
const powql = `${quotePowqlIdent(through.table)} filter .${sourceJCol} in (${placeholders}) { .${sourceJCol}, .${targetJCol} }`;
|
|
716
723
|
const { rows } = await this.exec(powql, params, timeout);
|
|
717
724
|
for (const row of rows) {
|
|
718
725
|
const sv = String(row[sourceJCol]);
|
|
@@ -794,6 +801,14 @@ export class PowqlInterface {
|
|
|
794
801
|
}
|
|
795
802
|
return out;
|
|
796
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* The table name as a PowQL type reference — backtick-quoted when it is a
|
|
806
|
+
* reserved word (e.g. a table named `order`). Used in every emitted
|
|
807
|
+
* statement; plain `this.table` stays in error messages.
|
|
808
|
+
*/
|
|
809
|
+
get qt() {
|
|
810
|
+
return quotePowqlIdent(this.table);
|
|
811
|
+
}
|
|
797
812
|
async create(args) {
|
|
798
813
|
return this.withMiddleware('create', args, async () => {
|
|
799
814
|
if (hasRelationFields(args.data, this.meta)) {
|
|
@@ -802,9 +817,11 @@ export class PowqlInterface {
|
|
|
802
817
|
const data = this.applyPkDefault(args.data);
|
|
803
818
|
const assigns = this.scalarData(data);
|
|
804
819
|
const params = [];
|
|
805
|
-
const body = assigns
|
|
820
|
+
const body = assigns
|
|
821
|
+
.map((a) => `${quotePowqlIdent(a.col.name)} := ${this.writeRef(a.value, a.col, params)}`)
|
|
822
|
+
.join(', ');
|
|
806
823
|
// `returning` surfaces the inserted row (all columns, schema order) in one round-trip.
|
|
807
|
-
const { rows } = await this.exec(`insert ${this.
|
|
824
|
+
const { rows } = await this.exec(`insert ${this.qt} { ${body} } returning`, params, args.timeout);
|
|
808
825
|
const row = rows.length ? this.shape(rows)[0] : null;
|
|
809
826
|
if (!row)
|
|
810
827
|
throw new NotFoundError({ table: this.table, where: data });
|
|
@@ -819,10 +836,10 @@ export class PowqlInterface {
|
|
|
819
836
|
const params = [];
|
|
820
837
|
const tuples = inputs.map((d) => {
|
|
821
838
|
const assigns = this.scalarData(d);
|
|
822
|
-
return `{ ${assigns.map((a) => `${a.col.name} := ${this.writeRef(a.value, a.col, params)}`).join(', ')} }`;
|
|
839
|
+
return `{ ${assigns.map((a) => `${quotePowqlIdent(a.col.name)} := ${this.writeRef(a.value, a.col, params)}`).join(', ')} }`;
|
|
823
840
|
});
|
|
824
841
|
// Multi-row insert with `returning` hands back every inserted row in one round-trip.
|
|
825
|
-
const { rows } = await this.exec(`insert ${this.
|
|
842
|
+
const { rows } = await this.exec(`insert ${this.qt} ${tuples.join(', ')} returning`, params, args.timeout);
|
|
826
843
|
return this.shape(rows);
|
|
827
844
|
});
|
|
828
845
|
}
|
|
@@ -837,7 +854,7 @@ export class PowqlInterface {
|
|
|
837
854
|
this.assertCompiledWhere(where, false, 'update');
|
|
838
855
|
const setClause = this.buildUpdateAssignments(args.data, params);
|
|
839
856
|
// `returning` hands back the post-update row(s); take the first (single-row contract).
|
|
840
|
-
const { rows } = await this.exec(`${this.
|
|
857
|
+
const { rows } = await this.exec(`${this.qt} filter ${where} update { ${setClause} } returning`, params, args.timeout);
|
|
841
858
|
const row = rows.length ? this.shape(rows)[0] : null;
|
|
842
859
|
if (!row)
|
|
843
860
|
throw new NotFoundError({ table: this.table, where: args.where });
|
|
@@ -852,7 +869,7 @@ export class PowqlInterface {
|
|
|
852
869
|
this.assertCompiledWhere(where, args.allowFullTableScan, 'updateMany');
|
|
853
870
|
const setClause = this.buildUpdateAssignments(args.data, params);
|
|
854
871
|
const filter = where ? ` filter ${where}` : '';
|
|
855
|
-
const { rowCount } = await this.exec(`${this.
|
|
872
|
+
const { rowCount } = await this.exec(`${this.qt}${filter} update { ${setClause} }`, params, args.timeout);
|
|
856
873
|
return { count: rowCount };
|
|
857
874
|
});
|
|
858
875
|
}
|
|
@@ -867,7 +884,7 @@ export class PowqlInterface {
|
|
|
867
884
|
}
|
|
868
885
|
const colMeta = this.column(field);
|
|
869
886
|
const ref = this.ref(field);
|
|
870
|
-
const col = colMeta.name;
|
|
887
|
+
const col = quotePowqlIdent(colMeta.name);
|
|
871
888
|
if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
|
|
872
889
|
const opObj = value;
|
|
873
890
|
if ('set' in opObj)
|
|
@@ -925,8 +942,10 @@ export class PowqlInterface {
|
|
|
925
942
|
// drifts from `powdbDialect`; falls back to the literal lowercase keywords.
|
|
926
943
|
const d = this.options.dialect;
|
|
927
944
|
const client = await this.pool.connect();
|
|
945
|
+
let began = false;
|
|
928
946
|
try {
|
|
929
947
|
await client.query(d?.beginStatement?.() ?? 'begin');
|
|
948
|
+
began = true;
|
|
930
949
|
const { TransactionClient } = await import('./client.js');
|
|
931
950
|
const tx = new TransactionClient(client, this.schema, this.middlewares, this.options);
|
|
932
951
|
const ctx = { schema: this.schema, tx: tx };
|
|
@@ -935,11 +954,16 @@ export class PowqlInterface {
|
|
|
935
954
|
return result;
|
|
936
955
|
}
|
|
937
956
|
catch (err) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
957
|
+
// Only roll back a transaction we actually opened — a failed BEGIN
|
|
958
|
+
// (queue timeout, re-entrancy E017) must not emit a stray ROLLBACK that
|
|
959
|
+
// could land inside another transaction on a shared engine handle.
|
|
960
|
+
if (began) {
|
|
961
|
+
try {
|
|
962
|
+
await client.query(d?.rollbackStatement?.() ?? 'rollback');
|
|
963
|
+
}
|
|
964
|
+
catch {
|
|
965
|
+
/* best-effort — the connection may be gone */
|
|
966
|
+
}
|
|
943
967
|
}
|
|
944
968
|
throw err;
|
|
945
969
|
}
|
|
@@ -962,7 +986,7 @@ export class PowqlInterface {
|
|
|
962
986
|
const where = this.buildWhere(resolvedWhere, params);
|
|
963
987
|
this.assertCompiledWhere(where, false, 'delete');
|
|
964
988
|
// `returning` hands back the deleted row(s) — no separate pre-image reselect needed.
|
|
965
|
-
const { rows } = await this.exec(`${this.
|
|
989
|
+
const { rows } = await this.exec(`${this.qt} filter ${where} delete returning`, params, args.timeout);
|
|
966
990
|
const row = rows.length ? this.shape(rows)[0] : null;
|
|
967
991
|
if (!row)
|
|
968
992
|
throw new NotFoundError({ table: this.table, where: args.where });
|
|
@@ -976,7 +1000,7 @@ export class PowqlInterface {
|
|
|
976
1000
|
const where = this.buildWhere(resolvedWhere, params);
|
|
977
1001
|
this.assertCompiledWhere(where, args.allowFullTableScan, 'deleteMany');
|
|
978
1002
|
const filter = where ? ` filter ${where}` : '';
|
|
979
|
-
const { rowCount } = await this.exec(`${this.
|
|
1003
|
+
const { rowCount } = await this.exec(`${this.qt}${filter} delete`, params, args.timeout);
|
|
980
1004
|
return { count: rowCount };
|
|
981
1005
|
});
|
|
982
1006
|
}
|
|
@@ -991,14 +1015,14 @@ export class PowqlInterface {
|
|
|
991
1015
|
}
|
|
992
1016
|
const params = [];
|
|
993
1017
|
const createBody = this.scalarData(createData)
|
|
994
|
-
.map((a) => `${a.col.name} := ${this.writeRef(a.value, a.col, params)}`)
|
|
1018
|
+
.map((a) => `${quotePowqlIdent(a.col.name)} := ${this.writeRef(a.value, a.col, params)}`)
|
|
995
1019
|
.join(', ');
|
|
996
1020
|
const updateBody = this.buildUpdateAssignments(args.update, params);
|
|
997
1021
|
// PowDB 0.7.0's `upsert` statement does NOT accept a trailing `returning`
|
|
998
1022
|
// (verified: "unexpected trailing token … 'returning'"), because it is one
|
|
999
1023
|
// atomic insert-or-update, not two branches. So upsert alone keeps the
|
|
1000
1024
|
// reselect-by-PK fetch; create/update/delete all use `returning`.
|
|
1001
|
-
await this.exec(`upsert ${this.
|
|
1025
|
+
await this.exec(`upsert ${this.qt} on .${pkCol} { ${createBody} } on conflict { ${updateBody} }`, params, args.timeout);
|
|
1002
1026
|
const pkField = this.meta.reverseColumnMap[pkCol] ?? pkCol;
|
|
1003
1027
|
const row = await this.reselectByPk(createData[pkField], args.timeout);
|
|
1004
1028
|
if (!row)
|
|
@@ -1043,7 +1067,7 @@ export class PowqlInterface {
|
|
|
1043
1067
|
const resolvedWhere = await this.resolveRelationFilters(args.where, args.timeout);
|
|
1044
1068
|
const where = this.buildWhere(resolvedWhere, params);
|
|
1045
1069
|
const filter = where ? ` filter ${where}` : '';
|
|
1046
|
-
const { rows } = await this.exec(`count(${this.
|
|
1070
|
+
const { rows } = await this.exec(`count(${this.qt}${filter})`, params, args.timeout);
|
|
1047
1071
|
return Number((rows[0]?.value ?? rows[0]?.count ?? 0));
|
|
1048
1072
|
});
|
|
1049
1073
|
}
|
|
@@ -1063,12 +1087,12 @@ export class PowqlInterface {
|
|
|
1063
1087
|
};
|
|
1064
1088
|
if (args._count) {
|
|
1065
1089
|
if (args._count === true) {
|
|
1066
|
-
result._count = (await scalar(`count(${this.
|
|
1090
|
+
result._count = (await scalar(`count(${this.qt}${filter})`)) ?? 0;
|
|
1067
1091
|
}
|
|
1068
1092
|
else {
|
|
1069
1093
|
const counts = {};
|
|
1070
1094
|
for (const field of Object.keys(args._count).filter((f) => args._count[f])) {
|
|
1071
|
-
counts[field] = (await scalar(`count(${this.
|
|
1095
|
+
counts[field] = (await scalar(`count(${this.qt}${filter} { ${this.ref(field)} })`)) ?? 0;
|
|
1072
1096
|
}
|
|
1073
1097
|
result._count = counts;
|
|
1074
1098
|
}
|
|
@@ -1080,7 +1104,7 @@ export class PowqlInterface {
|
|
|
1080
1104
|
const acc = {};
|
|
1081
1105
|
for (const field of Object.keys(spec).filter((f) => spec[f])) {
|
|
1082
1106
|
const powfn = fn.slice(1); // sum/avg/min/max
|
|
1083
|
-
acc[field] = await scalar(`${powfn}(${this.
|
|
1107
|
+
acc[field] = await scalar(`${powfn}(${this.qt}${filter} { ${this.ref(field)} })`);
|
|
1084
1108
|
}
|
|
1085
1109
|
result[fn] = acc;
|
|
1086
1110
|
}
|
|
@@ -1114,7 +1138,7 @@ export class PowqlInterface {
|
|
|
1114
1138
|
}
|
|
1115
1139
|
const having = this.buildHaving(args.having, params);
|
|
1116
1140
|
const order = this.buildOrder(args.orderBy);
|
|
1117
|
-
const powql = `${this.
|
|
1141
|
+
const powql = `${this.qt}${filter} group ${groupKeys.join(', ')}${having}${order} { ${proj.join(', ')} }`;
|
|
1118
1142
|
const { rows } = await this.exec(powql, params, args.timeout);
|
|
1119
1143
|
// Reshape: group keys → camel fields + coerced; aggregates → nested {_sum:{field}}.
|
|
1120
1144
|
return rows.map((raw) => {
|
package/dist/query/builder.d.ts
CHANGED
|
@@ -55,6 +55,12 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
55
55
|
/** Pre-computed column type lookups (avoids linear scans per query) */
|
|
56
56
|
private readonly columnPgTypeMap;
|
|
57
57
|
private readonly columnArrayTypeMap;
|
|
58
|
+
/**
|
|
59
|
+
* Columns whose type lives in a DIFFERENT schema than the introspected one
|
|
60
|
+
* (ColumnMetadata.pgTypeSchema is recorded only in that case) — such columns
|
|
61
|
+
* must never receive this schema's `::"enum"` cast (see enumTypeForColumn).
|
|
62
|
+
*/
|
|
63
|
+
private readonly crossSchemaTypeColumns;
|
|
58
64
|
/** Tracks tables that have already triggered a deep-with warning (one-time) */
|
|
59
65
|
private readonly deepWithWarned;
|
|
60
66
|
/**
|
|
@@ -249,7 +255,10 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
249
255
|
* loop calling `db.users.findMany()` thousands of times only logs once.
|
|
250
256
|
* Suppressed when `defaultLimit` is configured (the caller has already
|
|
251
257
|
* opted in to a bounded query) and when the user passed an explicit
|
|
252
|
-
* `limit`, `take`, or `cursor`.
|
|
258
|
+
* `limit`, `take`, or `cursor`. A per-call `warnOnUnlimited` overrides the
|
|
259
|
+
* config-level setting in either direction (`false` silences a call that
|
|
260
|
+
* intentionally reads the full set; `true` forces the warning even when
|
|
261
|
+
* disabled in config).
|
|
253
262
|
*/
|
|
254
263
|
private maybeWarnUnlimited;
|
|
255
264
|
/**
|
|
@@ -429,7 +438,12 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
429
438
|
private collectRelFilterParams;
|
|
430
439
|
/** Collect params from operator clauses. Mirrors buildOperatorClauses. */
|
|
431
440
|
private collectOperatorParams;
|
|
432
|
-
/**
|
|
441
|
+
/**
|
|
442
|
+
* Collect params from JSON filter. Mirrors buildJsonFilterClauses exactly:
|
|
443
|
+
* the `path` is bound at most once (its placeholder is shared by every
|
|
444
|
+
* extraction clause), then equals/contains/hasKey values, then the range
|
|
445
|
+
* comparison values in {@link JSON_RANGE_OPERATORS} order.
|
|
446
|
+
*/
|
|
433
447
|
private collectJsonFilterParams;
|
|
434
448
|
/** Collect params from array filter. Mirrors buildArrayFilterClauses. */
|
|
435
449
|
private collectArrayFilterParams;
|
|
@@ -545,6 +559,28 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
545
559
|
* (relation targets, not just `this.table`).
|
|
546
560
|
*/
|
|
547
561
|
private pgTypeForColumn;
|
|
562
|
+
/**
|
|
563
|
+
* The Postgres enum type name for a column, when the schema knows one.
|
|
564
|
+
*
|
|
565
|
+
* Introspection stores each column's `udt_name` in `pgTypes` and every
|
|
566
|
+
* database enum in `schema.enums` (typname → labels); a column whose type
|
|
567
|
+
* matches an enum key needs an explicit `::"EnumName"` cast on its write
|
|
568
|
+
* binds — bulk-insert forms like `UNNEST($1::text[])` otherwise type the
|
|
569
|
+
* value as text and Postgres refuses the implicit text→enum coercion
|
|
570
|
+
* ("column X is of type Y but expression is of type text").
|
|
571
|
+
*
|
|
572
|
+
* Postgres-only by construction: gated on the active dialect being
|
|
573
|
+
* `postgresql` AND on `schema.enums` having entries (only PG introspection
|
|
574
|
+
* produces them — `defineSchema` and the other engines leave it empty), so
|
|
575
|
+
* SQLite/MySQL/MSSQL/PowDB output is byte-identical.
|
|
576
|
+
*/
|
|
577
|
+
private enumTypeForColumn;
|
|
578
|
+
/**
|
|
579
|
+
* `::"EnumName"` cast suffix for a write-bind placeholder on an enum
|
|
580
|
+
* column; `''` for every other column, so non-enum SQL stays byte-identical.
|
|
581
|
+
* The type name is an introspected identifier and is quoted via the dialect.
|
|
582
|
+
*/
|
|
583
|
+
private enumCastSuffix;
|
|
548
584
|
/**
|
|
549
585
|
* Equality-fallthrough guard shared by every SQL-build path AND every
|
|
550
586
|
* cache-hit param-collect path. A plain object literal that matched no known
|
|
@@ -899,11 +935,32 @@ export declare class QueryInterface<T extends object, R extends object = {}> {
|
|
|
899
935
|
* E.g. '_text' → 'text', '_int4' → 'integer'
|
|
900
936
|
*/
|
|
901
937
|
private getArrayElementType;
|
|
938
|
+
/**
|
|
939
|
+
* Validate and enumerate the range comparisons (`gt`/`gte`/`lt`/`lte`) on a
|
|
940
|
+
* JSON filter, in the fixed {@link JSON_RANGE_OPERATORS} order. Shared by
|
|
941
|
+
* the SQL-build path ({@link buildJsonFilterClauses}) and the cache-hit
|
|
942
|
+
* param-collect path ({@link collectJsonFilterParams}) so both always agree
|
|
943
|
+
* on which params are pushed — and both throw identically for invalid
|
|
944
|
+
* shapes, so a warmed cache can never skip validation.
|
|
945
|
+
*/
|
|
946
|
+
private jsonRangeEntries;
|
|
902
947
|
/**
|
|
903
948
|
* Build SQL clauses for JSONB filter operators on a column.
|
|
904
|
-
* Supports: path, equals, contains, hasKey.
|
|
949
|
+
* Supports: path, equals, contains, hasKey, gt, gte, lt, lte.
|
|
950
|
+
*
|
|
951
|
+
* The `path` param is bound at most once and its placeholder is shared by
|
|
952
|
+
* every clause that extracts it (equals + range ops), so the param list
|
|
953
|
+
* stays byte-identical to {@link collectJsonFilterParams}.
|
|
905
954
|
*/
|
|
906
955
|
private buildJsonFilterClauses;
|
|
956
|
+
/**
|
|
957
|
+
* Cast an extracted JSON path text value to a numeric type for range
|
|
958
|
+
* comparison. PostgreSQL uses `(expr)::numeric` (exact — the right way to
|
|
959
|
+
* compare JSON numbers, and `::float` would lose precision on big ints);
|
|
960
|
+
* other dialects route through {@link Dialect.castAggregate} (SQLite/MySQL/
|
|
961
|
+
* SQL Server have no `::` operator) as a float cast.
|
|
962
|
+
*/
|
|
963
|
+
private castJsonNumeric;
|
|
907
964
|
/**
|
|
908
965
|
* Build SQL clauses for Array filter operators on a column.
|
|
909
966
|
* Supports: has, hasEvery, hasSome, isEmpty.
|