@vibeorm/migrate 2.0.0-alpha.1 → 2.0.0-alpha.3
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 +68 -23
- package/dist/index.js.map +6 -6
- package/dist/introspect/postgres.d.ts.map +1 -1
- package/dist/introspect/shared.d.ts +6 -1
- package/dist/introspect/shared.d.ts.map +1 -1
- package/dist/postgres-types.d.ts +8 -1
- package/dist/postgres-types.d.ts.map +1 -1
- package/dist/relations.d.ts +14 -4
- package/dist/relations.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -74,9 +74,12 @@ function detectImplicitM2MPairs(params) {
|
|
|
74
74
|
const target = modelsByName.get(relation.targetModel);
|
|
75
75
|
if (target === undefined || target.isView)
|
|
76
76
|
continue;
|
|
77
|
-
const counterpart =
|
|
78
|
-
if (counterpart === undefined)
|
|
77
|
+
const counterpart = soleCounterpart({ relation, ownModel: model.name, target });
|
|
78
|
+
if (counterpart === undefined || !isFieldlessListSide({ relation: counterpart }))
|
|
79
79
|
continue;
|
|
80
|
+
if (soleCounterpart({ relation: counterpart, ownModel: target.name, target: model }) !== relation) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
80
83
|
const joinTable = implicitJoinTable({
|
|
81
84
|
modelA: model.name,
|
|
82
85
|
modelB: relation.targetModel,
|
|
@@ -99,6 +102,11 @@ function isFieldlessListSide(params) {
|
|
|
99
102
|
const { relation } = params;
|
|
100
103
|
return relation.isList && (relation.fields === undefined || relation.fields.length === 0);
|
|
101
104
|
}
|
|
105
|
+
function soleCounterpart(params) {
|
|
106
|
+
const { relation, ownModel, target } = params;
|
|
107
|
+
const candidates = target.relations.filter((candidate) => candidate !== relation && candidate.targetModel === ownModel && candidate.relationName === relation.relationName);
|
|
108
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
109
|
+
}
|
|
102
110
|
|
|
103
111
|
// packages/migrate/src/postgres-types.ts
|
|
104
112
|
import { VibeError, isEnumType } from "@vibeorm/schema";
|
|
@@ -110,10 +118,13 @@ var SCALAR_TO_PG = {
|
|
|
110
118
|
BigInt: "bigint",
|
|
111
119
|
Float: "double precision",
|
|
112
120
|
Decimal: "numeric",
|
|
113
|
-
DateTime: "timestamptz
|
|
121
|
+
DateTime: "timestamptz",
|
|
114
122
|
Json: "jsonb",
|
|
115
123
|
Bytes: "bytea"
|
|
116
124
|
};
|
|
125
|
+
var CANONICAL_EQUIVALENTS = {
|
|
126
|
+
DateTime: ["timestamptz(3)", "timestamptz(6)"]
|
|
127
|
+
};
|
|
117
128
|
var NATIVE_ALIASES = {
|
|
118
129
|
charactervarying: "varchar",
|
|
119
130
|
character: "char",
|
|
@@ -155,7 +166,8 @@ function columnTypeKey(params) {
|
|
|
155
166
|
if (field.nativeType !== undefined) {
|
|
156
167
|
const normalized = normalizeNativeType({ raw: field.nativeType });
|
|
157
168
|
const canonical = normalizeNativeType({ raw: SCALAR_TO_PG[field.type] });
|
|
158
|
-
|
|
169
|
+
const isCanonical = normalized === canonical || (CANONICAL_EQUIVALENTS[field.type]?.includes(normalized) ?? false);
|
|
170
|
+
if (!isCanonical)
|
|
159
171
|
return `n:${normalized}${listSuffix}`;
|
|
160
172
|
}
|
|
161
173
|
return `s:${field.type}${listSuffix}`;
|
|
@@ -219,6 +231,9 @@ function defaultFingerprint(params) {
|
|
|
219
231
|
return `num:${value}`;
|
|
220
232
|
if (isEnumType(field.type))
|
|
221
233
|
return `enum:${value}`;
|
|
234
|
+
if (isNumericScalar({ type: field.type }) && NUMERIC_LITERAL.test(value)) {
|
|
235
|
+
return `num:${Number(value)}`;
|
|
236
|
+
}
|
|
222
237
|
return `str:${value}`;
|
|
223
238
|
}
|
|
224
239
|
case "enumValue":
|
|
@@ -254,6 +269,11 @@ function defaultSql(params) {
|
|
|
254
269
|
return def.sql;
|
|
255
270
|
}
|
|
256
271
|
}
|
|
272
|
+
var NUMERIC_LITERAL = /^-?\d+(\.\d+)?$/;
|
|
273
|
+
function isNumericScalar(params) {
|
|
274
|
+
const { type } = params;
|
|
275
|
+
return type === "Int" || type === "BigInt" || type === "Float" || type === "Decimal";
|
|
276
|
+
}
|
|
257
277
|
var PG_CHAR_TO_CASCADE_ACTION = {
|
|
258
278
|
a: "NoAction",
|
|
259
279
|
r: "Restrict",
|
|
@@ -2330,6 +2350,7 @@ function addFkRelations(params) {
|
|
|
2330
2350
|
const modelsByName = new Map(models.map((model) => [model.name, model]));
|
|
2331
2351
|
const relationsByModel = new Map;
|
|
2332
2352
|
const takeName = nameAllocator({ models });
|
|
2353
|
+
const ambiguousPairs = detectAmbiguousPairs({ fkGroups, joinTables, modelsByName });
|
|
2333
2354
|
for (const group of fkGroups) {
|
|
2334
2355
|
if (joinTables.has(group.table))
|
|
2335
2356
|
continue;
|
|
@@ -2337,6 +2358,7 @@ function addFkRelations(params) {
|
|
|
2337
2358
|
const target = modelsByName.get(group.refTable);
|
|
2338
2359
|
if (owner === undefined || target === undefined)
|
|
2339
2360
|
continue;
|
|
2361
|
+
const relationName = ambiguousPairs.has(modelPairKey({ a: group.table, b: group.refTable })) ? `${group.table}_${group.columns.join("_")}To${group.refTable}` : undefined;
|
|
2340
2362
|
const fkSide = {
|
|
2341
2363
|
name: takeName({ model: owner.name, base: lowerFirst(group.refTable) }),
|
|
2342
2364
|
model: owner.name,
|
|
@@ -2347,7 +2369,8 @@ function addFkRelations(params) {
|
|
|
2347
2369
|
onDelete: group.onDelete,
|
|
2348
2370
|
onUpdate: group.onUpdate,
|
|
2349
2371
|
isList: false,
|
|
2350
|
-
isOptional: !group.required
|
|
2372
|
+
isOptional: !group.required,
|
|
2373
|
+
...relationName === undefined ? {} : { relationName }
|
|
2351
2374
|
};
|
|
2352
2375
|
pushRelation({ relationsByModel, relation: fkSide });
|
|
2353
2376
|
const listSide = {
|
|
@@ -2356,7 +2379,8 @@ function addFkRelations(params) {
|
|
|
2356
2379
|
targetModel: group.table,
|
|
2357
2380
|
type: "oneToMany",
|
|
2358
2381
|
isList: true,
|
|
2359
|
-
isOptional: false
|
|
2382
|
+
isOptional: false,
|
|
2383
|
+
...relationName === undefined ? {} : { relationName }
|
|
2360
2384
|
};
|
|
2361
2385
|
pushRelation({ relationsByModel, relation: listSide });
|
|
2362
2386
|
}
|
|
@@ -2400,6 +2424,30 @@ function addJoinTableRelations(params) {
|
|
|
2400
2424
|
}
|
|
2401
2425
|
applyRelations({ models, relationsByModel });
|
|
2402
2426
|
}
|
|
2427
|
+
function modelPairKey(params) {
|
|
2428
|
+
const { a, b } = params;
|
|
2429
|
+
return [a, b].sort().join("\x00");
|
|
2430
|
+
}
|
|
2431
|
+
function detectAmbiguousPairs(params) {
|
|
2432
|
+
const { fkGroups, joinTables, modelsByName } = params;
|
|
2433
|
+
const counts = new Map;
|
|
2434
|
+
const bump = (key) => {
|
|
2435
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
2436
|
+
};
|
|
2437
|
+
for (const group of fkGroups) {
|
|
2438
|
+
if (joinTables.has(group.table))
|
|
2439
|
+
continue;
|
|
2440
|
+
if (!modelsByName.has(group.table) || !modelsByName.has(group.refTable))
|
|
2441
|
+
continue;
|
|
2442
|
+
bump(modelPairKey({ a: group.table, b: group.refTable }));
|
|
2443
|
+
}
|
|
2444
|
+
for (const [, joinTable] of joinTables) {
|
|
2445
|
+
if (joinTable.relationName !== undefined)
|
|
2446
|
+
continue;
|
|
2447
|
+
bump(modelPairKey({ a: joinTable.tableA, b: joinTable.tableB }));
|
|
2448
|
+
}
|
|
2449
|
+
return new Set([...counts.entries()].filter(([, count]) => count > 1).map(([key]) => key));
|
|
2450
|
+
}
|
|
2403
2451
|
function pushRelation(params) {
|
|
2404
2452
|
const { relationsByModel, relation } = params;
|
|
2405
2453
|
const list = relationsByModel.get(relation.model);
|
|
@@ -2500,17 +2548,18 @@ var COLUMNS_QUERY = `
|
|
|
2500
2548
|
`;
|
|
2501
2549
|
var CONSTRAINTS_QUERY = `
|
|
2502
2550
|
SELECT
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
FROM
|
|
2508
|
-
JOIN
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2551
|
+
c.conname AS constraint_name,
|
|
2552
|
+
CASE c.contype WHEN 'p' THEN 'PRIMARY KEY' ELSE 'UNIQUE' END AS constraint_type,
|
|
2553
|
+
cl.relname AS table_name,
|
|
2554
|
+
att.attname AS column_name
|
|
2555
|
+
FROM pg_catalog.pg_constraint c
|
|
2556
|
+
JOIN pg_catalog.pg_class cl ON cl.oid = c.conrelid
|
|
2557
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = cl.relnamespace
|
|
2558
|
+
JOIN unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord) ON true
|
|
2559
|
+
JOIN pg_catalog.pg_attribute att ON att.attrelid = c.conrelid AND att.attnum = k.attnum
|
|
2560
|
+
WHERE c.contype IN ('p', 'u')
|
|
2561
|
+
AND n.nspname = 'public'
|
|
2562
|
+
ORDER BY cl.relname, c.conname, k.ord;
|
|
2514
2563
|
`;
|
|
2515
2564
|
var FOREIGN_KEYS_QUERY = `
|
|
2516
2565
|
SELECT
|
|
@@ -2821,7 +2870,7 @@ function nonCanonicalModifier(params) {
|
|
|
2821
2870
|
const { column, udt, scalar } = params;
|
|
2822
2871
|
if (scalar === "DateTime" && udt === "timestamptz") {
|
|
2823
2872
|
const precision = column.datetimePrecision;
|
|
2824
|
-
return precision === null || precision ===
|
|
2873
|
+
return precision === null || precision === 6 ? undefined : `timestamptz(${precision})`;
|
|
2825
2874
|
}
|
|
2826
2875
|
if (scalar === "Decimal" && udt === "numeric") {
|
|
2827
2876
|
if (column.numericPrecision === null)
|
|
@@ -2876,10 +2925,6 @@ function parseColumnDefault(params) {
|
|
|
2876
2925
|
}
|
|
2877
2926
|
return { kind: "dbgenerated", sql: raw };
|
|
2878
2927
|
}
|
|
2879
|
-
function isNumericScalar(params) {
|
|
2880
|
-
const { type } = params;
|
|
2881
|
-
return type === "Int" || type === "BigInt" || type === "Float" || type === "Decimal";
|
|
2882
|
-
}
|
|
2883
2928
|
function parseIndexDef(params) {
|
|
2884
2929
|
const { table, name, def } = params;
|
|
2885
2930
|
const head = def.match(/^CREATE (UNIQUE )?INDEX .*? USING (\w+) \(/);
|
|
@@ -3810,4 +3855,4 @@ export {
|
|
|
3810
3855
|
MIGRATIONS_TABLE_NAME
|
|
3811
3856
|
};
|
|
3812
3857
|
|
|
3813
|
-
//# debugId=
|
|
3858
|
+
//# debugId=5088DA7EA679FA1464756E2164756E21
|