relq 1.0.120 → 1.0.122

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 (79) hide show
  1. package/dist/cjs/cli/commands/diff.cjs +143 -60
  2. package/dist/cjs/cli/commands/fix.cjs +298 -0
  3. package/dist/cjs/cli/commands/generate.cjs +217 -59
  4. package/dist/cjs/cli/commands/import.cjs +1 -0
  5. package/dist/cjs/cli/commands/pull.cjs +28 -4
  6. package/dist/cjs/cli/commands/push.cjs +493 -222
  7. package/dist/cjs/cli/commands/validate.cjs +2 -2
  8. package/dist/cjs/cli/index.cjs +3 -2
  9. package/dist/cjs/cli/utils/ast/codegen/constraints.cjs +12 -7
  10. package/dist/cjs/cli/utils/ast/codegen/defaults.cjs +17 -7
  11. package/dist/cjs/cli/utils/ast-codegen.cjs +135 -6
  12. package/dist/cjs/cli/utils/ast-transformer.cjs +122 -60
  13. package/dist/cjs/cli/utils/config-loader.cjs +3 -3
  14. package/dist/cjs/cli/utils/migration-generator.cjs +727 -531
  15. package/dist/cjs/cli/utils/postgres/introspect.cjs +2 -0
  16. package/dist/cjs/cli/utils/schema-diff.cjs +545 -661
  17. package/dist/cjs/cli/utils/schema-loader.cjs +101 -1
  18. package/dist/cjs/cli/utils/schema-surgeon.cjs +493 -0
  19. package/dist/cjs/cli/utils/schema-to-ast.cjs +66 -15
  20. package/dist/cjs/cli/utils/snapshot-manager.cjs +20 -1
  21. package/dist/cjs/cli/utils/source-id-validator.cjs +266 -0
  22. package/dist/cjs/cli/utils/tracking-id-validator.cjs +180 -0
  23. package/dist/cjs/cli/utils/type-generator.cjs +9 -1
  24. package/dist/cjs/cli/utils/types-manager.cjs +45 -9
  25. package/dist/cjs/cli/utils/ui.cjs +9 -1
  26. package/dist/cjs/cockroachdb-builder.cjs +9 -2
  27. package/dist/cjs/errors/relq-errors.cjs +14 -2
  28. package/dist/cjs/insert/conflict-builder.cjs +44 -29
  29. package/dist/cjs/insert/insert-builder.cjs +5 -2
  30. package/dist/cjs/schema-definition/pg-schema/defaults.cjs +1 -0
  31. package/dist/cjs/schema-definition/pg-schema/index.cjs +13 -2
  32. package/dist/cjs/schema-definition/pg-schema/pg-policy.cjs +103 -0
  33. package/dist/cjs/schema-definition/pg-schema/pg-sequence.cjs +5 -4
  34. package/dist/cjs/schema-definition/pg-schema/pg-view.cjs +79 -10
  35. package/dist/cjs/schema-definition/pg-schema/table-definition/constraints-builder.cjs +27 -11
  36. package/dist/cjs/update/update-builder.cjs +1 -1
  37. package/dist/cockroachdb-builder.d.ts +209 -8
  38. package/dist/config.d.ts +840 -839
  39. package/dist/dsql-builder.d.ts +53 -7
  40. package/dist/esm/cli/commands/diff.js +147 -64
  41. package/dist/esm/cli/commands/fix.js +263 -0
  42. package/dist/esm/cli/commands/generate.js +219 -61
  43. package/dist/esm/cli/commands/import.js +1 -0
  44. package/dist/esm/cli/commands/pull.js +28 -4
  45. package/dist/esm/cli/commands/push.js +495 -224
  46. package/dist/esm/cli/commands/validate.js +2 -2
  47. package/dist/esm/cli/index.js +3 -2
  48. package/dist/esm/cli/utils/ast/codegen/constraints.js +12 -7
  49. package/dist/esm/cli/utils/ast/codegen/defaults.js +17 -7
  50. package/dist/esm/cli/utils/ast-codegen.js +135 -6
  51. package/dist/esm/cli/utils/ast-transformer.js +122 -60
  52. package/dist/esm/cli/utils/config-loader.js +3 -3
  53. package/dist/esm/cli/utils/migration-generator.js +725 -528
  54. package/dist/esm/cli/utils/postgres/introspect.js +2 -0
  55. package/dist/esm/cli/utils/schema-diff.js +545 -653
  56. package/dist/esm/cli/utils/schema-loader.js +102 -2
  57. package/dist/esm/cli/utils/schema-surgeon.js +488 -0
  58. package/dist/esm/cli/utils/schema-to-ast.js +64 -15
  59. package/dist/esm/cli/utils/snapshot-manager.js +20 -1
  60. package/dist/esm/cli/utils/source-id-validator.js +263 -0
  61. package/dist/esm/cli/utils/tracking-id-validator.js +176 -0
  62. package/dist/esm/cli/utils/type-generator.js +9 -1
  63. package/dist/esm/cli/utils/types-manager.js +45 -9
  64. package/dist/esm/cli/utils/ui.js +8 -1
  65. package/dist/esm/cockroachdb-builder.js +1 -0
  66. package/dist/esm/errors/relq-errors.js +14 -2
  67. package/dist/esm/insert/conflict-builder.js +44 -29
  68. package/dist/esm/insert/insert-builder.js +5 -2
  69. package/dist/esm/schema-definition/pg-schema/defaults.js +1 -0
  70. package/dist/esm/schema-definition/pg-schema/index.js +2 -1
  71. package/dist/esm/schema-definition/pg-schema/pg-policy.js +95 -0
  72. package/dist/esm/schema-definition/pg-schema/pg-sequence.js +5 -4
  73. package/dist/esm/schema-definition/pg-schema/pg-view.js +75 -10
  74. package/dist/esm/schema-definition/pg-schema/table-definition/constraints-builder.js +27 -11
  75. package/dist/esm/update/update-builder.js +1 -1
  76. package/dist/index.d.ts +12 -2
  77. package/dist/nile-builder.d.ts +225 -8
  78. package/dist/pg-builder.d.ts +225 -8
  79. package/package.json +14 -15
