relq 1.0.2 → 1.0.4
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/cjs/cli/commands/add.cjs +403 -27
- package/dist/cjs/cli/commands/branch.cjs +13 -23
- package/dist/cjs/cli/commands/checkout.cjs +16 -29
- package/dist/cjs/cli/commands/cherry-pick.cjs +3 -4
- package/dist/cjs/cli/commands/commit.cjs +21 -29
- package/dist/cjs/cli/commands/diff.cjs +28 -32
- package/dist/cjs/cli/commands/export.cjs +7 -7
- package/dist/cjs/cli/commands/fetch.cjs +15 -21
- package/dist/cjs/cli/commands/generate.cjs +28 -54
- package/dist/cjs/cli/commands/history.cjs +19 -40
- package/dist/cjs/cli/commands/import.cjs +34 -41
- package/dist/cjs/cli/commands/init.cjs +69 -59
- package/dist/cjs/cli/commands/introspect.cjs +4 -8
- package/dist/cjs/cli/commands/log.cjs +26 -32
- package/dist/cjs/cli/commands/merge.cjs +24 -41
- package/dist/cjs/cli/commands/migrate.cjs +12 -25
- package/dist/cjs/cli/commands/pull.cjs +216 -106
- package/dist/cjs/cli/commands/push.cjs +35 -75
- package/dist/cjs/cli/commands/remote.cjs +2 -1
- package/dist/cjs/cli/commands/reset.cjs +22 -43
- package/dist/cjs/cli/commands/resolve.cjs +12 -14
- package/dist/cjs/cli/commands/rollback.cjs +16 -38
- package/dist/cjs/cli/commands/stash.cjs +5 -7
- package/dist/cjs/cli/commands/status.cjs +5 -10
- package/dist/cjs/cli/commands/sync.cjs +30 -50
- package/dist/cjs/cli/commands/tag.cjs +3 -4
- package/dist/cjs/cli/index.cjs +72 -9
- package/dist/cjs/cli/utils/change-tracker.cjs +107 -3
- package/dist/cjs/cli/utils/cli-utils.cjs +217 -0
- package/dist/cjs/cli/utils/config-loader.cjs +34 -8
- package/dist/cjs/cli/utils/fast-introspect.cjs +109 -3
- package/dist/cjs/cli/utils/git-utils.cjs +42 -161
- package/dist/cjs/cli/utils/pool-manager.cjs +156 -0
- package/dist/cjs/cli/utils/project-root.cjs +56 -5
- package/dist/cjs/cli/utils/relqignore.cjs +1 -0
- package/dist/cjs/cli/utils/repo-manager.cjs +47 -0
- package/dist/cjs/cli/utils/schema-comparator.cjs +301 -11
- package/dist/cjs/cli/utils/schema-diff.cjs +202 -1
- package/dist/cjs/cli/utils/schema-hash.cjs +2 -1
- package/dist/cjs/cli/utils/schema-introspect.cjs +7 -3
- package/dist/cjs/cli/utils/snapshot-manager.cjs +1 -0
- package/dist/cjs/cli/utils/spinner.cjs +14 -106
- package/dist/cjs/cli/utils/sql-generator.cjs +10 -2
- package/dist/cjs/cli/utils/type-generator.cjs +28 -16
- package/dist/config.d.ts +16 -6
- package/dist/esm/cli/commands/add.js +372 -29
- package/dist/esm/cli/commands/branch.js +14 -24
- package/dist/esm/cli/commands/checkout.js +16 -29
- package/dist/esm/cli/commands/cherry-pick.js +3 -4
- package/dist/esm/cli/commands/commit.js +22 -30
- package/dist/esm/cli/commands/diff.js +6 -10
- package/dist/esm/cli/commands/export.js +8 -8
- package/dist/esm/cli/commands/fetch.js +14 -20
- package/dist/esm/cli/commands/generate.js +28 -54
- package/dist/esm/cli/commands/history.js +11 -32
- package/dist/esm/cli/commands/import.js +35 -42
- package/dist/esm/cli/commands/init.js +65 -55
- package/dist/esm/cli/commands/introspect.js +4 -8
- package/dist/esm/cli/commands/log.js +6 -12
- package/dist/esm/cli/commands/merge.js +20 -37
- package/dist/esm/cli/commands/migrate.js +12 -25
- package/dist/esm/cli/commands/pull.js +204 -94
- package/dist/esm/cli/commands/push.js +21 -61
- package/dist/esm/cli/commands/remote.js +2 -1
- package/dist/esm/cli/commands/reset.js +16 -37
- package/dist/esm/cli/commands/resolve.js +13 -15
- package/dist/esm/cli/commands/rollback.js +16 -38
- package/dist/esm/cli/commands/stash.js +6 -8
- package/dist/esm/cli/commands/status.js +6 -11
- package/dist/esm/cli/commands/sync.js +30 -50
- package/dist/esm/cli/commands/tag.js +3 -4
- package/dist/esm/cli/index.js +72 -9
- package/dist/esm/cli/utils/change-tracker.js +107 -3
- package/dist/esm/cli/utils/cli-utils.js +169 -0
- package/dist/esm/cli/utils/config-loader.js +34 -8
- package/dist/esm/cli/utils/fast-introspect.js +109 -3
- package/dist/esm/cli/utils/git-utils.js +2 -124
- package/dist/esm/cli/utils/pool-manager.js +114 -0
- package/dist/esm/cli/utils/project-root.js +55 -5
- package/dist/esm/cli/utils/relqignore.js +1 -0
- package/dist/esm/cli/utils/repo-manager.js +42 -0
- package/dist/esm/cli/utils/schema-comparator.js +301 -11
- package/dist/esm/cli/utils/schema-diff.js +202 -1
- package/dist/esm/cli/utils/schema-hash.js +2 -1
- package/dist/esm/cli/utils/schema-introspect.js +7 -3
- package/dist/esm/cli/utils/snapshot-manager.js +1 -0
- package/dist/esm/cli/utils/spinner.js +1 -101
- package/dist/esm/cli/utils/sql-generator.js +10 -2
- package/dist/esm/cli/utils/type-generator.js +28 -16
- package/dist/index.d.ts +25 -8
- package/dist/schema-builder.d.ts +18 -7
- package/package.json +1 -1
|
@@ -6,16 +6,20 @@ exports.compareEnums = compareEnums;
|
|
|
6
6
|
exports.compareDomains = compareDomains;
|
|
7
7
|
exports.compareTables = compareTables;
|
|
8
8
|
const change_tracker_1 = require("./change-tracker.cjs");
|
|
9
|
+
function arraysEqual(a, b) {
|
|
10
|
+
if (a.length !== b.length)
|
|
11
|
+
return false;
|
|
12
|
+
return a.every((val, idx) => val === b[idx]);
|
|
13
|
+
}
|
|
9
14
|
function compareSchemas(before, after) {
|
|
10
15
|
const changes = [];
|
|
11
16
|
changes.push(...compareExtensions(before.extensions || [], after.extensions || []));
|
|
12
17
|
changes.push(...compareEnums(before.enums || [], after.enums || []));
|
|
13
18
|
changes.push(...compareDomains(before.domains || [], after.domains || []));
|
|
14
19
|
changes.push(...compareCompositeTypes(before.compositeTypes || [], after.compositeTypes || []));
|
|
20
|
+
changes.push(...compareSequences(before.sequences || [], after.sequences || []));
|
|
15
21
|
changes.push(...compareTables(before.tables, after.tables));
|
|
16
|
-
|
|
17
|
-
const afterViews = after.views || [];
|
|
18
|
-
changes.push(...compareViews(beforeViews, afterViews));
|
|
22
|
+
changes.push(...compareViews(before.views || [], after.views || []));
|
|
19
23
|
changes.push(...compareFunctions(before.functions || [], after.functions || []));
|
|
20
24
|
changes.push(...compareTriggers(before.triggers || [], after.triggers || []));
|
|
21
25
|
return changes;
|
|
@@ -105,6 +109,38 @@ function compareCompositeTypes(before, after) {
|
|
|
105
109
|
}
|
|
106
110
|
return changes;
|
|
107
111
|
}
|
|
112
|
+
function compareSequences(before, after) {
|
|
113
|
+
const changes = [];
|
|
114
|
+
const beforeMap = new Map(before.map(s => [s.name, s]));
|
|
115
|
+
const afterMap = new Map(after.map(s => [s.name, s]));
|
|
116
|
+
for (const [name, seq] of afterMap) {
|
|
117
|
+
if (!beforeMap.has(name)) {
|
|
118
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'SEQUENCE', name, null, seq));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const beforeSeq = beforeMap.get(name);
|
|
122
|
+
if (hasSequenceChanged(beforeSeq, seq)) {
|
|
123
|
+
changes.push((0, change_tracker_1.createChange)('ALTER', 'SEQUENCE', name, beforeSeq, seq));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const [name, seq] of beforeMap) {
|
|
128
|
+
if (!afterMap.has(name)) {
|
|
129
|
+
changes.push((0, change_tracker_1.createChange)('DROP', 'SEQUENCE', name, seq, null));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return changes;
|
|
133
|
+
}
|
|
134
|
+
function hasSequenceChanged(before, after) {
|
|
135
|
+
return (before.dataType !== after.dataType ||
|
|
136
|
+
before.start !== after.start ||
|
|
137
|
+
before.increment !== after.increment ||
|
|
138
|
+
before.minValue !== after.minValue ||
|
|
139
|
+
before.maxValue !== after.maxValue ||
|
|
140
|
+
before.cache !== after.cache ||
|
|
141
|
+
before.cycle !== after.cycle ||
|
|
142
|
+
before.ownedBy !== after.ownedBy);
|
|
143
|
+
}
|
|
108
144
|
function compareTables(before, after) {
|
|
109
145
|
const changes = [];
|
|
110
146
|
const beforeMap = new Map(before.map(t => [t.name, t]));
|
|
@@ -112,12 +148,57 @@ function compareTables(before, after) {
|
|
|
112
148
|
for (const [name, table] of afterMap) {
|
|
113
149
|
if (!beforeMap.has(name)) {
|
|
114
150
|
changes.push((0, change_tracker_1.createChange)('CREATE', 'TABLE', name, null, tableToChangeData(table)));
|
|
151
|
+
const tableIndexes = table.indexes || [];
|
|
152
|
+
for (const idx of tableIndexes) {
|
|
153
|
+
if (!idx.isPrimary) {
|
|
154
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'INDEX', idx.name, null, {
|
|
155
|
+
name: idx.name,
|
|
156
|
+
tableName: name,
|
|
157
|
+
columns: Array.isArray(idx.columns) ? idx.columns : [idx.columns],
|
|
158
|
+
isUnique: idx.isUnique,
|
|
159
|
+
type: idx.type,
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (table.isPartitioned && table.partitionType && table.partitionKey) {
|
|
164
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'PARTITION', name, null, {
|
|
165
|
+
tableName: name,
|
|
166
|
+
type: table.partitionType,
|
|
167
|
+
key: table.partitionKey,
|
|
168
|
+
}));
|
|
169
|
+
const childPartitions = table.childPartitions || [];
|
|
170
|
+
for (const cp of childPartitions) {
|
|
171
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'PARTITION_CHILD', cp.name, null, {
|
|
172
|
+
name: cp.name,
|
|
173
|
+
parentTable: name,
|
|
174
|
+
bound: cp.partitionBound,
|
|
175
|
+
}, name));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (table.comment) {
|
|
179
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'TABLE_COMMENT', name, null, {
|
|
180
|
+
tableName: name,
|
|
181
|
+
comment: table.comment,
|
|
182
|
+
}, name));
|
|
183
|
+
}
|
|
184
|
+
for (const col of table.columns) {
|
|
185
|
+
if (col.comment) {
|
|
186
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'COLUMN_COMMENT', col.name, null, {
|
|
187
|
+
tableName: name,
|
|
188
|
+
columnName: col.name,
|
|
189
|
+
comment: col.comment,
|
|
190
|
+
}, name));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
115
193
|
}
|
|
116
194
|
else {
|
|
117
195
|
const beforeTable = beforeMap.get(name);
|
|
118
196
|
changes.push(...compareColumns(beforeTable.columns, table.columns, name));
|
|
119
197
|
changes.push(...compareIndexes(beforeTable.indexes || [], table.indexes || [], name));
|
|
120
198
|
changes.push(...compareConstraints(beforeTable.constraints || [], table.constraints || [], name));
|
|
199
|
+
changes.push(...compareTableComments(beforeTable, table, name));
|
|
200
|
+
changes.push(...compareColumnComments(beforeTable.columns, table.columns, name));
|
|
201
|
+
changes.push(...comparePartitions(beforeTable, table, name));
|
|
121
202
|
}
|
|
122
203
|
}
|
|
123
204
|
for (const [name, table] of beforeMap) {
|
|
@@ -183,10 +264,65 @@ function columnToChangeData(col) {
|
|
|
183
264
|
scale: col.scale,
|
|
184
265
|
};
|
|
185
266
|
}
|
|
267
|
+
function normalizeDataType(type) {
|
|
268
|
+
if (!type)
|
|
269
|
+
return '';
|
|
270
|
+
let normalized = type.toLowerCase().trim();
|
|
271
|
+
const typeMap = {
|
|
272
|
+
'int4': 'integer',
|
|
273
|
+
'int8': 'bigint',
|
|
274
|
+
'int2': 'smallint',
|
|
275
|
+
'float4': 'real',
|
|
276
|
+
'float8': 'double precision',
|
|
277
|
+
'bool': 'boolean',
|
|
278
|
+
'timestamptz': 'timestamp',
|
|
279
|
+
'timetz': 'time',
|
|
280
|
+
'_text': 'text[]',
|
|
281
|
+
'_int4': 'integer[]',
|
|
282
|
+
'_int8': 'bigint[]',
|
|
283
|
+
'_varchar': 'varchar[]',
|
|
284
|
+
'_uuid': 'uuid[]',
|
|
285
|
+
'_bool': 'boolean[]',
|
|
286
|
+
'_jsonb': 'jsonb[]',
|
|
287
|
+
'character varying': 'varchar',
|
|
288
|
+
'character': 'char',
|
|
289
|
+
'double precision': 'doubleprecision',
|
|
290
|
+
};
|
|
291
|
+
if (normalized.startsWith('_') && !typeMap[normalized]) {
|
|
292
|
+
return normalized.substring(1) + '[]';
|
|
293
|
+
}
|
|
294
|
+
return typeMap[normalized] || normalized;
|
|
295
|
+
}
|
|
296
|
+
function normalizeDefault(value) {
|
|
297
|
+
if (value == null)
|
|
298
|
+
return null;
|
|
299
|
+
let normalized = value.trim().toLowerCase();
|
|
300
|
+
normalized = normalized.replace(/array\[\]::([\w\[\]]+)/gi, "'empty_array'");
|
|
301
|
+
normalized = normalized.replace(/::\w+(?:\s+\w+)?(?:\[\])?/g, '');
|
|
302
|
+
normalized = normalized.replace(/^array\[\]$/i, "'empty_array'");
|
|
303
|
+
normalized = normalized.replace(/now\s*\(\s*\)/g, 'now()');
|
|
304
|
+
normalized = normalized.replace(/gen_random_uuid\s*\(\s*\)/g, 'gen_random_uuid()');
|
|
305
|
+
normalized = normalized.replace(/current_date/g, 'current_date');
|
|
306
|
+
normalized = normalized.replace(/current_timestamp/g, 'current_timestamp');
|
|
307
|
+
normalized = normalized.replace(/'\[\]'/g, "'empty_array'");
|
|
308
|
+
normalized = normalized.replace(/'\{\}'/g, "'empty_array'");
|
|
309
|
+
normalized = normalized.replace(/:\s+/g, ':');
|
|
310
|
+
normalized = normalized.replace(/,\s+/g, ',');
|
|
311
|
+
normalized = normalized.replace(/\[\s+/g, '[');
|
|
312
|
+
normalized = normalized.replace(/\s+\]/g, ']');
|
|
313
|
+
normalized = normalized.replace(/\{\s+/g, '{');
|
|
314
|
+
normalized = normalized.replace(/\s+\}/g, '}');
|
|
315
|
+
if (normalized === 'true' || normalized === "'t'" || normalized === 't')
|
|
316
|
+
normalized = 'true';
|
|
317
|
+
if (normalized === 'false' || normalized === "'f'" || normalized === 'f')
|
|
318
|
+
normalized = 'false';
|
|
319
|
+
normalized = normalized.replace(/^'([^']*)'$/, '$1');
|
|
320
|
+
return normalized || null;
|
|
321
|
+
}
|
|
186
322
|
function hasColumnChanged(before, after) {
|
|
187
|
-
return (before.dataType
|
|
323
|
+
return (normalizeDataType(before.dataType) !== normalizeDataType(after.dataType) ||
|
|
188
324
|
before.isNullable !== after.isNullable ||
|
|
189
|
-
before.defaultValue !== after.defaultValue ||
|
|
325
|
+
normalizeDefault(before.defaultValue) !== normalizeDefault(after.defaultValue) ||
|
|
190
326
|
before.isPrimaryKey !== after.isPrimaryKey ||
|
|
191
327
|
before.isUnique !== after.isUnique);
|
|
192
328
|
}
|
|
@@ -218,10 +354,14 @@ function compareIndexes(before, after, tableName) {
|
|
|
218
354
|
}
|
|
219
355
|
function compareConstraints(before, after, tableName) {
|
|
220
356
|
const changes = [];
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
357
|
+
const beforeChecks = before.filter(c => c.type?.toUpperCase() === 'CHECK');
|
|
358
|
+
const afterChecks = after.filter(c => c.type?.toUpperCase() === 'CHECK');
|
|
359
|
+
const beforeOther = before.filter(c => c.type?.toUpperCase() !== 'CHECK');
|
|
360
|
+
const afterOther = after.filter(c => c.type?.toUpperCase() !== 'CHECK');
|
|
361
|
+
const beforeOtherMap = new Map(beforeOther.map(c => [c.name, c]));
|
|
362
|
+
const afterOtherMap = new Map(afterOther.map(c => [c.name, c]));
|
|
363
|
+
for (const [name, con] of afterOtherMap) {
|
|
364
|
+
if (!beforeOtherMap.has(name)) {
|
|
225
365
|
const objectType = constraintTypeToObjectType(con.type);
|
|
226
366
|
changes.push((0, change_tracker_1.createChange)('CREATE', objectType, name, null, {
|
|
227
367
|
name: con.name,
|
|
@@ -229,8 +369,8 @@ function compareConstraints(before, after, tableName) {
|
|
|
229
369
|
}, tableName));
|
|
230
370
|
}
|
|
231
371
|
}
|
|
232
|
-
for (const [name, con] of
|
|
233
|
-
if (!
|
|
372
|
+
for (const [name, con] of beforeOtherMap) {
|
|
373
|
+
if (!afterOtherMap.has(name)) {
|
|
234
374
|
const objectType = constraintTypeToObjectType(con.type);
|
|
235
375
|
changes.push((0, change_tracker_1.createChange)('DROP', objectType, name, {
|
|
236
376
|
name: con.name,
|
|
@@ -238,6 +378,59 @@ function compareConstraints(before, after, tableName) {
|
|
|
238
378
|
}, null, tableName));
|
|
239
379
|
}
|
|
240
380
|
}
|
|
381
|
+
const extractColumnFromCheckDef = (definition) => {
|
|
382
|
+
const enumMatch = definition.match(/\((\w+)\)::text\s*=\s*ANY/i);
|
|
383
|
+
if (enumMatch)
|
|
384
|
+
return enumMatch[1].toLowerCase();
|
|
385
|
+
const compMatch = definition.match(/\(\(?(\w+)\s*(?:>=?|<=?|<>|!=|=)/i);
|
|
386
|
+
if (compMatch)
|
|
387
|
+
return compMatch[1].toLowerCase();
|
|
388
|
+
return null;
|
|
389
|
+
};
|
|
390
|
+
const extractColumnFromCheckName = (name, tableName) => {
|
|
391
|
+
const lower = name.toLowerCase();
|
|
392
|
+
const tablePrefix = tableName.toLowerCase() + '_';
|
|
393
|
+
let colPart = lower.startsWith(tablePrefix) ? lower.slice(tablePrefix.length) : lower;
|
|
394
|
+
if (colPart.startsWith('check_'))
|
|
395
|
+
colPart = colPart.slice(6);
|
|
396
|
+
if (colPart.endsWith('_check'))
|
|
397
|
+
colPart = colPart.slice(0, -6);
|
|
398
|
+
return colPart;
|
|
399
|
+
};
|
|
400
|
+
const beforeChecksByCol = new Map();
|
|
401
|
+
const afterChecksByCol = new Map();
|
|
402
|
+
for (const c of beforeChecks) {
|
|
403
|
+
const col = extractColumnFromCheckDef(c.definition) || extractColumnFromCheckName(c.name, tableName);
|
|
404
|
+
beforeChecksByCol.set(col, c);
|
|
405
|
+
}
|
|
406
|
+
for (const c of afterChecks) {
|
|
407
|
+
const col = extractColumnFromCheckDef(c.definition) || extractColumnFromCheckName(c.name, tableName);
|
|
408
|
+
afterChecksByCol.set(col, c);
|
|
409
|
+
}
|
|
410
|
+
const matchedBefore = new Set();
|
|
411
|
+
const matchedAfter = new Set();
|
|
412
|
+
for (const [col, afterCon] of afterChecksByCol) {
|
|
413
|
+
if (beforeChecksByCol.has(col)) {
|
|
414
|
+
matchedBefore.add(beforeChecksByCol.get(col).name);
|
|
415
|
+
matchedAfter.add(afterCon.name);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
for (const c of afterChecks) {
|
|
419
|
+
if (!matchedAfter.has(c.name)) {
|
|
420
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'CHECK', c.name, null, {
|
|
421
|
+
name: c.name,
|
|
422
|
+
definition: c.definition,
|
|
423
|
+
}, tableName));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
for (const c of beforeChecks) {
|
|
427
|
+
if (!matchedBefore.has(c.name)) {
|
|
428
|
+
changes.push((0, change_tracker_1.createChange)('DROP', 'CHECK', c.name, {
|
|
429
|
+
name: c.name,
|
|
430
|
+
definition: c.definition,
|
|
431
|
+
}, null, tableName));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
241
434
|
return changes;
|
|
242
435
|
}
|
|
243
436
|
function constraintTypeToObjectType(type) {
|
|
@@ -252,6 +445,103 @@ function constraintTypeToObjectType(type) {
|
|
|
252
445
|
return 'EXCLUSION';
|
|
253
446
|
return 'CONSTRAINT';
|
|
254
447
|
}
|
|
448
|
+
function compareTableComments(before, after, tableName) {
|
|
449
|
+
const changes = [];
|
|
450
|
+
const beforeComment = before.comment;
|
|
451
|
+
const afterComment = after.comment;
|
|
452
|
+
if (afterComment && !beforeComment) {
|
|
453
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'TABLE_COMMENT', tableName, null, {
|
|
454
|
+
tableName,
|
|
455
|
+
comment: afterComment,
|
|
456
|
+
}, tableName));
|
|
457
|
+
}
|
|
458
|
+
else if (!afterComment && beforeComment) {
|
|
459
|
+
changes.push((0, change_tracker_1.createChange)('DROP', 'TABLE_COMMENT', tableName, {
|
|
460
|
+
tableName,
|
|
461
|
+
comment: beforeComment,
|
|
462
|
+
}, null, tableName));
|
|
463
|
+
}
|
|
464
|
+
else if (afterComment && beforeComment && afterComment !== beforeComment) {
|
|
465
|
+
changes.push((0, change_tracker_1.createChange)('ALTER', 'TABLE_COMMENT', tableName, {
|
|
466
|
+
tableName,
|
|
467
|
+
comment: beforeComment,
|
|
468
|
+
}, {
|
|
469
|
+
tableName,
|
|
470
|
+
comment: afterComment,
|
|
471
|
+
}, tableName));
|
|
472
|
+
}
|
|
473
|
+
return changes;
|
|
474
|
+
}
|
|
475
|
+
function compareColumnComments(before, after, tableName) {
|
|
476
|
+
const changes = [];
|
|
477
|
+
const beforeMap = new Map(before.map(c => [c.name, c]));
|
|
478
|
+
const afterMap = new Map(after.map(c => [c.name, c]));
|
|
479
|
+
for (const [name, col] of afterMap) {
|
|
480
|
+
const afterComment = col.comment;
|
|
481
|
+
const beforeCol = beforeMap.get(name);
|
|
482
|
+
const beforeComment = beforeCol ? beforeCol.comment : undefined;
|
|
483
|
+
if (afterComment && !beforeComment) {
|
|
484
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'COLUMN_COMMENT', name, null, {
|
|
485
|
+
tableName,
|
|
486
|
+
columnName: name,
|
|
487
|
+
comment: afterComment,
|
|
488
|
+
}, tableName));
|
|
489
|
+
}
|
|
490
|
+
else if (!afterComment && beforeComment) {
|
|
491
|
+
changes.push((0, change_tracker_1.createChange)('DROP', 'COLUMN_COMMENT', name, {
|
|
492
|
+
tableName,
|
|
493
|
+
columnName: name,
|
|
494
|
+
comment: beforeComment,
|
|
495
|
+
}, null, tableName));
|
|
496
|
+
}
|
|
497
|
+
else if (afterComment && beforeComment && afterComment !== beforeComment) {
|
|
498
|
+
changes.push((0, change_tracker_1.createChange)('ALTER', 'COLUMN_COMMENT', name, {
|
|
499
|
+
tableName,
|
|
500
|
+
columnName: name,
|
|
501
|
+
comment: beforeComment,
|
|
502
|
+
}, {
|
|
503
|
+
tableName,
|
|
504
|
+
columnName: name,
|
|
505
|
+
comment: afterComment,
|
|
506
|
+
}, tableName));
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return changes;
|
|
510
|
+
}
|
|
511
|
+
function comparePartitions(before, after, tableName) {
|
|
512
|
+
const changes = [];
|
|
513
|
+
const beforePartitioned = before.isPartitioned;
|
|
514
|
+
const afterPartitioned = after.isPartitioned;
|
|
515
|
+
if (afterPartitioned && !beforePartitioned) {
|
|
516
|
+
changes.push((0, change_tracker_1.createChange)('CREATE', 'PARTITION', tableName, null, {
|
|
517
|
+
tableName,
|
|
518
|
+
type: after.partitionType,
|
|
519
|
+
key: after.partitionKey,
|
|
520
|
+
}));
|
|
521
|
+
}
|
|
522
|
+
else if (!afterPartitioned && beforePartitioned) {
|
|
523
|
+
changes.push((0, change_tracker_1.createChange)('DROP', 'PARTITION', tableName, {
|
|
524
|
+
tableName,
|
|
525
|
+
type: before.partitionType,
|
|
526
|
+
key: before.partitionKey,
|
|
527
|
+
}, null));
|
|
528
|
+
}
|
|
529
|
+
else if (afterPartitioned && beforePartitioned) {
|
|
530
|
+
const keysMatch = arraysEqual(before.partitionKey || [], after.partitionKey || []);
|
|
531
|
+
if (before.partitionType !== after.partitionType || !keysMatch) {
|
|
532
|
+
changes.push((0, change_tracker_1.createChange)('ALTER', 'PARTITION', tableName, {
|
|
533
|
+
tableName,
|
|
534
|
+
type: before.partitionType,
|
|
535
|
+
key: before.partitionKey,
|
|
536
|
+
}, {
|
|
537
|
+
tableName,
|
|
538
|
+
type: after.partitionType,
|
|
539
|
+
key: after.partitionKey,
|
|
540
|
+
}));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return changes;
|
|
544
|
+
}
|
|
255
545
|
function compareViews(before, after) {
|
|
256
546
|
const changes = [];
|
|
257
547
|
const beforeMap = new Map(before.map(v => [v.name, v]));
|
|
@@ -7,6 +7,205 @@ exports.filterDiff = filterDiff;
|
|
|
7
7
|
exports.hasDestructiveChanges = hasDestructiveChanges;
|
|
8
8
|
exports.getDestructiveTables = getDestructiveTables;
|
|
9
9
|
const spinner_1 = require("./spinner.cjs");
|
|
10
|
+
const TYPE_ALIASES = {
|
|
11
|
+
'int': 'integer',
|
|
12
|
+
'int2': 'smallint',
|
|
13
|
+
'int4': 'integer',
|
|
14
|
+
'int8': 'bigint',
|
|
15
|
+
'integer': 'integer',
|
|
16
|
+
'smallint': 'smallint',
|
|
17
|
+
'bigint': 'bigint',
|
|
18
|
+
'serial': 'serial',
|
|
19
|
+
'serial2': 'smallserial',
|
|
20
|
+
'serial4': 'serial',
|
|
21
|
+
'serial8': 'bigserial',
|
|
22
|
+
'smallserial': 'smallserial',
|
|
23
|
+
'bigserial': 'bigserial',
|
|
24
|
+
'float': 'double precision',
|
|
25
|
+
'float4': 'real',
|
|
26
|
+
'float8': 'double precision',
|
|
27
|
+
'real': 'real',
|
|
28
|
+
'double precision': 'double precision',
|
|
29
|
+
'decimal': 'numeric',
|
|
30
|
+
'numeric': 'numeric',
|
|
31
|
+
'bool': 'boolean',
|
|
32
|
+
'boolean': 'boolean',
|
|
33
|
+
'char': 'character',
|
|
34
|
+
'character': 'character',
|
|
35
|
+
'bpchar': 'character',
|
|
36
|
+
'varchar': 'character varying',
|
|
37
|
+
'character varying': 'character varying',
|
|
38
|
+
'text': 'text',
|
|
39
|
+
'name': 'name',
|
|
40
|
+
'citext': 'citext',
|
|
41
|
+
'timestamp': 'timestamp without time zone',
|
|
42
|
+
'timestamp without time zone': 'timestamp without time zone',
|
|
43
|
+
'timestamptz': 'timestamp with time zone',
|
|
44
|
+
'timestamp with time zone': 'timestamp with time zone',
|
|
45
|
+
'date': 'date',
|
|
46
|
+
'time': 'time without time zone',
|
|
47
|
+
'time without time zone': 'time without time zone',
|
|
48
|
+
'timetz': 'time with time zone',
|
|
49
|
+
'time with time zone': 'time with time zone',
|
|
50
|
+
'interval': 'interval',
|
|
51
|
+
'abstime': 'abstime',
|
|
52
|
+
'reltime': 'reltime',
|
|
53
|
+
'tinterval': 'tinterval',
|
|
54
|
+
'bytea': 'bytea',
|
|
55
|
+
'bit': 'bit',
|
|
56
|
+
'varbit': 'bit varying',
|
|
57
|
+
'bit varying': 'bit varying',
|
|
58
|
+
'uuid': 'uuid',
|
|
59
|
+
'json': 'json',
|
|
60
|
+
'jsonb': 'jsonb',
|
|
61
|
+
'jsonpath': 'jsonpath',
|
|
62
|
+
'xml': 'xml',
|
|
63
|
+
'money': 'money',
|
|
64
|
+
'inet': 'inet',
|
|
65
|
+
'cidr': 'cidr',
|
|
66
|
+
'macaddr': 'macaddr',
|
|
67
|
+
'macaddr8': 'macaddr8',
|
|
68
|
+
'point': 'point',
|
|
69
|
+
'line': 'line',
|
|
70
|
+
'lseg': 'lseg',
|
|
71
|
+
'box': 'box',
|
|
72
|
+
'path': 'path',
|
|
73
|
+
'polygon': 'polygon',
|
|
74
|
+
'circle': 'circle',
|
|
75
|
+
'int4range': 'int4range',
|
|
76
|
+
'int8range': 'int8range',
|
|
77
|
+
'numrange': 'numrange',
|
|
78
|
+
'tsrange': 'tsrange',
|
|
79
|
+
'tstzrange': 'tstzrange',
|
|
80
|
+
'daterange': 'daterange',
|
|
81
|
+
'int4multirange': 'int4multirange',
|
|
82
|
+
'int8multirange': 'int8multirange',
|
|
83
|
+
'nummultirange': 'nummultirange',
|
|
84
|
+
'tsmultirange': 'tsmultirange',
|
|
85
|
+
'tstzmultirange': 'tstzmultirange',
|
|
86
|
+
'datemultirange': 'datemultirange',
|
|
87
|
+
'tsvector': 'tsvector',
|
|
88
|
+
'tsquery': 'tsquery',
|
|
89
|
+
'gtsvector': 'gtsvector',
|
|
90
|
+
'oid': 'oid',
|
|
91
|
+
'regclass': 'regclass',
|
|
92
|
+
'regcollation': 'regcollation',
|
|
93
|
+
'regconfig': 'regconfig',
|
|
94
|
+
'regdictionary': 'regdictionary',
|
|
95
|
+
'regnamespace': 'regnamespace',
|
|
96
|
+
'regoper': 'regoper',
|
|
97
|
+
'regoperator': 'regoperator',
|
|
98
|
+
'regproc': 'regproc',
|
|
99
|
+
'regprocedure': 'regprocedure',
|
|
100
|
+
'regrole': 'regrole',
|
|
101
|
+
'regtype': 'regtype',
|
|
102
|
+
'xid': 'xid',
|
|
103
|
+
'xid8': 'xid8',
|
|
104
|
+
'cid': 'cid',
|
|
105
|
+
'tid': 'tid',
|
|
106
|
+
'aclitem': 'aclitem',
|
|
107
|
+
'smgr': 'smgr',
|
|
108
|
+
'unknown': 'unknown',
|
|
109
|
+
'internal': 'internal',
|
|
110
|
+
'opaque': 'opaque',
|
|
111
|
+
'anyelement': 'anyelement',
|
|
112
|
+
'anyarray': 'anyarray',
|
|
113
|
+
'anynonarray': 'anynonarray',
|
|
114
|
+
'anyenum': 'anyenum',
|
|
115
|
+
'anyrange': 'anyrange',
|
|
116
|
+
'anymultirange': 'anymultirange',
|
|
117
|
+
'anycompatible': 'anycompatible',
|
|
118
|
+
'anycompatiblearray': 'anycompatiblearray',
|
|
119
|
+
'anycompatiblenonarray': 'anycompatiblenonarray',
|
|
120
|
+
'anycompatiblerange': 'anycompatiblerange',
|
|
121
|
+
'anycompatiblemultirange': 'anycompatiblemultirange',
|
|
122
|
+
'cstring': 'cstring',
|
|
123
|
+
'record': 'record',
|
|
124
|
+
'trigger': 'trigger',
|
|
125
|
+
'event_trigger': 'event_trigger',
|
|
126
|
+
'pg_lsn': 'pg_lsn',
|
|
127
|
+
'pg_snapshot': 'pg_snapshot',
|
|
128
|
+
'txid_snapshot': 'txid_snapshot',
|
|
129
|
+
'fdw_handler': 'fdw_handler',
|
|
130
|
+
'index_am_handler': 'index_am_handler',
|
|
131
|
+
'tsm_handler': 'tsm_handler',
|
|
132
|
+
'table_am_handler': 'table_am_handler',
|
|
133
|
+
'language_handler': 'language_handler',
|
|
134
|
+
'void': 'void',
|
|
135
|
+
'refcursor': 'refcursor',
|
|
136
|
+
'_int2': 'smallint[]',
|
|
137
|
+
'_int4': 'integer[]',
|
|
138
|
+
'_int8': 'bigint[]',
|
|
139
|
+
'_float4': 'real[]',
|
|
140
|
+
'_float8': 'double precision[]',
|
|
141
|
+
'_numeric': 'numeric[]',
|
|
142
|
+
'_bool': 'boolean[]',
|
|
143
|
+
'_text': 'text[]',
|
|
144
|
+
'_varchar': 'character varying[]',
|
|
145
|
+
'_bpchar': 'character[]',
|
|
146
|
+
'_char': 'character[]',
|
|
147
|
+
'_name': 'name[]',
|
|
148
|
+
'_bytea': 'bytea[]',
|
|
149
|
+
'_bit': 'bit[]',
|
|
150
|
+
'_varbit': 'bit varying[]',
|
|
151
|
+
'_uuid': 'uuid[]',
|
|
152
|
+
'_json': 'json[]',
|
|
153
|
+
'_jsonb': 'jsonb[]',
|
|
154
|
+
'_xml': 'xml[]',
|
|
155
|
+
'_money': 'money[]',
|
|
156
|
+
'_timestamp': 'timestamp without time zone[]',
|
|
157
|
+
'_timestamptz': 'timestamp with time zone[]',
|
|
158
|
+
'_date': 'date[]',
|
|
159
|
+
'_time': 'time without time zone[]',
|
|
160
|
+
'_timetz': 'time with time zone[]',
|
|
161
|
+
'_interval': 'interval[]',
|
|
162
|
+
'_inet': 'inet[]',
|
|
163
|
+
'_cidr': 'cidr[]',
|
|
164
|
+
'_macaddr': 'macaddr[]',
|
|
165
|
+
'_macaddr8': 'macaddr8[]',
|
|
166
|
+
'_point': 'point[]',
|
|
167
|
+
'_line': 'line[]',
|
|
168
|
+
'_lseg': 'lseg[]',
|
|
169
|
+
'_box': 'box[]',
|
|
170
|
+
'_path': 'path[]',
|
|
171
|
+
'_polygon': 'polygon[]',
|
|
172
|
+
'_circle': 'circle[]',
|
|
173
|
+
'_int4range': 'int4range[]',
|
|
174
|
+
'_int8range': 'int8range[]',
|
|
175
|
+
'_numrange': 'numrange[]',
|
|
176
|
+
'_tsrange': 'tsrange[]',
|
|
177
|
+
'_tstzrange': 'tstzrange[]',
|
|
178
|
+
'_daterange': 'daterange[]',
|
|
179
|
+
'_tsvector': 'tsvector[]',
|
|
180
|
+
'_tsquery': 'tsquery[]',
|
|
181
|
+
'_oid': 'oid[]',
|
|
182
|
+
'_regclass': 'regclass[]',
|
|
183
|
+
'_regtype': 'regtype[]',
|
|
184
|
+
'_regproc': 'regproc[]',
|
|
185
|
+
'_xid': 'xid[]',
|
|
186
|
+
'_cid': 'cid[]',
|
|
187
|
+
'_tid': 'tid[]',
|
|
188
|
+
'_aclitem': 'aclitem[]',
|
|
189
|
+
'_cstring': 'cstring[]',
|
|
190
|
+
'_record': 'record[]',
|
|
191
|
+
'_pg_lsn': 'pg_lsn[]',
|
|
192
|
+
'_txid_snapshot': 'txid_snapshot[]',
|
|
193
|
+
'_refcursor': 'refcursor[]',
|
|
194
|
+
'_citext': 'citext[]',
|
|
195
|
+
};
|
|
196
|
+
function normalizeType(type) {
|
|
197
|
+
if (!type)
|
|
198
|
+
return type;
|
|
199
|
+
let normalized = type.toLowerCase().trim();
|
|
200
|
+
if (TYPE_ALIASES[normalized]) {
|
|
201
|
+
return TYPE_ALIASES[normalized];
|
|
202
|
+
}
|
|
203
|
+
normalized = normalized.replace(' without time zone', '');
|
|
204
|
+
if (TYPE_ALIASES[normalized]) {
|
|
205
|
+
return TYPE_ALIASES[normalized];
|
|
206
|
+
}
|
|
207
|
+
return normalized;
|
|
208
|
+
}
|
|
10
209
|
function diffSchemas(local, remote) {
|
|
11
210
|
const tables = diffTables(local.tables, remote.tables);
|
|
12
211
|
const extensions = diffExtensions(local.extensions, remote.extensions);
|
|
@@ -83,7 +282,9 @@ function diffColumns(local, remote) {
|
|
|
83
282
|
}
|
|
84
283
|
function compareColumns(local, remote) {
|
|
85
284
|
const changes = [];
|
|
86
|
-
|
|
285
|
+
const localType = normalizeType(local.type);
|
|
286
|
+
const remoteType = normalizeType(remote.type);
|
|
287
|
+
if (localType !== remoteType) {
|
|
87
288
|
changes.push({ field: 'type', from: local.type, to: remote.type });
|
|
88
289
|
}
|
|
89
290
|
if (local.nullable !== remote.nullable) {
|
|
@@ -62,8 +62,9 @@ function normalizeTable(table) {
|
|
|
62
62
|
columns,
|
|
63
63
|
indexes,
|
|
64
64
|
constraints,
|
|
65
|
+
isPartitioned: table.isPartitioned,
|
|
65
66
|
partitionType: table.partitionType,
|
|
66
|
-
partitionKey: table.partitionKey
|
|
67
|
+
partitionKey: table.partitionKey ? [...table.partitionKey] : undefined,
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
70
|
function normalizeColumn(col) {
|
|
@@ -68,7 +68,7 @@ async function introspectDatabase(connection, onProgress, options) {
|
|
|
68
68
|
WHERE n.nspname = 'public' AND c.relispartition = true;
|
|
69
69
|
`);
|
|
70
70
|
const partitionTableNames = new Set(partitionNamesResult.rows.map((r) => r.name));
|
|
71
|
-
const nonPartitionTables = tablesResult.rows.filter((r) => !partitionTableNames.has(r.table_name) && !r.table_name.startsWith('_relq'));
|
|
71
|
+
const nonPartitionTables = tablesResult.rows.filter((r) => !partitionTableNames.has(r.table_name) && !r.table_name.startsWith('_relq') && !r.table_name.startsWith('_kuery'));
|
|
72
72
|
const totalTables = nonPartitionTables.length;
|
|
73
73
|
let tableIndex = 0;
|
|
74
74
|
for (let i = 0; i < tablesResult.rows.length; i++) {
|
|
@@ -76,9 +76,12 @@ async function introspectDatabase(connection, onProgress, options) {
|
|
|
76
76
|
const tableName = row.table_name;
|
|
77
77
|
const tableSchema = row.table_schema;
|
|
78
78
|
const rowCount = parseInt(row.row_count) || 0;
|
|
79
|
+
const isInternal = tableName.startsWith('_relq') || tableName.startsWith('_kuery');
|
|
80
|
+
if (isInternal) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
79
83
|
const isPartition = partitionTableNames.has(tableName);
|
|
80
|
-
|
|
81
|
-
if (!isPartition && !isInternal) {
|
|
84
|
+
if (!isPartition) {
|
|
82
85
|
tableIndex++;
|
|
83
86
|
onProgress?.('parsing_table', `${tableName} (${tableIndex}/${totalTables})`);
|
|
84
87
|
}
|
|
@@ -408,6 +411,7 @@ async function introspectDatabase(connection, onProgress, options) {
|
|
|
408
411
|
domains: [],
|
|
409
412
|
compositeTypes: [],
|
|
410
413
|
sequences: [],
|
|
414
|
+
collations: [],
|
|
411
415
|
functions,
|
|
412
416
|
triggers,
|
|
413
417
|
policies,
|