@vibeorm/migrate 1.1.4 → 1.1.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeorm/migrate",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Migration, introspection, and schema diff toolkit for VibeORM",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -37,6 +37,6 @@
37
37
  "bun": ">=1.1.0"
38
38
  },
39
39
  "dependencies": {
40
- "@vibeorm/parser": "1.1.4"
40
+ "@vibeorm/parser": "1.1.5"
41
41
  }
42
42
  }
@@ -37,9 +37,9 @@ function resolveColumnType(params: { field: ScalarField }): string {
37
37
  return field.prismaType === "BigInt" ? "BIGSERIAL" : "SERIAL";
38
38
  }
39
39
 
40
- // Native type override (e.g., @db.VarChar(255))
40
+ // Native type override (e.g., @db.VarChar(255)) — lowercased to canonical PG form
41
41
  if (field.nativeType) {
42
- return field.nativeType;
42
+ return field.nativeType.toLowerCase();
43
43
  }
44
44
 
45
45
  // List fields use PostgreSQL arrays
@@ -53,7 +53,7 @@ function resolveColumnType(params: { field: ScalarField }): string {
53
53
  /** Resolve to the base column type (no SERIAL — used for FK reference columns) */
54
54
  function resolveBaseColumnType(params: { field: ScalarField }): string {
55
55
  const { field } = params;
56
- if (field.nativeType) return field.nativeType;
56
+ if (field.nativeType) return field.nativeType.toLowerCase();
57
57
  if (field.isList) return `${PRISMA_TO_PG[field.prismaType]}[]`;
58
58
  return PRISMA_TO_PG[field.prismaType];
59
59
  }
@@ -77,7 +77,7 @@ function resolveColumnType(params: { field: ScalarField | EnumField; enums: Enum
77
77
  if (field.default?.kind === "autoincrement") {
78
78
  return field.prismaType === "BigInt" ? "BIGSERIAL" : "SERIAL";
79
79
  }
80
- if (field.nativeType) return field.nativeType;
80
+ if (field.nativeType) return field.nativeType.toLowerCase();
81
81
  if (field.isList) return `${PRISMA_TO_PG[field.prismaType]}[]`;
82
82
  return PRISMA_TO_PG[field.prismaType];
83
83
  }
@@ -89,7 +89,7 @@ function resolveBaseColumnType(params: { field: ScalarField | EnumField; enums:
89
89
  const enumDef = enums.find((e) => e.name === field.enumName);
90
90
  return q({ name: enumDef?.dbName ?? field.enumName });
91
91
  }
92
- if (field.nativeType) return field.nativeType;
92
+ if (field.nativeType) return field.nativeType.toLowerCase();
93
93
  if (field.isList) return `${PRISMA_TO_PG[field.prismaType]}[]`;
94
94
  return PRISMA_TO_PG[field.prismaType];
95
95
  }
@@ -123,6 +123,42 @@ function uniqueKey(params: { uc: UniqueConstraint; model: Model }): string {
123
123
  .join(",");
124
124
  }
125
125
 
126
+ /**
127
+ * Build the effective set of unique constraints for a model by merging
128
+ * explicit `uniqueConstraints` entries with synthetic single-field entries
129
+ * from fields that have `isUnique: true`.
130
+ *
131
+ * This normalizes the two representations of single-field uniqueness:
132
+ * - `@unique` on a field → `isUnique: true`, no `uniqueConstraints` entry
133
+ * - `@@unique([field])` on a model → `uniqueConstraints` entry, `isUnique: false`
134
+ *
135
+ * The database represents both identically, so the differ must treat them
136
+ * as equivalent to avoid phantom diffs when comparing parsed schemas against
137
+ * introspected schemas (which always use `isUnique: true` for single-field uniques).
138
+ */
139
+ function getEffectiveUniques(params: { model: Model }): Map<string, UniqueConstraint> {
140
+ const { model } = params;
141
+ const result = new Map<string, UniqueConstraint>();
142
+
143
+ // Add all explicit uniqueConstraints entries
144
+ for (const uc of model.uniqueConstraints) {
145
+ result.set(uniqueKey({ uc, model }), uc);
146
+ }
147
+
148
+ // Add synthetic entries for isUnique fields not already covered
149
+ for (const field of model.fields) {
150
+ if (field.kind === "relation") continue;
151
+ if (!field.isUnique) continue;
152
+ const syntheticUc: UniqueConstraint = { fields: [field.name], name: undefined };
153
+ const key = uniqueKey({ uc: syntheticUc, model });
154
+ if (!result.has(key)) {
155
+ result.set(key, syntheticUc);
156
+ }
157
+ }
158
+
159
+ return result;
160
+ }
161
+
126
162
  function indexKey(params: { idx: IndexDefinition; model: Model }): string {
127
163
  return params.idx.fields
128
164
  .map((f: string) => resolveFieldDbName({ model: params.model, fieldName: f }))
@@ -347,7 +383,7 @@ export function diffSchemas(params: { previous: Schema; current: Schema }): Diff
347
383
 
348
384
  const tableName = model.dbName;
349
385
 
350
- // Composite unique constraints
386
+ // Unique constraints from @@unique (single-field @unique is inline on the column)
351
387
  for (const uc of model.uniqueConstraints) {
352
388
  const cols = uc.fields.map((f: string) => q({ name: resolveFieldDbName({ model, fieldName: f }) })).join(", ");
353
389
  const resolvedFieldNames = uc.fields.map((f: string) => resolveFieldDbName({ model, fieldName: f }));
@@ -584,13 +620,11 @@ export function diffSchemas(params: { previous: Schema; current: Schema }): Diff
584
620
  }
585
621
 
586
622
  // ─── Unique Constraint Diffs ──────────────────────────────
623
+ // Use effective uniques to normalize @unique (field-level) and
624
+ // @@unique([field]) (model-level) representations before diffing.
587
625
 
588
- const prevUniques = new Map(
589
- prevModel.uniqueConstraints.map((uc: UniqueConstraint) => [uniqueKey({ uc, model: prevModel }), uc])
590
- );
591
- const currUniques = new Map(
592
- currModel.uniqueConstraints.map((uc: UniqueConstraint) => [uniqueKey({ uc, model: currModel }), uc])
593
- );
626
+ const prevUniques = getEffectiveUniques({ model: prevModel });
627
+ const currUniques = getEffectiveUniques({ model: currModel });
594
628
 
595
629
  for (const [key, uc] of currUniques) {
596
630
  if (prevUniques.has(key)) continue;