@vibeorm/schema 5.8.0 → 5.9.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 +29 -0
- package/dist/index-include.d.ts +18 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +362 -39
- package/dist/index.js.map +9 -7
- package/dist/ir.d.ts +63 -0
- package/dist/table-storage.d.ts +66 -0
- package/dist/validate.d.ts +23 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -442,6 +442,8 @@ var POSTGRES_CAPABILITIES = Object.freeze({
|
|
|
442
442
|
fixedNamespaces: true,
|
|
443
443
|
externalObjects: true,
|
|
444
444
|
indexOperatorClasses: true,
|
|
445
|
+
indexIncludeColumns: true,
|
|
446
|
+
tableStorageParameters: true,
|
|
445
447
|
exclusionConstraints: true,
|
|
446
448
|
exclusionExtensions: Object.freeze(["btree_gist"]),
|
|
447
449
|
checkNormalization: "rollback",
|
|
@@ -474,7 +476,10 @@ var POSTGRES_CAPABILITIES = Object.freeze({
|
|
|
474
476
|
uuidColumns: "native",
|
|
475
477
|
localDateColumns: true,
|
|
476
478
|
dateTruncation: true,
|
|
477
|
-
|
|
479
|
+
filteredAggregates: "filterClause",
|
|
480
|
+
groupingSets: "groupingSets",
|
|
481
|
+
rowCapture: true,
|
|
482
|
+
returningReadsJoinedSource: true
|
|
478
483
|
});
|
|
479
484
|
var SQLITE_CAPABILITIES = Object.freeze({
|
|
480
485
|
rowRuleAppendOnly: true,
|
|
@@ -484,6 +489,8 @@ var SQLITE_CAPABILITIES = Object.freeze({
|
|
|
484
489
|
fixedNamespaces: false,
|
|
485
490
|
externalObjects: false,
|
|
486
491
|
indexOperatorClasses: false,
|
|
492
|
+
indexIncludeColumns: false,
|
|
493
|
+
tableStorageParameters: false,
|
|
487
494
|
exclusionConstraints: false,
|
|
488
495
|
exclusionExtensions: Object.freeze([]),
|
|
489
496
|
checkNormalization: "sourceText",
|
|
@@ -516,7 +523,10 @@ var SQLITE_CAPABILITIES = Object.freeze({
|
|
|
516
523
|
uuidColumns: "text",
|
|
517
524
|
localDateColumns: true,
|
|
518
525
|
dateTruncation: false,
|
|
519
|
-
|
|
526
|
+
filteredAggregates: "filterClause",
|
|
527
|
+
groupingSets: "none",
|
|
528
|
+
rowCapture: false,
|
|
529
|
+
returningReadsJoinedSource: false
|
|
520
530
|
});
|
|
521
531
|
var MYSQL_CAPABILITIES = Object.freeze({
|
|
522
532
|
rowRuleAppendOnly: true,
|
|
@@ -526,6 +536,8 @@ var MYSQL_CAPABILITIES = Object.freeze({
|
|
|
526
536
|
fixedNamespaces: false,
|
|
527
537
|
externalObjects: false,
|
|
528
538
|
indexOperatorClasses: false,
|
|
539
|
+
indexIncludeColumns: false,
|
|
540
|
+
tableStorageParameters: false,
|
|
529
541
|
exclusionConstraints: false,
|
|
530
542
|
exclusionExtensions: Object.freeze([]),
|
|
531
543
|
checkNormalization: "temporary",
|
|
@@ -558,7 +570,10 @@ var MYSQL_CAPABILITIES = Object.freeze({
|
|
|
558
570
|
uuidColumns: "unsupported",
|
|
559
571
|
localDateColumns: true,
|
|
560
572
|
dateTruncation: false,
|
|
561
|
-
|
|
573
|
+
filteredAggregates: "caseWhen",
|
|
574
|
+
groupingSets: "rollup",
|
|
575
|
+
rowCapture: false,
|
|
576
|
+
returningReadsJoinedSource: false
|
|
562
577
|
});
|
|
563
578
|
var DIALECT_CAPABILITIES = Object.freeze({
|
|
564
579
|
postgres: POSTGRES_CAPABILITIES,
|
|
@@ -1070,10 +1085,12 @@ function shapeIssue(params) {
|
|
|
1070
1085
|
const { index } = params;
|
|
1071
1086
|
if (!dataOnly({ value: index }))
|
|
1072
1087
|
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"] }))
|
|
1088
|
+
if (!record({ value: index, required: ["kind", "fields", "expressions"], optional: ["name", "clientName", "constraintName", "where", "wherePredicate", "nullsNotDistinct", "include"] }))
|
|
1074
1089
|
return "Expression indexes require canonical index data properties";
|
|
1075
1090
|
if (typeof index.kind !== "string")
|
|
1076
1091
|
return "Index kind must be a string";
|
|
1092
|
+
if (index.include !== undefined && (!Array.isArray(index.include) || index.include.some((name) => !text({ value: name }))))
|
|
1093
|
+
return "Expression index INCLUDE columns must be a list of field names";
|
|
1077
1094
|
if (index.nullsNotDistinct !== undefined && typeof index.nullsNotDistinct !== "boolean" || index.name !== undefined && !text({ value: index.name }) || index.where !== undefined && !text({ value: index.where }))
|
|
1078
1095
|
return "Expression index names, predicates and flags must have their canonical data types";
|
|
1079
1096
|
const descriptor = Object.getOwnPropertyDescriptor(index, "expressions");
|
|
@@ -1139,14 +1156,15 @@ function structuralData(params) {
|
|
|
1139
1156
|
}
|
|
1140
1157
|
function indexKeyDefinitionKey(params) {
|
|
1141
1158
|
const { index, model } = params;
|
|
1159
|
+
const include = index.include === undefined ? [] : [{ include: index.include.map((name) => model?.fields.find((entry) => entry.name === name)?.dbName ?? name) }];
|
|
1142
1160
|
if (!isExpressionIndex({ index })) {
|
|
1143
1161
|
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() ?? ""]);
|
|
1162
|
+
return JSON.stringify([index.kind === "unique", index.nullsNotDistinct === true, index.kind === "unique" ? "btree" : index.kind, columns, index.where?.trim() ?? "", ...include]);
|
|
1145
1163
|
}
|
|
1146
1164
|
const issue = shapeIssue({ index });
|
|
1147
1165
|
if (issue !== undefined)
|
|
1148
1166
|
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]);
|
|
1167
|
+
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
1168
|
}
|
|
1151
1169
|
function scalarType(params) {
|
|
1152
1170
|
const { expression, model, dialect, add } = params;
|
|
@@ -2335,6 +2353,172 @@ function assertIndexOperatorClasses(params) {
|
|
|
2335
2353
|
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
2354
|
}
|
|
2337
2355
|
}
|
|
2356
|
+
// packages/schema/src/index-include.ts
|
|
2357
|
+
var INCLUDE_INDEX_KINDS = Object.freeze(["btree", "unique", "gist", "spgist"]);
|
|
2358
|
+
function hasIndexIncludeColumns(params) {
|
|
2359
|
+
return params.schema.models.some((model) => model.indexes.some((index) => index.include !== undefined));
|
|
2360
|
+
}
|
|
2361
|
+
function assertIndexIncludeColumns(params) {
|
|
2362
|
+
const { schema, dialect } = params;
|
|
2363
|
+
for (const model of schema.models)
|
|
2364
|
+
for (const index of model.indexes) {
|
|
2365
|
+
const include = index.include;
|
|
2366
|
+
if (include === undefined)
|
|
2367
|
+
continue;
|
|
2368
|
+
const site = `${index.kind === "unique" ? "@@unique" : "@@index"}${index.name === undefined ? "" : ` "${index.name}"`} on "${model.name}"`;
|
|
2369
|
+
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 } } });
|
|
2370
|
+
if (!Array.isArray(include) || include.length === 0 || include.some((name) => typeof name !== "string" || name === ""))
|
|
2371
|
+
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)" });
|
|
2372
|
+
if (!DIALECT_CAPABILITIES[dialect].indexIncludeColumns)
|
|
2373
|
+
throw unsupportedCapability({ dialect, feature: "indexIncludeColumns", hint: `${site} declares INCLUDE columns; covering indexes are PostgreSQL only` });
|
|
2374
|
+
if (!INCLUDE_INDEX_KINDS.includes(index.kind))
|
|
2375
|
+
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` });
|
|
2376
|
+
const keys = keyColumns({ index });
|
|
2377
|
+
const seen = new Set;
|
|
2378
|
+
for (const name of include) {
|
|
2379
|
+
if (!model.fields.some((field) => field.name === name))
|
|
2380
|
+
throw invalid({ rule: "index-include-field", message: `include names "${name}", which is not a scalar field of the model`, field: name });
|
|
2381
|
+
if (seen.has(name))
|
|
2382
|
+
throw invalid({ rule: "index-include-duplicate", message: `include lists "${name}" twice`, field: name });
|
|
2383
|
+
if (keys.has(name))
|
|
2384
|
+
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 });
|
|
2385
|
+
seen.add(name);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
function keyColumns(params) {
|
|
2390
|
+
return new Set(indexKeyTerms({ index: params.index }).flatMap((term) => term.kind === "field" ? [term.field.name] : []));
|
|
2391
|
+
}
|
|
2392
|
+
// packages/schema/src/table-storage.ts
|
|
2393
|
+
var INT_MAX = 2147483647;
|
|
2394
|
+
var HEAP_ONLY = {
|
|
2395
|
+
fillfactor: { type: "integer", min: 10, max: 100 },
|
|
2396
|
+
toast_tuple_target: { type: "integer", min: 128, max: 8160 },
|
|
2397
|
+
parallel_workers: { type: "integer", min: 0, max: 1024 },
|
|
2398
|
+
autovacuum_analyze_threshold: { type: "integer", min: 0, max: INT_MAX },
|
|
2399
|
+
autovacuum_analyze_scale_factor: { type: "real", min: 0, max: 100 }
|
|
2400
|
+
};
|
|
2401
|
+
var VACUUM = {
|
|
2402
|
+
autovacuum_enabled: { type: "boolean" },
|
|
2403
|
+
vacuum_index_cleanup: { type: "enum", values: ["auto", "on", "off"] },
|
|
2404
|
+
vacuum_truncate: { type: "boolean" },
|
|
2405
|
+
autovacuum_vacuum_threshold: { type: "integer", min: 0, max: INT_MAX },
|
|
2406
|
+
autovacuum_vacuum_scale_factor: { type: "real", min: 0, max: 100 },
|
|
2407
|
+
autovacuum_vacuum_insert_threshold: { type: "integer", min: -1, max: INT_MAX },
|
|
2408
|
+
autovacuum_vacuum_insert_scale_factor: { type: "real", min: 0, max: 100 },
|
|
2409
|
+
autovacuum_vacuum_cost_delay: { type: "real", min: 0, max: 100 },
|
|
2410
|
+
autovacuum_vacuum_cost_limit: { type: "integer", min: 1, max: 1e4 },
|
|
2411
|
+
autovacuum_freeze_min_age: { type: "integer", min: 0, max: 1e9 },
|
|
2412
|
+
autovacuum_freeze_max_age: { type: "integer", min: 1e5, max: 2000000000 },
|
|
2413
|
+
autovacuum_freeze_table_age: { type: "integer", min: 0, max: 2000000000 },
|
|
2414
|
+
autovacuum_multixact_freeze_min_age: { type: "integer", min: 0, max: 1e9 },
|
|
2415
|
+
autovacuum_multixact_freeze_max_age: { type: "integer", min: 1e4, max: 2000000000 },
|
|
2416
|
+
autovacuum_multixact_freeze_table_age: { type: "integer", min: 0, max: 2000000000 },
|
|
2417
|
+
log_autovacuum_min_duration: { type: "integer", min: -1, max: INT_MAX }
|
|
2418
|
+
};
|
|
2419
|
+
var TABLE_STORAGE_PARAMETERS = Object.freeze({
|
|
2420
|
+
...HEAP_ONLY,
|
|
2421
|
+
...VACUUM,
|
|
2422
|
+
...Object.fromEntries(Object.entries(VACUUM).map(([key, spec]) => [`toast.${key}`, spec]))
|
|
2423
|
+
});
|
|
2424
|
+
var TABLE_STORAGE_KEYS = Object.freeze(Object.keys(TABLE_STORAGE_PARAMETERS));
|
|
2425
|
+
var TOAST_PREFIX = "toast.";
|
|
2426
|
+
function specOf(params) {
|
|
2427
|
+
return Object.hasOwn(TABLE_STORAGE_PARAMETERS, params.key) ? TABLE_STORAGE_PARAMETERS[params.key] : undefined;
|
|
2428
|
+
}
|
|
2429
|
+
function isToastStorageKey(params) {
|
|
2430
|
+
return params.key.startsWith(TOAST_PREFIX);
|
|
2431
|
+
}
|
|
2432
|
+
function tableStoragePrismaKey(params) {
|
|
2433
|
+
return isToastStorageKey(params) ? `toast_${params.key.slice(TOAST_PREFIX.length)}` : params.key;
|
|
2434
|
+
}
|
|
2435
|
+
function tableStorageKeyFromPrisma(params) {
|
|
2436
|
+
if (specOf({ key: params.name }) !== undefined)
|
|
2437
|
+
return params.name;
|
|
2438
|
+
if (!params.name.startsWith("toast_"))
|
|
2439
|
+
return;
|
|
2440
|
+
const key = `${TOAST_PREFIX}${params.name.slice("toast_".length)}`;
|
|
2441
|
+
return specOf({ key }) === undefined ? undefined : key;
|
|
2442
|
+
}
|
|
2443
|
+
var TRUE_WORDS = new Set(["true", "t", "on", "yes", "y", "1"]);
|
|
2444
|
+
var FALSE_WORDS = new Set(["false", "f", "off", "no", "n", "0"]);
|
|
2445
|
+
function parseTableStorageValue(params) {
|
|
2446
|
+
const spec = specOf({ key: params.key });
|
|
2447
|
+
if (spec === undefined)
|
|
2448
|
+
return;
|
|
2449
|
+
const text = params.text.trim().toLowerCase();
|
|
2450
|
+
switch (spec.type) {
|
|
2451
|
+
case "boolean":
|
|
2452
|
+
return TRUE_WORDS.has(text) ? true : FALSE_WORDS.has(text) ? false : undefined;
|
|
2453
|
+
case "enum":
|
|
2454
|
+
return spec.values?.includes(text) === true ? text : TRUE_WORDS.has(text) ? "on" : FALSE_WORDS.has(text) ? "off" : undefined;
|
|
2455
|
+
case "integer":
|
|
2456
|
+
case "real": {
|
|
2457
|
+
if (text === "" || !/^[-+]?(\d+(\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(text))
|
|
2458
|
+
return;
|
|
2459
|
+
const value = Number(text);
|
|
2460
|
+
return Number.isFinite(value) ? value : undefined;
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
function renderTableStorageValue(params) {
|
|
2465
|
+
return typeof params.value === "boolean" ? params.value ? "true" : "false" : String(params.value);
|
|
2466
|
+
}
|
|
2467
|
+
function valueIssue(params) {
|
|
2468
|
+
const { spec, value } = params;
|
|
2469
|
+
switch (spec.type) {
|
|
2470
|
+
case "boolean":
|
|
2471
|
+
return typeof value === "boolean" ? undefined : "takes true or false";
|
|
2472
|
+
case "enum":
|
|
2473
|
+
return typeof value === "string" && spec.values?.includes(value) === true ? undefined : `takes one of ${spec.values?.map((entry) => `"${entry}"`).join(", ")}`;
|
|
2474
|
+
case "integer":
|
|
2475
|
+
case "real": {
|
|
2476
|
+
const bounds = `between ${spec.min} and ${spec.max}`;
|
|
2477
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
2478
|
+
return `takes a number ${bounds}`;
|
|
2479
|
+
if (spec.type === "integer" && !Number.isInteger(value))
|
|
2480
|
+
return `takes a whole number ${bounds}`;
|
|
2481
|
+
return value < (spec.min ?? -Infinity) || value > (spec.max ?? Infinity) ? `takes a value ${bounds}` : undefined;
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
function hasTableStorage(params) {
|
|
2486
|
+
return params.schema.models.some((model) => model.storage !== undefined);
|
|
2487
|
+
}
|
|
2488
|
+
function assertTableStorage(params) {
|
|
2489
|
+
const { schema, dialect } = params;
|
|
2490
|
+
for (const model of schema.models) {
|
|
2491
|
+
const storage = model.storage;
|
|
2492
|
+
if (storage === undefined)
|
|
2493
|
+
continue;
|
|
2494
|
+
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 } } });
|
|
2495
|
+
if (storage === null || typeof storage !== "object" || Array.isArray(storage) || Object.keys(storage).length === 0)
|
|
2496
|
+
throw invalid({ rule: "table-storage-shape", message: "storage takes a non-empty record of parameters (omit it for a table without any)" });
|
|
2497
|
+
if (model.isView)
|
|
2498
|
+
throw invalid({ rule: "table-storage-view", message: "a view has no table storage parameters" });
|
|
2499
|
+
if (!DIALECT_CAPABILITIES[dialect].tableStorageParameters)
|
|
2500
|
+
throw unsupportedCapability({ dialect, feature: "tableStorageParameters", hint: `@@storage on "${model.name}" declares table storage parameters; they are PostgreSQL only` });
|
|
2501
|
+
for (const [key, value] of Object.entries(storage)) {
|
|
2502
|
+
const spec = specOf({ key });
|
|
2503
|
+
if (spec === undefined)
|
|
2504
|
+
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 });
|
|
2505
|
+
const issue = valueIssue({ spec, value });
|
|
2506
|
+
if (issue !== undefined)
|
|
2507
|
+
throw invalid({ rule: "table-storage-value", message: `"${key}" ${issue}`, parameter: key });
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
function tableStorageEntries(params) {
|
|
2512
|
+
const storage = params.model.storage;
|
|
2513
|
+
if (storage === undefined)
|
|
2514
|
+
return [];
|
|
2515
|
+
const known = TABLE_STORAGE_KEYS.flatMap((key) => {
|
|
2516
|
+
const value = Object.hasOwn(storage, key) ? storage[key] : undefined;
|
|
2517
|
+
return value === undefined ? [] : [[key, value]];
|
|
2518
|
+
});
|
|
2519
|
+
const unknown = Object.entries(storage).flatMap(([key, value]) => specOf({ key }) !== undefined || value === undefined ? [] : [[key, value]]);
|
|
2520
|
+
return [...known, ...unknown];
|
|
2521
|
+
}
|
|
2338
2522
|
// packages/schema/src/module-schema.ts
|
|
2339
2523
|
function prepareDatabaseModuleSchema(params) {
|
|
2340
2524
|
const { schema, module } = params;
|
|
@@ -2857,6 +3041,8 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2857
3041
|
"SelectionMember",
|
|
2858
3042
|
"SelectionValue",
|
|
2859
3043
|
"BagKeys",
|
|
3044
|
+
"__VibeBagKeysIn",
|
|
3045
|
+
"__VibeCertain",
|
|
2860
3046
|
"IncludedRelation",
|
|
2861
3047
|
"IncludedCount",
|
|
2862
3048
|
"ViewDelegateMap",
|
|
@@ -2865,6 +3051,8 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2865
3051
|
"__VibeAt",
|
|
2866
3052
|
"__VibeItem",
|
|
2867
3053
|
"__VibeExact",
|
|
3054
|
+
"__VibePreviousInput",
|
|
3055
|
+
"__VibePrevious",
|
|
2868
3056
|
"extensionManifest",
|
|
2869
3057
|
"extensionMounts",
|
|
2870
3058
|
"computedManifest",
|
|
@@ -2905,6 +3093,12 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2905
3093
|
"RowLockRequest",
|
|
2906
3094
|
"GroupByTruncateUnit",
|
|
2907
3095
|
"GroupByKeyName",
|
|
3096
|
+
"GroupByPath",
|
|
3097
|
+
"GroupByExpressionValues",
|
|
3098
|
+
"GroupByKeyOrderInput",
|
|
3099
|
+
"GroupByOrderKeys",
|
|
3100
|
+
"GroupByKeyOrderCheck",
|
|
3101
|
+
"GroupingSetRow",
|
|
2908
3102
|
"JsonValue",
|
|
2909
3103
|
"InputJsonValue",
|
|
2910
3104
|
"InputJsonArray",
|
|
@@ -2930,9 +3124,20 @@ var RESERVED_ENUM_NAMES = [
|
|
|
2930
3124
|
"createClient",
|
|
2931
3125
|
"DatabaseAdapter",
|
|
2932
3126
|
"DbNow",
|
|
3127
|
+
"BigIntFieldRef",
|
|
3128
|
+
"BooleanFieldRef",
|
|
3129
|
+
"DateTimeFieldRef",
|
|
3130
|
+
"DecimalFieldRef",
|
|
3131
|
+
"EnumFieldRef",
|
|
3132
|
+
"FloatFieldRef",
|
|
3133
|
+
"IntFieldRef",
|
|
3134
|
+
"NumericFieldRef",
|
|
3135
|
+
"StringFieldRef",
|
|
2933
3136
|
"JoinedField",
|
|
2934
3137
|
"TransactionLocalSettings",
|
|
2935
3138
|
"VibeUpdateManySources",
|
|
3139
|
+
"VibeModelRows",
|
|
3140
|
+
"VibeHandleTypes",
|
|
2936
3141
|
"ClientContext",
|
|
2937
3142
|
"QueryOperation",
|
|
2938
3143
|
"QueryEvent",
|
|
@@ -3016,6 +3221,12 @@ var GENERATED_TYPE_NAMES = {
|
|
|
3016
3221
|
"HavingInput",
|
|
3017
3222
|
"GroupByOrderByInput",
|
|
3018
3223
|
"GroupByTruncatedKey",
|
|
3224
|
+
"GroupByExpressionKey",
|
|
3225
|
+
"FilteredAggregateInput",
|
|
3226
|
+
"FilteredAggregateHavingInput",
|
|
3227
|
+
"FilteredAggregateOrderByInput",
|
|
3228
|
+
"FilteredResult",
|
|
3229
|
+
"CoalesceOrderInput",
|
|
3019
3230
|
"FindManyArgs",
|
|
3020
3231
|
"FindPageArgs",
|
|
3021
3232
|
"FindFirstArgs",
|
|
@@ -3065,6 +3276,7 @@ var GENERATED_TYPE_NAMES = {
|
|
|
3065
3276
|
"ViewDelegate",
|
|
3066
3277
|
"ReadOnlyDelegate"
|
|
3067
3278
|
],
|
|
3279
|
+
generatedColumnSuffixes: ["WritableScalarFieldEnum", "GeneratedWriteGuard", "GeneratedBulkWriteRow"],
|
|
3068
3280
|
nestedPrefixes: [
|
|
3069
3281
|
"Create",
|
|
3070
3282
|
"UncheckedCreate",
|
|
@@ -3140,33 +3352,118 @@ var INVALID_BINDING_NAMES = new Set([
|
|
|
3140
3352
|
"object",
|
|
3141
3353
|
"undefined"
|
|
3142
3354
|
]);
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3355
|
+
var DISAMBIGUATED_TYPE_SUFFIXES = {
|
|
3356
|
+
ListRelationFilter: true,
|
|
3357
|
+
RelationFilter: true,
|
|
3358
|
+
RelationOrderByInput: true,
|
|
3359
|
+
RelationFindManyArgs: true,
|
|
3360
|
+
CreateArgs: true,
|
|
3361
|
+
UpdateArgs: true,
|
|
3362
|
+
UpdateWhereInput: true,
|
|
3363
|
+
UpsertArgs: true,
|
|
3364
|
+
DeleteArgs: true,
|
|
3365
|
+
CountArgs: true,
|
|
3366
|
+
CountSelect: true,
|
|
3367
|
+
AggregateArgs: true,
|
|
3368
|
+
ViewSelect: true,
|
|
3369
|
+
ViewInclude: true,
|
|
3370
|
+
ViewFindManyArgs: true,
|
|
3371
|
+
ViewFindUniqueArgs: true,
|
|
3372
|
+
ViewDelegate: true
|
|
3373
|
+
};
|
|
3374
|
+
function isDisambiguatedTypeSuffix(suffix) {
|
|
3375
|
+
return Object.hasOwn(DISAMBIGUATED_TYPE_SUFFIXES, suffix);
|
|
3376
|
+
}
|
|
3377
|
+
function generatedNameClaims(params) {
|
|
3378
|
+
const { schema } = params;
|
|
3379
|
+
const claims = [];
|
|
3380
|
+
const fixed = (options) => {
|
|
3381
|
+
for (const name of options.names)
|
|
3382
|
+
claims.push({ name, owner: options.owner, kind: "client", stem: name, suffix: "" });
|
|
3383
|
+
};
|
|
3384
|
+
fixed({ names: RESERVED_ENUM_NAMES, owner: "generated client" });
|
|
3146
3385
|
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");
|
|
3386
|
+
fixed({ names: ["RlsContext", "BoundVibeClientInstance", "BoundVibeTransactionClientInstance", "OperatorVibeClientInstance", "OperatorVibeTransactionClientInstance"], owner: "native RLS client" });
|
|
3152
3387
|
}
|
|
3153
3388
|
if (schema.models.some((model) => model.policy !== undefined))
|
|
3154
|
-
|
|
3389
|
+
fixed({ names: ["PolicyClientInstance"], owner: "policy client" });
|
|
3155
3390
|
if (schema.models.some((model) => model.fields.some((field) => isLocalDateField({ field })))) {
|
|
3156
|
-
|
|
3157
|
-
owners.set(name, "local-date filters");
|
|
3391
|
+
fixed({ names: ["LocalDate", "LocalDateFilter", "LocalDateNullableFilter"], owner: "local-date filters" });
|
|
3158
3392
|
}
|
|
3159
|
-
const
|
|
3160
|
-
|
|
3161
|
-
|
|
3393
|
+
for (const model of schema.models) {
|
|
3394
|
+
const owner = `model "${model.name}"`;
|
|
3395
|
+
const claim = (suffix) => {
|
|
3396
|
+
claims.push({ name: `${model.name}${suffix}`, owner, kind: "model", stem: model.name, suffix });
|
|
3397
|
+
};
|
|
3398
|
+
for (const suffix of GENERATED_TYPE_NAMES.modelSuffixes)
|
|
3399
|
+
claim(suffix);
|
|
3400
|
+
if (model.fields.some((field) => field.generated !== undefined && field.isUnsupported !== true)) {
|
|
3401
|
+
for (const suffix of GENERATED_TYPE_NAMES.generatedColumnSuffixes)
|
|
3402
|
+
claim(suffix);
|
|
3162
3403
|
}
|
|
3163
|
-
const
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3404
|
+
const withouts = ["", ...model.relations.map((relation) => `Without${relation.name.charAt(0).toUpperCase()}${relation.name.slice(1)}`)];
|
|
3405
|
+
for (const without of withouts) {
|
|
3406
|
+
for (const prefix of GENERATED_TYPE_NAMES.nestedPrefixes)
|
|
3407
|
+
claim(`${prefix}${without}Input`);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
for (const declared of schema.enums) {
|
|
3411
|
+
for (const suffix of GENERATED_TYPE_NAMES.enumSuffixes) {
|
|
3412
|
+
claims.push({ name: `${declared.name}${suffix}`, owner: `enum "${declared.name}"`, kind: "enum", stem: declared.name, suffix });
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
return claims;
|
|
3416
|
+
}
|
|
3417
|
+
function renameHint(params) {
|
|
3418
|
+
const named = [params.claim, params.keeper].filter((claim) => claim.kind !== "client");
|
|
3419
|
+
const table = named.some((claim) => claim.kind === "model") ? " (@@map, or map in the DSL, keeps a model's table name)" : "";
|
|
3420
|
+
return `rename ${[...new Set(named.map((claim) => claim.owner))].join(" or ")}${table}`;
|
|
3421
|
+
}
|
|
3422
|
+
function resolveGeneratedNames(params) {
|
|
3423
|
+
const claims = generatedNameClaims({ schema: params.schema });
|
|
3424
|
+
const issues = [];
|
|
3425
|
+
const keepers = new Map;
|
|
3426
|
+
for (const claim of claims) {
|
|
3427
|
+
if (claim.kind !== "client" && (!/^[$_\p{ID_Start}][$_\u200c\u200d\p{ID_Continue}]*$/u.test(claim.name) || INVALID_BINDING_NAMES.has(claim.name))) {
|
|
3428
|
+
issues.push({ rule: "invalid-generated-identifier", message: `Generated name "${claim.name}" from ${claim.owner} is not a legal TypeScript identifier` });
|
|
3429
|
+
}
|
|
3430
|
+
const keeper = keepers.get(claim.name);
|
|
3431
|
+
if (keeper === undefined || claim.stem.length > keeper.stem.length)
|
|
3432
|
+
keepers.set(claim.name, claim);
|
|
3433
|
+
}
|
|
3434
|
+
const renamed = new Map;
|
|
3435
|
+
const moved = [];
|
|
3436
|
+
for (const claim of claims) {
|
|
3437
|
+
const keeper = keepers.get(claim.name) ?? claim;
|
|
3438
|
+
if (keeper.owner === claim.owner)
|
|
3439
|
+
continue;
|
|
3440
|
+
if (claim.kind === "model" && isDisambiguatedTypeSuffix(claim.suffix) && keeper.suffix !== "" && claim.stem.length < keeper.stem.length) {
|
|
3441
|
+
const name = `${claim.stem}_${claim.suffix}`;
|
|
3442
|
+
renamed.set(`${claim.stem}\x00${claim.suffix}`, name);
|
|
3443
|
+
moved.push({ claim, keeper, name });
|
|
3444
|
+
continue;
|
|
3168
3445
|
}
|
|
3446
|
+
issues.push({ rule: "generated-name-collision", message: `Generated name "${claim.name}" from ${claim.owner} conflicts with ${keeper.owner}; ${renameHint({ claim, keeper })}` });
|
|
3447
|
+
}
|
|
3448
|
+
for (const { claim, keeper, name } of moved) {
|
|
3449
|
+
const taken = keepers.get(name);
|
|
3450
|
+
if (taken === undefined || taken.owner === claim.owner)
|
|
3451
|
+
continue;
|
|
3452
|
+
issues.push({
|
|
3453
|
+
rule: "generated-name-collision",
|
|
3454
|
+
message: `Generated name "${name}" from ${claim.owner} (renamed because ${keeper.owner} keeps "${claim.name}") conflicts with ${taken.owner}; ${renameHint({ claim, keeper: taken })}`
|
|
3455
|
+
});
|
|
3456
|
+
}
|
|
3457
|
+
return { renamed, issues };
|
|
3458
|
+
}
|
|
3459
|
+
function generatedTypeNames(params) {
|
|
3460
|
+
const { renamed } = resolveGeneratedNames({ schema: params.schema });
|
|
3461
|
+
return {
|
|
3462
|
+
model: ({ model, suffix }) => renamed.get(`${model}\x00${suffix}`) ?? `${model}${suffix}`
|
|
3169
3463
|
};
|
|
3464
|
+
}
|
|
3465
|
+
function validateGeneratedNames(params) {
|
|
3466
|
+
const { schema, issues } = params;
|
|
3170
3467
|
const aliases = new Map;
|
|
3171
3468
|
for (const model of schema.models) {
|
|
3172
3469
|
const clientName = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
@@ -3180,19 +3477,8 @@ function validateGeneratedNames(params) {
|
|
|
3180
3477
|
if (RESERVED_CLIENT_NAMES.includes(clientName)) {
|
|
3181
3478
|
issues.push({ rule: "reserved-client-name", message: `Model "${model.name}" conflicts with client member "${clientName}"`, model: model.name });
|
|
3182
3479
|
}
|
|
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
3480
|
}
|
|
3481
|
+
issues.push(...resolveGeneratedNames({ schema }).issues);
|
|
3196
3482
|
}
|
|
3197
3483
|
function foreignKeyKeys(params) {
|
|
3198
3484
|
const distinct = new Set;
|
|
@@ -3495,7 +3781,7 @@ function validatePhysicalNameUniqueness(params) {
|
|
|
3495
3781
|
for (const { index, site } of declarations) {
|
|
3496
3782
|
const unique = index.kind === "unique";
|
|
3497
3783
|
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() ?? ""]);
|
|
3784
|
+
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
3785
|
if (seenIndexKeys.has(key))
|
|
3500
3786
|
continue;
|
|
3501
3787
|
seenIndexKeys.add(key);
|
|
@@ -3933,6 +4219,27 @@ function validateModel(params) {
|
|
|
3933
4219
|
}
|
|
3934
4220
|
}
|
|
3935
4221
|
}
|
|
4222
|
+
if (relation.inverseKey !== undefined) {
|
|
4223
|
+
const { fields, references } = relation.inverseKey;
|
|
4224
|
+
if (relation.isList || hasFields || hasReferences || !Array.isArray(fields) || !Array.isArray(references) || fields.length === 0 || fields.length !== references.length) {
|
|
4225
|
+
issues.push({
|
|
4226
|
+
rule: "inverse-key-shape",
|
|
4227
|
+
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`,
|
|
4228
|
+
model: model.name,
|
|
4229
|
+
field: relation.name
|
|
4230
|
+
});
|
|
4231
|
+
} else {
|
|
4232
|
+
for (const name of fields) {
|
|
4233
|
+
if (!fieldNames.has(name))
|
|
4234
|
+
issues.push({ rule: "unknown-relation-field", message: `Relation "${model.name}.${relation.name}" uses unknown inverse-key field "${name}"`, model: model.name, field: relation.name });
|
|
4235
|
+
}
|
|
4236
|
+
const targetFields = target === undefined ? undefined : lookups.fieldsByModel.get(target);
|
|
4237
|
+
for (const name of references) {
|
|
4238
|
+
if (targetFields !== undefined && !targetFields.has(name))
|
|
4239
|
+
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 });
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
3936
4243
|
}
|
|
3937
4244
|
for (const field of model.fields) {
|
|
3938
4245
|
if (field.collation !== undefined && (field.type !== "String" || isLocalDateField({ field }))) {
|
|
@@ -4240,6 +4547,8 @@ function assertValidSchemaIR(params) {
|
|
|
4240
4547
|
}
|
|
4241
4548
|
assertExtensionPlacement({ schema: params.schema, dialect });
|
|
4242
4549
|
assertIndexOperatorClasses({ schema: params.schema, dialect });
|
|
4550
|
+
assertIndexIncludeColumns({ schema: params.schema, dialect });
|
|
4551
|
+
assertTableStorage({ schema: params.schema, dialect });
|
|
4243
4552
|
for (const entry of [...params.schema.models, ...params.schema.enums])
|
|
4244
4553
|
if (entry.namespace !== undefined)
|
|
4245
4554
|
assertSqlNamespace({ namespace: entry.namespace, dialect });
|
|
@@ -4548,6 +4857,7 @@ export {
|
|
|
4548
4857
|
EMPTY_EXTENSION_REGISTRY,
|
|
4549
4858
|
ENUM_STORAGES,
|
|
4550
4859
|
IDENTIFIER_LIMITS,
|
|
4860
|
+
INCLUDE_INDEX_KINDS,
|
|
4551
4861
|
MYSQL_CAPABILITIES,
|
|
4552
4862
|
MYSQL_FUNCTIONAL_KEY_LIMITS,
|
|
4553
4863
|
MYSQL_ROW_RULE_MESSAGE_MAX_BYTES,
|
|
@@ -4565,6 +4875,8 @@ export {
|
|
|
4565
4875
|
SQLITE_ROW_RULE_ERROR_PREFIX,
|
|
4566
4876
|
SQL_NAMESPACES,
|
|
4567
4877
|
ScopedQueryError,
|
|
4878
|
+
TABLE_STORAGE_KEYS,
|
|
4879
|
+
TABLE_STORAGE_PARAMETERS,
|
|
4568
4880
|
VIBE_ERROR_CODES,
|
|
4569
4881
|
VibeError,
|
|
4570
4882
|
assertExtensionModelPlacement,
|
|
@@ -4573,6 +4885,7 @@ export {
|
|
|
4573
4885
|
assertGeneratedColumns,
|
|
4574
4886
|
assertIdentifierFits,
|
|
4575
4887
|
assertIndexExpressions,
|
|
4888
|
+
assertIndexIncludeColumns,
|
|
4576
4889
|
assertIndexOperatorClasses,
|
|
4577
4890
|
assertJsonSchemaRef,
|
|
4578
4891
|
assertMigrationObjects,
|
|
@@ -4582,6 +4895,7 @@ export {
|
|
|
4582
4895
|
assertRowRuleEquality,
|
|
4583
4896
|
assertRowRuleReferentialActions,
|
|
4584
4897
|
assertSqlNamespace,
|
|
4898
|
+
assertTableStorage,
|
|
4585
4899
|
assertValidSchemaIR,
|
|
4586
4900
|
assertValidatorRef,
|
|
4587
4901
|
buildComputedManifest,
|
|
@@ -4607,7 +4921,10 @@ export {
|
|
|
4607
4921
|
fitDefaultName,
|
|
4608
4922
|
generatedColumnFromSql,
|
|
4609
4923
|
generatedColumnShapeIssue,
|
|
4924
|
+
generatedTypeNames,
|
|
4925
|
+
hasIndexIncludeColumns,
|
|
4610
4926
|
hasJsonSchemaAnnotation,
|
|
4927
|
+
hasTableStorage,
|
|
4611
4928
|
hasValidatorAnnotation,
|
|
4612
4929
|
identifierLength,
|
|
4613
4930
|
implicitJoinTable,
|
|
@@ -4632,6 +4949,7 @@ export {
|
|
|
4632
4949
|
isReservedDelegateName,
|
|
4633
4950
|
isSqlObjectDefinition,
|
|
4634
4951
|
isSqlObjectIdentity,
|
|
4952
|
+
isToastStorageKey,
|
|
4635
4953
|
jsonSchemaRefIssue,
|
|
4636
4954
|
jsonTypeAnnotationIssue,
|
|
4637
4955
|
jsonTypeAnnotationRef,
|
|
@@ -4643,6 +4961,7 @@ export {
|
|
|
4643
4961
|
normalizeJsonSchemaRef,
|
|
4644
4962
|
normalizeRowRules,
|
|
4645
4963
|
normalizeValidatorRef,
|
|
4964
|
+
parseTableStorageValue,
|
|
4646
4965
|
postgresGeneratedObjectName,
|
|
4647
4966
|
predicateCapabilityIssue,
|
|
4648
4967
|
predicateFieldNames,
|
|
@@ -4650,6 +4969,7 @@ export {
|
|
|
4650
4969
|
prepareDatabaseModuleSchema,
|
|
4651
4970
|
providerToDialect,
|
|
4652
4971
|
qualifiedSqlName,
|
|
4972
|
+
renderTableStorageValue,
|
|
4653
4973
|
resolveOnDelete,
|
|
4654
4974
|
resolveOnUpdate,
|
|
4655
4975
|
resolveReferentialActions,
|
|
@@ -4670,6 +4990,9 @@ export {
|
|
|
4670
4990
|
sqlObjectKey,
|
|
4671
4991
|
sqlObjectNamespace,
|
|
4672
4992
|
sqliteRowRuleConstraint,
|
|
4993
|
+
tableStorageEntries,
|
|
4994
|
+
tableStorageKeyFromPrisma,
|
|
4995
|
+
tableStoragePrismaKey,
|
|
4673
4996
|
timeOfDayType,
|
|
4674
4997
|
unsupportedCapability,
|
|
4675
4998
|
validateComputedConfig,
|
|
@@ -4681,4 +5004,4 @@ export {
|
|
|
4681
5004
|
validatorRefIssue
|
|
4682
5005
|
};
|
|
4683
5006
|
|
|
4684
|
-
//# debugId=
|
|
5007
|
+
//# debugId=61CF54A7622E428F64756E2164756E21
|