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
|
@@ -4,7 +4,7 @@ import * as readline from 'readline';
|
|
|
4
4
|
import { loadEnvConfig } from "../utils/env-loader.js";
|
|
5
5
|
import { initRepository, ensureRemoteTable, isInitialized } from "../utils/repo-manager.js";
|
|
6
6
|
import { createDefaultRelqignore } from "../utils/relqignore.js";
|
|
7
|
-
import { colors, createSpinner } from "../utils/
|
|
7
|
+
import { colors, createSpinner, fatal, warning, hint } from "../utils/cli-utils.js";
|
|
8
8
|
function ask(rl, question, defaultValue) {
|
|
9
9
|
const suffix = defaultValue ? ` ${colors.muted(`[${defaultValue}]`)}` : '';
|
|
10
10
|
return new Promise((resolve) => {
|
|
@@ -120,11 +120,9 @@ export async function initCommand(context) {
|
|
|
120
120
|
const cwd = process.cwd();
|
|
121
121
|
const spinner = createSpinner();
|
|
122
122
|
console.log('');
|
|
123
|
-
console.log(`${colors.bold('Relq')} - Git-like schema versioning for PostgreSQL`);
|
|
124
|
-
console.log('');
|
|
125
123
|
const { findConfigFileRecursive } = await import("../utils/config-loader.js");
|
|
124
|
+
const { findProjectRoot } = await import("../utils/project-root.js");
|
|
126
125
|
const existingConfig = findConfigFileRecursive(cwd);
|
|
127
|
-
const localRelqExists = isInitialized(cwd);
|
|
128
126
|
let projectRoot = cwd;
|
|
129
127
|
let existingConfigValues = null;
|
|
130
128
|
if (existingConfig) {
|
|
@@ -136,28 +134,35 @@ export async function initCommand(context) {
|
|
|
136
134
|
catch {
|
|
137
135
|
}
|
|
138
136
|
if (existingConfig.directory !== cwd) {
|
|
139
|
-
|
|
140
|
-
console.log(`
|
|
137
|
+
hint(`Found relq.config.ts in: ${colors.cyan(existingConfig.directory)}`);
|
|
138
|
+
console.log(` Initializing at project root...`);
|
|
141
139
|
console.log('');
|
|
142
|
-
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
const packageRoot = findProjectRoot(cwd);
|
|
144
|
+
if (packageRoot && packageRoot !== cwd) {
|
|
145
|
+
projectRoot = packageRoot;
|
|
146
|
+
hint(`Found package.json in: ${colors.cyan(packageRoot)}`);
|
|
147
|
+
console.log(` Initializing at project root...`);
|
|
143
148
|
console.log('');
|
|
144
|
-
return;
|
|
145
149
|
}
|
|
150
|
+
}
|
|
151
|
+
if (existingConfig && existingConfig.directory === projectRoot) {
|
|
146
152
|
const relqFolderExists = isInitialized(projectRoot);
|
|
147
153
|
if (relqFolderExists) {
|
|
148
|
-
console.log(`${colors.green('
|
|
154
|
+
console.log(`${colors.green('Relq is already initialized.')}`);
|
|
149
155
|
console.log('');
|
|
150
|
-
console.log(` ${colors.
|
|
151
|
-
console.log(` ${colors.
|
|
156
|
+
console.log(` ${colors.dim('-')} relq.config.ts`);
|
|
157
|
+
console.log(` ${colors.dim('-')} .relq/ folder`);
|
|
152
158
|
console.log('');
|
|
153
|
-
|
|
154
|
-
|
|
159
|
+
hint(`Use ${colors.cyan('relq status')} to see current state`);
|
|
160
|
+
hint(`Use ${colors.cyan('relq pull')} to sync with database`);
|
|
155
161
|
return;
|
|
156
162
|
}
|
|
157
163
|
else {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
console.log(`${colors.muted('This could mean the setup was incomplete.')}`);
|
|
164
|
+
warning('Found relq.config.ts but .relq/ folder is missing');
|
|
165
|
+
hint('This could mean the setup was incomplete');
|
|
161
166
|
console.log('');
|
|
162
167
|
const rl = readline.createInterface({
|
|
163
168
|
input: process.stdin,
|
|
@@ -181,12 +186,12 @@ export async function initCommand(context) {
|
|
|
181
186
|
}
|
|
182
187
|
if (missingFields.length > 0) {
|
|
183
188
|
console.log('');
|
|
184
|
-
|
|
189
|
+
warning('Your config is missing required fields:');
|
|
185
190
|
for (const field of missingFields) {
|
|
186
|
-
console.log(` ${colors.
|
|
191
|
+
console.log(` ${colors.dim('-')} ${field}`);
|
|
187
192
|
}
|
|
188
193
|
console.log('');
|
|
189
|
-
console.log(`${colors.
|
|
194
|
+
console.log(`${colors.dim("Let's fill in the missing fields:")}`);
|
|
190
195
|
console.log('');
|
|
191
196
|
let authorValue = existingConfigValues?.author;
|
|
192
197
|
let schemaValue = existingConfigValues?.schema;
|
|
@@ -198,9 +203,9 @@ export async function initCommand(context) {
|
|
|
198
203
|
}
|
|
199
204
|
if (missingFields.includes('connection')) {
|
|
200
205
|
console.log('');
|
|
201
|
-
console.log(
|
|
202
|
-
console.log(
|
|
203
|
-
console.log(
|
|
206
|
+
console.log('Connection not configured.');
|
|
207
|
+
console.log(' Set DATABASE_* environment variables in .env');
|
|
208
|
+
console.log(' or update relq.config.ts with connection details.');
|
|
204
209
|
rl.close();
|
|
205
210
|
return;
|
|
206
211
|
}
|
|
@@ -226,18 +231,18 @@ export async function initCommand(context) {
|
|
|
226
231
|
}
|
|
227
232
|
rl.close();
|
|
228
233
|
console.log('');
|
|
229
|
-
console.log(
|
|
234
|
+
console.log('Completing setup...');
|
|
230
235
|
console.log('');
|
|
231
236
|
initRepository(projectRoot);
|
|
232
|
-
console.log(
|
|
237
|
+
console.log(' Created .relq/ folder');
|
|
233
238
|
createDefaultRelqignore(projectRoot);
|
|
234
|
-
console.log(
|
|
239
|
+
console.log(' Created .relqignore');
|
|
235
240
|
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
236
241
|
if (fs.existsSync(gitignorePath)) {
|
|
237
242
|
const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
238
243
|
if (!gitignore.includes('.relq')) {
|
|
239
244
|
fs.appendFileSync(gitignorePath, '\n# Relq local state\n.relq/\n');
|
|
240
|
-
console.log(
|
|
245
|
+
console.log(' Added .relq/ to .gitignore');
|
|
241
246
|
}
|
|
242
247
|
}
|
|
243
248
|
if (existingConfigValues?.connection) {
|
|
@@ -251,9 +256,15 @@ export async function initCommand(context) {
|
|
|
251
256
|
}
|
|
252
257
|
}
|
|
253
258
|
console.log('');
|
|
254
|
-
console.log(
|
|
259
|
+
console.log('Setup complete!');
|
|
255
260
|
console.log('');
|
|
256
|
-
|
|
261
|
+
const calledFrom = context.flags['called-from'];
|
|
262
|
+
if (calledFrom) {
|
|
263
|
+
console.log(`Continuing with ${calledFrom}...`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
console.log('Run "relq pull" to sync with database.');
|
|
267
|
+
}
|
|
257
268
|
return;
|
|
258
269
|
}
|
|
259
270
|
rl.close();
|
|
@@ -272,7 +283,7 @@ export async function initCommand(context) {
|
|
|
272
283
|
output: process.stdout,
|
|
273
284
|
});
|
|
274
285
|
try {
|
|
275
|
-
console.log(
|
|
286
|
+
console.log('Checking for database connection...');
|
|
276
287
|
console.log('');
|
|
277
288
|
const envCheck = checkEnvVars();
|
|
278
289
|
let useEnv = false;
|
|
@@ -282,28 +293,28 @@ export async function initCommand(context) {
|
|
|
282
293
|
let user = 'postgres';
|
|
283
294
|
let password = '';
|
|
284
295
|
if (envCheck.found) {
|
|
285
|
-
console.log(
|
|
296
|
+
console.log('Found database environment variables:');
|
|
286
297
|
if (envCheck.vars.RELQ_PG_CONN_URL) {
|
|
287
|
-
console.log(
|
|
298
|
+
console.log(' RELQ_PG_CONN_URL');
|
|
288
299
|
}
|
|
289
300
|
else {
|
|
290
301
|
if (envCheck.vars.DATABASE_HOST)
|
|
291
|
-
console.log(`
|
|
302
|
+
console.log(` DATABASE_HOST: ${envCheck.vars.DATABASE_HOST}`);
|
|
292
303
|
if (envCheck.vars.DATABASE_PORT)
|
|
293
|
-
console.log(`
|
|
304
|
+
console.log(` DATABASE_PORT: ${envCheck.vars.DATABASE_PORT}`);
|
|
294
305
|
if (envCheck.vars.DATABASE_NAME)
|
|
295
|
-
console.log(`
|
|
306
|
+
console.log(` DATABASE_NAME: ${envCheck.vars.DATABASE_NAME}`);
|
|
296
307
|
if (envCheck.vars.DATABASE_USER)
|
|
297
|
-
console.log(`
|
|
308
|
+
console.log(` DATABASE_USER: ${envCheck.vars.DATABASE_USER}`);
|
|
298
309
|
if (envCheck.vars.DATABASE_PASSWORD)
|
|
299
|
-
console.log(
|
|
310
|
+
console.log(' DATABASE_PASSWORD: ***');
|
|
300
311
|
}
|
|
301
312
|
console.log('');
|
|
302
313
|
useEnv = await askYesNo(rl, 'Use these environment variables?', true);
|
|
303
314
|
console.log('');
|
|
304
315
|
}
|
|
305
316
|
if (!useEnv) {
|
|
306
|
-
console.log(
|
|
317
|
+
console.log('Database Connection');
|
|
307
318
|
console.log('');
|
|
308
319
|
host = await ask(rl, ' Host', 'localhost');
|
|
309
320
|
port = await ask(rl, ' Port', '5432');
|
|
@@ -313,21 +324,21 @@ export async function initCommand(context) {
|
|
|
313
324
|
console.log('');
|
|
314
325
|
}
|
|
315
326
|
const detectedPath = detectSchemaPath();
|
|
316
|
-
console.log(
|
|
327
|
+
console.log('Schema Configuration');
|
|
317
328
|
console.log('');
|
|
318
329
|
const schemaPath = await ask(rl, ' Schema file path', detectedPath);
|
|
319
330
|
console.log('');
|
|
320
|
-
console.log(
|
|
331
|
+
console.log('Author (for commit history)');
|
|
321
332
|
console.log('');
|
|
322
333
|
const author = await ask(rl, ' Name <email>', 'Developer <dev@example.com>');
|
|
323
334
|
console.log('');
|
|
324
|
-
console.log(
|
|
335
|
+
console.log('Features to track');
|
|
325
336
|
console.log('');
|
|
326
337
|
const includeFunctions = await askYesNo(rl, ' Include functions?', false);
|
|
327
338
|
const includeTriggers = await askYesNo(rl, ' Include triggers?', false);
|
|
328
339
|
console.log('');
|
|
329
340
|
rl.close();
|
|
330
|
-
console.log(
|
|
341
|
+
console.log('Creating files...');
|
|
331
342
|
console.log('');
|
|
332
343
|
const configPath = path.join(cwd, 'relq.config.ts');
|
|
333
344
|
if (!fs.existsSync(configPath)) {
|
|
@@ -344,26 +355,26 @@ export async function initCommand(context) {
|
|
|
344
355
|
includeTriggers,
|
|
345
356
|
});
|
|
346
357
|
fs.writeFileSync(configPath, configContent, 'utf-8');
|
|
347
|
-
console.log(
|
|
358
|
+
console.log(' Created relq.config.ts');
|
|
348
359
|
}
|
|
349
360
|
else {
|
|
350
|
-
console.log(
|
|
361
|
+
console.log(' relq.config.ts already exists');
|
|
351
362
|
}
|
|
352
363
|
initRepository(cwd);
|
|
353
|
-
console.log(
|
|
364
|
+
console.log(' Created .relq/ folder');
|
|
354
365
|
createDefaultRelqignore(cwd);
|
|
355
|
-
console.log(
|
|
366
|
+
console.log(' Created .relqignore');
|
|
356
367
|
const schemaDir = path.dirname(schemaPath);
|
|
357
368
|
if (!fs.existsSync(schemaDir)) {
|
|
358
369
|
fs.mkdirSync(schemaDir, { recursive: true });
|
|
359
|
-
console.log(`
|
|
370
|
+
console.log(` Created ${schemaDir}/`);
|
|
360
371
|
}
|
|
361
372
|
const gitignorePath = path.join(cwd, '.gitignore');
|
|
362
373
|
if (fs.existsSync(gitignorePath)) {
|
|
363
374
|
const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
364
375
|
if (!gitignore.includes('.relq')) {
|
|
365
376
|
fs.appendFileSync(gitignorePath, '\n# Relq local state\n.relq/\n');
|
|
366
|
-
console.log(
|
|
377
|
+
console.log(' Added .relq/ to .gitignore');
|
|
367
378
|
}
|
|
368
379
|
}
|
|
369
380
|
console.log('');
|
|
@@ -382,20 +393,19 @@ export async function initCommand(context) {
|
|
|
382
393
|
}
|
|
383
394
|
catch (error) {
|
|
384
395
|
spinner.fail('Could not connect to database');
|
|
385
|
-
|
|
396
|
+
hint("run 'relq pull' after fixing connection");
|
|
386
397
|
}
|
|
387
398
|
console.log('');
|
|
388
|
-
console.log(
|
|
399
|
+
console.log('Relq initialized successfully!');
|
|
389
400
|
console.log('');
|
|
390
|
-
console.log(
|
|
391
|
-
console.log(
|
|
392
|
-
console.log(
|
|
393
|
-
console.log(
|
|
401
|
+
console.log('Next steps:');
|
|
402
|
+
console.log(" 1. Review 'relq.config.ts'");
|
|
403
|
+
console.log(" 2. Run 'relq pull' to sync with database");
|
|
404
|
+
console.log(" 3. Run 'relq status' to see current state");
|
|
394
405
|
console.log('');
|
|
395
406
|
}
|
|
396
407
|
catch (error) {
|
|
397
408
|
rl.close();
|
|
398
|
-
|
|
399
|
-
process.exit(1);
|
|
409
|
+
fatal('Initialization failed', error instanceof Error ? error.message : String(error));
|
|
400
410
|
}
|
|
401
411
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as readline from 'readline';
|
|
3
3
|
import { parseSqlToDefineTable } from "../../introspect/index.js";
|
|
4
|
+
import { fatal } from "../utils/cli-utils.js";
|
|
4
5
|
function readStdin() {
|
|
5
6
|
return new Promise((resolve) => {
|
|
6
7
|
let data = '';
|
|
@@ -43,8 +44,7 @@ export async function introspectCommand(context) {
|
|
|
43
44
|
let sql;
|
|
44
45
|
if (filePath) {
|
|
45
46
|
if (!fs.existsSync(filePath)) {
|
|
46
|
-
|
|
47
|
-
process.exit(1);
|
|
47
|
+
fatal(`File not found: ${filePath}`, 'Check the file path and try again.');
|
|
48
48
|
}
|
|
49
49
|
sql = fs.readFileSync(filePath, 'utf-8');
|
|
50
50
|
console.log(`📄 Reading from: ${filePath}\n`);
|
|
@@ -56,10 +56,7 @@ export async function introspectCommand(context) {
|
|
|
56
56
|
sql = await readInteractive();
|
|
57
57
|
}
|
|
58
58
|
if (!sql.trim()) {
|
|
59
|
-
|
|
60
|
-
console.error('Usage: relq introspect --file schema.sql');
|
|
61
|
-
console.error(' or: cat schema.sql | relq introspect');
|
|
62
|
-
process.exit(1);
|
|
59
|
+
fatal('No SQL input provided', 'Usage: relq introspect --file schema.sql\n or: cat schema.sql | relq introspect');
|
|
63
60
|
}
|
|
64
61
|
console.log('🔍 Parsing SQL...\n');
|
|
65
62
|
try {
|
|
@@ -80,8 +77,7 @@ export async function introspectCommand(context) {
|
|
|
80
77
|
console.log(output.join('\n'));
|
|
81
78
|
}
|
|
82
79
|
catch (error) {
|
|
83
|
-
|
|
84
|
-
process.exit(1);
|
|
80
|
+
fatal('Error parsing SQL', error instanceof Error ? error.message : String(error));
|
|
85
81
|
}
|
|
86
82
|
}
|
|
87
83
|
function generateDefineTableCode(table) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { colors } from "../utils/
|
|
1
|
+
import { colors, fatal, hint } from "../utils/cli-utils.js";
|
|
2
2
|
import { isInitialized, getHead, getCommitHistory, shortHash, } from "../utils/repo-manager.js";
|
|
3
3
|
function formatDate(timestamp) {
|
|
4
4
|
const date = new Date(timestamp);
|
|
@@ -12,23 +12,18 @@ function formatDate(timestamp) {
|
|
|
12
12
|
return `${dayName} ${monthName} ${day} ${time} ${year}`;
|
|
13
13
|
}
|
|
14
14
|
export async function logCommand(context) {
|
|
15
|
-
const { flags } = context;
|
|
16
|
-
const projectRoot = process.cwd();
|
|
15
|
+
const { flags, projectRoot } = context;
|
|
17
16
|
const limit = parseInt(flags['n']) || 10;
|
|
18
17
|
const oneline = flags['oneline'] === true;
|
|
19
18
|
console.log('');
|
|
20
19
|
if (!isInitialized(projectRoot)) {
|
|
21
|
-
|
|
22
|
-
console.log('');
|
|
23
|
-
console.log(`${colors.muted('Run')} ${colors.cyan('relq init')} ${colors.muted('to initialize.')}`);
|
|
24
|
-
return;
|
|
20
|
+
fatal('not a relq repository (or any parent directories): .relq', "run 'relq init' to initialize");
|
|
25
21
|
}
|
|
26
22
|
const head = getHead(projectRoot);
|
|
27
23
|
const commits = getCommitHistory(limit, projectRoot);
|
|
28
24
|
if (commits.length === 0) {
|
|
29
|
-
console.log(
|
|
30
|
-
|
|
31
|
-
console.log(`${colors.muted('Run')} ${colors.cyan('relq commit -m "message"')} ${colors.muted('to create first commit.')}`);
|
|
25
|
+
console.log('No commits yet.');
|
|
26
|
+
hint("run 'relq commit -m <message>' to create first commit");
|
|
32
27
|
console.log('');
|
|
33
28
|
return;
|
|
34
29
|
}
|
|
@@ -56,4 +51,77 @@ export async function logCommand(context) {
|
|
|
56
51
|
console.log('');
|
|
57
52
|
}
|
|
58
53
|
}
|
|
54
|
+
export async function showCommand(context) {
|
|
55
|
+
const { args, projectRoot } = context;
|
|
56
|
+
const target = args[0];
|
|
57
|
+
console.log('');
|
|
58
|
+
if (!isInitialized(projectRoot)) {
|
|
59
|
+
console.log(`${colors.red('fatal:')} not a relq repository`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!target) {
|
|
63
|
+
console.log(`${colors.red('error:')} Please specify a commit or tag`);
|
|
64
|
+
console.log('');
|
|
65
|
+
console.log(`Usage: ${colors.cyan('relq show <commit|tag>')}`);
|
|
66
|
+
console.log('');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const fs = require('fs');
|
|
70
|
+
const path = require('path');
|
|
71
|
+
const { resolveRef, loadCommit } = require('../utils/repo-manager');
|
|
72
|
+
const hash = resolveRef(target, projectRoot);
|
|
73
|
+
if (!hash) {
|
|
74
|
+
console.log(`${colors.red('error:')} Commit or tag not found: ${target}`);
|
|
75
|
+
console.log('');
|
|
76
|
+
console.log('Available commits:');
|
|
77
|
+
const commitsDir = path.join(projectRoot, '.relq', 'commits');
|
|
78
|
+
if (fs.existsSync(commitsDir)) {
|
|
79
|
+
const files = fs.readdirSync(commitsDir);
|
|
80
|
+
for (const f of files.slice(0, 5)) {
|
|
81
|
+
console.log(` ${colors.yellow(shortHash(f.replace('.json', '')))}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const commitPath = path.join(projectRoot, '.relq', 'commits', `${hash}.json`);
|
|
87
|
+
if (!fs.existsSync(commitPath)) {
|
|
88
|
+
console.log(`${colors.red('error:')} Commit not found: ${hash}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const commitData = JSON.parse(fs.readFileSync(commitPath, 'utf-8'));
|
|
92
|
+
console.log(`${colors.yellow(`commit ${commitData.hash}`)}`);
|
|
93
|
+
console.log(`Author: ${commitData.author}`);
|
|
94
|
+
console.log(`Date: ${formatDate(commitData.timestamp)}`);
|
|
95
|
+
console.log('');
|
|
96
|
+
console.log(` ${commitData.message}`);
|
|
97
|
+
console.log('');
|
|
98
|
+
if (commitData.stats) {
|
|
99
|
+
console.log(`${colors.bold('Stats:')}`);
|
|
100
|
+
console.log(` Tables: ${commitData.stats.tables}`);
|
|
101
|
+
console.log(` Columns: ${commitData.stats.columns}`);
|
|
102
|
+
console.log(` Indexes: ${commitData.stats.indexes || 0}`);
|
|
103
|
+
console.log('');
|
|
104
|
+
}
|
|
105
|
+
if (commitData.changes && commitData.changes.length > 0) {
|
|
106
|
+
console.log(`${colors.bold('Changes:')}`);
|
|
107
|
+
for (const change of commitData.changes.slice(0, 20)) {
|
|
108
|
+
const symbol = change.action === 'CREATE'
|
|
109
|
+
? colors.green('+')
|
|
110
|
+
: change.action === 'DROP'
|
|
111
|
+
? colors.red('-')
|
|
112
|
+
: colors.yellow('~');
|
|
113
|
+
console.log(` ${symbol} ${change.objectType.toLowerCase()}: ${change.name}`);
|
|
114
|
+
}
|
|
115
|
+
if (commitData.changes.length > 20) {
|
|
116
|
+
console.log(` ${colors.muted(`... and ${commitData.changes.length - 20} more`)}`);
|
|
117
|
+
}
|
|
118
|
+
console.log('');
|
|
119
|
+
}
|
|
120
|
+
if (commitData.sql && commitData.sql.trim()) {
|
|
121
|
+
console.log(`${colors.bold('SQL:')}`);
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log(`${colors.cyan(commitData.sql)}`);
|
|
124
|
+
console.log('');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
59
127
|
export { logCommand as historyCommand };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { colors, createSpinner, fatal } from "../utils/cli-utils.js";
|
|
4
|
+
import { isInitialized, getHead, loadCommit, loadSnapshot, saveSnapshot, createCommit, shortHash, } from "../utils/repo-manager.js";
|
|
5
|
+
function loadBranchState(projectRoot) {
|
|
6
|
+
const branchPath = path.join(projectRoot, '.relq', 'branches.json');
|
|
7
|
+
if (fs.existsSync(branchPath)) {
|
|
8
|
+
return JSON.parse(fs.readFileSync(branchPath, 'utf-8'));
|
|
9
|
+
}
|
|
10
|
+
const head = require('../utils/repo-manager').getHead(projectRoot);
|
|
11
|
+
return { current: 'main', branches: { main: head || '' } };
|
|
12
|
+
}
|
|
13
|
+
function saveBranchState(state, projectRoot) {
|
|
14
|
+
const branchPath = path.join(projectRoot, '.relq', 'branches.json');
|
|
15
|
+
fs.writeFileSync(branchPath, JSON.stringify(state, null, 2));
|
|
16
|
+
}
|
|
17
|
+
export async function mergeCommand(context) {
|
|
18
|
+
const { config, args, flags, projectRoot } = context;
|
|
19
|
+
console.log('');
|
|
20
|
+
if (!isInitialized(projectRoot)) {
|
|
21
|
+
fatal('not a relq repository (or any parent directories): .relq', `Run ${colors.cyan('relq init')} to initialize.`);
|
|
22
|
+
}
|
|
23
|
+
const branchName = args[0];
|
|
24
|
+
const abort = flags['abort'] === true;
|
|
25
|
+
const mergeStatePath = path.join(projectRoot, '.relq', 'MERGE_STATE');
|
|
26
|
+
if (abort) {
|
|
27
|
+
if (fs.existsSync(mergeStatePath)) {
|
|
28
|
+
fs.unlinkSync(mergeStatePath);
|
|
29
|
+
console.log('Merge aborted');
|
|
30
|
+
console.log('');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
fatal('There is no merge to abort (MERGE_STATE missing)');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (fs.existsSync(mergeStatePath)) {
|
|
38
|
+
const mergeState = JSON.parse(fs.readFileSync(mergeStatePath, 'utf-8'));
|
|
39
|
+
fatal(`Merge in progress from '${mergeState.fromBranch}'`, `Use ${colors.cyan('relq resolve')} to resolve conflicts\nOr ${colors.cyan('relq merge --abort')} to cancel`);
|
|
40
|
+
}
|
|
41
|
+
if (!branchName) {
|
|
42
|
+
fatal('Please specify a branch to merge', `Usage: ${colors.cyan('relq merge <branch>')}`);
|
|
43
|
+
}
|
|
44
|
+
const state = loadBranchState(projectRoot);
|
|
45
|
+
if (!state.branches[branchName]) {
|
|
46
|
+
fatal(`Branch not found: ${branchName}`, `Use ${colors.cyan('relq branch')} to list available branches.`);
|
|
47
|
+
}
|
|
48
|
+
if (branchName === state.current) {
|
|
49
|
+
fatal('Cannot merge branch into itself');
|
|
50
|
+
}
|
|
51
|
+
const spinner = createSpinner();
|
|
52
|
+
spinner.start(`Merging '${branchName}' into '${state.current}'...`);
|
|
53
|
+
try {
|
|
54
|
+
const currentHash = getHead(projectRoot);
|
|
55
|
+
const incomingHash = state.branches[branchName];
|
|
56
|
+
if (!currentHash || !incomingHash) {
|
|
57
|
+
spinner.stop();
|
|
58
|
+
fatal('No commits to merge', `Run ${colors.cyan('relq pull')} first.`);
|
|
59
|
+
}
|
|
60
|
+
if (currentHash === incomingHash) {
|
|
61
|
+
spinner.succeed('Already up to date');
|
|
62
|
+
console.log('');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const currentCommit = loadCommit(currentHash, projectRoot);
|
|
66
|
+
const incomingCommit = loadCommit(incomingHash, projectRoot);
|
|
67
|
+
if (!currentCommit || !incomingCommit) {
|
|
68
|
+
spinner.stop();
|
|
69
|
+
fatal('Cannot load commit data - repository may be corrupt');
|
|
70
|
+
}
|
|
71
|
+
const currentSnapshot = loadSnapshot(projectRoot) || currentCommit.schema;
|
|
72
|
+
const incomingSnapshot = incomingCommit.schema;
|
|
73
|
+
if (!currentSnapshot || !incomingSnapshot) {
|
|
74
|
+
spinner.stop();
|
|
75
|
+
fatal('No snapshot data - repository may be corrupt');
|
|
76
|
+
}
|
|
77
|
+
const conflicts = detectMergeConflicts(currentSnapshot, incomingSnapshot);
|
|
78
|
+
if (conflicts.length > 0) {
|
|
79
|
+
const mergeState = {
|
|
80
|
+
fromBranch: branchName,
|
|
81
|
+
toBranch: state.current,
|
|
82
|
+
conflicts,
|
|
83
|
+
incomingSnapshot,
|
|
84
|
+
createdAt: new Date().toISOString(),
|
|
85
|
+
};
|
|
86
|
+
fs.writeFileSync(mergeStatePath, JSON.stringify(mergeState, null, 2));
|
|
87
|
+
spinner.fail(`${conflicts.length} conflict(s) detected`);
|
|
88
|
+
console.log('');
|
|
89
|
+
for (const c of conflicts.slice(0, 5)) {
|
|
90
|
+
const name = c.parentName ? `${c.parentName}.${c.objectName}` : c.objectName;
|
|
91
|
+
console.log(` ${colors.red('conflict:')} ${c.objectType.toLowerCase()} ${name}`);
|
|
92
|
+
}
|
|
93
|
+
if (conflicts.length > 5) {
|
|
94
|
+
console.log(` ${colors.muted(`... and ${conflicts.length - 5} more`)}`);
|
|
95
|
+
}
|
|
96
|
+
fatal(`Automatic merge failed; fix conflicts and then commit`, `Use ${colors.cyan('relq resolve --all-theirs')} to accept incoming\nOr ${colors.cyan('relq merge --abort')} to cancel`);
|
|
97
|
+
}
|
|
98
|
+
const mergedSnapshot = mergeSnapshots(currentSnapshot, incomingSnapshot);
|
|
99
|
+
saveSnapshot(mergedSnapshot, projectRoot);
|
|
100
|
+
const author = config?.author || 'Relq CLI';
|
|
101
|
+
const message = `Merge branch '${branchName}' into ${state.current}`;
|
|
102
|
+
const commit = createCommit(mergedSnapshot, author, message, projectRoot);
|
|
103
|
+
spinner.succeed(`Merged '${branchName}' into '${state.current}'`);
|
|
104
|
+
console.log(` ${colors.yellow(shortHash(commit.hash))} ${message}`);
|
|
105
|
+
console.log('');
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
spinner.fail('Merge failed');
|
|
109
|
+
fatal(err instanceof Error ? err.message : String(err));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function detectMergeConflicts(current, incoming) {
|
|
113
|
+
const conflicts = [];
|
|
114
|
+
for (const currentTable of current.tables) {
|
|
115
|
+
const incomingTable = incoming.tables.find(t => t.name === currentTable.name);
|
|
116
|
+
if (!incomingTable)
|
|
117
|
+
continue;
|
|
118
|
+
for (const currentCol of currentTable.columns) {
|
|
119
|
+
const incomingCol = incomingTable.columns.find(c => c.name === currentCol.name);
|
|
120
|
+
if (!incomingCol)
|
|
121
|
+
continue;
|
|
122
|
+
if (currentCol.type !== incomingCol.type) {
|
|
123
|
+
conflicts.push({
|
|
124
|
+
objectType: 'COLUMN',
|
|
125
|
+
objectName: currentCol.name,
|
|
126
|
+
parentName: currentTable.name,
|
|
127
|
+
currentValue: currentCol.type,
|
|
128
|
+
incomingValue: incomingCol.type,
|
|
129
|
+
description: `Type differs: ${currentCol.type} vs ${incomingCol.type}`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const currentEnum of current.enums) {
|
|
135
|
+
const incomingEnum = incoming.enums.find(e => e.name === currentEnum.name);
|
|
136
|
+
if (!incomingEnum)
|
|
137
|
+
continue;
|
|
138
|
+
const currentVals = JSON.stringify(currentEnum.values.sort());
|
|
139
|
+
const incomingVals = JSON.stringify(incomingEnum.values.sort());
|
|
140
|
+
if (currentVals !== incomingVals) {
|
|
141
|
+
conflicts.push({
|
|
142
|
+
objectType: 'ENUM',
|
|
143
|
+
objectName: currentEnum.name,
|
|
144
|
+
currentValue: currentEnum.values,
|
|
145
|
+
incomingValue: incomingEnum.values,
|
|
146
|
+
description: 'Values differ',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return conflicts;
|
|
151
|
+
}
|
|
152
|
+
function mergeSnapshots(current, incoming) {
|
|
153
|
+
const result = JSON.parse(JSON.stringify(current));
|
|
154
|
+
for (const table of incoming.tables) {
|
|
155
|
+
if (!result.tables.find(t => t.name === table.name)) {
|
|
156
|
+
result.tables.push(table);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for (const e of incoming.enums) {
|
|
160
|
+
if (!result.enums.find(x => x.name === e.name)) {
|
|
161
|
+
result.enums.push(e);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
for (const d of incoming.domains) {
|
|
165
|
+
if (!result.domains.find(x => x.name === d.name)) {
|
|
166
|
+
result.domains.push(d);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
export default mergeCommand;
|