dbdock 1.1.16 → 1.1.17
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 +222 -6
- package/dist/cli/commands/analyze.d.ts +1 -0
- package/dist/cli/commands/analyze.js +135 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/cross-migrate.d.ts +11 -0
- package/dist/cli/commands/cross-migrate.js +307 -0
- package/dist/cli/commands/cross-migrate.js.map +1 -0
- package/dist/cli/index.js +20 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/migration/analyzers/mongodb.analyzer.d.ts +3 -0
- package/dist/migration/analyzers/mongodb.analyzer.js +208 -0
- package/dist/migration/analyzers/mongodb.analyzer.js.map +1 -0
- package/dist/migration/analyzers/postgres.analyzer.d.ts +3 -0
- package/dist/migration/analyzers/postgres.analyzer.js +176 -0
- package/dist/migration/analyzers/postgres.analyzer.js.map +1 -0
- package/dist/migration/config.manager.d.ts +3 -0
- package/dist/migration/config.manager.js +80 -0
- package/dist/migration/config.manager.js.map +1 -0
- package/dist/migration/engines/migration.engine.d.ts +6 -0
- package/dist/migration/engines/migration.engine.js +62 -0
- package/dist/migration/engines/migration.engine.js.map +1 -0
- package/dist/migration/engines/mongo-to-postgres.engine.d.ts +2 -0
- package/dist/migration/engines/mongo-to-postgres.engine.js +409 -0
- package/dist/migration/engines/mongo-to-postgres.engine.js.map +1 -0
- package/dist/migration/engines/postgres-to-mongo.engine.d.ts +2 -0
- package/dist/migration/engines/postgres-to-mongo.engine.js +192 -0
- package/dist/migration/engines/postgres-to-mongo.engine.js.map +1 -0
- package/dist/migration/mappers/mongo-to-postgres.mapper.d.ts +2 -0
- package/dist/migration/mappers/mongo-to-postgres.mapper.js +263 -0
- package/dist/migration/mappers/mongo-to-postgres.mapper.js.map +1 -0
- package/dist/migration/mappers/postgres-to-mongo.mapper.d.ts +2 -0
- package/dist/migration/mappers/postgres-to-mongo.mapper.js +174 -0
- package/dist/migration/mappers/postgres-to-mongo.mapper.js.map +1 -0
- package/dist/migration/reference.detector.d.ts +2 -0
- package/dist/migration/reference.detector.js +57 -0
- package/dist/migration/reference.detector.js.map +1 -0
- package/dist/migration/type.mapper.d.ts +12 -0
- package/dist/migration/type.mapper.js +197 -0
- package/dist/migration/type.mapper.js.map +1 -0
- package/dist/migration/types.d.ts +183 -0
- package/dist/migration/types.js +11 -0
- package/dist/migration/types.js.map +1 -0
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DBDock
|
|
2
2
|
|
|
3
|
-
Stop writing backup scripts. Stop losing sleep over database migrations. DBDock handles PostgreSQL backups, restores, and database
|
|
3
|
+
Stop writing backup scripts. Stop losing sleep over database migrations. DBDock handles PostgreSQL backups, restores, database copies, and cross-database migrations between MongoDB and PostgreSQL in one command.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/dbdock)
|
|
6
6
|
[](LICENSE)
|
|
@@ -20,13 +20,14 @@ It's not hard. It's just repetitive. And repetitive stuff should be one command.
|
|
|
20
20
|
## The Fix
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
npx dbdock init
|
|
24
|
-
npx dbdock backup
|
|
25
|
-
npx dbdock restore
|
|
26
|
-
npx dbdock copydb "db_url_1" "db_url_2"
|
|
23
|
+
npx dbdock init # One-time setup (takes 30 seconds)
|
|
24
|
+
npx dbdock backup # Backup with encryption + compression
|
|
25
|
+
npx dbdock restore # Restore from any backup
|
|
26
|
+
npx dbdock copydb "db_url_1" "db_url_2" # Copy entire database, zero config
|
|
27
|
+
npx dbdock migrate "mongo_url" "postgres_url" # Cross-database migration
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
That's it. No shell scripts. No manual uploads. No
|
|
30
|
+
That's it. No shell scripts. No manual uploads. No throwaway migration code.
|
|
30
31
|
|
|
31
32
|
---
|
|
32
33
|
|
|
@@ -258,6 +259,221 @@ Got secrets sitting in `dbdock.config.json` from an older version? This extracts
|
|
|
258
259
|
|
|
259
260
|
---
|
|
260
261
|
|
|
262
|
+
## Cross-Database Migration (MongoDB ↔ PostgreSQL)
|
|
263
|
+
|
|
264
|
+
Move your data between MongoDB and PostgreSQL without writing throwaway scripts. DBDock analyzes the source, proposes a schema mapping, lets you review it, and handles the transfer.
|
|
265
|
+
|
|
266
|
+
### `dbdock analyze` — Understand your database first
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
npx dbdock analyze "mongodb://localhost:27017/myapp"
|
|
270
|
+
npx dbdock analyze "postgresql://user:pass@localhost:5432/myapp"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Scans the source database and shows you everything — collections/tables, field types, nested structures, inconsistencies (like a `price` field that's a string in 200 docs and a number in 15,000), and missing fields.
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
DBDock - Database Analysis
|
|
277
|
+
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
278
|
+
|
|
279
|
+
ℹ Database: MongoDB — myapp
|
|
280
|
+
ℹ Host: localhost:27017
|
|
281
|
+
|
|
282
|
+
✓ Analysis complete
|
|
283
|
+
|
|
284
|
+
Found 4 collections, 57.2K total documents
|
|
285
|
+
|
|
286
|
+
users (45K docs)
|
|
287
|
+
├─ _id (objectId)
|
|
288
|
+
├─ name (string)
|
|
289
|
+
├─ email (string)
|
|
290
|
+
├─ address (object)
|
|
291
|
+
│ ├─ street (string)
|
|
292
|
+
│ ├─ city (string)
|
|
293
|
+
│ └─ zip (string)
|
|
294
|
+
├─ phone (string) [62% present]
|
|
295
|
+
└─ orders (array: object)
|
|
296
|
+
|
|
297
|
+
products (12K docs)
|
|
298
|
+
├─ _id (objectId)
|
|
299
|
+
├─ title (string)
|
|
300
|
+
├─ price (string(203), number(11797)) ⚠ mixed types
|
|
301
|
+
├─ tags (array: string)
|
|
302
|
+
└─ meta (object)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### `dbdock migrate` — Cross-database migration
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
npx dbdock migrate "mongodb://localhost:27017/myapp" "postgresql://user:pass@localhost:5432/myapp"
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
DBDock analyzes the source, generates a schema mapping proposal, and presents it for review before touching anything:
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
DBDock - Cross-Database Migration
|
|
317
|
+
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
318
|
+
|
|
319
|
+
ℹ Source: MongoDB — myapp
|
|
320
|
+
ℹ Target: PostgreSQL — myapp
|
|
321
|
+
|
|
322
|
+
✓ Source analyzed: 4 collections, 57.2K documents
|
|
323
|
+
|
|
324
|
+
Proposed Schema Mapping:
|
|
325
|
+
|
|
326
|
+
users → users
|
|
327
|
+
├─ _id → (uuid_from_objectid) users.id (uuid) PK
|
|
328
|
+
├─ name → users.name (text)
|
|
329
|
+
├─ email → users.email (text)
|
|
330
|
+
├─ address {} → user_addresses (1:1 relation)
|
|
331
|
+
│ ├─ street → street (text)
|
|
332
|
+
│ ├─ city → city (text)
|
|
333
|
+
│ └─ zip → zip (text)
|
|
334
|
+
├─ orders [] → user_orders child table
|
|
335
|
+
|
|
336
|
+
products → products
|
|
337
|
+
├─ _id → (uuid_from_objectid) products.id (uuid) PK
|
|
338
|
+
├─ title → products.title (text)
|
|
339
|
+
├─ price → products.price (numeric) nullable
|
|
340
|
+
├─ tags [] → product_tags text[]
|
|
341
|
+
├─ meta {} → products.meta (jsonb)
|
|
342
|
+
|
|
343
|
+
⚠ Conflicts Found:
|
|
344
|
+
|
|
345
|
+
• products.price: string in 203 docs, number in 11797 docs
|
|
346
|
+
→ Suggestion: cast to numeric, log failures
|
|
347
|
+
|
|
348
|
+
• users.phone: missing in 38.0% of documents
|
|
349
|
+
→ Suggestion: nullable column
|
|
350
|
+
|
|
351
|
+
? Accept mapping? (Y / export / cancel)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
You review the mapping, then choose: execute it, export it as a config file to tweak, or cancel.
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
### What it handles
|
|
359
|
+
|
|
360
|
+
| Scenario | How DBDock handles it |
|
|
361
|
+
|---|---|
|
|
362
|
+
| **Nested objects** | Consistent shape → flattened to a related table. Varying/messy → kept as `jsonb` column |
|
|
363
|
+
| **Arrays of primitives** | `tags: ["a", "b"]` → PostgreSQL array column or junction table |
|
|
364
|
+
| **Arrays of objects** | `orders: [{item, qty}]` → child table with foreign key back to parent |
|
|
365
|
+
| **Missing fields** | Detects frequency across all documents, makes sparse fields nullable |
|
|
366
|
+
| **Type mismatches** | Same field with different types → casts to majority type, logs failures to `_migration_errors` |
|
|
367
|
+
| **ObjectId references** | Auto-detects `userId: ObjectId(...)` patterns → creates proper foreign keys |
|
|
368
|
+
| **Deep nesting** | Flattens up to configurable depth (default: 2), stores deeper levels as `jsonb` |
|
|
369
|
+
| **Postgres → Mongo** | 1:1 joins → embedded objects. Small 1:many → embedded arrays. Large 1:many → separate collections with refs |
|
|
370
|
+
| **Many-to-many** | Junction tables → arrays of values in the document |
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### The reverse — PostgreSQL to MongoDB
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
npx dbdock migrate "postgresql://user:pass@localhost:5432/myapp" "mongodb://localhost:27017/myapp"
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
DBDock detects table relationships and proposes embedding vs referencing strategies:
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
Proposed Document Mapping:
|
|
384
|
+
|
|
385
|
+
users → users collection
|
|
386
|
+
├─ id → _id
|
|
387
|
+
├─ name → name
|
|
388
|
+
├─ email → email
|
|
389
|
+
├─ addresses → embed object as address
|
|
390
|
+
├─ orders → embed array as orders (< 1000 rows)
|
|
391
|
+
|
|
392
|
+
products → products collection
|
|
393
|
+
├─ id → _id
|
|
394
|
+
├─ title → title
|
|
395
|
+
├─ price → price
|
|
396
|
+
├─ product_tags → embed as tags array
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Small 1:1 and 1:many relations get embedded. Large 1:many relations stay as separate collections with reference fields. You can override per table.
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### Dry run & validation
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
npx dbdock migrate --dry-run "mongodb://..." "postgresql://..."
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Runs the full migration into a temporary schema, validates counts and referential integrity, then cleans up. Nothing touches the real target:
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
Dry Run Results:
|
|
413
|
+
─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
|
414
|
+
✔ users: 45,000 → 45,000
|
|
415
|
+
✔ addresses: 45,000 → 44,998 (2 failed)
|
|
416
|
+
✔ orders: 312,400 → 312,400
|
|
417
|
+
✔ products: 12,000 → 12,000
|
|
418
|
+
✔ product_tags: 38,200 → 38,200
|
|
419
|
+
|
|
420
|
+
⚠ 2 rows failed (see _migration_errors)
|
|
421
|
+
✓ All foreign keys valid — dry run passed
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
### Incremental / delta migration
|
|
427
|
+
|
|
428
|
+
Already migrated once but your app is still running on the old database? Sync only new or changed data:
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
npx dbdock migrate --incremental --since "2026-03-10" "mongodb://..." "postgresql://..."
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Uses `createdAt`/`updatedAt` timestamps to only transfer new and changed documents. Existing rows in the target are upserted.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
### Save & reuse config
|
|
439
|
+
|
|
440
|
+
Export the mapping for your team to use reproducibly:
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
npx dbdock migrate --export-config ./migration.yaml "mongodb://..." "postgresql://..."
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Then anyone runs the same migration:
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
npx dbdock migrate --config ./migration.yaml "mongodb://..." "postgresql://..."
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Tweak the YAML/JSON config to adjust type mappings, embedding strategies, or rename target tables — then re-run.
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
### Migration options
|
|
457
|
+
|
|
458
|
+
| Flag | What it does |
|
|
459
|
+
|---|---|
|
|
460
|
+
| `--dry-run` | Migrate into temp schema, validate, clean up |
|
|
461
|
+
| `--incremental` | Only sync new/changed data |
|
|
462
|
+
| `--since <date>` | Cutoff date for incremental mode (ISO format) |
|
|
463
|
+
| `--config <path>` | Load a saved migration config (YAML or JSON) |
|
|
464
|
+
| `--export-config <path>` | Save migration plan to file without executing |
|
|
465
|
+
| `--batch-size <n>` | Documents per batch (default: 1000) |
|
|
466
|
+
| `--max-depth <n>` | Max nesting depth before storing as jsonb (default: 2) |
|
|
467
|
+
|
|
468
|
+
### Core principles
|
|
469
|
+
|
|
470
|
+
- **Never lose data** — failed rows go to `_migration_errors`, never silently dropped
|
|
471
|
+
- **Never surprise the user** — full mapping shown before execution, conflicts flagged
|
|
472
|
+
- **Always let you review** — nothing executes without explicit confirmation
|
|
473
|
+
- **Reproducible** — export/import configs for team-wide consistency
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
261
477
|
## Storage Providers
|
|
262
478
|
|
|
263
479
|
Pick your storage during `dbdock init`, or set it in `dbdock.config.json`:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function analyzeCommand(url: string): Promise<void>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.analyzeCommand = analyzeCommand;
|
|
7
|
+
const ora_1 = __importDefault(require("ora"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const logger_1 = require("../utils/logger");
|
|
10
|
+
const migration_engine_1 = require("../../migration/engines/migration.engine");
|
|
11
|
+
async function analyzeCommand(url) {
|
|
12
|
+
console.log('');
|
|
13
|
+
console.log(chalk_1.default.bold(' DBDock - Database Analysis'));
|
|
14
|
+
console.log(chalk_1.default.gray(' ─'.repeat(30)));
|
|
15
|
+
console.log('');
|
|
16
|
+
let parsed;
|
|
17
|
+
try {
|
|
18
|
+
parsed = (0, migration_engine_1.parseDatabaseUrl)(url);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
logger_1.logger.error(error instanceof Error ? error.message : String(error));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
logger_1.logger.info(`Database: ${chalk_1.default.cyan(parsed.type === 'mongodb' ? 'MongoDB' : 'PostgreSQL')} — ${parsed.database}`);
|
|
25
|
+
logger_1.logger.info(`Host: ${parsed.host}:${parsed.port}`);
|
|
26
|
+
console.log('');
|
|
27
|
+
const spinner = (0, ora_1.default)('Analyzing database structure...').start();
|
|
28
|
+
try {
|
|
29
|
+
const analysis = await (0, migration_engine_1.analyzeDatabase)(url);
|
|
30
|
+
spinner.succeed('Analysis complete');
|
|
31
|
+
console.log('');
|
|
32
|
+
if (analysis.type === 'mongodb') {
|
|
33
|
+
displayMongoAnalysis(analysis);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
displayPostgresAnalysis(analysis);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
spinner.fail('Analysis failed');
|
|
41
|
+
logger_1.logger.error(error instanceof Error ? error.message : String(error));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function displayMongoAnalysis(analysis) {
|
|
46
|
+
console.log(chalk_1.default.bold(` Found ${chalk_1.default.cyan(String(analysis.collections.length))} collections, ${chalk_1.default.cyan(formatNumber(analysis.totalDocuments))} total documents`));
|
|
47
|
+
console.log('');
|
|
48
|
+
for (const collection of analysis.collections) {
|
|
49
|
+
console.log(chalk_1.default.bold(` ${chalk_1.default.green(collection.name)} ${chalk_1.default.gray(`(${formatNumber(collection.documentCount)} docs)`)}`));
|
|
50
|
+
for (let i = 0; i < collection.fields.length; i++) {
|
|
51
|
+
const field = collection.fields[i];
|
|
52
|
+
const isLast = i === collection.fields.length - 1;
|
|
53
|
+
const prefix = isLast ? ' └─' : ' ├─';
|
|
54
|
+
displayMongoField(field, prefix, isLast ? ' ' : ' │ ');
|
|
55
|
+
}
|
|
56
|
+
console.log('');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function displayMongoField(field, prefix, childPrefix) {
|
|
60
|
+
const typeEntries = Object.entries(field.types).filter(([t]) => t !== 'null' && t !== 'undefined');
|
|
61
|
+
const typeStr = typeEntries
|
|
62
|
+
.map(([t, c]) => {
|
|
63
|
+
if (typeEntries.length > 1)
|
|
64
|
+
return `${t}(${c})`;
|
|
65
|
+
return t;
|
|
66
|
+
})
|
|
67
|
+
.join(', ');
|
|
68
|
+
let extra = '';
|
|
69
|
+
if (field.frequency < 100) {
|
|
70
|
+
extra += chalk_1.default.yellow(` [${field.frequency.toFixed(0)}% present]`);
|
|
71
|
+
}
|
|
72
|
+
if (field.isArray) {
|
|
73
|
+
extra += chalk_1.default.blue(` [array: ${field.arrayElementType || 'mixed'}]`);
|
|
74
|
+
}
|
|
75
|
+
if (field.isObjectId && field.name !== '_id') {
|
|
76
|
+
extra += chalk_1.default.magenta(` → ref${field.possibleReference ? `: ${field.possibleReference}` : ''}`);
|
|
77
|
+
}
|
|
78
|
+
if (typeEntries.length > 1) {
|
|
79
|
+
extra += chalk_1.default.red(' ⚠ mixed types');
|
|
80
|
+
}
|
|
81
|
+
console.log(`${prefix} ${chalk_1.default.white(field.name)} ${chalk_1.default.gray(`(${typeStr})`)}${extra}`);
|
|
82
|
+
if (field.nestedFields && field.isNestedObject && !field.isArray) {
|
|
83
|
+
for (let i = 0; i < field.nestedFields.length; i++) {
|
|
84
|
+
const nested = field.nestedFields[i];
|
|
85
|
+
const isLast = i === field.nestedFields.length - 1;
|
|
86
|
+
const nPrefix = childPrefix + (isLast ? ' └─' : ' ├─');
|
|
87
|
+
const nChildPrefix = childPrefix + (isLast ? ' ' : ' │ ');
|
|
88
|
+
displayMongoField(nested, nPrefix, nChildPrefix);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function displayPostgresAnalysis(analysis) {
|
|
93
|
+
console.log(chalk_1.default.bold(` Found ${chalk_1.default.cyan(String(analysis.tables.length))} tables, ${chalk_1.default.cyan(formatNumber(analysis.totalRows))} total rows`));
|
|
94
|
+
console.log('');
|
|
95
|
+
for (const table of analysis.tables) {
|
|
96
|
+
console.log(chalk_1.default.bold(` ${chalk_1.default.green(table.name)} ${chalk_1.default.gray(`(${formatNumber(table.rowCount)} rows)`)}`));
|
|
97
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
98
|
+
const col = table.columns[i];
|
|
99
|
+
const isLast = i === table.columns.length - 1 && table.foreignKeys.length === 0;
|
|
100
|
+
const prefix = isLast ? ' └─' : ' ├─';
|
|
101
|
+
let extra = '';
|
|
102
|
+
if (col.isPrimaryKey)
|
|
103
|
+
extra += chalk_1.default.yellow(' PK');
|
|
104
|
+
if (col.isUnique && !col.isPrimaryKey)
|
|
105
|
+
extra += chalk_1.default.blue(' UNIQUE');
|
|
106
|
+
if (!col.isNullable)
|
|
107
|
+
extra += chalk_1.default.gray(' NOT NULL');
|
|
108
|
+
if (col.columnDefault)
|
|
109
|
+
extra += chalk_1.default.gray(` DEFAULT ${col.columnDefault}`);
|
|
110
|
+
const fk = table.foreignKeys.find((f) => f.columnName === col.name);
|
|
111
|
+
if (fk) {
|
|
112
|
+
extra += chalk_1.default.magenta(` → ${fk.referencedTable}.${fk.referencedColumn}`);
|
|
113
|
+
}
|
|
114
|
+
console.log(`${prefix} ${chalk_1.default.white(col.name)} ${chalk_1.default.gray(`(${col.dataType})`)}${extra}`);
|
|
115
|
+
}
|
|
116
|
+
if (table.indexes.length > 0) {
|
|
117
|
+
const nonPkIndexes = table.indexes.filter((idx) => !idx.isPrimary);
|
|
118
|
+
for (let i = 0; i < nonPkIndexes.length; i++) {
|
|
119
|
+
const idx = nonPkIndexes[i];
|
|
120
|
+
const isLast = i === nonPkIndexes.length - 1;
|
|
121
|
+
const prefix = isLast ? ' └─' : ' ├─';
|
|
122
|
+
console.log(`${prefix} ${chalk_1.default.gray('idx:')} ${idx.name} ${chalk_1.default.gray(`(${idx.columns.join(', ')})`)}${idx.isUnique ? chalk_1.default.blue(' UNIQUE') : ''}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
console.log('');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function formatNumber(n) {
|
|
129
|
+
if (n >= 1000000)
|
|
130
|
+
return `${(n / 1000000).toFixed(1)}M`;
|
|
131
|
+
if (n >= 1000)
|
|
132
|
+
return `${(n / 1000).toFixed(1)}K`;
|
|
133
|
+
return String(n);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../../src/cli/commands/analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface MigrateOptions {
|
|
2
|
+
dryRun?: boolean;
|
|
3
|
+
incremental?: boolean;
|
|
4
|
+
since?: string;
|
|
5
|
+
config?: string;
|
|
6
|
+
exportConfig?: string;
|
|
7
|
+
batchSize?: number;
|
|
8
|
+
maxDepth?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function crossMigrateCommand(sourceUrl: string, targetUrl: string, options: MigrateOptions): Promise<void>;
|
|
11
|
+
export {};
|