relq 1.0.104 → 1.0.106

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.
@@ -157,6 +157,35 @@ async function runPush(config, projectRoot, opts = {}) {
157
157
  const diff = (0, schema_diff_1.diffSchemas)((0, schema_hash_1.normalizeSchema)(dbSchema), (0, schema_hash_1.normalizeSchema)(desiredSchema));
158
158
  let filteredDiff = (0, schema_diff_1.filterDiff)(diff, ignorePatterns.map(pat => pat.raw));
159
159
  const dbParsedSchema = await (0, ast_transformer_1.introspectedToParsedSchema)(dbSchema);
160
+ const snapshot = (0, snapshot_manager_1.loadSnapshot)(snapshotPath);
161
+ if (snapshot) {
162
+ const snapTables = Object.values(snapshot.tables || {});
163
+ for (const dbTable of dbParsedSchema.tables) {
164
+ const snapTable = snapTables.find(s => s.name === dbTable.name);
165
+ if (!snapTable)
166
+ continue;
167
+ if (snapTable.trackingId)
168
+ dbTable.trackingId = snapTable.trackingId;
169
+ const snapCols = Object.values(snapTable.columns || {});
170
+ for (const dbCol of dbTable.columns) {
171
+ const snapCol = snapCols.find(s => s.name === dbCol.name);
172
+ if (snapCol?.trackingId)
173
+ dbCol.trackingId = snapCol.trackingId;
174
+ }
175
+ const snapIdxs = Object.values(snapTable.indexes || {});
176
+ for (const dbIdx of dbTable.indexes) {
177
+ const snapIdx = snapIdxs.find(s => s.name === dbIdx.name);
178
+ if (snapIdx?.trackingId)
179
+ dbIdx.trackingId = snapIdx.trackingId;
180
+ }
181
+ const snapCons = Object.values(snapTable.constraints || {});
182
+ for (const dbCon of dbTable.constraints) {
183
+ const snapCon = snapCons.find(s => s.name === dbCon.name);
184
+ if (snapCon?.trackingId)
185
+ dbCon.trackingId = snapCon.trackingId;
186
+ }
187
+ }
188
+ }
160
189
  const desiredASTCopy = { ...desiredAST };
161
190
  if (!includeFunctions) {
162
191
  dbParsedSchema.functions = [];
@@ -176,7 +205,20 @@ async function runPush(config, projectRoot, opts = {}) {
176
205
  }
177
206
  console.log('');
178
207
  console.log(`${colors_1.colors.bold('Changes to push:')}`);
208
+ const renamedFromNames = new Set(comparison.renamed.tables.map(r => r.from));
209
+ const renamedToNames = new Set(comparison.renamed.tables.map(r => r.to));
210
+ for (const rename of comparison.renamed.tables) {
211
+ console.log(` ${colors_1.colors.cyan('→')} ${colors_1.colors.bold(rename.from)} → ${colors_1.colors.bold(rename.to)} ${colors_1.colors.muted('(rename)')}`);
212
+ }
213
+ for (const rename of comparison.renamed.columns) {
214
+ console.log(` ${colors_1.colors.cyan('→')} ${colors_1.colors.bold(rename.table)}.${rename.from} → ${rename.to} ${colors_1.colors.muted('(rename column)')}`);
215
+ }
216
+ for (const rename of comparison.renamed.indexes) {
217
+ console.log(` ${colors_1.colors.cyan('→')} index ${rename.from} → ${rename.to} ${colors_1.colors.muted('(rename index)')}`);
218
+ }
179
219
  for (const table of filteredDiff.tables) {
220
+ if (renamedFromNames.has(table.name) || renamedToNames.has(table.name))
221
+ continue;
180
222
  if (table.type === 'added') {
181
223
  console.log(` ${colors_1.colors.green('+')} ${colors_1.colors.bold(table.name)} ${colors_1.colors.muted('(new table)')}`);
182
224
  for (const col of table.columns || []) {
@@ -273,8 +315,11 @@ async function runPush(config, projectRoot, opts = {}) {
273
315
  || comparison.removed.triggers.length > 0;
274
316
  if ((0, schema_diff_1.hasDestructiveChanges)(filteredDiff) || hasNonTableDestructive) {
275
317
  const destructiveItems = [];
276
- for (const t of (0, schema_diff_1.getDestructiveTables)(filteredDiff))
318
+ for (const t of (0, schema_diff_1.getDestructiveTables)(filteredDiff)) {
319
+ if (renamedFromNames.has(t) || renamedToNames.has(t))
320
+ continue;
277
321
  destructiveItems.push(t);
322
+ }
278
323
  for (const e of comparison.removed.enums)
279
324
  destructiveItems.push(`enum ${e.name}`);
280
325
  for (const d of comparison.removed.domains)
@@ -289,33 +334,35 @@ async function runPush(config, projectRoot, opts = {}) {
289
334
  destructiveItems.push(`function ${f.name}`);
290
335
  for (const tr of comparison.removed.triggers)
291
336
  destructiveItems.push(`trigger ${tr.name}`);
292
- (0, ui_1.warning)('Destructive changes detected:');
293
- for (const item of destructiveItems) {
294
- console.log(` ${colors_1.colors.red('-')} ${item}`);
295
- }
296
- console.log('');
297
- if (!force && !skipPrompt) {
298
- const proceed = await p.confirm({
299
- message: 'Include destructive changes?',
300
- initialValue: false,
301
- });
302
- if (p.isCancel(proceed)) {
303
- (0, ui_1.fatal)('Operation cancelled by user');
337
+ if (destructiveItems.length > 0) {
338
+ (0, ui_1.warning)('Destructive changes detected:');
339
+ for (const item of destructiveItems) {
340
+ console.log(` ${colors_1.colors.red('-')} ${item}`);
304
341
  }
305
- if (!proceed) {
306
- filteredDiff = (0, schema_diff_1.stripDestructiveChanges)(filteredDiff);
307
- comparison.removed.enums = [];
308
- comparison.removed.domains = [];
309
- comparison.removed.sequences = [];
310
- comparison.removed.compositeTypes = [];
311
- comparison.removed.views = [];
312
- comparison.removed.functions = [];
313
- comparison.removed.triggers = [];
314
- if (!filteredDiff.hasChanges && !comparison.hasChanges) {
315
- p.log.info('No non-destructive changes to push.');
316
- process.exit(0);
342
+ console.log('');
343
+ if (!force && !skipPrompt) {
344
+ const proceed = await p.confirm({
345
+ message: 'Include destructive changes?',
346
+ initialValue: false,
347
+ });
348
+ if (p.isCancel(proceed)) {
349
+ (0, ui_1.fatal)('Operation cancelled by user');
350
+ }
351
+ if (!proceed) {
352
+ filteredDiff = (0, schema_diff_1.stripDestructiveChanges)(filteredDiff);
353
+ comparison.removed.enums = [];
354
+ comparison.removed.domains = [];
355
+ comparison.removed.sequences = [];
356
+ comparison.removed.compositeTypes = [];
357
+ comparison.removed.views = [];
358
+ comparison.removed.functions = [];
359
+ comparison.removed.triggers = [];
360
+ if (!filteredDiff.hasChanges && !comparison.hasChanges) {
361
+ p.log.info('No non-destructive changes to push.');
362
+ process.exit(0);
363
+ }
364
+ p.log.info('Destructive changes excluded. Continuing with safe changes only.');
317
365
  }
318
- p.log.info('Destructive changes excluded. Continuing with safe changes only.');
319
366
  }
320
367
  }
321
368
  }
@@ -1069,7 +1069,7 @@ function compareColumnProperties(oldCol, newCol) {
1069
1069
  if (oldCol.isUnique !== newCol.isUnique) {
1070
1070
  changes.push({ field: 'unique', from: oldCol.isUnique, to: newCol.isUnique });
1071
1071
  }
1072
- if (oldCol.defaultValue !== newCol.defaultValue) {
1072
+ if (!defaultsEqual(oldCol.defaultValue, newCol.defaultValue)) {
1073
1073
  changes.push({ field: 'default', from: oldCol.defaultValue, to: newCol.defaultValue });
1074
1074
  }
1075
1075
  const oldLength = oldCol.typeParams?.length;
@@ -1089,6 +1089,24 @@ function compareColumnProperties(oldCol, newCol) {
1089
1089
  }
1090
1090
  return changes;
1091
1091
  }
1092
+ function defaultsEqual(a, b) {
1093
+ if (a === b)
1094
+ return true;
1095
+ if (a == null && b == null)
1096
+ return true;
1097
+ if (a == null || b == null)
1098
+ return false;
1099
+ return normalizeDefault(a) === normalizeDefault(b);
1100
+ }
1101
+ function normalizeDefault(val) {
1102
+ let v = val.trim();
1103
+ v = v.replace(/::[\w\s]+(\[\])?$/i, '');
1104
+ const upper = v.toUpperCase();
1105
+ if (upper === 'NOW()' || upper === 'CURRENT_TIMESTAMP' || upper === 'CURRENT_TIMESTAMP()') {
1106
+ return 'CURRENT_TIMESTAMP';
1107
+ }
1108
+ return v;
1109
+ }
1092
1110
  function compareTableIndexes(oldTable, newTable, tableName, result) {
1093
1111
  const oldByName = new Map(oldTable.indexes.map(i => [i.name, i]));
1094
1112
  const newByName = new Map(newTable.indexes.map(i => [i.name, i]));
@@ -14,7 +14,7 @@ import { validateForDialect, formatDialectErrors } from "../utils/dialect-valida
14
14
  import { validateSchemaFile, formatValidationErrors } from "../utils/schema-validator.js";
15
15
  import { loadRelqignore } from "../utils/relqignore.js";
16
16
  import { isInitialized } from "../utils/repo-manager.js";
17
- import { saveSnapshot } from "../utils/snapshot-manager.js";
17
+ import { loadSnapshot, saveSnapshot } from "../utils/snapshot-manager.js";
18
18
  import { loadSchemaFile } from "../utils/schema-loader.js";
19
19
  import { diffSchemas, filterDiff, hasDestructiveChanges, getDestructiveTables, stripDestructiveChanges, formatCategorizedSummary, compareSchemas } from "../utils/schema-diff.js";
20
20
  import { normalizeSchema } from "../utils/schema-hash.js";
@@ -121,6 +121,35 @@ export async function runPush(config, projectRoot, opts = {}) {
121
121
  const diff = diffSchemas(normalizeSchema(dbSchema), normalizeSchema(desiredSchema));
122
122
  let filteredDiff = filterDiff(diff, ignorePatterns.map(pat => pat.raw));
123
123
  const dbParsedSchema = await introspectedToParsedSchema(dbSchema);
124
+ const snapshot = loadSnapshot(snapshotPath);
125
+ if (snapshot) {
126
+ const snapTables = Object.values(snapshot.tables || {});
127
+ for (const dbTable of dbParsedSchema.tables) {
128
+ const snapTable = snapTables.find(s => s.name === dbTable.name);
129
+ if (!snapTable)
130
+ continue;
131
+ if (snapTable.trackingId)
132
+ dbTable.trackingId = snapTable.trackingId;
133
+ const snapCols = Object.values(snapTable.columns || {});
134
+ for (const dbCol of dbTable.columns) {
135
+ const snapCol = snapCols.find(s => s.name === dbCol.name);
136
+ if (snapCol?.trackingId)
137
+ dbCol.trackingId = snapCol.trackingId;
138
+ }
139
+ const snapIdxs = Object.values(snapTable.indexes || {});
140
+ for (const dbIdx of dbTable.indexes) {
141
+ const snapIdx = snapIdxs.find(s => s.name === dbIdx.name);
142
+ if (snapIdx?.trackingId)
143
+ dbIdx.trackingId = snapIdx.trackingId;
144
+ }
145
+ const snapCons = Object.values(snapTable.constraints || {});
146
+ for (const dbCon of dbTable.constraints) {
147
+ const snapCon = snapCons.find(s => s.name === dbCon.name);
148
+ if (snapCon?.trackingId)
149
+ dbCon.trackingId = snapCon.trackingId;
150
+ }
151
+ }
152
+ }
124
153
  const desiredASTCopy = { ...desiredAST };
125
154
  if (!includeFunctions) {
126
155
  dbParsedSchema.functions = [];
@@ -140,7 +169,20 @@ export async function runPush(config, projectRoot, opts = {}) {
140
169
  }
141
170
  console.log('');
142
171
  console.log(`${colors.bold('Changes to push:')}`);
172
+ const renamedFromNames = new Set(comparison.renamed.tables.map(r => r.from));
173
+ const renamedToNames = new Set(comparison.renamed.tables.map(r => r.to));
174
+ for (const rename of comparison.renamed.tables) {
175
+ console.log(` ${colors.cyan('→')} ${colors.bold(rename.from)} → ${colors.bold(rename.to)} ${colors.muted('(rename)')}`);
176
+ }
177
+ for (const rename of comparison.renamed.columns) {
178
+ console.log(` ${colors.cyan('→')} ${colors.bold(rename.table)}.${rename.from} → ${rename.to} ${colors.muted('(rename column)')}`);
179
+ }
180
+ for (const rename of comparison.renamed.indexes) {
181
+ console.log(` ${colors.cyan('→')} index ${rename.from} → ${rename.to} ${colors.muted('(rename index)')}`);
182
+ }
143
183
  for (const table of filteredDiff.tables) {
184
+ if (renamedFromNames.has(table.name) || renamedToNames.has(table.name))
185
+ continue;
144
186
  if (table.type === 'added') {
145
187
  console.log(` ${colors.green('+')} ${colors.bold(table.name)} ${colors.muted('(new table)')}`);
146
188
  for (const col of table.columns || []) {
@@ -237,8 +279,11 @@ export async function runPush(config, projectRoot, opts = {}) {
237
279
  || comparison.removed.triggers.length > 0;
238
280
  if (hasDestructiveChanges(filteredDiff) || hasNonTableDestructive) {
239
281
  const destructiveItems = [];
240
- for (const t of getDestructiveTables(filteredDiff))
282
+ for (const t of getDestructiveTables(filteredDiff)) {
283
+ if (renamedFromNames.has(t) || renamedToNames.has(t))
284
+ continue;
241
285
  destructiveItems.push(t);
286
+ }
242
287
  for (const e of comparison.removed.enums)
243
288
  destructiveItems.push(`enum ${e.name}`);
244
289
  for (const d of comparison.removed.domains)
@@ -253,33 +298,35 @@ export async function runPush(config, projectRoot, opts = {}) {
253
298
  destructiveItems.push(`function ${f.name}`);
254
299
  for (const tr of comparison.removed.triggers)
255
300
  destructiveItems.push(`trigger ${tr.name}`);
256
- warning('Destructive changes detected:');
257
- for (const item of destructiveItems) {
258
- console.log(` ${colors.red('-')} ${item}`);
259
- }
260
- console.log('');
261
- if (!force && !skipPrompt) {
262
- const proceed = await p.confirm({
263
- message: 'Include destructive changes?',
264
- initialValue: false,
265
- });
266
- if (p.isCancel(proceed)) {
267
- fatal('Operation cancelled by user');
301
+ if (destructiveItems.length > 0) {
302
+ warning('Destructive changes detected:');
303
+ for (const item of destructiveItems) {
304
+ console.log(` ${colors.red('-')} ${item}`);
268
305
  }
269
- if (!proceed) {
270
- filteredDiff = stripDestructiveChanges(filteredDiff);
271
- comparison.removed.enums = [];
272
- comparison.removed.domains = [];
273
- comparison.removed.sequences = [];
274
- comparison.removed.compositeTypes = [];
275
- comparison.removed.views = [];
276
- comparison.removed.functions = [];
277
- comparison.removed.triggers = [];
278
- if (!filteredDiff.hasChanges && !comparison.hasChanges) {
279
- p.log.info('No non-destructive changes to push.');
280
- process.exit(0);
306
+ console.log('');
307
+ if (!force && !skipPrompt) {
308
+ const proceed = await p.confirm({
309
+ message: 'Include destructive changes?',
310
+ initialValue: false,
311
+ });
312
+ if (p.isCancel(proceed)) {
313
+ fatal('Operation cancelled by user');
314
+ }
315
+ if (!proceed) {
316
+ filteredDiff = stripDestructiveChanges(filteredDiff);
317
+ comparison.removed.enums = [];
318
+ comparison.removed.domains = [];
319
+ comparison.removed.sequences = [];
320
+ comparison.removed.compositeTypes = [];
321
+ comparison.removed.views = [];
322
+ comparison.removed.functions = [];
323
+ comparison.removed.triggers = [];
324
+ if (!filteredDiff.hasChanges && !comparison.hasChanges) {
325
+ p.log.info('No non-destructive changes to push.');
326
+ process.exit(0);
327
+ }
328
+ p.log.info('Destructive changes excluded. Continuing with safe changes only.');
281
329
  }
282
- p.log.info('Destructive changes excluded. Continuing with safe changes only.');
283
330
  }
284
331
  }
285
332
  }
@@ -1058,7 +1058,7 @@ function compareColumnProperties(oldCol, newCol) {
1058
1058
  if (oldCol.isUnique !== newCol.isUnique) {
1059
1059
  changes.push({ field: 'unique', from: oldCol.isUnique, to: newCol.isUnique });
1060
1060
  }
1061
- if (oldCol.defaultValue !== newCol.defaultValue) {
1061
+ if (!defaultsEqual(oldCol.defaultValue, newCol.defaultValue)) {
1062
1062
  changes.push({ field: 'default', from: oldCol.defaultValue, to: newCol.defaultValue });
1063
1063
  }
1064
1064
  const oldLength = oldCol.typeParams?.length;
@@ -1078,6 +1078,24 @@ function compareColumnProperties(oldCol, newCol) {
1078
1078
  }
1079
1079
  return changes;
1080
1080
  }
1081
+ function defaultsEqual(a, b) {
1082
+ if (a === b)
1083
+ return true;
1084
+ if (a == null && b == null)
1085
+ return true;
1086
+ if (a == null || b == null)
1087
+ return false;
1088
+ return normalizeDefault(a) === normalizeDefault(b);
1089
+ }
1090
+ function normalizeDefault(val) {
1091
+ let v = val.trim();
1092
+ v = v.replace(/::[\w\s]+(\[\])?$/i, '');
1093
+ const upper = v.toUpperCase();
1094
+ if (upper === 'NOW()' || upper === 'CURRENT_TIMESTAMP' || upper === 'CURRENT_TIMESTAMP()') {
1095
+ return 'CURRENT_TIMESTAMP';
1096
+ }
1097
+ return v;
1098
+ }
1081
1099
  function compareTableIndexes(oldTable, newTable, tableName, result) {
1082
1100
  const oldByName = new Map(oldTable.indexes.map(i => [i.name, i]));
1083
1101
  const newByName = new Map(newTable.indexes.map(i => [i.name, i]));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relq",
3
- "version": "1.0.104",
3
+ "version": "1.0.106",
4
4
  "description": "The Fully-Typed PostgreSQL ORM for TypeScript",
5
5
  "author": "Olajide Mathew O. <olajide.mathew@yuniq.solutions>",
6
6
  "license": "MIT",