@@ -44,9 +44,69 @@ const env_loader_1 = require("../utils/env-loader.cjs");
44
44
  const repo_manager_1 = require("../utils/repo-manager.cjs");
45
45
  const snapshot_manager_1 = require("../utils/snapshot-manager.cjs");
46
46
  const schema_diff_1 = require("../utils/schema-diff.cjs");
47
- const schema_hash_1 = require("../utils/schema-hash.cjs");
48
47
  const migration_generator_1 = require("../utils/migration-generator.cjs");
49
48
  const relqignore_1 = require("../utils/relqignore.cjs");
49
+ const schema_loader_1 = require("../utils/schema-loader.cjs");
50
+ const ast_transformer_1 = require("../utils/ast-transformer.cjs");
51
+ function applyIgnorePatterns(comparison, patterns) {
52
+ if (patterns.length === 0)
53
+ return;
54
+ const shouldIgnore = (name) => {
55
+ return patterns.some(pattern => {
56
+ if (pattern.includes('*')) {
57
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
58
+ return regex.test(name);
59
+ }
60
+ return name === pattern;
61
+ });
62
+ };
63
+ comparison.added.tables = comparison.added.tables.filter(t => !shouldIgnore(t.name));
64
+ comparison.removed.tables = comparison.removed.tables.filter(t => !shouldIgnore(t.name));
65
+ comparison.modified.tables = comparison.modified.tables.filter(t => !shouldIgnore(t.name));
66
+ comparison.renamed.tables = comparison.renamed.tables.filter(t => !shouldIgnore(t.from) && !shouldIgnore(t.to));
67
+ comparison.added.columns = comparison.added.columns.filter(c => !shouldIgnore(c.table));
68
+ comparison.removed.columns = comparison.removed.columns.filter(c => !shouldIgnore(c.table));
69
+ comparison.modified.columns = comparison.modified.columns.filter(c => !shouldIgnore(c.table));
70
+ comparison.renamed.columns = comparison.renamed.columns.filter(c => !shouldIgnore(c.table));
71
+ comparison.added.indexes = comparison.added.indexes.filter(i => !shouldIgnore(i.table));
72
+ comparison.removed.indexes = comparison.removed.indexes.filter(i => !shouldIgnore(i.table));
73
+ comparison.modified.indexes = comparison.modified.indexes.filter(i => !shouldIgnore(i.table));
74
+ comparison.renamed.indexes = comparison.renamed.indexes.filter(i => !shouldIgnore(i.table));
75
+ comparison.added.constraints = comparison.added.constraints.filter(c => !shouldIgnore(c.table));
76
+ comparison.removed.constraints = comparison.removed.constraints.filter(c => !shouldIgnore(c.table));
77
+ comparison.modified.constraints = comparison.modified.constraints.filter(c => !shouldIgnore(c.table));
78
+ comparison.renamed.constraints = comparison.renamed.constraints.filter(c => !shouldIgnore(c.table));
79
+ comparison.added.triggers = comparison.added.triggers.filter(t => !shouldIgnore(t.table));
80
+ comparison.removed.triggers = comparison.removed.triggers.filter(t => !shouldIgnore(t.table));
81
+ comparison.modified.triggers = comparison.modified.triggers.filter(t => !shouldIgnore(t.oldTrigger.table));
82
+ }
83
+ function countComparison(comparison) {
84
+ return {
85
+ tables: { added: comparison.added.tables.length, removed: comparison.removed.tables.length, modified: comparison.modified.tables.length, renamed: comparison.renamed.tables.length },
86
+ columns: { added: comparison.added.columns.length, removed: comparison.removed.columns.length, modified: comparison.modified.columns.length, renamed: comparison.renamed.columns.length },
87
+ indexes: { added: comparison.added.indexes.length, removed: comparison.removed.indexes.length, modified: comparison.modified.indexes.length, renamed: comparison.renamed.indexes.length },
88
+ constraints: { added: comparison.added.constraints.length, removed: comparison.removed.constraints.length, modified: comparison.modified.constraints.length, renamed: comparison.renamed.constraints.length },
89
+ enums: { added: comparison.added.enums.length, removed: comparison.removed.enums.length, modified: comparison.modified.enums.length, renamed: comparison.renamed.enums.length },
90
+ sequences: { added: comparison.added.sequences.length, removed: comparison.removed.sequences.length, modified: comparison.modified.sequences.length, renamed: comparison.renamed.sequences.length },
91
+ functions: { added: comparison.added.functions.length, removed: comparison.removed.functions.length, modified: comparison.modified.functions.length, renamed: comparison.renamed.functions.length },
92
+ views: { added: comparison.added.views.length, removed: comparison.removed.views.length, modified: comparison.modified.views.length },
93
+ triggers: { added: comparison.added.triggers.length, removed: comparison.removed.triggers.length, modified: comparison.modified.triggers.length },
94
+ domains: { added: comparison.added.domains.length, removed: comparison.removed.domains.length, modified: comparison.modified.domains.length },
95
+ compositeTypes: { added: comparison.added.compositeTypes.length, removed: comparison.removed.compositeTypes.length, modified: comparison.modified.compositeTypes.length },
96
+ extensions: { added: comparison.added.extensions.length, removed: comparison.removed.extensions.length },
97
+ };
98
+ }
99
+ function renderCategoryLines(label, counts, pushMode) {
100
+ const { added, removed, modified = 0, renamed = 0 } = counts;
101
+ if (added > 0)
102
+ console.log(` ${colors_1.colors.green('+')} ${added} ${label} ${pushMode ? 'to create' : 'in database only'}`);
103
+ if (removed > 0)
104
+ console.log(` ${colors_1.colors.red('-')} ${removed} ${label} ${pushMode ? 'to drop' : 'in local only'}`);
105
+ if (modified > 0)
106
+ console.log(` ${colors_1.colors.yellow('~')} ${modified} ${label} ${pushMode ? 'modified' : 'differ'}`);
107
+ if (renamed > 0)
108
+ console.log(` ${colors_1.colors.cyan('→')} ${renamed} ${label} renamed`);
109
+ }
50
110
  exports.default = (0, citty_1.defineCommand)({
51
111
  meta: { name: 'diff', description: 'Show schema differences' },
52
112
  args: {
@@ -63,95 +123,118 @@ exports.default = (0, citty_1.defineCommand)({
63
123
  const connection = config.connection;
64
124
  const includeFunctions = config.includeFunctions ?? false;
65
125
  const includeTriggers = config.includeTriggers ?? false;
126
+ const schemaPath = (0, config_loader_1.getSchemaPath)(config);
66
127
  const snapshotPath = config.sync?.snapshot || '.relq/snapshot.json';
67
- const snapshot = (0, snapshot_manager_1.loadSnapshot)(snapshotPath);
68
- if (!snapshot) {
69
- console.log(`${colors_1.colors.yellow('No local snapshot.')}`);
70
- console.log(`${colors_1.colors.muted('Run')} ${colors_1.colors.cyan('relq pull')} ${colors_1.colors.muted('first.')}`);
71
- console.log('');
72
- return;
73
- }
74
128
  const ignorePatterns = (0, relqignore_1.loadRelqignore)(projectRoot);
129
+ const rawPatterns = ignorePatterns.map(pat => pat.raw);
75
130
  const spin = p.spinner();
76
131
  try {
132
+ spin.start('Loading local schema file...');
133
+ const { ast: desiredAST } = await (0, schema_loader_1.loadSchemaFile)(schemaPath, projectRoot, config);
134
+ spin.stop('Schema file loaded');
77
135
  spin.start(`Connecting to ${(0, env_loader_1.getConnectionDescription)(connection)}...`);
78
136
  const dbSchema = await (0, dialect_introspect_1.dialectIntrospect)(config, {
79
137
  includeFunctions,
80
138
  includeTriggers,
81
139
  });
82
140
  spin.stop(`Connected — ${dbSchema.tables.length} tables in database`);
83
- const localSchema = (0, snapshot_manager_1.snapshotToDatabaseSchema)(snapshot);
84
- const rawPatterns = ignorePatterns.map(pat => pat.raw);
85
- const pushDiff = (0, schema_diff_1.diffSchemas)((0, schema_hash_1.normalizeSchema)(dbSchema), (0, schema_hash_1.normalizeSchema)(localSchema));
86
- const filteredPushDiff = (0, schema_diff_1.filterDiff)(pushDiff, rawPatterns);
87
- const pullDiff = (0, schema_diff_1.diffSchemas)((0, schema_hash_1.normalizeSchema)(localSchema), (0, schema_hash_1.normalizeSchema)(dbSchema));
88
- const filteredPullDiff = (0, schema_diff_1.filterDiff)(pullDiff, rawPatterns);
141
+ spin.start('Analyzing database schema...');
142
+ const dbParsedSchema = await (0, ast_transformer_1.introspectedToParsedSchema)(dbSchema);
143
+ const snapshot = (0, snapshot_manager_1.loadSnapshot)(snapshotPath);
144
+ if (snapshot && snapshot.tables) {
145
+ for (const dbTable of dbParsedSchema.tables) {
146
+ const snapTable = snapshot.tables[dbTable.name];
147
+ if (!snapTable)
148
+ continue;
149
+ if (snapTable.trackingId)
150
+ dbTable.trackingId = snapTable.trackingId;
151
+ for (const dbCol of dbTable.columns) {
152
+ const snapCol = snapTable.columns?.[dbCol.name];
153
+ if (snapCol?.trackingId)
154
+ dbCol.trackingId = snapCol.trackingId;
155
+ }
156
+ for (const dbIdx of dbTable.indexes) {
157
+ const snapIdx = snapTable.indexes?.[dbIdx.name];
158
+ if (snapIdx?.trackingId)
159
+ dbIdx.trackingId = snapIdx.trackingId;
160
+ }
161
+ for (const dbCon of dbTable.constraints) {
162
+ const snapCon = snapTable.constraints?.[dbCon.name];
163
+ if (snapCon?.trackingId)
164
+ dbCon.trackingId = snapCon.trackingId;
165
+ }
166
+ }
167
+ }
168
+ spin.stop('Schema analyzed');
169
+ const pushComparison = (0, schema_diff_1.compareSchemas)(dbParsedSchema, desiredAST);
170
+ applyIgnorePatterns(pushComparison, rawPatterns);
171
+ const pullComparison = (0, schema_diff_1.compareSchemas)(desiredAST, dbParsedSchema);
172
+ applyIgnorePatterns(pullComparison, rawPatterns);
89
173
  if (args.json) {
90
174
  console.log(JSON.stringify({
91
- pushChanges: filteredPushDiff.summary,
92
- pullChanges: filteredPullDiff.summary,
93
- hasPushChanges: filteredPushDiff.hasChanges,
94
- hasPullChanges: filteredPullDiff.hasChanges,
175
+ push: countComparison(pushComparison),
176
+ pull: countComparison(pullComparison),
177
+ hasPushChanges: pushComparison.hasChanges,
178
+ hasPullChanges: pullComparison.hasChanges,
95
179
  }, null, 2));
96
180
  return;
97
181
  }
98
- if (!filteredPushDiff.hasChanges && !filteredPullDiff.hasChanges) {
182
+ if (!pushComparison.hasChanges && !pullComparison.hasChanges) {
99
183
  console.log('');
100
184
  console.log(`${colors_1.colors.green('Local and database are in sync.')}`);
101
185
  console.log('');
102
186
  return;
103
187
  }
104
- if (filteredPushDiff.hasChanges) {
105
- const s = filteredPushDiff.summary;
188
+ if (pushComparison.hasChanges) {
189
+ const c = countComparison(pushComparison);
106
190
  console.log('');
107
191
  console.log(`${colors_1.colors.bold('Local changes')} ${colors_1.colors.muted('(push to apply)')}`);
108
192
  console.log('');
109
- if (s.tablesAdded > 0)
110
- console.log(` ${colors_1.colors.green('+')} ${s.tablesAdded} table(s) to create`);
111
- if (s.tablesRemoved > 0)
112
- console.log(` ${colors_1.colors.red('-')} ${s.tablesRemoved} table(s) to drop`);
113
- if (s.tablesModified > 0)
114
- console.log(` ${colors_1.colors.yellow('~')} ${s.tablesModified} table(s) modified`);
115
- if (s.columnsAdded > 0)
116
- console.log(` ${colors_1.colors.green('+')} ${s.columnsAdded} column(s) to add`);
117
- if (s.columnsRemoved > 0)
118
- console.log(` ${colors_1.colors.red('-')} ${s.columnsRemoved} column(s) to drop`);
119
- if (s.columnsModified > 0)
120
- console.log(` ${colors_1.colors.yellow('~')} ${s.columnsModified} column(s) modified`);
193
+ renderCategoryLines('table(s)', c.tables, true);
194
+ renderCategoryLines('column(s)', c.columns, true);
195
+ renderCategoryLines('index(es)', c.indexes, true);
196
+ renderCategoryLines('constraint(s)', c.constraints, true);
197
+ renderCategoryLines('enum(s)', c.enums, true);
198
+ renderCategoryLines('sequence(s)', c.sequences, true);
199
+ renderCategoryLines('function(s)', c.functions, true);
200
+ renderCategoryLines('view(s)', c.views, true);
201
+ renderCategoryLines('trigger(s)', c.triggers, true);
202
+ renderCategoryLines('domain(s)', c.domains, true);
203
+ renderCategoryLines('composite type(s)', c.compositeTypes, true);
204
+ renderCategoryLines('extension(s)', c.extensions, true);
121
205
  }
122
- if (filteredPullDiff.hasChanges) {
123
- const s = filteredPullDiff.summary;
206
+ if (pullComparison.hasChanges) {
207
+ const c = countComparison(pullComparison);
124
208
  console.log('');
125
209
  console.log(`${colors_1.colors.bold('Database drift')} ${colors_1.colors.muted('(pull to sync)')}`);
126
210
  console.log('');
127
- if (s.tablesAdded > 0)
128
- console.log(` ${colors_1.colors.green('+')} ${s.tablesAdded} table(s) in database only`);
129
- if (s.tablesRemoved > 0)
130
- console.log(` ${colors_1.colors.red('-')} ${s.tablesRemoved} table(s) in local only`);
131
- if (s.tablesModified > 0)
132
- console.log(` ${colors_1.colors.yellow('~')} ${s.tablesModified} table(s) differ`);
133
- if (s.columnsAdded > 0)
134
- console.log(` ${colors_1.colors.green('+')} ${s.columnsAdded} column(s) in database only`);
135
- if (s.columnsRemoved > 0)
136
- console.log(` ${colors_1.colors.red('-')} ${s.columnsRemoved} column(s) in local only`);
137
- if (s.columnsModified > 0)
138
- console.log(` ${colors_1.colors.yellow('~')} ${s.columnsModified} column(s) differ`);
211
+ renderCategoryLines('table(s)', c.tables, false);
212
+ renderCategoryLines('column(s)', c.columns, false);
213
+ renderCategoryLines('index(es)', c.indexes, false);
214
+ renderCategoryLines('constraint(s)', c.constraints, false);
215
+ renderCategoryLines('enum(s)', c.enums, false);
216
+ renderCategoryLines('sequence(s)', c.sequences, false);
217
+ renderCategoryLines('function(s)', c.functions, false);
218
+ renderCategoryLines('view(s)', c.views, false);
219
+ renderCategoryLines('trigger(s)', c.triggers, false);
220
+ renderCategoryLines('domain(s)', c.domains, false);
221
+ renderCategoryLines('composite type(s)', c.compositeTypes, false);
222
+ renderCategoryLines('extension(s)', c.extensions, false);
139
223
  }
140
- if (args.sql && filteredPushDiff.hasChanges) {
224
+ if (args.sql && pushComparison.hasChanges) {
141
225
  console.log('');
142
226
  console.log(`${colors_1.colors.bold('SQL Preview')} ${colors_1.colors.muted('(what push would execute)')}`);
143
227
  console.log('');
144
- const migration = (0, migration_generator_1.generateMigrationFile)(filteredPushDiff, 'diff-preview', {
145
- includeDown: false,
146
- includeComments: false,
147
- });
148
- if (migration.content.trim()) {
149
- const statements = migration.content.split(';').filter(s => s.trim());
150
- for (const stmt of statements.slice(0, 20)) {
151
- console.log(` ${colors_1.colors.cyan(stmt.trim())};`);
228
+ const migration = (0, migration_generator_1.generateMigrationFromComparison)(pushComparison);
229
+ const formatted = (0, migration_generator_1.formatMigrationStatements)(migration.up);
230
+ if (formatted.length > 0) {
231
+ for (const line of formatted.slice(0, 30)) {
232
+ console.log(` ${line.startsWith('--') ? colors_1.colors.muted(line) : colors_1.colors.cyan(line)}`);
152
233
  }
153
- if (statements.length > 20) {
154
- console.log(` ${colors_1.colors.muted(`... and ${statements.length - 20} more statements`)}`);
234
+ const stmtCount = formatted.filter(l => l.trim() && !l.trim().startsWith('--')).length;
235
+ const totalStmts = migration.up.length;
236
+ if (totalStmts > 20) {
237
+ console.log(` ${colors_1.colors.muted(`... and ${totalStmts - 20} more statements`)}`);
155
238
  }
156
239
  }
157
240
  else {
@@ -159,10 +242,10 @@ exports.default = (0, citty_1.defineCommand)({
159
242
  }
160
243
  }
161
244
  console.log('');
162
- if (filteredPushDiff.hasChanges) {
245
+ if (pushComparison.hasChanges) {
163
246
  console.log(`${colors_1.colors.muted('Run')} ${colors_1.colors.cyan('relq push')} ${colors_1.colors.muted('to apply local changes to database.')}`);
164
247
  }
165
- if (filteredPullDiff.hasChanges) {
248
+ if (pullComparison.hasChanges) {
166
249
  console.log(`${colors_1.colors.muted('Run')} ${colors_1.colors.cyan('relq pull')} ${colors_1.colors.muted('to sync local with database.')}`);
167
250
  }
168
251
  console.log('');
@@ -0,0 +1,298 @@
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
+ const citty_1 = require("citty");
37
+ const fs = __importStar(require("node:fs"));
38
+ const path = __importStar(require("node:path"));
39
+ const context_1 = require("../utils/context.cjs");
40
+ const colors_1 = require("../utils/colors.cjs");
41
+ const ui_1 = require("../utils/ui.cjs");
42
+ const config_loader_1 = require("../utils/config-loader.cjs");
43
+ const schema_loader_1 = require("../utils/schema-loader.cjs");
44
+ const tracking_id_validator_1 = require("../utils/tracking-id-validator.cjs");
45
+ const source_id_validator_1 = require("../utils/source-id-validator.cjs");
46
+ const ast_codegen_1 = require("../utils/ast-codegen.cjs");
47
+ const repo_manager_1 = require("../utils/repo-manager.cjs");
48
+ const schema_surgeon_1 = require("../utils/schema-surgeon.cjs");
49
+ function clearDuplicateTrackingIds(schema) {
50
+ let fixCount = 0;
51
+ const tableIds = new Map();
52
+ for (const table of schema.tables) {
53
+ if (table.partitionOf)
54
+ continue;
55
+ if (table.trackingId) {
56
+ if (tableIds.has(table.trackingId)) {
57
+ table.trackingId = undefined;
58
+ fixCount++;
59
+ }
60
+ else {
61
+ tableIds.set(table.trackingId, true);
62
+ }
63
+ }
64
+ }
65
+ for (const table of schema.tables) {
66
+ if (table.partitionOf)
67
+ continue;
68
+ const colIds = new Map();
69
+ for (const col of table.columns) {
70
+ if (col.trackingId) {
71
+ if (colIds.has(col.trackingId)) {
72
+ col.trackingId = undefined;
73
+ fixCount++;
74
+ }
75
+ else {
76
+ colIds.set(col.trackingId, true);
77
+ }
78
+ }
79
+ }
80
+ const idxIds = new Map();
81
+ for (const idx of table.indexes) {
82
+ if (idx.trackingId) {
83
+ if (idxIds.has(idx.trackingId)) {
84
+ idx.trackingId = undefined;
85
+ fixCount++;
86
+ }
87
+ else {
88
+ idxIds.set(idx.trackingId, true);
89
+ }
90
+ }
91
+ }
92
+ const conIds = new Map();
93
+ for (const con of table.constraints) {
94
+ if (con.trackingId) {
95
+ if (colIds.has(con.trackingId))
96
+ continue;
97
+ if (conIds.has(con.trackingId)) {
98
+ con.trackingId = undefined;
99
+ fixCount++;
100
+ }
101
+ else {
102
+ conIds.set(con.trackingId, true);
103
+ }
104
+ }
105
+ }
106
+ }
107
+ return fixCount;
108
+ }
109
+ function buildExportMap(schemaModule) {
110
+ const map = new Map();
111
+ for (const [key, value] of Object.entries(schemaModule)) {
112
+ if (!value || typeof value !== 'object')
113
+ continue;
114
+ if (value.$name && typeof value.$name === 'string') {
115
+ map.set(value.$name, key);
116
+ }
117
+ else if (value.$enumName && typeof value.$enumName === 'string') {
118
+ map.set(value.$enumName, key);
119
+ }
120
+ else if (value.$domainName && typeof value.$domainName === 'string') {
121
+ map.set(value.$domainName, key);
122
+ }
123
+ else if (value.$sequenceName && typeof value.$sequenceName === 'string') {
124
+ map.set(value.$sequenceName, key);
125
+ }
126
+ else if (value.$functionName && typeof value.$functionName === 'string') {
127
+ map.set(value.$functionName, key);
128
+ }
129
+ else if (value.$triggerName && typeof value.$triggerName === 'string') {
130
+ map.set(value.$triggerName, key);
131
+ }
132
+ else if (value.$viewName && typeof value.$viewName === 'string') {
133
+ map.set(value.$viewName, key);
134
+ }
135
+ }
136
+ return map;
137
+ }
138
+ exports.default = (0, citty_1.defineCommand)({
139
+ meta: { name: 'fix', description: 'Auto-repair tracking ID issues in schema' },
140
+ args: {
141
+ schema: { type: 'positional', description: 'Schema file path (optional)', required: false },
142
+ dryRun: { type: 'boolean', alias: 'dry-run', description: 'Show what would be fixed without writing' },
143
+ },
144
+ async run({ args }) {
145
+ const { config, projectRoot } = await (0, context_1.buildContext)({ requireConfig: true });
146
+ if (!config)
147
+ return (0, ui_1.fatal)('No relq.config.ts found. Run `relq init` first.');
148
+ console.log('');
149
+ let schemaPath;
150
+ if (args.schema) {
151
+ schemaPath = path.resolve(projectRoot, args.schema);
152
+ }
153
+ else {
154
+ schemaPath = path.resolve(projectRoot, (0, config_loader_1.getSchemaPath)(config));
155
+ }
156
+ const relativePath = path.relative(process.cwd(), schemaPath);
157
+ if (!fs.existsSync(schemaPath)) {
158
+ return (0, ui_1.fatal)(`Schema file not found: ${relativePath}`);
159
+ }
160
+ console.log(` Scanning ${colors_1.colors.cyan(relativePath)}...`);
161
+ const rawContent = fs.readFileSync(schemaPath, 'utf-8');
162
+ const sourceIssues = (0, source_id_validator_1.validateSourceTrackingIds)(schemaPath, rawContent);
163
+ let result;
164
+ try {
165
+ result = await (0, schema_loader_1.loadSchemaFile)(schemaPath, projectRoot, config);
166
+ }
167
+ catch (err) {
168
+ return (0, ui_1.fatal)(`Failed to load schema: ${err.message}`);
169
+ }
170
+ const { ast: parsedSchema } = result;
171
+ const runtimeIssues = (0, tracking_id_validator_1.validateTrackingIds)(parsedSchema);
172
+ const runtimeDuplicates = runtimeIssues.filter(i => i.kind === 'duplicate');
173
+ const runtimeMissing = runtimeIssues.filter(i => i.kind === 'missing');
174
+ const sourceLocations = new Set(sourceIssues.map(i => i.location));
175
+ const extraRuntimeMissing = runtimeMissing.filter(i => !sourceLocations.has(i.location));
176
+ const issuesBefore = [...sourceIssues, ...extraRuntimeMissing, ...runtimeDuplicates];
177
+ if (issuesBefore.length === 0) {
178
+ console.log('');
179
+ console.log(` ${colors_1.colors.green('✔')} ${colors_1.colors.bold('No issues found')} — schema tracking IDs are clean.`);
180
+ console.log('');
181
+ return;
182
+ }
183
+ const missingIssues = issuesBefore.filter(i => i.kind === 'missing');
184
+ const duplicateIssues = issuesBefore.filter(i => i.kind === 'duplicate');
185
+ if (args.dryRun) {
186
+ console.log('');
187
+ console.log((0, tracking_id_validator_1.formatTrackingIdIssues)(issuesBefore));
188
+ console.log('');
189
+ console.log(colors_1.colors.dim(' Dry run — no changes written.'));
190
+ console.log('');
191
+ return;
192
+ }
193
+ for (const issue of sourceIssues) {
194
+ if (issue.kind !== 'missing')
195
+ continue;
196
+ const parts = issue.location.split('.');
197
+ const tableName = parts[0];
198
+ const entityName = parts.slice(1).join('.');
199
+ const table = parsedSchema.tables.find(t => t.name === tableName);
200
+ if (!table)
201
+ continue;
202
+ if (issue.entity === 'index' && entityName) {
203
+ const idx = table.indexes.find(i => i.name === entityName);
204
+ if (idx)
205
+ idx.trackingId = undefined;
206
+ }
207
+ else if (issue.entity === 'constraint' && entityName) {
208
+ const con = table.constraints.find(c => c.name === entityName);
209
+ if (con)
210
+ con.trackingId = undefined;
211
+ }
212
+ }
213
+ const dupsFixed = clearDuplicateTrackingIds(parsedSchema);
214
+ (0, ast_codegen_1.assignTrackingIds)(parsedSchema);
215
+ const { createJiti } = await Promise.resolve().then(() => __importStar(require('jiti')));
216
+ const jiti = createJiti(projectRoot, { interopDefault: true });
217
+ const schemaModule = await jiti.import(schemaPath);
218
+ const exportMap = buildExportMap(schemaModule);
219
+ const tableIssues = issuesBefore.filter(i => i.entity === 'table' || i.entity === 'column' || i.entity === 'index' || i.entity === 'constraint');
220
+ const edits = (0, schema_surgeon_1.computeTrackingIdEdits)(schemaPath, rawContent, tableIssues, parsedSchema, exportMap);
221
+ const enumNames = new Set(parsedSchema.enums.map(e => e.name));
222
+ const domainNames = new Set(parsedSchema.domains.map(d => d.name));
223
+ const seqNames = new Set(parsedSchema.sequences.map(s => s.name));
224
+ for (const issue of issuesBefore) {
225
+ if (issue.entity !== 'table')
226
+ continue;
227
+ const name = issue.location;
228
+ if (enumNames.has(name)) {
229
+ const enumEdits = (0, schema_surgeon_1.computeTopLevelEdits)(schemaPath, rawContent, 'enum', parsedSchema.enums, exportMap, [issue]);
230
+ edits.push(...enumEdits);
231
+ }
232
+ else if (domainNames.has(name)) {
233
+ const domainEdits = (0, schema_surgeon_1.computeTopLevelEdits)(schemaPath, rawContent, 'domain', parsedSchema.domains, exportMap, [issue]);
234
+ edits.push(...domainEdits);
235
+ }
236
+ else if (seqNames.has(name)) {
237
+ const seqEdits = (0, schema_surgeon_1.computeTopLevelEdits)(schemaPath, rawContent, 'sequence', parsedSchema.sequences, exportMap, [issue]);
238
+ edits.push(...seqEdits);
239
+ }
240
+ }
241
+ if (edits.length === 0) {
242
+ console.log('');
243
+ console.log(colors_1.colors.dim(' Could not locate all entities in source — falling back to regeneration.'));
244
+ const { generateTypeScriptFromAST } = await Promise.resolve().then(() => __importStar(require("../utils/ast-codegen.cjs")));
245
+ const { detectDialect, getBuilderImportPath } = await Promise.resolve().then(() => __importStar(require("../utils/dialect-router.cjs")));
246
+ const dialect = detectDialect(config);
247
+ const builderImportPath = getBuilderImportPath(dialect);
248
+ const schemaBaseName = path.basename(schemaPath, '.ts');
249
+ const typesImportPath = `./${schemaBaseName}.types`;
250
+ const typescript = generateTypeScriptFromAST(parsedSchema, {
251
+ camelCase: config.generate?.camelCase ?? true,
252
+ importPath: builderImportPath,
253
+ includeFunctions: false,
254
+ includeTriggers: false,
255
+ columnTypeMap: {},
256
+ typesImportPath,
257
+ });
258
+ fs.writeFileSync(schemaPath, typescript, 'utf-8');
259
+ const fileHash = (0, repo_manager_1.hashFileContent)(typescript);
260
+ (0, repo_manager_1.saveFileHash)(fileHash, projectRoot);
261
+ }
262
+ else {
263
+ const fixed = (0, schema_surgeon_1.applyEdits)(rawContent, edits);
264
+ fs.writeFileSync(schemaPath, fixed, 'utf-8');
265
+ const fileHash = (0, repo_manager_1.hashFileContent)(fixed);
266
+ (0, repo_manager_1.saveFileHash)(fileHash, projectRoot);
267
+ }
268
+ const fixedContent = fs.readFileSync(schemaPath, 'utf-8');
269
+ const sourceIssuesAfter = (0, source_id_validator_1.validateSourceTrackingIds)(schemaPath, fixedContent);
270
+ const reloaded = await (0, schema_loader_1.loadSchemaFile)(schemaPath, projectRoot, config);
271
+ const runtimeIssuesAfter = (0, tracking_id_validator_1.validateTrackingIds)(reloaded.ast);
272
+ const remainingErrors = [
273
+ ...sourceIssuesAfter,
274
+ ...runtimeIssuesAfter.filter(i => i.severity === 'error'),
275
+ ];
276
+ if (remainingErrors.length > 0) {
277
+ console.log('');
278
+ console.log((0, tracking_id_validator_1.formatTrackingIdIssues)(remainingErrors));
279
+ console.log('');
280
+ return (0, ui_1.fatal)('Some issues could not be auto-fixed.');
281
+ }
282
+ console.log('');
283
+ console.log(` ${colors_1.colors.green('✔')} ${colors_1.colors.bold('All issues fixed')}`);
284
+ console.log(colors_1.colors.dim(' ───────────────────────────────────'));
285
+ if (edits.length > 0) {
286
+ console.log(` ${colors_1.colors.green('●')} ${edits.length} surgical edit(s) applied`);
287
+ }
288
+ if (missingIssues.length > 0) {
289
+ console.log(` ${colors_1.colors.green('+')} ${missingIssues.length} missing ID(s) generated`);
290
+ }
291
+ if (dupsFixed > 0) {
292
+ console.log(` ${colors_1.colors.green('~')} ${dupsFixed} duplicate ID(s) regenerated`);
293
+ }
294
+ console.log('');
295
+ console.log(` Updated ${colors_1.colors.cyan(relativePath)}`);
296
+ console.log('');
297
+ },
298
+ });