@vibeorm/migrate 2.6.0 → 2.7.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
@@ -233,6 +233,9 @@ var SCALAR_TO_PG = {
233
233
  var CANONICAL_EQUIVALENTS = {
234
234
  DateTime: ["timestamptz(3)", "timestamptz(6)"]
235
235
  };
236
+ var EXACT_CANONICAL_EQUIVALENTS = {
237
+ DateTime: ["timestamptz(6)"]
238
+ };
236
239
  var CANONICAL_UDT = {
237
240
  text: "String",
238
241
  bool: "Boolean",
@@ -301,13 +304,15 @@ var NATIVE_ALIASES = {
301
304
  var IMPLICIT_MODIFIERS = {
302
305
  bit: "(1)"
303
306
  };
307
+ var DEFAULT_PRECISION_SIX = new Set(["timestamp", "time", "timetz"]);
304
308
  function normalizeNativeType(params) {
305
309
  const compact = params.raw.toLowerCase().replace(/\s+/g, "");
306
310
  const match = compact.match(/^([a-z_0-9]+)(\(.*\))?(\[\])?$/);
307
311
  if (match === null)
308
312
  return compact;
309
313
  const base = NATIVE_ALIASES[match[1]] ?? match[1];
310
- return `${base}${match[2] ?? IMPLICIT_MODIFIERS[base] ?? ""}${match[3] ?? ""}`;
314
+ const modifier = DEFAULT_PRECISION_SIX.has(base) && match[2] === "(6)" ? "" : match[2] ?? IMPLICIT_MODIFIERS[base] ?? "";
315
+ return `${base}${modifier}${match[3] ?? ""}`;
311
316
  }
312
317
  function parseUnsupportedPostgresType(params) {
313
318
  const temporal = /^\s*(time(?:stamp)?)\s*(\(\s*\d+\s*\))?\s+(with|without)\s+time\s+zone\s*((?:\[\s*\]\s*)*)$/i.exec(params.raw);
@@ -320,7 +325,7 @@ function parseUnsupportedPostgresType(params) {
320
325
  return NATIVE_ALIASES[base] === undefined ? undefined : parsePostgresTypeName({ raw: normalizeNativeType(params) });
321
326
  }
322
327
  function columnTypeKey(params) {
323
- const { field } = params;
328
+ const { field, exact } = params;
324
329
  const listSuffix = field.isList ? "[]" : "";
325
330
  if (field.isUnsupported === true) {
326
331
  const parsed = parseUnsupportedPostgresType({ raw: field.nativeType ?? "" });
@@ -331,7 +336,7 @@ function columnTypeKey(params) {
331
336
  const scalar = namespace === undefined || namespace === "pg_catalog" ? scalarForBuiltinType({ name: parsed.name }) : undefined;
332
337
  if (scalar !== undefined) {
333
338
  const { isUnsupported: _unsupported, nativeTypeIdentity: _identity, ...rest } = field;
334
- return columnTypeKey({ field: { ...rest, type: scalar, nativeType: `${parsed.name}${parsed.modifier ?? ""}`, isList: parsed.array || field.isList } });
339
+ return columnTypeKey({ field: { ...rest, type: scalar, nativeType: `${parsed.name}${parsed.modifier ?? ""}`, isList: parsed.array || field.isList }, ...exact === undefined ? {} : { exact } });
335
340
  }
336
341
  return `u:${JSON.stringify([namespace ?? null, parsed.name, parsed.modifier, parsed.array || field.isList])}`;
337
342
  }
@@ -342,12 +347,37 @@ function columnTypeKey(params) {
342
347
  if (field.nativeType !== undefined) {
343
348
  const normalized = normalizeNativeType({ raw: field.nativeType });
344
349
  const canonical = normalizeNativeType({ raw: SCALAR_TO_PG[field.type] });
345
- const isCanonical = normalized === canonical || (CANONICAL_EQUIVALENTS[field.type]?.includes(normalized) ?? false);
350
+ const equivalents = exact === true ? EXACT_CANONICAL_EQUIVALENTS : CANONICAL_EQUIVALENTS;
351
+ const isCanonical = normalized === canonical || (equivalents[field.type]?.includes(normalized) ?? false);
346
352
  if (!isCanonical)
347
353
  return `n:${normalized}${listSuffix}`;
348
354
  }
349
355
  return `s:${field.type}${listSuffix}`;
350
356
  }
357
+ function declaresExactColumnType(params) {
358
+ const { field } = params;
359
+ if (field.isUnsupported === true || field.nativeType === undefined || isEnumType2(field.type))
360
+ return false;
361
+ return CANONICAL_EQUIVALENTS[field.type]?.includes(normalizeNativeType({ raw: field.nativeType })) ?? false;
362
+ }
363
+ function timestamptzPrecision(params) {
364
+ const { field } = params;
365
+ if (field.type !== "DateTime" || field.isUnsupported === true)
366
+ return;
367
+ const normalized = field.nativeType === undefined ? "timestamptz" : normalizeNativeType({ raw: field.nativeType });
368
+ if (normalized === "timestamptz")
369
+ return 6;
370
+ const match = /^timestamptz\((\d)\)$/.exec(normalized);
371
+ return match === null ? undefined : Number(match[1]);
372
+ }
373
+ function isTimestamptzPrecisionWidening(params) {
374
+ const { from, to } = params;
375
+ if (from.isList !== to.isList)
376
+ return false;
377
+ const before = timestamptzPrecision({ field: from });
378
+ const after = timestamptzPrecision({ field: to });
379
+ return before !== undefined && after !== undefined && after >= before;
380
+ }
351
381
  function isScalarToArrayChange(params) {
352
382
  const { from, to } = params;
353
383
  if (from.isList || !to.isList)
@@ -1094,16 +1124,20 @@ function assertStringEnumLabelsFit(params) {
1094
1124
  }
1095
1125
  }
1096
1126
  function columnTypeKeyFor(params) {
1097
- const { field, dialect, enums } = params;
1127
+ const { field, dialect, enums, exact } = params;
1098
1128
  switch (dialect) {
1099
1129
  case "postgres":
1100
- return columnTypeKey({ field });
1130
+ return columnTypeKey({ field, ...exact === undefined ? {} : { exact } });
1101
1131
  case "sqlite":
1102
1132
  return sqliteColumnTypeKey({ field, enums });
1103
1133
  case "mysql":
1104
1134
  return mysqlColumnTypeKey({ field, enums });
1105
1135
  }
1106
1136
  }
1137
+ function columnTypeChanged(params) {
1138
+ const { declared, actual } = params;
1139
+ return declared.pinsExactType ? declared.exactTypeKey !== actual.exactTypeKey : declared.typeKey !== actual.typeKey;
1140
+ }
1107
1141
  function defaultFingerprintFor(params) {
1108
1142
  const { field, dialect } = params;
1109
1143
  switch (dialect) {
@@ -1126,6 +1160,8 @@ function normalizeModel(params) {
1126
1160
  name,
1127
1161
  field,
1128
1162
  typeKey: columnTypeKeyFor({ field, dialect, enums }),
1163
+ exactTypeKey: columnTypeKeyFor({ field, dialect, enums, exact: true }),
1164
+ pinsExactType: dialect === "postgres" && declaresExactColumnType({ field }),
1129
1165
  nullable: field.isOptional,
1130
1166
  defaultKey: defaultFingerprintFor({ field, dialect })
1131
1167
  });
@@ -2199,8 +2235,9 @@ function reverseMapType(params) {
2199
2235
  function nonCanonicalModifier(params) {
2200
2236
  const { column, udt, scalar } = params;
2201
2237
  if (column.dataType === "ARRAY" && column.fullType !== null) {
2202
- const element = normalizeNativeType({ raw: column.fullType }).replace(/\[\]$/, "");
2203
- if (/^(numeric|timestamptz)\([\d,]+\)$/.test(element))
2238
+ const temporal = parseUnsupportedPostgresType({ raw: column.fullType });
2239
+ const element = temporal?.name === "timestamptz" ? `timestamptz${temporal.modifier}` : normalizeNativeType({ raw: column.fullType }).replace(/\[\]$/, "");
2240
+ if (element !== "timestamptz(6)" && /^(numeric|timestamptz)\([\d,]+\)$/.test(element))
2204
2241
  return element;
2205
2242
  }
2206
2243
  if (scalar === "DateTime" && udt === "timestamptz") {
@@ -2217,9 +2254,9 @@ function nonCanonicalModifier(params) {
2217
2254
  }
2218
2255
  function withModifier(params) {
2219
2256
  const { column, udt } = params;
2220
- if (udt === "varchar" && column.dataType === "ARRAY" && column.fullType !== null) {
2257
+ if ((udt === "varchar" || udt === "bpchar" || udt === "bit" || udt === "varbit") && column.dataType === "ARRAY" && column.fullType !== null) {
2221
2258
  const elementType = normalizeNativeType({ raw: column.fullType }).replace(/\[\]$/, "");
2222
- if (/^varchar\(\d+\)$/.test(elementType))
2259
+ if (/^(varchar|char|bit|varbit)\(\d+\)$/.test(elementType))
2223
2260
  return elementType;
2224
2261
  }
2225
2262
  if ((udt === "varchar" || udt === "bpchar") && column.charMaxLength !== null) {
@@ -2229,6 +2266,10 @@ function withModifier(params) {
2229
2266
  return "char";
2230
2267
  if ((udt === "bit" || udt === "varbit") && column.charMaxLength !== null)
2231
2268
  return `${udt}(${column.charMaxLength})`;
2269
+ if ((udt === "timestamp" || udt === "time" || udt === "timetz") && column.dataType === "ARRAY" && column.fullType !== null) {
2270
+ const element = parseUnsupportedPostgresType({ raw: column.fullType });
2271
+ return element === undefined || element.modifier === "" || element.modifier === "(6)" ? udt : `${udt}${element.modifier}`;
2272
+ }
2232
2273
  if ((udt === "timestamp" || udt === "time" || udt === "timetz") && column.datetimePrecision !== null && column.datetimePrecision !== 6) {
2233
2274
  return `${udt}(${column.datetimePrecision})`;
2234
2275
  }
@@ -3944,7 +3985,8 @@ async function verifySchemaObjects(params) {
3944
3985
  pin("primaryKey", desired.pk, live.pk);
3945
3986
  for (const [column, field] of desired.columns) {
3946
3987
  const stored = live.columns.get(column);
3947
- pin(`columns.${column}.type`, field.typeKey, stored?.typeKey);
3988
+ const exactType = field.pinsExactType;
3989
+ pin(`columns.${column}.type`, exactType ? field.exactTypeKey : field.typeKey, exactType ? stored?.exactTypeKey : stored?.typeKey);
3948
3990
  pin(`columns.${column}.nullable`, field.nullable, stored?.nullable);
3949
3991
  if (params.dialect === "mysql" && field.field.collation !== undefined) {
3950
3992
  pin(`columns.${column}.collation`, field.field.collation.toLowerCase(), stored?.field.collation?.toLowerCase());
@@ -6051,7 +6093,7 @@ function diffOneTable(params) {
6051
6093
  continue;
6052
6094
  }
6053
6095
  const changes = [];
6054
- if (before.typeKey !== column.typeKey)
6096
+ if (columnTypeChanged({ declared: column, actual: before }))
6055
6097
  changes.push("type");
6056
6098
  if (before.nullable !== column.nullable)
6057
6099
  changes.push("nullability");
@@ -6074,7 +6116,7 @@ function diffOneTable(params) {
6074
6116
  assertStringEnumLabelsFit({ field: column.field, values, dialect, table });
6075
6117
  }
6076
6118
  }
6077
- let narrowingType = changes.includes("type") && !isScalarToArrayChange({ from: before.field, to: column.field }) && !(storageChange && column.field.type === "String");
6119
+ let narrowingType = changes.includes("type") && !isScalarToArrayChange({ from: before.field, to: column.field }) && !(dialect === "postgres" && isTimestamptzPrecisionWidening({ from: before.field, to: column.field })) && !(storageChange && column.field.type === "String");
6078
6120
  if (dialect !== "postgres" && changes.includes("type") && isEnumType6(before.field.type) && isEnumType6(column.field.type)) {
6079
6121
  const fromValues = resolveEnumValues({ name: before.field.type.enum, enums: fromEnums });
6080
6122
  const toValues = resolveEnumValues({ name: column.field.type.enum, enums: toEnums });
@@ -10886,4 +10928,4 @@ export {
10886
10928
  withMigrationReference
10887
10929
  };
10888
10930
 
10889
- //# debugId=715A0F1724FB835564756E2164756E21
10931
+ //# debugId=CC107738F16DF7A964756E2164756E21