@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/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
- rowCapture: true
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
- rowCapture: false
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
- rowCapture: false
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
- function validateGeneratedNames(params) {
3144
- const { schema, issues } = params;
3145
- const owners = new Map(RESERVED_ENUM_NAMES.map((name) => [name, "generated client"]));
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
- owners.set("RlsContext", "native RLS client");
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
- owners.set("PolicyClientInstance", "policy client");
3635
+ fixed({ names: ["PolicyClientInstance"], owner: "policy client" });
3155
3636
  if (schema.models.some((model) => model.fields.some((field) => isLocalDateField({ field })))) {
3156
- for (const name of ["LocalDate", "LocalDateFilter", "LocalDateNullableFilter"])
3157
- owners.set(name, "local-date filters");
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 register = (params) => {
3160
- if (!/^[$_\p{ID_Start}][$_\u200c\u200d\p{ID_Continue}]*$/u.test(params.name) || INVALID_BINDING_NAMES.has(params.name)) {
3161
- issues.push({ rule: "invalid-generated-identifier", message: `Generated name "${params.name}" from ${params.owner} is not a legal TypeScript identifier` });
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
- const previous = owners.get(params.name);
3164
- if (previous !== undefined && previous !== params.owner) {
3165
- issues.push({ rule: "generated-name-collision", message: `Generated name "${params.name}" from ${params.owner} conflicts with ${previous}` });
3166
- } else {
3167
- owners.set(params.name, params.owner);
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=16597011ACA85C7264756E2164756E21
5516
+ //# debugId=D9E0341E199A9F8664756E2164756E21