turbine-orm 0.5.0 → 0.7.0
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/README.md +194 -26
- package/dist/cjs/cli/config.js +5 -15
- package/dist/cjs/cli/index.js +240 -41
- package/dist/cjs/cli/migrate.js +71 -46
- package/dist/cjs/cli/ui.js +5 -9
- package/dist/cjs/client.js +109 -46
- package/dist/cjs/errors.js +293 -0
- package/dist/cjs/generate.js +33 -13
- package/dist/cjs/index.js +39 -20
- package/dist/cjs/introspect.js +3 -5
- package/dist/cjs/pipeline.js +9 -2
- package/dist/cjs/query.js +442 -109
- package/dist/cjs/schema-builder.js +93 -24
- package/dist/cjs/schema-sql.js +157 -19
- package/dist/cjs/schema.js +5 -2
- package/dist/cjs/serverless.js +87 -176
- package/dist/cli/config.js +6 -16
- package/dist/cli/index.js +245 -46
- package/dist/cli/migrate.d.ts +6 -1
- package/dist/cli/migrate.js +72 -47
- package/dist/cli/ui.js +5 -9
- package/dist/client.d.ts +77 -4
- package/dist/client.js +109 -46
- package/dist/errors.d.ts +138 -0
- package/dist/errors.js +278 -0
- package/dist/generate.d.ts +1 -1
- package/dist/generate.js +36 -16
- package/dist/index.d.ts +11 -9
- package/dist/index.js +16 -12
- package/dist/introspect.d.ts +1 -1
- package/dist/introspect.js +4 -6
- package/dist/pipeline.d.ts +1 -1
- package/dist/pipeline.js +9 -2
- package/dist/query.d.ts +257 -36
- package/dist/query.js +443 -110
- package/dist/schema-builder.d.ts +2 -2
- package/dist/schema-builder.js +93 -25
- package/dist/schema-sql.d.ts +7 -3
- package/dist/schema-sql.js +157 -19
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +5 -2
- package/dist/serverless.d.ts +91 -139
- package/dist/serverless.js +86 -173
- package/package.json +33 -16
- package/dist/types.d.ts +0 -93
- package/dist/types.js +0 -126
package/dist/cjs/cli/index.js
CHANGED
|
@@ -56,13 +56,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
56
56
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
57
|
const node_fs_1 = require("node:fs");
|
|
58
58
|
const node_path_1 = require("node:path");
|
|
59
|
-
const
|
|
59
|
+
const node_url_1 = require("node:url");
|
|
60
60
|
const generate_js_1 = require("../generate.js");
|
|
61
|
+
const introspect_js_1 = require("../introspect.js");
|
|
61
62
|
const schema_sql_js_1 = require("../schema-sql.js");
|
|
62
63
|
const config_js_1 = require("./config.js");
|
|
63
64
|
const migrate_js_1 = require("./migrate.js");
|
|
64
65
|
const ui_js_1 = require("./ui.js");
|
|
65
|
-
const node_url_1 = require("node:url");
|
|
66
66
|
function parseArgs() {
|
|
67
67
|
const args = process.argv.slice(2);
|
|
68
68
|
const result = {
|
|
@@ -110,6 +110,9 @@ function parseArgs() {
|
|
|
110
110
|
case '--dry-run':
|
|
111
111
|
result.dryRun = true;
|
|
112
112
|
break;
|
|
113
|
+
case '--auto':
|
|
114
|
+
result.auto = true;
|
|
115
|
+
break;
|
|
113
116
|
case '--force':
|
|
114
117
|
case '-f':
|
|
115
118
|
result.force = true;
|
|
@@ -118,6 +121,10 @@ function parseArgs() {
|
|
|
118
121
|
case '-v':
|
|
119
122
|
result.verbose = true;
|
|
120
123
|
break;
|
|
124
|
+
case '--help':
|
|
125
|
+
case '-h':
|
|
126
|
+
result.help = true;
|
|
127
|
+
break;
|
|
121
128
|
default:
|
|
122
129
|
if (!arg.startsWith('-')) {
|
|
123
130
|
result.positional.push(arg);
|
|
@@ -175,7 +182,7 @@ async function cmdInit(args, config) {
|
|
|
175
182
|
(0, ui_js_1.banner)();
|
|
176
183
|
(0, ui_js_1.header)('Initializing Turbine project');
|
|
177
184
|
// Detect environment
|
|
178
|
-
const envUrl = process.env
|
|
185
|
+
const envUrl = process.env.DATABASE_URL;
|
|
179
186
|
const hasEnvFile = (0, node_fs_1.existsSync)('.env');
|
|
180
187
|
const hasEnvLocal = (0, node_fs_1.existsSync)('.env.local');
|
|
181
188
|
if (envUrl) {
|
|
@@ -214,7 +221,7 @@ async function cmdInit(args, config) {
|
|
|
214
221
|
(0, node_fs_1.mkdirSync)(migrDir, { recursive: true });
|
|
215
222
|
// Create .gitkeep
|
|
216
223
|
(0, node_fs_1.writeFileSync)(`${migrDir}/.gitkeep`, '', 'utf-8');
|
|
217
|
-
(0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(migrDir
|
|
224
|
+
(0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(`${migrDir}/`)}`);
|
|
218
225
|
}
|
|
219
226
|
else {
|
|
220
227
|
(0, ui_js_1.info)(`Migrations dir already exists: ${(0, ui_js_1.dim)(migrDir)}`);
|
|
@@ -222,7 +229,7 @@ async function cmdInit(args, config) {
|
|
|
222
229
|
// Create output directory
|
|
223
230
|
if (!(0, node_fs_1.existsSync)(config.out)) {
|
|
224
231
|
(0, node_fs_1.mkdirSync)(config.out, { recursive: true });
|
|
225
|
-
(0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(config.out
|
|
232
|
+
(0, ui_js_1.success)(`Created ${(0, ui_js_1.cyan)(`${config.out}/`)}`);
|
|
226
233
|
}
|
|
227
234
|
// Create seed file template
|
|
228
235
|
const seedDir = config.seedFile.substring(0, config.seedFile.lastIndexOf('/'));
|
|
@@ -266,7 +273,7 @@ async function cmdInit(args, config) {
|
|
|
266
273
|
* Define your database schema in TypeScript.
|
|
267
274
|
* Use \`npx turbine push\` to sync it to your database.
|
|
268
275
|
*
|
|
269
|
-
* @see https://
|
|
276
|
+
* @see https://turbineorm.dev
|
|
270
277
|
*/
|
|
271
278
|
|
|
272
279
|
import { defineSchema } from 'turbine-orm';
|
|
@@ -317,15 +324,15 @@ export default defineSchema({
|
|
|
317
324
|
spinner.succeed(`Found ${(0, ui_js_1.bold)(String(tableCount))} tables`);
|
|
318
325
|
const genSpinner = new ui_js_1.Spinner('Generating TypeScript client').start();
|
|
319
326
|
const result = (0, generate_js_1.generate)({ schema, outDir: config.out, connectionString: url });
|
|
320
|
-
genSpinner.succeed(`Generated ${(0, ui_js_1.bold)(String(result.files.length))} files to ${(0, ui_js_1.cyan)(config.out
|
|
327
|
+
genSpinner.succeed(`Generated ${(0, ui_js_1.bold)(String(result.files.length))} files to ${(0, ui_js_1.cyan)(`${config.out}/`)}`);
|
|
321
328
|
}
|
|
322
329
|
catch (err) {
|
|
323
330
|
spinner.fail('Could not connect to database');
|
|
324
331
|
if (err instanceof Error) {
|
|
325
|
-
console.log(` ${(0, ui_js_1.dim)(err.message)}`);
|
|
332
|
+
console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
|
|
326
333
|
}
|
|
327
334
|
(0, ui_js_1.newline)();
|
|
328
|
-
(0, ui_js_1.info)(
|
|
335
|
+
(0, ui_js_1.info)(`You can run generation later with: ${(0, ui_js_1.cyan)('npx turbine generate')}`);
|
|
329
336
|
}
|
|
330
337
|
}
|
|
331
338
|
// Next steps
|
|
@@ -401,7 +408,7 @@ async function cmdGenerate(args, config) {
|
|
|
401
408
|
genSpinner.succeed(`Generated ${(0, ui_js_1.bold)(String(result.files.length))} files in ${(0, ui_js_1.elapsed)(startTime)}`);
|
|
402
409
|
// List files
|
|
403
410
|
for (const file of result.files) {
|
|
404
|
-
console.log(` ${(0, ui_js_1.dim)(ui_js_1.symbols.teeEnd)} ${(0, ui_js_1.cyan)(result.outDir
|
|
411
|
+
console.log(` ${(0, ui_js_1.dim)(ui_js_1.symbols.teeEnd)} ${(0, ui_js_1.cyan)(`${result.outDir}/${file}`)}`);
|
|
405
412
|
}
|
|
406
413
|
// Usage hint
|
|
407
414
|
(0, ui_js_1.newline)();
|
|
@@ -449,9 +456,11 @@ async function cmdPush(args, config) {
|
|
|
449
456
|
for (const a of diff.alter) {
|
|
450
457
|
console.log(` ${(0, ui_js_1.yellow)(ui_js_1.symbols.arrowRight)} ${a.table}`);
|
|
451
458
|
for (const col of a.columns) {
|
|
452
|
-
const actionLabel = col.action === 'add'
|
|
453
|
-
|
|
454
|
-
|
|
459
|
+
const actionLabel = col.action === 'add'
|
|
460
|
+
? (0, ui_js_1.green)('+ add')
|
|
461
|
+
: col.action === 'drop'
|
|
462
|
+
? (0, ui_js_1.red)('- drop')
|
|
463
|
+
: (0, ui_js_1.yellow)(`~ ${col.action.replace('_', ' ')}`);
|
|
455
464
|
console.log(` ${actionLabel} ${col.column}`);
|
|
456
465
|
}
|
|
457
466
|
}
|
|
@@ -505,17 +514,20 @@ async function cmdMigrate(args, config) {
|
|
|
505
514
|
console.log(` ${(0, ui_js_1.bold)('turbine migrate')} ${(0, ui_js_1.dim)('— SQL-first migration system')}`);
|
|
506
515
|
(0, ui_js_1.newline)();
|
|
507
516
|
console.log(` ${(0, ui_js_1.bold)('Commands:')}`);
|
|
508
|
-
console.log(` ${(0, ui_js_1.cyan)('create <name>')}
|
|
509
|
-
console.log(` ${(0, ui_js_1.cyan)('
|
|
510
|
-
console.log(` ${(0, ui_js_1.cyan)('
|
|
511
|
-
console.log(` ${(0, ui_js_1.cyan)('
|
|
517
|
+
console.log(` ${(0, ui_js_1.cyan)('create <name>')} Create a new migration file`);
|
|
518
|
+
console.log(` ${(0, ui_js_1.cyan)('create <name> --auto')} Auto-generate from schema diff`);
|
|
519
|
+
console.log(` ${(0, ui_js_1.cyan)('up')} Apply pending migrations`);
|
|
520
|
+
console.log(` ${(0, ui_js_1.cyan)('down')} Rollback last migration`);
|
|
521
|
+
console.log(` ${(0, ui_js_1.cyan)('status')} Show migration status`);
|
|
512
522
|
(0, ui_js_1.newline)();
|
|
513
523
|
console.log(` ${(0, ui_js_1.bold)('Options:')}`);
|
|
524
|
+
console.log(` ${(0, ui_js_1.cyan)('--auto')} Auto-generate UP/DOWN SQL from schema diff`);
|
|
514
525
|
console.log(` ${(0, ui_js_1.cyan)('--step, -n')} Number of migrations to apply/rollback`);
|
|
515
526
|
console.log(` ${(0, ui_js_1.cyan)('--dry-run')} Show SQL without executing`);
|
|
516
527
|
(0, ui_js_1.newline)();
|
|
517
528
|
console.log(` ${(0, ui_js_1.bold)('Examples:')}`);
|
|
518
529
|
console.log(` ${(0, ui_js_1.dim)('npx turbine migrate create add_users_table')}`);
|
|
530
|
+
console.log(` ${(0, ui_js_1.dim)('npx turbine migrate create add_email_index --auto')}`);
|
|
519
531
|
console.log(` ${(0, ui_js_1.dim)('npx turbine migrate up')}`);
|
|
520
532
|
console.log(` ${(0, ui_js_1.dim)('npx turbine migrate down --step 2')}`);
|
|
521
533
|
(0, ui_js_1.newline)();
|
|
@@ -549,9 +561,61 @@ async function cmdMigrateCreate(args, config) {
|
|
|
549
561
|
(0, ui_js_1.newline)();
|
|
550
562
|
console.log(` ${(0, ui_js_1.dim)('Usage:')} ${(0, ui_js_1.cyan)('npx turbine migrate create <name>')}`);
|
|
551
563
|
console.log(` ${(0, ui_js_1.dim)('Example:')} ${(0, ui_js_1.cyan)('npx turbine migrate create add_users_table')}`);
|
|
564
|
+
console.log(` ${(0, ui_js_1.dim)('Auto:')} ${(0, ui_js_1.cyan)('npx turbine migrate create my_change --auto')}`);
|
|
552
565
|
(0, ui_js_1.newline)();
|
|
553
566
|
process.exit(1);
|
|
554
567
|
}
|
|
568
|
+
if (args.auto) {
|
|
569
|
+
// Auto-generate migration from schema diff
|
|
570
|
+
const url = requireUrl(config);
|
|
571
|
+
(0, ui_js_1.label)('Database', (0, ui_js_1.redactUrl)(url));
|
|
572
|
+
(0, ui_js_1.label)('Schema file', config.schemaFile);
|
|
573
|
+
(0, ui_js_1.newline)();
|
|
574
|
+
const schemaDef = await loadSchemaFile(config.schemaFile);
|
|
575
|
+
const diffSpinner = new ui_js_1.Spinner('Computing schema diff').start();
|
|
576
|
+
const diff = await (0, schema_sql_js_1.schemaDiff)(schemaDef, url);
|
|
577
|
+
if (diff.statements.length === 0) {
|
|
578
|
+
diffSpinner.succeed('Database is already in sync — nothing to migrate');
|
|
579
|
+
(0, ui_js_1.newline)();
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
diffSpinner.succeed(`Found ${(0, ui_js_1.bold)(String(diff.statements.length))} change(s)`);
|
|
583
|
+
(0, ui_js_1.newline)();
|
|
584
|
+
const upSQL = diff.statements.join('\n');
|
|
585
|
+
const downSQL = diff.reverseStatements.join('\n');
|
|
586
|
+
const file = (0, migrate_js_1.createMigration)(config.migrationsDir, name, { up: upSQL, down: downSQL });
|
|
587
|
+
const relPath = (0, node_path_1.relative)(process.cwd(), file.path);
|
|
588
|
+
(0, ui_js_1.success)(`Created auto-migration: ${(0, ui_js_1.bold)(file.filename)}`);
|
|
589
|
+
(0, ui_js_1.newline)();
|
|
590
|
+
console.log(` ${(0, ui_js_1.dim)('File:')} ${(0, ui_js_1.cyan)(relPath)}`);
|
|
591
|
+
(0, ui_js_1.newline)();
|
|
592
|
+
// Show summary of changes
|
|
593
|
+
if (diff.create.length > 0) {
|
|
594
|
+
console.log(` ${(0, ui_js_1.green)('+ Create')} ${diff.create.length} table(s): ${diff.create.map((t) => t.name).join(', ')}`);
|
|
595
|
+
}
|
|
596
|
+
if (diff.alter.length > 0) {
|
|
597
|
+
console.log(` ${(0, ui_js_1.yellow)('~ Alter')} ${diff.alter.length} table(s):`);
|
|
598
|
+
for (const a of diff.alter) {
|
|
599
|
+
for (const col of a.columns) {
|
|
600
|
+
const actionLabel = col.action === 'add'
|
|
601
|
+
? (0, ui_js_1.green)('+ add')
|
|
602
|
+
: col.action === 'drop'
|
|
603
|
+
? (0, ui_js_1.red)('- drop')
|
|
604
|
+
: col.action === 'add_unique'
|
|
605
|
+
? (0, ui_js_1.green)('+ unique')
|
|
606
|
+
: col.action === 'drop_unique'
|
|
607
|
+
? (0, ui_js_1.red)('- unique')
|
|
608
|
+
: (0, ui_js_1.yellow)(`~ ${col.action.replace(/_/g, ' ')}`);
|
|
609
|
+
console.log(` ${actionLabel} ${a.table}.${col.column}`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
(0, ui_js_1.newline)();
|
|
614
|
+
console.log(` ${(0, ui_js_1.dim)('Review the migration, then run:')}`);
|
|
615
|
+
console.log(` ${(0, ui_js_1.cyan)('npx turbine migrate up')}`);
|
|
616
|
+
(0, ui_js_1.newline)();
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
555
619
|
const file = (0, migrate_js_1.createMigration)(config.migrationsDir, name);
|
|
556
620
|
const relPath = (0, node_path_1.relative)(process.cwd(), file.path);
|
|
557
621
|
(0, ui_js_1.success)(`Created migration: ${(0, ui_js_1.bold)(file.filename)}`);
|
|
@@ -633,7 +697,7 @@ async function cmdMigrateDown(args, config) {
|
|
|
633
697
|
}
|
|
634
698
|
(0, ui_js_1.newline)();
|
|
635
699
|
}
|
|
636
|
-
async function cmdMigrateStatus(
|
|
700
|
+
async function cmdMigrateStatus(_args, config) {
|
|
637
701
|
(0, ui_js_1.banner)();
|
|
638
702
|
const url = requireUrl(config);
|
|
639
703
|
(0, ui_js_1.label)('Database', (0, ui_js_1.redactUrl)(url));
|
|
@@ -663,19 +727,22 @@ async function cmdMigrateStatus(args, config) {
|
|
|
663
727
|
const rows = statuses.map((s) => {
|
|
664
728
|
let status;
|
|
665
729
|
if (s.applied && s.checksumValid === false) {
|
|
666
|
-
status = (0, ui_js_1.red)(ui_js_1.symbols.warning
|
|
730
|
+
status = (0, ui_js_1.red)(`${ui_js_1.symbols.warning} Drifted`);
|
|
667
731
|
}
|
|
668
732
|
else if (s.applied) {
|
|
669
|
-
status = (0, ui_js_1.green)(ui_js_1.symbols.check
|
|
733
|
+
status = (0, ui_js_1.green)(`${ui_js_1.symbols.check} Applied`);
|
|
670
734
|
}
|
|
671
735
|
else {
|
|
672
|
-
status = (0, ui_js_1.yellow)(ui_js_1.symbols.dot
|
|
736
|
+
status = (0, ui_js_1.yellow)(`${ui_js_1.symbols.dot} Pending`);
|
|
673
737
|
}
|
|
674
738
|
return [
|
|
675
739
|
status,
|
|
676
740
|
s.file.filename,
|
|
677
741
|
s.appliedAt
|
|
678
|
-
? (0, ui_js_1.dim)(s.appliedAt
|
|
742
|
+
? (0, ui_js_1.dim)(s.appliedAt
|
|
743
|
+
.toISOString()
|
|
744
|
+
.replace('T', ' ')
|
|
745
|
+
.replace(/\.\d+Z$/, ' UTC'))
|
|
679
746
|
: (0, ui_js_1.dim)('—'),
|
|
680
747
|
];
|
|
681
748
|
});
|
|
@@ -689,7 +756,7 @@ async function cmdMigrateStatus(args, config) {
|
|
|
689
756
|
// ---------------------------------------------------------------------------
|
|
690
757
|
// Command: seed
|
|
691
758
|
// ---------------------------------------------------------------------------
|
|
692
|
-
async function cmdSeed(
|
|
759
|
+
async function cmdSeed(_args, config) {
|
|
693
760
|
(0, ui_js_1.banner)();
|
|
694
761
|
const seedFile = (0, node_path_1.resolve)(config.seedFile);
|
|
695
762
|
(0, ui_js_1.label)('Seed file', config.seedFile);
|
|
@@ -705,22 +772,20 @@ async function cmdSeed(args, config) {
|
|
|
705
772
|
const spinner = new ui_js_1.Spinner('Running seed file').start();
|
|
706
773
|
try {
|
|
707
774
|
// Use child_process to run the seed file via tsx or node
|
|
708
|
-
const {
|
|
775
|
+
const { execFileSync } = await Promise.resolve().then(() => __importStar(require('node:child_process')));
|
|
709
776
|
// Try tsx first (most compatible with .ts files), fall back to node --experimental-strip-types
|
|
710
777
|
const runners = [
|
|
711
|
-
{ cmd: 'npx tsx', name: 'tsx' },
|
|
712
|
-
{ cmd: 'node --experimental-strip-types', name: 'node' },
|
|
778
|
+
{ cmd: 'npx', args: ['tsx', seedFile], name: 'tsx' },
|
|
779
|
+
{ cmd: 'node', args: ['--experimental-strip-types', seedFile], name: 'node' },
|
|
713
780
|
];
|
|
714
|
-
// Shell-escape the seed file path to prevent injection
|
|
715
|
-
const escapedSeedFile = seedFile.replace(/'/g, "'\\''");
|
|
716
781
|
let ran = false;
|
|
717
782
|
for (const runner of runners) {
|
|
718
783
|
try {
|
|
719
|
-
|
|
784
|
+
execFileSync(runner.cmd, runner.args, {
|
|
720
785
|
stdio: 'inherit',
|
|
721
786
|
env: {
|
|
722
787
|
...process.env,
|
|
723
|
-
DATABASE_URL: config.url || process.env
|
|
788
|
+
DATABASE_URL: config.url || process.env.DATABASE_URL,
|
|
724
789
|
},
|
|
725
790
|
});
|
|
726
791
|
ran = true;
|
|
@@ -742,7 +807,7 @@ async function cmdSeed(args, config) {
|
|
|
742
807
|
catch (err) {
|
|
743
808
|
spinner.fail('Seed failed');
|
|
744
809
|
if (err instanceof Error) {
|
|
745
|
-
console.log(` ${(0, ui_js_1.dim)(err.message)}`);
|
|
810
|
+
console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
|
|
746
811
|
}
|
|
747
812
|
(0, ui_js_1.newline)();
|
|
748
813
|
process.exit(1);
|
|
@@ -752,7 +817,7 @@ async function cmdSeed(args, config) {
|
|
|
752
817
|
// ---------------------------------------------------------------------------
|
|
753
818
|
// Command: status
|
|
754
819
|
// ---------------------------------------------------------------------------
|
|
755
|
-
async function cmdStatus(
|
|
820
|
+
async function cmdStatus(_args, config) {
|
|
756
821
|
(0, ui_js_1.banner)();
|
|
757
822
|
const url = requireUrl(config);
|
|
758
823
|
(0, ui_js_1.label)('Database', (0, ui_js_1.redactUrl)(url));
|
|
@@ -770,7 +835,7 @@ async function cmdStatus(args, config) {
|
|
|
770
835
|
(0, ui_js_1.newline)();
|
|
771
836
|
for (const tbl of Object.values(schema.tables)) {
|
|
772
837
|
const relCount = Object.keys(tbl.relations).length;
|
|
773
|
-
const
|
|
838
|
+
const _pk = tbl.primaryKey.join(', ') || (0, ui_js_1.dim)('(none)');
|
|
774
839
|
console.log(` ${(0, ui_js_1.bold)((0, ui_js_1.cyan)(tbl.name))}`);
|
|
775
840
|
for (let i = 0; i < tbl.columns.length; i++) {
|
|
776
841
|
const col = tbl.columns[i];
|
|
@@ -779,7 +844,7 @@ async function cmdStatus(args, config) {
|
|
|
779
844
|
const nullable = col.nullable ? (0, ui_js_1.dim)('?') : '';
|
|
780
845
|
const def = col.hasDefault ? (0, ui_js_1.dim)(' (default)') : '';
|
|
781
846
|
const pkLabel = tbl.primaryKey.includes(col.name) ? ` ${(0, ui_js_1.magenta)('PK')}` : '';
|
|
782
|
-
console.log(` ${(0, ui_js_1.dim)(prefix)} ${col.field}${nullable}: ${(0, ui_js_1.green)(col.tsType)}${pkLabel}${def} ${(0, ui_js_1.gray)(ui_js_1.symbols.arrow
|
|
847
|
+
console.log(` ${(0, ui_js_1.dim)(prefix)} ${col.field}${nullable}: ${(0, ui_js_1.green)(col.tsType)}${pkLabel}${def} ${(0, ui_js_1.gray)(`${ui_js_1.symbols.arrow} ${col.pgType}`)}`);
|
|
783
848
|
}
|
|
784
849
|
const rels = Object.entries(tbl.relations);
|
|
785
850
|
if (rels.length > 0) {
|
|
@@ -812,11 +877,138 @@ async function cmdStudio(_args, _config) {
|
|
|
812
877
|
'A local web UI for browsing your database,',
|
|
813
878
|
'exploring relations, and managing data.',
|
|
814
879
|
'',
|
|
815
|
-
`Follow ${(0, ui_js_1.cyan)('@
|
|
880
|
+
`Follow ${(0, ui_js_1.cyan)('@turbineorm')} for updates.`,
|
|
816
881
|
].join('\n'), { title: (0, ui_js_1.bold)((0, ui_js_1.cyan)('Studio')), padding: 2 }));
|
|
817
882
|
(0, ui_js_1.newline)();
|
|
818
883
|
}
|
|
819
884
|
// ---------------------------------------------------------------------------
|
|
885
|
+
// Subcommand help
|
|
886
|
+
// ---------------------------------------------------------------------------
|
|
887
|
+
function showSubcommandHelp(command) {
|
|
888
|
+
const helpMap = {
|
|
889
|
+
init: showInitHelp,
|
|
890
|
+
generate: showGenerateHelp,
|
|
891
|
+
pull: showGenerateHelp,
|
|
892
|
+
push: showPushHelp,
|
|
893
|
+
migrate: showMigrateHelp,
|
|
894
|
+
migration: showMigrateHelp,
|
|
895
|
+
seed: showSeedHelp,
|
|
896
|
+
status: showStatusHelp,
|
|
897
|
+
};
|
|
898
|
+
const fn = helpMap[command];
|
|
899
|
+
if (fn) {
|
|
900
|
+
fn();
|
|
901
|
+
return true;
|
|
902
|
+
}
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
function showInitHelp() {
|
|
906
|
+
(0, ui_js_1.banner)();
|
|
907
|
+
console.log(` ${(0, ui_js_1.bold)('turbine init')} — Initialize a Turbine project`);
|
|
908
|
+
(0, ui_js_1.newline)();
|
|
909
|
+
console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
|
|
910
|
+
console.log(` npx turbine init ${(0, ui_js_1.dim)('[options]')}`);
|
|
911
|
+
(0, ui_js_1.newline)();
|
|
912
|
+
console.log(` Creates ${(0, ui_js_1.cyan)('turbine.config.ts')}, migrations directory, seed file template,`);
|
|
913
|
+
console.log(` and schema file template.`);
|
|
914
|
+
(0, ui_js_1.newline)();
|
|
915
|
+
console.log(` ${(0, ui_js_1.bold)('Options:')}`);
|
|
916
|
+
console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string to embed in config`);
|
|
917
|
+
console.log(` ${(0, ui_js_1.cyan)('--force, -f')} Overwrite existing config file`);
|
|
918
|
+
(0, ui_js_1.newline)();
|
|
919
|
+
}
|
|
920
|
+
function showGenerateHelp() {
|
|
921
|
+
(0, ui_js_1.banner)();
|
|
922
|
+
console.log(` ${(0, ui_js_1.bold)('turbine generate')} — Introspect database and generate TypeScript types`);
|
|
923
|
+
(0, ui_js_1.newline)();
|
|
924
|
+
console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
|
|
925
|
+
console.log(` npx turbine generate ${(0, ui_js_1.dim)('[options]')}`);
|
|
926
|
+
(0, ui_js_1.newline)();
|
|
927
|
+
console.log(` Connects to your database, reads the schema, and generates:`);
|
|
928
|
+
console.log(` ${(0, ui_js_1.dim)('•')} ${(0, ui_js_1.cyan)('types.ts')} — Entity interfaces, Create/Update input types`);
|
|
929
|
+
console.log(` ${(0, ui_js_1.dim)('•')} ${(0, ui_js_1.cyan)('metadata.ts')} — Runtime schema metadata`);
|
|
930
|
+
console.log(` ${(0, ui_js_1.dim)('•')} ${(0, ui_js_1.cyan)('index.ts')} — Configured client with typed table accessors`);
|
|
931
|
+
(0, ui_js_1.newline)();
|
|
932
|
+
console.log(` ${(0, ui_js_1.bold)('Options:')}`);
|
|
933
|
+
console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
|
|
934
|
+
console.log(` ${(0, ui_js_1.cyan)('--out, -o')} ${(0, ui_js_1.dim)('<dir>')} Output directory ${(0, ui_js_1.dim)('(default: ./generated/turbine)')}`);
|
|
935
|
+
console.log(` ${(0, ui_js_1.cyan)('--schema, -s')} ${(0, ui_js_1.dim)('<name>')} Postgres schema ${(0, ui_js_1.dim)('(default: public)')}`);
|
|
936
|
+
console.log(` ${(0, ui_js_1.cyan)('--include')} ${(0, ui_js_1.dim)('<tables>')} Comma-separated tables to include`);
|
|
937
|
+
console.log(` ${(0, ui_js_1.cyan)('--exclude')} ${(0, ui_js_1.dim)('<tables>')} Comma-separated tables to exclude`);
|
|
938
|
+
(0, ui_js_1.newline)();
|
|
939
|
+
}
|
|
940
|
+
function showPushHelp() {
|
|
941
|
+
(0, ui_js_1.banner)();
|
|
942
|
+
console.log(` ${(0, ui_js_1.bold)('turbine push')} — Apply schema-builder definitions to database`);
|
|
943
|
+
(0, ui_js_1.newline)();
|
|
944
|
+
console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
|
|
945
|
+
console.log(` npx turbine push ${(0, ui_js_1.dim)('[options]')}`);
|
|
946
|
+
(0, ui_js_1.newline)();
|
|
947
|
+
console.log(` Reads your ${(0, ui_js_1.cyan)('turbine/schema.ts')} file, diffs against the live database,`);
|
|
948
|
+
console.log(` and applies CREATE/ALTER statements.`);
|
|
949
|
+
(0, ui_js_1.newline)();
|
|
950
|
+
console.log(` ${(0, ui_js_1.bold)('Options:')}`);
|
|
951
|
+
console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
|
|
952
|
+
console.log(` ${(0, ui_js_1.cyan)('--dry-run')} Show SQL without executing`);
|
|
953
|
+
console.log(` ${(0, ui_js_1.cyan)('--verbose, -v')} Show detailed output`);
|
|
954
|
+
(0, ui_js_1.newline)();
|
|
955
|
+
}
|
|
956
|
+
function showMigrateHelp() {
|
|
957
|
+
(0, ui_js_1.banner)();
|
|
958
|
+
console.log(` ${(0, ui_js_1.bold)('turbine migrate')} — SQL migration management`);
|
|
959
|
+
(0, ui_js_1.newline)();
|
|
960
|
+
console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
|
|
961
|
+
console.log(` npx turbine migrate ${(0, ui_js_1.cyan)('<subcommand>')} ${(0, ui_js_1.dim)('[options]')}`);
|
|
962
|
+
(0, ui_js_1.newline)();
|
|
963
|
+
console.log(` ${(0, ui_js_1.bold)('Subcommands:')}`);
|
|
964
|
+
console.log(` ${(0, ui_js_1.cyan)('create')} ${(0, ui_js_1.dim)('<name>')} Create a new migration file`);
|
|
965
|
+
console.log(` ${(0, ui_js_1.cyan)('up')} Apply pending migrations`);
|
|
966
|
+
console.log(` ${(0, ui_js_1.cyan)('down')} Rollback last migration`);
|
|
967
|
+
console.log(` ${(0, ui_js_1.cyan)('status')} Show applied/pending migrations`);
|
|
968
|
+
(0, ui_js_1.newline)();
|
|
969
|
+
console.log(` ${(0, ui_js_1.bold)('Options:')}`);
|
|
970
|
+
console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
|
|
971
|
+
console.log(` ${(0, ui_js_1.cyan)('--step, -n')} ${(0, ui_js_1.dim)('<N>')} Number of migrations to apply/rollback`);
|
|
972
|
+
console.log(` ${(0, ui_js_1.cyan)('--dry-run')} Show SQL without executing`);
|
|
973
|
+
console.log(` ${(0, ui_js_1.cyan)('--verbose, -v')} Show detailed output`);
|
|
974
|
+
(0, ui_js_1.newline)();
|
|
975
|
+
console.log(` ${(0, ui_js_1.bold)('Examples:')}`);
|
|
976
|
+
console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate create add_users_table`);
|
|
977
|
+
console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate up`);
|
|
978
|
+
console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate down --step 2`);
|
|
979
|
+
console.log(` ${(0, ui_js_1.dim)('$')} npx turbine migrate status`);
|
|
980
|
+
(0, ui_js_1.newline)();
|
|
981
|
+
}
|
|
982
|
+
function showSeedHelp() {
|
|
983
|
+
(0, ui_js_1.banner)();
|
|
984
|
+
console.log(` ${(0, ui_js_1.bold)('turbine seed')} — Run seed file`);
|
|
985
|
+
(0, ui_js_1.newline)();
|
|
986
|
+
console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
|
|
987
|
+
console.log(` npx turbine seed ${(0, ui_js_1.dim)('[options]')}`);
|
|
988
|
+
(0, ui_js_1.newline)();
|
|
989
|
+
console.log(` Runs the seed file specified in ${(0, ui_js_1.cyan)('turbine.config.ts')}`);
|
|
990
|
+
console.log(` ${(0, ui_js_1.dim)('(default: ./turbine/seed.ts)')}`);
|
|
991
|
+
(0, ui_js_1.newline)();
|
|
992
|
+
console.log(` ${(0, ui_js_1.bold)('Options:')}`);
|
|
993
|
+
console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
|
|
994
|
+
(0, ui_js_1.newline)();
|
|
995
|
+
}
|
|
996
|
+
function showStatusHelp() {
|
|
997
|
+
(0, ui_js_1.banner)();
|
|
998
|
+
console.log(` ${(0, ui_js_1.bold)('turbine status')} — Show database schema summary`);
|
|
999
|
+
(0, ui_js_1.newline)();
|
|
1000
|
+
console.log(` ${(0, ui_js_1.bold)('Usage:')}`);
|
|
1001
|
+
console.log(` npx turbine status ${(0, ui_js_1.dim)('[options]')}`);
|
|
1002
|
+
(0, ui_js_1.newline)();
|
|
1003
|
+
console.log(` Introspects your database and displays tables, columns,`);
|
|
1004
|
+
console.log(` types, relations, and indexes.`);
|
|
1005
|
+
(0, ui_js_1.newline)();
|
|
1006
|
+
console.log(` ${(0, ui_js_1.bold)('Options:')}`);
|
|
1007
|
+
console.log(` ${(0, ui_js_1.cyan)('--url, -u')} ${(0, ui_js_1.dim)('<url>')} Postgres connection string`);
|
|
1008
|
+
console.log(` ${(0, ui_js_1.cyan)('--schema, -s')} ${(0, ui_js_1.dim)('<name>')} Postgres schema ${(0, ui_js_1.dim)('(default: public)')}`);
|
|
1009
|
+
(0, ui_js_1.newline)();
|
|
1010
|
+
}
|
|
1011
|
+
// ---------------------------------------------------------------------------
|
|
820
1012
|
// Help
|
|
821
1013
|
// ---------------------------------------------------------------------------
|
|
822
1014
|
function showHelp() {
|
|
@@ -875,6 +1067,13 @@ async function main() {
|
|
|
875
1067
|
showHelp();
|
|
876
1068
|
return;
|
|
877
1069
|
}
|
|
1070
|
+
// Subcommand help: e.g. `turbine migrate --help`
|
|
1071
|
+
if (args.help) {
|
|
1072
|
+
if (showSubcommandHelp(args.command))
|
|
1073
|
+
return;
|
|
1074
|
+
showHelp();
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
878
1077
|
if (args.command === 'version' || args.command === '--version' || args.command === '-V') {
|
|
879
1078
|
showVersion();
|
|
880
1079
|
return;
|
|
@@ -940,7 +1139,7 @@ async function main() {
|
|
|
940
1139
|
if (err.message.includes('ECONNREFUSED') || err.message.includes('connection')) {
|
|
941
1140
|
(0, ui_js_1.newline)();
|
|
942
1141
|
(0, ui_js_1.error)(`Could not connect to database`);
|
|
943
|
-
console.log(` ${(0, ui_js_1.dim)(err.message)}`);
|
|
1142
|
+
console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
|
|
944
1143
|
(0, ui_js_1.newline)();
|
|
945
1144
|
console.log(` ${(0, ui_js_1.dim)('Check that:')}`);
|
|
946
1145
|
console.log(` ${(0, ui_js_1.dim)('1.')} Your database is running`);
|
|
@@ -950,25 +1149,25 @@ async function main() {
|
|
|
950
1149
|
else if (err.message.includes('authentication')) {
|
|
951
1150
|
(0, ui_js_1.newline)();
|
|
952
1151
|
(0, ui_js_1.error)(`Authentication failed`);
|
|
953
|
-
console.log(` ${(0, ui_js_1.dim)(err.message)}`);
|
|
1152
|
+
console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
|
|
954
1153
|
}
|
|
955
1154
|
else if (err.message.includes('does not exist')) {
|
|
956
1155
|
(0, ui_js_1.newline)();
|
|
957
1156
|
(0, ui_js_1.error)(`Database or schema not found`);
|
|
958
|
-
console.log(` ${(0, ui_js_1.dim)(err.message)}`);
|
|
1157
|
+
console.log(` ${(0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.message))}`);
|
|
959
1158
|
}
|
|
960
1159
|
else {
|
|
961
1160
|
(0, ui_js_1.newline)();
|
|
962
|
-
(0, ui_js_1.error)(err.message);
|
|
1161
|
+
(0, ui_js_1.error)((0, ui_js_1.redactUrl)(err.message));
|
|
963
1162
|
if (args.verbose && err.stack) {
|
|
964
1163
|
(0, ui_js_1.newline)();
|
|
965
|
-
console.log((0, ui_js_1.dim)(err.stack));
|
|
1164
|
+
console.log((0, ui_js_1.dim)((0, ui_js_1.redactUrl)(err.stack)));
|
|
966
1165
|
}
|
|
967
1166
|
}
|
|
968
1167
|
}
|
|
969
1168
|
else {
|
|
970
1169
|
(0, ui_js_1.newline)();
|
|
971
|
-
(0, ui_js_1.error)(`Unexpected error: ${String(err)}`);
|
|
1170
|
+
(0, ui_js_1.error)(`Unexpected error: ${(0, ui_js_1.redactUrl)(String(err))}`);
|
|
972
1171
|
}
|
|
973
1172
|
(0, ui_js_1.newline)();
|
|
974
1173
|
process.exit(1);
|