turbine-orm 0.76.0 → 0.77.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/cjs/cli/index.js +2 -2
- package/dist/cjs/cli/migrate.js +8 -8
- package/dist/cjs/cli/studio.js +6 -3
- package/dist/cjs/client.js +10 -10
- package/dist/cjs/dialect.js +1 -1
- package/dist/cjs/errors.d.ts +2 -2
- package/dist/cjs/errors.js +21 -25
- package/dist/cjs/generate.js +1 -1
- package/dist/cjs/introspect.js +5 -5
- package/dist/cjs/mssql.js +12 -12
- package/dist/cjs/mysql.js +5 -5
- package/dist/cjs/nested-write.js +31 -31
- package/dist/cjs/observe.js +1 -1
- package/dist/cjs/pipeline-submittable.js +5 -1
- package/dist/cjs/pipeline.js +8 -0
- package/dist/cjs/powdb-introspect.d.ts +1 -1
- package/dist/cjs/powdb-introspect.js +4 -4
- package/dist/cjs/powdb-shared.d.ts +348 -0
- package/dist/cjs/powdb-shared.js +587 -0
- package/dist/cjs/powdb.d.ts +12 -299
- package/dist/cjs/powdb.js +106 -567
- package/dist/cjs/powql.d.ts +1 -1
- package/dist/cjs/powql.js +89 -89
- package/dist/cjs/prisma-compat.js +16 -16
- package/dist/cjs/query/aggregates.js +19 -20
- package/dist/cjs/query/batched-loader.js +8 -8
- package/dist/cjs/query/builder.js +8 -8
- package/dist/cjs/query/compound-unique.js +2 -2
- package/dist/cjs/query/filters.js +1 -1
- package/dist/cjs/query/relations.js +60 -48
- package/dist/cjs/query/types.js +4 -4
- package/dist/cjs/query/utils.js +5 -5
- package/dist/cjs/query/warn-registry.d.ts +7 -0
- package/dist/cjs/query/warn-registry.js +7 -0
- package/dist/cjs/query/where-compile.js +1 -1
- package/dist/cjs/query/where.js +30 -31
- package/dist/cjs/query/writes.js +7 -7
- package/dist/cjs/realtime.js +4 -4
- package/dist/cjs/schema-metadata.js +1 -1
- package/dist/cjs/schema-sql.js +3 -3
- package/dist/cjs/seed.js +1 -1
- package/dist/cjs/sqlite.js +7 -7
- package/dist/cjs/typed-sql.js +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/migrate.js +8 -8
- package/dist/cli/studio.js +6 -3
- package/dist/client.js +10 -10
- package/dist/dialect.js +1 -1
- package/dist/errors.d.ts +2 -2
- package/dist/errors.js +21 -25
- package/dist/generate.js +1 -1
- package/dist/introspect.js +5 -5
- package/dist/mssql.js +12 -12
- package/dist/mysql.js +5 -5
- package/dist/nested-write.js +31 -31
- package/dist/observe.js +1 -1
- package/dist/pipeline-submittable.js +6 -2
- package/dist/pipeline.js +9 -1
- package/dist/powdb-introspect.d.ts +1 -1
- package/dist/powdb-introspect.js +2 -2
- package/dist/powdb-shared.d.ts +348 -0
- package/dist/powdb-shared.js +570 -0
- package/dist/powdb.d.ts +12 -299
- package/dist/powdb.js +71 -534
- package/dist/powql.d.ts +1 -1
- package/dist/powql.js +43 -43
- package/dist/prisma-compat.js +16 -16
- package/dist/query/aggregates.js +19 -20
- package/dist/query/batched-loader.js +8 -8
- package/dist/query/builder.js +8 -8
- package/dist/query/compound-unique.js +2 -2
- package/dist/query/filters.js +1 -1
- package/dist/query/relations.js +60 -48
- package/dist/query/types.js +4 -4
- package/dist/query/utils.js +5 -5
- package/dist/query/warn-registry.d.ts +7 -0
- package/dist/query/warn-registry.js +7 -0
- package/dist/query/where-compile.js +1 -1
- package/dist/query/where.js +30 -31
- package/dist/query/writes.js +7 -7
- package/dist/realtime.js +4 -4
- package/dist/schema-metadata.js +1 -1
- package/dist/schema-sql.js +3 -3
- package/dist/seed.js +1 -1
- package/dist/sqlite.js +7 -7
- package/dist/typed-sql.js +1 -1
- package/package.json +15 -7
package/dist/query/aggregates.js
CHANGED
|
@@ -37,7 +37,7 @@ export function assertAggregatePiiOptIn(table, meta, field, column, usage, inclu
|
|
|
37
37
|
const colMeta = meta.columns.find((c) => c.name === column);
|
|
38
38
|
if (!colMeta?.pii)
|
|
39
39
|
return;
|
|
40
|
-
throw new ValidationError(
|
|
40
|
+
throw new ValidationError(`${usage} on column "${field}" of table "${table}" is refused: that column is ` +
|
|
41
41
|
'PII-tagged (`pii: true`), and this aggregate returns its stored values, which are excluded ' +
|
|
42
42
|
'from every default projection. Pass `includePii: UNSAFE` on this call to opt in ' +
|
|
43
43
|
"(import { UNSAFE } from 'turbine-orm'). " +
|
|
@@ -101,7 +101,7 @@ export function buildGroupBy(qi, args) {
|
|
|
101
101
|
const usedResultKeys = new Set();
|
|
102
102
|
const claimResultKey = (key, what) => {
|
|
103
103
|
if (key === '_count' || usedResultKeys.has(key)) {
|
|
104
|
-
throw new ValidationError(`
|
|
104
|
+
throw new ValidationError(`groupBy output name "${key}" (${what}) collides with another output column on table ` +
|
|
105
105
|
`"${qi.table}": set an explicit \`alias\` (or rename the aggregate key) to disambiguate.`);
|
|
106
106
|
}
|
|
107
107
|
usedResultKeys.add(key);
|
|
@@ -224,7 +224,7 @@ export function buildGroupBy(qi, args) {
|
|
|
224
224
|
}
|
|
225
225
|
const alwaysNumeric = aggKey === '_sum' || aggKey === '_avg';
|
|
226
226
|
if (alwaysNumeric && target.type === 'text') {
|
|
227
|
-
throw new ValidationError(`
|
|
227
|
+
throw new ValidationError(`groupBy ${aggKey} target "${key}" on table "${qi.table}": ` +
|
|
228
228
|
`${aggKey} over a JSON path is always numeric: remove \`type: 'text'\`.`);
|
|
229
229
|
}
|
|
230
230
|
const numeric = alwaysNumeric || target.type === 'numeric';
|
|
@@ -446,7 +446,7 @@ export function buildGroupByOrderBy(qi, orderBy, byOrderExprs, aggOrderExprs) {
|
|
|
446
446
|
if (key === '_count') {
|
|
447
447
|
const expr = aggOrderExprs.get('_count');
|
|
448
448
|
if (!expr) {
|
|
449
|
-
throw new ValidationError(`
|
|
449
|
+
throw new ValidationError(`Cannot order groupBy by "_count" on table "${qi.table}": _count is not selected. ` +
|
|
450
450
|
`Orderable keys: ${validKeys()}.`);
|
|
451
451
|
}
|
|
452
452
|
// Refuse a direction that is neither asc nor desc BEFORE normalizeOrderBy,
|
|
@@ -457,7 +457,7 @@ export function buildGroupByOrderBy(qi, orderBy, byOrderExprs, aggOrderExprs) {
|
|
|
457
457
|
}
|
|
458
458
|
// `_sum` / `_avg` / `_min` / `_max`: an object of field → direction/spec.
|
|
459
459
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
460
|
-
throw new ValidationError(`
|
|
460
|
+
throw new ValidationError(`Invalid groupBy orderBy for "${key}" on table "${qi.table}": ` +
|
|
461
461
|
`expected a field map like { ${key}: { amount: 'desc' } }.`);
|
|
462
462
|
}
|
|
463
463
|
for (const [field, dirSpec] of Object.entries(value)) {
|
|
@@ -469,7 +469,7 @@ export function buildGroupByOrderBy(qi, orderBy, byOrderExprs, aggOrderExprs) {
|
|
|
469
469
|
const expr = aggOrderExprs.get(`${key}:${field}`) ??
|
|
470
470
|
(canonical === undefined ? undefined : aggOrderExprs.get(`${key}:${canonical}`));
|
|
471
471
|
if (!expr) {
|
|
472
|
-
throw new ValidationError(`
|
|
472
|
+
throw new ValidationError(`Cannot order groupBy by "${key}.${field}" on table "${qi.table}": ` +
|
|
473
473
|
`that aggregate is not requested in this call. Orderable keys: ${validKeys()}.`);
|
|
474
474
|
}
|
|
475
475
|
assertOrderDirection(dirSpec, `groupBy orderBy "${key}.${field}" on table "${qi.table}"`);
|
|
@@ -480,8 +480,7 @@ export function buildGroupByOrderBy(qi, orderBy, byOrderExprs, aggOrderExprs) {
|
|
|
480
480
|
// Plain by-field name or JSON group-key alias.
|
|
481
481
|
const expr = lookupGroupKey(qi, byOrderExprs, key);
|
|
482
482
|
if (!expr) {
|
|
483
|
-
throw new ValidationError(`
|
|
484
|
-
`Orderable keys: ${validKeys()}.`);
|
|
483
|
+
throw new ValidationError(`Unknown field "${key}" in groupBy orderBy on table "${qi.table}". ` + `Orderable keys: ${validKeys()}.`);
|
|
485
484
|
}
|
|
486
485
|
assertOrderDirection(value, `groupBy orderBy "${key}" on table "${qi.table}"`);
|
|
487
486
|
pushOrderTerm(expr, key, value);
|
|
@@ -495,18 +494,18 @@ export function buildGroupByOrderBy(qi, orderBy, byOrderExprs, aggOrderExprs) {
|
|
|
495
494
|
*/
|
|
496
495
|
export function resolveJsonPathTarget(qi, context, field, path) {
|
|
497
496
|
if (typeof field !== 'string') {
|
|
498
|
-
throw new ValidationError(`
|
|
497
|
+
throw new ValidationError(`groupBy ${context} on table "${qi.table}" requires a string \`field\`.`);
|
|
499
498
|
}
|
|
500
499
|
const col = qi.toColumn(field);
|
|
501
500
|
if (!Array.isArray(path) ||
|
|
502
501
|
path.length === 0 ||
|
|
503
502
|
path.some((el) => typeof el !== 'string' && !(typeof el === 'number' && Number.isFinite(el)))) {
|
|
504
|
-
throw new ValidationError(`
|
|
503
|
+
throw new ValidationError(`groupBy ${context} on "${field}" (table "${qi.table}") requires a non-empty \`path\` ` +
|
|
505
504
|
`array of keys/indexes (e.g. { field: '${field}', path: ['category'] }).`);
|
|
506
505
|
}
|
|
507
506
|
const colType = whereMod.pgTypeForColumn(qi, qi.tableMeta, col);
|
|
508
507
|
if (!whereMod.isJsonColumnType(qi, colType)) {
|
|
509
|
-
throw new ValidationError(`
|
|
508
|
+
throw new ValidationError(`groupBy ${context} on "${field}": column "${col}" on table "${qi.table}" is not a JSON ` +
|
|
510
509
|
`column (actual type: ${colType}).`);
|
|
511
510
|
}
|
|
512
511
|
return col;
|
|
@@ -530,11 +529,11 @@ export function buildDistinctOnSource(qi, distinctOn, whereSql, params) {
|
|
|
530
529
|
throw new UnsupportedFeatureError('DISTINCT ON row source (groupBy distinctOn)', qi.dialect.name, 'groupBy({ distinctOn }) requires PostgreSQL: SELECT DISTINCT ON is not portable.');
|
|
531
530
|
}
|
|
532
531
|
if (!Array.isArray(distinctOn.columns) || distinctOn.columns.length === 0) {
|
|
533
|
-
throw new ValidationError(`
|
|
532
|
+
throw new ValidationError(`groupBy distinctOn on table "${qi.table}" requires a non-empty \`columns\` array.`);
|
|
534
533
|
}
|
|
535
534
|
const orderEntries = Object.entries(distinctOn.orderBy ?? {});
|
|
536
535
|
if (orderEntries.length === 0) {
|
|
537
|
-
throw new ValidationError(`
|
|
536
|
+
throw new ValidationError(`groupBy distinctOn on table "${qi.table}" requires \`orderBy\` to pick ONE row per ` +
|
|
538
537
|
"column combination deterministically (e.g. orderBy: { createdAt: 'desc' }).");
|
|
539
538
|
}
|
|
540
539
|
// A repeated DISTINCT ON column is a no-op, so drop it rather than emit it
|
|
@@ -554,7 +553,7 @@ export function buildDistinctOnSource(qi, distinctOn, whereSql, params) {
|
|
|
554
553
|
continue;
|
|
555
554
|
}
|
|
556
555
|
if (isVectorOrderBy(value) || qi.isRelationOrderByValue(value)) {
|
|
557
|
-
throw new ValidationError(`
|
|
556
|
+
throw new ValidationError(`groupBy distinctOn.orderBy on "${key}" (table "${qi.table}") supports plain columns, ` +
|
|
558
557
|
'sort specs, and JSON-path orderings only.');
|
|
559
558
|
}
|
|
560
559
|
const col = qi.resolveOrderByColumn(qi.table, qi.tableMeta, key);
|
|
@@ -668,7 +667,7 @@ function splitHavingField(qi, field, value) {
|
|
|
668
667
|
aggEntries.push({ key: k, fn, filter: v });
|
|
669
668
|
}
|
|
670
669
|
else if (k.startsWith('_')) {
|
|
671
|
-
throw new ValidationError(`
|
|
670
|
+
throw new ValidationError(`Unknown aggregate "${k}" in having for field "${field}" on table "${qi.table}". ` +
|
|
672
671
|
`Supported: ${Object.keys(HAVING_AGGREGATE_FNS).join(', ')}.`);
|
|
673
672
|
}
|
|
674
673
|
else {
|
|
@@ -704,7 +703,7 @@ function buildHavingCombinator(qi, key, value, params, jsonAggExprs, groupKeys,
|
|
|
704
703
|
const parts = [];
|
|
705
704
|
for (const condition of conditions) {
|
|
706
705
|
if (!isUnmatchedPlainObject(condition)) {
|
|
707
|
-
throw new ValidationError(`
|
|
706
|
+
throw new ValidationError(`Invalid having "${key}" on table "${qi.table}": expected ` +
|
|
708
707
|
`${key === 'OR' ? 'an array of having objects' : 'a having object (or an array of them)'}.`);
|
|
709
708
|
}
|
|
710
709
|
const sub = buildHavingClauses(qi, condition, params, jsonAggExprs, groupKeys, depth + 1);
|
|
@@ -745,7 +744,7 @@ function buildHavingScalarClauses(qi, field, value, params, groupKeys) {
|
|
|
745
744
|
const ref = groupKeys ? lookupGroupKey(qi, groupKeys, field) : undefined;
|
|
746
745
|
if (!ref) {
|
|
747
746
|
const known = groupKeys ? [...groupKeys.keys()] : [];
|
|
748
|
-
throw new ValidationError(`
|
|
747
|
+
throw new ValidationError(`having on "${field}" (table "${qi.table}") filters the grouped value itself, but ` +
|
|
749
748
|
`"${field}" is not one of the \`by\` group keys [${known.join(', ') || 'none'}]. A predicate on a ` +
|
|
750
749
|
'non-grouped column cannot go in HAVING: move it to `where` (it filters rows, not groups), add ' +
|
|
751
750
|
`"${field}" to \`by\`, or filter an aggregate of it instead (e.g. { ${field}: { _count: { gt: 0 } } }).`);
|
|
@@ -765,7 +764,7 @@ function buildHavingScalarClauses(qi, field, value, params, groupKeys) {
|
|
|
765
764
|
clauses.push(...whereMod.buildOperatorClauses(qi, ref.expr, value, params));
|
|
766
765
|
}
|
|
767
766
|
else if (isUnmatchedPlainObject(value)) {
|
|
768
|
-
throw new ValidationError(`
|
|
767
|
+
throw new ValidationError(`Unknown operator${Object.keys(value).length > 1 ? 's' : ''} ` +
|
|
769
768
|
`${Object.keys(value)
|
|
770
769
|
.map((k) => `"${k}"`)
|
|
771
770
|
.join(', ')} on ${ref.label} in having for table "${qi.table}".`);
|
|
@@ -785,7 +784,7 @@ function buildHavingScalarClauses(qi, field, value, params, groupKeys) {
|
|
|
785
784
|
*/
|
|
786
785
|
export function buildHavingNumericClauses(qi, expr, filter, params) {
|
|
787
786
|
if (filter === null) {
|
|
788
|
-
throw new ValidationError(`
|
|
787
|
+
throw new ValidationError(`Invalid having filter on "${expr}" for table "${qi.table}": expected a value or operator object.`);
|
|
789
788
|
}
|
|
790
789
|
// Bare value (number, string, boolean, Date, …) → equality.
|
|
791
790
|
if (typeof filter !== 'object' || filter instanceof Date) {
|
|
@@ -796,7 +795,7 @@ export function buildHavingNumericClauses(qi, expr, filter, params) {
|
|
|
796
795
|
const allowedKeys = new Set(['equals', 'not', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn']);
|
|
797
796
|
for (const k of Object.keys(op)) {
|
|
798
797
|
if (!allowedKeys.has(k)) {
|
|
799
|
-
throw new ValidationError(`
|
|
798
|
+
throw new ValidationError(`Unknown having operator "${k}" on "${expr}" for table "${qi.table}". ` +
|
|
800
799
|
`Supported: ${[...allowedKeys].join(', ')}.`);
|
|
801
800
|
}
|
|
802
801
|
}
|
|
@@ -418,11 +418,11 @@ export function resolveCountRelations(parentMeta, countSpec) {
|
|
|
418
418
|
continue;
|
|
419
419
|
const rel = ownLookup(parentMeta.relations, relName);
|
|
420
420
|
if (!rel) {
|
|
421
|
-
throw new RelationError(`
|
|
421
|
+
throw new RelationError(`Unknown relation "${relName}" in _count on table "${parentMeta.name}". ` +
|
|
422
422
|
availableClause(Object.keys(parentMeta.relations), 'It has no relations.'));
|
|
423
423
|
}
|
|
424
424
|
if (!isToMany(rel)) {
|
|
425
|
-
throw new ValidationError(`
|
|
425
|
+
throw new ValidationError(`_count is only supported for to-many relations; "${relName}" on ` +
|
|
426
426
|
`"${parentMeta.name}" is a to-one relation.`);
|
|
427
427
|
}
|
|
428
428
|
out.push(rel);
|
|
@@ -452,7 +452,7 @@ export function rejectNestedPickOrder(withClause) {
|
|
|
452
452
|
if (options.orderBy) {
|
|
453
453
|
for (const [key, value] of Object.entries(options.orderBy)) {
|
|
454
454
|
if (isRelationPickOrderBy(value)) {
|
|
455
|
-
throw new ValidationError(`
|
|
455
|
+
throw new ValidationError(`Pick-row ordering on relation "${key}" is only supported in a top-level ` +
|
|
456
456
|
'findMany orderBy: nested `with` orderBy does not support it.');
|
|
457
457
|
}
|
|
458
458
|
}
|
|
@@ -494,7 +494,7 @@ export async function loadRelationsBatched(ctx, parents, withClause, timeout, de
|
|
|
494
494
|
// RelationError (E005), NOT ValidationError: the join strategy throws
|
|
495
495
|
// E005 for this exact shape (relations.ts), and under 'auto' the two
|
|
496
496
|
// must refuse identically or the error CODE depends on table size.
|
|
497
|
-
throw new RelationError(`
|
|
497
|
+
throw new RelationError(`Unknown relation "${relName}" on table "${ctx.parentMeta.name}". ` +
|
|
498
498
|
availableClause(Object.keys(ctx.parentMeta.relations), 'It has no relations.'));
|
|
499
499
|
}
|
|
500
500
|
resolved.push({ relName, rel, options: spec === true ? {} : spec });
|
|
@@ -522,7 +522,7 @@ export async function loadRelationsBatched(ctx, parents, withClause, timeout, de
|
|
|
522
522
|
// nested projections all learning it together, which is a feature release,
|
|
523
523
|
// not a line in a correctness fix. Until then both strategies say no.
|
|
524
524
|
if (hasCount && depth > 0) {
|
|
525
|
-
throw new RelationError(`
|
|
525
|
+
throw new RelationError(`Unknown relation "_count" on table "${ctx.parentMeta.name}". ` +
|
|
526
526
|
`${availableClause(Object.keys(ctx.parentMeta.relations), 'It has no relations.')} ` +
|
|
527
527
|
'(`_count` is supported on the top-level `with` only, on every relationLoadStrategy.)');
|
|
528
528
|
}
|
|
@@ -804,7 +804,7 @@ function stripRankColumn(result) {
|
|
|
804
804
|
async function loadManyToMany(ctx, parents, rel, relName, options, timeout, depth, path) {
|
|
805
805
|
const through = rel.through;
|
|
806
806
|
if (!through) {
|
|
807
|
-
throw new ValidationError(`
|
|
807
|
+
throw new ValidationError(`manyToMany relation "${relName}" is missing its junction (\`through\`).`);
|
|
808
808
|
}
|
|
809
809
|
const sourceJ = normalizeKeyColumns(through.sourceKey);
|
|
810
810
|
const targetJ = normalizeKeyColumns(through.targetKey);
|
|
@@ -962,7 +962,7 @@ async function loadOneCount(ctx, parents, rel) {
|
|
|
962
962
|
if (rel.type === 'manyToMany') {
|
|
963
963
|
const through = rel.through;
|
|
964
964
|
if (!through) {
|
|
965
|
-
throw new ValidationError(`
|
|
965
|
+
throw new ValidationError(`manyToMany relation "${rel.name}" is missing its junction (\`through\`).`);
|
|
966
966
|
}
|
|
967
967
|
const sourceRef = normalizeKeyColumns(rel.referenceKey);
|
|
968
968
|
const sourceJ = normalizeKeyColumns(through.sourceKey);
|
|
@@ -1147,6 +1147,6 @@ function groupBy(rows, field) {
|
|
|
1147
1147
|
function requireTable(schema, table, relName) {
|
|
1148
1148
|
const meta = schema.tables[table];
|
|
1149
1149
|
if (!meta)
|
|
1150
|
-
throw new RelationError(`
|
|
1150
|
+
throw new RelationError(`Unknown relation target "${table}" (relation "${relName}").`);
|
|
1151
1151
|
return meta;
|
|
1152
1152
|
}
|
package/dist/query/builder.js
CHANGED
|
@@ -669,7 +669,7 @@ export class QueryInterface {
|
|
|
669
669
|
this.schema = schema;
|
|
670
670
|
const meta = schema.tables[table];
|
|
671
671
|
if (!meta) {
|
|
672
|
-
throw new ValidationError(`
|
|
672
|
+
throw new ValidationError(`Unknown table "${table}". ${availableClause(Object.keys(schema.tables), 'The schema has no tables.')}`);
|
|
673
673
|
}
|
|
674
674
|
this.tableMeta = meta;
|
|
675
675
|
this.middlewares = middlewares ?? [];
|
|
@@ -970,7 +970,7 @@ export class QueryInterface {
|
|
|
970
970
|
paginationValue(value, arg) {
|
|
971
971
|
const n = Number(value);
|
|
972
972
|
if (!Number.isSafeInteger(n) || n < 0) {
|
|
973
|
-
throw new ValidationError(
|
|
973
|
+
throw new ValidationError(`${arg} on "${this.table}" must be a non-negative integer, received: ${String(value)}`);
|
|
974
974
|
}
|
|
975
975
|
return n;
|
|
976
976
|
}
|
|
@@ -1054,7 +1054,7 @@ export class QueryInterface {
|
|
|
1054
1054
|
return this.currentJsonEncoding;
|
|
1055
1055
|
}
|
|
1056
1056
|
if (!JSON_ENCODINGS.includes(argEncoding)) {
|
|
1057
|
-
throw new ValidationError(`
|
|
1057
|
+
throw new ValidationError(`Invalid \`jsonEncoding\` on "${this.table}": ${JSON.stringify(argEncoding)}. ` +
|
|
1058
1058
|
`Expected ${JSON_ENCODINGS.map((e) => `'${e}'`).join(' or ')}.`);
|
|
1059
1059
|
}
|
|
1060
1060
|
this.currentJsonEncoding = argEncoding;
|
|
@@ -1882,7 +1882,7 @@ export class QueryInterface {
|
|
|
1882
1882
|
if (!paramsOk) {
|
|
1883
1883
|
details.push(`cache-hit params and freshly-built params diverge (collected ${collectedParams.length}, built ${freshParams.length})`);
|
|
1884
1884
|
}
|
|
1885
|
-
const message = `
|
|
1885
|
+
const message = `SQL cache lockstep violation on ${op} (fingerprint "${cacheKey}"). ` +
|
|
1886
1886
|
`This is a Turbine internal invariant violation, please report it at ` +
|
|
1887
1887
|
`https://github.com/zvndev/turbine-orm/issues. The fingerprint, SQL-build, and ` +
|
|
1888
1888
|
`param-collect paths must enumerate where-clause keys identically.\n${details.join('\n')}`;
|
|
@@ -1976,7 +1976,7 @@ export class QueryInterface {
|
|
|
1976
1976
|
'engine has no such cache to keep it out of. Remove the option, or set it only on PostgreSQL queries.');
|
|
1977
1977
|
}
|
|
1978
1978
|
if (this.options?.planCacheMode === 'force_generic_plan') {
|
|
1979
|
-
throw new ValidationError('
|
|
1979
|
+
throw new ValidationError('forceCustomPlan: true cannot be honoured on a client configured with ' +
|
|
1980
1980
|
"planCacheMode: 'force_generic_plan'. That setting is a connection parameter and it governs UNNAMED " +
|
|
1981
1981
|
'statements as well as named ones, so the mechanism this option uses (withholding the ' +
|
|
1982
1982
|
'prepared-statement name, so the driver re-parses the statement on every execution and it is planned ' +
|
|
@@ -2220,7 +2220,7 @@ export class QueryInterface {
|
|
|
2220
2220
|
// optional filter" is its whole contract and Prisma's `findFirst` behaves
|
|
2221
2221
|
// the same way; ask for one row by identity with `findUnique`.
|
|
2222
2222
|
if (whereMod.userPredicateIsEmpty(this.ctx, (args.where ?? {}))) {
|
|
2223
|
-
throw new ValidationError(`
|
|
2223
|
+
throw new ValidationError(`findUnique on "${this.table}" refused: the \`where\` clause has no predicate, ` +
|
|
2224
2224
|
'so this would return an arbitrary row rather than a specific one. ' +
|
|
2225
2225
|
'A key whose value is `undefined` does not count, check that the value you are looking up is defined. ' +
|
|
2226
2226
|
'If you meant "any row matching an optional filter", use `findFirst`.');
|
|
@@ -2661,7 +2661,7 @@ export class QueryInterface {
|
|
|
2661
2661
|
if (args?.distinct && args.distinct.length > 0 && args.orderBy) {
|
|
2662
2662
|
for (const [, d] of orderByEntries(args.orderBy)) {
|
|
2663
2663
|
if (this.isRelationOrderByValue(d)) {
|
|
2664
|
-
throw new ValidationError('
|
|
2664
|
+
throw new ValidationError('`distinct` cannot be combined with relation orderBy (pick-row, `_count`, or ' +
|
|
2665
2665
|
'to-one relation ordering): the outer re-order cannot reference the parent table.');
|
|
2666
2666
|
}
|
|
2667
2667
|
}
|
|
@@ -2858,7 +2858,7 @@ export class QueryInterface {
|
|
|
2858
2858
|
// the user's order (picks the right representative row), outer re-ordered
|
|
2859
2859
|
// by the user's order alone.
|
|
2860
2860
|
if (orderByEntries(args.orderBy).some(([, d]) => isVectorOrderBy(d))) {
|
|
2861
|
-
throw new ValidationError('
|
|
2861
|
+
throw new ValidationError('`distinct` cannot be combined with vector distance ordering.');
|
|
2862
2862
|
}
|
|
2863
2863
|
const userOrder = this.buildOrderBy(args.orderBy, freshParams);
|
|
2864
2864
|
const inner = `SELECT ${distinctPrefix}${selectClause} FROM ${qt}${tail} ORDER BY ${distinctCols
|
|
@@ -179,7 +179,7 @@ export function expandCompoundUniqueWhere(meta, where) {
|
|
|
179
179
|
providedByColumn.size === expected.size &&
|
|
180
180
|
[...providedByColumn.keys()].every((c) => expected.has(c));
|
|
181
181
|
if (!exact) {
|
|
182
|
-
throw new ValidationError(`
|
|
182
|
+
throw new ValidationError(`Compound unique selector "${key}" on table "${meta.name}" must supply exactly ` +
|
|
183
183
|
`{ ${fields.join(', ')} }, received { ${provided.join(', ') || '(none)'} }.`);
|
|
184
184
|
}
|
|
185
185
|
result ??= { ...where };
|
|
@@ -236,7 +236,7 @@ export function assertWhereIdentifiesOneRow(meta, table, where) {
|
|
|
236
236
|
? `Name a unique key (${keys.join(', ')}), or use \`findFirst\` if you meant "any row matching a filter".`
|
|
237
237
|
: `Table "${table}" declares no primary key and no unique constraint, so no \`where\` can identify one row ` +
|
|
238
238
|
'here. Use `findFirst` (add an `orderBy` to make which row it is deterministic).';
|
|
239
|
-
throw new ValidationError(`
|
|
239
|
+
throw new ValidationError(`findUnique on "${table}" refused: the \`where\` clause does not identify a single row, ` +
|
|
240
240
|
`so this would return an arbitrary one of the rows that match. ${advice}`);
|
|
241
241
|
}
|
|
242
242
|
export function uniqueKeyNames(meta) {
|
package/dist/query/filters.js
CHANGED
|
@@ -136,7 +136,7 @@ export function fingerprintOperatorShape(value) {
|
|
|
136
136
|
export function assertBindableEqualsOperand(value, column) {
|
|
137
137
|
if (!isUnmatchedPlainObject(value))
|
|
138
138
|
return;
|
|
139
|
-
throw new ValidationError(`
|
|
139
|
+
throw new ValidationError(`Plain-object value for operator 'equals' on ${column}: ` +
|
|
140
140
|
`objects are only valid 'equals' values on JSON (json/jsonb) columns, ` +
|
|
141
141
|
`where 'equals' is the JSONB containment filter.`);
|
|
142
142
|
}
|