@vibeorm/schema 5.8.0 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities.d.ts +40 -0
- package/dist/exclusion.d.ts +8 -0
- package/dist/extension.d.ts +0 -5
- package/dist/failure-kind.d.ts +72 -0
- package/dist/index-include.d.ts +18 -0
- package/dist/index.d.ts +14 -3
- package/dist/index.js +874 -42
- package/dist/index.js.map +20 -12
- package/dist/ir.d.ts +63 -0
- package/dist/native-rls-admission.d.ts +1 -1
- package/dist/partial-predicate.d.ts +18 -0
- package/dist/reserved.d.ts +0 -10
- package/dist/row-rules.d.ts +1 -22
- package/dist/sealed.d.ts +16 -0
- package/dist/suggest.d.ts +53 -0
- package/dist/table-storage.d.ts +66 -0
- package/dist/unique-keys.d.ts +48 -0
- package/dist/validate.d.ts +27 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -222,9 +222,12 @@ var RESERVED_DELEGATE_NAMES = [
|
|
|
222
222
|
"delete",
|
|
223
223
|
"deleteMany",
|
|
224
224
|
"count",
|
|
225
|
+
"exists",
|
|
225
226
|
"aggregate",
|
|
226
227
|
"groupBy",
|
|
227
|
-
"fields"
|
|
228
|
+
"fields",
|
|
229
|
+
"uniques",
|
|
230
|
+
"exclusions"
|
|
228
231
|
];
|
|
229
232
|
var RESERVED_CLIENT_NAMES = [
|
|
230
233
|
"$connect",
|
|
@@ -254,7 +257,8 @@ var RESERVED_CLIENT_NAMES = [
|
|
|
254
257
|
"$withContext",
|
|
255
258
|
"$advisoryLock",
|
|
256
259
|
"$advisoryLocks",
|
|
257
|
-
"$tryAdvisoryLock"
|
|
260
|
+
"$tryAdvisoryLock",
|
|
261
|
+
"$sql"
|
|
258
262
|
];
|
|
259
263
|
var RESERVED_COLUMN_PREFIX = "__vibe_";
|
|
260
264
|
function isReservedDelegateName(params) {
|
|
@@ -442,6 +446,8 @@ var POSTGRES_CAPABILITIES = Object.freeze({
|
|
|
442
446
|
fixedNamespaces: true,
|
|
443
447
|
externalObjects: true,
|
|
444
448
|
indexOperatorClasses: true,
|
|
449
|
+
indexIncludeColumns: true,
|
|
450
|
+
tableStorageParameters: true,
|
|
445
451
|
exclusionConstraints: true,
|
|
446
452
|
exclusionExtensions: Object.freeze(["btree_gist"]),
|
|
447
453
|
checkNormalization: "rollback",
|
|
@@ -474,7 +480,11 @@ var POSTGRES_CAPABILITIES = Object.freeze({
|
|
|
474
480
|
uuidColumns: "native",
|
|
475
481
|
localDateColumns: true,
|
|
476
482
|
dateTruncation: true,
|
|
477
|
-
|
|
483
|
+
filteredAggregates: "filterClause",
|
|
484
|
+
groupingSets: "groupingSets",
|
|
485
|
+
rowCapture: true,
|
|
486
|
+
returningReadsJoinedSource: true,
|
|
487
|
+
upsertSkipUnchanged: true
|
|
478
488
|
});
|
|
479
489
|
var SQLITE_CAPABILITIES = Object.freeze({
|
|
480
490
|
rowRuleAppendOnly: true,
|
|
@@ -484,6 +494,8 @@ var SQLITE_CAPABILITIES = Object.freeze({
|
|
|
484
494
|
fixedNamespaces: false,
|
|
485
495
|
externalObjects: false,
|
|
486
496
|
indexOperatorClasses: false,
|
|
497
|
+
indexIncludeColumns: false,
|
|
498
|
+
tableStorageParameters: false,
|
|
487
499
|
exclusionConstraints: false,
|
|
488
500
|
exclusionExtensions: Object.freeze([]),
|
|
489
501
|
checkNormalization: "sourceText",
|
|
@@ -516,7 +528,11 @@ var SQLITE_CAPABILITIES = Object.freeze({
|
|
|
516
528
|
uuidColumns: "text",
|
|
517
529
|
localDateColumns: true,
|
|
518
530
|
dateTruncation: false,
|
|
519
|
-
|
|
531
|
+
filteredAggregates: "filterClause",
|
|
532
|
+
groupingSets: "none",
|
|
533
|
+
rowCapture: false,
|
|
534
|
+
returningReadsJoinedSource: false,
|
|
535
|
+
upsertSkipUnchanged: true
|
|
520
536
|
});
|
|
521
537
|
var MYSQL_CAPABILITIES = Object.freeze({
|
|
522
538
|
rowRuleAppendOnly: true,
|
|
@@ -526,6 +542,8 @@ var MYSQL_CAPABILITIES = Object.freeze({
|
|
|
526
542
|
fixedNamespaces: false,
|
|
527
543
|
externalObjects: false,
|
|
528
544
|
indexOperatorClasses: false,
|
|
545
|
+
indexIncludeColumns: false,
|
|
546
|
+
tableStorageParameters: false,
|
|
529
547
|
exclusionConstraints: false,
|
|
530
548
|
exclusionExtensions: Object.freeze([]),
|
|
531
549
|
checkNormalization: "temporary",
|
|
@@ -558,7 +576,11 @@ var MYSQL_CAPABILITIES = Object.freeze({
|
|
|
558
576
|
uuidColumns: "unsupported",
|
|
559
577
|
localDateColumns: true,
|
|
560
578
|
dateTruncation: false,
|
|
561
|
-
|
|
579
|
+
filteredAggregates: "caseWhen",
|
|
580
|
+
groupingSets: "rollup",
|
|
581
|
+
rowCapture: false,
|
|
582
|
+
returningReadsJoinedSource: false,
|
|
583
|
+
upsertSkipUnchanged: true
|
|
562
584
|
});
|
|
563
585
|
var DIALECT_CAPABILITIES = Object.freeze({
|
|
564
586
|
postgres: POSTGRES_CAPABILITIES,
|
|
@@ -1070,10 +1092,12 @@ function shapeIssue(params) {
|
|
|
1070
1092
|
const { index } = params;
|
|
1071
1093
|
if (!dataOnly({ value: index }))
|
|
1072
1094
|
return "Expression indexes accept JSON-safe plain data only, not accessors, callbacks or cycles";
|
|
1073
|
-
if (!record({ value: index, required: ["kind", "fields", "expressions"], optional: ["name", "clientName", "constraintName", "where", "wherePredicate", "nullsNotDistinct"] }))
|
|
1095
|
+
if (!record({ value: index, required: ["kind", "fields", "expressions"], optional: ["name", "clientName", "constraintName", "where", "wherePredicate", "nullsNotDistinct", "include"] }))
|
|
1074
1096
|
return "Expression indexes require canonical index data properties";
|
|
1075
1097
|
if (typeof index.kind !== "string")
|
|
1076
1098
|
return "Index kind must be a string";
|
|
1099
|
+
if (index.include !== undefined && (!Array.isArray(index.include) || index.include.some((name) => !text({ value: name }))))
|
|
1100
|
+
return "Expression index INCLUDE columns must be a list of field names";
|
|
1077
1101
|
if (index.nullsNotDistinct !== undefined && typeof index.nullsNotDistinct !== "boolean" || index.name !== undefined && !text({ value: index.name }) || index.where !== undefined && !text({ value: index.where }))
|
|
1078
1102
|
return "Expression index names, predicates and flags must have their canonical data types";
|
|
1079
1103
|
const descriptor = Object.getOwnPropertyDescriptor(index, "expressions");
|
|
@@ -1139,14 +1163,15 @@ function structuralData(params) {
|
|
|
1139
1163
|
}
|
|
1140
1164
|
function indexKeyDefinitionKey(params) {
|
|
1141
1165
|
const { index, model } = params;
|
|
1166
|
+
const include = index.include === undefined ? [] : [{ include: index.include.map((name) => model?.fields.find((entry) => entry.name === name)?.dbName ?? name) }];
|
|
1142
1167
|
if (!isExpressionIndex({ index })) {
|
|
1143
1168
|
const columns = index.fields.map((field) => [model?.fields.find((entry) => entry.name === field.name)?.dbName ?? field.name, field.sort === "desc", field.operatorClass === undefined ? null : [field.operatorClass.namespace, field.operatorClass.name]]);
|
|
1144
|
-
return JSON.stringify([index.kind === "unique", index.nullsNotDistinct === true, index.kind === "unique" ? "btree" : index.kind, columns, index.where?.trim() ?? ""]);
|
|
1169
|
+
return JSON.stringify([index.kind === "unique", index.nullsNotDistinct === true, index.kind === "unique" ? "btree" : index.kind, columns, index.where?.trim() ?? "", ...include]);
|
|
1145
1170
|
}
|
|
1146
1171
|
const issue = shapeIssue({ index });
|
|
1147
1172
|
if (issue !== undefined)
|
|
1148
1173
|
throw invalid({ message: issue });
|
|
1149
|
-
return JSON.stringify(["expression", index.kind, structuralData({ value: index.expressions, model }), index.nullsNotDistinct === true, index.where?.trim() ?? "", structuralData({ value: index.wherePredicate, model }) ?? null]);
|
|
1174
|
+
return JSON.stringify(["expression", index.kind, structuralData({ value: index.expressions, model }), index.nullsNotDistinct === true, index.where?.trim() ?? "", structuralData({ value: index.wherePredicate, model }) ?? null, ...include]);
|
|
1150
1175
|
}
|
|
1151
1176
|
function scalarType(params) {
|
|
1152
1177
|
const { expression, model, dialect, add } = params;
|
|
@@ -1548,12 +1573,81 @@ function assertSqlNamespace(params) {
|
|
|
1548
1573
|
function qualifiedSqlName(params) {
|
|
1549
1574
|
return { namespace: params.namespace ?? params.defaultNamespace ?? SQL_NAMESPACES.postgres, name: params.name };
|
|
1550
1575
|
}
|
|
1576
|
+
// packages/schema/src/sealed.ts
|
|
1577
|
+
var sealed = new WeakSet;
|
|
1578
|
+
var valid = new WeakSet;
|
|
1579
|
+
var admitted = new WeakMap;
|
|
1580
|
+
function sealSchemaIR(params) {
|
|
1581
|
+
if (sealed.has(params.schema))
|
|
1582
|
+
return params.schema;
|
|
1583
|
+
const copy = frozenPlainCopy({ value: params.schema });
|
|
1584
|
+
if (copy === undefined)
|
|
1585
|
+
return params.schema;
|
|
1586
|
+
sealed.add(copy);
|
|
1587
|
+
return copy;
|
|
1588
|
+
}
|
|
1589
|
+
function isKnownValidSchemaIR(params) {
|
|
1590
|
+
return valid.has(params.schema);
|
|
1591
|
+
}
|
|
1592
|
+
function rememberValidSchemaIR(params) {
|
|
1593
|
+
if (sealed.has(params.schema))
|
|
1594
|
+
valid.add(params.schema);
|
|
1595
|
+
}
|
|
1596
|
+
function isKnownAdmittedSchemaIR(params) {
|
|
1597
|
+
return admitted.get(params.schema)?.includes(params.dialect) === true;
|
|
1598
|
+
}
|
|
1599
|
+
function rememberAdmittedSchemaIR(params) {
|
|
1600
|
+
if (!sealed.has(params.schema))
|
|
1601
|
+
return;
|
|
1602
|
+
const dialects = admitted.get(params.schema);
|
|
1603
|
+
if (dialects === undefined)
|
|
1604
|
+
admitted.set(params.schema, [params.dialect]);
|
|
1605
|
+
else if (!dialects.includes(params.dialect))
|
|
1606
|
+
dialects.push(params.dialect);
|
|
1607
|
+
}
|
|
1608
|
+
function frozenPlainCopy(params) {
|
|
1609
|
+
const { value } = params;
|
|
1610
|
+
if (typeof value === "function" || typeof value === "symbol")
|
|
1611
|
+
return;
|
|
1612
|
+
if (typeof value !== "object" || value === null)
|
|
1613
|
+
return value;
|
|
1614
|
+
if (Array.isArray(value)) {
|
|
1615
|
+
if (Object.getPrototypeOf(value) !== Array.prototype)
|
|
1616
|
+
return;
|
|
1617
|
+
const out = [];
|
|
1618
|
+
for (let index = 0;index < value.length; index++) {
|
|
1619
|
+
const member = value[index];
|
|
1620
|
+
const item = frozenPlainCopy({ value: member });
|
|
1621
|
+
if (item === undefined && member !== undefined)
|
|
1622
|
+
return;
|
|
1623
|
+
out.push(item);
|
|
1624
|
+
}
|
|
1625
|
+
return Object.freeze(out);
|
|
1626
|
+
}
|
|
1627
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1628
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
1629
|
+
return;
|
|
1630
|
+
if (Object.getOwnPropertySymbols(value).length > 0)
|
|
1631
|
+
return;
|
|
1632
|
+
const out = prototype === null ? Object.create(null) : {};
|
|
1633
|
+
for (const key of Object.keys(value)) {
|
|
1634
|
+
const member = value[key];
|
|
1635
|
+
const item = frozenPlainCopy({ value: member });
|
|
1636
|
+
if (item === undefined && member !== undefined)
|
|
1637
|
+
return;
|
|
1638
|
+
Object.defineProperty(out, key, { value: item, enumerable: true, writable: true, configurable: true });
|
|
1639
|
+
}
|
|
1640
|
+
return Object.freeze(out);
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1551
1643
|
// packages/schema/src/native-rls-admission.ts
|
|
1552
1644
|
function assertNativeRlsAdmission(params) {
|
|
1553
1645
|
const { schema } = params;
|
|
1554
1646
|
if (schema.rls === undefined && !schema.models.some((model) => model.rls !== undefined))
|
|
1555
1647
|
return;
|
|
1556
1648
|
const dialect = params.dialect ?? providerToDialect({ provider: schema.datasource.provider });
|
|
1649
|
+
if (isKnownAdmittedSchemaIR({ schema, dialect }))
|
|
1650
|
+
return;
|
|
1557
1651
|
if (!DIALECT_CAPABILITIES[dialect].nativeRowLevelSecurity) {
|
|
1558
1652
|
throw unsupportedCapability({ dialect, feature: "nativeRowLevelSecurity" });
|
|
1559
1653
|
}
|
|
@@ -1571,6 +1665,7 @@ function assertNativeRlsAdmission(params) {
|
|
|
1571
1665
|
});
|
|
1572
1666
|
}
|
|
1573
1667
|
}
|
|
1668
|
+
rememberAdmittedSchemaIR({ schema, dialect });
|
|
1574
1669
|
}
|
|
1575
1670
|
// packages/schema/src/model-sql-namespace.ts
|
|
1576
1671
|
function modelSqlNamespace(params) {
|
|
@@ -2335,6 +2430,172 @@ function assertIndexOperatorClasses(params) {
|
|
|
2335
2430
|
throw new VibeError({ code: "VIBE_SCHEMA_INVALID", message: "Index operator class must be a qualified SQL name { namespace, name }", meta: { rule: "index-operator-class-identity", model: model.name, field: field.name } });
|
|
2336
2431
|
}
|
|
2337
2432
|
}
|
|
2433
|
+
// packages/schema/src/index-include.ts
|
|
2434
|
+
var INCLUDE_INDEX_KINDS = Object.freeze(["btree", "unique", "gist", "spgist"]);
|
|
2435
|
+
function hasIndexIncludeColumns(params) {
|
|
2436
|
+
return params.schema.models.some((model) => model.indexes.some((index) => index.include !== undefined));
|
|
2437
|
+
}
|
|
2438
|
+
function assertIndexIncludeColumns(params) {
|
|
2439
|
+
const { schema, dialect } = params;
|
|
2440
|
+
for (const model of schema.models)
|
|
2441
|
+
for (const index of model.indexes) {
|
|
2442
|
+
const include = index.include;
|
|
2443
|
+
if (include === undefined)
|
|
2444
|
+
continue;
|
|
2445
|
+
const site = `${index.kind === "unique" ? "@@unique" : "@@index"}${index.name === undefined ? "" : ` "${index.name}"`} on "${model.name}"`;
|
|
2446
|
+
const invalid = (params) => new VibeError({ code: "VIBE_SCHEMA_INVALID", message: `${site}: ${params.message}`, meta: { rule: params.rule, model: model.name, ...index.name === undefined ? {} : { index: index.name }, ...params.field === undefined ? {} : { field: params.field } } });
|
|
2447
|
+
if (!Array.isArray(include) || include.length === 0 || include.some((name) => typeof name !== "string" || name === ""))
|
|
2448
|
+
throw invalid({ rule: "index-include-shape", message: "include must be a non-empty list of field names (omit it for an index without INCLUDE columns)" });
|
|
2449
|
+
if (!DIALECT_CAPABILITIES[dialect].indexIncludeColumns)
|
|
2450
|
+
throw unsupportedCapability({ dialect, feature: "indexIncludeColumns", hint: `${site} declares INCLUDE columns; covering indexes are PostgreSQL only` });
|
|
2451
|
+
if (!INCLUDE_INDEX_KINDS.includes(index.kind))
|
|
2452
|
+
throw unsupportedCapability({ dialect, feature: `INCLUDE columns on a ${index.kind} index`, hint: `${site}: PostgreSQL stores INCLUDE columns in btree, unique, GiST and SP-GiST indexes only` });
|
|
2453
|
+
const keys = keyColumns({ index });
|
|
2454
|
+
const seen = new Set;
|
|
2455
|
+
for (const name of include) {
|
|
2456
|
+
if (!model.fields.some((field) => field.name === name))
|
|
2457
|
+
throw invalid({ rule: "index-include-field", message: `include names "${name}", which is not a scalar field of the model`, field: name });
|
|
2458
|
+
if (seen.has(name))
|
|
2459
|
+
throw invalid({ rule: "index-include-duplicate", message: `include lists "${name}" twice`, field: name });
|
|
2460
|
+
if (keys.has(name))
|
|
2461
|
+
throw invalid({ rule: "index-include-key-column", message: `"${name}" is already a key column of the index; PostgreSQL refuses a column that is both key and included`, field: name });
|
|
2462
|
+
seen.add(name);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
function keyColumns(params) {
|
|
2467
|
+
return new Set(indexKeyTerms({ index: params.index }).flatMap((term) => term.kind === "field" ? [term.field.name] : []));
|
|
2468
|
+
}
|
|
2469
|
+
// packages/schema/src/table-storage.ts
|
|
2470
|
+
var INT_MAX = 2147483647;
|
|
2471
|
+
var HEAP_ONLY = {
|
|
2472
|
+
fillfactor: { type: "integer", min: 10, max: 100 },
|
|
2473
|
+
toast_tuple_target: { type: "integer", min: 128, max: 8160 },
|
|
2474
|
+
parallel_workers: { type: "integer", min: 0, max: 1024 },
|
|
2475
|
+
autovacuum_analyze_threshold: { type: "integer", min: 0, max: INT_MAX },
|
|
2476
|
+
autovacuum_analyze_scale_factor: { type: "real", min: 0, max: 100 }
|
|
2477
|
+
};
|
|
2478
|
+
var VACUUM = {
|
|
2479
|
+
autovacuum_enabled: { type: "boolean" },
|
|
2480
|
+
vacuum_index_cleanup: { type: "enum", values: ["auto", "on", "off"] },
|
|
2481
|
+
vacuum_truncate: { type: "boolean" },
|
|
2482
|
+
autovacuum_vacuum_threshold: { type: "integer", min: 0, max: INT_MAX },
|
|
2483
|
+
autovacuum_vacuum_scale_factor: { type: "real", min: 0, max: 100 },
|
|
2484
|
+
autovacuum_vacuum_insert_threshold: { type: "integer", min: -1, max: INT_MAX },
|
|
2485
|
+
autovacuum_vacuum_insert_scale_factor: { type: "real", min: 0, max: 100 },
|
|
2486
|
+
autovacuum_vacuum_cost_delay: { type: "real", min: 0, max: 100 },
|
|
2487
|
+
autovacuum_vacuum_cost_limit: { type: "integer", min: 1, max: 1e4 },
|
|
2488
|
+
autovacuum_freeze_min_age: { type: "integer", min: 0, max: 1e9 },
|
|
2489
|
+
autovacuum_freeze_max_age: { type: "integer", min: 1e5, max: 2000000000 },
|
|
2490
|
+
autovacuum_freeze_table_age: { type: "integer", min: 0, max: 2000000000 },
|
|
2491
|
+
autovacuum_multixact_freeze_min_age: { type: "integer", min: 0, max: 1e9 },
|
|
2492
|
+
autovacuum_multixact_freeze_max_age: { type: "integer", min: 1e4, max: 2000000000 },
|
|
2493
|
+
autovacuum_multixact_freeze_table_age: { type: "integer", min: 0, max: 2000000000 },
|
|
2494
|
+
log_autovacuum_min_duration: { type: "integer", min: -1, max: INT_MAX }
|
|
2495
|
+
};
|
|
2496
|
+
var TABLE_STORAGE_PARAMETERS = Object.freeze({
|
|
2497
|
+
...HEAP_ONLY,
|
|
2498
|
+
...VACUUM,
|
|
2499
|
+
...Object.fromEntries(Object.entries(VACUUM).map(([key, spec]) => [`toast.${key}`, spec]))
|
|
2500
|
+
});
|
|
2501
|
+
var TABLE_STORAGE_KEYS = Object.freeze(Object.keys(TABLE_STORAGE_PARAMETERS));
|
|
2502
|
+
var TOAST_PREFIX = "toast.";
|
|
2503
|
+
function specOf(params) {
|
|
2504
|
+
return Object.hasOwn(TABLE_STORAGE_PARAMETERS, params.key) ? TABLE_STORAGE_PARAMETERS[params.key] : undefined;
|
|
2505
|
+
}
|
|
2506
|
+
function isToastStorageKey(params) {
|
|
2507
|
+
return params.key.startsWith(TOAST_PREFIX);
|
|
2508
|
+
}
|
|
2509
|
+
function tableStoragePrismaKey(params) {
|
|
2510
|
+
return isToastStorageKey(params) ? `toast_${params.key.slice(TOAST_PREFIX.length)}` : params.key;
|
|
2511
|
+
}
|
|
2512
|
+
function tableStorageKeyFromPrisma(params) {
|
|
2513
|
+
if (specOf({ key: params.name }) !== undefined)
|
|
2514
|
+
return params.name;
|
|
2515
|
+
if (!params.name.startsWith("toast_"))
|
|
2516
|
+
return;
|
|
2517
|
+
const key = `${TOAST_PREFIX}${params.name.slice("toast_".length)}`;
|
|
2518
|
+
return specOf({ key }) === undefined ? undefined : key;
|
|
2519
|
+
}
|
|
2520
|
+
var TRUE_WORDS = new Set(["true", "t", "on", "yes", "y", "1"]);
|
|
2521
|
+
var FALSE_WORDS = new Set(["false", "f", "off", "no", "n", "0"]);
|
|
2522
|
+
function parseTableStorageValue(params) {
|
|
2523
|
+
const spec = specOf({ key: params.key });
|
|
2524
|
+
if (spec === undefined)
|
|
2525
|
+
return;
|
|
2526
|
+
const text = params.text.trim().toLowerCase();
|
|
2527
|
+
switch (spec.type) {
|
|
2528
|
+
case "boolean":
|
|
2529
|
+
return TRUE_WORDS.has(text) ? true : FALSE_WORDS.has(text) ? false : undefined;
|
|
2530
|
+
case "enum":
|
|
2531
|
+
return spec.values?.includes(text) === true ? text : TRUE_WORDS.has(text) ? "on" : FALSE_WORDS.has(text) ? "off" : undefined;
|
|
2532
|
+
case "integer":
|
|
2533
|
+
case "real": {
|
|
2534
|
+
if (text === "" || !/^[-+]?(\d+(\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(text))
|
|
2535
|
+
return;
|
|
2536
|
+
const value = Number(text);
|
|
2537
|
+
return Number.isFinite(value) ? value : undefined;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
function renderTableStorageValue(params) {
|
|
2542
|
+
return typeof params.value === "boolean" ? params.value ? "true" : "false" : String(params.value);
|
|
2543
|
+
}
|
|
2544
|
+
function valueIssue(params) {
|
|
2545
|
+
const { spec, value } = params;
|
|
2546
|
+
switch (spec.type) {
|
|
2547
|
+
case "boolean":
|
|
2548
|
+
return typeof value === "boolean" ? undefined : "takes true or false";
|
|
2549
|
+
case "enum":
|
|
2550
|
+
return typeof value === "string" && spec.values?.includes(value) === true ? undefined : `takes one of ${spec.values?.map((entry) => `"${entry}"`).join(", ")}`;
|
|
2551
|
+
case "integer":
|
|
2552
|
+
case "real": {
|
|
2553
|
+
const bounds = `between ${spec.min} and ${spec.max}`;
|
|
2554
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
2555
|
+
return `takes a number ${bounds}`;
|
|
2556
|
+
if (spec.type === "integer" && !Number.isInteger(value))
|
|
2557
|
+
return `takes a whole number ${bounds}`;
|
|
2558
|
+
return value < (spec.min ?? -Infinity) || value > (spec.max ?? Infinity) ? `takes a value ${bounds}` : undefined;
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
function hasTableStorage(params) {
|
|
2563
|
+
return params.schema.models.some((model) => model.storage !== undefined);
|
|
2564
|
+
}
|
|
2565
|
+
function assertTableStorage(params) {
|
|
2566
|
+
const { schema, dialect } = params;
|
|
2567
|
+
for (const model of schema.models) {
|
|
2568
|
+
const storage = model.storage;
|
|
2569
|
+
if (storage === undefined)
|
|
2570
|
+
continue;
|
|
2571
|
+
const invalid = (issue) => new VibeError({ code: "VIBE_SCHEMA_INVALID", message: `@@storage on "${model.name}": ${issue.message}`, meta: { rule: issue.rule, model: model.name, ...issue.parameter === undefined ? {} : { parameter: issue.parameter } } });
|
|
2572
|
+
if (storage === null || typeof storage !== "object" || Array.isArray(storage) || Object.keys(storage).length === 0)
|
|
2573
|
+
throw invalid({ rule: "table-storage-shape", message: "storage takes a non-empty record of parameters (omit it for a table without any)" });
|
|
2574
|
+
if (model.isView)
|
|
2575
|
+
throw invalid({ rule: "table-storage-view", message: "a view has no table storage parameters" });
|
|
2576
|
+
if (!DIALECT_CAPABILITIES[dialect].tableStorageParameters)
|
|
2577
|
+
throw unsupportedCapability({ dialect, feature: "tableStorageParameters", hint: `@@storage on "${model.name}" declares table storage parameters; they are PostgreSQL only` });
|
|
2578
|
+
for (const [key, value] of Object.entries(storage)) {
|
|
2579
|
+
const spec = specOf({ key });
|
|
2580
|
+
if (spec === undefined)
|
|
2581
|
+
throw invalid({ rule: "table-storage-parameter", message: `"${key}" is not a table storage parameter VibeORM declares (${TABLE_STORAGE_KEYS.filter((entry) => !isToastStorageKey({ key: entry })).join(", ")}, and toast. variants of the vacuum ones)`, parameter: key });
|
|
2582
|
+
const issue = valueIssue({ spec, value });
|
|
2583
|
+
if (issue !== undefined)
|
|
2584
|
+
throw invalid({ rule: "table-storage-value", message: `"${key}" ${issue}`, parameter: key });
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
function tableStorageEntries(params) {
|
|
2589
|
+
const storage = params.model.storage;
|
|
2590
|
+
if (storage === undefined)
|
|
2591
|
+
return [];
|
|
2592
|
+
const known = TABLE_STORAGE_KEYS.flatMap((key) => {
|
|
2593
|
+
const value = Object.hasOwn(storage, key) ? storage[key] : undefined;
|
|
2594
|
+
return value === undefined ? [] : [[key, value]];
|
|
2595
|
+
});
|
|
2596
|
+
const unknown = Object.entries(storage).flatMap(([key, value]) => specOf({ key }) !== undefined || value === undefined ? [] : [[key, value]]);
|
|
2597
|
+
return [...known, ...unknown];
|
|
2598
|
+
}
|
|
2338
2599
|
// packages/schema/src/module-schema.ts
|
|
2339
2600
|
function prepareDatabaseModuleSchema(params) {
|
|
2340
2601
|
const { schema, module } = params;
|
|
@@ -2370,6 +2631,24 @@ function prepareDatabaseModuleSchema(params) {
|
|
|
2370
2631
|
enums: schema.enums.map((entry) => enumStorageOf({ enumDef: entry }) === "database" ? { ...entry, namespace } : entry)
|
|
2371
2632
|
};
|
|
2372
2633
|
}
|
|
2634
|
+
// packages/schema/src/exclusion.ts
|
|
2635
|
+
function exclusionFields(params) {
|
|
2636
|
+
const { source } = params.exclusion;
|
|
2637
|
+
if (source === undefined)
|
|
2638
|
+
return;
|
|
2639
|
+
const fields = new Set;
|
|
2640
|
+
for (const key of source.keys) {
|
|
2641
|
+
if ("field" in key)
|
|
2642
|
+
fields.add(key.field);
|
|
2643
|
+
else
|
|
2644
|
+
for (const field of key.fields)
|
|
2645
|
+
fields.add(field);
|
|
2646
|
+
}
|
|
2647
|
+
for (const endpoint of [source.range.lower, source.range.upper])
|
|
2648
|
+
if ("field" in endpoint)
|
|
2649
|
+
fields.add(endpoint.field);
|
|
2650
|
+
return [...fields];
|
|
2651
|
+
}
|
|
2373
2652
|
// packages/schema/src/check-rules.ts
|
|
2374
2653
|
var CHECK_RULE_GROUP_MAX = 8;
|
|
2375
2654
|
var field = (name) => ({ kind: "field", name });
|
|
@@ -2533,6 +2812,133 @@ function dialectCollation(params) {
|
|
|
2533
2812
|
return;
|
|
2534
2813
|
}
|
|
2535
2814
|
}
|
|
2815
|
+
// packages/schema/src/failure-kind.ts
|
|
2816
|
+
var CONNECTION_FAILURE_REASONS = Object.freeze([
|
|
2817
|
+
"connection-refused",
|
|
2818
|
+
"connection-timeout",
|
|
2819
|
+
"connection-lost",
|
|
2820
|
+
"connection-not-writable",
|
|
2821
|
+
"acquire-timeout",
|
|
2822
|
+
"pool-exhausted",
|
|
2823
|
+
"pool-closed",
|
|
2824
|
+
"too-many-connections",
|
|
2825
|
+
"server-shutdown"
|
|
2826
|
+
]);
|
|
2827
|
+
var CONNECTION_REASON_SET = new Set(CONNECTION_FAILURE_REASONS);
|
|
2828
|
+
function isConnectionFailureReason(params) {
|
|
2829
|
+
return typeof params.value === "string" && CONNECTION_REASON_SET.has(params.value);
|
|
2830
|
+
}
|
|
2831
|
+
var FAILURE_KINDS = Object.freeze([
|
|
2832
|
+
"connection",
|
|
2833
|
+
"conflict",
|
|
2834
|
+
"timeout",
|
|
2835
|
+
"constraint"
|
|
2836
|
+
]);
|
|
2837
|
+
var VIBE_CODE_SET = new Set(VIBE_ERROR_CODES);
|
|
2838
|
+
var CONFLICT_REASONS = new Set(["deadlock", "serialization-failure", "busy"]);
|
|
2839
|
+
var TIMEOUT_REASONS = new Set(["timeout", "transaction-deadline"]);
|
|
2840
|
+
var POSTGRES_CONSTRAINT_SQLSTATES = new Set(["23502", "23514"]);
|
|
2841
|
+
var SQLITE_CONSTRAINT_CODES = new Set([
|
|
2842
|
+
"SQLITE_CONSTRAINT_NOTNULL",
|
|
2843
|
+
"SQLITE_CONSTRAINT_CHECK",
|
|
2844
|
+
"SQLITE_CONSTRAINT_TRIGGER"
|
|
2845
|
+
]);
|
|
2846
|
+
var MYSQL_CONSTRAINT_ERRNOS = new Set([1048, 1364, 3819]);
|
|
2847
|
+
function constraintRefusal(params) {
|
|
2848
|
+
const { meta } = params;
|
|
2849
|
+
if (typeof meta.sqlstate === "string")
|
|
2850
|
+
return POSTGRES_CONSTRAINT_SQLSTATES.has(meta.sqlstate);
|
|
2851
|
+
if (typeof meta.sqlState === "string" && typeof meta.errno === "number")
|
|
2852
|
+
return MYSQL_CONSTRAINT_ERRNOS.has(meta.errno);
|
|
2853
|
+
return typeof meta.code === "string" && SQLITE_CONSTRAINT_CODES.has(meta.code);
|
|
2854
|
+
}
|
|
2855
|
+
function failureKindOf(params) {
|
|
2856
|
+
const { error } = params;
|
|
2857
|
+
if (typeof error !== "object" || error === null)
|
|
2858
|
+
return;
|
|
2859
|
+
const { code, meta } = error;
|
|
2860
|
+
if (typeof code !== "string" || !VIBE_CODE_SET.has(code))
|
|
2861
|
+
return;
|
|
2862
|
+
const facts = typeof meta === "object" && meta !== null ? meta : {};
|
|
2863
|
+
const reason = facts.reason;
|
|
2864
|
+
switch (code) {
|
|
2865
|
+
case "VIBE_ADAPTER":
|
|
2866
|
+
if (isConnectionFailureReason({ value: reason }))
|
|
2867
|
+
return "connection";
|
|
2868
|
+
return typeof reason === "string" && TIMEOUT_REASONS.has(reason) ? "timeout" : undefined;
|
|
2869
|
+
case "VIBE_TRANSACTION":
|
|
2870
|
+
if (typeof reason !== "string")
|
|
2871
|
+
return;
|
|
2872
|
+
if (CONFLICT_REASONS.has(reason))
|
|
2873
|
+
return "conflict";
|
|
2874
|
+
return TIMEOUT_REASONS.has(reason) ? "timeout" : undefined;
|
|
2875
|
+
case "VIBE_UNIQUE_VIOLATION":
|
|
2876
|
+
case "VIBE_FK_VIOLATION":
|
|
2877
|
+
case "VIBE_EXCLUSION_VIOLATION":
|
|
2878
|
+
return "constraint";
|
|
2879
|
+
case "VIBE_VALIDATION":
|
|
2880
|
+
return constraintRefusal({ meta: facts }) ? "constraint" : undefined;
|
|
2881
|
+
default:
|
|
2882
|
+
return;
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
// packages/schema/src/suggest.ts
|
|
2886
|
+
function editDistance(params) {
|
|
2887
|
+
const { from, to } = params;
|
|
2888
|
+
const rows = from.length + 1;
|
|
2889
|
+
const columns = to.length + 1;
|
|
2890
|
+
const table = new Array(rows * columns).fill(0);
|
|
2891
|
+
for (let row = 0;row < rows; row++)
|
|
2892
|
+
table[row * columns] = row;
|
|
2893
|
+
for (let column = 0;column < columns; column++)
|
|
2894
|
+
table[column] = column;
|
|
2895
|
+
for (let row = 1;row < rows; row++) {
|
|
2896
|
+
for (let column = 1;column < columns; column++) {
|
|
2897
|
+
const cost = from[row - 1] === to[column - 1] ? 0 : 1;
|
|
2898
|
+
let best = Math.min(table[(row - 1) * columns + column] + 1, table[row * columns + column - 1] + 1, table[(row - 1) * columns + column - 1] + cost);
|
|
2899
|
+
if (row > 1 && column > 1 && from[row - 1] === to[column - 2] && from[row - 2] === to[column - 1]) {
|
|
2900
|
+
best = Math.min(best, table[(row - 2) * columns + column - 2] + 1);
|
|
2901
|
+
}
|
|
2902
|
+
table[row * columns + column] = best;
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
return table[rows * columns - 1];
|
|
2906
|
+
}
|
|
2907
|
+
function suggestName(params) {
|
|
2908
|
+
const { name } = params;
|
|
2909
|
+
let best;
|
|
2910
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
2911
|
+
let tied = false;
|
|
2912
|
+
for (const candidate of new Set(params.candidates)) {
|
|
2913
|
+
if (candidate === name)
|
|
2914
|
+
continue;
|
|
2915
|
+
const distance = editDistance({ from: name, to: candidate });
|
|
2916
|
+
const limit = Math.max(2, Math.floor(Math.max(name.length, candidate.length) / 3));
|
|
2917
|
+
if (distance > limit || distance >= name.length)
|
|
2918
|
+
continue;
|
|
2919
|
+
if (distance < bestDistance) {
|
|
2920
|
+
best = candidate;
|
|
2921
|
+
bestDistance = distance;
|
|
2922
|
+
tied = false;
|
|
2923
|
+
} else if (distance === bestDistance) {
|
|
2924
|
+
tied = true;
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
return tied ? undefined : best;
|
|
2928
|
+
}
|
|
2929
|
+
function didYouMean(params) {
|
|
2930
|
+
return params.suggestion === undefined ? "" : ` \u2014 did you mean ${JSON.stringify(params.suggestion)}?`;
|
|
2931
|
+
}
|
|
2932
|
+
var unknownNameMetas = new WeakSet;
|
|
2933
|
+
function withSuggestion(params) {
|
|
2934
|
+
const suggestion = suggestName({ name: params.name, candidates: params.candidates });
|
|
2935
|
+
const meta = suggestion === undefined ? params.meta : { ...params.meta, suggestion };
|
|
2936
|
+
unknownNameMetas.add(meta);
|
|
2937
|
+
return { message: suggestion === undefined ? params.message : `${params.message}${didYouMean({ suggestion })}`, meta };
|
|
2938
|
+
}
|
|
2939
|
+
function isUnknownNameRefusal(params) {
|
|
2940
|
+
return unknownNameMetas.has(params.meta);
|
|
2941
|
+
}
|
|
2536
2942
|
// packages/schema/src/computed.ts
|
|
2537
2943
|
function buildComputedManifest(params) {
|
|
2538
2944
|
const { computed } = params;
|
|
@@ -2571,6 +2977,8 @@ function validateComputedConfig(params) {
|
|
|
2571
2977
|
}
|
|
2572
2978
|
if (fieldName === "_count")
|
|
2573
2979
|
problems.push(`"${at}" collides with the _count projection`);
|
|
2980
|
+
if (fieldName === "_aggregate")
|
|
2981
|
+
problems.push(`"${at}" collides with the _aggregate projection`);
|
|
2574
2982
|
if (model.fields.some((field) => field.name === fieldName)) {
|
|
2575
2983
|
problems.push(`"${at}" collides with a schema field of the same name`);
|
|
2576
2984
|
}
|
|
@@ -2857,6 +3265,10 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2857
3265
|
"SelectionMember",
|
|
2858
3266
|
"SelectionValue",
|
|
2859
3267
|
"BagKeys",
|
|
3268
|
+
"__VibeBagKeysIn",
|
|
3269
|
+
"__VibeCertain",
|
|
3270
|
+
"__VibeAllOn",
|
|
3271
|
+
"__VibeAggregateSelection",
|
|
2860
3272
|
"IncludedRelation",
|
|
2861
3273
|
"IncludedCount",
|
|
2862
3274
|
"ViewDelegateMap",
|
|
@@ -2865,6 +3277,21 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2865
3277
|
"__VibeAt",
|
|
2866
3278
|
"__VibeItem",
|
|
2867
3279
|
"__VibeExact",
|
|
3280
|
+
"__VibeLiteral",
|
|
3281
|
+
"__VibePreviousInput",
|
|
3282
|
+
"__VibePrevious",
|
|
3283
|
+
"__VibeUpdated",
|
|
3284
|
+
"__VibeDeleted",
|
|
3285
|
+
"__VibeOrNullRow",
|
|
3286
|
+
"__VibeUpserted",
|
|
3287
|
+
"__VibeCreated",
|
|
3288
|
+
"__VibeAggregateValue",
|
|
3289
|
+
"__VibeSplitEntries",
|
|
3290
|
+
"__VibeViewAggregates",
|
|
3291
|
+
"__VibeViewBucket",
|
|
3292
|
+
"__VibeViewFiltered",
|
|
3293
|
+
"__VibeViewBy",
|
|
3294
|
+
"__VibeViewByKey",
|
|
2868
3295
|
"extensionManifest",
|
|
2869
3296
|
"extensionMounts",
|
|
2870
3297
|
"computedManifest",
|
|
@@ -2877,6 +3304,7 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2877
3304
|
"Partial",
|
|
2878
3305
|
"Omit",
|
|
2879
3306
|
"NonNullable",
|
|
3307
|
+
"NoInfer",
|
|
2880
3308
|
"Promise",
|
|
2881
3309
|
"PromiseLike",
|
|
2882
3310
|
"Awaited",
|
|
@@ -2905,6 +3333,12 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2905
3333
|
"RowLockRequest",
|
|
2906
3334
|
"GroupByTruncateUnit",
|
|
2907
3335
|
"GroupByKeyName",
|
|
3336
|
+
"GroupByPath",
|
|
3337
|
+
"GroupByExpressionValues",
|
|
3338
|
+
"GroupByKeyOrderInput",
|
|
3339
|
+
"GroupByOrderKeys",
|
|
3340
|
+
"GroupByKeyOrderCheck",
|
|
3341
|
+
"GroupingSetRow",
|
|
2908
3342
|
"JsonValue",
|
|
2909
3343
|
"InputJsonValue",
|
|
2910
3344
|
"InputJsonArray",
|
|
@@ -2930,9 +3364,21 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2930
3364
|
"createClient",
|
|
2931
3365
|
"DatabaseAdapter",
|
|
2932
3366
|
"DbNow",
|
|
3367
|
+
"BigIntFieldRef",
|
|
3368
|
+
"BooleanFieldRef",
|
|
3369
|
+
"DateTimeFieldRef",
|
|
3370
|
+
"DecimalFieldRef",
|
|
3371
|
+
"EnumFieldRef",
|
|
3372
|
+
"FloatFieldRef",
|
|
3373
|
+
"IntFieldRef",
|
|
3374
|
+
"NumericFieldRef",
|
|
3375
|
+
"StringFieldRef",
|
|
2933
3376
|
"JoinedField",
|
|
2934
3377
|
"TransactionLocalSettings",
|
|
2935
3378
|
"VibeUpdateManySources",
|
|
3379
|
+
"VibeModelRows",
|
|
3380
|
+
"VibeUniqueKeys",
|
|
3381
|
+
"VibeHandleTypes",
|
|
2936
3382
|
"ClientContext",
|
|
2937
3383
|
"QueryOperation",
|
|
2938
3384
|
"QueryEvent",
|
|
@@ -3016,6 +3462,12 @@ var GENERATED_TYPE_NAMES = {
|
|
|
3016
3462
|
"HavingInput",
|
|
3017
3463
|
"GroupByOrderByInput",
|
|
3018
3464
|
"GroupByTruncatedKey",
|
|
3465
|
+
"GroupByExpressionKey",
|
|
3466
|
+
"FilteredAggregateInput",
|
|
3467
|
+
"FilteredAggregateHavingInput",
|
|
3468
|
+
"FilteredAggregateOrderByInput",
|
|
3469
|
+
"FilteredResult",
|
|
3470
|
+
"CoalesceOrderInput",
|
|
3019
3471
|
"FindManyArgs",
|
|
3020
3472
|
"FindPageArgs",
|
|
3021
3473
|
"FindFirstArgs",
|
|
@@ -3040,6 +3492,10 @@ var GENERATED_TYPE_NAMES = {
|
|
|
3040
3492
|
"OmitBase",
|
|
3041
3493
|
"CountResult",
|
|
3042
3494
|
"CountPayload",
|
|
3495
|
+
"AggregateEntries",
|
|
3496
|
+
"AggregateEntryArgs",
|
|
3497
|
+
"AggregateOf",
|
|
3498
|
+
"AggregatePayload",
|
|
3043
3499
|
"AggregateValues",
|
|
3044
3500
|
"AggregateSelection",
|
|
3045
3501
|
"CountOutput",
|
|
@@ -3056,6 +3512,7 @@ var GENERATED_TYPE_NAMES = {
|
|
|
3056
3512
|
"ViewNestedArgs",
|
|
3057
3513
|
"ViewFindManyArgs",
|
|
3058
3514
|
"ViewFindUniqueArgs",
|
|
3515
|
+
"ViewAggregateBag",
|
|
3059
3516
|
"ViewScalars",
|
|
3060
3517
|
"ViewSelectScalars",
|
|
3061
3518
|
"ViewReveal",
|
|
@@ -3065,6 +3522,7 @@ var GENERATED_TYPE_NAMES = {
|
|
|
3065
3522
|
"ViewDelegate",
|
|
3066
3523
|
"ReadOnlyDelegate"
|
|
3067
3524
|
],
|
|
3525
|
+
generatedColumnSuffixes: ["WritableScalarFieldEnum", "GeneratedWriteGuard", "GeneratedBulkWriteRow"],
|
|
3068
3526
|
nestedPrefixes: [
|
|
3069
3527
|
"Create",
|
|
3070
3528
|
"UncheckedCreate",
|
|
@@ -3140,33 +3598,118 @@ var INVALID_BINDING_NAMES = new Set([
|
|
|
3140
3598
|
"object",
|
|
3141
3599
|
"undefined"
|
|
3142
3600
|
]);
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3601
|
+
var DISAMBIGUATED_TYPE_SUFFIXES = {
|
|
3602
|
+
ListRelationFilter: true,
|
|
3603
|
+
RelationFilter: true,
|
|
3604
|
+
RelationOrderByInput: true,
|
|
3605
|
+
RelationFindManyArgs: true,
|
|
3606
|
+
CreateArgs: true,
|
|
3607
|
+
UpdateArgs: true,
|
|
3608
|
+
UpdateWhereInput: true,
|
|
3609
|
+
UpsertArgs: true,
|
|
3610
|
+
DeleteArgs: true,
|
|
3611
|
+
CountArgs: true,
|
|
3612
|
+
CountSelect: true,
|
|
3613
|
+
AggregateArgs: true,
|
|
3614
|
+
ViewSelect: true,
|
|
3615
|
+
ViewInclude: true,
|
|
3616
|
+
ViewFindManyArgs: true,
|
|
3617
|
+
ViewFindUniqueArgs: true,
|
|
3618
|
+
ViewDelegate: true
|
|
3619
|
+
};
|
|
3620
|
+
function isDisambiguatedTypeSuffix(suffix) {
|
|
3621
|
+
return Object.hasOwn(DISAMBIGUATED_TYPE_SUFFIXES, suffix);
|
|
3622
|
+
}
|
|
3623
|
+
function generatedNameClaims(params) {
|
|
3624
|
+
const { schema } = params;
|
|
3625
|
+
const claims = [];
|
|
3626
|
+
const fixed = (options) => {
|
|
3627
|
+
for (const name of options.names)
|
|
3628
|
+
claims.push({ name, owner: options.owner, kind: "client", stem: name, suffix: "" });
|
|
3629
|
+
};
|
|
3630
|
+
fixed({ names: RESERVED_ENUM_NAMES, owner: "generated client" });
|
|
3146
3631
|
if (schema.rls !== undefined) {
|
|
3147
|
-
|
|
3148
|
-
owners.set("BoundVibeClientInstance", "native RLS client");
|
|
3149
|
-
owners.set("BoundVibeTransactionClientInstance", "native RLS client");
|
|
3150
|
-
owners.set("OperatorVibeClientInstance", "native RLS client");
|
|
3151
|
-
owners.set("OperatorVibeTransactionClientInstance", "native RLS client");
|
|
3632
|
+
fixed({ names: ["RlsContext", "BoundVibeClientInstance", "BoundVibeTransactionClientInstance", "OperatorVibeClientInstance", "OperatorVibeTransactionClientInstance"], owner: "native RLS client" });
|
|
3152
3633
|
}
|
|
3153
3634
|
if (schema.models.some((model) => model.policy !== undefined))
|
|
3154
|
-
|
|
3635
|
+
fixed({ names: ["PolicyClientInstance"], owner: "policy client" });
|
|
3155
3636
|
if (schema.models.some((model) => model.fields.some((field) => isLocalDateField({ field })))) {
|
|
3156
|
-
|
|
3157
|
-
|
|
3637
|
+
fixed({ names: ["LocalDate", "LocalDateFilter", "LocalDateNullableFilter"], owner: "local-date filters" });
|
|
3638
|
+
}
|
|
3639
|
+
for (const model of schema.models) {
|
|
3640
|
+
const owner = `model "${model.name}"`;
|
|
3641
|
+
const claim = (suffix) => {
|
|
3642
|
+
claims.push({ name: `${model.name}${suffix}`, owner, kind: "model", stem: model.name, suffix });
|
|
3643
|
+
};
|
|
3644
|
+
for (const suffix of GENERATED_TYPE_NAMES.modelSuffixes)
|
|
3645
|
+
claim(suffix);
|
|
3646
|
+
if (model.fields.some((field) => field.generated !== undefined && field.isUnsupported !== true)) {
|
|
3647
|
+
for (const suffix of GENERATED_TYPE_NAMES.generatedColumnSuffixes)
|
|
3648
|
+
claim(suffix);
|
|
3649
|
+
}
|
|
3650
|
+
const withouts = ["", ...model.relations.map((relation) => `Without${relation.name.charAt(0).toUpperCase()}${relation.name.slice(1)}`)];
|
|
3651
|
+
for (const without of withouts) {
|
|
3652
|
+
for (const prefix of GENERATED_TYPE_NAMES.nestedPrefixes)
|
|
3653
|
+
claim(`${prefix}${without}Input`);
|
|
3654
|
+
}
|
|
3158
3655
|
}
|
|
3159
|
-
const
|
|
3160
|
-
|
|
3161
|
-
|
|
3656
|
+
for (const declared of schema.enums) {
|
|
3657
|
+
for (const suffix of GENERATED_TYPE_NAMES.enumSuffixes) {
|
|
3658
|
+
claims.push({ name: `${declared.name}${suffix}`, owner: `enum "${declared.name}"`, kind: "enum", stem: declared.name, suffix });
|
|
3162
3659
|
}
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3660
|
+
}
|
|
3661
|
+
return claims;
|
|
3662
|
+
}
|
|
3663
|
+
function renameHint(params) {
|
|
3664
|
+
const named = [params.claim, params.keeper].filter((claim) => claim.kind !== "client");
|
|
3665
|
+
const table = named.some((claim) => claim.kind === "model") ? " (@@map, or map in the DSL, keeps a model's table name)" : "";
|
|
3666
|
+
return `rename ${[...new Set(named.map((claim) => claim.owner))].join(" or ")}${table}`;
|
|
3667
|
+
}
|
|
3668
|
+
function resolveGeneratedNames(params) {
|
|
3669
|
+
const claims = generatedNameClaims({ schema: params.schema });
|
|
3670
|
+
const issues = [];
|
|
3671
|
+
const keepers = new Map;
|
|
3672
|
+
for (const claim of claims) {
|
|
3673
|
+
if (claim.kind !== "client" && (!/^[$_\p{ID_Start}][$_\u200c\u200d\p{ID_Continue}]*$/u.test(claim.name) || INVALID_BINDING_NAMES.has(claim.name))) {
|
|
3674
|
+
issues.push({ rule: "invalid-generated-identifier", message: `Generated name "${claim.name}" from ${claim.owner} is not a legal TypeScript identifier` });
|
|
3675
|
+
}
|
|
3676
|
+
const keeper = keepers.get(claim.name);
|
|
3677
|
+
if (keeper === undefined || claim.stem.length > keeper.stem.length)
|
|
3678
|
+
keepers.set(claim.name, claim);
|
|
3679
|
+
}
|
|
3680
|
+
const renamed = new Map;
|
|
3681
|
+
const moved = [];
|
|
3682
|
+
for (const claim of claims) {
|
|
3683
|
+
const keeper = keepers.get(claim.name) ?? claim;
|
|
3684
|
+
if (keeper.owner === claim.owner)
|
|
3685
|
+
continue;
|
|
3686
|
+
if (claim.kind === "model" && isDisambiguatedTypeSuffix(claim.suffix) && keeper.suffix !== "" && claim.stem.length < keeper.stem.length) {
|
|
3687
|
+
const name = `${claim.stem}_${claim.suffix}`;
|
|
3688
|
+
renamed.set(`${claim.stem}\x00${claim.suffix}`, name);
|
|
3689
|
+
moved.push({ claim, keeper, name });
|
|
3690
|
+
continue;
|
|
3168
3691
|
}
|
|
3692
|
+
issues.push({ rule: "generated-name-collision", message: `Generated name "${claim.name}" from ${claim.owner} conflicts with ${keeper.owner}; ${renameHint({ claim, keeper })}` });
|
|
3693
|
+
}
|
|
3694
|
+
for (const { claim, keeper, name } of moved) {
|
|
3695
|
+
const taken = keepers.get(name);
|
|
3696
|
+
if (taken === undefined || taken.owner === claim.owner)
|
|
3697
|
+
continue;
|
|
3698
|
+
issues.push({
|
|
3699
|
+
rule: "generated-name-collision",
|
|
3700
|
+
message: `Generated name "${name}" from ${claim.owner} (renamed because ${keeper.owner} keeps "${claim.name}") conflicts with ${taken.owner}; ${renameHint({ claim, keeper: taken })}`
|
|
3701
|
+
});
|
|
3702
|
+
}
|
|
3703
|
+
return { renamed, issues };
|
|
3704
|
+
}
|
|
3705
|
+
function generatedTypeNames(params) {
|
|
3706
|
+
const { renamed } = resolveGeneratedNames({ schema: params.schema });
|
|
3707
|
+
return {
|
|
3708
|
+
model: ({ model, suffix }) => renamed.get(`${model}\x00${suffix}`) ?? `${model}${suffix}`
|
|
3169
3709
|
};
|
|
3710
|
+
}
|
|
3711
|
+
function validateGeneratedNames(params) {
|
|
3712
|
+
const { schema, issues } = params;
|
|
3170
3713
|
const aliases = new Map;
|
|
3171
3714
|
for (const model of schema.models) {
|
|
3172
3715
|
const clientName = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
@@ -3180,19 +3723,8 @@ function validateGeneratedNames(params) {
|
|
|
3180
3723
|
if (RESERVED_CLIENT_NAMES.includes(clientName)) {
|
|
3181
3724
|
issues.push({ rule: "reserved-client-name", message: `Model "${model.name}" conflicts with client member "${clientName}"`, model: model.name });
|
|
3182
3725
|
}
|
|
3183
|
-
const owner = `model "${model.name}"`;
|
|
3184
|
-
for (const suffix of GENERATED_TYPE_NAMES.modelSuffixes)
|
|
3185
|
-
register({ name: `${model.name}${suffix}`, owner });
|
|
3186
|
-
const withouts = ["", ...model.relations.map((relation) => `Without${relation.name.charAt(0).toUpperCase()}${relation.name.slice(1)}`)];
|
|
3187
|
-
for (const without of withouts) {
|
|
3188
|
-
for (const prefix of GENERATED_TYPE_NAMES.nestedPrefixes)
|
|
3189
|
-
register({ name: `${model.name}${prefix}${without}Input`, owner });
|
|
3190
|
-
}
|
|
3191
|
-
}
|
|
3192
|
-
for (const declared of schema.enums) {
|
|
3193
|
-
for (const suffix of GENERATED_TYPE_NAMES.enumSuffixes)
|
|
3194
|
-
register({ name: `${declared.name}${suffix}`, owner: `enum "${declared.name}"` });
|
|
3195
3726
|
}
|
|
3727
|
+
issues.push(...resolveGeneratedNames({ schema }).issues);
|
|
3196
3728
|
}
|
|
3197
3729
|
function foreignKeyKeys(params) {
|
|
3198
3730
|
const distinct = new Set;
|
|
@@ -3495,7 +4027,7 @@ function validatePhysicalNameUniqueness(params) {
|
|
|
3495
4027
|
for (const { index, site } of declarations) {
|
|
3496
4028
|
const unique = index.kind === "unique";
|
|
3497
4029
|
const columns = index.fields.map((entry) => [columnOf(entry.name), entry.sort === "desc", entry.operatorClass === undefined ? null : [entry.operatorClass.namespace, entry.operatorClass.name]]);
|
|
3498
|
-
const key = isExpressionIndex({ index }) ? indexKeyDefinitionKey({ index, model }) : JSON.stringify([unique, index.nullsNotDistinct === true, unique ? "btree" : index.kind, columns, index.where?.trim() ?? ""]);
|
|
4030
|
+
const key = isExpressionIndex({ index }) ? indexKeyDefinitionKey({ index, model }) : JSON.stringify([unique, index.nullsNotDistinct === true, unique ? "btree" : index.kind, columns, index.where?.trim() ?? "", ...index.include === undefined ? [] : [{ include: index.include.map(columnOf) }]]);
|
|
3499
4031
|
if (seenIndexKeys.has(key))
|
|
3500
4032
|
continue;
|
|
3501
4033
|
seenIndexKeys.add(key);
|
|
@@ -3933,6 +4465,27 @@ function validateModel(params) {
|
|
|
3933
4465
|
}
|
|
3934
4466
|
}
|
|
3935
4467
|
}
|
|
4468
|
+
if (relation.inverseKey !== undefined) {
|
|
4469
|
+
const { fields, references } = relation.inverseKey;
|
|
4470
|
+
if (relation.isList || hasFields || hasReferences || !Array.isArray(fields) || !Array.isArray(references) || fields.length === 0 || fields.length !== references.length) {
|
|
4471
|
+
issues.push({
|
|
4472
|
+
rule: "inverse-key-shape",
|
|
4473
|
+
message: `Relation "${model.name}.${relation.name}" declares an inverse key, which needs a to-one without foreign-key fields and as many references as fields`,
|
|
4474
|
+
model: model.name,
|
|
4475
|
+
field: relation.name
|
|
4476
|
+
});
|
|
4477
|
+
} else {
|
|
4478
|
+
for (const name of fields) {
|
|
4479
|
+
if (!fieldNames.has(name))
|
|
4480
|
+
issues.push({ rule: "unknown-relation-field", message: `Relation "${model.name}.${relation.name}" uses unknown inverse-key field "${name}"`, model: model.name, field: relation.name });
|
|
4481
|
+
}
|
|
4482
|
+
const targetFields = target === undefined ? undefined : lookups.fieldsByModel.get(target);
|
|
4483
|
+
for (const name of references) {
|
|
4484
|
+
if (targetFields !== undefined && !targetFields.has(name))
|
|
4485
|
+
issues.push({ rule: "unknown-relation-reference", message: `Relation "${model.name}.${relation.name}" references unknown inverse-key field "${relation.targetModel}.${name}"`, model: model.name, field: relation.name });
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
3936
4489
|
}
|
|
3937
4490
|
for (const field of model.fields) {
|
|
3938
4491
|
if (field.collation !== undefined && (field.type !== "String" || isLocalDateField({ field }))) {
|
|
@@ -4224,6 +4777,12 @@ function assertMysqlCheckReferentialActions(params) {
|
|
|
4224
4777
|
}
|
|
4225
4778
|
}
|
|
4226
4779
|
function assertValidSchemaIR(params) {
|
|
4780
|
+
if (isKnownValidSchemaIR(params))
|
|
4781
|
+
return;
|
|
4782
|
+
assertSchemaIRNow(params);
|
|
4783
|
+
rememberValidSchemaIR(params);
|
|
4784
|
+
}
|
|
4785
|
+
function assertSchemaIRNow(params) {
|
|
4227
4786
|
const rowRules = createRowRuleValidationContext(params);
|
|
4228
4787
|
const dialect = providerToDialect({ provider: params.schema.datasource.provider });
|
|
4229
4788
|
assertIndexExpressions({ schema: params.schema, dialect });
|
|
@@ -4240,6 +4799,8 @@ function assertValidSchemaIR(params) {
|
|
|
4240
4799
|
}
|
|
4241
4800
|
assertExtensionPlacement({ schema: params.schema, dialect });
|
|
4242
4801
|
assertIndexOperatorClasses({ schema: params.schema, dialect });
|
|
4802
|
+
assertIndexIncludeColumns({ schema: params.schema, dialect });
|
|
4803
|
+
assertTableStorage({ schema: params.schema, dialect });
|
|
4243
4804
|
for (const entry of [...params.schema.models, ...params.schema.enums])
|
|
4244
4805
|
if (entry.namespace !== undefined)
|
|
4245
4806
|
assertSqlNamespace({ namespace: entry.namespace, dialect });
|
|
@@ -4540,14 +5101,261 @@ function validRlsForeignKey(params) {
|
|
|
4540
5101
|
];
|
|
4541
5102
|
return validFields && uniqueSets.some((set) => set.length === refs.length && set.every((name) => refs.includes(name)));
|
|
4542
5103
|
}
|
|
5104
|
+
// packages/schema/src/partial-predicate.ts
|
|
5105
|
+
function normalizeWhere(params) {
|
|
5106
|
+
const { where } = params;
|
|
5107
|
+
if (where === undefined || where.trim() === "")
|
|
5108
|
+
return "";
|
|
5109
|
+
if (/\$|\\|--|\/\*/.test(where))
|
|
5110
|
+
return `raw:${where.trim()}`;
|
|
5111
|
+
const tokens = tokenizeWhere({ text: where });
|
|
5112
|
+
const parsed = parseOrExpression({ tokens, at: 0 });
|
|
5113
|
+
return parsed !== undefined && parsed.at === tokens.length ? parsed.text : tokens.join(" ");
|
|
5114
|
+
}
|
|
5115
|
+
function tokenizeWhere(params) {
|
|
5116
|
+
const { text } = params;
|
|
5117
|
+
const tokens = [];
|
|
5118
|
+
let i = 0;
|
|
5119
|
+
while (i < text.length) {
|
|
5120
|
+
const ch = text[i];
|
|
5121
|
+
if (/\s/.test(ch)) {
|
|
5122
|
+
i += 1;
|
|
5123
|
+
continue;
|
|
5124
|
+
}
|
|
5125
|
+
if (ch === "'") {
|
|
5126
|
+
let literal = "'";
|
|
5127
|
+
i += 1;
|
|
5128
|
+
while (i < text.length) {
|
|
5129
|
+
literal += text[i];
|
|
5130
|
+
if (text[i] === "'") {
|
|
5131
|
+
if (text[i + 1] === "'") {
|
|
5132
|
+
literal += "'";
|
|
5133
|
+
i += 2;
|
|
5134
|
+
continue;
|
|
5135
|
+
}
|
|
5136
|
+
i += 1;
|
|
5137
|
+
break;
|
|
5138
|
+
}
|
|
5139
|
+
i += 1;
|
|
5140
|
+
}
|
|
5141
|
+
tokens.push(literal);
|
|
5142
|
+
continue;
|
|
5143
|
+
}
|
|
5144
|
+
if (ch === '"' || ch === "`") {
|
|
5145
|
+
let name = "";
|
|
5146
|
+
i += 1;
|
|
5147
|
+
while (i < text.length) {
|
|
5148
|
+
if (text[i] === ch) {
|
|
5149
|
+
if (text[i + 1] !== ch) {
|
|
5150
|
+
i += 1;
|
|
5151
|
+
break;
|
|
5152
|
+
}
|
|
5153
|
+
name += ch;
|
|
5154
|
+
i += 2;
|
|
5155
|
+
} else {
|
|
5156
|
+
name += text[i];
|
|
5157
|
+
i += 1;
|
|
5158
|
+
}
|
|
5159
|
+
}
|
|
5160
|
+
tokens.push(JSON.stringify(name));
|
|
5161
|
+
continue;
|
|
5162
|
+
}
|
|
5163
|
+
if (ch === "[") {
|
|
5164
|
+
const end = text.indexOf("]", i + 1);
|
|
5165
|
+
const inner = end === -1 ? undefined : text.slice(i + 1, end);
|
|
5166
|
+
if (inner !== undefined && tokens[tokens.length - 1] !== "array" && /^[A-Za-z_][A-Za-z_0-9$]*$/.test(inner)) {
|
|
5167
|
+
tokens.push(JSON.stringify(inner));
|
|
5168
|
+
i = end + 1;
|
|
5169
|
+
continue;
|
|
5170
|
+
}
|
|
5171
|
+
tokens.push(ch);
|
|
5172
|
+
i += 1;
|
|
5173
|
+
continue;
|
|
5174
|
+
}
|
|
5175
|
+
const word = /^[A-Za-z_][A-Za-z_0-9$]*/.exec(text.slice(i));
|
|
5176
|
+
if (word !== null) {
|
|
5177
|
+
tokens.push(word[0].toLowerCase());
|
|
5178
|
+
i += word[0].length;
|
|
5179
|
+
continue;
|
|
5180
|
+
}
|
|
5181
|
+
const number = /^[0-9]+(?:\.[0-9]+)?/.exec(text.slice(i));
|
|
5182
|
+
if (number !== null) {
|
|
5183
|
+
tokens.push(number[0]);
|
|
5184
|
+
i += number[0].length;
|
|
5185
|
+
continue;
|
|
5186
|
+
}
|
|
5187
|
+
tokens.push(ch);
|
|
5188
|
+
i += 1;
|
|
5189
|
+
}
|
|
5190
|
+
return tokens;
|
|
5191
|
+
}
|
|
5192
|
+
function parseOrExpression(params) {
|
|
5193
|
+
const first = parseAndExpression({ tokens: params.tokens, at: params.at });
|
|
5194
|
+
if (first === undefined)
|
|
5195
|
+
return;
|
|
5196
|
+
let at = first.at;
|
|
5197
|
+
const parts = [first.text];
|
|
5198
|
+
while (params.tokens[at] === "or") {
|
|
5199
|
+
const next = parseAndExpression({ tokens: params.tokens, at: at + 1 });
|
|
5200
|
+
if (next === undefined)
|
|
5201
|
+
return;
|
|
5202
|
+
parts.push(next.text);
|
|
5203
|
+
at = next.at;
|
|
5204
|
+
}
|
|
5205
|
+
return parts.length === 1 ? { text: parts[0], at, kind: first.kind } : { text: parts.join(" or "), at, kind: "or" };
|
|
5206
|
+
}
|
|
5207
|
+
function parseAndExpression(params) {
|
|
5208
|
+
const first = parsePrimaryExpression({ tokens: params.tokens, at: params.at });
|
|
5209
|
+
if (first === undefined)
|
|
5210
|
+
return;
|
|
5211
|
+
let at = first.at;
|
|
5212
|
+
const operands = [first];
|
|
5213
|
+
while (params.tokens[at] === "and") {
|
|
5214
|
+
const next = parsePrimaryExpression({ tokens: params.tokens, at: at + 1 });
|
|
5215
|
+
if (next === undefined)
|
|
5216
|
+
return;
|
|
5217
|
+
operands.push(next);
|
|
5218
|
+
at = next.at;
|
|
5219
|
+
}
|
|
5220
|
+
return operands.length === 1 ? { text: first.text, at, kind: first.kind } : {
|
|
5221
|
+
text: operands.map((operand) => operand.kind === "or" ? `(${operand.text})` : operand.text).join(" and "),
|
|
5222
|
+
at,
|
|
5223
|
+
kind: "and"
|
|
5224
|
+
};
|
|
5225
|
+
}
|
|
5226
|
+
function parsePrimaryExpression(params) {
|
|
5227
|
+
const { tokens } = params;
|
|
5228
|
+
let at = params.at;
|
|
5229
|
+
if (tokens[at] === "not") {
|
|
5230
|
+
const operand = parsePrimaryExpression({ tokens, at: at + 1 });
|
|
5231
|
+
if (operand === undefined)
|
|
5232
|
+
return;
|
|
5233
|
+
const inner = operand.kind === "atom" ? operand.text : `(${operand.text})`;
|
|
5234
|
+
return { text: `not ${inner}`, at: operand.at, kind: "atom" };
|
|
5235
|
+
}
|
|
5236
|
+
if (tokens[at] === "(") {
|
|
5237
|
+
const inner = parseOrExpression({ tokens, at: at + 1 });
|
|
5238
|
+
if (inner === undefined || tokens[inner.at] !== ")")
|
|
5239
|
+
return;
|
|
5240
|
+
return { text: inner.text, at: inner.at + 1, kind: inner.kind };
|
|
5241
|
+
}
|
|
5242
|
+
const parts = [];
|
|
5243
|
+
let depth = 0;
|
|
5244
|
+
while (at < tokens.length) {
|
|
5245
|
+
const token = tokens[at];
|
|
5246
|
+
if (depth === 0 && (token === "and" || token === "or" || token === ")"))
|
|
5247
|
+
break;
|
|
5248
|
+
if (token === "(")
|
|
5249
|
+
depth += 1;
|
|
5250
|
+
if (token === ")")
|
|
5251
|
+
depth -= 1;
|
|
5252
|
+
parts.push(token);
|
|
5253
|
+
at += 1;
|
|
5254
|
+
}
|
|
5255
|
+
if (parts.length === 0)
|
|
5256
|
+
return;
|
|
5257
|
+
if (parts[1] === "is" && (parts.length === 3 && parts[2] === "null" || parts.length === 4 && parts[2] === "not" && parts[3] === "null")) {
|
|
5258
|
+
const quoted = /^"([a-z_][a-z_0-9]*)"$/.exec(parts[0]);
|
|
5259
|
+
if (quoted !== null && !/^(?:true|false|null|unknown|default|user|current_.*|session_user|system_user|localtime|localtimestamp|and|or|not|is)$/.test(quoted[1]))
|
|
5260
|
+
parts[0] = quoted[1];
|
|
5261
|
+
}
|
|
5262
|
+
return { text: parts.join(" "), at, kind: "atom" };
|
|
5263
|
+
}
|
|
5264
|
+
|
|
5265
|
+
// packages/schema/src/unique-keys.ts
|
|
5266
|
+
var RANK = { primaryKey: 0, field: 1, block: 2, partial: 3, expression: 4 };
|
|
5267
|
+
function comparisonKey(params) {
|
|
5268
|
+
const { model, index } = params;
|
|
5269
|
+
const common = [index.nullsNotDistinct === true, normalizeWhere({ where: index.where }), index.include ?? []];
|
|
5270
|
+
if (isExpressionIndex({ index }))
|
|
5271
|
+
return JSON.stringify(["expression", indexKeyDefinitionKey({ index, model }), ...common]);
|
|
5272
|
+
return JSON.stringify(["fields", index.fields.map((field) => [field.name, field.sort === "desc", field.operatorClass ?? null]), ...common]);
|
|
5273
|
+
}
|
|
5274
|
+
function modelUniqueKeys(params) {
|
|
5275
|
+
const { model, dialect } = params;
|
|
5276
|
+
if (model.isView)
|
|
5277
|
+
return [];
|
|
5278
|
+
const table = model.dbName ?? model.name;
|
|
5279
|
+
const columnOf = (name) => model.fields.find((field) => field.name === name)?.dbName ?? name;
|
|
5280
|
+
const candidates = [];
|
|
5281
|
+
const primaryKey = model.primaryKey?.fields ?? model.fields.filter((field) => field.isId).map((field) => field.name);
|
|
5282
|
+
if (primaryKey.length > 0) {
|
|
5283
|
+
const name = dialect === "mysql" ? "PRIMARY" : dialect === "sqlite" ? null : model.primaryKeyConstraintName ?? defaultPrimaryKeyName({ table, dialect });
|
|
5284
|
+
candidates.push({
|
|
5285
|
+
rank: RANK.primaryKey,
|
|
5286
|
+
order: 0,
|
|
5287
|
+
natural: model.primaryKey?.clientName ?? primaryKey.join("_"),
|
|
5288
|
+
fallback: model.primaryKeyConstraintName ?? defaultPrimaryKeyName({ table, dialect: "sqlite" }),
|
|
5289
|
+
entry: { name, names: name === null ? [] : [name], fields: primaryKey, primaryKey: true, partial: false }
|
|
5290
|
+
});
|
|
5291
|
+
}
|
|
5292
|
+
const seen = new Set;
|
|
5293
|
+
const add = (params) => {
|
|
5294
|
+
const { index } = params;
|
|
5295
|
+
const identity = comparisonKey({ model, index });
|
|
5296
|
+
if (seen.has(identity))
|
|
5297
|
+
return;
|
|
5298
|
+
seen.add(identity);
|
|
5299
|
+
const partial = index.where !== undefined;
|
|
5300
|
+
if (isExpressionIndex({ index })) {
|
|
5301
|
+
const sourceFields = indexKeyFieldNames({ index });
|
|
5302
|
+
const indexName = index.name ?? (sourceFields === undefined ? undefined : defaultExpressionIndexName({ table, model, index, dialect }));
|
|
5303
|
+
if (indexName === undefined)
|
|
5304
|
+
return;
|
|
5305
|
+
const names = [...new Set([index.constraintName ?? indexName, indexName])];
|
|
5306
|
+
candidates.push({
|
|
5307
|
+
rank: RANK.expression,
|
|
5308
|
+
order: params.order,
|
|
5309
|
+
natural: sourceFields?.join("_"),
|
|
5310
|
+
fallback: index.name ?? defaultExpressionIndexName({ table, model, index, dialect: "sqlite" }),
|
|
5311
|
+
entry: { name: names[0], names, ...sourceFields === undefined ? {} : { sourceFields }, primaryKey: false, partial }
|
|
5312
|
+
});
|
|
5313
|
+
return;
|
|
5314
|
+
}
|
|
5315
|
+
const fields = index.fields.map((field) => field.name);
|
|
5316
|
+
const indexName = index.name ?? defaultIndexName({ table, columns: fields.map(columnOf), unique: true, dialect });
|
|
5317
|
+
const names = [...new Set([index.constraintName ?? indexName, indexName])];
|
|
5318
|
+
candidates.push({
|
|
5319
|
+
rank: partial ? RANK.partial : params.rank,
|
|
5320
|
+
order: params.order,
|
|
5321
|
+
natural: index.clientName ?? fields.join("_"),
|
|
5322
|
+
fallback: index.constraintName ?? index.name ?? defaultIndexName({ table, columns: fields.map(columnOf), unique: true, dialect: "sqlite" }),
|
|
5323
|
+
entry: { name: names[0], names, fields, primaryKey: false, partial }
|
|
5324
|
+
});
|
|
5325
|
+
};
|
|
5326
|
+
const fieldKey = (name) => ({ kind: "unique", fields: [{ name }] });
|
|
5327
|
+
model.indexes.forEach((index, position) => {
|
|
5328
|
+
if (index.kind !== "unique")
|
|
5329
|
+
return;
|
|
5330
|
+
const own = isExpressionIndex({ index }) || index.fields.length !== 1 ? -1 : model.fields.findIndex((field) => field.isUnique && field.name === index.fields[0].name && comparisonKey({ model, index }) === comparisonKey({ model, index: fieldKey(field.name) }));
|
|
5331
|
+
add({ index, rank: own >= 0 ? RANK.field : RANK.block, order: own >= 0 ? own : position });
|
|
5332
|
+
});
|
|
5333
|
+
model.fields.forEach((field, position) => {
|
|
5334
|
+
if (field.isUnique)
|
|
5335
|
+
add({ index: fieldKey(field.name), rank: RANK.field, order: position });
|
|
5336
|
+
});
|
|
5337
|
+
const claimed = new Set;
|
|
5338
|
+
const keyed = new Map;
|
|
5339
|
+
for (const candidate of [...candidates].sort((left, right) => left.rank - right.rank || left.order - right.order)) {
|
|
5340
|
+
let key = candidate.natural !== undefined && !claimed.has(candidate.natural) ? candidate.natural : candidate.fallback;
|
|
5341
|
+
for (let suffix = 2;claimed.has(key); suffix++)
|
|
5342
|
+
key = `${candidate.fallback}_${suffix}`;
|
|
5343
|
+
claimed.add(key);
|
|
5344
|
+
keyed.set(candidate, key);
|
|
5345
|
+
}
|
|
5346
|
+
return candidates.sort((left, right) => left.rank - right.rank || left.order - right.order).map((candidate) => ({ key: keyed.get(candidate), ...candidate.entry }));
|
|
5347
|
+
}
|
|
4543
5348
|
export {
|
|
4544
5349
|
CHECK_RULE_GROUP_MAX,
|
|
5350
|
+
CONNECTION_FAILURE_REASONS,
|
|
4545
5351
|
DATE_TRUNCATION_UNITS,
|
|
4546
5352
|
DIALECTS,
|
|
4547
5353
|
DIALECT_CAPABILITIES,
|
|
4548
5354
|
EMPTY_EXTENSION_REGISTRY,
|
|
4549
5355
|
ENUM_STORAGES,
|
|
5356
|
+
FAILURE_KINDS,
|
|
4550
5357
|
IDENTIFIER_LIMITS,
|
|
5358
|
+
INCLUDE_INDEX_KINDS,
|
|
4551
5359
|
MYSQL_CAPABILITIES,
|
|
4552
5360
|
MYSQL_FUNCTIONAL_KEY_LIMITS,
|
|
4553
5361
|
MYSQL_ROW_RULE_MESSAGE_MAX_BYTES,
|
|
@@ -4565,6 +5373,8 @@ export {
|
|
|
4565
5373
|
SQLITE_ROW_RULE_ERROR_PREFIX,
|
|
4566
5374
|
SQL_NAMESPACES,
|
|
4567
5375
|
ScopedQueryError,
|
|
5376
|
+
TABLE_STORAGE_KEYS,
|
|
5377
|
+
TABLE_STORAGE_PARAMETERS,
|
|
4568
5378
|
VIBE_ERROR_CODES,
|
|
4569
5379
|
VibeError,
|
|
4570
5380
|
assertExtensionModelPlacement,
|
|
@@ -4573,6 +5383,7 @@ export {
|
|
|
4573
5383
|
assertGeneratedColumns,
|
|
4574
5384
|
assertIdentifierFits,
|
|
4575
5385
|
assertIndexExpressions,
|
|
5386
|
+
assertIndexIncludeColumns,
|
|
4576
5387
|
assertIndexOperatorClasses,
|
|
4577
5388
|
assertJsonSchemaRef,
|
|
4578
5389
|
assertMigrationObjects,
|
|
@@ -4582,6 +5393,7 @@ export {
|
|
|
4582
5393
|
assertRowRuleEquality,
|
|
4583
5394
|
assertRowRuleReferentialActions,
|
|
4584
5395
|
assertSqlNamespace,
|
|
5396
|
+
assertTableStorage,
|
|
4585
5397
|
assertValidSchemaIR,
|
|
4586
5398
|
assertValidatorRef,
|
|
4587
5399
|
buildComputedManifest,
|
|
@@ -4596,18 +5408,25 @@ export {
|
|
|
4596
5408
|
defaultRowRuleName,
|
|
4597
5409
|
defineExtension,
|
|
4598
5410
|
dialectCollation,
|
|
5411
|
+
didYouMean,
|
|
5412
|
+
editDistance,
|
|
4599
5413
|
encodePrismaString,
|
|
4600
5414
|
enumStorageOf,
|
|
4601
5415
|
exactDecimalLiteral,
|
|
4602
5416
|
exactIntegerLiteral,
|
|
5417
|
+
exclusionFields,
|
|
4603
5418
|
extensionDeclarations,
|
|
4604
5419
|
extensionManifestEntry,
|
|
4605
5420
|
extensionOptionsHash,
|
|
5421
|
+
failureKindOf,
|
|
4606
5422
|
fieldTypeIdentity,
|
|
4607
5423
|
fitDefaultName,
|
|
4608
5424
|
generatedColumnFromSql,
|
|
4609
5425
|
generatedColumnShapeIssue,
|
|
5426
|
+
generatedTypeNames,
|
|
5427
|
+
hasIndexIncludeColumns,
|
|
4610
5428
|
hasJsonSchemaAnnotation,
|
|
5429
|
+
hasTableStorage,
|
|
4611
5430
|
hasValidatorAnnotation,
|
|
4612
5431
|
identifierLength,
|
|
4613
5432
|
implicitJoinTable,
|
|
@@ -4622,6 +5441,7 @@ export {
|
|
|
4622
5441
|
internalError,
|
|
4623
5442
|
invalidStoredData,
|
|
4624
5443
|
isCanonicalLocalDate,
|
|
5444
|
+
isConnectionFailureReason,
|
|
4625
5445
|
isEnumType,
|
|
4626
5446
|
isExpressionIndex,
|
|
4627
5447
|
isImplicitManyToManyRelation,
|
|
@@ -4632,17 +5452,22 @@ export {
|
|
|
4632
5452
|
isReservedDelegateName,
|
|
4633
5453
|
isSqlObjectDefinition,
|
|
4634
5454
|
isSqlObjectIdentity,
|
|
5455
|
+
isToastStorageKey,
|
|
5456
|
+
isUnknownNameRefusal,
|
|
4635
5457
|
jsonSchemaRefIssue,
|
|
4636
5458
|
jsonTypeAnnotationIssue,
|
|
4637
5459
|
jsonTypeAnnotationRef,
|
|
4638
5460
|
localDateCheckName,
|
|
4639
5461
|
mergeExtensionDeclarations,
|
|
4640
5462
|
modelSqlNamespace,
|
|
5463
|
+
modelUniqueKeys,
|
|
4641
5464
|
mysqlIndexKeyWidth,
|
|
4642
5465
|
mysqlRowRuleMessageByteLength,
|
|
4643
5466
|
normalizeJsonSchemaRef,
|
|
4644
5467
|
normalizeRowRules,
|
|
4645
5468
|
normalizeValidatorRef,
|
|
5469
|
+
normalizeWhere,
|
|
5470
|
+
parseTableStorageValue,
|
|
4646
5471
|
postgresGeneratedObjectName,
|
|
4647
5472
|
predicateCapabilityIssue,
|
|
4648
5473
|
predicateFieldNames,
|
|
@@ -4650,6 +5475,7 @@ export {
|
|
|
4650
5475
|
prepareDatabaseModuleSchema,
|
|
4651
5476
|
providerToDialect,
|
|
4652
5477
|
qualifiedSqlName,
|
|
5478
|
+
renderTableStorageValue,
|
|
4653
5479
|
resolveOnDelete,
|
|
4654
5480
|
resolveOnUpdate,
|
|
4655
5481
|
resolveReferentialActions,
|
|
@@ -4664,12 +5490,17 @@ export {
|
|
|
4664
5490
|
rowRuleTriggerName,
|
|
4665
5491
|
scalarListDefault,
|
|
4666
5492
|
schemaRowRuleIdentities,
|
|
5493
|
+
sealSchemaIR,
|
|
4667
5494
|
serializeJsonDefault,
|
|
4668
5495
|
setDefaultRelationOf,
|
|
4669
5496
|
sqlNamespaceIssue,
|
|
4670
5497
|
sqlObjectKey,
|
|
4671
5498
|
sqlObjectNamespace,
|
|
4672
5499
|
sqliteRowRuleConstraint,
|
|
5500
|
+
suggestName,
|
|
5501
|
+
tableStorageEntries,
|
|
5502
|
+
tableStorageKeyFromPrisma,
|
|
5503
|
+
tableStoragePrismaKey,
|
|
4673
5504
|
timeOfDayType,
|
|
4674
5505
|
unsupportedCapability,
|
|
4675
5506
|
validateComputedConfig,
|
|
@@ -4678,7 +5509,8 @@ export {
|
|
|
4678
5509
|
validateRlsContextIR,
|
|
4679
5510
|
validateRowRules,
|
|
4680
5511
|
validateSchemaIR,
|
|
4681
|
-
validatorRefIssue
|
|
5512
|
+
validatorRefIssue,
|
|
5513
|
+
withSuggestion
|
|
4682
5514
|
};
|
|
4683
5515
|
|
|
4684
|
-
//# debugId=
|
|
5516
|
+
//# debugId=D9E0341E199A9F8664756E2164756E21
|