relq 1.0.0 → 1.0.2

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.
Files changed (159) hide show
  1. package/dist/cjs/addon/buffer/index.cjs +1881 -0
  2. package/dist/cjs/addon/pg/index.cjs +4812 -0
  3. package/dist/cjs/addon/pg-cursor/index.cjs +1451 -0
  4. package/dist/cjs/addon/pg-format/index.cjs +2270 -0
  5. package/dist/cjs/cli/commands/add.cjs +30 -1
  6. package/dist/cjs/cli/commands/branch.cjs +141 -0
  7. package/dist/cjs/cli/commands/checkout.cjs +134 -0
  8. package/dist/cjs/cli/commands/cherry-pick.cjs +283 -0
  9. package/dist/cjs/cli/commands/diff.cjs +148 -69
  10. package/dist/cjs/cli/commands/export.cjs +64 -5
  11. package/dist/cjs/cli/commands/fetch.cjs +34 -4
  12. package/dist/cjs/cli/commands/history.cjs +1 -1
  13. package/dist/cjs/cli/commands/import.cjs +283 -12
  14. package/dist/cjs/cli/commands/log.cjs +75 -0
  15. package/dist/cjs/cli/commands/merge.cjs +224 -0
  16. package/dist/cjs/cli/commands/migrate.cjs +1 -1
  17. package/dist/cjs/cli/commands/pull.cjs +123 -7
  18. package/dist/cjs/cli/commands/push.cjs +245 -29
  19. package/dist/cjs/cli/commands/remote.cjs +16 -0
  20. package/dist/cjs/cli/commands/reset.cjs +169 -0
  21. package/dist/cjs/cli/commands/resolve.cjs +193 -0
  22. package/dist/cjs/cli/commands/rollback.cjs +1 -1
  23. package/dist/cjs/cli/commands/stash.cjs +154 -0
  24. package/dist/cjs/cli/commands/status.cjs +48 -0
  25. package/dist/cjs/cli/commands/tag.cjs +147 -0
  26. package/dist/cjs/cli/index.cjs +46 -2
  27. package/dist/cjs/cli/utils/commit-manager.cjs +3 -3
  28. package/dist/cjs/cli/utils/env-loader.cjs +3 -2
  29. package/dist/cjs/cli/utils/fast-introspect.cjs +1 -1
  30. package/dist/cjs/cli/utils/project-root.cjs +56 -0
  31. package/dist/cjs/cli/utils/relqignore.cjs +296 -38
  32. package/dist/cjs/cli/utils/repo-manager.cjs +45 -3
  33. package/dist/cjs/cli/utils/schema-introspect.cjs +2 -2
  34. package/dist/cjs/cli/utils/sql-generator.cjs +1 -1
  35. package/dist/cjs/cli/utils/sql-parser.cjs +102 -13
  36. package/dist/cjs/condition/array-condition-builder.cjs +1 -1
  37. package/dist/cjs/condition/condition-collector.cjs +1 -1
  38. package/dist/cjs/condition/fulltext-condition-builder.cjs +1 -1
  39. package/dist/cjs/condition/geometric-condition-builder.cjs +1 -1
  40. package/dist/cjs/condition/jsonb-condition-builder.cjs +1 -1
  41. package/dist/cjs/condition/network-condition-builder.cjs +1 -1
  42. package/dist/cjs/condition/range-condition-builder.cjs +1 -1
  43. package/dist/cjs/copy/copy-builder.cjs +1 -1
  44. package/dist/cjs/core/query-builder.cjs +1 -1
  45. package/dist/cjs/core/relq-client.cjs +2 -2
  46. package/dist/cjs/count/count-builder.cjs +1 -1
  47. package/dist/cjs/cte/cte-builder.cjs +1 -1
  48. package/dist/cjs/delete/delete-builder.cjs +1 -1
  49. package/dist/cjs/function/create-function-builder.cjs +1 -1
  50. package/dist/cjs/functions/advanced-functions.cjs +1 -1
  51. package/dist/cjs/functions/case-builder.cjs +1 -1
  52. package/dist/cjs/functions/geometric-functions.cjs +1 -1
  53. package/dist/cjs/functions/network-functions.cjs +1 -1
  54. package/dist/cjs/functions/sql-functions.cjs +1 -1
  55. package/dist/cjs/indexing/create-index-builder.cjs +1 -1
  56. package/dist/cjs/indexing/drop-index-builder.cjs +1 -1
  57. package/dist/cjs/insert/conflict-builder.cjs +1 -1
  58. package/dist/cjs/insert/insert-builder.cjs +1 -1
  59. package/dist/cjs/maintenance/vacuum-builder.cjs +1 -1
  60. package/dist/cjs/pubsub/listen-notify-builder.cjs +1 -1
  61. package/dist/cjs/pubsub/listener-connection.cjs +2 -2
  62. package/dist/cjs/raw/raw-query-builder.cjs +1 -1
  63. package/dist/cjs/schema/schema-builder.cjs +1 -1
  64. package/dist/cjs/schema-definition/table-definition.cjs +1 -1
  65. package/dist/cjs/select/aggregate-builder.cjs +1 -1
  66. package/dist/cjs/select/select-builder.cjs +1 -1
  67. package/dist/cjs/sequence/sequence-builder.cjs +1 -1
  68. package/dist/cjs/table/alter-table-builder.cjs +1 -1
  69. package/dist/cjs/table/constraint-builder.cjs +1 -1
  70. package/dist/cjs/table/create-table-builder.cjs +1 -1
  71. package/dist/cjs/table/partition-builder.cjs +1 -1
  72. package/dist/cjs/table/truncate-builder.cjs +1 -1
  73. package/dist/cjs/transaction/transaction-builder.cjs +1 -1
  74. package/dist/cjs/trigger/create-trigger-builder.cjs +1 -1
  75. package/dist/cjs/update/array-update-builder.cjs +1 -1
  76. package/dist/cjs/update/update-builder.cjs +1 -1
  77. package/dist/cjs/utils/index.cjs +1 -1
  78. package/dist/cjs/view/create-view-builder.cjs +1 -1
  79. package/dist/cjs/window/window-builder.cjs +1 -1
  80. package/dist/esm/cli/commands/add.js +30 -1
  81. package/dist/esm/cli/commands/branch.js +105 -0
  82. package/dist/esm/cli/commands/checkout.js +98 -0
  83. package/dist/esm/cli/commands/cherry-pick.js +247 -0
  84. package/dist/esm/cli/commands/diff.js +148 -69
  85. package/dist/esm/cli/commands/export.js +64 -5
  86. package/dist/esm/cli/commands/fetch.js +35 -5
  87. package/dist/esm/cli/commands/history.js +1 -1
  88. package/dist/esm/cli/commands/import.js +283 -12
  89. package/dist/esm/cli/commands/log.js +74 -0
  90. package/dist/esm/cli/commands/merge.js +188 -0
  91. package/dist/esm/cli/commands/migrate.js +1 -1
  92. package/dist/esm/cli/commands/pull.js +124 -8
  93. package/dist/esm/cli/commands/push.js +246 -30
  94. package/dist/esm/cli/commands/remote.js +13 -0
  95. package/dist/esm/cli/commands/reset.js +133 -0
  96. package/dist/esm/cli/commands/resolve.js +157 -0
  97. package/dist/esm/cli/commands/rollback.js +1 -1
  98. package/dist/esm/cli/commands/stash.js +118 -0
  99. package/dist/esm/cli/commands/status.js +15 -0
  100. package/dist/esm/cli/commands/tag.js +111 -0
  101. package/dist/esm/cli/index.js +47 -3
  102. package/dist/esm/cli/utils/commit-manager.js +3 -3
  103. package/dist/esm/cli/utils/env-loader.js +3 -2
  104. package/dist/esm/cli/utils/fast-introspect.js +1 -1
  105. package/dist/esm/cli/utils/project-root.js +19 -0
  106. package/dist/esm/cli/utils/relqignore.js +277 -37
  107. package/dist/esm/cli/utils/repo-manager.js +41 -3
  108. package/dist/esm/cli/utils/schema-introspect.js +2 -2
  109. package/dist/esm/cli/utils/sql-generator.js +1 -1
  110. package/dist/esm/cli/utils/sql-parser.js +102 -13
  111. package/dist/esm/condition/array-condition-builder.js +1 -1
  112. package/dist/esm/condition/condition-collector.js +1 -1
  113. package/dist/esm/condition/fulltext-condition-builder.js +1 -1
  114. package/dist/esm/condition/geometric-condition-builder.js +1 -1
  115. package/dist/esm/condition/jsonb-condition-builder.js +1 -1
  116. package/dist/esm/condition/network-condition-builder.js +1 -1
  117. package/dist/esm/condition/range-condition-builder.js +1 -1
  118. package/dist/esm/copy/copy-builder.js +1 -1
  119. package/dist/esm/core/query-builder.js +1 -1
  120. package/dist/esm/core/relq-client.js +2 -2
  121. package/dist/esm/count/count-builder.js +1 -1
  122. package/dist/esm/cte/cte-builder.js +1 -1
  123. package/dist/esm/delete/delete-builder.js +1 -1
  124. package/dist/esm/function/create-function-builder.js +1 -1
  125. package/dist/esm/functions/advanced-functions.js +1 -1
  126. package/dist/esm/functions/case-builder.js +1 -1
  127. package/dist/esm/functions/geometric-functions.js +1 -1
  128. package/dist/esm/functions/network-functions.js +1 -1
  129. package/dist/esm/functions/sql-functions.js +1 -1
  130. package/dist/esm/indexing/create-index-builder.js +1 -1
  131. package/dist/esm/indexing/drop-index-builder.js +1 -1
  132. package/dist/esm/insert/conflict-builder.js +1 -1
  133. package/dist/esm/insert/insert-builder.js +1 -1
  134. package/dist/esm/maintenance/vacuum-builder.js +1 -1
  135. package/dist/esm/pubsub/listen-notify-builder.js +1 -1
  136. package/dist/esm/pubsub/listener-connection.js +2 -2
  137. package/dist/esm/raw/raw-query-builder.js +1 -1
  138. package/dist/esm/schema/schema-builder.js +1 -1
  139. package/dist/esm/schema-definition/table-definition.js +1 -1
  140. package/dist/esm/select/aggregate-builder.js +1 -1
  141. package/dist/esm/select/select-builder.js +1 -1
  142. package/dist/esm/sequence/sequence-builder.js +1 -1
  143. package/dist/esm/table/alter-table-builder.js +1 -1
  144. package/dist/esm/table/constraint-builder.js +1 -1
  145. package/dist/esm/table/create-table-builder.js +1 -1
  146. package/dist/esm/table/partition-builder.js +1 -1
  147. package/dist/esm/table/truncate-builder.js +1 -1
  148. package/dist/esm/transaction/transaction-builder.js +1 -1
  149. package/dist/esm/trigger/create-trigger-builder.js +1 -1
  150. package/dist/esm/update/array-update-builder.js +1 -1
  151. package/dist/esm/update/update-builder.js +1 -1
  152. package/dist/esm/utils/index.js +1 -1
  153. package/dist/esm/view/create-view-builder.js +1 -1
  154. package/dist/esm/window/window-builder.js +1 -1
  155. package/package.json +1 -1
  156. /package/dist/{addons/buffer.js → esm/addon/buffer/index.js} +0 -0
  157. /package/dist/{addons/pg.js → esm/addon/pg/index.js} +0 -0
  158. /package/dist/{addons/pg-cursor.js → esm/addon/pg-cursor/index.js} +0 -0
  159. /package/dist/{addons/pg-format.js → esm/addon/pg-format/index.js} +0 -0
