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
|
@@ -37,27 +37,19 @@ exports.historyCommand = historyCommand;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const config_loader_1 = require("../utils/config-loader.cjs");
|
|
39
39
|
const env_loader_1 = require("../utils/env-loader.cjs");
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
bold: '\x1b[1m',
|
|
43
|
-
dim: '\x1b[2m',
|
|
44
|
-
red: '\x1b[31m',
|
|
45
|
-
green: '\x1b[32m',
|
|
46
|
-
yellow: '\x1b[33m',
|
|
47
|
-
cyan: '\x1b[36m',
|
|
48
|
-
};
|
|
40
|
+
const cli_utils_1 = require("../utils/cli-utils.cjs");
|
|
41
|
+
const pool_manager_1 = require("../utils/pool-manager.cjs");
|
|
49
42
|
async function historyCommand(context) {
|
|
50
43
|
const { config, flags } = context;
|
|
51
44
|
if (!config) {
|
|
52
|
-
|
|
53
|
-
process.exit(1);
|
|
45
|
+
(0, cli_utils_1.fatal)('No configuration found', `run ${cli_utils_1.colors.cyan('relq init')} to create a configuration file`);
|
|
54
46
|
}
|
|
55
|
-
(0, config_loader_1.requireValidConfig)(config);
|
|
47
|
+
await (0, config_loader_1.requireValidConfig)(config, { calledFrom: 'history' });
|
|
56
48
|
const connection = config.connection;
|
|
57
49
|
const migrationsDir = config.migrations?.directory || './migrations';
|
|
58
50
|
const tableName = config.migrations?.tableName || '_relq_migrations';
|
|
59
51
|
const limit = parseInt(flags['n']) || 20;
|
|
60
|
-
console.log(
|
|
52
|
+
console.log('Migration History');
|
|
61
53
|
console.log(`Database: ${(0, env_loader_1.getConnectionDescription)(connection)}`);
|
|
62
54
|
console.log('');
|
|
63
55
|
try {
|
|
@@ -76,42 +68,41 @@ async function historyCommand(context) {
|
|
|
76
68
|
const toShow = history.slice(0, limit);
|
|
77
69
|
const pendingCount = history.filter(h => h.pending).length;
|
|
78
70
|
const appliedCount = history.filter(h => !h.pending).length;
|
|
79
|
-
console.log(
|
|
80
|
-
console.log(`${
|
|
71
|
+
console.log(`Showing ${toShow.length} of ${history.length} migrations`);
|
|
72
|
+
console.log(`${appliedCount} applied, ${pendingCount} pending`);
|
|
81
73
|
console.log('');
|
|
82
74
|
for (const record of toShow) {
|
|
83
75
|
if (record.pending) {
|
|
84
|
-
console.log(`${colors.yellow}○ ${record.name}${colors.reset} ${colors.dim}(pending)${colors.reset}`);
|
|
76
|
+
console.log(`${cli_utils_1.colors.yellow}○ ${record.name}${cli_utils_1.colors.reset} ${cli_utils_1.colors.dim}(pending)${cli_utils_1.colors.reset}`);
|
|
85
77
|
}
|
|
86
78
|
else {
|
|
87
79
|
const date = record.appliedAt ? formatDate(record.appliedAt) : '';
|
|
88
|
-
console.log(`${colors.green}● ${record.name}${colors.reset} ${colors.dim}${date}${colors.reset}`);
|
|
80
|
+
console.log(`${cli_utils_1.colors.green}● ${record.name}${cli_utils_1.colors.reset} ${cli_utils_1.colors.dim}${date}${cli_utils_1.colors.reset}`);
|
|
89
81
|
}
|
|
90
82
|
}
|
|
91
83
|
if (history.length > limit) {
|
|
92
84
|
console.log('');
|
|
93
|
-
console.log(`${colors.dim}Use "relq history -n ${history.length}" to see all.${colors.reset}`);
|
|
85
|
+
console.log(`${cli_utils_1.colors.dim}Use "relq history -n ${history.length}" to see all.${cli_utils_1.colors.reset}`);
|
|
94
86
|
}
|
|
95
87
|
}
|
|
96
88
|
catch (error) {
|
|
97
89
|
if (error?.code === '42P01') {
|
|
98
|
-
console.log(`${colors.yellow}No migration table found.${colors.reset}`);
|
|
99
|
-
console.log(`Run "${colors.cyan}relq push${colors.reset}" to initialize.`);
|
|
90
|
+
console.log(`${cli_utils_1.colors.yellow}No migration table found.${cli_utils_1.colors.reset}`);
|
|
91
|
+
console.log(`Run "${cli_utils_1.colors.cyan}relq push${cli_utils_1.colors.reset}" to initialize.`);
|
|
100
92
|
console.log('');
|
|
101
93
|
const files = getMigrationFiles(migrationsDir);
|
|
102
94
|
if (files.length > 0) {
|
|
103
|
-
console.log(`${colors.bold}Pending migrations:${colors.reset}`);
|
|
95
|
+
console.log(`${cli_utils_1.colors.bold}Pending migrations:${cli_utils_1.colors.reset}`);
|
|
104
96
|
for (const file of files.slice(0, limit)) {
|
|
105
|
-
console.log(` ${colors.yellow}○ ${file}${colors.reset}`);
|
|
97
|
+
console.log(` ${cli_utils_1.colors.yellow}○ ${file}${cli_utils_1.colors.reset}`);
|
|
106
98
|
}
|
|
107
99
|
}
|
|
108
100
|
else {
|
|
109
|
-
console.log(`${colors.dim}No migration files found.${colors.reset}`);
|
|
101
|
+
console.log(`${cli_utils_1.colors.dim}No migration files found.${cli_utils_1.colors.reset}`);
|
|
110
102
|
}
|
|
111
103
|
return;
|
|
112
104
|
}
|
|
113
|
-
|
|
114
|
-
process.exit(1);
|
|
105
|
+
(0, cli_utils_1.fatal)('Failed to load history', error instanceof Error ? error.message : String(error));
|
|
115
106
|
}
|
|
116
107
|
}
|
|
117
108
|
function getMigrationFiles(migrationsDir) {
|
|
@@ -123,29 +114,17 @@ function getMigrationFiles(migrationsDir) {
|
|
|
123
114
|
.sort();
|
|
124
115
|
}
|
|
125
116
|
async function getAppliedMigrations(connection, tableName) {
|
|
126
|
-
|
|
127
|
-
const pool = new Pool({
|
|
128
|
-
host: connection.host,
|
|
129
|
-
port: connection.port || 5432,
|
|
130
|
-
database: connection.database,
|
|
131
|
-
user: connection.user,
|
|
132
|
-
password: connection.password,
|
|
133
|
-
connectionString: connection.url,
|
|
134
|
-
});
|
|
135
|
-
try {
|
|
117
|
+
return (0, pool_manager_1.withPool)(connection, async (pool) => {
|
|
136
118
|
const result = await pool.query(`
|
|
137
119
|
SELECT name, applied_at
|
|
138
120
|
FROM "${tableName}"
|
|
139
121
|
ORDER BY id DESC;
|
|
140
122
|
`);
|
|
141
|
-
return result.rows.map(r => ({
|
|
123
|
+
return result.rows.map((r) => ({
|
|
142
124
|
name: r.name,
|
|
143
125
|
appliedAt: new Date(r.applied_at),
|
|
144
126
|
}));
|
|
145
|
-
}
|
|
146
|
-
finally {
|
|
147
|
-
await pool.end();
|
|
148
|
-
}
|
|
127
|
+
});
|
|
149
128
|
}
|
|
150
129
|
function formatDate(date) {
|
|
151
130
|
const now = new Date();
|
|
@@ -43,26 +43,22 @@ const schema_comparator_1 = require("../utils/schema-comparator.cjs");
|
|
|
43
43
|
const change_tracker_1 = require("../utils/change-tracker.cjs");
|
|
44
44
|
const relqignore_1 = require("../utils/relqignore.cjs");
|
|
45
45
|
const git_utils_1 = require("../utils/git-utils.cjs");
|
|
46
|
-
async function importCommand(sqlFilePath, options = {}) {
|
|
46
|
+
async function importCommand(sqlFilePath, options = {}, projectRoot = process.cwd()) {
|
|
47
47
|
const { includeFunctions = false, includeTriggers = false, force = false, dryRun = false } = options;
|
|
48
|
-
const projectRoot = process.cwd();
|
|
49
48
|
const spinner = (0, git_utils_1.createSpinner)();
|
|
50
49
|
console.log('');
|
|
51
50
|
if (!sqlFilePath) {
|
|
52
|
-
(0, git_utils_1.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
console.log(' --include-functions Include functions in import');
|
|
64
|
-
console.log(' --include-triggers Include triggers in import');
|
|
65
|
-
process.exit(1);
|
|
51
|
+
(0, git_utils_1.fatal)('No SQL file specified', 'usage: relq import <sql-file> [options]\n\n' +
|
|
52
|
+
'Options:\n' +
|
|
53
|
+
' --output <path> Output schema file path\n' +
|
|
54
|
+
' --force Force import, overwrite local changes\n' +
|
|
55
|
+
' --dry-run Preview changes without applying\n' +
|
|
56
|
+
' --theirs Accept all incoming changes\n' +
|
|
57
|
+
' --ours Keep all local changes (reject incoming)\n' +
|
|
58
|
+
' --abort Abort the import operation\n' +
|
|
59
|
+
' --include-functions Include functions in import\n' +
|
|
60
|
+
' --include-triggers Include triggers in import');
|
|
61
|
+
return;
|
|
66
62
|
}
|
|
67
63
|
if (options.abort) {
|
|
68
64
|
console.log('Aborting import...');
|
|
@@ -85,11 +81,8 @@ async function importCommand(sqlFilePath, options = {}) {
|
|
|
85
81
|
(0, git_utils_1.warning)(warn);
|
|
86
82
|
}
|
|
87
83
|
if (!validation.valid) {
|
|
88
|
-
(0, git_utils_1.
|
|
89
|
-
|
|
90
|
-
console.log(` - ${err}`);
|
|
91
|
-
}
|
|
92
|
-
process.exit(1);
|
|
84
|
+
(0, git_utils_1.fatal)('Invalid PostgreSQL SQL file', validation.errors.join('\n - '));
|
|
85
|
+
return;
|
|
93
86
|
}
|
|
94
87
|
console.log(`Importing ${git_utils_1.colors.cyan(path.basename(sqlFilePath))} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(sqlContent.length)})`)}`);
|
|
95
88
|
console.log('');
|
|
@@ -104,7 +97,8 @@ async function importCommand(sqlFilePath, options = {}) {
|
|
|
104
97
|
(0, git_utils_1.printDirtyWorkingTreeError)(status, 'import');
|
|
105
98
|
console.log('');
|
|
106
99
|
(0, git_utils_1.printMergeStrategyHelp)();
|
|
107
|
-
|
|
100
|
+
(0, git_utils_1.fatal)('Working tree is not clean', 'Commit or stash your changes before importing.');
|
|
101
|
+
return;
|
|
108
102
|
}
|
|
109
103
|
}
|
|
110
104
|
spinner.start('Parsing SQL schema');
|
|
@@ -232,7 +226,7 @@ async function importCommand(sqlFilePath, options = {}) {
|
|
|
232
226
|
partitions: parsedSchema.partitions,
|
|
233
227
|
};
|
|
234
228
|
if (ignoredCount > 0) {
|
|
235
|
-
console.log(`${
|
|
229
|
+
console.log(`${ignoredCount} object(s) ignored by .relqignore`);
|
|
236
230
|
}
|
|
237
231
|
const dependencyErrors = (0, relqignore_1.validateIgnoreDependencies)({
|
|
238
232
|
tables: filteredTables.map(t => ({
|
|
@@ -250,14 +244,9 @@ async function importCommand(sqlFilePath, options = {}) {
|
|
|
250
244
|
}, ignorePatterns);
|
|
251
245
|
if (dependencyErrors.length > 0) {
|
|
252
246
|
spinner.stop();
|
|
253
|
-
(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
console.log(` ${git_utils_1.colors.red('✗')} ${depError.message}`);
|
|
257
|
-
}
|
|
258
|
-
console.log('');
|
|
259
|
-
(0, git_utils_1.hint)('Either un-ignore the type or add the column to .relqignore');
|
|
260
|
-
process.exit(1);
|
|
247
|
+
const errorMessages = dependencyErrors.map(e => e.message).join('\n ');
|
|
248
|
+
(0, git_utils_1.fatal)('Dependency validation failed', `${errorMessages}\n\nEither un-ignore the type or add the column to .relqignore`);
|
|
249
|
+
return;
|
|
261
250
|
}
|
|
262
251
|
spinner.start('Generating TypeScript schema');
|
|
263
252
|
const dbSchema = convertToDbSchema(filteredSchema, filteredFunctions, triggers, comments);
|
|
@@ -313,7 +302,7 @@ async function importCommand(sqlFilePath, options = {}) {
|
|
|
313
302
|
}
|
|
314
303
|
else {
|
|
315
304
|
console.log('');
|
|
316
|
-
console.log(`${
|
|
305
|
+
console.log(`${drops.length} object(s) only in existing schema (preserved)`);
|
|
317
306
|
}
|
|
318
307
|
}
|
|
319
308
|
console.log('');
|
|
@@ -340,8 +329,10 @@ async function importCommand(sqlFilePath, options = {}) {
|
|
|
340
329
|
console.log(`${git_utils_1.colors.yellow('Dry run mode')} - no files written`);
|
|
341
330
|
console.log('');
|
|
342
331
|
console.log('Would write:');
|
|
343
|
-
|
|
344
|
-
|
|
332
|
+
const dryRunOutputPath = options.output || './db/schema.ts';
|
|
333
|
+
const dryRunAbsPath = path.resolve(projectRoot, dryRunOutputPath);
|
|
334
|
+
console.log(` ${git_utils_1.colors.cyan(dryRunAbsPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
|
|
335
|
+
console.log(` ${git_utils_1.colors.cyan(path.join(projectRoot, '.relq/snapshot.json'))}`);
|
|
345
336
|
if (changes.length > 0) {
|
|
346
337
|
console.log(` Stage ${changes.length} change(s)`);
|
|
347
338
|
}
|
|
@@ -349,29 +340,29 @@ async function importCommand(sqlFilePath, options = {}) {
|
|
|
349
340
|
return;
|
|
350
341
|
}
|
|
351
342
|
const outputPath = options.output || './db/schema.ts';
|
|
352
|
-
const absoluteOutputPath = path.resolve(outputPath);
|
|
343
|
+
const absoluteOutputPath = path.resolve(projectRoot, outputPath);
|
|
353
344
|
const outputDir = path.dirname(absoluteOutputPath);
|
|
354
345
|
if (!fs.existsSync(outputDir)) {
|
|
355
346
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
356
347
|
}
|
|
357
348
|
fs.writeFileSync(absoluteOutputPath, finalTypescriptContent, 'utf-8');
|
|
358
|
-
console.log(`Written ${git_utils_1.colors.cyan(
|
|
349
|
+
console.log(`Written ${git_utils_1.colors.cyan(absoluteOutputPath)} ${git_utils_1.colors.gray(`(${(0, git_utils_1.formatBytes)(finalTypescriptContent.length)})`)}`);
|
|
359
350
|
(0, repo_manager_1.saveSnapshot)(mergedSchema, projectRoot);
|
|
360
351
|
if (changes.length > 0) {
|
|
361
352
|
(0, repo_manager_1.addUnstagedChanges)(changes, projectRoot);
|
|
362
353
|
(0, repo_manager_1.stageChanges)(['.'], projectRoot);
|
|
363
354
|
console.log('');
|
|
364
|
-
console.log(`${
|
|
355
|
+
console.log(`${changes.length} change(s) staged for commit`);
|
|
365
356
|
}
|
|
366
357
|
console.log('');
|
|
367
|
-
console.log(
|
|
358
|
+
console.log('Import successful.');
|
|
368
359
|
console.log('');
|
|
369
360
|
if (changes.length > 0) {
|
|
370
|
-
(0, git_utils_1.hint)('
|
|
371
|
-
(0, git_utils_1.hint)('
|
|
361
|
+
(0, git_utils_1.hint)("run 'relq status' to see staged changes");
|
|
362
|
+
(0, git_utils_1.hint)("run 'relq commit -m <message>' to commit");
|
|
372
363
|
}
|
|
373
364
|
else {
|
|
374
|
-
(0, git_utils_1.hint)('
|
|
365
|
+
(0, git_utils_1.hint)("run 'relq status' to see current state");
|
|
375
366
|
}
|
|
376
367
|
console.log('');
|
|
377
368
|
}
|
|
@@ -468,6 +459,7 @@ function convertToDbSchema(parsed, functions = [], triggers = [], comments = [])
|
|
|
468
459
|
cycle: s.cycle,
|
|
469
460
|
ownedBy: s.ownedBy,
|
|
470
461
|
})) || [],
|
|
462
|
+
collations: [],
|
|
471
463
|
extensions: parsed.extensions,
|
|
472
464
|
partitions: parsed.partitions,
|
|
473
465
|
functions: functions.map(f => ({
|
|
@@ -736,6 +728,7 @@ function snapshotToDbSchemaForGeneration(snapshot) {
|
|
|
736
728
|
cycle: s.cycle,
|
|
737
729
|
ownedBy: s.ownedBy ?? undefined,
|
|
738
730
|
})) || [],
|
|
731
|
+
collations: [],
|
|
739
732
|
extensions: (snapshot.extensions || []).map(e => typeof e === 'string' ? e : e.name),
|
|
740
733
|
partitions: [],
|
|
741
734
|
functions: snapshot.functions?.map(f => ({
|
|
@@ -40,9 +40,9 @@ const readline = __importStar(require("readline"));
|
|
|
40
40
|
const env_loader_1 = require("../utils/env-loader.cjs");
|
|
41
41
|
const repo_manager_1 = require("../utils/repo-manager.cjs");
|
|
42
42
|
const relqignore_1 = require("../utils/relqignore.cjs");
|
|
43
|
-
const
|
|
43
|
+
const cli_utils_1 = require("../utils/cli-utils.cjs");
|
|
44
44
|
function ask(rl, question, defaultValue) {
|
|
45
|
-
const suffix = defaultValue ? ` ${
|
|
45
|
+
const suffix = defaultValue ? ` ${cli_utils_1.colors.muted(`[${defaultValue}]`)}` : '';
|
|
46
46
|
return new Promise((resolve) => {
|
|
47
47
|
rl.question(`${question}${suffix}: `, (answer) => {
|
|
48
48
|
resolve(answer.trim() || defaultValue || '');
|
|
@@ -50,7 +50,7 @@ function ask(rl, question, defaultValue) {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
function askYesNo(rl, question, defaultYes = true) {
|
|
53
|
-
const suffix = defaultYes ?
|
|
53
|
+
const suffix = defaultYes ? cli_utils_1.colors.muted('[Y/n]') : cli_utils_1.colors.muted('[y/N]');
|
|
54
54
|
return new Promise((resolve) => {
|
|
55
55
|
rl.question(`${question} ${suffix}: `, (answer) => {
|
|
56
56
|
const a = answer.trim().toLowerCase();
|
|
@@ -154,13 +154,11 @@ ${connectionBlock}
|
|
|
154
154
|
}
|
|
155
155
|
async function initCommand(context) {
|
|
156
156
|
const cwd = process.cwd();
|
|
157
|
-
const spinner = (0,
|
|
158
|
-
console.log('');
|
|
159
|
-
console.log(`${spinner_1.colors.bold('Relq')} - Git-like schema versioning for PostgreSQL`);
|
|
157
|
+
const spinner = (0, cli_utils_1.createSpinner)();
|
|
160
158
|
console.log('');
|
|
161
159
|
const { findConfigFileRecursive } = await Promise.resolve().then(() => __importStar(require("../utils/config-loader.cjs")));
|
|
160
|
+
const { findProjectRoot } = await Promise.resolve().then(() => __importStar(require("../utils/project-root.cjs")));
|
|
162
161
|
const existingConfig = findConfigFileRecursive(cwd);
|
|
163
|
-
const localRelqExists = (0, repo_manager_1.isInitialized)(cwd);
|
|
164
162
|
let projectRoot = cwd;
|
|
165
163
|
let existingConfigValues = null;
|
|
166
164
|
if (existingConfig) {
|
|
@@ -172,28 +170,35 @@ async function initCommand(context) {
|
|
|
172
170
|
catch {
|
|
173
171
|
}
|
|
174
172
|
if (existingConfig.directory !== cwd) {
|
|
175
|
-
|
|
176
|
-
console.log(`
|
|
173
|
+
(0, cli_utils_1.hint)(`Found relq.config.ts in: ${cli_utils_1.colors.cyan(existingConfig.directory)}`);
|
|
174
|
+
console.log(` Initializing at project root...`);
|
|
177
175
|
console.log('');
|
|
178
|
-
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
const packageRoot = findProjectRoot(cwd);
|
|
180
|
+
if (packageRoot && packageRoot !== cwd) {
|
|
181
|
+
projectRoot = packageRoot;
|
|
182
|
+
(0, cli_utils_1.hint)(`Found package.json in: ${cli_utils_1.colors.cyan(packageRoot)}`);
|
|
183
|
+
console.log(` Initializing at project root...`);
|
|
179
184
|
console.log('');
|
|
180
|
-
return;
|
|
181
185
|
}
|
|
186
|
+
}
|
|
187
|
+
if (existingConfig && existingConfig.directory === projectRoot) {
|
|
182
188
|
const relqFolderExists = (0, repo_manager_1.isInitialized)(projectRoot);
|
|
183
189
|
if (relqFolderExists) {
|
|
184
|
-
console.log(`${
|
|
190
|
+
console.log(`${cli_utils_1.colors.green('Relq is already initialized.')}`);
|
|
185
191
|
console.log('');
|
|
186
|
-
console.log(` ${
|
|
187
|
-
console.log(` ${
|
|
192
|
+
console.log(` ${cli_utils_1.colors.dim('-')} relq.config.ts`);
|
|
193
|
+
console.log(` ${cli_utils_1.colors.dim('-')} .relq/ folder`);
|
|
188
194
|
console.log('');
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
(0, cli_utils_1.hint)(`Use ${cli_utils_1.colors.cyan('relq status')} to see current state`);
|
|
196
|
+
(0, cli_utils_1.hint)(`Use ${cli_utils_1.colors.cyan('relq pull')} to sync with database`);
|
|
191
197
|
return;
|
|
192
198
|
}
|
|
193
199
|
else {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
console.log(`${spinner_1.colors.muted('This could mean the setup was incomplete.')}`);
|
|
200
|
+
(0, cli_utils_1.warning)('Found relq.config.ts but .relq/ folder is missing');
|
|
201
|
+
(0, cli_utils_1.hint)('This could mean the setup was incomplete');
|
|
197
202
|
console.log('');
|
|
198
203
|
const rl = readline.createInterface({
|
|
199
204
|
input: process.stdin,
|
|
@@ -217,12 +222,12 @@ async function initCommand(context) {
|
|
|
217
222
|
}
|
|
218
223
|
if (missingFields.length > 0) {
|
|
219
224
|
console.log('');
|
|
220
|
-
|
|
225
|
+
(0, cli_utils_1.warning)('Your config is missing required fields:');
|
|
221
226
|
for (const field of missingFields) {
|
|
222
|
-
console.log(` ${
|
|
227
|
+
console.log(` ${cli_utils_1.colors.dim('-')} ${field}`);
|
|
223
228
|
}
|
|
224
229
|
console.log('');
|
|
225
|
-
console.log(`${
|
|
230
|
+
console.log(`${cli_utils_1.colors.dim("Let's fill in the missing fields:")}`);
|
|
226
231
|
console.log('');
|
|
227
232
|
let authorValue = existingConfigValues?.author;
|
|
228
233
|
let schemaValue = existingConfigValues?.schema;
|
|
@@ -234,9 +239,9 @@ async function initCommand(context) {
|
|
|
234
239
|
}
|
|
235
240
|
if (missingFields.includes('connection')) {
|
|
236
241
|
console.log('');
|
|
237
|
-
console.log(
|
|
238
|
-
console.log(
|
|
239
|
-
console.log(
|
|
242
|
+
console.log('Connection not configured.');
|
|
243
|
+
console.log(' Set DATABASE_* environment variables in .env');
|
|
244
|
+
console.log(' or update relq.config.ts with connection details.');
|
|
240
245
|
rl.close();
|
|
241
246
|
return;
|
|
242
247
|
}
|
|
@@ -262,18 +267,18 @@ async function initCommand(context) {
|
|
|
262
267
|
}
|
|
263
268
|
rl.close();
|
|
264
269
|
console.log('');
|
|
265
|
-
console.log(
|
|
270
|
+
console.log('Completing setup...');
|
|
266
271
|
console.log('');
|
|
267
272
|
(0, repo_manager_1.initRepository)(projectRoot);
|
|
268
|
-
console.log(
|
|
273
|
+
console.log(' Created .relq/ folder');
|
|
269
274
|
(0, relqignore_1.createDefaultRelqignore)(projectRoot);
|
|
270
|
-
console.log(
|
|
275
|
+
console.log(' Created .relqignore');
|
|
271
276
|
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
272
277
|
if (fs.existsSync(gitignorePath)) {
|
|
273
278
|
const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
274
279
|
if (!gitignore.includes('.relq')) {
|
|
275
280
|
fs.appendFileSync(gitignorePath, '\n# Relq local state\n.relq/\n');
|
|
276
|
-
console.log(
|
|
281
|
+
console.log(' Added .relq/ to .gitignore');
|
|
277
282
|
}
|
|
278
283
|
}
|
|
279
284
|
if (existingConfigValues?.connection) {
|
|
@@ -287,14 +292,20 @@ async function initCommand(context) {
|
|
|
287
292
|
}
|
|
288
293
|
}
|
|
289
294
|
console.log('');
|
|
290
|
-
console.log(
|
|
295
|
+
console.log('Setup complete!');
|
|
291
296
|
console.log('');
|
|
292
|
-
|
|
297
|
+
const calledFrom = context.flags['called-from'];
|
|
298
|
+
if (calledFrom) {
|
|
299
|
+
console.log(`Continuing with ${calledFrom}...`);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
console.log('Run "relq pull" to sync with database.');
|
|
303
|
+
}
|
|
293
304
|
return;
|
|
294
305
|
}
|
|
295
306
|
rl.close();
|
|
296
307
|
console.log('');
|
|
297
|
-
console.log(`${
|
|
308
|
+
console.log(`${cli_utils_1.colors.muted('Cancelled.')}`);
|
|
298
309
|
return;
|
|
299
310
|
}
|
|
300
311
|
catch {
|
|
@@ -308,7 +319,7 @@ async function initCommand(context) {
|
|
|
308
319
|
output: process.stdout,
|
|
309
320
|
});
|
|
310
321
|
try {
|
|
311
|
-
console.log(
|
|
322
|
+
console.log('Checking for database connection...');
|
|
312
323
|
console.log('');
|
|
313
324
|
const envCheck = checkEnvVars();
|
|
314
325
|
let useEnv = false;
|
|
@@ -318,28 +329,28 @@ async function initCommand(context) {
|
|
|
318
329
|
let user = 'postgres';
|
|
319
330
|
let password = '';
|
|
320
331
|
if (envCheck.found) {
|
|
321
|
-
console.log(
|
|
332
|
+
console.log('Found database environment variables:');
|
|
322
333
|
if (envCheck.vars.RELQ_PG_CONN_URL) {
|
|
323
|
-
console.log(
|
|
334
|
+
console.log(' RELQ_PG_CONN_URL');
|
|
324
335
|
}
|
|
325
336
|
else {
|
|
326
337
|
if (envCheck.vars.DATABASE_HOST)
|
|
327
|
-
console.log(`
|
|
338
|
+
console.log(` DATABASE_HOST: ${envCheck.vars.DATABASE_HOST}`);
|
|
328
339
|
if (envCheck.vars.DATABASE_PORT)
|
|
329
|
-
console.log(`
|
|
340
|
+
console.log(` DATABASE_PORT: ${envCheck.vars.DATABASE_PORT}`);
|
|
330
341
|
if (envCheck.vars.DATABASE_NAME)
|
|
331
|
-
console.log(`
|
|
342
|
+
console.log(` DATABASE_NAME: ${envCheck.vars.DATABASE_NAME}`);
|
|
332
343
|
if (envCheck.vars.DATABASE_USER)
|
|
333
|
-
console.log(`
|
|
344
|
+
console.log(` DATABASE_USER: ${envCheck.vars.DATABASE_USER}`);
|
|
334
345
|
if (envCheck.vars.DATABASE_PASSWORD)
|
|
335
|
-
console.log(
|
|
346
|
+
console.log(' DATABASE_PASSWORD: ***');
|
|
336
347
|
}
|
|
337
348
|
console.log('');
|
|
338
349
|
useEnv = await askYesNo(rl, 'Use these environment variables?', true);
|
|
339
350
|
console.log('');
|
|
340
351
|
}
|
|
341
352
|
if (!useEnv) {
|
|
342
|
-
console.log(
|
|
353
|
+
console.log('Database Connection');
|
|
343
354
|
console.log('');
|
|
344
355
|
host = await ask(rl, ' Host', 'localhost');
|
|
345
356
|
port = await ask(rl, ' Port', '5432');
|
|
@@ -349,21 +360,21 @@ async function initCommand(context) {
|
|
|
349
360
|
console.log('');
|
|
350
361
|
}
|
|
351
362
|
const detectedPath = detectSchemaPath();
|
|
352
|
-
console.log(
|
|
363
|
+
console.log('Schema Configuration');
|
|
353
364
|
console.log('');
|
|
354
365
|
const schemaPath = await ask(rl, ' Schema file path', detectedPath);
|
|
355
366
|
console.log('');
|
|
356
|
-
console.log(
|
|
367
|
+
console.log('Author (for commit history)');
|
|
357
368
|
console.log('');
|
|
358
369
|
const author = await ask(rl, ' Name <email>', 'Developer <dev@example.com>');
|
|
359
370
|
console.log('');
|
|
360
|
-
console.log(
|
|
371
|
+
console.log('Features to track');
|
|
361
372
|
console.log('');
|
|
362
373
|
const includeFunctions = await askYesNo(rl, ' Include functions?', false);
|
|
363
374
|
const includeTriggers = await askYesNo(rl, ' Include triggers?', false);
|
|
364
375
|
console.log('');
|
|
365
376
|
rl.close();
|
|
366
|
-
console.log(
|
|
377
|
+
console.log('Creating files...');
|
|
367
378
|
console.log('');
|
|
368
379
|
const configPath = path.join(cwd, 'relq.config.ts');
|
|
369
380
|
if (!fs.existsSync(configPath)) {
|
|
@@ -380,26 +391,26 @@ async function initCommand(context) {
|
|
|
380
391
|
includeTriggers,
|
|
381
392
|
});
|
|
382
393
|
fs.writeFileSync(configPath, configContent, 'utf-8');
|
|
383
|
-
console.log(
|
|
394
|
+
console.log(' Created relq.config.ts');
|
|
384
395
|
}
|
|
385
396
|
else {
|
|
386
|
-
console.log(
|
|
397
|
+
console.log(' relq.config.ts already exists');
|
|
387
398
|
}
|
|
388
399
|
(0, repo_manager_1.initRepository)(cwd);
|
|
389
|
-
console.log(
|
|
400
|
+
console.log(' Created .relq/ folder');
|
|
390
401
|
(0, relqignore_1.createDefaultRelqignore)(cwd);
|
|
391
|
-
console.log(
|
|
402
|
+
console.log(' Created .relqignore');
|
|
392
403
|
const schemaDir = path.dirname(schemaPath);
|
|
393
404
|
if (!fs.existsSync(schemaDir)) {
|
|
394
405
|
fs.mkdirSync(schemaDir, { recursive: true });
|
|
395
|
-
console.log(`
|
|
406
|
+
console.log(` Created ${schemaDir}/`);
|
|
396
407
|
}
|
|
397
408
|
const gitignorePath = path.join(cwd, '.gitignore');
|
|
398
409
|
if (fs.existsSync(gitignorePath)) {
|
|
399
410
|
const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
400
411
|
if (!gitignore.includes('.relq')) {
|
|
401
412
|
fs.appendFileSync(gitignorePath, '\n# Relq local state\n.relq/\n');
|
|
402
|
-
console.log(
|
|
413
|
+
console.log(' Added .relq/ to .gitignore');
|
|
403
414
|
}
|
|
404
415
|
}
|
|
405
416
|
console.log('');
|
|
@@ -418,20 +429,19 @@ async function initCommand(context) {
|
|
|
418
429
|
}
|
|
419
430
|
catch (error) {
|
|
420
431
|
spinner.fail('Could not connect to database');
|
|
421
|
-
|
|
432
|
+
(0, cli_utils_1.hint)("run 'relq pull' after fixing connection");
|
|
422
433
|
}
|
|
423
434
|
console.log('');
|
|
424
|
-
console.log(
|
|
435
|
+
console.log('Relq initialized successfully!');
|
|
425
436
|
console.log('');
|
|
426
|
-
console.log(
|
|
427
|
-
console.log(
|
|
428
|
-
console.log(
|
|
429
|
-
console.log(
|
|
437
|
+
console.log('Next steps:');
|
|
438
|
+
console.log(" 1. Review 'relq.config.ts'");
|
|
439
|
+
console.log(" 2. Run 'relq pull' to sync with database");
|
|
440
|
+
console.log(" 3. Run 'relq status' to see current state");
|
|
430
441
|
console.log('');
|
|
431
442
|
}
|
|
432
443
|
catch (error) {
|
|
433
444
|
rl.close();
|
|
434
|
-
|
|
435
|
-
process.exit(1);
|
|
445
|
+
(0, cli_utils_1.fatal)('Initialization failed', error instanceof Error ? error.message : String(error));
|
|
436
446
|
}
|
|
437
447
|
}
|
|
@@ -37,6 +37,7 @@ exports.introspectCommand = introspectCommand;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const readline = __importStar(require("readline"));
|
|
39
39
|
const index_1 = require("../../introspect/index.cjs");
|
|
40
|
+
const cli_utils_1 = require("../utils/cli-utils.cjs");
|
|
40
41
|
function readStdin() {
|
|
41
42
|
return new Promise((resolve) => {
|
|
42
43
|
let data = '';
|
|
@@ -79,8 +80,7 @@ async function introspectCommand(context) {
|
|
|
79
80
|
let sql;
|
|
80
81
|
if (filePath) {
|
|
81
82
|
if (!fs.existsSync(filePath)) {
|
|
82
|
-
|
|
83
|
-
process.exit(1);
|
|
83
|
+
(0, cli_utils_1.fatal)(`File not found: ${filePath}`, 'Check the file path and try again.');
|
|
84
84
|
}
|
|
85
85
|
sql = fs.readFileSync(filePath, 'utf-8');
|
|
86
86
|
console.log(`📄 Reading from: ${filePath}\n`);
|
|
@@ -92,10 +92,7 @@ async function introspectCommand(context) {
|
|
|
92
92
|
sql = await readInteractive();
|
|
93
93
|
}
|
|
94
94
|
if (!sql.trim()) {
|
|
95
|
-
|
|
96
|
-
console.error('Usage: relq introspect --file schema.sql');
|
|
97
|
-
console.error(' or: cat schema.sql | relq introspect');
|
|
98
|
-
process.exit(1);
|
|
95
|
+
(0, cli_utils_1.fatal)('No SQL input provided', 'Usage: relq introspect --file schema.sql\n or: cat schema.sql | relq introspect');
|
|
99
96
|
}
|
|
100
97
|
console.log('🔍 Parsing SQL...\n');
|
|
101
98
|
try {
|
|
@@ -116,8 +113,7 @@ async function introspectCommand(context) {
|
|
|
116
113
|
console.log(output.join('\n'));
|
|
117
114
|
}
|
|
118
115
|
catch (error) {
|
|
119
|
-
|
|
120
|
-
process.exit(1);
|
|
116
|
+
(0, cli_utils_1.fatal)('Error parsing SQL', error instanceof Error ? error.message : String(error));
|
|
121
117
|
}
|
|
122
118
|
}
|
|
123
119
|
function generateDefineTableCode(table) {
|