metal-orm 1.1.27 → 1.1.29

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.d.cts CHANGED
@@ -6232,6 +6232,7 @@ interface ColumnDiff {
6232
6232
  nullabilityChanged?: boolean;
6233
6233
  defaultChanged?: boolean;
6234
6234
  autoIncrementChanged?: boolean;
6235
+ referenceChanged?: boolean;
6235
6236
  }
6236
6237
  /** Represents a column in the database schema. */
6237
6238
  interface DatabaseColumn {
package/dist/index.d.ts CHANGED
@@ -6232,6 +6232,7 @@ interface ColumnDiff {
6232
6232
  nullabilityChanged?: boolean;
6233
6233
  defaultChanged?: boolean;
6234
6234
  autoIncrementChanged?: boolean;
6235
+ referenceChanged?: boolean;
6235
6236
  }
6236
6237
  /** Represents a column in the database schema. */
6237
6238
  interface DatabaseColumn {
package/dist/index.js CHANGED
@@ -11155,7 +11155,10 @@ var renderColumnDefinition = (table, col2, dialect, options = {}) => {
11155
11155
  parts.push(`CHECK (${col2.check})`);
11156
11156
  }
11157
11157
  if (col2.references) {
11158
- parts.push(dialect.renderReference(col2.references, table));
11158
+ const referenceSql = dialect.renderReference(col2.references, table);
11159
+ parts.push(
11160
+ col2.references.name ? `CONSTRAINT ${dialect.quoteIdentifier(col2.references.name)} ${referenceSql}` : referenceSql
11161
+ );
11159
11162
  }
11160
11163
  return { sql: parts.join(" "), inlinePrimary: !!(options.includePrimary && col2.primary) };
11161
11164
  };
@@ -11276,6 +11279,11 @@ var normalizeDefault = (value) => {
11276
11279
  if (value === void 0 || value === null) return void 0;
11277
11280
  return String(value).trim();
11278
11281
  };
11282
+ var normalizeReferenceAction = (value) => (value || "NO ACTION").toUpperCase().replace(/\s+/g, " ").trim();
11283
+ var sameReference = (expected, actual) => {
11284
+ if (!expected || !actual) return expected === actual;
11285
+ return expected.table === actual.table && expected.column === actual.column && expected.name === actual.name && normalizeReferenceAction(expected.onDelete) === normalizeReferenceAction(actual.onDelete) && normalizeReferenceAction(expected.onUpdate) === normalizeReferenceAction(actual.onUpdate) && !!expected.deferrable === !!actual.deferrable;
11286
+ };
11279
11287
  var diffColumn = (expected, actual, dialect) => {
11280
11288
  const expectedType = normalizeType(dialect.renderColumnType(expected));
11281
11289
  const actualType = normalizeType(actual.type);
@@ -11285,7 +11293,8 @@ var diffColumn = (expected, actual, dialect) => {
11285
11293
  typeChanged: expectedType !== actualType,
11286
11294
  nullabilityChanged: !!expected.notNull !== !!actual.notNull,
11287
11295
  defaultChanged: expectedDefault !== actualDefault,
11288
- autoIncrementChanged: !!expected.autoIncrement !== !!actual.autoIncrement
11296
+ autoIncrementChanged: !!expected.autoIncrement !== !!actual.autoIncrement,
11297
+ referenceChanged: !sameReference(expected.references, actual.references)
11289
11298
  };
11290
11299
  };
11291
11300
  var unsupportedMutationWarning = (dialect, operation, target) => `Dialect "${dialect.name}" does not provide the ${operation} capability for ${target}; manual migration is required.`;
@@ -11322,6 +11331,11 @@ var diffSchema = (expectedTables, actualSchema, dialect, options = {}) => {
11322
11331
  const expectedColumn = table.columns[columnName];
11323
11332
  const actualColumn = actualColumns.get(columnName);
11324
11333
  const columnDiff = diffColumn(expectedColumn, actualColumn, dialect);
11334
+ if (columnDiff.referenceChanged) {
11335
+ plan.warnings.push(
11336
+ `Foreign key definition on ${key}.${columnName} differs from the expected schema; manual constraint migration is required.`
11337
+ );
11338
+ }
11325
11339
  const shouldAlter = columnDiff.typeChanged || columnDiff.nullabilityChanged || columnDiff.defaultChanged || columnDiff.autoIncrementChanged;
11326
11340
  if (shouldAlter) {
11327
11341
  const capability = dialect.mutations.alterColumn;
@@ -12403,6 +12417,288 @@ var mysqlIntrospector = {
12403
12417
  }
12404
12418
  };
12405
12419
 
12420
+ // src/core/ddl/introspect/sqlite-foreign-key-ddl.ts
12421
+ var isIdentifierChar = (value) => /[A-Za-z0-9_]/.test(value);
12422
+ var keywordAt = (text, position2, keyword) => {
12423
+ if (position2 < 0 || position2 + keyword.length > text.length) return false;
12424
+ if (position2 > 0 && isIdentifierChar(text[position2 - 1])) return false;
12425
+ if (position2 + keyword.length < text.length && isIdentifierChar(text[position2 + keyword.length])) {
12426
+ return false;
12427
+ }
12428
+ return text.slice(position2, position2 + keyword.length).toUpperCase() === keyword.toUpperCase();
12429
+ };
12430
+ var skipWhitespace = (text, position2) => {
12431
+ let pos = position2;
12432
+ while (pos < text.length && /\s/.test(text[pos])) pos += 1;
12433
+ return pos;
12434
+ };
12435
+ var readIdentifier = (text, position2) => {
12436
+ let pos = skipWhitespace(text, position2);
12437
+ if (pos >= text.length) return void 0;
12438
+ const quote = text[pos];
12439
+ if (quote === '"' || quote === "`" || quote === "[") {
12440
+ const close = quote === "[" ? "]" : quote;
12441
+ pos += 1;
12442
+ let value = "";
12443
+ while (pos < text.length) {
12444
+ const current = text[pos++];
12445
+ if (current === close) {
12446
+ if (pos < text.length && text[pos] === close) {
12447
+ value += close;
12448
+ pos += 1;
12449
+ continue;
12450
+ }
12451
+ return { value, next: pos };
12452
+ }
12453
+ value += current;
12454
+ }
12455
+ return void 0;
12456
+ }
12457
+ const start = pos;
12458
+ while (pos < text.length && !/\s/.test(text[pos]) && text[pos] !== "(" && text[pos] !== ")" && text[pos] !== ",") {
12459
+ pos += 1;
12460
+ }
12461
+ if (pos === start) return void 0;
12462
+ return { value: text.slice(start, pos), next: pos };
12463
+ };
12464
+ var splitTableBody = (createSql) => {
12465
+ const open = createSql.indexOf("(");
12466
+ if (open < 0) return [];
12467
+ let depth = 1;
12468
+ let quote = "";
12469
+ let bracket = false;
12470
+ let lineComment = false;
12471
+ let blockComment = false;
12472
+ let close = -1;
12473
+ for (let i = open + 1; i < createSql.length; i += 1) {
12474
+ const current = createSql[i];
12475
+ const next = createSql[i + 1] ?? "";
12476
+ if (lineComment) {
12477
+ if (current === "\n" || current === "\r") lineComment = false;
12478
+ continue;
12479
+ }
12480
+ if (blockComment) {
12481
+ if (current === "*" && next === "/") {
12482
+ blockComment = false;
12483
+ i += 1;
12484
+ }
12485
+ continue;
12486
+ }
12487
+ if (quote) {
12488
+ if (current === quote) {
12489
+ if (next === quote) i += 1;
12490
+ else quote = "";
12491
+ }
12492
+ continue;
12493
+ }
12494
+ if (bracket) {
12495
+ if (current === "]") {
12496
+ if (next === "]") i += 1;
12497
+ else bracket = false;
12498
+ }
12499
+ continue;
12500
+ }
12501
+ if (current === "-" && next === "-") {
12502
+ lineComment = true;
12503
+ i += 1;
12504
+ continue;
12505
+ }
12506
+ if (current === "/" && next === "*") {
12507
+ blockComment = true;
12508
+ i += 1;
12509
+ continue;
12510
+ }
12511
+ if (current === "'" || current === '"' || current === "`") {
12512
+ quote = current;
12513
+ continue;
12514
+ }
12515
+ if (current === "[") {
12516
+ bracket = true;
12517
+ continue;
12518
+ }
12519
+ if (current === "(") depth += 1;
12520
+ else if (current === ")") {
12521
+ depth -= 1;
12522
+ if (depth === 0) {
12523
+ close = i;
12524
+ break;
12525
+ }
12526
+ }
12527
+ }
12528
+ if (close < 0) return [];
12529
+ const body = createSql.slice(open + 1, close);
12530
+ const segments = [];
12531
+ let start = 0;
12532
+ depth = 0;
12533
+ quote = "";
12534
+ bracket = false;
12535
+ lineComment = false;
12536
+ blockComment = false;
12537
+ for (let i = 0; i < body.length; i += 1) {
12538
+ const current = body[i];
12539
+ const next = body[i + 1] ?? "";
12540
+ if (lineComment) {
12541
+ if (current === "\n" || current === "\r") lineComment = false;
12542
+ continue;
12543
+ }
12544
+ if (blockComment) {
12545
+ if (current === "*" && next === "/") {
12546
+ blockComment = false;
12547
+ i += 1;
12548
+ }
12549
+ continue;
12550
+ }
12551
+ if (quote) {
12552
+ if (current === quote) {
12553
+ if (next === quote) i += 1;
12554
+ else quote = "";
12555
+ }
12556
+ continue;
12557
+ }
12558
+ if (bracket) {
12559
+ if (current === "]") {
12560
+ if (next === "]") i += 1;
12561
+ else bracket = false;
12562
+ }
12563
+ continue;
12564
+ }
12565
+ if (current === "-" && next === "-") {
12566
+ lineComment = true;
12567
+ i += 1;
12568
+ continue;
12569
+ }
12570
+ if (current === "/" && next === "*") {
12571
+ blockComment = true;
12572
+ i += 1;
12573
+ continue;
12574
+ }
12575
+ if (current === "'" || current === '"' || current === "`") {
12576
+ quote = current;
12577
+ continue;
12578
+ }
12579
+ if (current === "[") {
12580
+ bracket = true;
12581
+ continue;
12582
+ }
12583
+ if (current === "(") depth += 1;
12584
+ else if (current === ")" && depth > 0) depth -= 1;
12585
+ else if (current === "," && depth === 0) {
12586
+ segments.push(body.slice(start, i).trim());
12587
+ start = i + 1;
12588
+ }
12589
+ }
12590
+ segments.push(body.slice(start).trim());
12591
+ return segments.filter(Boolean);
12592
+ };
12593
+ var findTopLevelKeyword = (text, keyword, start = 0) => {
12594
+ let depth = 0;
12595
+ let quote = "";
12596
+ let bracket = false;
12597
+ for (let i = start; i < text.length; i += 1) {
12598
+ const current = text[i];
12599
+ const next = text[i + 1] ?? "";
12600
+ if (quote) {
12601
+ if (current === quote) {
12602
+ if (next === quote) i += 1;
12603
+ else quote = "";
12604
+ }
12605
+ continue;
12606
+ }
12607
+ if (bracket) {
12608
+ if (current === "]") {
12609
+ if (next === "]") i += 1;
12610
+ else bracket = false;
12611
+ }
12612
+ continue;
12613
+ }
12614
+ if (current === "'" || current === '"' || current === "`") {
12615
+ quote = current;
12616
+ continue;
12617
+ }
12618
+ if (current === "[") {
12619
+ bracket = true;
12620
+ continue;
12621
+ }
12622
+ if (current === "(") {
12623
+ depth += 1;
12624
+ continue;
12625
+ }
12626
+ if (current === ")") {
12627
+ if (depth > 0) depth -= 1;
12628
+ continue;
12629
+ }
12630
+ if (depth === 0 && keywordAt(text, i, keyword)) return i;
12631
+ }
12632
+ return -1;
12633
+ };
12634
+ var isInitiallyDeferred = (segment, start) => {
12635
+ const deferrablePos = findTopLevelKeyword(segment, "DEFERRABLE", start);
12636
+ if (deferrablePos < 0) return false;
12637
+ const before = segment.slice(start, deferrablePos).trimEnd();
12638
+ if (/\bNOT$/i.test(before)) return false;
12639
+ return /^DEFERRABLE\s+INITIALLY\s+DEFERRED\b/i.test(segment.slice(deferrablePos));
12640
+ };
12641
+ var parseTableForeignKey = (segment) => {
12642
+ let pos = skipWhitespace(segment, 0);
12643
+ let name;
12644
+ if (keywordAt(segment, pos, "CONSTRAINT")) {
12645
+ pos += "CONSTRAINT".length;
12646
+ const parsedName = readIdentifier(segment, pos);
12647
+ if (!parsedName) return void 0;
12648
+ name = parsedName.value;
12649
+ pos = skipWhitespace(segment, parsedName.next);
12650
+ }
12651
+ if (!keywordAt(segment, pos, "FOREIGN")) return void 0;
12652
+ pos += "FOREIGN".length;
12653
+ pos = skipWhitespace(segment, pos);
12654
+ if (!keywordAt(segment, pos, "KEY")) return void 0;
12655
+ pos += "KEY".length;
12656
+ pos = skipWhitespace(segment, pos);
12657
+ if (segment[pos] !== "(") return void 0;
12658
+ pos += 1;
12659
+ const source = readIdentifier(segment, pos);
12660
+ if (!source) return void 0;
12661
+ pos = skipWhitespace(segment, source.next);
12662
+ if (segment[pos] === ",") return void 0;
12663
+ const referencesPos = findTopLevelKeyword(segment, "REFERENCES", pos);
12664
+ if (referencesPos < 0) return void 0;
12665
+ return {
12666
+ column: source.value,
12667
+ ...name ? { name } : {},
12668
+ deferrable: isInitiallyDeferred(segment, referencesPos)
12669
+ };
12670
+ };
12671
+ var parseInlineForeignKey = (segment) => {
12672
+ const source = readIdentifier(segment, 0);
12673
+ if (!source) return void 0;
12674
+ const referencesPos = findTopLevelKeyword(segment, "REFERENCES", source.next);
12675
+ if (referencesPos < 0) return void 0;
12676
+ let name;
12677
+ const constraintPos = findTopLevelKeyword(segment, "CONSTRAINT", source.next);
12678
+ if (constraintPos >= 0 && constraintPos < referencesPos) {
12679
+ const parsedName = readIdentifier(segment, constraintPos + "CONSTRAINT".length);
12680
+ if (parsedName) name = parsedName.value;
12681
+ }
12682
+ return {
12683
+ column: source.value,
12684
+ ...name ? { name } : {},
12685
+ deferrable: isInitiallyDeferred(segment, referencesPos)
12686
+ };
12687
+ };
12688
+ var parseSqliteForeignKeyModifiers = (createSql) => {
12689
+ const result = [];
12690
+ for (const segment of splitTableBody(createSql)) {
12691
+ const tableConstraint = parseTableForeignKey(segment);
12692
+ if (tableConstraint) {
12693
+ result.push(tableConstraint);
12694
+ continue;
12695
+ }
12696
+ const inlineConstraint = parseInlineForeignKey(segment);
12697
+ if (inlineConstraint) result.push(inlineConstraint);
12698
+ }
12699
+ return result;
12700
+ };
12701
+
12406
12702
  // src/core/ddl/introspect/sqlite.ts
12407
12703
  var toReferentialAction = (value) => {
12408
12704
  if (!value) return void 0;
@@ -12420,7 +12716,7 @@ var columnNode2 = (table, name, alias) => ({
12420
12716
  });
12421
12717
  var buildPragmaQuery = (name, table, alias, columnAliases) => ({
12422
12718
  type: "SelectQuery",
12423
- from: fnTable(name, [valueToOperand(table)], alias, { columnAliases }),
12719
+ from: fnTable(name, [valueToOperand(table)], alias),
12424
12720
  columns: columnAliases.map((column) => columnNode2(alias, column)),
12425
12721
  joins: []
12426
12722
  });
@@ -12481,7 +12777,10 @@ var sqliteIntrospector = {
12481
12777
  const tablesQuery = {
12482
12778
  type: "SelectQuery",
12483
12779
  from: { type: "Table", name: "sqlite_master" },
12484
- columns: [columnNode2(alias, "name")],
12780
+ columns: [
12781
+ columnNode2(alias, "name"),
12782
+ columnNode2(alias, "sql")
12783
+ ],
12485
12784
  joins: [],
12486
12785
  where: and(
12487
12786
  eq(columnNode2(alias, "type"), "table"),
@@ -12551,6 +12850,14 @@ var sqliteIntrospector = {
12551
12850
  };
12552
12851
  }
12553
12852
  });
12853
+ if (row.sql) {
12854
+ for (const modifier of parseSqliteForeignKeyModifiers(row.sql)) {
12855
+ const reference = tableEntry.columns.find((column) => column.name === modifier.column)?.references;
12856
+ if (!reference) continue;
12857
+ if (modifier.name) reference.name = modifier.name;
12858
+ reference.deferrable = modifier.deferrable;
12859
+ }
12860
+ }
12554
12861
  for (const idx of indexList) {
12555
12862
  if (!idx.name) continue;
12556
12863
  const indexColumns = await runPragma(
@@ -13774,6 +14081,7 @@ var createSqliteSchemaDialect = () => composeSchemaDialect({
13774
14081
  void table;
13775
14082
  return !!(column.autoIncrement && primaryKey.length === 1 && primaryKey[0] === column.name);
13776
14083
  },
14084
+ renderReferenceSuffix: (ref) => ref.deferrable ? "DEFERRABLE INITIALLY DEFERRED" : void 0,
13777
14085
  renderIndex(table, index, services) {
13778
14086
  const name = index.name || deriveIndexName(table, index);
13779
14087
  const columns = renderIndexColumns(services, index.columns);