@@ -41,6 +41,7 @@ const type_generator_1 = require("../utils/type-generator.cjs");
41
41
  const repo_manager_1 = require("../utils/repo-manager.cjs");
42
42
  const schema_comparator_1 = require("../utils/schema-comparator.cjs");
43
43
  const change_tracker_1 = require("../utils/change-tracker.cjs");
44
+ const relqignore_1 = require("../utils/relqignore.cjs");
44
45
  const git_utils_1 = require("../utils/git-utils.cjs");
45
46
  async function importCommand(sqlFilePath, options = {}) {
46
47
  const { includeFunctions = false, includeTriggers = false, force = false, dryRun = false } = options;
@@ -144,26 +145,143 @@ async function importCommand(sqlFilePath, options = {}) {
144
145
  }
145
146
  }
146
147
  console.log('');
148
+ const ignorePatterns = (0, relqignore_1.loadRelqignore)(projectRoot);
149
+ let ignoredCount = 0;
150
+ const filteredTables = parsedSchema.tables.filter(table => {
151
+ if ((0, relqignore_1.isTableIgnored)(table.name, ignorePatterns).ignored) {
152
+ ignoredCount++;
153
+ return false;
154
+ }
155
+ return true;
156
+ }).map(table => {
157
+ const filteredColumns = table.columns.filter(col => {
158
+ if ((0, relqignore_1.isColumnIgnored)(table.name, col.name, ignorePatterns).ignored) {
159
+ ignoredCount++;
160
+ return false;
161
+ }
162
+ return true;
163
+ });
164
+ const filteredIndexes = table.indexes.filter(idx => {
165
+ if ((0, relqignore_1.isIndexIgnored)(table.name, idx.name, ignorePatterns).ignored) {
166
+ ignoredCount++;
167
+ return false;
168
+ }
169
+ return true;
170
+ });
171
+ const filteredConstraints = table.constraints.filter(con => {
172
+ if ((0, relqignore_1.isConstraintIgnored)(table.name, con.name, ignorePatterns).ignored) {
173
+ ignoredCount++;
174
+ return false;
175
+ }
176
+ return true;
177
+ });
178
+ return {
179
+ ...table,
180
+ columns: filteredColumns,
181
+ indexes: filteredIndexes,
182
+ constraints: filteredConstraints,
183
+ };
184
+ });
185
+ const filteredEnums = parsedSchema.enums.filter(e => {
186
+ if ((0, relqignore_1.isEnumIgnored)(e.name, ignorePatterns).ignored) {
187
+ ignoredCount++;
188
+ return false;
189
+ }
190
+ return true;
191
+ });
192
+ const filteredDomains = parsedSchema.domains.filter(d => {
193
+ if ((0, relqignore_1.isDomainIgnored)(d.name, ignorePatterns).ignored) {
194
+ ignoredCount++;
195
+ return false;
196
+ }
197
+ return true;
198
+ });
199
+ const filteredCompositeTypes = parsedSchema.compositeTypes.filter(c => {
200
+ if ((0, relqignore_1.isCompositeTypeIgnored)(c.name, ignorePatterns).ignored) {
201
+ ignoredCount++;
202
+ return false;
203
+ }
204
+ return true;
205
+ });
206
+ const filteredSequences = parsedSchema.sequences.filter(s => {
207
+ if ((0, relqignore_1.isSequenceIgnored)(s.name, ignorePatterns).ignored) {
208
+ ignoredCount++;
209
+ return false;
210
+ }
211
+ return true;
212
+ });
213
+ const filteredFunctions = functions.filter(f => {
214
+ if ((0, relqignore_1.isFunctionIgnored)(f.name, ignorePatterns).ignored) {
215
+ ignoredCount++;
216
+ return false;
217
+ }
218
+ return true;
219
+ });
220
+ const filteredSchema = {
221
+ tables: filteredTables,
222
+ enums: filteredEnums,
223
+ domains: filteredDomains,
224
+ compositeTypes: filteredCompositeTypes,
225
+ sequences: filteredSequences,
226
+ collations: parsedSchema.collations,
227
+ foreignTables: parsedSchema.foreignTables,
228
+ views: parsedSchema.views,
229
+ materializedViews: parsedSchema.materializedViews,
230
+ foreignServers: parsedSchema.foreignServers,
231
+ extensions: parsedSchema.extensions,
232
+ partitions: parsedSchema.partitions,
233
+ };
234
+ if (ignoredCount > 0) {
235
+ console.log(`${git_utils_1.colors.gray(`ℹ ${ignoredCount} object(s) ignored by .relqignore`)}`);
236
+ }
237
+ const dependencyErrors = (0, relqignore_1.validateIgnoreDependencies)({
238
+ tables: filteredTables.map(t => ({
239
+ name: t.name,
240
+ columns: t.columns.map(c => ({
241
+ name: c.name,
242
+ type: c.dataType,
243
+ default: c.defaultValue,
244
+ })),
245
+ })),
246
+ enums: parsedSchema.enums,
247
+ domains: parsedSchema.domains,
248
+ sequences: parsedSchema.sequences,
249
+ compositeTypes: parsedSchema.compositeTypes,
250
+ }, ignorePatterns);
251
+ if (dependencyErrors.length > 0) {
252
+ spinner.stop();
253
+ (0, git_utils_1.error)('Dependency validation failed:');
254
+ console.log('');
255
+ for (const depError of dependencyErrors) {
256
+ console.log(` ${git_utils_1.colors.red('✗')} ${depError.message}`);
257
+ }
258
+ console.log('');
259
+ (0, git_utils_1.hint)('Either un-ignore the type or add the column to .relqignore');
260
+ process.exit(1);
261
+ }
147
262
  spinner.start('Generating TypeScript schema');
