@vibeorm/schema 5.7.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/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
- rowCapture: true
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
- rowCapture: false
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
- rowCapture: false
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,9 +3041,18 @@ 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",
3049
+ "__VibeObjects",
3050
+ "__VibeKeys",
3051
+ "__VibeAt",
3052
+ "__VibeItem",
3053
+ "__VibeExact",
3054
+ "__VibePreviousInput",
3055
+ "__VibePrevious",
2863
3056
  "extensionManifest",
2864
3057
  "extensionMounts",
2865
3058
  "computedManifest",
@@ -2879,6 +3072,7 @@ var RESERVED_ENUM_NAMES = [
2879
3072
  "Date",
2880
3073
  "Uint8Array",
2881
3074
  "schema",
3075
+ "jsonSchemas",
2882
3076
  "VibeClient",
2883
3077
  "VibeClientInstance",
2884
3078
  "VibeQueryPromise",
@@ -2899,6 +3093,12 @@ var RESERVED_ENUM_NAMES = [
2899
3093
  "RowLockRequest",
2900
3094
  "GroupByTruncateUnit",
2901
3095
  "GroupByKeyName",
3096
+ "GroupByPath",
3097
+ "GroupByExpressionValues",
3098
+ "GroupByKeyOrderInput",
3099
+ "GroupByOrderKeys",
3100
+ "GroupByKeyOrderCheck",
3101
+ "GroupingSetRow",
2902
3102
  "JsonValue",
2903
3103
  "InputJsonValue",
2904
3104
  "InputJsonArray",
@@ -2924,9 +3124,20 @@ var RESERVED_ENUM_NAMES = [
2924
3124
  "createClient",
2925
3125
  "DatabaseAdapter",
2926
3126
  "DbNow",
3127
+ "BigIntFieldRef",
3128
+ "BooleanFieldRef",
3129
+ "DateTimeFieldRef",
3130
+ "DecimalFieldRef",
3131
+ "EnumFieldRef",
3132
+ "FloatFieldRef",
3133
+ "IntFieldRef",
3134
+ "NumericFieldRef",
3135
+ "StringFieldRef",
2927
3136
  "JoinedField",
2928
3137
  "TransactionLocalSettings",
2929
3138
  "VibeUpdateManySources",
3139
+ "VibeModelRows",
3140
+ "VibeHandleTypes",
2930
3141
  "ClientContext",
2931
3142
  "QueryOperation",
2932
3143
  "QueryEvent",
@@ -3010,6 +3221,12 @@ var GENERATED_TYPE_NAMES = {
3010
3221
  "HavingInput",
3011
3222
  "GroupByOrderByInput",
3012
3223
  "GroupByTruncatedKey",
3224
+ "GroupByExpressionKey",
3225
+ "FilteredAggregateInput",
3226
+ "FilteredAggregateHavingInput",
3227
+ "FilteredAggregateOrderByInput",
3228
+ "FilteredResult",
3229
+ "CoalesceOrderInput",
3013
3230
  "FindManyArgs",
3014
3231
  "FindPageArgs",
3015
3232
  "FindFirstArgs",
@@ -3059,6 +3276,7 @@ var GENERATED_TYPE_NAMES = {
3059
3276
  "ViewDelegate",
3060
3277
  "ReadOnlyDelegate"
3061
3278
  ],
3279
+ generatedColumnSuffixes: ["WritableScalarFieldEnum", "GeneratedWriteGuard", "GeneratedBulkWriteRow"],
3062
3280
  nestedPrefixes: [
3063
3281
  "Create",
3064
3282
  "UncheckedCreate",
@@ -3134,33 +3352,118 @@ var INVALID_BINDING_NAMES = new Set([
3134
3352
  "object",
3135
3353
  "undefined"
3136
3354
  ]);
3137
- function validateGeneratedNames(params) {
3138
- const { schema, issues } = params;
3139
- const owners = new Map(RESERVED_ENUM_NAMES.map((name) => [name, "generated client"]));
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" });
3140
3385
  if (schema.rls !== undefined) {
3141
- owners.set("RlsContext", "native RLS client");
3142
- owners.set("BoundVibeClientInstance", "native RLS client");
3143
- owners.set("BoundVibeTransactionClientInstance", "native RLS client");
3144
- owners.set("OperatorVibeClientInstance", "native RLS client");
3145
- owners.set("OperatorVibeTransactionClientInstance", "native RLS client");
3386
+ fixed({ names: ["RlsContext", "BoundVibeClientInstance", "BoundVibeTransactionClientInstance", "OperatorVibeClientInstance", "OperatorVibeTransactionClientInstance"], owner: "native RLS client" });
3146
3387
  }
3147
3388
  if (schema.models.some((model) => model.policy !== undefined))
3148
- owners.set("PolicyClientInstance", "policy client");
3389
+ fixed({ names: ["PolicyClientInstance"], owner: "policy client" });
3149
3390
  if (schema.models.some((model) => model.fields.some((field) => isLocalDateField({ field })))) {
3150
- for (const name of ["LocalDate", "LocalDateFilter", "LocalDateNullableFilter"])
3151
- owners.set(name, "local-date filters");
3391
+ fixed({ names: ["LocalDate", "LocalDateFilter", "LocalDateNullableFilter"], owner: "local-date filters" });
3392
+ }
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);
3403
+ }
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
+ }
3152
3409
  }
3153
- const register = (params) => {
3154
- if (!/^[$_\p{ID_Start}][$_\u200c\u200d\p{ID_Continue}]*$/u.test(params.name) || INVALID_BINDING_NAMES.has(params.name)) {
3155
- issues.push({ rule: "invalid-generated-identifier", message: `Generated name "${params.name}" from ${params.owner} is not a legal TypeScript identifier` });
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 });
3156
3413
  }
3157
- const previous = owners.get(params.name);
3158
- if (previous !== undefined && previous !== params.owner) {
3159
- issues.push({ rule: "generated-name-collision", message: `Generated name "${params.name}" from ${params.owner} conflicts with ${previous}` });
3160
- } else {
3161
- owners.set(params.name, params.owner);
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;
3162
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}`
3163
3463
  };
3464
+ }
3465
+ function validateGeneratedNames(params) {
3466
+ const { schema, issues } = params;
3164
3467
  const aliases = new Map;
3165
3468
  for (const model of schema.models) {
3166
3469
  const clientName = model.name.charAt(0).toLowerCase() + model.name.slice(1);
@@ -3174,19 +3477,8 @@ function validateGeneratedNames(params) {
3174
3477
  if (RESERVED_CLIENT_NAMES.includes(clientName)) {
3175
3478
  issues.push({ rule: "reserved-client-name", message: `Model "${model.name}" conflicts with client member "${clientName}"`, model: model.name });
3176
3479
  }
3177
- const owner = `model "${model.name}"`;
3178
- for (const suffix of GENERATED_TYPE_NAMES.modelSuffixes)
3179
- register({ name: `${model.name}${suffix}`, owner });
3180
- const withouts = ["", ...model.relations.map((relation) => `Without${relation.name.charAt(0).toUpperCase()}${relation.name.slice(1)}`)];
3181
- for (const without of withouts) {
3182
- for (const prefix of GENERATED_TYPE_NAMES.nestedPrefixes)
3183
- register({ name: `${model.name}${prefix}${without}Input`, owner });
3184
- }
3185
- }
3186
- for (const declared of schema.enums) {
3187
- for (const suffix of GENERATED_TYPE_NAMES.enumSuffixes)
3188
- register({ name: `${declared.name}${suffix}`, owner: `enum "${declared.name}"` });
3189
3480
  }
3481
+ issues.push(...resolveGeneratedNames({ schema }).issues);
3190
3482
  }
3191
3483
  function foreignKeyKeys(params) {
3192
3484
  const distinct = new Set;
@@ -3489,7 +3781,7 @@ function validatePhysicalNameUniqueness(params) {
3489
3781
  for (const { index, site } of declarations) {
3490
3782
  const unique = index.kind === "unique";
3491
3783
  const columns = index.fields.map((entry) => [columnOf(entry.name), entry.sort === "desc", entry.operatorClass === undefined ? null : [entry.operatorClass.namespace, entry.operatorClass.name]]);
3492
- 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) }]]);
3493
3785
  if (seenIndexKeys.has(key))
3494
3786
  continue;
3495
3787
  seenIndexKeys.add(key);
@@ -3927,6 +4219,27 @@ function validateModel(params) {
3927
4219
  }
3928
4220
  }
3929
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
+ }
3930
4243
  }
3931
4244
  for (const field of model.fields) {
3932
4245
  if (field.collation !== undefined && (field.type !== "String" || isLocalDateField({ field }))) {
@@ -3937,6 +4250,14 @@ function validateModel(params) {
3937
4250
  field: field.name
3938
4251
  });
3939
4252
  }
4253
+ if (field.bigIntMode !== undefined && (field.type !== "BigInt" || field.bigIntMode !== "number")) {
4254
+ issues.push({
4255
+ rule: "bigint-mode",
4256
+ message: `@number on "${model.name}.${field.name}" \u2014 a number read mode is only valid on BigInt fields, and its one value is "number"`,
4257
+ model: model.name,
4258
+ field: field.name
4259
+ });
4260
+ }
3940
4261
  }
3941
4262
  if (model.policy !== undefined) {
3942
4263
  const policyField = model.fields.find((field) => field.name === model.policy?.field);
@@ -4226,6 +4547,8 @@ function assertValidSchemaIR(params) {
4226
4547
  }
4227
4548
  assertExtensionPlacement({ schema: params.schema, dialect });
4228
4549
  assertIndexOperatorClasses({ schema: params.schema, dialect });
4550
+ assertIndexIncludeColumns({ schema: params.schema, dialect });
4551
+ assertTableStorage({ schema: params.schema, dialect });
4229
4552
  for (const entry of [...params.schema.models, ...params.schema.enums])
4230
4553
  if (entry.namespace !== undefined)
4231
4554
  assertSqlNamespace({ namespace: entry.namespace, dialect });
@@ -4534,6 +4857,7 @@ export {
4534
4857
  EMPTY_EXTENSION_REGISTRY,
4535
4858
  ENUM_STORAGES,
4536
4859
  IDENTIFIER_LIMITS,
4860
+ INCLUDE_INDEX_KINDS,
4537
4861
  MYSQL_CAPABILITIES,
4538
4862
  MYSQL_FUNCTIONAL_KEY_LIMITS,
4539
4863
  MYSQL_ROW_RULE_MESSAGE_MAX_BYTES,
@@ -4551,6 +4875,8 @@ export {
4551
4875
  SQLITE_ROW_RULE_ERROR_PREFIX,
4552
4876
  SQL_NAMESPACES,
4553
4877
  ScopedQueryError,
4878
+ TABLE_STORAGE_KEYS,
4879
+ TABLE_STORAGE_PARAMETERS,
4554
4880
  VIBE_ERROR_CODES,
4555
4881
  VibeError,
4556
4882
  assertExtensionModelPlacement,
@@ -4559,6 +4885,7 @@ export {
4559
4885
  assertGeneratedColumns,
4560
4886
  assertIdentifierFits,
4561
4887
  assertIndexExpressions,
4888
+ assertIndexIncludeColumns,
4562
4889
  assertIndexOperatorClasses,
4563
4890
  assertJsonSchemaRef,
4564
4891
  assertMigrationObjects,
@@ -4568,6 +4895,7 @@ export {
4568
4895
  assertRowRuleEquality,
4569
4896
  assertRowRuleReferentialActions,
4570
4897
  assertSqlNamespace,
4898
+ assertTableStorage,
4571
4899
  assertValidSchemaIR,
4572
4900
  assertValidatorRef,
4573
4901
  buildComputedManifest,
@@ -4593,7 +4921,10 @@ export {
4593
4921
  fitDefaultName,
4594
4922
  generatedColumnFromSql,
4595
4923
  generatedColumnShapeIssue,
4924
+ generatedTypeNames,
4925
+ hasIndexIncludeColumns,
4596
4926
  hasJsonSchemaAnnotation,
4927
+ hasTableStorage,
4597
4928
  hasValidatorAnnotation,
4598
4929
  identifierLength,
4599
4930
  implicitJoinTable,
@@ -4618,6 +4949,7 @@ export {
4618
4949
  isReservedDelegateName,
4619
4950
  isSqlObjectDefinition,
4620
4951
  isSqlObjectIdentity,
4952
+ isToastStorageKey,
4621
4953
  jsonSchemaRefIssue,
4622
4954
  jsonTypeAnnotationIssue,
4623
4955
  jsonTypeAnnotationRef,
@@ -4629,6 +4961,7 @@ export {
4629
4961
  normalizeJsonSchemaRef,
4630
4962
  normalizeRowRules,
4631
4963
  normalizeValidatorRef,
4964
+ parseTableStorageValue,
4632
4965
  postgresGeneratedObjectName,
4633
4966
  predicateCapabilityIssue,
4634
4967
  predicateFieldNames,
@@ -4636,6 +4969,7 @@ export {
4636
4969
  prepareDatabaseModuleSchema,
4637
4970
  providerToDialect,
4638
4971
  qualifiedSqlName,
4972
+ renderTableStorageValue,
4639
4973
  resolveOnDelete,
4640
4974
  resolveOnUpdate,
4641
4975
  resolveReferentialActions,
@@ -4656,6 +4990,9 @@ export {
4656
4990
  sqlObjectKey,
4657
4991
  sqlObjectNamespace,
4658
4992
  sqliteRowRuleConstraint,
4993
+ tableStorageEntries,
4994
+ tableStorageKeyFromPrisma,
4995
+ tableStoragePrismaKey,
4659
4996
  timeOfDayType,
4660
4997
  unsupportedCapability,
4661
4998
  validateComputedConfig,
@@ -4667,4 +5004,4 @@ export {
4667
5004
  validatorRefIssue
4668
5005
  };
4669
5006
 
4670
- //# debugId=8784FDF6327C16F164756E2164756E21
5007
+ //# debugId=61CF54A7622E428F64756E2164756E21