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