148
- const dbSchema = convertToDbSchema(parsedSchema, functions, triggers, comments);
263
+ const dbSchema = convertToDbSchema(filteredSchema, filteredFunctions, triggers, comments);
149
264
  const typescriptContent = (0, type_generator_1.generateTypeScript)(dbSchema, {
150
265
  camelCase: true,
151
266
  includeFunctions,
152
267
  includeTriggers,
153
268
  });
154
269
  spinner.succeed('Generated TypeScript schema');
155
- const normalizedSchema = convertToNormalizedSchema(parsedSchema, functions, triggers);
270
+ const incomingSchema = convertToNormalizedSchema(filteredSchema, filteredFunctions, triggers);
156
271
  const existingSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot);
272
+ const replaceAll = options.theirs === true;
273
+ let mergedSchema;
157
274
  let changes = [];
158
275
  if (existingSnapshot) {
159
276
  spinner.start('Detecting changes');
277
+ mergedSchema = mergeSchemas(existingSnapshot, incomingSchema, replaceAll);
160
278
  const beforeSchema = snapshotToDbSchema(existingSnapshot);
161
- const afterSchema = snapshotToDbSchema(normalizedSchema);
279
+ const afterSchema = snapshotToDbSchema(mergedSchema);
162
280
  changes = (0, schema_comparator_1.compareSchemas)(beforeSchema, afterSchema);
163
281
  spinner.stop();
164
282
  if (changes.length > 0) {
165
283
  console.log('');
166
- console.log(`${git_utils_1.colors.bold('Changes detected:')}`);
284
+ console.log(`${git_utils_1.colors.bold('Changes detected:')}${replaceAll ? git_utils_1.colors.yellow(' (--theirs: full replacement)') : ''}`);
167
285
  console.log('');
168
286
  const creates = changes.filter(c => c.type === 'CREATE');
169
287
  const alters = changes.filter(c => c.type === 'ALTER');
@@ -185,11 +303,17 @@ async function importCommand(sqlFilePath, options = {}) {
185
303
  }
186
304
  }
187
305
  if (drops.length > 0) {
188
- for (const change of drops.slice(0, 10)) {
189
- console.log(`\t${git_utils_1.colors.red((0, change_tracker_1.getChangeDisplayName)(change))}`);
306
+ if (replaceAll) {
307
+ for (const change of drops.slice(0, 10)) {
308
+ console.log(`\t${git_utils_1.colors.red((0, change_tracker_1.getChangeDisplayName)(change))}`);
309
+ }
310
+ if (drops.length > 10) {
311
+ console.log(`\t${git_utils_1.colors.gray(`... and ${drops.length - 10} more deletions`)}`);
312
+ }
190
313
  }
191
- if (drops.length > 10) {
192
- console.log(`\t${git_utils_1.colors.gray(`... and ${drops.length - 10} more deletions`)}`);
314
+ else {
315
+ console.log('');
316
+ console.log(`${git_utils_1.colors.gray(`ℹ ${drops.length} object(s) only in existing schema (preserved)`)}`);
193
317
  }
194
318
  }
195
319
  console.log('');
@@ -201,15 +325,22 @@ async function importCommand(sqlFilePath, options = {}) {
201
325
  }
202
326
  }
203
327
  else {
328
+ mergedSchema = incomingSchema;
204
329
  changes = [];
205
330
  console.log(`${git_utils_1.colors.cyan('First import')} - creating initial snapshot`);
206
331
  }
332
+ const mergedDbSchema = snapshotToDbSchemaForGeneration(mergedSchema);
333
+ const finalTypescriptContent = (0, type_generator_1.generateTypeScript)(mergedDbSchema, {
334
+ camelCase: true,
335
+ includeFunctions,
336
+ includeTriggers,
337
+ });
207
338
  if (dryRun) {
208
339
  console.log('');
209
340
  console.log(`${git_utils_1.colors.yellow('Dry run mode')} - no files written`);
210
341
  console.log('');
211
342
  console.log('Would write:');
212
- console.log(` ${git_utils_1.colors.cyan(options.output || './db/schema.ts')} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(typescriptContent.length)})`)}`);
343
+ console.log(` ${git_utils_1.colors.cyan(options.output || './db/schema.ts')} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
213
344
  console.log(` ${git_utils_1.colors.cyan('.relq/snapshot.json')}`);
214
345
  if (changes.length > 0) {
215
346
  console.log(` Stage ${changes.length} change(s)`);
@@ -223,9 +354,9 @@ async function importCommand(sqlFilePath, options = {}) {
223
354
  if (!fs.existsSync(outputDir)) {
224
355
  fs.mkdirSync(outputDir, { recursive: true });
225
356
  }
226
- fs.writeFileSync(absoluteOutputPath, typescriptContent, 'utf-8');
227
- console.log(`Written ${git_utils_1.colors.cyan(outputPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(typescriptContent.length)})`)}`);
228
- (0, repo_manager_1.saveSnapshot)(normalizedSchema, projectRoot);
357
+ fs.writeFileSync(absoluteOutputPath, finalTypescriptContent, 'utf-8');
358
+ console.log(`Written ${git_utils_1.colors.cyan(outputPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
359
+ (0, repo_manager_1.saveSnapshot)(mergedSchema, projectRoot);
229
360
  if (changes.length > 0) {
230
361
  (0, repo_manager_1.addUnstagedChanges)(changes, projectRoot);
231
362
  (0, repo_manager_1.stageChanges)(['.'], projectRoot);
@@ -442,6 +573,17 @@ function convertToNormalizedSchema(parsed, functions = [], triggers = []) {
442
573
  forEach: 'STATEMENT',
443
574
  functionName: t.functionName || '',
444
575
  })),
576
+ views: parsed.views.map(v => ({
577
+ name: v.name,
578
+ schema: v.schema || 'public',
579
+ definition: v.definition,
580
+ })),
581
+ materializedViews: parsed.materializedViews.map(mv => ({
582
+ name: mv.name,
583
+ schema: mv.schema || 'public',
584
+ definition: mv.definition,
585
+ withData: mv.withData ?? true,
586
+ })),
445
587
  };
446
588
  }
447
589
  function snapshotToDbSchema(snapshot) {
@@ -521,4 +663,133 @@ function snapshotToDbSchema(snapshot) {
521
663
  sequences: [],
522
664
  });
523
665
  }
666
+ function snapshotToDbSchemaForGeneration(snapshot) {
667
+ return {
668
+ tables: snapshot.tables.map(t => ({
669
+ name: t.name,
670
+ schema: t.schema || 'public',
671
+ comment: null,
672
+ columns: t.columns.map(c => ({
673
+ name: c.name,
674
+ dataType: c.type,
675
+ udtName: c.type,
676
+ isNullable: c.nullable,
677
+ defaultValue: c.default ?? null,
678
+ isPrimaryKey: c.primaryKey || false,
679
+ isUnique: c.unique || false,
680
+ maxLength: null,
681
+ precision: null,
682
+ scale: null,
683
+ references: null,
684
+ comment: null,
685
+ isGenerated: c.isGenerated || false,
686
+ generationExpression: c.generationExpression || null,
687
+ identityGeneration: c.identity?.type || null,
688
+ })),
689
+ indexes: t.indexes.map(i => ({
690
+ name: i.name,
691
+ columns: Array.isArray(i.columns) ? i.columns : [i.columns],
692
+ isUnique: i.unique || false,
693
+ isPrimary: false,
694
+ type: i.type || 'btree',
695
+ definition: i.definition,
696
+ whereClause: i.whereClause,
697
+ comment: null,
698
+ })),
699
+ constraints: t.constraints?.map(c => ({
700
+ name: c.name,
701
+ type: c.type,
702
+ columns: [],
703
+ definition: c.definition,
704
+ })) || [],
705
+ rowCount: 0,
706
+ isPartitioned: t.isPartitioned || false,
707
+ partitionType: t.partitionType,
708
+ partitionKey: t.partitionKey ? [t.partitionKey].flat() : undefined,
709
+ })),
710
+ enums: snapshot.enums?.map(e => ({
711
+ name: e.name,
712
+ values: e.values,
713
+ })) || [],
714
+ domains: snapshot.domains?.map(d => ({
715
+ name: d.name,
716
+ baseType: d.baseType,
717
+ isNotNull: d.notNull || false,
718
+ defaultValue: d.default || null,
719
+ checkExpression: d.check || null,
720
+ check: d.check,
721
+ default: d.default,
722
+ notNull: d.notNull,
723
+ })) || [],
724
+ compositeTypes: snapshot.compositeTypes?.map(c => ({
725
+ name: c.name,
726
+ attributes: c.attributes || [],
727
+ })) || [],
728
+ sequences: snapshot.sequences?.map(s => ({
729
+ name: s.name,
730
+ dataType: s.dataType,
731
+ start: s.startValue,
732
+ increment: s.increment,
733
+ minValue: s.minValue,
734
+ maxValue: s.maxValue,
735
+ cache: s.cache,
736
+ cycle: s.cycle,
737
+ ownedBy: s.ownedBy ?? undefined,
738
+ })) || [],
739
+ extensions: (snapshot.extensions || []).map(e => typeof e === 'string' ? e : e.name),
740
+ partitions: [],
741
+ functions: snapshot.functions?.map(f => ({
742
+ name: f.name,
743
+ schema: 'public',
744
+ returnType: f.returnType,
745
+ argTypes: f.argTypes || [],
746
+ language: f.language,
747
+ definition: '',
748
+ isAggregate: false,
749
+ volatility: 'VOLATILE',
750
+ })) || [],
751
+ triggers: snapshot.triggers?.map(t => ({
752
+ name: t.name,
753
+ tableName: t.table,
754
+ timing: t.timing,
755
+ event: t.events?.[0] || '',
756
+ functionName: t.functionName || '',
757
+ definition: '',
758
+ isEnabled: t.isEnabled ?? true,
759
+ })) || [],
760
+ policies: [],
761
+ foreignServers: [],
762
+ foreignTables: [],
763
+ };
764
+ }
765
+ function mergeSchemas(existing, incoming, replaceAll = false) {
766
+ if (replaceAll) {
767
+ return incoming;
768
+ }
769
+ function mergeByName(existingArr, incomingArr) {
770
+ const incomingMap = new Map(incomingArr.map(item => [item.name, item]));
771
+ const resultMap = new Map();
772
+ for (const item of existingArr) {
773
+ resultMap.set(item.name, item);
774
+ }
775
+ for (const item of incomingArr) {
776
+ resultMap.set(item.name, item);
777
+ }
778
+ return Array.from(resultMap.values());
779
+ }
780
+ return {
781
+ extensions: mergeByName(existing.extensions || [], incoming.extensions || []),
782
+ enums: mergeByName(existing.enums || [], incoming.enums || []),
783
+ domains: mergeByName(existing.domains || [], incoming.domains || []),
784
+ compositeTypes: mergeByName(existing.compositeTypes || [], incoming.compositeTypes || []),
785
+ sequences: mergeByName(existing.sequences || [], incoming.sequences || []),
786
+ collations: mergeByName(existing.collations || [], incoming.collations || []),
787
+ tables: mergeByName(existing.tables || [], incoming.tables || []),
788
+ functions: mergeByName(existing.functions || [], incoming.functions || []),
789
+ triggers: mergeByName(existing.triggers || [], incoming.triggers || []),
790
+ views: mergeByName(existing.views || [], incoming.views || []),
791
+ materializedViews: mergeByName(existing.materializedViews || [], incoming.materializedViews || []),
792
+ foreignTables: mergeByName(existing.foreignTables || [], incoming.foreignTables || []),
793
+ };
794
+ }
524
795
  exports.default = importCommand;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logCommand = logCommand;
4
4
  exports.historyCommand = logCommand;
5
+ exports.showCommand = showCommand;
5
6
  const spinner_1 = require("../utils/spinner.cjs");
6
7
  const repo_manager_1 = require("../utils/repo-manager.cjs");
7
8
  function formatDate(timestamp) {
@@ -60,3 +61,77 @@ async function logCommand(context) {
60
61
  console.log('');
61
62
  }
62
63
  }
64
+ async function showCommand(context) {
65
+ const { args } = context;
66
+ const projectRoot = process.cwd();
67
+ const target = args[0];
68
+ console.log('');
69
+ if (!(0, repo_manager_1.isInitialized)(projectRoot)) {
70
+ console.log(`${spinner_1.colors.red('fatal:')} not a relq repository`);
71
+ return;
72
+ }
73
+ if (!target) {
74
+ console.log(`${spinner_1.colors.red('error:')} Please specify a commit or tag`);
75
+ console.log('');
76
+ console.log(`Usage: ${spinner_1.colors.cyan('relq show <commit|tag>')}`);
77
+ console.log('');
78
+ return;
79
+ }
80
+ const fs = require('fs');
81
+ const path = require('path');
82
+ const { resolveRef, loadCommit } = require("../utils/repo-manager.cjs");
83
+ const hash = resolveRef(target, projectRoot);
84
+ if (!hash) {
85
+ console.log(`${spinner_1.colors.red('error:')} Commit or tag not found: ${target}`);
86
+ console.log('');
87
+ console.log('Available commits:');
88
+ const commitsDir = path.join(projectRoot, '.relq', 'commits');
89
+ if (fs.existsSync(commitsDir)) {
90
+ const files = fs.readdirSync(commitsDir);
91
+ for (const f of files.slice(0, 5)) {
92
+ console.log(` ${spinner_1.colors.yellow((0, repo_manager_1.shortHash)(f.replace('.json', '')))}`);
93
+ }
94
+ }
95
+ return;
96
+ }
97
+ const commitPath = path.join(projectRoot, '.relq', 'commits', `${hash}.json`);
98
+ if (!fs.existsSync(commitPath)) {
99
+ console.log(`${spinner_1.colors.red('error:')} Commit not found: ${hash}`);
100
+ return;
101
+ }
102
+ const commitData = JSON.parse(fs.readFileSync(commitPath, 'utf-8'));
103
+ console.log(`${spinner_1.colors.yellow(`commit ${commitData.hash}`)}`);
104
+ console.log(`Author: ${commitData.author}`);
105
+ console.log(`Date: ${formatDate(commitData.timestamp)}`);
106
+ console.log('');
107
+ console.log(` ${commitData.message}`);
108
+ console.log('');
109
+ if (commitData.stats) {
110
+ console.log(`${spinner_1.colors.bold('Stats:')}`);
111
+ console.log(` Tables: ${commitData.stats.tables}`);
112
+ console.log(` Columns: ${commitData.stats.columns}`);
113
+ console.log(` Indexes: ${commitData.stats.indexes || 0}`);
114
+ console.log('');
115
+ }
116
+ if (commitData.changes && commitData.changes.length > 0) {
117
+ console.log(`${spinner_1.colors.bold('Changes:')}`);
118
+ for (const change of commitData.changes.slice(0, 20)) {
119
+ const symbol = change.action === 'CREATE'
120
+ ? spinner_1.colors.green('+')
121
+ : change.action === 'DROP'
122
+ ? spinner_1.colors.red('-')
123
+ : spinner_1.colors.yellow('~');
124
+ console.log(` ${symbol} ${change.objectType.toLowerCase()}: ${change.name}`);
125
+ }
126
+ if (commitData.changes.length > 20) {
127
+ console.log(` ${spinner_1.colors.muted(`... and ${commitData.changes.length - 20} more`)}`);
128
+ }
129
+ console.log('');
130
+ }
131
+ if (commitData.sql && commitData.sql.trim()) {
132
+ console.log(`${spinner_1.colors.bold('SQL:')}`);
133
+ console.log('');
134
+ console.log(`${spinner_1.colors.cyan(commitData.sql)}`);
135
+ console.log('');
136
+ }
137
+ }
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.mergeCommand = mergeCommand;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const spinner_1 = require("../utils/spinner.cjs");
40
+ const repo_manager_1 = require("../utils/repo-manager.cjs");
41
+ function loadBranchState(projectRoot) {
42
+ const branchPath = path.join(projectRoot, '.relq', 'branches.json');
43
+ if (fs.existsSync(branchPath)) {
44
+ return JSON.parse(fs.readFileSync(branchPath, 'utf-8'));
45
+ }
46
+ const head = require("../utils/repo-manager.cjs").getHead(projectRoot);
47
+ return { current: 'main', branches: { main: head || '' } };
48
+ }
49
+ function saveBranchState(state, projectRoot) {
50
+ const branchPath = path.join(projectRoot, '.relq', 'branches.json');
51
+ fs.writeFileSync(branchPath, JSON.stringify(state, null, 2));
52
+ }
53
+ async function mergeCommand(context) {
54
+ const { config, args, flags } = context;
55
+ const projectRoot = process.cwd();
56
+ console.log('');
57
+ if (!(0, repo_manager_1.isInitialized)(projectRoot)) {
58
+ console.log(`${spinner_1.colors.red('fatal:')} not a relq repository`);
59
+ return;
60
+ }
61
+ const branchName = args[0];
62
+ const abort = flags['abort'] === true;
63
+ const mergeStatePath = path.join(projectRoot, '.relq', 'MERGE_STATE');
64
+ if (abort) {
65
+ if (fs.existsSync(mergeStatePath)) {
66
+ fs.unlinkSync(mergeStatePath);
67
+ console.log(`${spinner_1.colors.green('✓')} Merge aborted`);
68
+ }
69
+ else {
70
+ console.log(`${spinner_1.colors.muted('No merge in progress.')}`);
71
+ }
72
+ console.log('');
73
+ return;
74
+ }
75
+ if (fs.existsSync(mergeStatePath)) {
76
+ const mergeState = JSON.parse(fs.readFileSync(mergeStatePath, 'utf-8'));
77
+ console.log(`${spinner_1.colors.red('error:')} Merge in progress from '${mergeState.fromBranch}'`);
78
+ console.log('');
79
+ console.log(`${spinner_1.colors.muted('Use')} ${spinner_1.colors.cyan('relq resolve')} ${spinner_1.colors.muted('to resolve conflicts')}`);
80
+ console.log(`${spinner_1.colors.muted('Or')} ${spinner_1.colors.cyan('relq merge --abort')} ${spinner_1.colors.muted('to cancel')}`);
81
+ console.log('');
82
+ return;
83
+ }
84
+ if (!branchName) {
85
+ console.log(`${spinner_1.colors.red('error:')} Please specify a branch to merge`);
86
+ console.log('');
87
+ console.log(`Usage: ${spinner_1.colors.cyan('relq merge <branch>')}`);
88
+ console.log('');
89
+ return;
90
+ }
91
+ const state = loadBranchState(projectRoot);
92
+ if (!state.branches[branchName]) {
93
+ console.log(`${spinner_1.colors.red('error:')} Branch not found: ${branchName}`);
94
+ return;
95
+ }
96
+ if (branchName === state.current) {
97
+ console.log(`${spinner_1.colors.red('error:')} Cannot merge branch into itself`);
98
+ return;
99
+ }
100
+ const spinner = (0, spinner_1.createSpinner)();
101
+ spinner.start(`Merging '${branchName}' into '${state.current}'...`);
102
+ try {
103
+ const currentHash = (0, repo_manager_1.getHead)(projectRoot);
104
+ const incomingHash = state.branches[branchName];
105
+ if (!currentHash || !incomingHash) {
106
+ spinner.fail('No commits to merge');
107
+ return;
108
+ }
109
+ if (currentHash === incomingHash) {
110
+ spinner.succeed('Already up to date');
111
+ console.log('');
112
+ return;
113
+ }
114
+ const currentCommit = (0, repo_manager_1.loadCommit)(currentHash, projectRoot);
115
+ const incomingCommit = (0, repo_manager_1.loadCommit)(incomingHash, projectRoot);
116
+ if (!currentCommit || !incomingCommit) {
117
+ spinner.fail('Cannot load commit data');
118
+ return;
119
+ }
120
+ const currentSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot) || currentCommit.schema;
121
+ const incomingSnapshot = incomingCommit.schema;
122
+ if (!currentSnapshot || !incomingSnapshot) {
123
+ spinner.fail('No snapshot data');
124
+ return;
125
+ }
126
+ const conflicts = detectMergeConflicts(currentSnapshot, incomingSnapshot);
127
+ if (conflicts.length > 0) {
128
+ const mergeState = {
129
+ fromBranch: branchName,
130
+ toBranch: state.current,
131
+ conflicts,
132
+ incomingSnapshot,
133
+ createdAt: new Date().toISOString(),
134
+ };
135
+ fs.writeFileSync(mergeStatePath, JSON.stringify(mergeState, null, 2));
136
+ spinner.fail(`${conflicts.length} conflict(s) detected`);
137
+ console.log('');
138
+ for (const c of conflicts.slice(0, 5)) {
139
+ const name = c.parentName ? `${c.parentName}.${c.objectName}` : c.objectName;
140
+ console.log(` ${spinner_1.colors.red('conflict:')} ${c.objectType.toLowerCase()} ${name}`);
141
+ }
142
+ if (conflicts.length > 5) {
143
+ console.log(` ${spinner_1.colors.muted(`... and ${conflicts.length - 5} more`)}`);
144
+ }
145
+ console.log('');
146
+ console.log(`${spinner_1.colors.muted('Use')} ${spinner_1.colors.cyan('relq resolve --all-theirs')} ${spinner_1.colors.muted('to accept incoming')}`);
147
+ console.log(`${spinner_1.colors.muted('Or')} ${spinner_1.colors.cyan('relq merge --abort')} ${spinner_1.colors.muted('to cancel')}`);
148
+ console.log('');
149
+ return;
150
+ }
151
+ const mergedSnapshot = mergeSnapshots(currentSnapshot, incomingSnapshot);
152
+ (0, repo_manager_1.saveSnapshot)(mergedSnapshot, projectRoot);
153
+ const author = config?.author || 'Relq CLI';
154
+ const message = `Merge branch '${branchName}' into ${state.current}`;
155
+ const commit = (0, repo_manager_1.createCommit)(mergedSnapshot, author, message, projectRoot);
156
+ spinner.succeed(`Merged '${branchName}' into '${state.current}'`);
157
+ console.log(` ${spinner_1.colors.yellow((0, repo_manager_1.shortHash)(commit.hash))} ${message}`);
158
+ console.log('');
159
+ }
160
+ catch (error) {
161
+ spinner.fail('Merge failed');
162
+ console.error(spinner_1.colors.red(`Error: ${error instanceof Error ? error.message : error}`));
163
+ }
164
+ }
165
+ function detectMergeConflicts(current, incoming) {
166
+ const conflicts = [];
167
+ for (const currentTable of current.tables) {
168
+ const incomingTable = incoming.tables.find(t => t.name === currentTable.name);
169
+ if (!incomingTable)
170
+ continue;
171
+ for (const currentCol of currentTable.columns) {
172
+ const incomingCol = incomingTable.columns.find(c => c.name === currentCol.name);
173
+ if (!incomingCol)
174
+ continue;
175
+ if (currentCol.type !== incomingCol.type) {
176
+ conflicts.push({
177
+ objectType: 'COLUMN',
178
+ objectName: currentCol.name,
179
+ parentName: currentTable.name,
180
+ currentValue: currentCol.type,
181
+ incomingValue: incomingCol.type,
182
+ description: `Type differs: ${currentCol.type} vs ${incomingCol.type}`,
183
+ });
184
+ }
185
+ }
186
+ }
187
+ for (const currentEnum of current.enums) {
188
+ const incomingEnum = incoming.enums.find(e => e.name === currentEnum.name);
189
+ if (!incomingEnum)
190
+ continue;
191
+ const currentVals = JSON.stringify(currentEnum.values.sort());
192
+ const incomingVals = JSON.stringify(incomingEnum.values.sort());
193
+ if (currentVals !== incomingVals) {
194
+ conflicts.push({
195
+ objectType: 'ENUM',
196
+ objectName: currentEnum.name,
197
+ currentValue: currentEnum.values,
198
+ incomingValue: incomingEnum.values,
199
+ description: 'Values differ',
200
+ });
201
+ }
202
+ }
203
+ return conflicts;
204
+ }
205
+ function mergeSnapshots(current, incoming) {
206
+ const result = JSON.parse(JSON.stringify(current));
207
+ for (const table of incoming.tables) {
208
+ if (!result.tables.find(t => t.name === table.name)) {
209
+ result.tables.push(table);
210
+ }
211
+ }
212
+ for (const e of incoming.enums) {
213
+ if (!result.enums.find(x => x.name === e.name)) {
214
+ result.enums.push(e);
215
+ }
216
+ }
217
+ for (const d of incoming.domains) {
218
+ if (!result.domains.find(x => x.name === d.name)) {
219
+ result.domains.push(d);
220
+ }
221
+ }
222
+ return result;
223
+ }
224
+ exports.default = mergeCommand;
@@ -75,7 +75,7 @@ async function migrateCommand(context) {
75
75
  console.log(` Connection: ${(0, env_loader_1.getConnectionDescription)(connection)}`);
76
76
  console.log(` Migrations: ${migrationsDir}\n`);
77
77
  try {
78
- const { Pool } = await Promise.resolve().then(() => __importStar(require("../../../addons/pg.js")));
78
+ const { Pool } = await Promise.resolve().then(() => __importStar(require("../../addon/pg/index.cjs")));
79
79
  const pool = new Pool({
80
80
  host: connection.host,
81
81
  port: connection.port || 5432,