@vibeorm/runtime 2.4.0 → 2.5.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 +7 -0
- package/dist/adapter-kit/index.d.ts +2 -1
- package/dist/adapter-kit/index.d.ts.map +1 -1
- package/dist/adapter-kit/index.js +53 -3
- package/dist/adapter-kit/index.js.map +5 -4
- package/dist/adapter-kit/row-changes.d.ts +29 -0
- package/dist/adapter-kit/row-changes.d.ts.map +1 -0
- package/dist/adapter-kit/savepoint-gate.d.ts +8 -0
- package/dist/adapter-kit/savepoint-gate.d.ts.map +1 -1
- package/dist/adapter.d.ts +14 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/advisory-key.d.ts +10 -0
- package/dist/advisory-key.d.ts.map +1 -0
- package/dist/advisory-lock.d.ts +3 -3
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/codecs.d.ts.map +1 -1
- package/dist/database-module.d.ts.map +1 -1
- package/dist/find-page.d.ts +35 -0
- package/dist/find-page.d.ts.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +541 -274
- package/dist/index.js.map +26 -22
- package/dist/keyset-iterator.d.ts.map +1 -1
- package/dist/keyset-projection.d.ts +12 -0
- package/dist/keyset-projection.d.ts.map +1 -0
- package/dist/model-meta.d.ts +5 -1
- package/dist/model-meta.d.ts.map +1 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/query-builder.d.ts +8 -1
- package/dist/query-builder.d.ts.map +1 -1
- package/dist/read-only.d.ts +17 -1
- package/dist/read-only.d.ts.map +1 -1
- package/dist/relation-plan.d.ts +1 -0
- package/dist/relation-plan.d.ts.map +1 -1
- package/dist/render-cache.d.ts.map +1 -1
- package/dist/rls-readiness.d.ts.map +1 -1
- package/dist/scoped.d.ts.map +1 -1
- package/dist/transaction-row-changes.d.ts +28 -0
- package/dist/transaction-row-changes.d.ts.map +1 -0
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ function createSqlModel(params) {
|
|
|
30
30
|
if (model === undefined)
|
|
31
31
|
throw new VibeError({ code: "VIBE_VALIDATION", message: "Unknown SQL model" });
|
|
32
32
|
const tableName = model.dbName ?? model.name;
|
|
33
|
-
const table = sql.ident({ parts: [tableName] });
|
|
33
|
+
const table = sql.ident({ parts: model.namespace === undefined ? [tableName] : [model.namespace, tableName] });
|
|
34
34
|
const fields = Object.fromEntries(model.fields.filter((field) => field.isUnsupported !== true).map((field) => {
|
|
35
35
|
let decoder;
|
|
36
36
|
if (isEnumType(field.type)) {
|
|
@@ -199,8 +199,62 @@ function statementFor(params) {
|
|
|
199
199
|
key: params.key
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
|
+
// packages/runtime/src/advisory-key.ts
|
|
203
|
+
import { createHash } from "crypto";
|
|
204
|
+
import { VibeError as VibeError5 } from "@vibeorm/schema";
|
|
205
|
+
function advisoryKeyOf(params) {
|
|
206
|
+
const { text } = params;
|
|
207
|
+
const refuse = () => new VibeError5({
|
|
208
|
+
code: "VIBE_VALIDATION",
|
|
209
|
+
message: "advisoryKeyOf text must be a well-formed UTF-16 string",
|
|
210
|
+
meta: { reason: "advisory-key-text" }
|
|
211
|
+
});
|
|
212
|
+
if (typeof text !== "string")
|
|
213
|
+
throw refuse();
|
|
214
|
+
for (let index = 0;index < text.length; index++) {
|
|
215
|
+
const unit = text.charCodeAt(index);
|
|
216
|
+
if (unit >= 55296 && unit <= 56319) {
|
|
217
|
+
const next = text.charCodeAt(index + 1);
|
|
218
|
+
if (!(next >= 56320 && next <= 57343))
|
|
219
|
+
throw refuse();
|
|
220
|
+
index++;
|
|
221
|
+
} else if (unit >= 56320 && unit <= 57343) {
|
|
222
|
+
throw refuse();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return createHash("sha256").update(text, "utf8").digest().readBigInt64BE(0);
|
|
226
|
+
}
|
|
227
|
+
// packages/runtime/src/transaction-row-changes.ts
|
|
228
|
+
import { VibeError as VibeError6 } from "@vibeorm/schema";
|
|
229
|
+
var observations = new WeakMap;
|
|
230
|
+
function registerTransactionObservation(params) {
|
|
231
|
+
observations.set(params.db, params.observation);
|
|
232
|
+
}
|
|
233
|
+
function inheritTransactionObservation(params) {
|
|
234
|
+
const observation = observations.get(params.from);
|
|
235
|
+
if (observation !== undefined)
|
|
236
|
+
observations.set(params.to, observation);
|
|
237
|
+
}
|
|
238
|
+
function transactionRowChanges(params) {
|
|
239
|
+
const observation = observations.get(params.db);
|
|
240
|
+
if (observation === undefined)
|
|
241
|
+
throw new VibeError6({
|
|
242
|
+
code: "VIBE_CONFIG",
|
|
243
|
+
message: "transactionRowChanges requires a registered handle from this VibeORM runtime installation",
|
|
244
|
+
meta: { reason: "transaction-observation-handle" }
|
|
245
|
+
});
|
|
246
|
+
if (!observation.inTransaction)
|
|
247
|
+
throw new VibeError6({
|
|
248
|
+
code: "VIBE_TRANSACTION",
|
|
249
|
+
message: "transactionRowChanges requires an active transaction handle",
|
|
250
|
+
meta: { reason: "transaction-observation-context" }
|
|
251
|
+
});
|
|
252
|
+
observation.assertActive();
|
|
253
|
+
const count = observation.read();
|
|
254
|
+
return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : "unknown";
|
|
255
|
+
}
|
|
202
256
|
// packages/runtime/src/model-meta.ts
|
|
203
|
-
import { VibeError as
|
|
257
|
+
import { VibeError as VibeError7, enumStorageOf, isEnumType as isEnumType2, validateComputedConfig } from "@vibeorm/schema";
|
|
204
258
|
import { enumMembershipCodec } from "@vibeorm/sql";
|
|
205
259
|
function toClientName(params) {
|
|
206
260
|
const { name } = params;
|
|
@@ -308,6 +362,7 @@ function buildFieldMeta(params) {
|
|
|
308
362
|
type: field.type,
|
|
309
363
|
scalarType: enumName === null ? field.type : null,
|
|
310
364
|
enumName,
|
|
365
|
+
...enumStorage !== "database" || enumDef === undefined || enumDef.namespace === undefined && (!isEnumType2(field.type) || field.type.namespace === undefined) ? {} : { enumSqlName: { namespace: enumDef.namespace ?? (isEnumType2(field.type) ? field.type.namespace : undefined) ?? "public", name: enumDef.dbName ?? enumDef.name } },
|
|
311
366
|
enumStorage,
|
|
312
367
|
enumCodec: enumStorage === "string" && enumDef !== undefined ? enumMembershipCodec({ model, field: field.name, enum: enumDef.name, members: enumDef.values }) : null,
|
|
313
368
|
isList: field.isList,
|
|
@@ -329,7 +384,7 @@ function buildModelMeta(params) {
|
|
|
329
384
|
for (const name of model.primaryKey.fields) {
|
|
330
385
|
const field = fieldByName.get(name);
|
|
331
386
|
if (field === undefined) {
|
|
332
|
-
throw new
|
|
387
|
+
throw new VibeError7({
|
|
333
388
|
code: "VIBE_SCHEMA_INVALID",
|
|
334
389
|
message: `model "${model.name}" declares composite primary-key field "${name}", which does not exist`,
|
|
335
390
|
meta: { model: model.name, field: name }
|
|
@@ -396,6 +451,7 @@ function buildModelMeta(params) {
|
|
|
396
451
|
name: model.name,
|
|
397
452
|
clientName: toClientName({ name: model.name }),
|
|
398
453
|
tableName: model.dbName ?? model.name,
|
|
454
|
+
...model.namespace === undefined ? {} : { namespace: model.namespace },
|
|
399
455
|
fields,
|
|
400
456
|
fieldByName,
|
|
401
457
|
fieldByColumn,
|
|
@@ -435,7 +491,7 @@ function getModelMeta(params) {
|
|
|
435
491
|
const { meta, model } = params;
|
|
436
492
|
const found = meta.modelByName.get(model);
|
|
437
493
|
if (found === undefined) {
|
|
438
|
-
throw new
|
|
494
|
+
throw new VibeError7({
|
|
439
495
|
code: "VIBE_VALIDATION",
|
|
440
496
|
message: `unknown model "${model}"`,
|
|
441
497
|
meta: { model, known: [...new Set(meta.models.map((entry) => entry.name))] }
|
|
@@ -448,20 +504,20 @@ function getFieldMeta(params) {
|
|
|
448
504
|
const found = model.fieldByName.get(field);
|
|
449
505
|
if (found === undefined) {
|
|
450
506
|
if (model.computed !== null && model.computed.has(field)) {
|
|
451
|
-
throw new
|
|
507
|
+
throw new VibeError7({
|
|
452
508
|
code: "VIBE_VALIDATION",
|
|
453
509
|
message: `"${field}" on model "${model.name}" is a computed field \u2014 computed fields appear in results (select/omit) only, not in ${context}`,
|
|
454
510
|
meta: { model: model.name, field, context, computed: true }
|
|
455
511
|
});
|
|
456
512
|
}
|
|
457
513
|
if (model.relationByName.has(field)) {
|
|
458
|
-
throw new
|
|
514
|
+
throw new VibeError7({
|
|
459
515
|
code: "VIBE_VALIDATION",
|
|
460
516
|
message: `"${field}" on model "${model.name}" is a relation \u2014 not valid in ${context} here (relation writes use nested-write verbs, relation reads use select/include)`,
|
|
461
517
|
meta: { model: model.name, field, context }
|
|
462
518
|
});
|
|
463
519
|
}
|
|
464
|
-
throw new
|
|
520
|
+
throw new VibeError7({
|
|
465
521
|
code: "VIBE_VALIDATION",
|
|
466
522
|
message: `unknown field "${field}" on model "${model.name}" in ${context}`,
|
|
467
523
|
meta: { model: model.name, field, context }
|
|
@@ -471,8 +527,8 @@ function getFieldMeta(params) {
|
|
|
471
527
|
}
|
|
472
528
|
// packages/runtime/src/codecs.ts
|
|
473
529
|
import { JSON_TRANSPORT, projectionOutputName, parsePgArrayLiteral, toPgArrayLiteral } from "@vibeorm/sql";
|
|
474
|
-
import { VibeError as
|
|
475
|
-
import { DIALECT_CODECS, decodeIsNoop } from "@vibeorm/sql";
|
|
530
|
+
import { VibeError as VibeError8, isEnumType as isEnumType3 } from "@vibeorm/schema";
|
|
531
|
+
import { DIALECT_CODECS, decodeIsNoop, nativeEnumArrayParameter } from "@vibeorm/sql";
|
|
476
532
|
import {
|
|
477
533
|
DIALECT_CODECS as DIALECT_CODECS2,
|
|
478
534
|
MYSQL_CODECS,
|
|
@@ -500,7 +556,10 @@ function encodeValue(params) {
|
|
|
500
556
|
const codec = fieldCodec({ dialect, field });
|
|
501
557
|
if (field.isList && Array.isArray(value)) {
|
|
502
558
|
const elements = value.map((element) => element === null || element === undefined ? element : codec.encode(element));
|
|
503
|
-
|
|
559
|
+
if (!isPostgresEnumList({ dialect, field }))
|
|
560
|
+
return elements;
|
|
561
|
+
const literal = toPgArrayLiteral({ values: elements });
|
|
562
|
+
return field.enumSqlName === undefined ? literal : nativeEnumArrayParameter({ value: literal, type: field.enumSqlName });
|
|
504
563
|
}
|
|
505
564
|
return codec.encode(value);
|
|
506
565
|
}
|
|
@@ -533,7 +592,7 @@ function validateAtomicOperand(params) {
|
|
|
533
592
|
} else if (typeof value === "number" && Number.isFinite(value)) {
|
|
534
593
|
return value;
|
|
535
594
|
}
|
|
536
|
-
throw new
|
|
595
|
+
throw new VibeError8({
|
|
537
596
|
code: "VIBE_VALIDATION",
|
|
538
597
|
message: `Invalid arithmetic operand for ${field.scalarType} field "${field.name}"`,
|
|
539
598
|
meta: { field: field.name, value }
|
|
@@ -542,7 +601,7 @@ function validateAtomicOperand(params) {
|
|
|
542
601
|
function toRealNumber(params) {
|
|
543
602
|
const { field, value } = params;
|
|
544
603
|
const refuse = () => {
|
|
545
|
-
throw new
|
|
604
|
+
throw new VibeError8({
|
|
546
605
|
code: "VIBE_VALIDATION",
|
|
547
606
|
message: `"${String(value)}" is not a numeric value for the Decimal field "${field.name}"`,
|
|
548
607
|
meta: { field: field.name, value }
|
|
@@ -782,7 +841,7 @@ function positionalMaterializer(params) {
|
|
|
782
841
|
const output = projectionOutputName({ column });
|
|
783
842
|
const entry = plan.byColumn.get(output);
|
|
784
843
|
if (entry === undefined)
|
|
785
|
-
throw new
|
|
844
|
+
throw new VibeError8({ code: "VIBE_INTERNAL", message: "positional projection has no schema field", meta: { model: model.name, column: output } });
|
|
786
845
|
return entry;
|
|
787
846
|
});
|
|
788
847
|
const width = slots.length;
|
|
@@ -790,7 +849,7 @@ function positionalMaterializer(params) {
|
|
|
790
849
|
const chunked = width > chunkSize;
|
|
791
850
|
const count = Math.ceil(width / chunkSize);
|
|
792
851
|
const invalid = () => {
|
|
793
|
-
throw new
|
|
852
|
+
throw new VibeError8({ code: "VIBE_INTERNAL", message: "positional relation payload does not match its SQL projection", meta: { model: model.name, expectedColumns: width } });
|
|
794
853
|
};
|
|
795
854
|
if (width === 0 || new Set(slots.map((slot) => slot.name)).size !== width)
|
|
796
855
|
return invalid();
|
|
@@ -832,7 +891,7 @@ function decodeAggregateValue(params) {
|
|
|
832
891
|
return field === null ? value : decodeValue({ dialect, field, value });
|
|
833
892
|
}
|
|
834
893
|
// packages/runtime/src/lateral-projection.ts
|
|
835
|
-
import { VibeError as
|
|
894
|
+
import { VibeError as VibeError9, unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
|
|
836
895
|
function isPlainObject(value) {
|
|
837
896
|
return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
|
|
838
897
|
}
|
|
@@ -849,7 +908,7 @@ function lateralProjection(params) {
|
|
|
849
908
|
const columns = names.map((name) => {
|
|
850
909
|
const field = model.fieldByName.get(name);
|
|
851
910
|
if (field === undefined)
|
|
852
|
-
throw new
|
|
911
|
+
throw new VibeError9({ code: "VIBE_INTERNAL", message: "lateral projection references an unknown field", meta: { model: model.name, field: name } });
|
|
853
912
|
return Object.freeze(applyLateralTransform({ model, column: { table: LATERAL_CHILD_ALIAS, name: field.columnName } }));
|
|
854
913
|
});
|
|
855
914
|
const descriptor = Object.freeze({ columns: Object.freeze(columns), hiddenOrder: Object.freeze(hiddenOrder) });
|
|
@@ -898,7 +957,7 @@ function applyLateralTransform(params) {
|
|
|
898
957
|
|
|
899
958
|
// packages/runtime/src/query-builder.ts
|
|
900
959
|
import { isSqlFragment, mapConflictColumns } from "@vibeorm/sql";
|
|
901
|
-
import { VibeError as
|
|
960
|
+
import { VibeError as VibeError13, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
|
|
902
961
|
import {
|
|
903
962
|
SQL_DEFAULT_CELL,
|
|
904
963
|
containsPattern,
|
|
@@ -912,9 +971,9 @@ import {
|
|
|
912
971
|
import { describeRowLock } from "@vibeorm/sql";
|
|
913
972
|
|
|
914
973
|
// packages/runtime/src/bulk-upsert.ts
|
|
915
|
-
import { VibeError as
|
|
974
|
+
import { VibeError as VibeError10, unsupportedCapability as unsupportedCapability3 } from "@vibeorm/schema";
|
|
916
975
|
function validationError2(params) {
|
|
917
|
-
return new
|
|
976
|
+
return new VibeError10({
|
|
918
977
|
code: "VIBE_VALIDATION",
|
|
919
978
|
message: params.message,
|
|
920
979
|
...params.meta === undefined ? {} : { meta: params.meta }
|
|
@@ -1238,7 +1297,7 @@ function assertConflictKeysAreComparable(params) {
|
|
|
1238
1297
|
}
|
|
1239
1298
|
|
|
1240
1299
|
// packages/runtime/src/keyset.ts
|
|
1241
|
-
import { VibeError as
|
|
1300
|
+
import { VibeError as VibeError11 } from "@vibeorm/schema";
|
|
1242
1301
|
var KEYSET_TOKEN_VERSION = 1;
|
|
1243
1302
|
var KEYSET_TOKEN_PREFIX = "vk1.";
|
|
1244
1303
|
var KEYSET_MAX_PAGE_SIZE = 1e4;
|
|
@@ -1248,10 +1307,10 @@ var DATETIME_NEEDS_PRECISION_ASSERTION = Object.freeze({
|
|
|
1248
1307
|
sqlite: false
|
|
1249
1308
|
});
|
|
1250
1309
|
function keysetValidation(params) {
|
|
1251
|
-
return new
|
|
1310
|
+
return new VibeError11({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
|
|
1252
1311
|
}
|
|
1253
1312
|
function keysetUnsupported(params) {
|
|
1254
|
-
return new
|
|
1313
|
+
return new VibeError11({
|
|
1255
1314
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
1256
1315
|
message: params.message,
|
|
1257
1316
|
meta: params.meta
|
|
@@ -1371,7 +1430,7 @@ function compileKeysetOrderPlan(params) {
|
|
|
1371
1430
|
meta: { model: model.name, orderFields: [...seen], feature: "keysetTieBreaker" }
|
|
1372
1431
|
});
|
|
1373
1432
|
}
|
|
1374
|
-
return { model: model.name, keys, signature: signatureOf2({ model: model.name, keys }) };
|
|
1433
|
+
return { model: model.name, keys, signature: signatureOf2({ model: model.name, keys, ...model.namespace === undefined ? {} : { namespace: model.namespace, table: model.tableName } }) };
|
|
1375
1434
|
}
|
|
1376
1435
|
function signatureOf2(params) {
|
|
1377
1436
|
const { model, keys } = params;
|
|
@@ -1379,7 +1438,7 @@ function signatureOf2(params) {
|
|
|
1379
1438
|
const base = `${key.field.name}:${key.direction}`;
|
|
1380
1439
|
return key.field.isOptional ? `${base}:nulls=${key.nulls}` : base;
|
|
1381
1440
|
});
|
|
1382
|
-
return [model, ...parts].join("|");
|
|
1441
|
+
return [model, ...params.namespace === undefined ? [] : [`physical=${JSON.stringify([params.namespace, params.table])}`], ...parts].join("|");
|
|
1383
1442
|
}
|
|
1384
1443
|
function encodeValueFor(params) {
|
|
1385
1444
|
const { key, value, model } = params;
|
|
@@ -1634,9 +1693,9 @@ function decodeKeysetToken(params) {
|
|
|
1634
1693
|
}
|
|
1635
1694
|
|
|
1636
1695
|
// packages/runtime/src/relation-plan.ts
|
|
1637
|
-
import { VibeError as
|
|
1696
|
+
import { VibeError as VibeError12, implicitJoinTable, qualifiedSqlName, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
|
|
1638
1697
|
function validationError3(params) {
|
|
1639
|
-
return new
|
|
1698
|
+
return new VibeError12({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
|
|
1640
1699
|
}
|
|
1641
1700
|
function isPlainObject2(value) {
|
|
1642
1701
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
|
|
@@ -1661,7 +1720,7 @@ function keyFields(params) {
|
|
|
1661
1720
|
return names.map((name) => {
|
|
1662
1721
|
const field = model.fieldByName.get(name);
|
|
1663
1722
|
if (field === undefined) {
|
|
1664
|
-
throw new
|
|
1723
|
+
throw new VibeError12({
|
|
1665
1724
|
code: "VIBE_SCHEMA_INVALID",
|
|
1666
1725
|
message: `relation "${relation.name}" on ${relation.model} names unknown ${what} field "${name}"`,
|
|
1667
1726
|
meta: { model: relation.model, relation: relation.name }
|
|
@@ -1673,7 +1732,7 @@ function keyFields(params) {
|
|
|
1673
1732
|
function singleKeyPair(params) {
|
|
1674
1733
|
const { link, what } = params;
|
|
1675
1734
|
if (link.parentKeys.length !== 1 || link.childKeys.length !== 1) {
|
|
1676
|
-
throw new
|
|
1735
|
+
throw new VibeError12({
|
|
1677
1736
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
1678
1737
|
message: `${what} on relation "${link.relation.name}" of ${link.relation.model} needs a single-column relation key \u2014 this relation links ${link.parentKeys.length} columns; use an explicit junction model`,
|
|
1679
1738
|
meta: { model: link.relation.model, relation: link.relation.name, arity: link.parentKeys.length }
|
|
@@ -1717,12 +1776,15 @@ function resolveRelationLinkUncached(params) {
|
|
|
1717
1776
|
const target = getModelMeta({ meta, model: relation.targetModel });
|
|
1718
1777
|
if (relation.type === "manyToMany") {
|
|
1719
1778
|
if (relation.model === relation.targetModel) {
|
|
1720
|
-
throw new
|
|
1779
|
+
throw new VibeError12({
|
|
1721
1780
|
code: "VIBE_SCHEMA_INVALID",
|
|
1722
1781
|
message: `relation "${relation.name}" on ${relation.model} is an implicit self many-to-many: both sides own the ` + `same join-table column, so this field and its inverse would read the same rows. Model each direction ` + `with an explicit junction model.`,
|
|
1723
1782
|
meta: { model: relation.model, relation: relation.name, targetModel: relation.targetModel }
|
|
1724
1783
|
});
|
|
1725
1784
|
}
|
|
1785
|
+
const namespace = qualifiedSqlName({ name: model.tableName, namespace: model.namespace }).namespace;
|
|
1786
|
+
if (namespace !== qualifiedSqlName({ name: target.tableName, namespace: target.namespace }).namespace)
|
|
1787
|
+
throw unsupportedCapability4({ dialect: "postgres", feature: "implicitJoinNamespaces", hint: "Implicit join parents must share one physical namespace" });
|
|
1726
1788
|
const join = implicitJoinTable({
|
|
1727
1789
|
modelA: relation.model,
|
|
1728
1790
|
modelB: relation.targetModel,
|
|
@@ -1737,6 +1799,7 @@ function resolveRelationLinkUncached(params) {
|
|
|
1737
1799
|
childKeys: [singlePrimaryKey({ model: target, relation })],
|
|
1738
1800
|
join: {
|
|
1739
1801
|
tableName: join.tableName,
|
|
1802
|
+
...model.namespace === undefined && target.namespace === undefined ? {} : { namespace },
|
|
1740
1803
|
parentColumn: parentIsA ? "A" : "B",
|
|
1741
1804
|
childColumn: parentIsA ? "B" : "A"
|
|
1742
1805
|
}
|
|
@@ -1759,7 +1822,7 @@ function resolveRelationLinkUncached(params) {
|
|
|
1759
1822
|
}
|
|
1760
1823
|
const reverse = findReverseRelation({ relation, target });
|
|
1761
1824
|
if (reverse === null || reverse.fields === undefined || reverse.fields.length === 0) {
|
|
1762
|
-
throw new
|
|
1825
|
+
throw new VibeError12({
|
|
1763
1826
|
code: "VIBE_SCHEMA_INVALID",
|
|
1764
1827
|
message: `relation "${relation.name}" on ${relation.model} has no foreign-key counterpart on ${relation.targetModel}`,
|
|
1765
1828
|
meta: { model: relation.model, relation: relation.name, target: relation.targetModel }
|
|
@@ -1784,7 +1847,7 @@ function pairedKeys(params) {
|
|
|
1784
1847
|
const parentKeys = keyFields({ model, names: parentNames, relation, what: "fields" });
|
|
1785
1848
|
const childKeys = keyFields({ model: target, names: childNames, relation, what: "references" });
|
|
1786
1849
|
if (parentKeys.length !== childKeys.length) {
|
|
1787
|
-
throw new
|
|
1850
|
+
throw new VibeError12({
|
|
1788
1851
|
code: "VIBE_SCHEMA_INVALID",
|
|
1789
1852
|
message: `relation "${relation.name}" on ${relation.model} links ${parentKeys.length} field(s) to ${childKeys.length} reference(s) \u2014 a foreign key must pair every column`,
|
|
1790
1853
|
meta: { model: relation.model, relation: relation.name }
|
|
@@ -2134,7 +2197,7 @@ var AGG_FN_BY_KEY = {
|
|
|
2134
2197
|
_max: "max"
|
|
2135
2198
|
};
|
|
2136
2199
|
function validationError4(params) {
|
|
2137
|
-
return new
|
|
2200
|
+
return new VibeError13({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
|
|
2138
2201
|
}
|
|
2139
2202
|
function isPlainObject3(value) {
|
|
2140
2203
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof Uint8Array);
|
|
@@ -2238,21 +2301,21 @@ function assertLockIsExpressible(params) {
|
|
|
2238
2301
|
if (rowLockStrengths.length === 0) {
|
|
2239
2302
|
if (lock.strength === "update" && lock.wait === "wait")
|
|
2240
2303
|
return;
|
|
2241
|
-
throw
|
|
2304
|
+
throw unsupportedCapability5({
|
|
2242
2305
|
dialect: dialect.name,
|
|
2243
2306
|
feature: site,
|
|
2244
2307
|
hint: `${dialect.name} has no locking-read clause at all. Only lock: "update" is accepted there, ` + `as the documented no-op its single-writer transactions already provide`
|
|
2245
2308
|
});
|
|
2246
2309
|
}
|
|
2247
2310
|
if (!rowLockStrengths.includes(lock.strength)) {
|
|
2248
|
-
throw
|
|
2311
|
+
throw unsupportedCapability5({
|
|
2249
2312
|
dialect: dialect.name,
|
|
2250
2313
|
feature: site,
|
|
2251
2314
|
hint: `${dialect.name} has these lock strengths: ${rowLockStrengths.join(", ")}`
|
|
2252
2315
|
});
|
|
2253
2316
|
}
|
|
2254
2317
|
if (!rowLockWaitPolicies.includes(lock.wait)) {
|
|
2255
|
-
throw
|
|
2318
|
+
throw unsupportedCapability5({
|
|
2256
2319
|
dialect: dialect.name,
|
|
2257
2320
|
feature: site,
|
|
2258
2321
|
hint: `${dialect.name} has these lock wait policies: ${rowLockWaitPolicies.join(", ")}`
|
|
@@ -2262,7 +2325,7 @@ function assertLockIsExpressible(params) {
|
|
|
2262
2325
|
function compileConflictTarget(params) {
|
|
2263
2326
|
const { dialect, meta, model, method, target, where } = params;
|
|
2264
2327
|
if ((target !== undefined || where !== undefined) && dialect.doNothingForm === "insertIgnore") {
|
|
2265
|
-
throw
|
|
2328
|
+
throw unsupportedCapability5({
|
|
2266
2329
|
dialect: dialect.name,
|
|
2267
2330
|
feature: `a conflict target on ${model.clientName}.${method}()`,
|
|
2268
2331
|
hint: "mysql's INSERT IGNORE / ON DUPLICATE KEY fire on ANY duplicate key \u2014 no target can be named; gate the call per dialect"
|
|
@@ -2280,7 +2343,7 @@ function compileConflictTarget(params) {
|
|
|
2280
2343
|
out.columns = target.map((name) => getFieldMeta({ model, field: String(name), context: "onConflict target" }).columnName);
|
|
2281
2344
|
} else if (isPlainObject3(target) && typeof target.constraint === "string" && target.constraint.length > 0 && Object.keys(target).length === 1) {
|
|
2282
2345
|
if (!dialect.capabilities.conflictTargetConstraint) {
|
|
2283
|
-
throw
|
|
2346
|
+
throw unsupportedCapability5({
|
|
2284
2347
|
dialect: dialect.name,
|
|
2285
2348
|
feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
|
|
2286
2349
|
hint: "only postgres supports ON CONSTRAINT targets \u2014 name the indexed columns instead"
|
|
@@ -2302,7 +2365,7 @@ function compileConflictTarget(params) {
|
|
|
2302
2365
|
});
|
|
2303
2366
|
}
|
|
2304
2367
|
if (!dialect.capabilities.partialIndexes) {
|
|
2305
|
-
throw
|
|
2368
|
+
throw unsupportedCapability5({
|
|
2306
2369
|
dialect: dialect.name,
|
|
2307
2370
|
feature: "a partial-index conflict target",
|
|
2308
2371
|
hint: "this dialect has no partial indexes to target"
|
|
@@ -2388,7 +2451,7 @@ function assertListFilterable(params) {
|
|
|
2388
2451
|
const { dialect, model, field, operator } = params;
|
|
2389
2452
|
if (dialect.capabilities.scalarArrays)
|
|
2390
2453
|
return;
|
|
2391
|
-
throw
|
|
2454
|
+
throw unsupportedCapability5({
|
|
2392
2455
|
dialect: dialect.name,
|
|
2393
2456
|
feature: `scalar list filter "${operator}" on ${model.name}.${field.name}`,
|
|
2394
2457
|
hint: "only postgres has native array columns \u2014 model the list as a related table instead"
|
|
@@ -2398,7 +2461,7 @@ function assertListWritable(params) {
|
|
|
2398
2461
|
const { dialect, model, field } = params;
|
|
2399
2462
|
if (!field.isList || dialect.capabilities.scalarArrays)
|
|
2400
2463
|
return;
|
|
2401
|
-
throw
|
|
2464
|
+
throw unsupportedCapability5({
|
|
2402
2465
|
dialect: dialect.name,
|
|
2403
2466
|
feature: `writing the scalar list ${model.name}.${field.name}`,
|
|
2404
2467
|
hint: "only postgres has native array columns \u2014 model the list as a related table instead"
|
|
@@ -2515,7 +2578,7 @@ function compileJsonFieldFilter(params) {
|
|
|
2515
2578
|
const requireOp = (op) => {
|
|
2516
2579
|
if (dialect.supportedJsonOps.includes(op))
|
|
2517
2580
|
return;
|
|
2518
|
-
throw
|
|
2581
|
+
throw unsupportedCapability5({
|
|
2519
2582
|
dialect: dialect.name,
|
|
2520
2583
|
feature: `json filter "${op}" on ${model.name}.${field.name}`,
|
|
2521
2584
|
hint: `this dialect can express: ${dialect.supportedJsonOps.join(", ")}`
|
|
@@ -2836,7 +2899,7 @@ function buildRelationExists(params) {
|
|
|
2836
2899
|
kind: "exists",
|
|
2837
2900
|
select: {
|
|
2838
2901
|
kind: "select",
|
|
2839
|
-
table: { name: target.tableName, alias: childAlias },
|
|
2902
|
+
table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace }, alias: childAlias },
|
|
2840
2903
|
columns: [],
|
|
2841
2904
|
selectExpr: { kind: "one" },
|
|
2842
2905
|
where: correlated({
|
|
@@ -2852,7 +2915,7 @@ function buildRelationExists(params) {
|
|
|
2852
2915
|
...negate ? { negate: true } : {},
|
|
2853
2916
|
select: {
|
|
2854
2917
|
kind: "select",
|
|
2855
|
-
table: { name: join.tableName, alias: jtAlias },
|
|
2918
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: jtAlias },
|
|
2856
2919
|
columns: [],
|
|
2857
2920
|
selectExpr: { kind: "one" },
|
|
2858
2921
|
where: {
|
|
@@ -2875,7 +2938,7 @@ function buildRelationExists(params) {
|
|
|
2875
2938
|
...negate ? { negate: true } : {},
|
|
2876
2939
|
select: {
|
|
2877
2940
|
kind: "select",
|
|
2878
|
-
table: { name: target.tableName, alias: childAlias },
|
|
2941
|
+
table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace }, alias: childAlias },
|
|
2879
2942
|
columns: [],
|
|
2880
2943
|
selectExpr: { kind: "one" },
|
|
2881
2944
|
where: correlated(correlateLink({ link, childTable: childAlias, outerTable: outer }))
|
|
@@ -3149,7 +3212,7 @@ function compileRelationOrderTerms(params) {
|
|
|
3149
3212
|
const alias = `__ord${++aliasSeq.n}`;
|
|
3150
3213
|
const select = link.kind === "manyToMany" ? {
|
|
3151
3214
|
kind: "select",
|
|
3152
|
-
table: { name: link.join.tableName, alias },
|
|
3215
|
+
table: { name: link.join.tableName, ...link.join?.namespace === undefined ? {} : { namespace: link.join.namespace }, alias },
|
|
3153
3216
|
columns: [],
|
|
3154
3217
|
selectExpr: { kind: "countAll" },
|
|
3155
3218
|
where: {
|
|
@@ -3163,7 +3226,7 @@ function compileRelationOrderTerms(params) {
|
|
|
3163
3226
|
}
|
|
3164
3227
|
} : {
|
|
3165
3228
|
kind: "select",
|
|
3166
|
-
table: { name: link.target.tableName, alias },
|
|
3229
|
+
table: { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias },
|
|
3167
3230
|
columns: [],
|
|
3168
3231
|
selectExpr: { kind: "countAll" },
|
|
3169
3232
|
where: correlateLink({ link, childTable: alias, outerTable: outer })
|
|
@@ -3183,7 +3246,7 @@ function compileRelationOrderTerms(params) {
|
|
|
3183
3246
|
terms.push({
|
|
3184
3247
|
select: {
|
|
3185
3248
|
kind: "select",
|
|
3186
|
-
table: { name: link.target.tableName, alias },
|
|
3249
|
+
table: { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias },
|
|
3187
3250
|
columns: [compareColumnRef({ dialect, field, table: alias })],
|
|
3188
3251
|
where: correlateLink({ link, childTable: alias, outerTable: outer })
|
|
3189
3252
|
},
|
|
@@ -3737,7 +3800,7 @@ function parseCursor(params) {
|
|
|
3737
3800
|
function keysetFieldOfTerm(params) {
|
|
3738
3801
|
const { dialect, model, term } = params;
|
|
3739
3802
|
if (!("column" in term)) {
|
|
3740
|
-
throw
|
|
3803
|
+
throw unsupportedCapability5({
|
|
3741
3804
|
dialect: dialect.name,
|
|
3742
3805
|
feature: `keyset pagination over a relation or aggregate orderBy on model "${model.name}"`,
|
|
3743
3806
|
hint: "order by scalar columns plus a unique tie-breaker; a correlated subquery value is not on the row, so no position can describe it"
|
|
@@ -3745,7 +3808,7 @@ function keysetFieldOfTerm(params) {
|
|
|
3745
3808
|
}
|
|
3746
3809
|
const field = model.fieldByColumn.get(term.column.name);
|
|
3747
3810
|
if (field === undefined) {
|
|
3748
|
-
throw
|
|
3811
|
+
throw unsupportedCapability5({
|
|
3749
3812
|
dialect: dialect.name,
|
|
3750
3813
|
feature: `keyset pagination over a computed order key on model "${model.name}"`,
|
|
3751
3814
|
hint: "order by scalar columns plus a unique tie-breaker"
|
|
@@ -4125,7 +4188,7 @@ function buildFindShape(params) {
|
|
|
4125
4188
|
const outerOrder = distinctOuterOrder ?? arranged.slice(0, distinctLeadCount);
|
|
4126
4189
|
const inner = {
|
|
4127
4190
|
kind: "select",
|
|
4128
|
-
table: { name: model.tableName },
|
|
4191
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4129
4192
|
columns: withOuterOrderKeys(columns, outerOrder),
|
|
4130
4193
|
rowNumber: {
|
|
4131
4194
|
partitionBy: distinctPartition,
|
|
@@ -4149,7 +4212,7 @@ function buildFindShape(params) {
|
|
|
4149
4212
|
if (distinctOuterOrder !== null) {
|
|
4150
4213
|
const inner = {
|
|
4151
4214
|
kind: "select",
|
|
4152
|
-
table: { name: model.tableName },
|
|
4215
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4153
4216
|
columns: withOuterOrderKeys(columns, distinctOuterOrder),
|
|
4154
4217
|
...lateralJoins.length > 0 ? { lateralJoins } : {},
|
|
4155
4218
|
...where === undefined ? {} : { where },
|
|
@@ -4177,7 +4240,7 @@ function buildFindShape(params) {
|
|
|
4177
4240
|
const innerColumns = withOuterOrderKeys(withKeyColumns(projected, correlationKeys), orderTerms);
|
|
4178
4241
|
const inner = {
|
|
4179
4242
|
kind: "select",
|
|
4180
|
-
table: { name: model.tableName },
|
|
4243
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4181
4244
|
columns: innerColumns,
|
|
4182
4245
|
...where === undefined ? {} : { where },
|
|
4183
4246
|
...distinctOn === undefined ? {} : { distinctOn },
|
|
@@ -4187,7 +4250,7 @@ function buildFindShape(params) {
|
|
|
4187
4250
|
};
|
|
4188
4251
|
const statement = {
|
|
4189
4252
|
kind: "select",
|
|
4190
|
-
table: { name: model.tableName },
|
|
4253
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4191
4254
|
columns,
|
|
4192
4255
|
fromSelect: inner,
|
|
4193
4256
|
lateralJoins,
|
|
@@ -4197,7 +4260,7 @@ function buildFindShape(params) {
|
|
|
4197
4260
|
}
|
|
4198
4261
|
const statement = {
|
|
4199
4262
|
kind: "select",
|
|
4200
|
-
table: { name: model.tableName },
|
|
4263
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4201
4264
|
columns,
|
|
4202
4265
|
...lateralJoins.length > 0 ? { lateralJoins } : {},
|
|
4203
4266
|
...where === undefined ? {} : { where },
|
|
@@ -4241,12 +4304,12 @@ function buildLateralCount(params) {
|
|
|
4241
4304
|
};
|
|
4242
4305
|
select = {
|
|
4243
4306
|
kind: "select",
|
|
4244
|
-
table: filter === undefined ? { name: join.tableName, alias: joinAlias } : { name: link.target.tableName, alias: childAlias },
|
|
4307
|
+
table: filter === undefined ? { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: joinAlias } : { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias: childAlias },
|
|
4245
4308
|
columns: [],
|
|
4246
4309
|
selectExpr: { kind: "countAll", alias: columnAlias },
|
|
4247
4310
|
where: filter === undefined ? correlation : { kind: "and", operands: [correlation, filter] },
|
|
4248
4311
|
...filter === undefined ? {} : { innerJoins: [{
|
|
4249
|
-
table: { name: join.tableName, alias: joinAlias },
|
|
4312
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: joinAlias },
|
|
4250
4313
|
on: [{ left: { table: joinAlias, name: join.childColumn }, right: { table: childAlias, name: pair.child.columnName } }]
|
|
4251
4314
|
}] }
|
|
4252
4315
|
};
|
|
@@ -4254,7 +4317,7 @@ function buildLateralCount(params) {
|
|
|
4254
4317
|
const correlation = correlateLink({ link, childTable: childAlias, outerTable: model.tableName });
|
|
4255
4318
|
select = {
|
|
4256
4319
|
kind: "select",
|
|
4257
|
-
table: { name: link.target.tableName, alias: childAlias },
|
|
4320
|
+
table: { name: link.target.tableName, ...link.target.namespace === undefined ? {} : { namespace: link.target.namespace }, alias: childAlias },
|
|
4258
4321
|
columns: [],
|
|
4259
4322
|
selectExpr: { kind: "countAll", alias: columnAlias },
|
|
4260
4323
|
where: filter === undefined ? correlation : { kind: "and", operands: [correlation, filter] }
|
|
@@ -4277,7 +4340,7 @@ function buildLateralJoinClause(params) {
|
|
|
4277
4340
|
kind: "exists",
|
|
4278
4341
|
select: {
|
|
4279
4342
|
kind: "select",
|
|
4280
|
-
table: { name: join.tableName, alias: jtAlias },
|
|
4343
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: jtAlias },
|
|
4281
4344
|
columns: [],
|
|
4282
4345
|
selectExpr: { kind: "one" },
|
|
4283
4346
|
where: {
|
|
@@ -4329,7 +4392,7 @@ function buildLateralJoinClause(params) {
|
|
|
4329
4392
|
rowFormat: "positional",
|
|
4330
4393
|
select: {
|
|
4331
4394
|
kind: "select",
|
|
4332
|
-
table: { name: target.tableName, alias: LATERAL_CHILD_ALIAS },
|
|
4395
|
+
table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace }, alias: LATERAL_CHILD_ALIAS },
|
|
4333
4396
|
columns,
|
|
4334
4397
|
where,
|
|
4335
4398
|
...orderBy === undefined || orderBy.length === 0 ? {} : { orderBy },
|
|
@@ -4685,7 +4748,7 @@ function resolveStrategy(params) {
|
|
|
4685
4748
|
const strategy = explicit ?? defaultRelationStrategy ?? "query";
|
|
4686
4749
|
if (strategy === "join" && !dialect.capabilities.lateralJoin) {
|
|
4687
4750
|
if (explicit !== undefined || hasRelations) {
|
|
4688
|
-
throw
|
|
4751
|
+
throw unsupportedCapability5({
|
|
4689
4752
|
dialect: dialect.name,
|
|
4690
4753
|
feature: 'relationStrategy "join"',
|
|
4691
4754
|
hint: 'lateral joins are postgres-only \u2014 use the portable "query" strategy on this dialect'
|
|
@@ -4856,7 +4919,7 @@ function buildQuery(params) {
|
|
|
4856
4919
|
const bounded = countTake !== undefined || countSkip !== undefined;
|
|
4857
4920
|
const boundedInner = (innerFields) => ({
|
|
4858
4921
|
kind: "select",
|
|
4859
|
-
table: { name: model.tableName },
|
|
4922
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4860
4923
|
columns: projectionColumns({ model, selectedFields: innerFields }),
|
|
4861
4924
|
...where === undefined ? {} : { where },
|
|
4862
4925
|
...countOrder === undefined || countOrder.length === 0 ? {} : { orderBy: countOrder },
|
|
@@ -4915,7 +4978,7 @@ function buildQuery(params) {
|
|
|
4915
4978
|
aggregateSpec: { selections, countShorthand: false },
|
|
4916
4979
|
statement: {
|
|
4917
4980
|
kind: "select",
|
|
4918
|
-
table: { name: model.tableName },
|
|
4981
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4919
4982
|
columns: [],
|
|
4920
4983
|
aggregates: aggSelects,
|
|
4921
4984
|
...where === undefined ? {} : { where }
|
|
@@ -4940,7 +5003,7 @@ function buildQuery(params) {
|
|
|
4940
5003
|
countAlias: COUNT_ALIAS,
|
|
4941
5004
|
statement: {
|
|
4942
5005
|
kind: "select",
|
|
4943
|
-
table: { name: model.tableName },
|
|
5006
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4944
5007
|
columns: [],
|
|
4945
5008
|
selectExpr: { kind: "countAll", alias: COUNT_ALIAS },
|
|
4946
5009
|
...where === undefined ? {} : { where }
|
|
@@ -4960,7 +5023,7 @@ function buildQuery(params) {
|
|
|
4960
5023
|
aggregateSpec: spec,
|
|
4961
5024
|
statement: {
|
|
4962
5025
|
kind: "select",
|
|
4963
|
-
table: { name: model.tableName },
|
|
5026
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4964
5027
|
columns: [],
|
|
4965
5028
|
aggregates: aggSelects,
|
|
4966
5029
|
...where === undefined ? {} : { where }
|
|
@@ -4970,7 +5033,7 @@ function buildQuery(params) {
|
|
|
4970
5033
|
const innerFields = referenced.length > 0 ? referenced : model.primaryKey.map((field) => field.name);
|
|
4971
5034
|
const inner = {
|
|
4972
5035
|
kind: "select",
|
|
4973
|
-
table: { name: model.tableName },
|
|
5036
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
4974
5037
|
columns: projectionColumns({ model, selectedFields: innerFields }),
|
|
4975
5038
|
...where === undefined ? {} : { where },
|
|
4976
5039
|
...orderBy === undefined || orderBy.length === 0 ? {} : { orderBy },
|
|
@@ -5023,7 +5086,7 @@ function buildQuery(params) {
|
|
|
5023
5086
|
groupByFields: byFields.map((field) => field.name),
|
|
5024
5087
|
statement: {
|
|
5025
5088
|
kind: "select",
|
|
5026
|
-
table: { name: model.tableName },
|
|
5089
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
5027
5090
|
columns: byColumns,
|
|
5028
5091
|
...aggSelects.length === 0 ? {} : { aggregates: aggSelects },
|
|
5029
5092
|
...where === undefined ? {} : { where },
|
|
@@ -5065,7 +5128,7 @@ function buildQuery(params) {
|
|
|
5065
5128
|
throw validationError4({ message: "DO NOTHING cannot carry update expressions" });
|
|
5066
5129
|
if (spec.action === "update") {
|
|
5067
5130
|
if (!dialect.capabilities.returning)
|
|
5068
|
-
throw
|
|
5131
|
+
throw unsupportedCapability5({ dialect: dialect.name, feature: "create onConflict update returning", hint: "use upsertMany for a count-only conflict update" });
|
|
5069
5132
|
if (compiled.columns === undefined && compiled.constraint === undefined)
|
|
5070
5133
|
throw validationError4({ message: "A conflict update requires an explicit target" });
|
|
5071
5134
|
const updates = requireObject({ value: spec.update, what: "onConflict.update", model });
|
|
@@ -5103,7 +5166,7 @@ function buildQuery(params) {
|
|
|
5103
5166
|
refetchWhere: row.knownKey,
|
|
5104
5167
|
statement: {
|
|
5105
5168
|
kind: "insert",
|
|
5106
|
-
table: { name: model.tableName },
|
|
5169
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
5107
5170
|
columns,
|
|
5108
5171
|
rows: [columns.map((column) => row.values[column])],
|
|
5109
5172
|
...conflictClause === undefined ? {} : { onConflict: conflictClause },
|
|
@@ -5114,7 +5177,7 @@ function buildQuery(params) {
|
|
|
5114
5177
|
case "createMany":
|
|
5115
5178
|
case "createManyAndReturn": {
|
|
5116
5179
|
if (method === "createManyAndReturn" && !dialect.capabilities.createManyAndReturn) {
|
|
5117
|
-
throw
|
|
5180
|
+
throw unsupportedCapability5({
|
|
5118
5181
|
dialect: dialect.name,
|
|
5119
5182
|
feature: "createManyAndReturn",
|
|
5120
5183
|
hint: "this dialect cannot RETURNING multiple inserted rows \u2014 use createMany then findMany"
|
|
@@ -5151,7 +5214,7 @@ function buildQuery(params) {
|
|
|
5151
5214
|
}
|
|
5152
5215
|
const statements = groups.map((group) => ({
|
|
5153
5216
|
kind: "insert",
|
|
5154
|
-
table: { name: model.tableName },
|
|
5217
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
5155
5218
|
columns: group.columns,
|
|
5156
5219
|
rows: group.rows,
|
|
5157
5220
|
...manyConflict === undefined ? {} : { onConflict: manyConflict },
|
|
@@ -5237,7 +5300,7 @@ function buildQuery(params) {
|
|
|
5237
5300
|
};
|
|
5238
5301
|
const upsertStatements = upsertGroups.map((group) => ({
|
|
5239
5302
|
kind: "insert",
|
|
5240
|
-
table: { name: model.tableName },
|
|
5303
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
5241
5304
|
columns: group.columns,
|
|
5242
5305
|
rows: group.rows,
|
|
5243
5306
|
onConflict
|
|
@@ -5254,7 +5317,7 @@ function buildQuery(params) {
|
|
|
5254
5317
|
case "updateManyAndReturn": {
|
|
5255
5318
|
const isUnique = method === "update";
|
|
5256
5319
|
if (method === "updateManyAndReturn" && !dialect.capabilities.returning) {
|
|
5257
|
-
throw
|
|
5320
|
+
throw unsupportedCapability5({
|
|
5258
5321
|
dialect: dialect.name,
|
|
5259
5322
|
feature: "updateManyAndReturn",
|
|
5260
5323
|
hint: "this dialect has no RETURNING \u2014 use updateMany then findMany, accepting that the read is a separate, unprotected statement"
|
|
@@ -5276,7 +5339,7 @@ function buildQuery(params) {
|
|
|
5276
5339
|
refetchWhere: isUnique ? uniqueRefetchWhere({ model, where, data: args.data }) : null,
|
|
5277
5340
|
statement: {
|
|
5278
5341
|
kind: "update",
|
|
5279
|
-
table: { name: model.tableName },
|
|
5342
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
5280
5343
|
set: compileUpdateSet({
|
|
5281
5344
|
dialect,
|
|
5282
5345
|
model,
|
|
@@ -5299,7 +5362,7 @@ function buildQuery(params) {
|
|
|
5299
5362
|
});
|
|
5300
5363
|
}
|
|
5301
5364
|
if (!dialect.capabilities.conflictTargetConstraint) {
|
|
5302
|
-
throw
|
|
5365
|
+
throw unsupportedCapability5({
|
|
5303
5366
|
dialect: dialect.name,
|
|
5304
5367
|
feature: "a named-constraint conflict target on upsert",
|
|
5305
5368
|
hint: "only postgres supports ON CONFLICT ON CONSTRAINT \u2014 rely on the where-derived column target instead"
|
|
@@ -5317,7 +5380,7 @@ function buildQuery(params) {
|
|
|
5317
5380
|
const targetFields = conflictTargetGroup({ model, where }).fields;
|
|
5318
5381
|
for (const field of targetFields) {
|
|
5319
5382
|
if (!(field.columnName in row.values)) {
|
|
5320
|
-
throw new
|
|
5383
|
+
throw new VibeError13({
|
|
5321
5384
|
code: "VIBE_INTERNAL",
|
|
5322
5385
|
message: `upsert on ${model.name}: create data does not bind conflict-target column "${field.columnName}" \u2014 this shape must run the find-then-write fallback flow`,
|
|
5323
5386
|
meta: { model: model.name, column: field.columnName }
|
|
@@ -5328,7 +5391,7 @@ function buildQuery(params) {
|
|
|
5328
5391
|
for (const [key, value] of Object.entries(where)) {
|
|
5329
5392
|
if (value === undefined || nativeTargetNames.has(key))
|
|
5330
5393
|
continue;
|
|
5331
|
-
throw new
|
|
5394
|
+
throw new VibeError13({
|
|
5332
5395
|
code: "VIBE_INTERNAL",
|
|
5333
5396
|
message: `upsert on ${model.name}: where field "${key}" is not part of the conflict target \u2014 guarded upserts must run the find-then-write fallback flow`,
|
|
5334
5397
|
meta: { model: model.name, field: key }
|
|
@@ -5343,7 +5406,7 @@ function buildQuery(params) {
|
|
|
5343
5406
|
refetchWhereBase: { ...where },
|
|
5344
5407
|
statement: {
|
|
5345
5408
|
kind: "insert",
|
|
5346
|
-
table: { name: model.tableName },
|
|
5409
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
5347
5410
|
columns,
|
|
5348
5411
|
rows: [columns.map((column) => row.values[column])],
|
|
5349
5412
|
onConflict: {
|
|
@@ -5369,7 +5432,7 @@ function buildQuery(params) {
|
|
|
5369
5432
|
refetchWhere: isUnique ? where : null,
|
|
5370
5433
|
statement: {
|
|
5371
5434
|
kind: "delete",
|
|
5372
|
-
table: { name: model.tableName },
|
|
5435
|
+
table: { name: model.tableName, ...model.namespace === undefined ? {} : { namespace: model.namespace } },
|
|
5373
5436
|
...compiled === undefined ? {} : { where: compiled },
|
|
5374
5437
|
...isUnique ? { returning: returningColumns({ model, selectedFields }) } : {}
|
|
5375
5438
|
}
|
|
@@ -5381,7 +5444,7 @@ function buildQuery(params) {
|
|
|
5381
5444
|
import { getSqlDialect, renderStatement } from "@vibeorm/sql";
|
|
5382
5445
|
|
|
5383
5446
|
// packages/runtime/src/extensions.ts
|
|
5384
|
-
import { VibeError as
|
|
5447
|
+
import { VibeError as VibeError14, extensionManifestEntry } from "@vibeorm/schema";
|
|
5385
5448
|
function assertExtensionManifest(params) {
|
|
5386
5449
|
const { manifest } = params;
|
|
5387
5450
|
const instances = params.instances ?? [];
|
|
@@ -5404,7 +5467,7 @@ function assertExtensionManifest(params) {
|
|
|
5404
5467
|
problems.push(`"${name}" is configured but missing from the generated client`);
|
|
5405
5468
|
}
|
|
5406
5469
|
if (problems.length > 0) {
|
|
5407
|
-
throw new
|
|
5470
|
+
throw new VibeError14({
|
|
5408
5471
|
code: "VIBE_STALE_CLIENT",
|
|
5409
5472
|
message: `extension list changed since generate; run vibeorm generate \u2014 ${problems.join("; ")}`,
|
|
5410
5473
|
meta: { manifest, problems }
|
|
@@ -5419,7 +5482,7 @@ function buildExtensionOperatorMap(params) {
|
|
|
5419
5482
|
for (const operator of extension.sql?.whereOperators ?? []) {
|
|
5420
5483
|
const existing = owner.get(operator.name);
|
|
5421
5484
|
if (existing !== undefined) {
|
|
5422
|
-
throw new
|
|
5485
|
+
throw new VibeError14({
|
|
5423
5486
|
code: "VIBE_CONFIG",
|
|
5424
5487
|
message: `where operator "${operator.name}" is claimed by both "${existing}" and "${extension.name}"`,
|
|
5425
5488
|
meta: { operator: operator.name }
|
|
@@ -5435,7 +5498,7 @@ function buildExtensionOperatorMap(params) {
|
|
|
5435
5498
|
options: extension.options
|
|
5436
5499
|
});
|
|
5437
5500
|
if ("error" in compiled) {
|
|
5438
|
-
throw new
|
|
5501
|
+
throw new VibeError14({
|
|
5439
5502
|
code: "VIBE_VALIDATION",
|
|
5440
5503
|
message: `"${operator.name}" on ${model}.${field}: ${compiled.error}`,
|
|
5441
5504
|
meta: { model, field, operator: operator.name, extension: extension.name }
|
|
@@ -5468,7 +5531,7 @@ function buildConnectHooks(params) {
|
|
|
5468
5531
|
}
|
|
5469
5532
|
|
|
5470
5533
|
// packages/runtime/src/relation-key.ts
|
|
5471
|
-
import { VibeError as
|
|
5534
|
+
import { VibeError as VibeError15 } from "@vibeorm/schema";
|
|
5472
5535
|
function relationValueKey(params) {
|
|
5473
5536
|
const { value } = params;
|
|
5474
5537
|
if (value === null || value === undefined)
|
|
@@ -5501,7 +5564,7 @@ function relationTupleKey(params) {
|
|
|
5501
5564
|
if (value === null || value === undefined)
|
|
5502
5565
|
return null;
|
|
5503
5566
|
if (typeof value === "object" && !(value instanceof Date) && !(value instanceof Uint8Array)) {
|
|
5504
|
-
throw new
|
|
5567
|
+
throw new VibeError15({
|
|
5505
5568
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
5506
5569
|
message: "a relation key of this type cannot be compared faithfully in memory \u2014 relation links support String, Int, BigInt, Boolean, DateTime and Bytes keys",
|
|
5507
5570
|
meta: { received: Object.prototype.toString.call(value) }
|
|
@@ -5527,7 +5590,7 @@ function assertWriteScope(params) {
|
|
|
5527
5590
|
}
|
|
5528
5591
|
|
|
5529
5592
|
// packages/runtime/src/nested-writes.ts
|
|
5530
|
-
import { VibeError as
|
|
5593
|
+
import { VibeError as VibeError16 } from "@vibeorm/schema";
|
|
5531
5594
|
function parentTupleOf(params) {
|
|
5532
5595
|
const { link, row } = params;
|
|
5533
5596
|
return link.parentKeys.map((field) => row[field.name]);
|
|
@@ -5574,10 +5637,10 @@ function detachAssignment(params) {
|
|
|
5574
5637
|
return out;
|
|
5575
5638
|
}
|
|
5576
5639
|
function validationError5(params) {
|
|
5577
|
-
return new
|
|
5640
|
+
return new VibeError16({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
|
|
5578
5641
|
}
|
|
5579
5642
|
function notFound(params) {
|
|
5580
|
-
return new
|
|
5643
|
+
return new VibeError16({ code: "VIBE_NOT_FOUND", message: params.message, meta: params.meta });
|
|
5581
5644
|
}
|
|
5582
5645
|
function isPlainObject4(value) {
|
|
5583
5646
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof Uint8Array);
|
|
@@ -5744,7 +5807,7 @@ async function insertJoinRows(params) {
|
|
|
5744
5807
|
await run.statement({
|
|
5745
5808
|
statement: {
|
|
5746
5809
|
kind: "insert",
|
|
5747
|
-
table: { name: join.tableName },
|
|
5810
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
|
|
5748
5811
|
columns: ["A", "B"],
|
|
5749
5812
|
rows: rows.slice(start, start + perChunk),
|
|
5750
5813
|
onConflict: { columns: ["A", "B"], doNothing: true }
|
|
@@ -5764,7 +5827,7 @@ async function deleteJoinRows(params) {
|
|
|
5764
5827
|
await run.statement({
|
|
5765
5828
|
statement: {
|
|
5766
5829
|
kind: "delete",
|
|
5767
|
-
table: { name: join.tableName },
|
|
5830
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
|
|
5768
5831
|
where: {
|
|
5769
5832
|
kind: "and",
|
|
5770
5833
|
operands: [
|
|
@@ -5813,7 +5876,7 @@ async function deleteJoinRowsForChildren(params) {
|
|
|
5813
5876
|
await run.statement({
|
|
5814
5877
|
statement: {
|
|
5815
5878
|
kind: "delete",
|
|
5816
|
-
table: { name: join.tableName },
|
|
5879
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
|
|
5817
5880
|
where: isSelf ? {
|
|
5818
5881
|
kind: "or",
|
|
5819
5882
|
operands: [
|
|
@@ -6193,7 +6256,7 @@ async function loadMemberKeys(params) {
|
|
|
6193
6256
|
const rows = await run.statement({
|
|
6194
6257
|
statement: {
|
|
6195
6258
|
kind: "select",
|
|
6196
|
-
table: { name: join.tableName },
|
|
6259
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace } },
|
|
6197
6260
|
columns: [{ name: join.childColumn }],
|
|
6198
6261
|
where: narrow === null ? parentMatch : {
|
|
6199
6262
|
kind: "and",
|
|
@@ -6794,7 +6857,7 @@ function previewOperation(params) {
|
|
|
6794
6857
|
};
|
|
6795
6858
|
}
|
|
6796
6859
|
// packages/runtime/src/diagnostics/plan.ts
|
|
6797
|
-
import { VibeError as
|
|
6860
|
+
import { VibeError as VibeError17, unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
|
|
6798
6861
|
import { NATIVE_RLS, getSqlDialect as getSqlDialect2, renderPostgresExplain, renderPostgresWorkload, renderStatement as renderStatement2 } from "@vibeorm/sql";
|
|
6799
6862
|
var PLAN_DEFAULTS = Object.freeze({ maxNodes: 200, maxConditionLength: 2000 });
|
|
6800
6863
|
var CONDITION_KEYS = [
|
|
@@ -6813,7 +6876,7 @@ var CONDITION_KEYS = [
|
|
|
6813
6876
|
"Output"
|
|
6814
6877
|
];
|
|
6815
6878
|
function planError(params) {
|
|
6816
|
-
return new
|
|
6879
|
+
return new VibeError17({ code: "VIBE_ADAPTER", message: params.message, meta: {} });
|
|
6817
6880
|
}
|
|
6818
6881
|
function asRecord(value) {
|
|
6819
6882
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
@@ -6846,14 +6909,14 @@ function parsePostgresPlan(params) {
|
|
|
6846
6909
|
const maxNodes = params.maxNodes ?? PLAN_DEFAULTS.maxNodes;
|
|
6847
6910
|
const includeLiterals = params.includeLiterals === true;
|
|
6848
6911
|
if (!Number.isInteger(maxNodes) || maxNodes < 1) {
|
|
6849
|
-
throw new
|
|
6912
|
+
throw new VibeError17({ code: "VIBE_CONFIG", message: `maxNodes must be a positive integer, got ${String(maxNodes)}`, meta: { maxNodes } });
|
|
6850
6913
|
}
|
|
6851
6914
|
let parsed = payload;
|
|
6852
6915
|
if (typeof payload === "string") {
|
|
6853
6916
|
try {
|
|
6854
6917
|
parsed = JSON.parse(payload);
|
|
6855
6918
|
} catch {
|
|
6856
|
-
throw new
|
|
6919
|
+
throw new VibeError17({
|
|
6857
6920
|
code: "VIBE_ADAPTER",
|
|
6858
6921
|
message: "EXPLAIN returned malformed JSON",
|
|
6859
6922
|
meta: { reason: "malformed-plan-json", mode }
|
|
@@ -6921,7 +6984,7 @@ function parsePostgresPlan(params) {
|
|
|
6921
6984
|
var WRITE_LEADERS = ["INSERT", "UPDATE", "DELETE", "MERGE", "TRUNCATE", "CREATE", "DROP", "ALTER", "GRANT", "REVOKE", "COPY", "CALL", "DO"];
|
|
6922
6985
|
var SIDE_EFFECT_CALLS = /\bpg_(?:try_)?advisory_(?:xact_)?lock(?:_shared)?\s*\(/i;
|
|
6923
6986
|
function refuse(params) {
|
|
6924
|
-
return new
|
|
6987
|
+
return new VibeError17({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta ?? {} });
|
|
6925
6988
|
}
|
|
6926
6989
|
function executableReadRefusal(params) {
|
|
6927
6990
|
const normalized = normalizeSql({ text: params.text });
|
|
@@ -6972,7 +7035,7 @@ async function readPlanContext(params) {
|
|
|
6972
7035
|
}
|
|
6973
7036
|
function requirePostgres(params) {
|
|
6974
7037
|
if (params.dialect !== "postgres") {
|
|
6975
|
-
throw
|
|
7038
|
+
throw unsupportedCapability6({
|
|
6976
7039
|
dialect: params.dialect,
|
|
6977
7040
|
feature: "query plan inspection",
|
|
6978
7041
|
hint: "plan inspection is PostgreSQL-shaped; operation tracing (telemetry) works on every dialect"
|
|
@@ -7051,7 +7114,7 @@ async function explainOnSession(params) {
|
|
|
7051
7114
|
const context = await readPlanContext({ executor, dialect, rlsContextKeys: contextKeys });
|
|
7052
7115
|
if (!context.representative) {
|
|
7053
7116
|
if (params.requireRepresentativeContext === true) {
|
|
7054
|
-
throw new
|
|
7117
|
+
throw new VibeError17({
|
|
7055
7118
|
code: "VIBE_RLS_CONTEXT",
|
|
7056
7119
|
message: `refusing to report a plan taken under a non-representative identity: ${context.reason ?? "role bypasses row policies"}`,
|
|
7057
7120
|
meta: { currentUser: context.currentUser, bypassRls: context.bypassRls, superuser: context.superuser }
|
|
@@ -7127,7 +7190,7 @@ async function explainOperation(params) {
|
|
|
7127
7190
|
});
|
|
7128
7191
|
}
|
|
7129
7192
|
// packages/runtime/src/diagnostics/statement-diagnostics.ts
|
|
7130
|
-
import { VibeError as
|
|
7193
|
+
import { VibeError as VibeError18 } from "@vibeorm/schema";
|
|
7131
7194
|
import { renderPostgresWorkload as renderPostgresWorkload2 } from "@vibeorm/sql";
|
|
7132
7195
|
var STATEMENT_DIAGNOSTICS_DEFAULTS = Object.freeze({
|
|
7133
7196
|
slowerThanMs: 0,
|
|
@@ -7139,7 +7202,7 @@ var STATEMENT_DIAGNOSTICS_DEFAULTS = Object.freeze({
|
|
|
7139
7202
|
});
|
|
7140
7203
|
var EXPLAIN_MODES = ["off", "estimate", "analyze"];
|
|
7141
7204
|
function configError(params) {
|
|
7142
|
-
return new
|
|
7205
|
+
return new VibeError18({ code: "VIBE_CONFIG", message: params.message, meta: params.meta ?? {} });
|
|
7143
7206
|
}
|
|
7144
7207
|
function isExplainMode(value) {
|
|
7145
7208
|
return typeof value === "string" && EXPLAIN_MODES.includes(value);
|
|
@@ -7265,7 +7328,7 @@ function summarizePlan(params) {
|
|
|
7265
7328
|
};
|
|
7266
7329
|
}
|
|
7267
7330
|
function errorCode(error) {
|
|
7268
|
-
return error instanceof
|
|
7331
|
+
return error instanceof VibeError18 ? error.code : "VIBE_INTERNAL";
|
|
7269
7332
|
}
|
|
7270
7333
|
function createStatementDiagnostics(params) {
|
|
7271
7334
|
const { config, adapter, dialect } = params;
|
|
@@ -7376,7 +7439,7 @@ function createStatementDiagnostics(params) {
|
|
|
7376
7439
|
};
|
|
7377
7440
|
}
|
|
7378
7441
|
// packages/runtime/src/diagnostics/workload.ts
|
|
7379
|
-
import { unsupportedCapability as
|
|
7442
|
+
import { unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
|
|
7380
7443
|
import { getSqlDialect as getSqlDialect3, renderPostgresWorkload as renderPostgresWorkload3 } from "@vibeorm/sql";
|
|
7381
7444
|
var STATEMENTS_INFO_MIN_VERSION = 140000;
|
|
7382
7445
|
var STATEMENTS_MIN_VERSION = 130000;
|
|
@@ -7409,7 +7472,7 @@ async function readAvailability(params) {
|
|
|
7409
7472
|
async function readWorkloadStatistics(params) {
|
|
7410
7473
|
const { executor } = params;
|
|
7411
7474
|
if (params.dialect !== "postgres") {
|
|
7412
|
-
throw
|
|
7475
|
+
throw unsupportedCapability7({
|
|
7413
7476
|
dialect: params.dialect,
|
|
7414
7477
|
feature: "workload statistics (pg_stat_statements)",
|
|
7415
7478
|
hint: "server workload statistics are PostgreSQL-only; operation telemetry works on every dialect"
|
|
@@ -7487,7 +7550,7 @@ async function readWorkloadStatistics(params) {
|
|
|
7487
7550
|
};
|
|
7488
7551
|
}
|
|
7489
7552
|
// packages/runtime/src/diagnostics/insight.ts
|
|
7490
|
-
import { VibeError as
|
|
7553
|
+
import { VibeError as VibeError19 } from "@vibeorm/schema";
|
|
7491
7554
|
var DIAGNOSTIC_THRESHOLDS = Object.freeze({
|
|
7492
7555
|
repeatThreshold: 5,
|
|
7493
7556
|
minRepeatThreshold: 2,
|
|
@@ -7505,7 +7568,7 @@ function bounded(params) {
|
|
|
7505
7568
|
if (value === undefined)
|
|
7506
7569
|
return fallback;
|
|
7507
7570
|
if (!Number.isInteger(value) || value < min || value > max) {
|
|
7508
|
-
throw new
|
|
7571
|
+
throw new VibeError19({
|
|
7509
7572
|
code: "VIBE_CONFIG",
|
|
7510
7573
|
message: `${name} must be an integer between ${min} and ${max}, got ${String(value)}`,
|
|
7511
7574
|
meta: { [name]: value }
|
|
@@ -7728,11 +7791,11 @@ function recommendFromPlan(params) {
|
|
|
7728
7791
|
return findings.slice(0, maxFindings);
|
|
7729
7792
|
}
|
|
7730
7793
|
// packages/runtime/src/relation-loader.ts
|
|
7731
|
-
import { VibeError as
|
|
7794
|
+
import { VibeError as VibeError21 } from "@vibeorm/schema";
|
|
7732
7795
|
import { renderStatement as renderStatement3 } from "@vibeorm/sql";
|
|
7733
7796
|
|
|
7734
7797
|
// packages/runtime/src/computed.ts
|
|
7735
|
-
import { VibeError as
|
|
7798
|
+
import { VibeError as VibeError20 } from "@vibeorm/schema";
|
|
7736
7799
|
function sameNeeds(a, b) {
|
|
7737
7800
|
if (a.length !== b.length)
|
|
7738
7801
|
return false;
|
|
@@ -7768,7 +7831,7 @@ function assertComputedManifest(params) {
|
|
|
7768
7831
|
problems.push(`"${key}" is configured but missing from the generated client`);
|
|
7769
7832
|
}
|
|
7770
7833
|
if (problems.length > 0) {
|
|
7771
|
-
throw new
|
|
7834
|
+
throw new VibeError20({
|
|
7772
7835
|
code: "VIBE_STALE_CLIENT",
|
|
7773
7836
|
message: `computed-field config changed since generate; run vibeorm generate \u2014 ${problems.join("; ")}`,
|
|
7774
7837
|
meta: { problems }
|
|
@@ -7796,7 +7859,7 @@ function resolveRelationConcurrency(params) {
|
|
|
7796
7859
|
if (concurrency === undefined)
|
|
7797
7860
|
return 1;
|
|
7798
7861
|
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
7799
|
-
throw new
|
|
7862
|
+
throw new VibeError21({
|
|
7800
7863
|
code: "VIBE_CONFIG",
|
|
7801
7864
|
message: `relationLoading.concurrency must be a positive integer \u2014 got ${String(concurrency)}`,
|
|
7802
7865
|
meta: { concurrency }
|
|
@@ -7944,7 +8007,7 @@ function buildChildStatement(params) {
|
|
|
7944
8007
|
if (window === undefined) {
|
|
7945
8008
|
return {
|
|
7946
8009
|
kind: "select",
|
|
7947
|
-
table: { name: target.tableName },
|
|
8010
|
+
table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace } },
|
|
7948
8011
|
columns,
|
|
7949
8012
|
where,
|
|
7950
8013
|
...orderBy === undefined || orderBy.length === 0 ? {} : { orderBy }
|
|
@@ -7952,7 +8015,7 @@ function buildChildStatement(params) {
|
|
|
7952
8015
|
}
|
|
7953
8016
|
const inner = {
|
|
7954
8017
|
kind: "select",
|
|
7955
|
-
table: { name: target.tableName },
|
|
8018
|
+
table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace } },
|
|
7956
8019
|
columns,
|
|
7957
8020
|
where,
|
|
7958
8021
|
rowNumber: { partitionBy: [...window.partitionBy], orderBy: orderBy ?? [], alias: WINDOW_ROW_ALIAS }
|
|
@@ -7981,7 +8044,7 @@ function chunkKeys(params) {
|
|
|
7981
8044
|
const rendered = renderStatement3({ dialect: ctx.dialect, statement: build(keys.slice(0, 1)) });
|
|
7982
8045
|
fixed = rendered.values.length - (expands ? arity : 1);
|
|
7983
8046
|
if (fixed + arity > budget) {
|
|
7984
|
-
throw new
|
|
8047
|
+
throw new VibeError21({
|
|
7985
8048
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
7986
8049
|
message: `relation "${relation}" needs ${fixed + arity} bound parameters for its own predicate, more than ${ctx.dialect.name}'s ${budget}-parameter statement budget \u2014 narrow the nested filter`,
|
|
7987
8050
|
meta: { relation, dialect: ctx.dialect.name, required: fixed + arity, budget }
|
|
@@ -8111,7 +8174,7 @@ async function loadManyToMany(params) {
|
|
|
8111
8174
|
const link = node.link;
|
|
8112
8175
|
const join = link.join;
|
|
8113
8176
|
if (join === null) {
|
|
8114
|
-
throw new
|
|
8177
|
+
throw new VibeError21({
|
|
8115
8178
|
code: "VIBE_INTERNAL",
|
|
8116
8179
|
message: `manyToMany relation "${node.name}" resolved without join-table wiring`
|
|
8117
8180
|
});
|
|
@@ -8156,11 +8219,11 @@ async function loadManyToMany(params) {
|
|
|
8156
8219
|
const where = nestedWhere === undefined ? membership : { kind: "and", operands: [membership, nestedWhere] };
|
|
8157
8220
|
const base = {
|
|
8158
8221
|
kind: "select",
|
|
8159
|
-
table: { name: target.tableName },
|
|
8222
|
+
table: { name: target.tableName, ...target.namespace === undefined ? {} : { namespace: target.namespace } },
|
|
8160
8223
|
columns: [...childColumns, { table: M2M_JOIN_ALIAS, name: join.parentColumn, alias: M2M_PARENT_ALIAS }],
|
|
8161
8224
|
innerJoins: [
|
|
8162
8225
|
{
|
|
8163
|
-
table: { name: join.tableName, alias: M2M_JOIN_ALIAS },
|
|
8226
|
+
table: { name: join.tableName, ...join.namespace === undefined ? {} : { namespace: join.namespace }, alias: M2M_JOIN_ALIAS },
|
|
8164
8227
|
on: [
|
|
8165
8228
|
{
|
|
8166
8229
|
left: { table: M2M_JOIN_ALIAS, name: join.childColumn },
|
|
@@ -8270,7 +8333,7 @@ async function loadCounts(params) {
|
|
|
8270
8333
|
const where = filter === undefined ? membership : { kind: "and", operands: [membership, filter] };
|
|
8271
8334
|
const base = {
|
|
8272
8335
|
kind: "select",
|
|
8273
|
-
table: { name: joinsChildTable ? target.tableName : table },
|
|
8336
|
+
table: { name: joinsChildTable ? target.tableName : table, ...(joinsChildTable || join === null ? target.namespace : join.namespace) === undefined ? {} : { namespace: joinsChildTable || join === null ? target.namespace : join.namespace } },
|
|
8274
8337
|
columns: projectedColumns,
|
|
8275
8338
|
selectExpr: { kind: "countAll", alias: COUNT_VALUE_ALIAS },
|
|
8276
8339
|
where,
|
|
@@ -8282,7 +8345,7 @@ async function loadCounts(params) {
|
|
|
8282
8345
|
...base,
|
|
8283
8346
|
innerJoins: [
|
|
8284
8347
|
{
|
|
8285
|
-
table: { name: join.tableName, alias: M2M_JOIN_ALIAS },
|
|
8348
|
+
table: { name: join.tableName, ...join?.namespace === undefined ? {} : { namespace: join.namespace }, alias: M2M_JOIN_ALIAS },
|
|
8286
8349
|
on: [
|
|
8287
8350
|
{
|
|
8288
8351
|
left: { table: M2M_JOIN_ALIAS, name: join.childColumn },
|
|
@@ -8408,7 +8471,7 @@ async function attachLateralRelations(params) {
|
|
|
8408
8471
|
try {
|
|
8409
8472
|
parsed = JSON.parse(raw);
|
|
8410
8473
|
} catch (cause) {
|
|
8411
|
-
throw new
|
|
8474
|
+
throw new VibeError21({
|
|
8412
8475
|
code: "VIBE_INTERNAL",
|
|
8413
8476
|
message: `relation column "${column}" returned text that is not valid JSON`,
|
|
8414
8477
|
meta: { relation: node.name },
|
|
@@ -8418,7 +8481,7 @@ async function attachLateralRelations(params) {
|
|
|
8418
8481
|
}
|
|
8419
8482
|
if (isList) {
|
|
8420
8483
|
if (!Array.isArray(parsed)) {
|
|
8421
|
-
throw new
|
|
8484
|
+
throw new VibeError21({ code: "VIBE_INTERNAL", message: "to-many relation payload must be an array", meta: { relation: node.name } });
|
|
8422
8485
|
}
|
|
8423
8486
|
const children = parsed.map(decodePosition);
|
|
8424
8487
|
for (const child of children) {
|
|
@@ -8459,7 +8522,7 @@ async function attachLateralRelations(params) {
|
|
|
8459
8522
|
const raw = row[column];
|
|
8460
8523
|
const count = typeof raw === "number" || typeof raw === "bigint" || typeof raw === "string" && /^\d+$/.test(raw) ? Number(raw) : NaN;
|
|
8461
8524
|
if (!Number.isSafeInteger(count) || count < 0) {
|
|
8462
|
-
throw new
|
|
8525
|
+
throw new VibeError21({ code: "VIBE_INTERNAL", message: "relation count payload must be a non-negative safe integer", meta: { relation: selection.counts[index]?.name } });
|
|
8463
8526
|
}
|
|
8464
8527
|
counts[selection.counts[index].name] = count;
|
|
8465
8528
|
delete row[column];
|
|
@@ -8468,11 +8531,11 @@ async function attachLateralRelations(params) {
|
|
|
8468
8531
|
}
|
|
8469
8532
|
}
|
|
8470
8533
|
// packages/runtime/src/views.ts
|
|
8471
|
-
import { VibeError as
|
|
8534
|
+
import { VibeError as VibeError23 } from "@vibeorm/schema";
|
|
8472
8535
|
|
|
8473
8536
|
// packages/runtime/src/sql-access.ts
|
|
8474
8537
|
import { Buffer as Buffer2 } from "buffer";
|
|
8475
|
-
import { VibeError as
|
|
8538
|
+
import { VibeError as VibeError22 } from "@vibeorm/schema";
|
|
8476
8539
|
import { isSqlFragment as isSqlFragment2 } from "@vibeorm/sql";
|
|
8477
8540
|
function containsSqlFragment(value, seen = new Set) {
|
|
8478
8541
|
if (isSqlFragment2(value))
|
|
@@ -8497,7 +8560,7 @@ function containsSqlFragment(value, seen = new Set) {
|
|
|
8497
8560
|
return false;
|
|
8498
8561
|
}
|
|
8499
8562
|
function restrictedSqlArgs(params) {
|
|
8500
|
-
const refuse = () => params.refusal?.() ?? new
|
|
8563
|
+
const refuse = () => params.refusal?.() ?? new VibeError22({ code: "VIBE_VALIDATION", message: `SQL fragments are unavailable through ${params.path}; use the unrestricted client`, meta: { path: params.path } });
|
|
8501
8564
|
if (containsSqlFragment(params.value))
|
|
8502
8565
|
throw refuse();
|
|
8503
8566
|
const seen = new Map;
|
|
@@ -8559,13 +8622,13 @@ function restrictConflictPredicates(params) {
|
|
|
8559
8622
|
const target = spec.target;
|
|
8560
8623
|
const declared = conflictSchemas.get(params.meta)?.get(params.model.name)?.some((index) => typeof spec.where === "string" && index.where === spec.where && Array.isArray(target) && target.length === index.fields.length && index.fields.every((field, position) => field === target[position]));
|
|
8561
8624
|
if (declared !== true)
|
|
8562
|
-
throw new
|
|
8625
|
+
throw new VibeError22({ code: "VIBE_VALIDATION", message: `${params.path}: ${key}.where must match a declared unique index and its target fields; free-form SQL requires the unrestricted client`, meta: { model: params.model.name, path: params.path } });
|
|
8563
8626
|
}
|
|
8564
8627
|
}
|
|
8565
8628
|
|
|
8566
8629
|
// packages/runtime/src/views.ts
|
|
8567
8630
|
function validationError6(params) {
|
|
8568
|
-
return new
|
|
8631
|
+
return new VibeError23({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
|
|
8569
8632
|
}
|
|
8570
8633
|
|
|
8571
8634
|
class ViewResult {
|
|
@@ -8919,7 +8982,7 @@ function createView(params) {
|
|
|
8919
8982
|
for (const [clientName, mask] of resolved) {
|
|
8920
8983
|
const delegate = models[clientName];
|
|
8921
8984
|
if (delegate === undefined) {
|
|
8922
|
-
throw new
|
|
8985
|
+
throw new VibeError23({
|
|
8923
8986
|
code: "VIBE_INTERNAL",
|
|
8924
8987
|
message: `view "${name}": no delegate for model "${mask.model.name}"`,
|
|
8925
8988
|
meta: { view: name, model: mask.model.name }
|
|
@@ -8935,9 +8998,9 @@ function attachDefineView(params) {
|
|
|
8935
8998
|
Object.defineProperty(client, "$defineView", { value, enumerable: true });
|
|
8936
8999
|
}
|
|
8937
9000
|
// packages/runtime/src/validators.ts
|
|
8938
|
-
import { VibeError as
|
|
9001
|
+
import { VibeError as VibeError24 } from "@vibeorm/schema";
|
|
8939
9002
|
function validationFailed(params) {
|
|
8940
|
-
return new
|
|
9003
|
+
return new VibeError24({
|
|
8941
9004
|
code: "VIBE_VALIDATION",
|
|
8942
9005
|
message: `validation failed for ${params.model}.${params.field}: ${params.issues[0]?.message ?? "invalid value"}`,
|
|
8943
9006
|
meta: { model: params.model, field: params.field, issues: params.issues }
|
|
@@ -8946,7 +9009,7 @@ function validationFailed(params) {
|
|
|
8946
9009
|
function validateValue(params) {
|
|
8947
9010
|
const result = params.schema["~standard"].validate(params.value);
|
|
8948
9011
|
if (result instanceof Promise) {
|
|
8949
|
-
throw new
|
|
9012
|
+
throw new VibeError24({
|
|
8950
9013
|
code: "VIBE_VALIDATION",
|
|
8951
9014
|
message: `async validator on ${params.model}.${params.field} \u2014 write validators must be synchronous (validate before calling the client for async rules)`,
|
|
8952
9015
|
meta: { model: params.model, field: params.field }
|
|
@@ -9069,10 +9132,10 @@ function deferPolicyOperation(params) {
|
|
|
9069
9132
|
}
|
|
9070
9133
|
|
|
9071
9134
|
// packages/runtime/src/policy.ts
|
|
9072
|
-
import { VibeError as
|
|
9135
|
+
import { VibeError as VibeError27 } from "@vibeorm/schema";
|
|
9073
9136
|
|
|
9074
9137
|
// packages/runtime/src/module-context.ts
|
|
9075
|
-
import { VibeError as
|
|
9138
|
+
import { VibeError as VibeError25 } from "@vibeorm/schema";
|
|
9076
9139
|
var binders = new WeakMap;
|
|
9077
9140
|
function registerModuleBinder(params) {
|
|
9078
9141
|
binders.set(params.client, params.bind);
|
|
@@ -9085,7 +9148,7 @@ function inheritReadOnlyModuleBinder(params) {
|
|
|
9085
9148
|
function bindModuleContext(params) {
|
|
9086
9149
|
const bind = binders.get(params.db);
|
|
9087
9150
|
if (bind === undefined)
|
|
9088
|
-
throw new
|
|
9151
|
+
throw new VibeError25({
|
|
9089
9152
|
code: "VIBE_CONFIG",
|
|
9090
9153
|
message: `Module ${params.artifact.manifest.id} needs an unrestricted handle from the same VibeORM runtime installation; scoped and foreign handles cannot attach package models`,
|
|
9091
9154
|
meta: { reason: "module_handle", moduleId: params.artifact.manifest.id, protocol: params.artifact.manifest.protocol }
|
|
@@ -9094,9 +9157,10 @@ function bindModuleContext(params) {
|
|
|
9094
9157
|
}
|
|
9095
9158
|
|
|
9096
9159
|
// packages/runtime/src/read-only.ts
|
|
9097
|
-
import { ReadOnlyClientError } from "@vibeorm/schema";
|
|
9160
|
+
import { ReadOnlyClientError, VibeError as VibeError26 } from "@vibeorm/schema";
|
|
9098
9161
|
var READ_DELEGATE_METHODS = Object.freeze([
|
|
9099
9162
|
"findMany",
|
|
9163
|
+
"findPage",
|
|
9100
9164
|
"findFirst",
|
|
9101
9165
|
"findFirstOrThrow",
|
|
9102
9166
|
"findUnique",
|
|
@@ -9124,6 +9188,42 @@ var DELEGATE_METHOD_ACCESS = Object.freeze(Object.fromEntries([
|
|
|
9124
9188
|
function delegateMethodAccess(params) {
|
|
9125
9189
|
return Object.hasOwn(DELEGATE_METHOD_ACCESS, params.method) ? DELEGATE_METHOD_ACCESS[params.method] : undefined;
|
|
9126
9190
|
}
|
|
9191
|
+
function createDelegateMethodClassifier(params) {
|
|
9192
|
+
const context = contexts.get(params.db);
|
|
9193
|
+
if (context === undefined)
|
|
9194
|
+
throw new VibeError26({
|
|
9195
|
+
code: "VIBE_CONFIG",
|
|
9196
|
+
message: "Configured classification requires a registered VibeORM client handle",
|
|
9197
|
+
meta: { reason: "delegate-classifier-handle" }
|
|
9198
|
+
});
|
|
9199
|
+
context.assertActive?.();
|
|
9200
|
+
return ({ method, model }) => {
|
|
9201
|
+
context.assertActive?.();
|
|
9202
|
+
const target = model === undefined ? undefined : context.meta.models.find((entry) => entry.name === model || entry.clientName === model);
|
|
9203
|
+
if (model !== undefined && target === undefined)
|
|
9204
|
+
return;
|
|
9205
|
+
const core = delegateMethodAccess({ method });
|
|
9206
|
+
if (core !== undefined)
|
|
9207
|
+
return core;
|
|
9208
|
+
const parts = method.split(".");
|
|
9209
|
+
if (parts.length > 2)
|
|
9210
|
+
return;
|
|
9211
|
+
const [property, member] = parts;
|
|
9212
|
+
const mount = context.mounts.find((entry) => entry.property === property && (target === undefined ? entry.scope === "client" : entry.scope === "model" && entry.model === target.name));
|
|
9213
|
+
if (mount === undefined || mount.readOnly === undefined)
|
|
9214
|
+
return;
|
|
9215
|
+
const root = params.db;
|
|
9216
|
+
const owner = target === undefined ? root : root.$models?.[target.name];
|
|
9217
|
+
if (typeof owner !== "object" || owner === null || property === undefined)
|
|
9218
|
+
return;
|
|
9219
|
+
const value = owner[property];
|
|
9220
|
+
if (mount.readOnly === true)
|
|
9221
|
+
return member === undefined && typeof value === "function" ? "read" : undefined;
|
|
9222
|
+
if (member === undefined || !mount.readOnly.includes(member) || typeof value !== "object" || value === null)
|
|
9223
|
+
return;
|
|
9224
|
+
return typeof value[member] === "function" ? "read" : undefined;
|
|
9225
|
+
};
|
|
9226
|
+
}
|
|
9127
9227
|
var CLIENT_MEMBER_ACCESS = Object.freeze({
|
|
9128
9228
|
$models: "rebuilt",
|
|
9129
9229
|
$on: "forwarded",
|
|
@@ -9323,8 +9423,11 @@ function readOnlyOver(params) {
|
|
|
9323
9423
|
const existing = facades.get(params.client);
|
|
9324
9424
|
if (existing !== undefined)
|
|
9325
9425
|
return existing;
|
|
9326
|
-
const
|
|
9426
|
+
const context = contexts.get(params.client) ?? params.context;
|
|
9427
|
+
const built = buildReadOnly({ client: params.client, context });
|
|
9327
9428
|
inheritReadOnlyModuleBinder({ from: params.client, to: built });
|
|
9429
|
+
inheritTransactionObservation({ from: params.client, to: built });
|
|
9430
|
+
contexts.set(built, context);
|
|
9328
9431
|
facades.set(params.client, built);
|
|
9329
9432
|
return built;
|
|
9330
9433
|
}
|
|
@@ -9332,7 +9435,8 @@ function attachReadOnly(params) {
|
|
|
9332
9435
|
const context = {
|
|
9333
9436
|
meta: params.meta,
|
|
9334
9437
|
mounts: params.mounts ?? [],
|
|
9335
|
-
operations: params.operations
|
|
9438
|
+
operations: params.operations,
|
|
9439
|
+
...params.assertActive === undefined ? {} : { assertActive: params.assertActive }
|
|
9336
9440
|
};
|
|
9337
9441
|
contexts.set(params.client, context);
|
|
9338
9442
|
Object.defineProperty(params.client, "$readOnly", {
|
|
@@ -9346,6 +9450,7 @@ function inheritReadOnly(params) {
|
|
|
9346
9450
|
if (context === undefined)
|
|
9347
9451
|
return;
|
|
9348
9452
|
contexts.set(params.to, context);
|
|
9453
|
+
inheritTransactionObservation({ from: params.from, to: params.to });
|
|
9349
9454
|
Object.defineProperty(params.to, "$readOnly", {
|
|
9350
9455
|
value: () => readOnlyOver({ client: params.to, context }),
|
|
9351
9456
|
enumerable: true,
|
|
@@ -9355,7 +9460,7 @@ function inheritReadOnly(params) {
|
|
|
9355
9460
|
|
|
9356
9461
|
// packages/runtime/src/policy.ts
|
|
9357
9462
|
function policyError(message, meta) {
|
|
9358
|
-
return new
|
|
9463
|
+
return new VibeError27({ code: "VIBE_VALIDATION", message, meta: meta ?? {} });
|
|
9359
9464
|
}
|
|
9360
9465
|
function policiedModels(meta) {
|
|
9361
9466
|
return meta.models.filter((model) => model.policy !== undefined);
|
|
@@ -9705,9 +9810,10 @@ function scopedDelegate(params) {
|
|
|
9705
9810
|
const pkWhere = pk.length === 1 ? { [pk[0]]: target[pk[0]] } : { [pkClientKey()]: Object.fromEntries(pk.map((name) => [name, target[name]])) };
|
|
9706
9811
|
return write(raw, pkWhere);
|
|
9707
9812
|
};
|
|
9708
|
-
const notFound = (method) => new
|
|
9813
|
+
const notFound = (method) => new VibeError27({ code: "VIBE_NOT_FOUND", message: `${method} on ${model.name}: no row matches the unique where inside the bound policy context`, meta: { model: model.name, method } });
|
|
9709
9814
|
return {
|
|
9710
9815
|
findMany: (args) => base.findMany(scopeFind(args)),
|
|
9816
|
+
findPage: (args) => base.findPage(scopeFind(args)),
|
|
9711
9817
|
findFirst: (args) => base.findFirst(scopeFind(args)),
|
|
9712
9818
|
findFirstOrThrow: (args) => base.findFirstOrThrow(scopeFind(args)),
|
|
9713
9819
|
findUnique: (args) => base.findFirst(scopeUnique(args)),
|
|
@@ -9739,7 +9845,7 @@ function scopedDelegate(params) {
|
|
|
9739
9845
|
})
|
|
9740
9846
|
})),
|
|
9741
9847
|
upsertMany: () => {
|
|
9742
|
-
throw new
|
|
9848
|
+
throw new VibeError27({
|
|
9743
9849
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
9744
9850
|
message: "upsertMany is not available on a policy-bound client: its conflict target is not policy-checked yet",
|
|
9745
9851
|
meta: { model: model.name }
|
|
@@ -9748,7 +9854,7 @@ function scopedDelegate(params) {
|
|
|
9748
9854
|
updateManyAndReturn: (args) => deferred(() => {
|
|
9749
9855
|
const run = base.updateManyAndReturn;
|
|
9750
9856
|
if (run === undefined) {
|
|
9751
|
-
throw new
|
|
9857
|
+
throw new VibeError27({
|
|
9752
9858
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
9753
9859
|
message: "updateManyAndReturn is not available on this delegate",
|
|
9754
9860
|
meta: { model: model.name }
|
|
@@ -9807,6 +9913,7 @@ function globalDelegate(params) {
|
|
|
9807
9913
|
const payload = (value, phase) => forceWriteData({ meta, model, data: value ?? {}, context, phase });
|
|
9808
9914
|
const overrides = {
|
|
9809
9915
|
findMany: (args) => base.findMany(readArgs(args)),
|
|
9916
|
+
findPage: (args) => base.findPage(readArgs(args)),
|
|
9810
9917
|
findFirst: (args) => base.findFirst(readArgs(args)),
|
|
9811
9918
|
findFirstOrThrow: (args) => base.findFirstOrThrow(readArgs(args)),
|
|
9812
9919
|
findUnique: (args) => base.findUnique(readArgs(args)),
|
|
@@ -9822,7 +9929,7 @@ function globalDelegate(params) {
|
|
|
9822
9929
|
updateManyAndReturn: (args) => deferred(() => {
|
|
9823
9930
|
const run = base.updateManyAndReturn;
|
|
9824
9931
|
if (run === undefined) {
|
|
9825
|
-
throw new
|
|
9932
|
+
throw new VibeError27({
|
|
9826
9933
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
9827
9934
|
message: "updateManyAndReturn is not available on this delegate"
|
|
9828
9935
|
});
|
|
@@ -9833,7 +9940,7 @@ function globalDelegate(params) {
|
|
|
9833
9940
|
upsertMany: (args) => deferred(() => {
|
|
9834
9941
|
if (params.policyBound === false)
|
|
9835
9942
|
return base.upsertMany(args);
|
|
9836
|
-
throw new
|
|
9943
|
+
throw new VibeError27({
|
|
9837
9944
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
9838
9945
|
message: "upsertMany is not available on a policy-bound client: its conflict target is not policy-checked yet"
|
|
9839
9946
|
});
|
|
@@ -10004,7 +10111,7 @@ function attachPolicy(params) {
|
|
|
10004
10111
|
});
|
|
10005
10112
|
}
|
|
10006
10113
|
// packages/runtime/src/scoped.ts
|
|
10007
|
-
import { ScopedQueryError, VibeError as
|
|
10114
|
+
import { ScopedQueryError, VibeError as VibeError28 } from "@vibeorm/schema";
|
|
10008
10115
|
function refusal(params) {
|
|
10009
10116
|
return new ScopedQueryError(params);
|
|
10010
10117
|
}
|
|
@@ -10728,7 +10835,7 @@ function createScopeRewriter(params) {
|
|
|
10728
10835
|
})
|
|
10729
10836
|
};
|
|
10730
10837
|
}
|
|
10731
|
-
var FIND_LIKE = ["findMany", "findFirst", "findFirstOrThrow", "count", "aggregate", "groupBy"];
|
|
10838
|
+
var FIND_LIKE = ["findPage", "findMany", "findFirst", "findFirstOrThrow", "count", "aggregate", "groupBy"];
|
|
10732
10839
|
function rewriteScopedCall(params) {
|
|
10733
10840
|
const { meta, resolved, scope, preds, method } = params;
|
|
10734
10841
|
const ctx = { meta, resolved, scope, preds };
|
|
@@ -10857,6 +10964,7 @@ function scopedDelegate2(params) {
|
|
|
10857
10964
|
};
|
|
10858
10965
|
return {
|
|
10859
10966
|
findMany: (args) => run("findMany", args),
|
|
10967
|
+
findPage: (args) => run("findPage", args),
|
|
10860
10968
|
findFirst: (args) => run("findFirst", args),
|
|
10861
10969
|
findFirstOrThrow: (args) => run("findFirstOrThrow", args),
|
|
10862
10970
|
findUnique: (args) => run("findUnique", args),
|
|
@@ -10960,7 +11068,7 @@ function attachScoped(params) {
|
|
|
10960
11068
|
Object.defineProperty(client, "$scoped", {
|
|
10961
11069
|
value: (config) => {
|
|
10962
11070
|
if (!isPlainObject8(config) || !isPlainObject8(config.models)) {
|
|
10963
|
-
throw new
|
|
11071
|
+
throw new VibeError28({
|
|
10964
11072
|
code: "VIBE_VALIDATION",
|
|
10965
11073
|
message: "$scoped takes { scope: string | number | bigint | null, models: { <Model>: \u2026 } }"
|
|
10966
11074
|
});
|
|
@@ -10976,7 +11084,7 @@ function attachScoped(params) {
|
|
|
10976
11084
|
}
|
|
10977
11085
|
const scope = config.scope;
|
|
10978
11086
|
if (scope !== null && typeof scope !== "string" && typeof scope !== "number" && typeof scope !== "bigint") {
|
|
10979
|
-
throw new
|
|
11087
|
+
throw new VibeError28({
|
|
10980
11088
|
code: "VIBE_VALIDATION",
|
|
10981
11089
|
message: `$scoped: scope must be a string, number, bigint or null \u2014 got ${typeof scope}`
|
|
10982
11090
|
});
|
|
@@ -10992,7 +11100,7 @@ function attachScoped(params) {
|
|
|
10992
11100
|
});
|
|
10993
11101
|
}
|
|
10994
11102
|
// packages/runtime/src/rls-readiness.ts
|
|
10995
|
-
import { VibeError as
|
|
11103
|
+
import { VibeError as VibeError29, assertValidSchemaIR, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
|
|
10996
11104
|
import { NATIVE_RLS as NATIVE_RLS2, getSqlDialect as getSqlDialect4, renderRlsPolicy, renderRlsRole, NATIVE_RLS_PROBE_POLICY, renderRlsReadinessQuery, renderRlsProbeTable } from "@vibeorm/sql";
|
|
10997
11105
|
import { RLS_READINESS_SQL, NATIVE_RLS_PROBE_POLICY as NATIVE_RLS_PROBE_POLICY2 } from "@vibeorm/sql";
|
|
10998
11106
|
function textOf(params) {
|
|
@@ -11016,7 +11124,7 @@ function intOf(params) {
|
|
|
11016
11124
|
return Number.parseInt(value, 10);
|
|
11017
11125
|
}
|
|
11018
11126
|
function unreadableCatalog(params) {
|
|
11019
|
-
return new
|
|
11127
|
+
return new VibeError29({
|
|
11020
11128
|
code: "VIBE_ADAPTER",
|
|
11021
11129
|
message: `native RLS readiness could not read the "${params.key}" result of the folded catalog read: ${params.detail}. ` + "The inspection is refused rather than treated as an empty result set.",
|
|
11022
11130
|
meta: { result: params.key }
|
|
@@ -11072,10 +11180,10 @@ function unprotectedTablesOf(params) {
|
|
|
11072
11180
|
function requireNativeRls(params) {
|
|
11073
11181
|
const dialect = getSqlDialect4({ dialect: params.adapter.dialect });
|
|
11074
11182
|
if (!dialect.capabilities.nativeRowLevelSecurity) {
|
|
11075
|
-
throw
|
|
11183
|
+
throw unsupportedCapability8({ dialect: dialect.name, feature: "nativeRowLevelSecurity" });
|
|
11076
11184
|
}
|
|
11077
11185
|
if (params.schema.rls === undefined) {
|
|
11078
|
-
throw new
|
|
11186
|
+
throw new VibeError29({
|
|
11079
11187
|
code: "VIBE_CONFIG",
|
|
11080
11188
|
message: "Native row-level security readiness requires a schema that declares native RLS"
|
|
11081
11189
|
});
|
|
@@ -11092,24 +11200,27 @@ async function probeExpressions(params) {
|
|
|
11092
11200
|
if (tables.length === 0)
|
|
11093
11201
|
return { available: true, expressions: [] };
|
|
11094
11202
|
return adapter.transaction(async (tx) => {
|
|
11095
|
-
const current = await tx.execute(renderRlsReadinessQuery({ dialect, query: "readSearchPath" }));
|
|
11203
|
+
const current = await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "readSearchPath" }), effect: "read" });
|
|
11096
11204
|
const searchPath = current[0] === undefined ? "" : textOf({ row: current[0], key: "searchPath" });
|
|
11097
|
-
await tx.execute(renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath: "" }));
|
|
11205
|
+
await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath: "" }), effect: "read" });
|
|
11098
11206
|
for (const entry of params.desired === undefined ? tables : []) {
|
|
11099
|
-
await tx.executeUnsafe(renderRlsProbeTable({ dialect, table: entry.table, action: "create" }));
|
|
11100
|
-
await tx.executeUnsafe(
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11207
|
+
await tx.executeUnsafe({ ...renderRlsProbeTable({ dialect, table: entry.table, action: "create" }), effect: "read" });
|
|
11208
|
+
await tx.executeUnsafe({
|
|
11209
|
+
...renderRlsPolicy({
|
|
11210
|
+
dialect,
|
|
11211
|
+
schema,
|
|
11212
|
+
model: entry.model,
|
|
11213
|
+
policyName: NATIVE_RLS_PROBE_POLICY,
|
|
11214
|
+
targetSchema: "pg_temp"
|
|
11215
|
+
}),
|
|
11216
|
+
effect: "read"
|
|
11217
|
+
});
|
|
11107
11218
|
}
|
|
11108
|
-
const rows = await tx.execute(renderRlsReadinessQuery({ dialect, query: "expressions" }));
|
|
11219
|
+
const rows = await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "expressions" }), effect: "read" });
|
|
11109
11220
|
for (const entry of params.desired === undefined ? tables : []) {
|
|
11110
|
-
await tx.executeUnsafe(renderRlsProbeTable({ dialect, table: entry.table, action: "drop" }));
|
|
11221
|
+
await tx.executeUnsafe({ ...renderRlsProbeTable({ dialect, table: entry.table, action: "drop" }), effect: "read" });
|
|
11111
11222
|
}
|
|
11112
|
-
await tx.execute(renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath }));
|
|
11223
|
+
await tx.execute({ ...renderRlsReadinessQuery({ dialect, query: "setSearchPath", searchPath }), effect: "read" });
|
|
11113
11224
|
return {
|
|
11114
11225
|
available: true,
|
|
11115
11226
|
expressions: [...rows.filter((row) => params.desired === undefined || row.probe === false).map((row) => ({
|
|
@@ -11366,7 +11477,7 @@ async function inspectNativeRlsTransaction(params) {
|
|
|
11366
11477
|
const dialect = requireNativeRls({ adapter, schema });
|
|
11367
11478
|
const protectedTables = protectedTablesOf({ schema });
|
|
11368
11479
|
const unprotected = unprotectedTablesOf({ schema });
|
|
11369
|
-
const catalogRows = await adapter.execute(renderRlsReadinessQuery({ dialect, query: "catalog" }));
|
|
11480
|
+
const catalogRows = await adapter.execute({ ...renderRlsReadinessQuery({ dialect, query: "catalog" }), effect: "read" });
|
|
11370
11481
|
const catalog = catalogRows[0] ?? {};
|
|
11371
11482
|
const identityRow = catalogRowsOf({ row: catalog, key: "identity" })[0] ?? {};
|
|
11372
11483
|
const identity = {
|
|
@@ -11476,7 +11587,7 @@ async function inspectNativeRls(params) {
|
|
|
11476
11587
|
const embeddedRole = adapter.provider === "pglite" ? requireEmbeddedRole({ role: params.runtimeRole }) : undefined;
|
|
11477
11588
|
return adapter.transaction(async (tx) => {
|
|
11478
11589
|
if (embeddedRole !== undefined) {
|
|
11479
|
-
await tx.executeUnsafe(renderRlsRole({ dialect: getSqlDialect4({ dialect: adapter.dialect }), role: embeddedRole }));
|
|
11590
|
+
await tx.executeUnsafe({ ...renderRlsRole({ dialect: getSqlDialect4({ dialect: adapter.dialect }), role: embeddedRole }), effect: "read" });
|
|
11480
11591
|
}
|
|
11481
11592
|
return inspectNativeRlsTransaction({
|
|
11482
11593
|
adapter: tx,
|
|
@@ -11488,7 +11599,7 @@ async function inspectNativeRls(params) {
|
|
|
11488
11599
|
function requireEmbeddedRole(params) {
|
|
11489
11600
|
const { role } = params;
|
|
11490
11601
|
if (typeof role !== "string" || role.length === 0 || role.includes("\x00")) {
|
|
11491
|
-
throw new
|
|
11602
|
+
throw new VibeError29({
|
|
11492
11603
|
code: "VIBE_CONFIG",
|
|
11493
11604
|
message: "PGlite native row-level security requires a pre-existing restricted runtime role (nativeRls.runtimeRole) \u2014 its default embedded session is privileged and bypasses every policy",
|
|
11494
11605
|
meta: { provider: "pglite" }
|
|
@@ -11500,7 +11611,7 @@ function assertNativeRlsReady(params) {
|
|
|
11500
11611
|
const { report } = params;
|
|
11501
11612
|
if (report.ready)
|
|
11502
11613
|
return;
|
|
11503
|
-
throw new
|
|
11614
|
+
throw new VibeError29({
|
|
11504
11615
|
code: "VIBE_CONFIG",
|
|
11505
11616
|
message: `Native row-level security is not ready on this database: ${report.problems.map((problem) => `${problem.name} (${problem.status})`).join(", ")}`,
|
|
11506
11617
|
meta: {
|
|
@@ -11525,17 +11636,114 @@ function formatNativeRlsReport(params) {
|
|
|
11525
11636
|
return lines;
|
|
11526
11637
|
}
|
|
11527
11638
|
// packages/runtime/src/database-module.ts
|
|
11528
|
-
import { createHash } from "crypto";
|
|
11529
|
-
import { VibeError as
|
|
11639
|
+
import { createHash as createHash2 } from "crypto";
|
|
11640
|
+
import { VibeError as VibeError35, assertValidSchemaIR as assertValidSchemaIR3, prepareDatabaseModuleSchema, providerToDialect } from "@vibeorm/schema";
|
|
11641
|
+
|
|
11642
|
+
// packages/runtime/src/client.ts
|
|
11643
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
11644
|
+
|
|
11645
|
+
// packages/runtime/src/find-page.ts
|
|
11646
|
+
import { VibeError as VibeError30 } from "@vibeorm/schema";
|
|
11647
|
+
|
|
11648
|
+
// packages/runtime/src/keyset-projection.ts
|
|
11649
|
+
function keysetProjection(params) {
|
|
11650
|
+
const { plan, select, omit } = params;
|
|
11651
|
+
const names = plan.keys.map((key) => key.field.name);
|
|
11652
|
+
if (select !== undefined) {
|
|
11653
|
+
const hidden = names.filter((name) => select[name] !== true);
|
|
11654
|
+
if (hidden.length === 0)
|
|
11655
|
+
return { select, hidden };
|
|
11656
|
+
const widened = { ...select };
|
|
11657
|
+
for (const name of hidden)
|
|
11658
|
+
widened[name] = true;
|
|
11659
|
+
return { select: widened, hidden };
|
|
11660
|
+
}
|
|
11661
|
+
if (omit !== undefined) {
|
|
11662
|
+
const hidden = names.filter((name) => omit[name] === true);
|
|
11663
|
+
if (hidden.length === 0)
|
|
11664
|
+
return { omit, hidden };
|
|
11665
|
+
const narrowed = { ...omit };
|
|
11666
|
+
for (const name of hidden)
|
|
11667
|
+
narrowed[name] = false;
|
|
11668
|
+
return { omit: narrowed, hidden };
|
|
11669
|
+
}
|
|
11670
|
+
return { hidden: [] };
|
|
11671
|
+
}
|
|
11672
|
+
|
|
11673
|
+
// packages/runtime/src/find-page.ts
|
|
11674
|
+
var PAGE_ARGUMENTS = new Set([
|
|
11675
|
+
"where",
|
|
11676
|
+
"orderBy",
|
|
11677
|
+
"take",
|
|
11678
|
+
"after",
|
|
11679
|
+
"select",
|
|
11680
|
+
"include",
|
|
11681
|
+
"omit",
|
|
11682
|
+
"relationStrategy",
|
|
11683
|
+
"keyset"
|
|
11684
|
+
]);
|
|
11685
|
+
function validatePageArgs(params) {
|
|
11686
|
+
const { model, args } = params;
|
|
11687
|
+
if (typeof args !== "object" || args === null || Array.isArray(args)) {
|
|
11688
|
+
throw new VibeError30({ code: "VIBE_VALIDATION", message: `${model}.findPage requires an argument object`, meta: { model, reason: "keyset-page-args" } });
|
|
11689
|
+
}
|
|
11690
|
+
for (const key of Object.keys(args)) {
|
|
11691
|
+
if (!PAGE_ARGUMENTS.has(key)) {
|
|
11692
|
+
throw new VibeError30({ code: "VIBE_VALIDATION", message: `${model}.findPage does not accept ${key}`, meta: { model, argument: key, reason: "keyset-page-argument" } });
|
|
11693
|
+
}
|
|
11694
|
+
}
|
|
11695
|
+
const take = "take" in args ? args.take : undefined;
|
|
11696
|
+
if (typeof take !== "number" || !Number.isSafeInteger(take) || take < 1 || take > KEYSET_MAX_PAGE_SIZE) {
|
|
11697
|
+
throw new VibeError30({ code: "VIBE_VALIDATION", message: `findPage take must be an integer between 1 and ${KEYSET_MAX_PAGE_SIZE}`, meta: { model, reason: "keyset-page-size" } });
|
|
11698
|
+
}
|
|
11699
|
+
return args;
|
|
11700
|
+
}
|
|
11701
|
+
function preparePage(params) {
|
|
11702
|
+
const { meta, model, dialect, args } = params;
|
|
11703
|
+
const plan = compileKeysetOrderPlan({
|
|
11704
|
+
model,
|
|
11705
|
+
dialect,
|
|
11706
|
+
terms: compileKeysetOrderInputs({ meta, model, dialect, orderBy: args.orderBy }),
|
|
11707
|
+
...parseKeysetOptions({ model, value: args.keyset })
|
|
11708
|
+
});
|
|
11709
|
+
const projection = keysetProjection({
|
|
11710
|
+
plan,
|
|
11711
|
+
select: args.select,
|
|
11712
|
+
omit: args.omit
|
|
11713
|
+
});
|
|
11714
|
+
return {
|
|
11715
|
+
plan,
|
|
11716
|
+
args: {
|
|
11717
|
+
...args,
|
|
11718
|
+
take: args.take + 1,
|
|
11719
|
+
...projection.select === undefined ? {} : { select: projection.select },
|
|
11720
|
+
...projection.omit === undefined ? {} : { omit: projection.omit }
|
|
11721
|
+
}
|
|
11722
|
+
};
|
|
11723
|
+
}
|
|
11724
|
+
function pageContinuation(params) {
|
|
11725
|
+
const { plan, rows, take, after } = params;
|
|
11726
|
+
const first = rows[0];
|
|
11727
|
+
if (typeof after === "string" && first !== undefined && keysetRowIsAfter({
|
|
11728
|
+
keys: plan.keys,
|
|
11729
|
+
row: keysetRowValues({ plan, row: first }),
|
|
11730
|
+
position: decodeKeysetToken({ plan, token: after })
|
|
11731
|
+
}) === false) {
|
|
11732
|
+
throw new VibeError30({ code: "VIBE_DATA_INVALID", message: `keyset page for ${plan.model} is not advancing; check ordering precision`, meta: { model: plan.model, reason: "keyset-position-not-advancing" } });
|
|
11733
|
+
}
|
|
11734
|
+
const last = rows[take - 1];
|
|
11735
|
+
return rows.length > take && last !== undefined ? encodeKeysetToken({ plan, row: last }) : null;
|
|
11736
|
+
}
|
|
11530
11737
|
|
|
11531
11738
|
// packages/runtime/src/client.ts
|
|
11532
11739
|
import { compileSql } from "@vibeorm/sql";
|
|
11533
|
-
import { RlsContextError as RlsContextError2, VibeError as
|
|
11740
|
+
import { RlsContextError as RlsContextError2, VibeError as VibeError34, assertValidSchemaIR as assertValidSchemaIR2, unsupportedCapability as unsupportedCapability9 } from "@vibeorm/schema";
|
|
11534
11741
|
import { ADVISORY_LOCK_RESULT_COLUMN, ParamCollector, getSqlDialect as getSqlDialect5, renderRlsContext, renderRlsPolicy as renderRlsPolicy2, renderRlsRole as renderRlsRole2, renderStatement as renderStatement5 } from "@vibeorm/sql";
|
|
11535
11742
|
|
|
11536
11743
|
// packages/runtime/src/render-cache.ts
|
|
11537
11744
|
import {
|
|
11538
11745
|
isSqlFragment as isSqlFragment3,
|
|
11746
|
+
isNativeEnumArrayParameter,
|
|
11539
11747
|
isDbNowMarker,
|
|
11540
11748
|
isJsonParamCell,
|
|
11541
11749
|
isListSetOperation,
|
|
@@ -11587,7 +11795,22 @@ function addCol(walk, column) {
|
|
|
11587
11795
|
addIdent(walk, column.alias);
|
|
11588
11796
|
}
|
|
11589
11797
|
}
|
|
11798
|
+
function addParameter(walk, value) {
|
|
11799
|
+
if (isNativeEnumArrayParameter(value)) {
|
|
11800
|
+
walk.key += "enumArray";
|
|
11801
|
+
addIdent(walk, value.type.namespace);
|
|
11802
|
+
addIdent(walk, value.type.name);
|
|
11803
|
+
walk.values.push(value.value);
|
|
11804
|
+
return;
|
|
11805
|
+
}
|
|
11806
|
+
walk.key += "param";
|
|
11807
|
+
walk.values.push(value);
|
|
11808
|
+
}
|
|
11590
11809
|
function addTable(walk, table) {
|
|
11810
|
+
if (table.namespace !== undefined) {
|
|
11811
|
+
walk.key += "namespace";
|
|
11812
|
+
addIdent(walk, table.namespace);
|
|
11813
|
+
}
|
|
11591
11814
|
addIdent(walk, table.name);
|
|
11592
11815
|
if (table.alias !== undefined) {
|
|
11593
11816
|
walk.key += "@";
|
|
@@ -11609,7 +11832,7 @@ function addSetEntry(walk, name, value) {
|
|
|
11609
11832
|
if (isSetOperation(value)) {
|
|
11610
11833
|
walk.key += `=o${value.__op}`;
|
|
11611
11834
|
addIdent(walk, name);
|
|
11612
|
-
walk
|
|
11835
|
+
addParameter(walk, value.value);
|
|
11613
11836
|
return;
|
|
11614
11837
|
}
|
|
11615
11838
|
if (isDbNowMarker(value)) {
|
|
@@ -11622,12 +11845,12 @@ function addSetEntry(walk, name, value) {
|
|
|
11622
11845
|
if (isListSetOperation(value)) {
|
|
11623
11846
|
walk.key += `=l${value.__listOp}`;
|
|
11624
11847
|
addIdent(walk, name);
|
|
11625
|
-
walk
|
|
11848
|
+
addParameter(walk, value.value);
|
|
11626
11849
|
return;
|
|
11627
11850
|
}
|
|
11628
11851
|
walk.key += "=v";
|
|
11629
11852
|
addIdent(walk, name);
|
|
11630
|
-
walk
|
|
11853
|
+
addParameter(walk, value);
|
|
11631
11854
|
}
|
|
11632
11855
|
function addReturning(walk, returning) {
|
|
11633
11856
|
if (returning === undefined || returning.length === 0) {
|
|
@@ -11651,7 +11874,7 @@ function walkExpr(walk, dialect, expr) {
|
|
|
11651
11874
|
}
|
|
11652
11875
|
walk.key += `c${expr.op}`;
|
|
11653
11876
|
addCol(walk, expr.column);
|
|
11654
|
-
walk
|
|
11877
|
+
addParameter(walk, expr.value);
|
|
11655
11878
|
return true;
|
|
11656
11879
|
case "cmpCol":
|
|
11657
11880
|
walk.key += `k${expr.op}`;
|
|
@@ -11670,7 +11893,7 @@ function walkExpr(walk, dialect, expr) {
|
|
|
11670
11893
|
walk.key += expr.negate === true ? "i1" : "i0";
|
|
11671
11894
|
addCol(walk, expr.column);
|
|
11672
11895
|
if (dialect.inArrayStrategy === "any") {
|
|
11673
|
-
walk.values
|
|
11896
|
+
addParameter(walk, Array.isArray(expr.values) ? [...expr.values] : expr.values);
|
|
11674
11897
|
} else {
|
|
11675
11898
|
walk.key += `#${expr.values.length}`;
|
|
11676
11899
|
for (const value of expr.values)
|
|
@@ -11730,22 +11953,22 @@ function walkExpr(walk, dialect, expr) {
|
|
|
11730
11953
|
case "aggCmp":
|
|
11731
11954
|
walk.key += `g${expr.op}`;
|
|
11732
11955
|
addAgg(walk, expr.agg);
|
|
11733
|
-
walk
|
|
11956
|
+
addParameter(walk, expr.value);
|
|
11734
11957
|
return true;
|
|
11735
11958
|
case "arrayHas":
|
|
11736
11959
|
walk.key += expr.negate === true ? "h1" : "h0";
|
|
11737
11960
|
addCol(walk, expr.column);
|
|
11738
|
-
walk
|
|
11961
|
+
addParameter(walk, expr.value);
|
|
11739
11962
|
return true;
|
|
11740
11963
|
case "arrayContainsAll":
|
|
11741
11964
|
walk.key += "H";
|
|
11742
11965
|
addCol(walk, expr.column);
|
|
11743
|
-
walk.values
|
|
11966
|
+
addParameter(walk, Array.isArray(expr.values) ? [...expr.values] : expr.values);
|
|
11744
11967
|
return true;
|
|
11745
11968
|
case "arrayOverlaps":
|
|
11746
11969
|
walk.key += "V";
|
|
11747
11970
|
addCol(walk, expr.column);
|
|
11748
|
-
walk.values
|
|
11971
|
+
addParameter(walk, Array.isArray(expr.values) ? [...expr.values] : expr.values);
|
|
11749
11972
|
return true;
|
|
11750
11973
|
case "arrayIsEmpty":
|
|
11751
11974
|
walk.key += expr.empty ? "e1" : "e0";
|
|
@@ -12041,11 +12264,11 @@ function renderStatementCached(params) {
|
|
|
12041
12264
|
}
|
|
12042
12265
|
|
|
12043
12266
|
// packages/runtime/src/strict-args.ts
|
|
12044
|
-
import { VibeError as
|
|
12267
|
+
import { VibeError as VibeError31 } from "@vibeorm/schema";
|
|
12045
12268
|
var SKIP = Symbol.for("vibeorm.skip");
|
|
12046
12269
|
function explicitUndefined(params) {
|
|
12047
12270
|
const { model, method, path } = params;
|
|
12048
|
-
return new
|
|
12271
|
+
return new VibeError31({
|
|
12049
12272
|
code: "VIBE_VALIDATION",
|
|
12050
12273
|
message: `${model}.${method}(): explicit undefined at ${path} \u2014 an undefined value is refused ` + `because it would silently drop the property (widening a filter or losing a write). ` + `Omit the property, or pass SKIP to omit it deliberately; ` + `VibeClient({ strictArguments: false }) restores the legacy behaviour.`,
|
|
12051
12274
|
meta: { model, method, path }
|
|
@@ -12251,10 +12474,10 @@ function bindRlsContext(params) {
|
|
|
12251
12474
|
}
|
|
12252
12475
|
|
|
12253
12476
|
// packages/runtime/src/telemetry/recorder.ts
|
|
12254
|
-
import { VibeError as
|
|
12477
|
+
import { VibeError as VibeError33 } from "@vibeorm/schema";
|
|
12255
12478
|
|
|
12256
12479
|
// packages/runtime/src/telemetry/config.ts
|
|
12257
|
-
import { VibeError as
|
|
12480
|
+
import { VibeError as VibeError32 } from "@vibeorm/schema";
|
|
12258
12481
|
var TELEMETRY_DEFAULTS = Object.freeze({
|
|
12259
12482
|
captureSql: false,
|
|
12260
12483
|
captureParameterValues: false,
|
|
@@ -12269,7 +12492,7 @@ var TELEMETRY_DEFAULTS = Object.freeze({
|
|
|
12269
12492
|
latencyBucketsMs: Object.freeze([1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000])
|
|
12270
12493
|
});
|
|
12271
12494
|
function configError2(params) {
|
|
12272
|
-
return new
|
|
12495
|
+
return new VibeError32({
|
|
12273
12496
|
code: "VIBE_CONFIG",
|
|
12274
12497
|
message: `telemetry: ${params.message}`,
|
|
12275
12498
|
...params.meta === undefined ? {} : { meta: params.meta }
|
|
@@ -12357,7 +12580,7 @@ function deriveStage(params) {
|
|
|
12357
12580
|
return "decode";
|
|
12358
12581
|
}
|
|
12359
12582
|
function errorCodeOf(error) {
|
|
12360
|
-
return error instanceof
|
|
12583
|
+
return error instanceof VibeError33 ? error.code : undefined;
|
|
12361
12584
|
}
|
|
12362
12585
|
function newHistogram(bounds) {
|
|
12363
12586
|
return { counts: new Array(bounds.length + 1).fill(0), sum: 0, count: 0 };
|
|
@@ -12740,7 +12963,7 @@ async function instrumentStatement(params) {
|
|
|
12740
12963
|
// packages/runtime/src/client.ts
|
|
12741
12964
|
function notFound2(params) {
|
|
12742
12965
|
const { model, method } = params;
|
|
12743
|
-
return new
|
|
12966
|
+
return new VibeError34({
|
|
12744
12967
|
code: "VIBE_NOT_FOUND",
|
|
12745
12968
|
message: `no ${model} record matched the where clause of ${method}()`,
|
|
12746
12969
|
meta: { model, method }
|
|
@@ -12748,7 +12971,7 @@ function notFound2(params) {
|
|
|
12748
12971
|
}
|
|
12749
12972
|
function transactionLifecycleRefusal(params) {
|
|
12750
12973
|
const { method } = params;
|
|
12751
|
-
return new
|
|
12974
|
+
return new VibeError34({
|
|
12752
12975
|
code: "VIBE_VALIDATION",
|
|
12753
12976
|
message: `${method}() is not available on a transaction client \u2014 the connection is owned by the open transaction; call it on the client that started the transaction`,
|
|
12754
12977
|
meta: { method, inTransaction: true }
|
|
@@ -12756,7 +12979,7 @@ function transactionLifecycleRefusal(params) {
|
|
|
12756
12979
|
}
|
|
12757
12980
|
function viewIsReadOnly(params) {
|
|
12758
12981
|
const { model, method } = params;
|
|
12759
|
-
return new
|
|
12982
|
+
return new VibeError34({
|
|
12760
12983
|
code: "VIBE_VALIDATION",
|
|
12761
12984
|
message: `${model} is a view \u2014 ${method}() is not available on views (they are read-only); write to the underlying table instead`,
|
|
12762
12985
|
meta: { model, method }
|
|
@@ -12863,7 +13086,7 @@ async function engineTransaction(params) {
|
|
|
12863
13086
|
const support = engine.adapter.budgets?.transactionDeadline;
|
|
12864
13087
|
const requested = options.deadline.enforcement ?? "between-statements";
|
|
12865
13088
|
if (support === undefined || support === "unsupported" || requested === "cancel-running-statements" && support !== "cancel-running-statements") {
|
|
12866
|
-
throw new
|
|
13089
|
+
throw new VibeError34({
|
|
12867
13090
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
12868
13091
|
message: "the adapter does not declare support for the requested transaction deadline",
|
|
12869
13092
|
meta: { provider: engine.adapter.provider, feature: "transactionDeadline", requested, supported: support ?? "undeclared" }
|
|
@@ -12876,10 +13099,10 @@ async function engineTransaction(params) {
|
|
|
12876
13099
|
const execute = async () => {
|
|
12877
13100
|
if (engine.rlsSchema !== undefined && engine.inTransaction !== true) {
|
|
12878
13101
|
if (adapter.provider === "pglite") {
|
|
12879
|
-
await adapter.executeUnsafe(renderRlsRole2({ dialect: engine.dialect, role: engine.options.nativeRls.runtimeRole }));
|
|
13102
|
+
await adapter.executeUnsafe({ ...renderRlsRole2({ dialect: engine.dialect, role: engine.options.nativeRls.runtimeRole }), effect: "read" });
|
|
12880
13103
|
}
|
|
12881
13104
|
if (engine.context !== undefined && Object.keys(engine.rlsSchema.rls.context).length > 0) {
|
|
12882
|
-
await adapter.executeUnsafe(renderRlsContext({ dialect: engine.dialect, context: engine.rlsSchema.rls.context, values: engine.context.settings }));
|
|
13105
|
+
await adapter.executeUnsafe({ ...renderRlsContext({ dialect: engine.dialect, context: engine.rlsSchema.rls.context, values: engine.context.settings }), effect: "read" });
|
|
12883
13106
|
}
|
|
12884
13107
|
const readiness = await inspectNativeRlsTransaction({ adapter, schema: engine.rlsSchema, runtimeRole: engine.options.nativeRls?.runtimeRole, cacheKey: engine.rootIdentity });
|
|
12885
13108
|
assertNativeRlsReady({ report: readiness });
|
|
@@ -13052,7 +13275,7 @@ class QueryPromise extends Promise {
|
|
|
13052
13275
|
}
|
|
13053
13276
|
#claim() {
|
|
13054
13277
|
if (this.#started) {
|
|
13055
|
-
throw new
|
|
13278
|
+
throw new VibeError34({
|
|
13056
13279
|
code: "VIBE_VALIDATION",
|
|
13057
13280
|
message: "$transaction([...]) needs operations that have not dispatched \u2014 pass delegate calls in the same tick they are created (this one was awaited or created earlier and already executed outside the transaction)"
|
|
13058
13281
|
});
|
|
@@ -13097,6 +13320,21 @@ var LAZY_OPERATIONS = {
|
|
|
13097
13320
|
refuseQueryPromise({ value: params.value, reason: params.reason });
|
|
13098
13321
|
}
|
|
13099
13322
|
};
|
|
13323
|
+
function statementEffect(params) {
|
|
13324
|
+
if (params.adapter.rowChanges === undefined)
|
|
13325
|
+
return;
|
|
13326
|
+
const { statement, dialect } = params;
|
|
13327
|
+
if (containsSqlFragment(statement))
|
|
13328
|
+
return "unknown";
|
|
13329
|
+
if (statement.kind === "select" || statement.kind === "advisoryLock" || statement.kind === "rlsContext" || statement.kind === "rlsRole")
|
|
13330
|
+
return "read";
|
|
13331
|
+
if (statement.kind === "insert") {
|
|
13332
|
+
if (dialect.upsertForm === "onDuplicateKey" && statement.onConflict !== undefined && !("doNothing" in statement.onConflict))
|
|
13333
|
+
return "unknown";
|
|
13334
|
+
return "write";
|
|
13335
|
+
}
|
|
13336
|
+
return statement.kind === "update" || statement.kind === "delete" ? "write" : "unknown";
|
|
13337
|
+
}
|
|
13100
13338
|
async function runRows(params) {
|
|
13101
13339
|
const { engine, plan } = params;
|
|
13102
13340
|
const renderStarted = renderClock({ engine });
|
|
@@ -13116,17 +13354,19 @@ async function runRows(params) {
|
|
|
13116
13354
|
rowCount: (value) => value.length,
|
|
13117
13355
|
run: () => engine.adapter.execute({
|
|
13118
13356
|
text: rendered.text,
|
|
13119
|
-
values: bindValues({ adapter: engine.adapter, values: rendered.values })
|
|
13357
|
+
values: bindValues({ adapter: engine.adapter, values: rendered.values }),
|
|
13358
|
+
effect: statementEffect({ statement: plan.statement, dialect: engine.dialect, adapter: engine.adapter })
|
|
13120
13359
|
})
|
|
13121
13360
|
});
|
|
13122
13361
|
return materializeRows({ dialect: engine.dialect.name, model: plan.model, rows, wire: engine.adapter.wire });
|
|
13123
13362
|
}
|
|
13124
13363
|
async function runBoundAffected(params) {
|
|
13125
|
-
const { adapter, text, values } = params;
|
|
13364
|
+
const { adapter, text, values, effect } = params;
|
|
13365
|
+
const input = { text, values, ...effect === undefined ? {} : { effect } };
|
|
13126
13366
|
const bound = adapter.executeAffected;
|
|
13127
13367
|
if (bound !== undefined)
|
|
13128
|
-
return await bound.call(adapter,
|
|
13129
|
-
return await adapter.executeUnsafe(
|
|
13368
|
+
return await bound.call(adapter, input);
|
|
13369
|
+
return await adapter.executeUnsafe(input);
|
|
13130
13370
|
}
|
|
13131
13371
|
async function runAffected(params) {
|
|
13132
13372
|
const { engine, plan } = params;
|
|
@@ -13159,7 +13399,8 @@ async function runAffected(params) {
|
|
|
13159
13399
|
run: () => runBoundAffected({
|
|
13160
13400
|
adapter: engine.adapter,
|
|
13161
13401
|
text: rendered.text,
|
|
13162
|
-
values: bindValues({ adapter: engine.adapter, values: rendered.values })
|
|
13402
|
+
values: bindValues({ adapter: engine.adapter, values: rendered.values }),
|
|
13403
|
+
effect: statementEffect({ statement: plan.statement, dialect: engine.dialect, adapter: engine.adapter })
|
|
13163
13404
|
})
|
|
13164
13405
|
});
|
|
13165
13406
|
return result.affectedRows;
|
|
@@ -13170,14 +13411,14 @@ function plan(params) {
|
|
|
13170
13411
|
const args = engine.readOnlySql === true ? restrictedSqlArgs({ value: params.args, path: "$readOnly", refusal: () => readOnlyRefusal({ path: `${model}.${method}`, reason: "raw" }) }) : params.args;
|
|
13171
13412
|
if (args !== undefined && args["lock"] !== undefined) {
|
|
13172
13413
|
if (engine.inTransaction !== true) {
|
|
13173
|
-
throw new
|
|
13414
|
+
throw new VibeError34({
|
|
13174
13415
|
code: "VIBE_VALIDATION",
|
|
13175
13416
|
message: `lock on ${model}.${method}() requires a transaction \u2014 call it on the client $transaction hands its callback (outside one, the lock would release at statement end)`,
|
|
13176
13417
|
meta: { model, method }
|
|
13177
13418
|
});
|
|
13178
13419
|
}
|
|
13179
13420
|
if (!LOCKABLE_METHODS.includes(method)) {
|
|
13180
|
-
throw new
|
|
13421
|
+
throw new VibeError34({
|
|
13181
13422
|
code: "VIBE_VALIDATION",
|
|
13182
13423
|
message: `lock on ${model}.${method}() is not supported \u2014 only ${LOCKABLE_METHODS.join(", ")} take a lock. ` + `Lock the rows with a find inside the transaction, then write them`,
|
|
13183
13424
|
meta: { model, method }
|
|
@@ -13204,7 +13445,7 @@ function readAcquiredVerdict(params) {
|
|
|
13204
13445
|
return true;
|
|
13205
13446
|
if (value === false || value === 0 || value === "f" || value === "false" || value === "0")
|
|
13206
13447
|
return false;
|
|
13207
|
-
throw new
|
|
13448
|
+
throw new VibeError34({
|
|
13208
13449
|
code: "VIBE_INTERNAL",
|
|
13209
13450
|
message: `internal: ${params.method}() expected a boolean "${ADVISORY_LOCK_RESULT_COLUMN}" column, got ${String(value)}`,
|
|
13210
13451
|
meta: { method: params.method, value: String(value) }
|
|
@@ -13246,7 +13487,7 @@ async function insertedKeyWhere(params) {
|
|
|
13246
13487
|
const keyField = source.model.primaryKey[0];
|
|
13247
13488
|
const lastInsertIdSql = engine.dialect.lastInsertIdSql;
|
|
13248
13489
|
if (lastInsertIdSql === null || source.model.primaryKey.length !== 1 || keyField === undefined) {
|
|
13249
|
-
throw
|
|
13490
|
+
throw unsupportedCapability9({
|
|
13250
13491
|
dialect: engine.dialect.name,
|
|
13251
13492
|
feature: `${source.method} on ${source.model.name} without RETURNING`,
|
|
13252
13493
|
hint: "this model's key is assigned by the database and cannot be read back on this dialect"
|
|
@@ -13264,11 +13505,11 @@ async function insertedKeyWhere(params) {
|
|
|
13264
13505
|
text: lastInsertIdSql,
|
|
13265
13506
|
values: [],
|
|
13266
13507
|
rowCount: (value) => value.rows.length,
|
|
13267
|
-
run: () => engine.adapter.executeUnsafe({ text: lastInsertIdSql })
|
|
13508
|
+
run: () => engine.adapter.executeUnsafe({ text: lastInsertIdSql, effect: "read" })
|
|
13268
13509
|
});
|
|
13269
13510
|
const id = result.rows[0]?.id;
|
|
13270
13511
|
if (id === undefined || id === null) {
|
|
13271
|
-
throw new
|
|
13512
|
+
throw new VibeError34({
|
|
13272
13513
|
code: "VIBE_INTERNAL",
|
|
13273
13514
|
message: `could not read back the generated key for ${source.model.name}`,
|
|
13274
13515
|
meta: { model: source.model.name }
|
|
@@ -13303,7 +13544,8 @@ async function runSingleMutation(params) {
|
|
|
13303
13544
|
run: () => runBoundAffected({
|
|
13304
13545
|
adapter: target.adapter,
|
|
13305
13546
|
text: rendered.text,
|
|
13306
|
-
values: bindValues({ adapter: target.adapter, values: rendered.values })
|
|
13547
|
+
values: bindValues({ adapter: target.adapter, values: rendered.values }),
|
|
13548
|
+
effect: statementEffect({ statement, dialect: target.dialect, adapter: target.adapter })
|
|
13307
13549
|
})
|
|
13308
13550
|
});
|
|
13309
13551
|
return result;
|
|
@@ -13439,7 +13681,8 @@ function relationExecutor(params) {
|
|
|
13439
13681
|
rowCount: (value) => value.length,
|
|
13440
13682
|
run: () => engine.adapter.execute({
|
|
13441
13683
|
text: rendered.text,
|
|
13442
|
-
values: bindValues({ adapter: engine.adapter, values: rendered.values })
|
|
13684
|
+
values: bindValues({ adapter: engine.adapter, values: rendered.values }),
|
|
13685
|
+
effect: statementEffect({ statement, dialect: engine.dialect, adapter: engine.adapter })
|
|
13443
13686
|
})
|
|
13444
13687
|
});
|
|
13445
13688
|
};
|
|
@@ -13521,7 +13764,8 @@ function makeRunner(params) {
|
|
|
13521
13764
|
rowCount: (value) => value.length,
|
|
13522
13765
|
run: () => engine.adapter.execute({
|
|
13523
13766
|
text: rendered.text,
|
|
13524
|
-
values: bindValues({ adapter: engine.adapter, values: rendered.values })
|
|
13767
|
+
values: bindValues({ adapter: engine.adapter, values: rendered.values }),
|
|
13768
|
+
effect: statementEffect({ statement, dialect: engine.dialect, adapter: engine.adapter })
|
|
13525
13769
|
})
|
|
13526
13770
|
});
|
|
13527
13771
|
}
|
|
@@ -13575,6 +13819,16 @@ function createDelegate(params) {
|
|
|
13575
13819
|
const rows = shapeRows({ plan: built, rows: await runRows({ engine: target, plan: built }) });
|
|
13576
13820
|
return await finalizeRows({ engine: target, model: built.model, shape: shapeOf(built), rows });
|
|
13577
13821
|
};
|
|
13822
|
+
const findPage = async (target, input) => {
|
|
13823
|
+
const args = validatePageArgs({ model, args: input });
|
|
13824
|
+
const original = plan({ engine: target, model, method: "findMany", args });
|
|
13825
|
+
const page = preparePage({ meta: target.meta, model: original.model, dialect: target.dialect, args });
|
|
13826
|
+
const built = plan({ engine: target, model, method: "findMany", args: page.args });
|
|
13827
|
+
const rows = await runRows({ engine: target, plan: built });
|
|
13828
|
+
const nextCursor = pageContinuation({ plan: page.plan, rows, take: args.take, after: args.after });
|
|
13829
|
+
const items = await finalizeRows({ engine: target, model: built.model, shape: shapeOf(original), rows: rows.slice(0, args.take) });
|
|
13830
|
+
return { items, nextCursor };
|
|
13831
|
+
};
|
|
13578
13832
|
const findFirst = async (target, args) => {
|
|
13579
13833
|
const built = plan({ engine: target, model, method: "findFirst", args });
|
|
13580
13834
|
const rows = shapeRows({ plan: built, rows: await runRows({ engine: target, plan: built }) });
|
|
@@ -13596,7 +13850,7 @@ function createDelegate(params) {
|
|
|
13596
13850
|
const skipping = args.onConflict !== undefined;
|
|
13597
13851
|
if (hasNestedWrites({ model: modelMeta, data: args.data })) {
|
|
13598
13852
|
if (skipping) {
|
|
13599
|
-
throw new
|
|
13853
|
+
throw new VibeError34({
|
|
13600
13854
|
code: "VIBE_VALIDATION",
|
|
13601
13855
|
message: `onConflict cannot combine with nested writes on ${modelMeta.name}.create() \u2014 insert the parent row alone, then connect relations`,
|
|
13602
13856
|
meta: { model: modelMeta.name }
|
|
@@ -13697,7 +13951,7 @@ function createDelegate(params) {
|
|
|
13697
13951
|
const upsert = async (target, args) => {
|
|
13698
13952
|
const modelMeta = getModelMeta({ meta: target.meta, model });
|
|
13699
13953
|
if (hasNestedWrites({ model: modelMeta, data: args.create }) || hasNestedWrites({ model: modelMeta, data: args.update })) {
|
|
13700
|
-
throw new
|
|
13954
|
+
throw new VibeError34({
|
|
13701
13955
|
code: "VIBE_VALIDATION",
|
|
13702
13956
|
message: `nested writes are not supported inside upsert arms on ${modelMeta.name} \u2014 use create()/update() with nested data`,
|
|
13703
13957
|
meta: { model: modelMeta.name }
|
|
@@ -13705,7 +13959,7 @@ function createDelegate(params) {
|
|
|
13705
13959
|
}
|
|
13706
13960
|
if (!upsertUsesNativeStatement({ model: modelMeta, args })) {
|
|
13707
13961
|
if (args.onConflict !== undefined) {
|
|
13708
|
-
throw new
|
|
13962
|
+
throw new VibeError34({
|
|
13709
13963
|
code: "VIBE_VALIDATION",
|
|
13710
13964
|
message: `onConflict on ${modelMeta.name}.upsert() needs the native single-statement path \u2014 this shape (a guard field beyond the conflict target, or create data not binding the where's key) runs the find-then-write fallback, which cannot honor an explicit conflict target`,
|
|
13711
13965
|
meta: { model: modelMeta.name }
|
|
@@ -13763,7 +14017,8 @@ function createDelegate(params) {
|
|
|
13763
14017
|
rowCount: (value) => value.length,
|
|
13764
14018
|
run: () => target.adapter.execute({
|
|
13765
14019
|
text: rendered.text,
|
|
13766
|
-
values: bindValues({ adapter: target.adapter, values: rendered.values })
|
|
14020
|
+
values: bindValues({ adapter: target.adapter, values: rendered.values }),
|
|
14021
|
+
effect: statementEffect({ statement: built.statement, dialect: target.dialect, adapter: target.adapter })
|
|
13767
14022
|
})
|
|
13768
14023
|
});
|
|
13769
14024
|
if (built.aggregateSpec !== null) {
|
|
@@ -13803,6 +14058,7 @@ function createDelegate(params) {
|
|
|
13803
14058
|
const lazy = (method, run) => createQueryPromise({ engine, run, model, method });
|
|
13804
14059
|
const delegate = {
|
|
13805
14060
|
findMany: (args) => lazy("findMany", (target) => findMany(target, args)),
|
|
14061
|
+
findPage: (args) => lazy("findPage", (target) => findPage(target, args)),
|
|
13806
14062
|
findFirst: (args) => lazy("findFirst", (target) => findFirst(target, args)),
|
|
13807
14063
|
findUnique: (args) => lazy("findUnique", (target) => findUnique(target, args)),
|
|
13808
14064
|
findFirstOrThrow: (args) => lazy("findFirstOrThrow", async (target) => {
|
|
@@ -13954,7 +14210,8 @@ function buildClient(params) {
|
|
|
13954
14210
|
run: () => runBoundAffected({
|
|
13955
14211
|
adapter: target.adapter,
|
|
13956
14212
|
text: rendered.text,
|
|
13957
|
-
values: bindValues({ adapter: target.adapter, values: rendered.values })
|
|
14213
|
+
values: bindValues({ adapter: target.adapter, values: rendered.values }),
|
|
14214
|
+
effect: statementEffect({ statement, dialect: target.dialect, adapter: target.adapter })
|
|
13958
14215
|
})
|
|
13959
14216
|
});
|
|
13960
14217
|
if (scope !== undefined)
|
|
@@ -13983,7 +14240,7 @@ function buildClient(params) {
|
|
|
13983
14240
|
}
|
|
13984
14241
|
for (const operation of operations) {
|
|
13985
14242
|
if (!isQueryPromise(operation)) {
|
|
13986
|
-
claimError = new
|
|
14243
|
+
claimError = new VibeError34({
|
|
13987
14244
|
code: "VIBE_VALIDATION",
|
|
13988
14245
|
message: "$transaction([...]) takes query promises from model delegate calls \u2014 a foreign promise is already running and cannot join the transaction"
|
|
13989
14246
|
});
|
|
@@ -14048,7 +14305,7 @@ function buildClient(params) {
|
|
|
14048
14305
|
$models: models,
|
|
14049
14306
|
$on: (event, listener) => {
|
|
14050
14307
|
if (event !== "query") {
|
|
14051
|
-
throw new
|
|
14308
|
+
throw new VibeError34({
|
|
14052
14309
|
code: "VIBE_VALIDATION",
|
|
14053
14310
|
message: `unknown client event "${String(event)}" \u2014 supported: "query"`,
|
|
14054
14311
|
meta: { event }
|
|
@@ -14063,7 +14320,7 @@ function buildClient(params) {
|
|
|
14063
14320
|
$querySql: async ({ query, decoder }) => {
|
|
14064
14321
|
assertEngineActive({ engine });
|
|
14065
14322
|
if (decoder === null || typeof decoder !== "object" || typeof decoder.decode !== "function")
|
|
14066
|
-
throw new
|
|
14323
|
+
throw new VibeError34({ code: "VIBE_VALIDATION", message: "$querySql requires an explicit result decoder" });
|
|
14067
14324
|
const statement = compileSql({ dialect: engine.dialect, query });
|
|
14068
14325
|
let output = [];
|
|
14069
14326
|
await runRaw("$querySql", statement, (rows) => {
|
|
@@ -14086,7 +14343,7 @@ function buildClient(params) {
|
|
|
14086
14343
|
$connect: async () => {
|
|
14087
14344
|
assertEngineActive({ engine, requireContext: false });
|
|
14088
14345
|
if (engine.borrowedModule === true)
|
|
14089
|
-
throw new
|
|
14346
|
+
throw new VibeError34({ code: "VIBE_VALIDATION", message: "A package module borrows its adapter; the application owns connection lifecycle", meta: { reason: "module_borrowed_lifecycle", method: "$connect" } });
|
|
14090
14347
|
if (engine.inTransaction === true)
|
|
14091
14348
|
throw transactionLifecycleRefusal({ method: "$connect" });
|
|
14092
14349
|
if (engine.rlsSchema !== undefined) {
|
|
@@ -14108,7 +14365,7 @@ function buildClient(params) {
|
|
|
14108
14365
|
$disconnect: async () => {
|
|
14109
14366
|
assertEngineActive({ engine, requireContext: false });
|
|
14110
14367
|
if (engine.borrowedModule === true)
|
|
14111
|
-
throw new
|
|
14368
|
+
throw new VibeError34({ code: "VIBE_VALIDATION", message: "A package module borrows its adapter; the application owns connection lifecycle", meta: { reason: "module_borrowed_lifecycle", method: "$disconnect" } });
|
|
14112
14369
|
if (engine.inTransaction === true)
|
|
14113
14370
|
throw transactionLifecycleRefusal({ method: "$disconnect" });
|
|
14114
14371
|
await engine.diagnostics?.flush();
|
|
@@ -14140,11 +14397,12 @@ function buildClient(params) {
|
|
|
14140
14397
|
client,
|
|
14141
14398
|
meta: engine.meta,
|
|
14142
14399
|
...engine.extensionMounts === undefined ? {} : { mounts: engine.extensionMounts },
|
|
14143
|
-
operations: LAZY_OPERATIONS
|
|
14400
|
+
operations: LAZY_OPERATIONS,
|
|
14401
|
+
assertActive: () => assertEngineActive({ engine })
|
|
14144
14402
|
});
|
|
14145
14403
|
} else {
|
|
14146
14404
|
const refuseLegacy = () => {
|
|
14147
|
-
throw new
|
|
14405
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: "Native row-level security cannot be combined with application policy or tenant scoping" });
|
|
14148
14406
|
};
|
|
14149
14407
|
Object.defineProperties(client, {
|
|
14150
14408
|
$withContext: { enumerable: true, value: (context) => {
|
|
@@ -14162,7 +14420,8 @@ function buildClient(params) {
|
|
|
14162
14420
|
client,
|
|
14163
14421
|
meta: engine.meta,
|
|
14164
14422
|
...engine.extensionMounts === undefined ? {} : { mounts: engine.extensionMounts },
|
|
14165
|
-
operations: LAZY_OPERATIONS
|
|
14423
|
+
operations: LAZY_OPERATIONS,
|
|
14424
|
+
assertActive: () => assertEngineActive({ engine })
|
|
14166
14425
|
});
|
|
14167
14426
|
}
|
|
14168
14427
|
for (const delegate of Object.values(models))
|
|
@@ -14173,12 +14432,12 @@ function buildClient(params) {
|
|
|
14173
14432
|
registerModuleBinder({ client, bind: ({ schema, manifest }) => {
|
|
14174
14433
|
assertEngineActive({ engine, requireContext: false });
|
|
14175
14434
|
if (engine.rlsSchema !== undefined || engine.meta.models.some((model) => model.policy !== undefined))
|
|
14176
|
-
throw new
|
|
14435
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: `Module ${manifest.id} cannot attach models to a policy or native-RLS context`, meta: { reason: "module_restricted_context", moduleId: manifest.id } });
|
|
14177
14436
|
if (manifest.dialect !== engine.dialect.name)
|
|
14178
|
-
throw new
|
|
14437
|
+
throw new VibeError34({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Module ${manifest.id} requires ${manifest.dialect}, received ${engine.dialect.name}`, meta: { reason: "module_dialect", moduleId: manifest.id } });
|
|
14179
14438
|
const previous = engine.moduleManifests.get(manifest.id);
|
|
14180
14439
|
if (previous !== undefined && (previous.schemaChecksum !== manifest.schemaChecksum || previous.revision !== manifest.revision || previous.contract !== manifest.contract))
|
|
14181
|
-
throw new
|
|
14440
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: `Module ${manifest.id} was already bound with a different manifest; use compatible package artifacts`, meta: { reason: "module_manifest_conflict", moduleId: manifest.id, revision: manifest.revision } });
|
|
14182
14441
|
let meta = moduleMetadata.get(schema);
|
|
14183
14442
|
if (meta === undefined) {
|
|
14184
14443
|
meta = buildRuntimeMeta({ schema });
|
|
@@ -14189,8 +14448,14 @@ function buildClient(params) {
|
|
|
14189
14448
|
const { validate: _validate, ...options } = engine.options;
|
|
14190
14449
|
return buildClient({ engine: { ...engine, meta, options, borrowedModule: true, extensionMounts: [], connectHooks: [], renderCache: new StatementRenderCache } });
|
|
14191
14450
|
} });
|
|
14451
|
+
registerTransactionObservation({ db: client, observation: {
|
|
14452
|
+
inTransaction: engine.inTransaction === true,
|
|
14453
|
+
assertActive: () => assertEngineActive({ engine }),
|
|
14454
|
+
read: () => engine.adapter.rowChanges?.() ?? "unknown"
|
|
14455
|
+
} });
|
|
14192
14456
|
return client;
|
|
14193
14457
|
}
|
|
14458
|
+
var EXTENSION_EFFECT = new AsyncLocalStorage;
|
|
14194
14459
|
function makeMountContext(params) {
|
|
14195
14460
|
const { engine, extension, model } = params;
|
|
14196
14461
|
return {
|
|
@@ -14220,7 +14485,8 @@ function makeMountContext(params) {
|
|
|
14220
14485
|
rowCount: (value) => value.length,
|
|
14221
14486
|
run: () => target.adapter.execute({
|
|
14222
14487
|
text,
|
|
14223
|
-
values: bindValues({ adapter: target.adapter, values: [...values] })
|
|
14488
|
+
values: bindValues({ adapter: target.adapter, values: [...values] }),
|
|
14489
|
+
effect: EXTENSION_EFFECT.getStore() ?? "unknown"
|
|
14224
14490
|
})
|
|
14225
14491
|
});
|
|
14226
14492
|
return model === null ? rows : materializeRows({ dialect: target.dialect.name, model, rows, wire: target.adapter.wire });
|
|
@@ -14233,7 +14499,7 @@ function makeMountContext(params) {
|
|
|
14233
14499
|
compileWhere: ({ where, model: modelName, qualify }) => {
|
|
14234
14500
|
const target = modelName === undefined ? model : getModelMeta({ meta: engine.meta, model: modelName });
|
|
14235
14501
|
if (target === null) {
|
|
14236
|
-
throw new
|
|
14502
|
+
throw new VibeError34({
|
|
14237
14503
|
code: "VIBE_INTERNAL",
|
|
14238
14504
|
message: `extension "${extension}" compiled a where with no model in scope`,
|
|
14239
14505
|
meta: { extension }
|
|
@@ -14253,8 +14519,27 @@ function makeMountContext(params) {
|
|
|
14253
14519
|
function createMountSurface(params) {
|
|
14254
14520
|
const { engine, mount, model } = params;
|
|
14255
14521
|
const original = mount.create(makeMountContext({ engine, extension: mount.extension, model }));
|
|
14522
|
+
const effectOf = (path, args) => {
|
|
14523
|
+
if (containsSqlFragment(args))
|
|
14524
|
+
return "unknown";
|
|
14525
|
+
return mount.readOnly === true && path.length === 0 || Array.isArray(mount.readOnly) && path.length === 1 && mount.readOnly.includes(String(path[0])) ? "read" : "unknown";
|
|
14526
|
+
};
|
|
14527
|
+
const wrapEffects = (value, path) => {
|
|
14528
|
+
if (typeof value === "function")
|
|
14529
|
+
return function(...args) {
|
|
14530
|
+
return EXTENSION_EFFECT.run(effectOf(path, args), () => Reflect.apply(value, this, args));
|
|
14531
|
+
};
|
|
14532
|
+
if (value === null || typeof value !== "object" || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
|
|
14533
|
+
return value;
|
|
14534
|
+
const result = Object.create(Object.getPrototypeOf(value));
|
|
14535
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
14536
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
14537
|
+
Object.defineProperty(result, key, "value" in descriptor ? { ...descriptor, value: wrapEffects(descriptor.value, [...path, key]) } : descriptor);
|
|
14538
|
+
}
|
|
14539
|
+
return result;
|
|
14540
|
+
};
|
|
14256
14541
|
if (engine.rlsSchema === undefined)
|
|
14257
|
-
return original;
|
|
14542
|
+
return wrapEffects(original, []);
|
|
14258
14543
|
const wrap = (value, path) => {
|
|
14259
14544
|
if (typeof value === "function") {
|
|
14260
14545
|
return (...args) => createQueryPromise({ engine, run: async (target) => {
|
|
@@ -14263,24 +14548,24 @@ function createMountSurface(params) {
|
|
|
14263
14548
|
for (const key of path) {
|
|
14264
14549
|
receiver = current;
|
|
14265
14550
|
if (current === null || typeof current !== "object" && typeof current !== "function")
|
|
14266
|
-
throw new
|
|
14551
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: "Extension mount changed its method shape" });
|
|
14267
14552
|
current = Reflect.get(current, key);
|
|
14268
14553
|
}
|
|
14269
14554
|
if (typeof current !== "function")
|
|
14270
|
-
throw new
|
|
14271
|
-
return Reflect.apply(current, receiver, args);
|
|
14555
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: "Extension mount changed its method shape" });
|
|
14556
|
+
return EXTENSION_EFFECT.run(effectOf(path, args), () => Reflect.apply(current, receiver, args));
|
|
14272
14557
|
} });
|
|
14273
14558
|
}
|
|
14274
14559
|
if (value === null || typeof value !== "object")
|
|
14275
14560
|
return value;
|
|
14276
14561
|
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
14277
|
-
throw new
|
|
14562
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: "Native RLS extension mounts must expose plain objects and methods" });
|
|
14278
14563
|
}
|
|
14279
14564
|
const result = {};
|
|
14280
14565
|
for (const key of Reflect.ownKeys(value)) {
|
|
14281
14566
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
14282
14567
|
if (!("value" in descriptor))
|
|
14283
|
-
throw new
|
|
14568
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: "Native RLS extension mount accessors are unsupported" });
|
|
14284
14569
|
Object.defineProperty(result, key, { value: wrap(descriptor.value, [...path, key]), enumerable: descriptor.enumerable });
|
|
14285
14570
|
}
|
|
14286
14571
|
return Object.freeze(result);
|
|
@@ -14297,7 +14582,7 @@ function attachExtensionMounts(params) {
|
|
|
14297
14582
|
const model = getModelMeta({ meta: engine.meta, model: mount.model ?? "" });
|
|
14298
14583
|
const delegate = models[model.name];
|
|
14299
14584
|
if (delegate === undefined || mount.property in delegate) {
|
|
14300
|
-
throw new
|
|
14585
|
+
throw new VibeError34({
|
|
14301
14586
|
code: "VIBE_CONFIG",
|
|
14302
14587
|
message: `extension "${mount.extension}" cannot mount "${mount.property}" on ${model.name} \u2014 the name is taken`,
|
|
14303
14588
|
meta: { extension: mount.extension, model: model.name, property: mount.property }
|
|
@@ -14308,7 +14593,7 @@ function attachExtensionMounts(params) {
|
|
|
14308
14593
|
continue;
|
|
14309
14594
|
}
|
|
14310
14595
|
if (!mount.property.startsWith("$") || mount.property in client) {
|
|
14311
|
-
throw new
|
|
14596
|
+
throw new VibeError34({
|
|
14312
14597
|
code: "VIBE_CONFIG",
|
|
14313
14598
|
message: `extension "${mount.extension}" cannot mount client property "${mount.property}" \u2014 root mounts are $-prefixed and must not collide`,
|
|
14314
14599
|
meta: { extension: mount.extension, property: mount.property }
|
|
@@ -14334,7 +14619,7 @@ function createClient(params) {
|
|
|
14334
14619
|
if (schema.rls !== undefined) {
|
|
14335
14620
|
const dialect = getSqlDialect5({ dialect: dialectName });
|
|
14336
14621
|
if (!dialect.capabilities.nativeRowLevelSecurity)
|
|
14337
|
-
throw
|
|
14622
|
+
throw unsupportedCapability9({ dialect: dialectName, feature: "nativeRowLevelSecurity" });
|
|
14338
14623
|
assertValidSchemaIR2({ schema });
|
|
14339
14624
|
for (const model of schema.models) {
|
|
14340
14625
|
if (model.rls !== "unprotected")
|
|
@@ -14343,9 +14628,9 @@ function createClient(params) {
|
|
|
14343
14628
|
const role = options?.nativeRls?.runtimeRole;
|
|
14344
14629
|
if (adapter.provider === "pglite") {
|
|
14345
14630
|
if (typeof role !== "string" || role.length === 0 || role.includes("\x00"))
|
|
14346
|
-
throw new
|
|
14631
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: "PGlite native row-level security requires a pre-existing restricted runtimeRole; embedded binding is not a boundary against the host process" });
|
|
14347
14632
|
} else if (role !== undefined) {
|
|
14348
|
-
throw new
|
|
14633
|
+
throw new VibeError34({ code: "VIBE_CONFIG", message: "Server native row-level security must use the runtime login role, not a runtimeRole switch" });
|
|
14349
14634
|
}
|
|
14350
14635
|
}
|
|
14351
14636
|
if (extensions?.manifest !== undefined) {
|
|
@@ -14355,7 +14640,7 @@ function createClient(params) {
|
|
|
14355
14640
|
assertComputedManifest({ manifest: computed.manifest, specs: computed.specs });
|
|
14356
14641
|
}
|
|
14357
14642
|
if (computed === undefined && options !== undefined && options["computed"] !== undefined) {
|
|
14358
|
-
throw new
|
|
14643
|
+
throw new VibeError34({
|
|
14359
14644
|
code: "VIBE_CONFIG",
|
|
14360
14645
|
message: "this client was generated without computed fields \u2014 declare them in vibeorm.config.ts and re-run vibeorm generate",
|
|
14361
14646
|
meta: {}
|
|
@@ -14408,16 +14693,17 @@ function freezeData(params) {
|
|
|
14408
14693
|
function defineDatabaseModule(params) {
|
|
14409
14694
|
for (const key of ["id", "contract", "revision"]) {
|
|
14410
14695
|
if (typeof params[key] !== "string" || params[key].trim().length === 0 || params[key].includes("\x00"))
|
|
14411
|
-
throw new
|
|
14696
|
+
throw new VibeError35({ code: "VIBE_CONFIG", message: `Database module ${key} must be a non-empty identifier`, meta: { reason: "module_manifest", key } });
|
|
14412
14697
|
}
|
|
14413
|
-
|
|
14414
|
-
|
|
14415
|
-
|
|
14698
|
+
const preparedSchema = prepareDatabaseModuleSchema({ schema: params.schema, module: params });
|
|
14699
|
+
assertValidSchemaIR3({ schema: preparedSchema });
|
|
14700
|
+
if (preparedSchema.rls !== undefined || preparedSchema.extensions.length > 0 || preparedSchema.models.some((model) => model.policy !== undefined))
|
|
14701
|
+
throw new VibeError35({
|
|
14416
14702
|
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
14417
14703
|
message: `Module ${params.id} cannot declare extensions, policy or native RLS in this module protocol`,
|
|
14418
14704
|
meta: { reason: "module_schema_feature", moduleId: params.id }
|
|
14419
14705
|
});
|
|
14420
|
-
const serialized = JSON.stringify(canonicalValue({ value:
|
|
14706
|
+
const serialized = JSON.stringify(canonicalValue({ value: preparedSchema }));
|
|
14421
14707
|
const schema = JSON.parse(serialized);
|
|
14422
14708
|
freezeData({ value: schema });
|
|
14423
14709
|
const manifest = Object.freeze({
|
|
@@ -14425,11 +14711,12 @@ function defineDatabaseModule(params) {
|
|
|
14425
14711
|
contract: params.contract,
|
|
14426
14712
|
revision: params.revision,
|
|
14427
14713
|
protocol: 1,
|
|
14714
|
+
...params.namespace === undefined ? {} : { namespace: params.namespace },
|
|
14428
14715
|
dialect: providerToDialect({ provider: schema.datasource.provider }),
|
|
14429
|
-
schemaChecksum:
|
|
14716
|
+
schemaChecksum: createHash2("sha256").update(serialized).digest("hex")
|
|
14430
14717
|
});
|
|
14431
|
-
if (params.manifest !== undefined && Object.keys(manifest).some((key) => params.manifest[key] !== manifest[key]))
|
|
14432
|
-
throw new
|
|
14718
|
+
if (params.manifest !== undefined && (params.manifest.namespace !== manifest.namespace || Object.keys(manifest).some((key) => params.manifest[key] !== manifest[key])))
|
|
14719
|
+
throw new VibeError35({
|
|
14433
14720
|
code: "VIBE_STALE_CLIENT",
|
|
14434
14721
|
message: `Module ${params.id} has incompatible or modified generated metadata; regenerate with a compatible runtime`,
|
|
14435
14722
|
meta: { reason: "module_artifact", moduleId: params.id, revision: params.revision, protocol: params.manifest.protocol }
|
|
@@ -14439,32 +14726,9 @@ function defineDatabaseModule(params) {
|
|
|
14439
14726
|
return Object.freeze({ ...artifact, bind, create: ({ adapter }) => bind({ db: createClient({ schema, adapter }) }) });
|
|
14440
14727
|
}
|
|
14441
14728
|
// packages/runtime/src/keyset-iterator.ts
|
|
14442
|
-
import { VibeError as
|
|
14729
|
+
import { VibeError as VibeError36 } from "@vibeorm/schema";
|
|
14443
14730
|
function validation(params) {
|
|
14444
|
-
return new
|
|
14445
|
-
}
|
|
14446
|
-
function projectionFor(params) {
|
|
14447
|
-
const { plan, select, omit } = params;
|
|
14448
|
-
const names = plan.keys.map((key) => key.field.name);
|
|
14449
|
-
if (select !== undefined) {
|
|
14450
|
-
const hidden = names.filter((name) => select[name] !== true);
|
|
14451
|
-
if (hidden.length === 0)
|
|
14452
|
-
return { select, hidden };
|
|
14453
|
-
const widened = { ...select };
|
|
14454
|
-
for (const name of hidden)
|
|
14455
|
-
widened[name] = true;
|
|
14456
|
-
return { select: widened, hidden };
|
|
14457
|
-
}
|
|
14458
|
-
if (omit !== undefined) {
|
|
14459
|
-
const hidden = names.filter((name) => omit[name] === true);
|
|
14460
|
-
if (hidden.length === 0)
|
|
14461
|
-
return { omit, hidden };
|
|
14462
|
-
const narrowed = { ...omit };
|
|
14463
|
-
for (const name of hidden)
|
|
14464
|
-
narrowed[name] = false;
|
|
14465
|
-
return { omit: narrowed, hidden };
|
|
14466
|
-
}
|
|
14467
|
-
return { hidden: [] };
|
|
14731
|
+
return new VibeError36({ code: "VIBE_VALIDATION", message: params.message, meta: params.meta });
|
|
14468
14732
|
}
|
|
14469
14733
|
function iterateKeyset(options) {
|
|
14470
14734
|
const { source, meta, dialect, orderBy, pageSize, signal } = options;
|
|
@@ -14481,7 +14745,7 @@ function iterateKeyset(options) {
|
|
|
14481
14745
|
terms: compileKeysetOrderInputs({ dialect, meta, model, orderBy }),
|
|
14482
14746
|
...options.timestampPrecision === undefined ? {} : { timestampPrecision: options.timestampPrecision }
|
|
14483
14747
|
});
|
|
14484
|
-
const projection =
|
|
14748
|
+
const projection = keysetProjection({ plan, select: options.select, omit: options.omit });
|
|
14485
14749
|
const keysetArg = options.timestampPrecision === undefined ? {} : { keyset: { timestampPrecision: options.timestampPrecision } };
|
|
14486
14750
|
let buffer = [];
|
|
14487
14751
|
let position = options.after ?? null;
|
|
@@ -14518,7 +14782,7 @@ function iterateKeyset(options) {
|
|
|
14518
14782
|
});
|
|
14519
14783
|
if (advanced === false) {
|
|
14520
14784
|
stop();
|
|
14521
|
-
throw new
|
|
14785
|
+
throw new VibeError36({
|
|
14522
14786
|
code: "VIBE_DATA_INVALID",
|
|
14523
14787
|
message: `keyset traversal of "${options.model}" is not advancing: the engine returned a row that does not sort after the previous position. ` + "The ordering is not total, or a cursor value lost precision \u2014 a DateTime column finer than milliseconds asserted as millisecond-exact does this.",
|
|
14524
14788
|
meta: { model: options.model, order: plan.signature, reason: "keyset-position-not-advancing" }
|
|
@@ -14591,7 +14855,7 @@ function iterateKeyset(options) {
|
|
|
14591
14855
|
return iterator;
|
|
14592
14856
|
}
|
|
14593
14857
|
// packages/runtime/src/telemetry/collector.ts
|
|
14594
|
-
import { VibeError as
|
|
14858
|
+
import { VibeError as VibeError37 } from "@vibeorm/schema";
|
|
14595
14859
|
function createTelemetryCollector(params) {
|
|
14596
14860
|
const throwOn = new Set(params?.throwOn ?? []);
|
|
14597
14861
|
const operations = [];
|
|
@@ -14601,7 +14865,7 @@ function createTelemetryCollector(params) {
|
|
|
14601
14865
|
let shutdowns = 0;
|
|
14602
14866
|
const hostile = (phase) => {
|
|
14603
14867
|
if (throwOn.has(phase)) {
|
|
14604
|
-
throw new
|
|
14868
|
+
throw new VibeError37({
|
|
14605
14869
|
code: "VIBE_INTERNAL",
|
|
14606
14870
|
message: `telemetry collector: deliberate ${phase} failure`,
|
|
14607
14871
|
meta: { reason: "telemetry-collector-deliberate-failure", phase }
|
|
@@ -14657,7 +14921,7 @@ function createTelemetryCollector(params) {
|
|
|
14657
14921
|
operationFor: (lookup) => {
|
|
14658
14922
|
const matches = operations.filter((event) => event.method === lookup.method && (lookup.model === undefined || event.model === lookup.model));
|
|
14659
14923
|
if (matches.length > 1) {
|
|
14660
|
-
throw new
|
|
14924
|
+
throw new VibeError37({
|
|
14661
14925
|
code: "VIBE_VALIDATION",
|
|
14662
14926
|
message: `telemetry collector: ${matches.length} operations match ${lookup.model ?? "*"}.${lookup.method}`,
|
|
14663
14927
|
meta: {
|
|
@@ -14691,6 +14955,7 @@ export {
|
|
|
14691
14955
|
TELEMETRY_DEFAULTS,
|
|
14692
14956
|
ViewResult,
|
|
14693
14957
|
WRITE_DELEGATE_METHODS,
|
|
14958
|
+
advisoryKeyOf,
|
|
14694
14959
|
affectedRowsAreRowCounts,
|
|
14695
14960
|
analyzeOperationTelemetry,
|
|
14696
14961
|
applyComputedFields,
|
|
@@ -14717,6 +14982,7 @@ export {
|
|
|
14717
14982
|
compileSelect,
|
|
14718
14983
|
compileWhere,
|
|
14719
14984
|
createClient,
|
|
14985
|
+
createDelegateMethodClassifier,
|
|
14720
14986
|
createScopeRewriter,
|
|
14721
14987
|
createSqlModel,
|
|
14722
14988
|
createStatementDiagnostics,
|
|
@@ -14780,8 +15046,9 @@ export {
|
|
|
14780
15046
|
summarizePlan,
|
|
14781
15047
|
toClientName,
|
|
14782
15048
|
toSqlExecutor,
|
|
15049
|
+
transactionRowChanges,
|
|
14783
15050
|
updateWithNested,
|
|
14784
15051
|
validateWriteData
|
|
14785
15052
|
};
|
|
14786
15053
|
|
|
14787
|
-
//# debugId=
|
|
15054
|
+
//# debugId=9B1DF0989FAC48E264756E2164756E21
|