@famgia/omnify-atlas 0.0.5 → 0.0.7
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 +294 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +161 -15
- package/dist/index.d.ts +161 -15
- package/dist/index.js +288 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -25,8 +25,10 @@ __export(index_exports, {
|
|
|
25
25
|
addMigrationRecord: () => addMigrationRecord,
|
|
26
26
|
applySchema: () => applySchema,
|
|
27
27
|
buildSchemaHashes: () => buildSchemaHashes,
|
|
28
|
+
buildSchemaSnapshots: () => buildSchemaSnapshots,
|
|
28
29
|
checkAtlasVersion: () => checkAtlasVersion,
|
|
29
30
|
compareSchemas: () => compareSchemas,
|
|
31
|
+
compareSchemasDeep: () => compareSchemasDeep,
|
|
30
32
|
computeHash: () => computeHash,
|
|
31
33
|
computeSchemaHash: () => computeSchemaHash,
|
|
32
34
|
createEmptyLockFile: () => createEmptyLockFile,
|
|
@@ -39,15 +41,19 @@ __export(index_exports, {
|
|
|
39
41
|
getPrimaryKeyType: () => getPrimaryKeyType,
|
|
40
42
|
getTimestampType: () => getTimestampType,
|
|
41
43
|
hasBlockingIssues: () => hasBlockingIssues,
|
|
44
|
+
isLockFileV2: () => isLockFileV2,
|
|
42
45
|
mapPropertyToSql: () => mapPropertyToSql,
|
|
43
46
|
parseDiffOutput: () => parseDiffOutput,
|
|
44
47
|
previewSchemaChanges: () => previewSchemaChanges,
|
|
45
48
|
propertyNameToColumnName: () => propertyNameToColumnName,
|
|
49
|
+
propertyToSnapshot: () => propertyToSnapshot,
|
|
46
50
|
readLockFile: () => readLockFile,
|
|
47
51
|
renderHcl: () => renderHcl,
|
|
48
52
|
runAtlasDiff: () => runAtlasDiff,
|
|
49
53
|
schemaNameToTableName: () => schemaNameToTableName,
|
|
54
|
+
schemaToSnapshot: () => schemaToSnapshot,
|
|
50
55
|
updateLockFile: () => updateLockFile,
|
|
56
|
+
updateLockFileV1: () => updateLockFileV1,
|
|
51
57
|
validateHcl: () => validateHcl,
|
|
52
58
|
writeLockFile: () => writeLockFile
|
|
53
59
|
});
|
|
@@ -57,7 +63,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
57
63
|
var import_node_crypto = require("crypto");
|
|
58
64
|
var import_promises = require("fs/promises");
|
|
59
65
|
var LOCK_FILE_NAME = ".omnify.lock";
|
|
60
|
-
var LOCK_FILE_VERSION =
|
|
66
|
+
var LOCK_FILE_VERSION = 2;
|
|
61
67
|
function computeHash(content) {
|
|
62
68
|
return (0, import_node_crypto.createHash)("sha256").update(content, "utf8").digest("hex");
|
|
63
69
|
}
|
|
@@ -80,13 +86,75 @@ function createEmptyLockFile(driver) {
|
|
|
80
86
|
migrations: []
|
|
81
87
|
};
|
|
82
88
|
}
|
|
89
|
+
function propertyToSnapshot(property) {
|
|
90
|
+
const prop = property;
|
|
91
|
+
return {
|
|
92
|
+
type: prop.type,
|
|
93
|
+
nullable: prop.nullable,
|
|
94
|
+
unique: prop.unique,
|
|
95
|
+
default: prop.default,
|
|
96
|
+
length: prop.length,
|
|
97
|
+
unsigned: prop.unsigned,
|
|
98
|
+
precision: prop.precision,
|
|
99
|
+
scale: prop.scale,
|
|
100
|
+
enum: prop.enum,
|
|
101
|
+
relation: prop.relation,
|
|
102
|
+
target: prop.target,
|
|
103
|
+
onDelete: prop.onDelete,
|
|
104
|
+
onUpdate: prop.onUpdate,
|
|
105
|
+
mappedBy: prop.mappedBy,
|
|
106
|
+
joinTable: prop.joinTable,
|
|
107
|
+
// renamedFrom is kept in snapshot for comparison (rename detection),
|
|
108
|
+
// but will be stripped when writing to lock file.
|
|
109
|
+
renamedFrom: prop.renamedFrom
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function schemaToSnapshot(schema, hash, modifiedAt) {
|
|
113
|
+
const properties = {};
|
|
114
|
+
if (schema.properties) {
|
|
115
|
+
for (const [name, prop] of Object.entries(schema.properties)) {
|
|
116
|
+
properties[name] = propertyToSnapshot(prop);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const opts = schema.options;
|
|
120
|
+
let indexes;
|
|
121
|
+
if (opts?.indexes && opts.indexes.length > 0) {
|
|
122
|
+
indexes = opts.indexes.map((idx) => ({
|
|
123
|
+
columns: idx.columns,
|
|
124
|
+
unique: idx.unique ?? false,
|
|
125
|
+
name: idx.name
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
let uniqueConstraints;
|
|
129
|
+
if (opts?.unique) {
|
|
130
|
+
uniqueConstraints = Array.isArray(opts.unique[0]) ? opts.unique : [opts.unique];
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
name: schema.name,
|
|
134
|
+
kind: schema.kind ?? "object",
|
|
135
|
+
hash,
|
|
136
|
+
relativePath: schema.relativePath,
|
|
137
|
+
modifiedAt,
|
|
138
|
+
properties,
|
|
139
|
+
primaryKeyType: opts?.primaryKeyType,
|
|
140
|
+
timestamps: opts?.timestamps,
|
|
141
|
+
softDelete: opts?.softDelete,
|
|
142
|
+
indexes,
|
|
143
|
+
uniqueConstraints,
|
|
144
|
+
values: schema.values
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function isLockFileV2(lockFile) {
|
|
148
|
+
return lockFile.version === 2;
|
|
149
|
+
}
|
|
83
150
|
async function readLockFile(lockFilePath) {
|
|
84
151
|
try {
|
|
85
152
|
const content = await (0, import_promises.readFile)(lockFilePath, "utf8");
|
|
86
153
|
const parsed = JSON.parse(content);
|
|
87
|
-
|
|
154
|
+
const lockFile = parsed;
|
|
155
|
+
if (lockFile.version !== 1 && lockFile.version !== 2) {
|
|
88
156
|
throw new Error(
|
|
89
|
-
`Lock file version mismatch: expected
|
|
157
|
+
`Lock file version mismatch: expected 1 or 2, got ${lockFile.version}`
|
|
90
158
|
);
|
|
91
159
|
}
|
|
92
160
|
return parsed;
|
|
@@ -121,6 +189,138 @@ async function buildSchemaHashes(schemas) {
|
|
|
121
189
|
}
|
|
122
190
|
return hashes;
|
|
123
191
|
}
|
|
192
|
+
async function buildSchemaSnapshots(schemas) {
|
|
193
|
+
const snapshots = {};
|
|
194
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
195
|
+
const hash = computeSchemaHash(schema);
|
|
196
|
+
let modifiedAt;
|
|
197
|
+
try {
|
|
198
|
+
const stats = await (0, import_promises.stat)(schema.filePath);
|
|
199
|
+
modifiedAt = stats.mtime.toISOString();
|
|
200
|
+
} catch {
|
|
201
|
+
modifiedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
202
|
+
}
|
|
203
|
+
snapshots[name] = schemaToSnapshot(schema, hash, modifiedAt);
|
|
204
|
+
}
|
|
205
|
+
return snapshots;
|
|
206
|
+
}
|
|
207
|
+
function diffPropertySnapshots(prev, curr) {
|
|
208
|
+
const modifications = [];
|
|
209
|
+
if (prev.type !== curr.type) modifications.push("type");
|
|
210
|
+
if (prev.nullable !== curr.nullable) modifications.push("nullable");
|
|
211
|
+
if (prev.unique !== curr.unique) modifications.push("unique");
|
|
212
|
+
if (JSON.stringify(prev.default) !== JSON.stringify(curr.default)) modifications.push("default");
|
|
213
|
+
if (prev.length !== curr.length) modifications.push("length");
|
|
214
|
+
if (prev.unsigned !== curr.unsigned) modifications.push("unsigned");
|
|
215
|
+
if (prev.precision !== curr.precision) modifications.push("precision");
|
|
216
|
+
if (prev.scale !== curr.scale) modifications.push("scale");
|
|
217
|
+
if (JSON.stringify(prev.enum) !== JSON.stringify(curr.enum)) modifications.push("enum");
|
|
218
|
+
if (prev.relation !== curr.relation) modifications.push("relation");
|
|
219
|
+
if (prev.target !== curr.target) modifications.push("target");
|
|
220
|
+
if (prev.onDelete !== curr.onDelete) modifications.push("onDelete");
|
|
221
|
+
if (prev.onUpdate !== curr.onUpdate) modifications.push("onUpdate");
|
|
222
|
+
if (prev.mappedBy !== curr.mappedBy) modifications.push("mappedBy");
|
|
223
|
+
return modifications;
|
|
224
|
+
}
|
|
225
|
+
function diffIndexes(prev, curr) {
|
|
226
|
+
const changes = [];
|
|
227
|
+
const prevIndexes = prev ?? [];
|
|
228
|
+
const currIndexes = curr ?? [];
|
|
229
|
+
const indexKey = (idx) => `${idx.columns.join(",")}:${idx.unique}`;
|
|
230
|
+
const prevKeys = new Map(prevIndexes.map((idx) => [indexKey(idx), idx]));
|
|
231
|
+
const currKeys = new Map(currIndexes.map((idx) => [indexKey(idx), idx]));
|
|
232
|
+
for (const [key, idx] of currKeys) {
|
|
233
|
+
if (!prevKeys.has(key)) {
|
|
234
|
+
changes.push({ changeType: "added", index: idx });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
for (const [key, idx] of prevKeys) {
|
|
238
|
+
if (!currKeys.has(key)) {
|
|
239
|
+
changes.push({ changeType: "removed", index: idx });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return changes;
|
|
243
|
+
}
|
|
244
|
+
function diffSchemaSnapshots(prev, curr) {
|
|
245
|
+
const columnChanges = [];
|
|
246
|
+
const prevProps = prev.properties;
|
|
247
|
+
const currProps = curr.properties;
|
|
248
|
+
const prevNames = new Set(Object.keys(prevProps));
|
|
249
|
+
const currNames = new Set(Object.keys(currProps));
|
|
250
|
+
const renamedNewNames = /* @__PURE__ */ new Set();
|
|
251
|
+
const renamedOldNames = /* @__PURE__ */ new Set();
|
|
252
|
+
for (const [name, currProp] of Object.entries(currProps)) {
|
|
253
|
+
if (currProp.renamedFrom && prevProps[currProp.renamedFrom]) {
|
|
254
|
+
const prevProp = prevProps[currProp.renamedFrom];
|
|
255
|
+
const mods = diffPropertySnapshots(prevProp, currProp);
|
|
256
|
+
const filteredMods = mods.filter((m) => m !== "renamedFrom");
|
|
257
|
+
columnChanges.push({
|
|
258
|
+
column: name,
|
|
259
|
+
changeType: "renamed",
|
|
260
|
+
previousColumn: currProp.renamedFrom,
|
|
261
|
+
previousDef: prevProp,
|
|
262
|
+
currentDef: currProp,
|
|
263
|
+
modifications: filteredMods.length > 0 ? filteredMods : void 0
|
|
264
|
+
});
|
|
265
|
+
renamedNewNames.add(name);
|
|
266
|
+
renamedOldNames.add(currProp.renamedFrom);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
for (const name of currNames) {
|
|
270
|
+
if (!prevNames.has(name) && !renamedNewNames.has(name)) {
|
|
271
|
+
columnChanges.push({
|
|
272
|
+
column: name,
|
|
273
|
+
changeType: "added",
|
|
274
|
+
currentDef: currProps[name]
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
for (const name of prevNames) {
|
|
279
|
+
if (!currNames.has(name) && !renamedOldNames.has(name)) {
|
|
280
|
+
columnChanges.push({
|
|
281
|
+
column: name,
|
|
282
|
+
changeType: "removed",
|
|
283
|
+
previousDef: prevProps[name]
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
for (const name of currNames) {
|
|
288
|
+
if (prevNames.has(name) && !renamedNewNames.has(name)) {
|
|
289
|
+
const prevProp = prevProps[name];
|
|
290
|
+
const currProp = currProps[name];
|
|
291
|
+
const mods = diffPropertySnapshots(prevProp, currProp);
|
|
292
|
+
if (mods.length > 0) {
|
|
293
|
+
columnChanges.push({
|
|
294
|
+
column: name,
|
|
295
|
+
changeType: "modified",
|
|
296
|
+
previousDef: prevProp,
|
|
297
|
+
currentDef: currProp,
|
|
298
|
+
modifications: mods
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const indexChanges = diffIndexes(prev.indexes, curr.indexes);
|
|
304
|
+
const optionChanges = {};
|
|
305
|
+
let hasOptionChanges = false;
|
|
306
|
+
if (prev.timestamps !== curr.timestamps) {
|
|
307
|
+
optionChanges.timestamps = { from: prev.timestamps, to: curr.timestamps };
|
|
308
|
+
hasOptionChanges = true;
|
|
309
|
+
}
|
|
310
|
+
if (prev.softDelete !== curr.softDelete) {
|
|
311
|
+
optionChanges.softDelete = { from: prev.softDelete, to: curr.softDelete };
|
|
312
|
+
hasOptionChanges = true;
|
|
313
|
+
}
|
|
314
|
+
if (prev.primaryKeyType !== curr.primaryKeyType) {
|
|
315
|
+
optionChanges.primaryKeyType = { from: prev.primaryKeyType, to: curr.primaryKeyType };
|
|
316
|
+
hasOptionChanges = true;
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
columnChanges: columnChanges.length > 0 ? columnChanges : void 0,
|
|
320
|
+
indexChanges: indexChanges.length > 0 ? indexChanges : void 0,
|
|
321
|
+
optionChanges: hasOptionChanges ? optionChanges : void 0
|
|
322
|
+
};
|
|
323
|
+
}
|
|
124
324
|
function compareSchemas(currentHashes, lockFile) {
|
|
125
325
|
const changes = [];
|
|
126
326
|
const unchanged = [];
|
|
@@ -175,11 +375,95 @@ function compareSchemas(currentHashes, lockFile) {
|
|
|
175
375
|
unchanged
|
|
176
376
|
};
|
|
177
377
|
}
|
|
178
|
-
function
|
|
378
|
+
function compareSchemasDeep(currentSnapshots, lockFile) {
|
|
379
|
+
const changes = [];
|
|
380
|
+
const unchanged = [];
|
|
381
|
+
const previousSnapshots = lockFile?.schemas ?? {};
|
|
382
|
+
const previousNames = new Set(Object.keys(previousSnapshots));
|
|
383
|
+
const currentNames = new Set(Object.keys(currentSnapshots));
|
|
384
|
+
for (const name of currentNames) {
|
|
385
|
+
if (!previousNames.has(name)) {
|
|
386
|
+
const current = currentSnapshots[name];
|
|
387
|
+
if (current) {
|
|
388
|
+
changes.push({
|
|
389
|
+
schemaName: name,
|
|
390
|
+
changeType: "added",
|
|
391
|
+
currentHash: current.hash
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
for (const name of previousNames) {
|
|
397
|
+
if (!currentNames.has(name)) {
|
|
398
|
+
const previous = previousSnapshots[name];
|
|
399
|
+
if (previous) {
|
|
400
|
+
changes.push({
|
|
401
|
+
schemaName: name,
|
|
402
|
+
changeType: "removed",
|
|
403
|
+
previousHash: previous.hash
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
for (const name of currentNames) {
|
|
409
|
+
if (previousNames.has(name)) {
|
|
410
|
+
const current = currentSnapshots[name];
|
|
411
|
+
const previous = previousSnapshots[name];
|
|
412
|
+
if (current.hash !== previous.hash) {
|
|
413
|
+
const diff = diffSchemaSnapshots(previous, current);
|
|
414
|
+
changes.push({
|
|
415
|
+
schemaName: name,
|
|
416
|
+
changeType: "modified",
|
|
417
|
+
previousHash: previous.hash,
|
|
418
|
+
currentHash: current.hash,
|
|
419
|
+
...diff
|
|
420
|
+
});
|
|
421
|
+
} else {
|
|
422
|
+
unchanged.push(name);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
hasChanges: changes.length > 0,
|
|
428
|
+
changes,
|
|
429
|
+
unchanged
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function stripTransientInfo(snapshots) {
|
|
433
|
+
const result = {};
|
|
434
|
+
for (const [schemaName, snapshot] of Object.entries(snapshots)) {
|
|
435
|
+
if (!snapshot.properties) {
|
|
436
|
+
result[schemaName] = snapshot;
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
const cleanProperties = {};
|
|
440
|
+
for (const [propName, prop] of Object.entries(snapshot.properties)) {
|
|
441
|
+
const { renamedFrom, ...rest } = prop;
|
|
442
|
+
cleanProperties[propName] = rest;
|
|
443
|
+
}
|
|
444
|
+
result[schemaName] = {
|
|
445
|
+
...snapshot,
|
|
446
|
+
properties: cleanProperties
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
return result;
|
|
450
|
+
}
|
|
451
|
+
function updateLockFile(existingLockFile, currentSnapshots, driver) {
|
|
452
|
+
const cleanSnapshots = stripTransientInfo(currentSnapshots);
|
|
179
453
|
return {
|
|
180
454
|
version: LOCK_FILE_VERSION,
|
|
181
455
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
182
456
|
driver,
|
|
457
|
+
schemas: cleanSnapshots,
|
|
458
|
+
migrations: existingLockFile?.migrations ?? [],
|
|
459
|
+
hclChecksum: existingLockFile?.hclChecksum
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function updateLockFileV1(existingLockFile, currentHashes, driver) {
|
|
463
|
+
return {
|
|
464
|
+
version: 1,
|
|
465
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
466
|
+
driver,
|
|
183
467
|
schemas: currentHashes,
|
|
184
468
|
migrations: existingLockFile?.migrations ?? [],
|
|
185
469
|
hclChecksum: existingLockFile?.hclChecksum
|
|
@@ -1360,8 +1644,10 @@ function hasBlockingIssues(_preview) {
|
|
|
1360
1644
|
addMigrationRecord,
|
|
1361
1645
|
applySchema,
|
|
1362
1646
|
buildSchemaHashes,
|
|
1647
|
+
buildSchemaSnapshots,
|
|
1363
1648
|
checkAtlasVersion,
|
|
1364
1649
|
compareSchemas,
|
|
1650
|
+
compareSchemasDeep,
|
|
1365
1651
|
computeHash,
|
|
1366
1652
|
computeSchemaHash,
|
|
1367
1653
|
createEmptyLockFile,
|
|
@@ -1374,15 +1660,19 @@ function hasBlockingIssues(_preview) {
|
|
|
1374
1660
|
getPrimaryKeyType,
|
|
1375
1661
|
getTimestampType,
|
|
1376
1662
|
hasBlockingIssues,
|
|
1663
|
+
isLockFileV2,
|
|
1377
1664
|
mapPropertyToSql,
|
|
1378
1665
|
parseDiffOutput,
|
|
1379
1666
|
previewSchemaChanges,
|
|
1380
1667
|
propertyNameToColumnName,
|
|
1668
|
+
propertyToSnapshot,
|
|
1381
1669
|
readLockFile,
|
|
1382
1670
|
renderHcl,
|
|
1383
1671
|
runAtlasDiff,
|
|
1384
1672
|
schemaNameToTableName,
|
|
1673
|
+
schemaToSnapshot,
|
|
1385
1674
|
updateLockFile,
|
|
1675
|
+
updateLockFileV1,
|
|
1386
1676
|
validateHcl,
|
|
1387
1677
|
writeLockFile
|
|
1388
1678
|
});
|