relq 1.0.1 → 1.0.3
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/addon/buffer/index.cjs +1881 -0
- package/dist/cjs/addon/pg/index.cjs +4812 -0
- package/dist/cjs/addon/pg-cursor/index.cjs +1451 -0
- package/dist/cjs/addon/pg-format/index.cjs +2270 -0
- package/dist/cjs/cli/commands/add.cjs +430 -25
- package/dist/cjs/cli/commands/branch.cjs +131 -0
- package/dist/cjs/cli/commands/checkout.cjs +121 -0
- package/dist/cjs/cli/commands/cherry-pick.cjs +282 -0
- package/dist/cjs/cli/commands/commit.cjs +21 -29
- package/dist/cjs/cli/commands/diff.cjs +144 -69
- package/dist/cjs/cli/commands/export.cjs +70 -11
- package/dist/cjs/cli/commands/fetch.cjs +42 -18
- 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 +305 -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 +84 -15
- package/dist/cjs/cli/commands/merge.cjs +207 -0
- package/dist/cjs/cli/commands/migrate.cjs +13 -26
- package/dist/cjs/cli/commands/pull.cjs +321 -95
- package/dist/cjs/cli/commands/push.cjs +228 -52
- package/dist/cjs/cli/commands/remote.cjs +17 -0
- package/dist/cjs/cli/commands/reset.cjs +148 -0
- package/dist/cjs/cli/commands/resolve.cjs +191 -0
- package/dist/cjs/cli/commands/rollback.cjs +17 -39
- package/dist/cjs/cli/commands/stash.cjs +152 -0
- package/dist/cjs/cli/commands/status.cjs +52 -9
- package/dist/cjs/cli/commands/sync.cjs +30 -50
- package/dist/cjs/cli/commands/tag.cjs +146 -0
- package/dist/cjs/cli/index.cjs +117 -10
- 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/commit-manager.cjs +3 -3
- package/dist/cjs/cli/utils/config-loader.cjs +34 -8
- package/dist/cjs/cli/utils/env-loader.cjs +3 -2
- package/dist/cjs/cli/utils/fast-introspect.cjs +110 -4
- 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 +107 -0
- package/dist/cjs/cli/utils/relqignore.cjs +297 -38
- package/dist/cjs/cli/utils/repo-manager.cjs +92 -3
- 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 +9 -5
- 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 +2 -2
- package/dist/cjs/cli/utils/sql-parser.cjs +94 -7
- package/dist/cjs/cli/utils/type-generator.cjs +28 -16
- package/dist/cjs/condition/array-condition-builder.cjs +1 -1
- package/dist/cjs/condition/condition-collector.cjs +1 -1
- package/dist/cjs/condition/fulltext-condition-builder.cjs +1 -1
- package/dist/cjs/condition/geometric-condition-builder.cjs +1 -1
- package/dist/cjs/condition/jsonb-condition-builder.cjs +1 -1
- package/dist/cjs/condition/network-condition-builder.cjs +1 -1
- package/dist/cjs/condition/range-condition-builder.cjs +1 -1
- package/dist/cjs/copy/copy-builder.cjs +1 -1
- package/dist/cjs/core/query-builder.cjs +1 -1
- package/dist/cjs/core/relq-client.cjs +2 -2
- package/dist/cjs/count/count-builder.cjs +1 -1
- package/dist/cjs/cte/cte-builder.cjs +1 -1
- package/dist/cjs/delete/delete-builder.cjs +1 -1
- package/dist/cjs/function/create-function-builder.cjs +1 -1
- package/dist/cjs/functions/advanced-functions.cjs +1 -1
- package/dist/cjs/functions/case-builder.cjs +1 -1
- package/dist/cjs/functions/geometric-functions.cjs +1 -1
- package/dist/cjs/functions/network-functions.cjs +1 -1
- package/dist/cjs/functions/sql-functions.cjs +1 -1
- package/dist/cjs/indexing/create-index-builder.cjs +1 -1
- package/dist/cjs/indexing/drop-index-builder.cjs +1 -1
- package/dist/cjs/insert/conflict-builder.cjs +1 -1
- package/dist/cjs/insert/insert-builder.cjs +1 -1
- package/dist/cjs/maintenance/vacuum-builder.cjs +1 -1
- package/dist/cjs/pubsub/listen-notify-builder.cjs +1 -1
- package/dist/cjs/pubsub/listener-connection.cjs +2 -2
- package/dist/cjs/raw/raw-query-builder.cjs +1 -1
- package/dist/cjs/schema/schema-builder.cjs +1 -1
- package/dist/cjs/schema-definition/table-definition.cjs +1 -1
- package/dist/cjs/select/aggregate-builder.cjs +1 -1
- package/dist/cjs/select/select-builder.cjs +1 -1
- package/dist/cjs/sequence/sequence-builder.cjs +1 -1
- package/dist/cjs/table/alter-table-builder.cjs +1 -1
- package/dist/cjs/table/constraint-builder.cjs +1 -1
- package/dist/cjs/table/create-table-builder.cjs +1 -1
- package/dist/cjs/table/partition-builder.cjs +1 -1
- package/dist/cjs/table/truncate-builder.cjs +1 -1
- package/dist/cjs/transaction/transaction-builder.cjs +1 -1
- package/dist/cjs/trigger/create-trigger-builder.cjs +1 -1
- package/dist/cjs/update/array-update-builder.cjs +1 -1
- package/dist/cjs/update/update-builder.cjs +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/cjs/view/create-view-builder.cjs +1 -1
- package/dist/cjs/window/window-builder.cjs +1 -1
- package/dist/config.d.ts +16 -25
- package/dist/esm/cli/commands/add.js +399 -27
- package/dist/esm/cli/commands/branch.js +95 -0
- package/dist/esm/cli/commands/checkout.js +85 -0
- package/dist/esm/cli/commands/cherry-pick.js +246 -0
- package/dist/esm/cli/commands/commit.js +22 -30
- package/dist/esm/cli/commands/diff.js +144 -69
- package/dist/esm/cli/commands/export.js +71 -12
- package/dist/esm/cli/commands/fetch.js +42 -18
- 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 +306 -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 +78 -10
- package/dist/esm/cli/commands/merge.js +171 -0
- package/dist/esm/cli/commands/migrate.js +13 -26
- package/dist/esm/cli/commands/pull.js +313 -87
- package/dist/esm/cli/commands/push.js +223 -47
- package/dist/esm/cli/commands/remote.js +14 -0
- package/dist/esm/cli/commands/reset.js +112 -0
- package/dist/esm/cli/commands/resolve.js +155 -0
- package/dist/esm/cli/commands/rollback.js +17 -39
- package/dist/esm/cli/commands/stash.js +116 -0
- package/dist/esm/cli/commands/status.js +20 -10
- package/dist/esm/cli/commands/sync.js +30 -50
- package/dist/esm/cli/commands/tag.js +110 -0
- package/dist/esm/cli/index.js +118 -11
- 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/commit-manager.js +3 -3
- package/dist/esm/cli/utils/config-loader.js +34 -8
- package/dist/esm/cli/utils/env-loader.js +3 -2
- package/dist/esm/cli/utils/fast-introspect.js +110 -4
- 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 +69 -0
- package/dist/esm/cli/utils/relqignore.js +278 -37
- package/dist/esm/cli/utils/repo-manager.js +83 -3
- 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 +9 -5
- 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 +2 -2
- package/dist/esm/cli/utils/sql-parser.js +94 -7
- package/dist/esm/cli/utils/type-generator.js +28 -16
- package/dist/esm/condition/array-condition-builder.js +1 -1
- package/dist/esm/condition/condition-collector.js +1 -1
- package/dist/esm/condition/fulltext-condition-builder.js +1 -1
- package/dist/esm/condition/geometric-condition-builder.js +1 -1
- package/dist/esm/condition/jsonb-condition-builder.js +1 -1
- package/dist/esm/condition/network-condition-builder.js +1 -1
- package/dist/esm/condition/range-condition-builder.js +1 -1
- package/dist/esm/copy/copy-builder.js +1 -1
- package/dist/esm/core/query-builder.js +1 -1
- package/dist/esm/core/relq-client.js +2 -2
- package/dist/esm/count/count-builder.js +1 -1
- package/dist/esm/cte/cte-builder.js +1 -1
- package/dist/esm/delete/delete-builder.js +1 -1
- package/dist/esm/function/create-function-builder.js +1 -1
- package/dist/esm/functions/advanced-functions.js +1 -1
- package/dist/esm/functions/case-builder.js +1 -1
- package/dist/esm/functions/geometric-functions.js +1 -1
- package/dist/esm/functions/network-functions.js +1 -1
- package/dist/esm/functions/sql-functions.js +1 -1
- package/dist/esm/indexing/create-index-builder.js +1 -1
- package/dist/esm/indexing/drop-index-builder.js +1 -1
- package/dist/esm/insert/conflict-builder.js +1 -1
- package/dist/esm/insert/insert-builder.js +1 -1
- package/dist/esm/maintenance/vacuum-builder.js +1 -1
- package/dist/esm/pubsub/listen-notify-builder.js +1 -1
- package/dist/esm/pubsub/listener-connection.js +2 -2
- package/dist/esm/raw/raw-query-builder.js +1 -1
- package/dist/esm/schema/schema-builder.js +1 -1
- package/dist/esm/schema-definition/table-definition.js +1 -1
- package/dist/esm/select/aggregate-builder.js +1 -1
- package/dist/esm/select/select-builder.js +1 -1
- package/dist/esm/sequence/sequence-builder.js +1 -1
- package/dist/esm/table/alter-table-builder.js +1 -1
- package/dist/esm/table/constraint-builder.js +1 -1
- package/dist/esm/table/create-table-builder.js +1 -1
- package/dist/esm/table/partition-builder.js +1 -1
- package/dist/esm/table/truncate-builder.js +1 -1
- package/dist/esm/transaction/transaction-builder.js +1 -1
- package/dist/esm/trigger/create-trigger-builder.js +1 -1
- package/dist/esm/update/array-update-builder.js +1 -1
- package/dist/esm/update/update-builder.js +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/view/create-view-builder.js +1 -1
- package/dist/esm/window/window-builder.js +1 -1
- package/dist/index.d.ts +25 -8
- package/dist/schema-builder.d.ts +16 -6
- package/package.json +1 -1
- /package/dist/{addons/buffer.js → esm/addon/buffer/index.js} +0 -0
- /package/dist/{addons/pg.js → esm/addon/pg/index.js} +0 -0
- /package/dist/{addons/pg-cursor.js → esm/addon/pg-cursor/index.js} +0 -0
- /package/dist/{addons/pg-format.js → esm/addon/pg-format/index.js} +0 -0
|
@@ -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;
|
|
@@ -245,8 +244,24 @@ async function pullCommand(context) {
|
|
|
245
244
|
includeTriggers,
|
|
246
245
|
});
|
|
247
246
|
spinner.succeed(`Found ${dbSchema.tables.length} tables`);
|
|
248
|
-
const ignorePatterns = (0, relqignore_1.
|
|
249
|
-
const filteredTables =
|
|
247
|
+
const ignorePatterns = (0, relqignore_1.loadRelqignore)(projectRoot);
|
|
248
|
+
const filteredTables = dbSchema.tables
|
|
249
|
+
.filter(t => !(0, relqignore_1.isTableIgnored)(t.name, ignorePatterns).ignored)
|
|
250
|
+
.map(t => ({
|
|
251
|
+
...t,
|
|
252
|
+
columns: t.columns.filter(c => !(0, relqignore_1.isColumnIgnored)(t.name, c.name, ignorePatterns).ignored),
|
|
253
|
+
indexes: t.indexes.filter(i => !(0, relqignore_1.isIndexIgnored)(t.name, i.name, ignorePatterns).ignored),
|
|
254
|
+
constraints: t.constraints.filter(c => !(0, relqignore_1.isConstraintIgnored)(t.name, c.name, ignorePatterns).ignored),
|
|
255
|
+
}));
|
|
256
|
+
const filteredEnums = dbSchema.enums.filter(e => !(0, relqignore_1.isEnumIgnored)(e.name, ignorePatterns).ignored);
|
|
257
|
+
const filteredDomains = dbSchema.domains.filter(d => !(0, relqignore_1.isDomainIgnored)(d.name, ignorePatterns).ignored);
|
|
258
|
+
const filteredCompositeTypes = dbSchema.compositeTypes.filter(c => !(0, relqignore_1.isCompositeTypeIgnored)(c.name, ignorePatterns).ignored);
|
|
259
|
+
const filteredFunctions = includeFunctions
|
|
260
|
+
? dbSchema.functions.filter(f => !(0, relqignore_1.isFunctionIgnored)(f.name, ignorePatterns).ignored)
|
|
261
|
+
: [];
|
|
262
|
+
const filteredTriggers = includeTriggers
|
|
263
|
+
? dbSchema.triggers
|
|
264
|
+
: [];
|
|
250
265
|
const localHead = (0, repo_manager_1.getHead)(projectRoot);
|
|
251
266
|
const localSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot);
|
|
252
267
|
const schemaExists = fs.existsSync(schemaPath);
|
|
@@ -274,13 +289,16 @@ async function pullCommand(context) {
|
|
|
274
289
|
type: c.type,
|
|
275
290
|
definition: c.definition,
|
|
276
291
|
})),
|
|
292
|
+
isPartitioned: t.isPartitioned,
|
|
293
|
+
partitionType: t.partitionType,
|
|
294
|
+
partitionKey: normalizePartitionKey(t.partitionKey),
|
|
277
295
|
})),
|
|
278
|
-
enums:
|
|
296
|
+
enums: filteredEnums.map(e => ({
|
|
279
297
|
name: e.name,
|
|
280
298
|
schema: 'public',
|
|
281
299
|
values: e.values,
|
|
282
300
|
})),
|
|
283
|
-
domains:
|
|
301
|
+
domains: filteredDomains.map(d => ({
|
|
284
302
|
name: d.name,
|
|
285
303
|
schema: 'public',
|
|
286
304
|
baseType: d.baseType,
|
|
@@ -288,20 +306,20 @@ async function pullCommand(context) {
|
|
|
288
306
|
default: d.defaultValue || null,
|
|
289
307
|
check: d.checkExpression || null,
|
|
290
308
|
})),
|
|
291
|
-
compositeTypes:
|
|
309
|
+
compositeTypes: filteredCompositeTypes.map(c => ({
|
|
292
310
|
name: c.name,
|
|
293
311
|
schema: 'public',
|
|
294
312
|
attributes: c.attributes,
|
|
295
313
|
})),
|
|
296
314
|
sequences: [],
|
|
297
315
|
collations: [],
|
|
298
|
-
functions:
|
|
316
|
+
functions: filteredFunctions.map(f => ({
|
|
299
317
|
name: f.name,
|
|
300
318
|
returnType: f.returnType,
|
|
301
319
|
argTypes: f.argTypes,
|
|
302
320
|
language: f.language,
|
|
303
321
|
})),
|
|
304
|
-
triggers:
|
|
322
|
+
triggers: filteredTriggers.map(t => ({
|
|
305
323
|
name: t.name,
|
|
306
324
|
table: t.tableName,
|
|
307
325
|
events: [t.event],
|
|
@@ -312,59 +330,93 @@ async function pullCommand(context) {
|
|
|
312
330
|
extensions: dbSchema.extensions.map(ext => ({ name: ext })),
|
|
313
331
|
};
|
|
314
332
|
console.log('');
|
|
333
|
+
const mergeStatePath = path.join(projectRoot, '.relq', 'MERGE_STATE');
|
|
334
|
+
if (fs.existsSync(mergeStatePath) && !force) {
|
|
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`);
|
|
336
|
+
}
|
|
315
337
|
if (schemaExists && localSnapshot && !force) {
|
|
316
338
|
const localTables = new Set(localSnapshot.tables.map(t => t.name));
|
|
317
339
|
const remoteTables = new Set(currentSchema.tables.map(t => t.name));
|
|
318
340
|
const added = [...remoteTables].filter(t => !localTables.has(t));
|
|
319
341
|
const removed = [...localTables].filter(t => !remoteTables.has(t));
|
|
342
|
+
const conflicts = detectObjectConflicts(localSnapshot, currentSchema);
|
|
343
|
+
if (conflicts.length > 0 && !force) {
|
|
344
|
+
const mergeState = {
|
|
345
|
+
conflicts,
|
|
346
|
+
remoteSnapshot: currentSchema,
|
|
347
|
+
createdAt: new Date().toISOString(),
|
|
348
|
+
};
|
|
349
|
+
fs.writeFileSync(mergeStatePath, JSON.stringify(mergeState, null, 2));
|
|
350
|
+
console.log('');
|
|
351
|
+
console.log(`Both local and remote have modified the same objects:`);
|
|
352
|
+
console.log('');
|
|
353
|
+
for (const c of conflicts.slice(0, 10)) {
|
|
354
|
+
const name = c.parentName ? `${c.parentName}.${c.objectName}` : c.objectName;
|
|
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)}`);
|
|
357
|
+
}
|
|
358
|
+
if (conflicts.length > 10) {
|
|
359
|
+
console.log(` ${cli_utils_1.colors.muted(`... and ${conflicts.length - 10} more`)}`);
|
|
360
|
+
}
|
|
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`);
|
|
362
|
+
}
|
|
320
363
|
if (added.length === 0 && removed.length === 0) {
|
|
321
|
-
console.log(
|
|
364
|
+
console.log('Already up to date with remote');
|
|
322
365
|
console.log('');
|
|
323
366
|
return;
|
|
324
367
|
}
|
|
325
|
-
console.log(`${
|
|
368
|
+
console.log(`${cli_utils_1.colors.yellow('Remote has changes:')}`);
|
|
326
369
|
if (added.length > 0) {
|
|
327
|
-
console.log(` ${
|
|
370
|
+
console.log(` ${cli_utils_1.colors.green(`+${added.length}`)} tables added`);
|
|
328
371
|
}
|
|
329
372
|
if (removed.length > 0) {
|
|
330
|
-
console.log(` ${
|
|
373
|
+
console.log(` ${cli_utils_1.colors.red(`-${removed.length}`)} tables removed`);
|
|
331
374
|
}
|
|
332
375
|
console.log('');
|
|
333
376
|
if (!dryRun) {
|
|
334
|
-
const proceed = await
|
|
377
|
+
const proceed = await (0, cli_utils_1.confirm)(`${cli_utils_1.colors.bold('Pull these changes?')}`, true);
|
|
335
378
|
if (!proceed) {
|
|
336
|
-
|
|
337
|
-
console.log(`${spinner_1.colors.muted('Cancelled.')}`);
|
|
338
|
-
return;
|
|
379
|
+
(0, cli_utils_1.fatal)('Operation cancelled by user');
|
|
339
380
|
}
|
|
340
381
|
console.log('');
|
|
341
382
|
}
|
|
342
383
|
}
|
|
343
384
|
else if (schemaExists && !force) {
|
|
344
|
-
|
|
385
|
+
(0, cli_utils_1.warning)('Local schema exists but not tracked');
|
|
345
386
|
console.log('');
|
|
346
|
-
console.log(` ${
|
|
387
|
+
console.log(` ${cli_utils_1.colors.cyan(schemaPath)}`);
|
|
347
388
|
console.log('');
|
|
348
389
|
if (!dryRun) {
|
|
349
|
-
const proceed = await
|
|
390
|
+
const proceed = await (0, cli_utils_1.confirm)(`${cli_utils_1.colors.bold('Overwrite local schema?')}`, false);
|
|
350
391
|
if (!proceed) {
|
|
351
|
-
|
|
352
|
-
console.log(`${spinner_1.colors.muted('Cancelled. Run')} ${spinner_1.colors.cyan('relq status')} ${spinner_1.colors.muted('to see current state.')}`);
|
|
353
|
-
return;
|
|
392
|
+
(0, cli_utils_1.fatal)('Operation cancelled by user', `Run ${cli_utils_1.colors.cyan('relq status')} to see current state.`);
|
|
354
393
|
}
|
|
355
394
|
console.log('');
|
|
356
395
|
}
|
|
357
396
|
}
|
|
358
397
|
else if (!schemaExists) {
|
|
359
|
-
console.log(
|
|
398
|
+
console.log('First pull - creating schema');
|
|
360
399
|
console.log('');
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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`);
|
|
364
416
|
console.log('');
|
|
365
417
|
}
|
|
366
418
|
if (dryRun) {
|
|
367
|
-
console.log(
|
|
419
|
+
console.log('Dry run - no files written');
|
|
368
420
|
console.log('');
|
|
369
421
|
return;
|
|
370
422
|
}
|
|
@@ -385,26 +437,200 @@ async function pullCommand(context) {
|
|
|
385
437
|
spinner.start('Writing schema file...');
|
|
386
438
|
fs.writeFileSync(schemaPath, typescript, 'utf-8');
|
|
387
439
|
const fileSize = Buffer.byteLength(typescript, 'utf8');
|
|
388
|
-
spinner.succeed(`Written ${
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
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
|
+
}
|
|
392
550
|
}
|
|
393
551
|
else {
|
|
394
|
-
(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
|
+
}
|
|
395
567
|
}
|
|
396
|
-
spinner.start('Creating commit...');
|
|
397
|
-
const message = localHead ? 'Pulled schema from database' : 'Initial schema pull';
|
|
398
|
-
const commit = (0, repo_manager_1.createCommit)(currentSchema, author, message, projectRoot);
|
|
399
|
-
spinner.succeed(`Created commit ${spinner_1.colors.yellow((0, repo_manager_1.shortHash)(commit.hash))}`);
|
|
400
|
-
const duration = Date.now() - startTime;
|
|
401
|
-
console.log('');
|
|
402
|
-
console.log(`${spinner_1.colors.green('✓')} Pull completed in ${spinner_1.colors.cyan(`${duration}ms`)}`);
|
|
403
568
|
console.log('');
|
|
404
569
|
}
|
|
405
|
-
catch (
|
|
570
|
+
catch (err) {
|
|
406
571
|
spinner.fail('Pull failed');
|
|
407
|
-
|
|
408
|
-
|
|
572
|
+
(0, cli_utils_1.fatal)(err instanceof Error ? err.message : String(err));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function detectObjectConflicts(local, remote) {
|
|
576
|
+
const conflicts = [];
|
|
577
|
+
for (const localTable of local.tables) {
|
|
578
|
+
const remoteTable = remote.tables.find(t => t.name === localTable.name);
|
|
579
|
+
if (!remoteTable)
|
|
580
|
+
continue;
|
|
581
|
+
for (const localCol of localTable.columns) {
|
|
582
|
+
const remoteCol = remoteTable.columns.find(c => c.name === localCol.name);
|
|
583
|
+
if (!remoteCol)
|
|
584
|
+
continue;
|
|
585
|
+
if (localCol.type !== remoteCol.type) {
|
|
586
|
+
conflicts.push({
|
|
587
|
+
objectType: 'COLUMN',
|
|
588
|
+
objectName: localCol.name,
|
|
589
|
+
parentName: localTable.name,
|
|
590
|
+
localValue: localCol.type,
|
|
591
|
+
remoteValue: remoteCol.type,
|
|
592
|
+
description: `Type changed: ${localCol.type} → ${remoteCol.type}`,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
else if (localCol.nullable !== remoteCol.nullable) {
|
|
596
|
+
conflicts.push({
|
|
597
|
+
objectType: 'COLUMN',
|
|
598
|
+
objectName: localCol.name,
|
|
599
|
+
parentName: localTable.name,
|
|
600
|
+
localValue: localCol.nullable,
|
|
601
|
+
remoteValue: remoteCol.nullable,
|
|
602
|
+
description: `Nullable changed: ${localCol.nullable} → ${remoteCol.nullable}`,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
else if (String(localCol.default || '') !== String(remoteCol.default || '')) {
|
|
606
|
+
if (localCol.default && remoteCol.default && localCol.default !== remoteCol.default) {
|
|
607
|
+
conflicts.push({
|
|
608
|
+
objectType: 'COLUMN',
|
|
609
|
+
objectName: localCol.name,
|
|
610
|
+
parentName: localTable.name,
|
|
611
|
+
localValue: localCol.default,
|
|
612
|
+
remoteValue: remoteCol.default,
|
|
613
|
+
description: `Default changed`,
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
for (const localEnum of local.enums) {
|
|
620
|
+
const remoteEnum = remote.enums.find(e => e.name === localEnum.name);
|
|
621
|
+
if (!remoteEnum)
|
|
622
|
+
continue;
|
|
623
|
+
const localVals = JSON.stringify(localEnum.values.sort());
|
|
624
|
+
const remoteVals = JSON.stringify(remoteEnum.values.sort());
|
|
625
|
+
if (localVals !== remoteVals) {
|
|
626
|
+
conflicts.push({
|
|
627
|
+
objectType: 'ENUM',
|
|
628
|
+
objectName: localEnum.name,
|
|
629
|
+
localValue: localEnum.values,
|
|
630
|
+
remoteValue: remoteEnum.values,
|
|
631
|
+
description: `Values differ`,
|
|
632
|
+
});
|
|
633
|
+
}
|
|
409
634
|
}
|
|
635
|
+
return conflicts;
|
|
410
636
|
}
|