metal-orm 1.1.28 → 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.cjs CHANGED
@@ -11642,7 +11642,10 @@ var renderColumnDefinition = (table, col2, dialect, options = {}) => {
11642
11642
  parts.push(`CHECK (${col2.check})`);
11643
11643
  }
11644
11644
  if (col2.references) {
11645
- parts.push(dialect.renderReference(col2.references, table));
11645
+ const referenceSql = dialect.renderReference(col2.references, table);
11646
+ parts.push(
11647
+ col2.references.name ? `CONSTRAINT ${dialect.quoteIdentifier(col2.references.name)} ${referenceSql}` : referenceSql
11648
+ );
11646
11649
  }
11647
11650
  return { sql: parts.join(" "), inlinePrimary: !!(options.includePrimary && col2.primary) };
11648
11651
  };
@@ -11763,6 +11766,11 @@ var normalizeDefault = (value) => {
11763
11766
  if (value === void 0 || value === null) return void 0;
11764
11767
  return String(value).trim();
11765
11768
  };
11769
+ var normalizeReferenceAction = (value) => (value || "NO ACTION").toUpperCase().replace(/\s+/g, " ").trim();
11770
+ var sameReference = (expected, actual) => {
11771
+ if (!expected || !actual) return expected === actual;
11772
+ 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;
11773
+ };
11766
11774
  var diffColumn = (expected, actual, dialect) => {
11767
11775
  const expectedType = normalizeType(dialect.renderColumnType(expected));
11768
11776
  const actualType = normalizeType(actual.type);
@@ -11772,7 +11780,8 @@ var diffColumn = (expected, actual, dialect) => {
11772
11780
  typeChanged: expectedType !== actualType,
11773
11781
  nullabilityChanged: !!expected.notNull !== !!actual.notNull,
11774
11782
  defaultChanged: expectedDefault !== actualDefault,
11775
- autoIncrementChanged: !!expected.autoIncrement !== !!actual.autoIncrement
11783
+ autoIncrementChanged: !!expected.autoIncrement !== !!actual.autoIncrement,
11784
+ referenceChanged: !sameReference(expected.references, actual.references)
11776
11785
  };
11777
11786
  };
11778
11787
  var unsupportedMutationWarning = (dialect, operation, target) => `Dialect "${dialect.name}" does not provide the ${operation} capability for ${target}; manual migration is required.`;
