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
|
@@ -36,17 +36,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.pullCommand = pullCommand;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
-
const readline = __importStar(require("readline"));
|
|
40
39
|
const config_loader_1 = require("../utils/config-loader.cjs");
|
|
41
40
|
const fast_introspect_1 = require("../utils/fast-introspect.cjs");
|
|
42
41
|
const type_generator_1 = require("../utils/type-generator.cjs");
|
|
43
42
|
const env_loader_1 = require("../utils/env-loader.cjs");
|
|
44
|
-
const
|
|
43
|
+
const cli_utils_1 = require("../utils/cli-utils.cjs");
|
|
45
44
|
const relqignore_1 = require("../utils/relqignore.cjs");
|
|
46
45
|
const repo_manager_1 = require("../utils/repo-manager.cjs");
|
|
46
|
+
const schema_comparator_1 = require("../utils/schema-comparator.cjs");
|
|
47
47
|
function toCamelCase(str) {
|
|
48
48
|
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
49
49
|
}
|
|
50
|
+
function normalizePartitionKey(partitionKey) {
|
|
51
|
+
if (!partitionKey)
|
|
52
|
+
return undefined;
|
|
53
|
+
if (Array.isArray(partitionKey)) {
|
|
54
|
+
return partitionKey;
|
|
55
|
+
}
|
|
56
|
+
if (typeof partitionKey === 'string') {
|
|
57
|
+
return partitionKey
|
|
58
|
+
.replace(/^\{|\}$/g, '')
|
|
59
|
+
.split(',')
|
|
60
|
+
.map(k => k.trim())
|
|
61
|
+
.filter(Boolean);
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
50
65
|
function parseSchemaFileForSnapshot(schemaPath) {
|
|
51
66
|
if (!fs.existsSync(schemaPath)) {
|
|
52
67
|
return null;
|
|
@@ -152,86 +167,70 @@ function parseSchemaFileForSnapshot(schemaPath) {
|
|
|
152
167
|
extensions: [],
|
|
153
168
|
};
|
|
154
169
|
}
|
|
155
|
-
function askConfirm(question, defaultYes = true) {
|
|
156
|
-
const suffix = defaultYes ? spinner_1.colors.muted('[Y/n]') : spinner_1.colors.muted('[y/N]');
|
|
157
|
-
const rl = readline.createInterface({
|
|
158
|
-
input: process.stdin,
|
|
159
|
-
output: process.stdout,
|
|
160
|
-
});
|
|
161
|
-
return new Promise((resolve) => {
|
|
162
|
-
rl.question(`${question} ${suffix}: `, (answer) => {
|
|
163
|
-
rl.close();
|
|
164
|
-
const a = answer.trim().toLowerCase();
|
|
165
|
-
if (!a)
|
|
166
|
-
resolve(defaultYes);
|
|
167
|
-
else
|
|
168
|
-
resolve(a === 'y' || a === 'yes');
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
170
|
async function pullCommand(context) {
|
|
173
|
-
const { config, flags } = context;
|
|
171
|
+
const { config, flags, projectRoot } = context;
|
|
174
172
|
if (!config) {
|
|
175
|
-
|
|
176
|
-
process.exit(1);
|
|
173
|
+
(0, cli_utils_1.fatal)('No configuration found', `Run ${cli_utils_1.colors.cyan('relq init')} to create one.`);
|
|
177
174
|
}
|
|
178
|
-
(0, config_loader_1.requireValidConfig)(config);
|
|
175
|
+
await (0, config_loader_1.requireValidConfig)(config, { calledFrom: 'pull' });
|
|
179
176
|
const connection = config.connection;
|
|
180
|
-
const projectRoot = process.cwd();
|
|
181
177
|
const force = flags['force'] === true;
|
|
178
|
+
const merge = flags['merge'] === true;
|
|
179
|
+
const noCommit = flags['no-commit'] === true;
|
|
182
180
|
const dryRun = flags['dry-run'] === true;
|
|
183
181
|
const author = config.author || 'Relq CLI';
|
|
184
|
-
const
|
|
182
|
+
const schemaPathRaw = typeof config.schema === 'string' ? config.schema : './db/schema.ts';
|
|
183
|
+
const schemaPath = path.resolve(projectRoot, schemaPathRaw);
|
|
185
184
|
const includeFunctions = config.generate?.includeFunctions ?? false;
|
|
186
185
|
const includeTriggers = config.generate?.includeTriggers ?? false;
|
|
187
|
-
const spinner = (0,
|
|
186
|
+
const spinner = (0, cli_utils_1.createSpinner)();
|
|
188
187
|
const startTime = Date.now();
|
|
189
188
|
console.log('');
|
|
190
189
|
if (!(0, repo_manager_1.isInitialized)(projectRoot)) {
|
|
191
190
|
(0, repo_manager_1.initRepository)(projectRoot);
|
|
192
|
-
console.log(
|
|
191
|
+
console.log('Initialized .relq folder');
|
|
193
192
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
const stagedChanges = (0, repo_manager_1.getStagedChanges)(projectRoot);
|
|
194
|
+
const unstagedChanges = (0, repo_manager_1.getUnstagedChanges)(projectRoot);
|
|
195
|
+
const hasLocalChanges = stagedChanges.length > 0 || unstagedChanges.length > 0;
|
|
196
|
+
let stashedSchemaContent = null;
|
|
197
|
+
const schemaFileExists = fs.existsSync(schemaPath);
|
|
198
|
+
if (hasLocalChanges) {
|
|
199
|
+
if (force) {
|
|
200
|
+
(0, repo_manager_1.clearWorkingState)(projectRoot);
|
|
201
|
+
}
|
|
202
|
+
else if (merge) {
|
|
203
|
+
if (schemaFileExists) {
|
|
204
|
+
stashedSchemaContent = fs.readFileSync(schemaPath, 'utf-8');
|
|
205
|
+
}
|
|
206
|
+
(0, repo_manager_1.clearWorkingState)(projectRoot);
|
|
207
|
+
console.log(`Stashed local file content for restore after pull`);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
198
210
|
const hasUnstaged = unstagedChanges.length > 0;
|
|
199
211
|
const hasStaged = stagedChanges.length > 0;
|
|
200
|
-
if (hasUnstaged && hasStaged) {
|
|
201
|
-
console.error(spinner_1.colors.red('Error: You have uncommitted and unstaged changes.'));
|
|
202
|
-
}
|
|
203
|
-
else if (hasStaged) {
|
|
204
|
-
console.error(spinner_1.colors.red('Error: You have uncommitted changes.'));
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
console.error(spinner_1.colors.red('Error: You have unstaged changes.'));
|
|
208
|
-
}
|
|
209
212
|
console.log('');
|
|
210
213
|
if (hasStaged) {
|
|
211
|
-
console.log(` ${
|
|
214
|
+
console.log(` ${cli_utils_1.colors.green('Staged (uncommitted):')} ${stagedChanges.length} change(s)`);
|
|
212
215
|
}
|
|
213
216
|
if (hasUnstaged) {
|
|
214
|
-
console.log(` ${
|
|
217
|
+
console.log(` ${cli_utils_1.colors.red('Unstaged:')} ${unstagedChanges.length} change(s)`);
|
|
215
218
|
}
|
|
216
|
-
|
|
217
|
-
if (hasUnstaged &&
|
|
218
|
-
|
|
219
|
-
console.log(` ${spinner_1.colors.cyan('relq add .')} - stage all changes`);
|
|
220
|
-
console.log(` ${spinner_1.colors.cyan('relq commit -m "message"')} - then commit`);
|
|
219
|
+
let errorMsg = 'You have uncommitted changes';
|
|
220
|
+
if (hasUnstaged && hasStaged) {
|
|
221
|
+
errorMsg = 'You have uncommitted and unstaged changes';
|
|
221
222
|
}
|
|
222
|
-
else {
|
|
223
|
-
|
|
224
|
-
console.log(` ${spinner_1.colors.cyan('relq commit -m "message"')} - commit staged changes`);
|
|
223
|
+
else if (hasUnstaged) {
|
|
224
|
+
errorMsg = 'You have unstaged changes';
|
|
225
225
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
return;
|
|
226
|
+
const hint = `Commit first: ${cli_utils_1.colors.cyan('relq add . && relq commit -m "message"')}\nOr merge: ${cli_utils_1.colors.cyan('relq pull --merge')} (preserve local edits)\nOr force: ${cli_utils_1.colors.cyan('relq pull --force')} (discard & pull)`;
|
|
227
|
+
(0, cli_utils_1.fatal)(errorMsg, hint);
|
|
229
228
|
}
|
|
230
229
|
}
|
|
231
230
|
try {
|
|
232
231
|
spinner.start('Connecting to database...');
|
|
233
232
|
await (0, repo_manager_1.ensureRemoteTable)(connection);
|
|
234
|
-
spinner.succeed(`Connected to ${
|
|
233
|
+
spinner.succeed(`Connected to ${cli_utils_1.colors.cyan((0, env_loader_1.getConnectionDescription)(connection))}`);
|
|
235
234
|
spinner.start('Fetching remote commits...');
|
|
236
235
|
const remoteCommits = await (0, repo_manager_1.fetchRemoteCommits)(connection, 100);
|
|
237
236
|
const remoteHead = remoteCommits.length > 0 ? remoteCommits[0].hash : null;
|
|
@@ -290,6 +289,9 @@ async function pullCommand(context) {
|
|
|
290
289
|
type: c.type,
|
|
291
290
|
definition: c.definition,
|
|
292
291
|
})),
|
|
292
|
+
isPartitioned: t.isPartitioned,
|
|
293
|
+
partitionType: t.partitionType,
|
|
294
|
+
partitionKey: normalizePartitionKey(t.partitionKey),
|
|
293
295
|
})),
|
|
294
296
|
enums: filteredEnums.map(e => ({
|
|
295
297
|
name: e.name,
|
|
@@ -330,12 +332,7 @@ async function pullCommand(context) {
|
|
|
330
332
|
console.log('');
|
|
331
333
|
const mergeStatePath = path.join(projectRoot, '.relq', 'MERGE_STATE');
|
|
332
334
|
if (fs.existsSync(mergeStatePath) && !force) {
|
|
333
|
-
|
|
334
|
-
console.log('');
|
|
335
|
-
console.log(`${spinner_1.colors.muted('Use')} ${spinner_1.colors.cyan('relq resolve')} ${spinner_1.colors.muted('to see and resolve conflicts')}`);
|
|
336
|
-
console.log(`${spinner_1.colors.muted('Or use')} ${spinner_1.colors.cyan('relq pull --force')} ${spinner_1.colors.muted('to overwrite local')}`);
|
|
337
|
-
console.log('');
|
|
338
|
-
return;
|
|
335
|
+
(0, cli_utils_1.fatal)('You have unresolved merge conflicts', `Use ${cli_utils_1.colors.cyan('relq resolve')} to see and resolve conflicts\nOr use ${cli_utils_1.colors.cyan('relq pull --force')} to overwrite local`);
|
|
339
336
|
}
|
|
340
337
|
if (schemaExists && localSnapshot && !force) {
|
|
341
338
|
const localTables = new Set(localSnapshot.tables.map(t => t.name));
|
|
@@ -350,75 +347,76 @@ async function pullCommand(context) {
|
|
|
350
347
|
createdAt: new Date().toISOString(),
|
|
351
348
|
};
|
|
352
349
|
fs.writeFileSync(mergeStatePath, JSON.stringify(mergeState, null, 2));
|
|
353
|
-
console.log(`${spinner_1.colors.red('error:')} Merge conflict detected`);
|
|
354
350
|
console.log('');
|
|
355
351
|
console.log(`Both local and remote have modified the same objects:`);
|
|
356
352
|
console.log('');
|
|
357
353
|
for (const c of conflicts.slice(0, 10)) {
|
|
358
354
|
const name = c.parentName ? `${c.parentName}.${c.objectName}` : c.objectName;
|
|
359
|
-
console.log(` ${
|
|
360
|
-
console.log(` ${
|
|
355
|
+
console.log(` ${cli_utils_1.colors.red('conflict:')} ${c.objectType.toLowerCase()} ${cli_utils_1.colors.bold(name)}`);
|
|
356
|
+
console.log(` ${cli_utils_1.colors.muted(c.description)}`);
|
|
361
357
|
}
|
|
362
358
|
if (conflicts.length > 10) {
|
|
363
|
-
console.log(` ${
|
|
359
|
+
console.log(` ${cli_utils_1.colors.muted(`... and ${conflicts.length - 10} more`)}`);
|
|
364
360
|
}
|
|
365
|
-
|
|
366
|
-
console.log('To resolve:');
|
|
367
|
-
console.log(` ${spinner_1.colors.cyan('relq resolve --theirs <name>')} Take remote version`);
|
|
368
|
-
console.log(` ${spinner_1.colors.cyan('relq resolve --ours <name>')} Keep local version`);
|
|
369
|
-
console.log(` ${spinner_1.colors.cyan('relq resolve --all-theirs')} Take all remote`);
|
|
370
|
-
console.log(` ${spinner_1.colors.cyan('relq pull --force')} Force overwrite local`);
|
|
371
|
-
console.log('');
|
|
372
|
-
return;
|
|
361
|
+
(0, cli_utils_1.fatal)('Automatic merge failed; fix conflicts and then commit', `${cli_utils_1.colors.cyan('relq resolve --theirs <name>')} Take remote version\n${cli_utils_1.colors.cyan('relq resolve --all-theirs')} Take all remote\n${cli_utils_1.colors.cyan('relq pull --force')} Force overwrite local`);
|
|
373
362
|
}
|
|
374
363
|
if (added.length === 0 && removed.length === 0) {
|
|
375
|
-
console.log(
|
|
364
|
+
console.log('Already up to date with remote');
|
|
376
365
|
console.log('');
|
|
377
366
|
return;
|
|
378
367
|
}
|
|
379
|
-
console.log(`${
|
|
368
|
+
console.log(`${cli_utils_1.colors.yellow('Remote has changes:')}`);
|
|
380
369
|
if (added.length > 0) {
|
|
381
|
-
console.log(` ${
|
|
370
|
+
console.log(` ${cli_utils_1.colors.green(`+${added.length}`)} tables added`);
|
|
382
371
|
}
|
|
383
372
|
if (removed.length > 0) {
|
|
384
|
-
console.log(` ${
|
|
373
|
+
console.log(` ${cli_utils_1.colors.red(`-${removed.length}`)} tables removed`);
|
|
385
374
|
}
|
|
386
375
|
console.log('');
|
|
387
376
|
if (!dryRun) {
|
|
388
|
-
const proceed = await
|
|
377
|
+
const proceed = await (0, cli_utils_1.confirm)(`${cli_utils_1.colors.bold('Pull these changes?')}`, true);
|
|
389
378
|
if (!proceed) {
|
|
390
|
-
|
|
391
|
-
console.log(`${spinner_1.colors.muted('Cancelled.')}`);
|
|
392
|
-
return;
|
|
379
|
+
(0, cli_utils_1.fatal)('Operation cancelled by user');
|
|
393
380
|
}
|
|
394
381
|
console.log('');
|
|
395
382
|
}
|
|
396
383
|
}
|
|
397
384
|
else if (schemaExists && !force) {
|
|
398
|
-
|
|
385
|
+
(0, cli_utils_1.warning)('Local schema exists but not tracked');
|
|
399
386
|
console.log('');
|
|
400
|
-
console.log(` ${
|
|
387
|
+
console.log(` ${cli_utils_1.colors.cyan(schemaPath)}`);
|
|
401
388
|
console.log('');
|
|
402
389
|
if (!dryRun) {
|
|
403
|
-
const proceed = await
|
|
390
|
+
const proceed = await (0, cli_utils_1.confirm)(`${cli_utils_1.colors.bold('Overwrite local schema?')}`, false);
|
|
404
391
|
if (!proceed) {
|
|
405
|
-
|
|
406
|
-
console.log(`${spinner_1.colors.muted('Cancelled. Run')} ${spinner_1.colors.cyan('relq status')} ${spinner_1.colors.muted('to see current state.')}`);
|
|
407
|
-
return;
|
|
392
|
+
(0, cli_utils_1.fatal)('Operation cancelled by user', `Run ${cli_utils_1.colors.cyan('relq status')} to see current state.`);
|
|
408
393
|
}
|
|
409
394
|
console.log('');
|
|
410
395
|
}
|
|
411
396
|
}
|
|
412
397
|
else if (!schemaExists) {
|
|
413
|
-
console.log(
|
|
398
|
+
console.log('First pull - creating schema');
|
|
414
399
|
console.log('');
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
400
|
+
const indexCount = filteredTables.reduce((sum, t) => sum + (t.indexes?.filter(i => !i.isPrimary).length || 0), 0);
|
|
401
|
+
const partitionCount = filteredTables.filter(t => t.isPartitioned).length;
|
|
402
|
+
const tableCommentCount = filteredTables.filter(t => t.comment).length;
|
|
403
|
+
const columnCommentCount = filteredTables.reduce((sum, t) => sum + t.columns.filter(c => c.comment).length, 0);
|
|
404
|
+
console.log('Schema Summary:');
|
|
405
|
+
console.log(` ${cli_utils_1.colors.green(String(filteredTables.length))} tables`);
|
|
406
|
+
if (indexCount > 0)
|
|
407
|
+
console.log(` ${cli_utils_1.colors.green(String(indexCount))} indexes`);
|
|
408
|
+
if (partitionCount > 0)
|
|
409
|
+
console.log(` ${cli_utils_1.colors.green(String(partitionCount))} partitioned tables`);
|
|
410
|
+
if (tableCommentCount > 0)
|
|
411
|
+
console.log(` ${cli_utils_1.colors.green(String(tableCommentCount))} table comments`);
|
|
412
|
+
if (columnCommentCount > 0)
|
|
413
|
+
console.log(` ${cli_utils_1.colors.green(String(columnCommentCount))} column comments`);
|
|
414
|
+
if (dbSchema.extensions.length > 0)
|
|
415
|
+
console.log(` ${cli_utils_1.colors.green(String(dbSchema.extensions.length))} extensions`);
|
|
418
416
|
console.log('');
|
|
419
417
|
}
|
|
420
418
|
if (dryRun) {
|
|
421
|
-
console.log(
|
|
419
|
+
console.log('Dry run - no files written');
|
|
422
420
|
console.log('');
|
|
423
421
|
return;
|
|
424
422
|
}
|
|
@@ -439,27 +437,139 @@ async function pullCommand(context) {
|
|
|
439
437
|
spinner.start('Writing schema file...');
|
|
440
438
|
fs.writeFileSync(schemaPath, typescript, 'utf-8');
|
|
441
439
|
const fileSize = Buffer.byteLength(typescript, 'utf8');
|
|
442
|
-
spinner.succeed(`Written ${
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
440
|
+
spinner.succeed(`Written ${cli_utils_1.colors.cyan(schemaPath)} ${cli_utils_1.colors.muted(`(${(0, cli_utils_1.formatBytes)(fileSize)})`)}`);
|
|
441
|
+
const fileHash = (0, repo_manager_1.hashFileContent)(typescript);
|
|
442
|
+
(0, repo_manager_1.saveFileHash)(fileHash, projectRoot);
|
|
443
|
+
const oldSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot);
|
|
444
|
+
const beforeSchema = oldSnapshot ? {
|
|
445
|
+
extensions: oldSnapshot.extensions?.map(e => e.name) || [],
|
|
446
|
+
enums: oldSnapshot.enums || [],
|
|
447
|
+
domains: oldSnapshot.domains?.map(d => ({
|
|
448
|
+
name: d.name,
|
|
449
|
+
baseType: d.baseType,
|
|
450
|
+
isNotNull: d.notNull,
|
|
451
|
+
defaultValue: d.default,
|
|
452
|
+
checkExpression: d.check,
|
|
453
|
+
})) || [],
|
|
454
|
+
compositeTypes: oldSnapshot.compositeTypes || [],
|
|
455
|
+
sequences: oldSnapshot.sequences || [],
|
|
456
|
+
tables: oldSnapshot.tables.map(t => ({
|
|
457
|
+
name: t.name,
|
|
458
|
+
schema: t.schema,
|
|
459
|
+
columns: t.columns.map(c => ({
|
|
460
|
+
name: c.name,
|
|
461
|
+
dataType: c.type,
|
|
462
|
+
isNullable: c.nullable,
|
|
463
|
+
defaultValue: c.default,
|
|
464
|
+
isPrimaryKey: c.primaryKey,
|
|
465
|
+
isUnique: c.unique,
|
|
466
|
+
comment: c.comment,
|
|
467
|
+
})),
|
|
468
|
+
indexes: t.indexes.map(i => ({
|
|
469
|
+
name: i.name,
|
|
470
|
+
columns: i.columns,
|
|
471
|
+
isUnique: i.unique,
|
|
472
|
+
type: i.type,
|
|
473
|
+
})),
|
|
474
|
+
constraints: t.constraints || [],
|
|
475
|
+
isPartitioned: t.isPartitioned,
|
|
476
|
+
partitionType: t.partitionType,
|
|
477
|
+
partitionKey: t.partitionKey,
|
|
478
|
+
comment: t.comment,
|
|
479
|
+
})),
|
|
480
|
+
functions: oldSnapshot.functions || [],
|
|
481
|
+
triggers: oldSnapshot.triggers || [],
|
|
482
|
+
} : {
|
|
483
|
+
extensions: [],
|
|
484
|
+
enums: [],
|
|
485
|
+
domains: [],
|
|
486
|
+
compositeTypes: [],
|
|
487
|
+
sequences: [],
|
|
488
|
+
tables: [],
|
|
489
|
+
functions: [],
|
|
490
|
+
triggers: [],
|
|
491
|
+
};
|
|
492
|
+
const afterSchema = {
|
|
493
|
+
extensions: dbSchema.extensions || [],
|
|
494
|
+
enums: filteredEnums || [],
|
|
495
|
+
domains: filteredDomains?.map(d => ({
|
|
496
|
+
name: d.name,
|
|
497
|
+
baseType: d.baseType,
|
|
498
|
+
isNotNull: d.isNotNull,
|
|
499
|
+
defaultValue: d.defaultValue,
|
|
500
|
+
checkExpression: d.checkExpression,
|
|
501
|
+
})) || [],
|
|
502
|
+
compositeTypes: filteredCompositeTypes || [],
|
|
503
|
+
sequences: [],
|
|
504
|
+
tables: filteredTables.map(t => ({
|
|
505
|
+
name: t.name,
|
|
506
|
+
schema: t.schema,
|
|
507
|
+
columns: t.columns.map(c => ({
|
|
508
|
+
name: c.name,
|
|
509
|
+
dataType: c.dataType,
|
|
510
|
+
isNullable: c.isNullable,
|
|
511
|
+
defaultValue: c.defaultValue,
|
|
512
|
+
isPrimaryKey: c.isPrimaryKey,
|
|
513
|
+
isUnique: c.isUnique,
|
|
514
|
+
comment: c.comment,
|
|
515
|
+
})),
|
|
516
|
+
indexes: t.indexes.map(i => ({
|
|
517
|
+
name: i.name,
|
|
518
|
+
columns: i.columns,
|
|
519
|
+
isUnique: i.isUnique,
|
|
520
|
+
type: i.type,
|
|
521
|
+
})),
|
|
522
|
+
constraints: t.constraints || [],
|
|
523
|
+
isPartitioned: t.isPartitioned,
|
|
524
|
+
partitionType: t.partitionType,
|
|
525
|
+
partitionKey: t.partitionKey,
|
|
526
|
+
childPartitions: t.childPartitions,
|
|
527
|
+
comment: t.comment,
|
|
528
|
+
})),
|
|
529
|
+
functions: filteredFunctions || [],
|
|
530
|
+
triggers: filteredTriggers || [],
|
|
531
|
+
};
|
|
532
|
+
const schemaChanges = (0, schema_comparator_1.compareSchemas)(beforeSchema, afterSchema);
|
|
533
|
+
(0, repo_manager_1.saveSnapshot)(currentSchema, projectRoot);
|
|
534
|
+
const duration = Date.now() - startTime;
|
|
535
|
+
if (noCommit) {
|
|
536
|
+
if (schemaChanges.length > 0) {
|
|
537
|
+
(0, repo_manager_1.addUnstagedChanges)(schemaChanges, projectRoot);
|
|
538
|
+
spinner.succeed(`Detected ${schemaChanges.length} schema change(s)`);
|
|
539
|
+
}
|
|
540
|
+
console.log('');
|
|
541
|
+
console.log(`Pull completed in ${(0, cli_utils_1.formatDuration)(duration)}`);
|
|
542
|
+
if (schemaChanges.length > 0) {
|
|
543
|
+
console.log('');
|
|
544
|
+
console.log(`${cli_utils_1.colors.green(String(schemaChanges.length))} change(s) ready to stage`);
|
|
545
|
+
console.log(`hint: run ${cli_utils_1.colors.cyan("'relq add .'")} to stage all changes`);
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
console.log('Already up to date');
|
|
549
|
+
}
|
|
446
550
|
}
|
|
447
551
|
else {
|
|
448
|
-
(0,
|
|
552
|
+
const connectionDesc = (0, env_loader_1.getConnectionDescription)(connection);
|
|
553
|
+
const commitMessage = `pull: sync from ${connectionDesc}`;
|
|
554
|
+
const commit = (0, repo_manager_1.createCommit)(currentSchema, author, commitMessage, projectRoot);
|
|
555
|
+
(0, repo_manager_1.clearWorkingState)(projectRoot);
|
|
556
|
+
console.log('');
|
|
557
|
+
console.log(`Pull completed in ${(0, cli_utils_1.formatDuration)(duration)}`);
|
|
558
|
+
console.log('');
|
|
559
|
+
console.log(`${cli_utils_1.colors.yellow('→')} ${(0, repo_manager_1.shortHash)(commit.hash)} ${commitMessage}`);
|
|
560
|
+
console.log(` ${cli_utils_1.colors.green(String(commit.stats.tables))} tables, ${cli_utils_1.colors.green(String(commit.stats.columns))} columns`);
|
|
561
|
+
if (stashedSchemaContent) {
|
|
562
|
+
fs.writeFileSync(schemaPath, stashedSchemaContent, 'utf-8');
|
|
563
|
+
console.log('');
|
|
564
|
+
console.log(`${cli_utils_1.colors.yellow('Restored')} local schema file content`);
|
|
565
|
+
console.log(`hint: run ${cli_utils_1.colors.cyan("'relq add .'")} to detect changes against the new snapshot`);
|
|
566
|
+
}
|
|
449
567
|
}
|
|
450
|
-
spinner.start('Creating commit...');
|
|
451
|
-
const message = localHead ? 'Pulled schema from database' : 'Initial schema pull';
|
|
452
|
-
const commit = (0, repo_manager_1.createCommit)(currentSchema, author, message, projectRoot);
|
|
453
|
-
spinner.succeed(`Created commit ${spinner_1.colors.yellow((0, repo_manager_1.shortHash)(commit.hash))}`);
|
|
454
|
-
const duration = Date.now() - startTime;
|
|
455
|
-
console.log('');
|
|
456
|
-
console.log(`${spinner_1.colors.green('✓')} Pull completed in ${spinner_1.colors.cyan(`${duration}ms`)}`);
|
|
457
568
|
console.log('');
|
|
458
569
|
}
|
|
459
|
-
catch (
|
|
570
|
+
catch (err) {
|
|
460
571
|
spinner.fail('Pull failed');
|
|
461
|
-
|
|
462
|
-
process.exit(1);
|
|
572
|
+
(0, cli_utils_1.fatal)(err instanceof Error ? err.message : String(err));
|
|
463
573
|
}
|
|
464
574
|
}
|
|
465
575
|
function detectObjectConflicts(local, remote) {
|