@@ -11809,6 +11818,11 @@ var diffSchema = (expectedTables, actualSchema, dialect, options = {}) => {
11809
11818
  const expectedColumn = table.columns[columnName];
11810
11819
  const actualColumn = actualColumns.get(columnName);
11811
11820
  const columnDiff = diffColumn(expectedColumn, actualColumn, dialect);
11821
+ if (columnDiff.referenceChanged) {
11822
+ plan.warnings.push(
11823
+ `Foreign key definition on ${key}.${columnName} differs from the expected schema; manual constraint migration is required.`
11824
+ );
11825
+ }
11812
11826
  const shouldAlter = columnDiff.typeChanged || columnDiff.nullabilityChanged || columnDiff.defaultChanged || columnDiff.autoIncrementChanged;
11813
11827
  if (shouldAlter) {
11814
11828
  const capability = dialect.mutations.alterColumn;
@@ -12890,6 +12904,288 @@ var mysqlIntrospector = {
12890
12904
  }
12891
12905
  };
12892
12906
 
12907
+ // src/core/ddl/introspect/sqlite-foreign-key-ddl.ts
12908
+ var isIdentifierChar = (value) => /[A-Za-z0-9_]/.test(value);
12909
+ var keywordAt = (text, position2, keyword) => {
12910
+ if (position2 < 0 || position2 + keyword.length > text.length) return false;
12911
+ if (position2 > 0 && isIdentifierChar(text[position2 - 1])) return false;
12912
+ if (position2 + keyword.length < text.length && isIdentifierChar(text[position2 + keyword.length])) {
12913
+ return false;
12914
+ }
12915
+ return text.slice(position2, position2 + keyword.length).toUpperCase() === keyword.toUpperCase();
12916
+ };
12917
+ var skipWhitespace = (text, position2) => {
12918
+ let pos = position2;
12919
+ while (pos < text.length && /\s/.test(text[pos])) pos += 1;
12920
+ return pos;
12921
+ };
12922
+ var readIdentifier = (text, position2) => {
12923
+ let pos = skipWhitespace(text, position2);
12924
+ if (pos >= text.length) return void 0;
12925
+ const quote = text[pos];
12926
+ if (quote === '"' || quote === "`" || quote === "[") {
12927
+ const close = quote === "[" ? "]" : quote;
12928
+ pos += 1;
12929
+ let value = "";
12930
+ while (pos < text.length) {
12931
+ const current = text[pos++];
12932
+ if (current === close) {
12933
+ if (pos < text.length && text[pos] === close) {
12934
+ value += close;
12935
+ pos += 1;
12936
+ continue;
12937
+ }
12938
+ return { value, next: pos };
12939
+ }
12940
+ value += current;
12941
+ }
12942
+ return void 0;
12943
+ }
12944
+ const start = pos;
12945
+ while (pos < text.length && !/\s/.test(text[pos]) && text[pos] !== "(" && text[pos] !== ")" && text[pos] !== ",") {
12946
+ pos += 1;
12947
+ }
12948
+ if (pos === start) return void 0;
12949
+ return { value: text.slice(start, pos), next: pos };
12950
+ };
12951
+ var splitTableBody = (createSql) => {
12952
+ const open = createSql.indexOf("(");
12953
+ if (open < 0) return [];
12954
+ let depth = 1;
12955
+ let quote = "";
12956
+ let bracket = false;
12957
+ let lineComment = false;
12958
+ let blockComment = false;
12959
+ let close = -1;
12960
+ for (let i = open + 1; i < createSql.length; i += 1) {
12961
+ const current = createSql[i];
12962
+ const next = createSql[i + 1] ?? "";
12963
+ if (lineComment) {
12964
+ if (current === "\n" || current === "\r") lineComment = false;
12965
+ continue;
12966
+ }
12967
+ if (blockComment) {
12968
+ if (current === "*" && next === "/") {
12969
+ blockComment = false;
12970
+ i += 1;
12971
+ }
12972
+ continue;
12973
+ }
12974
+ if (quote) {
12975
+ if (current === quote) {
12976
+ if (next === quote) i += 1;
12977
+ else quote = "";
12978
+ }
12979
+ continue;
12980
+ }
12981
+ if (bracket) {
12982
+ if (current === "]") {
12983
+ if (next === "]") i += 1;
12984
+ else bracket = false;
12985
+ }
12986
+ continue;
12987
+ }
12988
+ if (current === "-" && next === "-") {
12989
+ lineComment = true;
12990
+ i += 1;
12991
+ continue;
12992
+ }
12993
+ if (current === "/" && next === "*") {
12994
+ blockComment = true;
12995
+ i += 1;
12996
+ continue;
12997
+ }
12998
+ if (current === "'" || current === '"' || current === "`") {
12999
+ quote = current;
13000
+ continue;
13001
+ }
13002
+ if (current === "[") {
13003
+ bracket = true;
13004
+ continue;
13005
+ }
13006
+ if (current === "(") depth += 1;
13007
+ else if (current === ")") {
13008
+ depth -= 1;
13009
+ if (depth === 0) {
13010
+ close = i;
13011
+ break;
13012
+ }
13013
+ }
13014
+ }
13015
+ if (close < 0) return [];
13016
+ const body = createSql.slice(open + 1, close);
13017
+ const segments = [];
13018
+ let start = 0;
13019
+ depth = 0;
13020
+ quote = "";
13021
+ bracket = false;
13022
+ lineComment = false;
13023
+ blockComment = false;
13024
+ for (let i = 0; i < body.length; i += 1) {
13025
+ const current = body[i];
13026
+ const next = body[i + 1] ?? "";
13027
+ if (lineComment) {
13028
+ if (current === "\n" || current === "\r") lineComment = false;
13029
+ continue;
13030
+ }
13031
+ if (blockComment) {
13032
+ if (current === "*" && next === "/") {
13033
+ blockComment = false;
13034
+ i += 1;
13035
+ }
13036
+ continue;
13037
+ }
13038
+ if (quote) {
13039
+ if (current === quote) {
13040
+ if (next === quote) i += 1;
13041
+ else quote = "";
13042
+ }
13043
+ continue;
13044
+ }
13045
+ if (bracket) {
13046
+ if (current === "]") {
13047
+ if (next === "]") i += 1;
13048
+ else bracket = false;
13049
+ }
13050
+ continue;
13051
+ }
13052
+ if (current === "-" && next === "-") {
13053
+ lineComment = true;
13054
+ i += 1;
13055
+ continue;
13056
+ }
13057
+ if (current === "/" && next === "*") {
13058
+ blockComment = true;
13059
+ i += 1;
13060
+ continue;
13061
+ }
13062
+ if (current === "'" || current === '"' || current === "`") {
13063
+ quote = current;
13064
+ continue;
13065
+ }
13066
+ if (current === "[") {
13067
+ bracket = true;
13068
+ continue;
13069
+ }
13070
+ if (current === "(") depth += 1;
13071
+ else if (current === ")" && depth > 0) depth -= 1;
13072
+ else if (current === "," && depth === 0) {
13073
+ segments.push(body.slice(start, i).trim());
13074
+ start = i + 1;
13075
+ }
13076
+ }
13077
+ segments.push(body.slice(start).trim());
13078
+ return segments.filter(Boolean);
13079
+ };
13080
+ var findTopLevelKeyword = (text, keyword, start = 0) => {
13081
+ let depth = 0;
13082
+ let quote = "";
13083
+ let bracket = false;
13084
+ for (let i = start; i < text.length; i += 1) {
13085
+ const current = text[i];
13086
+ const next = text[i + 1] ?? "";
13087
+ if (quote) {
13088
+ if (current === quote) {
13089
+ if (next === quote) i += 1;
13090
+ else quote = "";
13091
+ }
13092
+ continue;
13093
+ }
13094
+ if (bracket) {
13095
+ if (current === "]") {
13096
+ if (next === "]") i += 1;
13097
+ else bracket = false;
13098
+ }
13099
+ continue;
13100
+ }
13101
+ if (current === "'" || current === '"' || current === "`") {
13102
+ quote = current;
13103
+ continue;
13104
+ }
13105
+ if (current === "[") {
13106
+ bracket = true;
13107
+ continue;
13108
+ }
13109
+ if (current === "(") {
13110
+ depth += 1;
13111
+ continue;
13112
+ }
13113
+ if (current === ")") {
13114
+ if (depth > 0) depth -= 1;
13115
+ continue;
13116
+ }
13117
+ if (depth === 0 && keywordAt(text, i, keyword)) return i;
13118
+ }
13119
+ return -1;
13120
+ };
13121
+ var isInitiallyDeferred = (segment, start) => {
13122
+ const deferrablePos = findTopLevelKeyword(segment, "DEFERRABLE", start);
13123
+ if (deferrablePos < 0) return false;
13124
+ const before = segment.slice(start, deferrablePos).trimEnd();
13125
+ if (/\bNOT$/i.test(before)) return false;
13126
+ return /^DEFERRABLE\s+INITIALLY\s+DEFERRED\b/i.test(segment.slice(deferrablePos));
13127
+ };
13128
+ var parseTableForeignKey = (segment) => {
13129
+ let pos = skipWhitespace(segment, 0);
13130
+ let name;
13131
+ if (keywordAt(segment, pos, "CONSTRAINT")) {
13132
+ pos += "CONSTRAINT".length;
13133
+ const parsedName = readIdentifier(segment, pos);
13134
+ if (!parsedName) return void 0;
13135
+ name = parsedName.value;
13136
+ pos = skipWhitespace(segment, parsedName.next);
13137
+ }
13138
+ if (!keywordAt(segment, pos, "FOREIGN")) return void 0;
13139
+ pos += "FOREIGN".length;
13140
+ pos = skipWhitespace(segment, pos);
13141
+ if (!keywordAt(segment, pos, "KEY")) return void 0;
13142
+ pos += "KEY".length;
13143
+ pos = skipWhitespace(segment, pos);
13144
+ if (segment[pos] !== "(") return void 0;
13145
+ pos += 1;
13146
+ const source = readIdentifier(segment, pos);
13147
+ if (!source) return void 0;
13148
+ pos = skipWhitespace(segment, source.next);
13149
+ if (segment[pos] === ",") return void 0;
13150
+ const referencesPos = findTopLevelKeyword(segment, "REFERENCES", pos);
13151
+ if (referencesPos < 0) return void 0;
13152
+ return {
13153
+ column: source.value,
13154
+ ...name ? { name } : {},
13155
+ deferrable: isInitiallyDeferred(segment, referencesPos)
13156
+ };
13157
+ };
13158
+ var parseInlineForeignKey = (segment) => {
13159
+ const source = readIdentifier(segment, 0);
13160
+ if (!source) return void 0;
13161
+ const referencesPos = findTopLevelKeyword(segment, "REFERENCES", source.next);
13162
+ if (referencesPos < 0) return void 0;
13163
+ let name;
13164
+ const constraintPos = findTopLevelKeyword(segment, "CONSTRAINT", source.next);
13165
+ if (constraintPos >= 0 && constraintPos < referencesPos) {
13166
+ const parsedName = readIdentifier(segment, constraintPos + "CONSTRAINT".length);
13167
+ if (parsedName) name = parsedName.value;
13168
+ }
13169
+ return {
13170
+ column: source.value,
13171
+ ...name ? { name } : {},
13172
+ deferrable: isInitiallyDeferred(segment, referencesPos)
13173
+ };
13174
+ };
13175
+ var parseSqliteForeignKeyModifiers = (createSql) => {
13176
+ const result = [];
13177
+ for (const segment of splitTableBody(createSql)) {
13178
+ const tableConstraint = parseTableForeignKey(segment);
13179
+ if (tableConstraint) {
13180
+ result.push(tableConstraint);
13181
+ continue;
13182
+ }
13183
+ const inlineConstraint = parseInlineForeignKey(segment);
13184
+ if (inlineConstraint) result.push(inlineConstraint);
13185
+ }
13186
+ return result;
13187
+ };
13188
+
12893
13189
  // src/core/ddl/introspect/sqlite.ts
12894
13190
  var toReferentialAction = (value) => {
12895
13191
  if (!value) return void 0;
@@ -12907,7 +13203,7 @@ var columnNode2 = (table, name, alias) => ({
12907
13203
  });
12908
13204
  var buildPragmaQuery = (name, table, alias, columnAliases) => ({
12909
13205
  type: "SelectQuery",
12910
- from: fnTable(name, [valueToOperand(table)], alias, { columnAliases }),
13206
+ from: fnTable(name, [valueToOperand(table)], alias),
12911
13207
  columns: columnAliases.map((column) => columnNode2(alias, column)),
12912
13208
  joins: []
12913
13209
  });
@@ -12968,7 +13264,10 @@ var sqliteIntrospector = {
12968
13264
  const tablesQuery = {
12969
13265
  type: "SelectQuery",
12970
13266
  from: { type: "Table", name: "sqlite_master" },
12971
- columns: [columnNode2(alias, "name")],
13267
+ columns: [
13268
+ columnNode2(alias, "name"),
13269
+ columnNode2(alias, "sql")
13270
+ ],
12972
13271
  joins: [],
12973
13272
  where: and(
12974
13273
  eq(columnNode2(alias, "type"), "table"),
@@ -13038,6 +13337,14 @@ var sqliteIntrospector = {
13038
13337
  };
13039
13338
  }
13040
13339
  });
13340
+ if (row.sql) {
13341
+ for (const modifier of parseSqliteForeignKeyModifiers(row.sql)) {
13342
+ const reference = tableEntry.columns.find((column) => column.name === modifier.column)?.references;
13343
+ if (!reference) continue;
13344
+ if (modifier.name) reference.name = modifier.name;
13345
+ reference.deferrable = modifier.deferrable;
13346
+ }
13347
+ }
13041
13348
  for (const idx of indexList) {
13042
13349
  if (!idx.name) continue;
13043
13350
  const indexColumns = await runPragma(
@@ -14261,6 +14568,7 @@ var createSqliteSchemaDialect = () => composeSchemaDialect({
14261
14568
  void table;
14262
14569
  return !!(column.autoIncrement && primaryKey.length === 1 && primaryKey[0] === column.name);
14263
14570
  },
14571
+ renderReferenceSuffix: (ref) => ref.deferrable ? "DEFERRABLE INITIALLY DEFERRED" : void 0,
14264
14572
  renderIndex(table, index, services) {
14265
14573
  const name = index.name || deriveIndexName(table, index);
14266
14574
  const columns = renderIndexColumns(services, index.columns);