mpx-db 1.0.3 → 1.1.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 +135 -2
- package/package.json +8 -2
- package/src/cli.js +53 -15
- package/src/commands/connections.js +63 -10
- package/src/commands/data.js +20 -7
- package/src/commands/migrate.js +142 -36
- package/src/commands/query.js +44 -14
- package/src/commands/schema.js +120 -50
- package/src/mcp.js +307 -0
- package/src/schema.js +581 -0
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ Stop juggling multiple database tools. `mpx-db` gives you one clean interface fo
|
|
|
13
13
|
✅ **Schema operations** — Dump, describe, visualize database structure
|
|
14
14
|
✅ **Data export** — Export to JSON/CSV with one command
|
|
15
15
|
✅ **Secure** — Encrypted credential storage
|
|
16
|
+
✅ **AI-native** — JSON output, MCP server, schema discovery for AI agents
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -224,6 +225,135 @@ mpx-db migrate create add_order_status_field
|
|
|
224
225
|
mpx-db export dev orders --format csv --output orders-backup.csv
|
|
225
226
|
```
|
|
226
227
|
|
|
228
|
+
## AI Agent Usage
|
|
229
|
+
|
|
230
|
+
`mpx-db` is **AI-native** — designed for both humans and AI agents. Every command supports machine-readable output and schema discovery.
|
|
231
|
+
|
|
232
|
+
### JSON Output
|
|
233
|
+
|
|
234
|
+
Add `--json` to any command for structured output:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Query with JSON output
|
|
238
|
+
mpx-db query dev "SELECT * FROM users LIMIT 3" --json
|
|
239
|
+
{
|
|
240
|
+
"success": true,
|
|
241
|
+
"type": "query",
|
|
242
|
+
"rows": [
|
|
243
|
+
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
|
|
244
|
+
{ "id": 2, "name": "Bob", "email": "bob@example.com" },
|
|
245
|
+
{ "id": 3, "name": "Charlie", "email": "charlie@example.com" }
|
|
246
|
+
],
|
|
247
|
+
"rowCount": 3,
|
|
248
|
+
"duration": 12
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
# List tables with JSON
|
|
252
|
+
mpx-db tables dev --json
|
|
253
|
+
{
|
|
254
|
+
"tables": [
|
|
255
|
+
{ "name": "users", "type": "table", "rowCount": 150 },
|
|
256
|
+
{ "name": "orders", "type": "table", "rowCount": 892 }
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
# Migration status
|
|
261
|
+
mpx-db migrate status dev --json
|
|
262
|
+
{
|
|
263
|
+
"migrations": [
|
|
264
|
+
{ "name": "20260215_100000_create_users", "status": "applied", "appliedAt": "2026-02-15T10:05:00.000Z" },
|
|
265
|
+
{ "name": "20260216_120000_add_orders", "status": "pending", "appliedAt": null }
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Schema Discovery
|
|
271
|
+
|
|
272
|
+
Get the full command schema for AI agent integration:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
mpx-db --schema
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Returns a comprehensive JSON schema describing all commands, flags, inputs, outputs, and examples.
|
|
279
|
+
|
|
280
|
+
### MCP (Model Context Protocol) Server
|
|
281
|
+
|
|
282
|
+
Run `mpx-db` as an MCP server for seamless AI agent integration:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
mpx-db mcp
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### Claude Desktop Integration
|
|
289
|
+
|
|
290
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"mcpServers": {
|
|
295
|
+
"mpx-db": {
|
|
296
|
+
"command": "npx",
|
|
297
|
+
"args": ["mpx-db", "mcp"]
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Now Claude can directly query your databases, inspect schemas, and run migrations!
|
|
304
|
+
|
|
305
|
+
#### Available MCP Tools
|
|
306
|
+
|
|
307
|
+
- `query` — Execute SQL queries
|
|
308
|
+
- `list_tables` — Get all tables with row counts
|
|
309
|
+
- `describe_table` — Show table schema
|
|
310
|
+
- `get_info` — Database information
|
|
311
|
+
- `export_table` — Export table data as JSON
|
|
312
|
+
- `get_schema` — Get full command schema
|
|
313
|
+
|
|
314
|
+
### Quiet Mode
|
|
315
|
+
|
|
316
|
+
Suppress non-essential output with `--quiet`:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
# Just the data, no banners or progress messages
|
|
320
|
+
mpx-db query dev "SELECT COUNT(*) FROM users" --quiet --json
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Exit Codes
|
|
324
|
+
|
|
325
|
+
Predictable exit codes for CI/CD and scripting:
|
|
326
|
+
|
|
327
|
+
- `0` — Success
|
|
328
|
+
- `1` — Error (connection failed, query failed, etc.)
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
#!/bin/bash
|
|
332
|
+
if mpx-db query dev "SELECT 1" --quiet; then
|
|
333
|
+
echo "Database is up"
|
|
334
|
+
else
|
|
335
|
+
echo "Database is down"
|
|
336
|
+
exit 1
|
|
337
|
+
fi
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Example: AI Agent Workflow
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
// AI agent discovers available commands
|
|
344
|
+
const schema = await exec('mpx-db --schema');
|
|
345
|
+
|
|
346
|
+
// Agent queries database
|
|
347
|
+
const result = await exec('mpx-db query dev "SELECT * FROM orders WHERE status = \'pending\'" --json');
|
|
348
|
+
const orders = JSON.parse(result.stdout);
|
|
349
|
+
|
|
350
|
+
// Agent inspects schema
|
|
351
|
+
const tables = await exec('mpx-db tables dev --json');
|
|
352
|
+
|
|
353
|
+
// Agent runs migration
|
|
354
|
+
await exec('mpx-db migrate up dev --json --quiet');
|
|
355
|
+
```
|
|
356
|
+
|
|
227
357
|
## Architecture
|
|
228
358
|
|
|
229
359
|
```
|
|
@@ -310,15 +440,18 @@ Test suite includes:
|
|
|
310
440
|
|
|
311
441
|
## Roadmap
|
|
312
442
|
|
|
313
|
-
**v1.
|
|
443
|
+
**v1.1 (Current)** ✅
|
|
314
444
|
- SQLite, PostgreSQL, MySQL support
|
|
315
445
|
- Connection management
|
|
316
446
|
- Query execution with beautiful output
|
|
317
447
|
- Schema inspection (dump, describe, tables, info)
|
|
318
448
|
- Migration system (create, up, down, status)
|
|
319
449
|
- Data export (JSON, CSV)
|
|
450
|
+
- **AI-native features:** JSON output (`--json`), schema discovery (`--schema`), MCP server mode
|
|
451
|
+
- **Quiet mode** (`--quiet`) for scripting
|
|
452
|
+
- Predictable exit codes
|
|
320
453
|
|
|
321
|
-
**v1.
|
|
454
|
+
**v1.2 (Planned)**
|
|
322
455
|
- Interactive query REPL mode
|
|
323
456
|
- Query history and favorites
|
|
324
457
|
- Auto-complete for table/column names
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mpx-db",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Database management CLI - Connect, query, migrate, and manage databases from the terminal",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -20,7 +20,12 @@
|
|
|
20
20
|
"mysql",
|
|
21
21
|
"sqlite",
|
|
22
22
|
"schema",
|
|
23
|
-
"sql"
|
|
23
|
+
"sql",
|
|
24
|
+
"mcp",
|
|
25
|
+
"ai-native",
|
|
26
|
+
"model-context-protocol",
|
|
27
|
+
"automation",
|
|
28
|
+
"json-output"
|
|
24
29
|
],
|
|
25
30
|
"author": "Mesaplex <support@mesaplex.com>",
|
|
26
31
|
"license": "MIT",
|
|
@@ -34,6 +39,7 @@
|
|
|
34
39
|
"node": ">=18.0.0"
|
|
35
40
|
},
|
|
36
41
|
"dependencies": {
|
|
42
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
37
43
|
"better-sqlite3": "^12.6.2",
|
|
38
44
|
"chalk": "^5.3.0",
|
|
39
45
|
"cli-table3": "^0.6.5",
|
package/src/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
rollbackMigration
|
|
15
15
|
} from './commands/migrate.js';
|
|
16
16
|
import { exportData } from './commands/data.js';
|
|
17
|
+
import { getSchema } from './schema.js';
|
|
17
18
|
|
|
18
19
|
const __filename = fileURLToPath(import.meta.url);
|
|
19
20
|
const __dirname = dirname(__filename);
|
|
@@ -21,10 +22,27 @@ const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8')
|
|
|
21
22
|
|
|
22
23
|
const program = new Command();
|
|
23
24
|
|
|
25
|
+
// Global options state (passed to commands via options parameter)
|
|
26
|
+
let globalOptions = {};
|
|
27
|
+
|
|
24
28
|
program
|
|
25
29
|
.name('mpx-db')
|
|
26
30
|
.description('Database management CLI - Connect, query, migrate, and manage databases')
|
|
27
|
-
.version(pkg.version)
|
|
31
|
+
.version(pkg.version)
|
|
32
|
+
.option('--json', 'Output as JSON (machine-readable)')
|
|
33
|
+
.option('-q, --quiet', 'Suppress non-essential output')
|
|
34
|
+
.option('--schema', 'Output JSON schema describing all commands and flags')
|
|
35
|
+
.hook('preAction', (thisCommand) => {
|
|
36
|
+
// Merge parent options with command options
|
|
37
|
+
const parentOpts = thisCommand.parent?.opts() || {};
|
|
38
|
+
const opts = thisCommand.opts();
|
|
39
|
+
globalOptions = { ...parentOpts, ...opts };
|
|
40
|
+
|
|
41
|
+
// Disable chalk if JSON mode
|
|
42
|
+
if (globalOptions.json) {
|
|
43
|
+
chalk.level = 0;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
28
46
|
|
|
29
47
|
// Connect command
|
|
30
48
|
program
|
|
@@ -32,7 +50,7 @@ program
|
|
|
32
50
|
.description('Test and optionally save a database connection')
|
|
33
51
|
.argument('<url>', 'Connection URL (sqlite://, postgres://, mysql://)')
|
|
34
52
|
.option('-s, --save <name>', 'Save connection with a name')
|
|
35
|
-
.action(handleConnect);
|
|
53
|
+
.action((url, options) => handleConnect(url, { ...globalOptions, ...options }));
|
|
36
54
|
|
|
37
55
|
// Connections command
|
|
38
56
|
const connections = program
|
|
@@ -42,13 +60,13 @@ const connections = program
|
|
|
42
60
|
connections
|
|
43
61
|
.command('list')
|
|
44
62
|
.description('List all saved connections')
|
|
45
|
-
.action(listConnections);
|
|
63
|
+
.action(() => listConnections(globalOptions));
|
|
46
64
|
|
|
47
65
|
connections
|
|
48
66
|
.command('remove')
|
|
49
67
|
.description('Remove a saved connection')
|
|
50
68
|
.argument('<name>', 'Connection name')
|
|
51
|
-
.action(removeConnection);
|
|
69
|
+
.action((name) => removeConnection(name, globalOptions));
|
|
52
70
|
|
|
53
71
|
// Query command
|
|
54
72
|
program
|
|
@@ -56,21 +74,21 @@ program
|
|
|
56
74
|
.description('Execute a SQL query')
|
|
57
75
|
.argument('<target>', 'Connection name or URL')
|
|
58
76
|
.argument('<sql>', 'SQL query to execute')
|
|
59
|
-
.action(handleQuery);
|
|
77
|
+
.action((target, sql) => handleQuery(target, sql, globalOptions));
|
|
60
78
|
|
|
61
79
|
// Info command
|
|
62
80
|
program
|
|
63
81
|
.command('info')
|
|
64
82
|
.description('Show database information')
|
|
65
83
|
.argument('<target>', 'Connection name or URL')
|
|
66
|
-
.action(showInfo);
|
|
84
|
+
.action((target) => showInfo(target, globalOptions));
|
|
67
85
|
|
|
68
86
|
// Tables command
|
|
69
87
|
program
|
|
70
88
|
.command('tables')
|
|
71
89
|
.description('List all tables')
|
|
72
90
|
.argument('<target>', 'Connection name or URL')
|
|
73
|
-
.action(listTables);
|
|
91
|
+
.action((target) => listTables(target, globalOptions));
|
|
74
92
|
|
|
75
93
|
// Describe command
|
|
76
94
|
program
|
|
@@ -78,7 +96,7 @@ program
|
|
|
78
96
|
.description('Show table schema')
|
|
79
97
|
.argument('<target>', 'Connection name or URL')
|
|
80
98
|
.argument('<table>', 'Table name')
|
|
81
|
-
.action(describeTable);
|
|
99
|
+
.action((target, table) => describeTable(target, table, globalOptions));
|
|
82
100
|
|
|
83
101
|
// Schema commands
|
|
84
102
|
const schema = program
|
|
@@ -89,7 +107,7 @@ schema
|
|
|
89
107
|
.command('dump')
|
|
90
108
|
.description('Dump database schema as SQL')
|
|
91
109
|
.argument('<target>', 'Connection name or URL')
|
|
92
|
-
.action(dumpSchema);
|
|
110
|
+
.action((target) => dumpSchema(target, globalOptions));
|
|
93
111
|
|
|
94
112
|
// Migration commands
|
|
95
113
|
const migrate = program
|
|
@@ -99,31 +117,31 @@ const migrate = program
|
|
|
99
117
|
migrate
|
|
100
118
|
.command('init')
|
|
101
119
|
.description('Initialize migrations directory')
|
|
102
|
-
.action(initMigrations);
|
|
120
|
+
.action(() => initMigrations(globalOptions));
|
|
103
121
|
|
|
104
122
|
migrate
|
|
105
123
|
.command('create')
|
|
106
124
|
.description('Create a new migration file')
|
|
107
125
|
.argument('<description>', 'Migration description')
|
|
108
|
-
.action(createMigration);
|
|
126
|
+
.action((description) => createMigration(description, globalOptions));
|
|
109
127
|
|
|
110
128
|
migrate
|
|
111
129
|
.command('status')
|
|
112
130
|
.description('Show migration status')
|
|
113
131
|
.argument('<target>', 'Connection name or URL')
|
|
114
|
-
.action(showMigrationStatus);
|
|
132
|
+
.action((target) => showMigrationStatus(target, globalOptions));
|
|
115
133
|
|
|
116
134
|
migrate
|
|
117
135
|
.command('up')
|
|
118
136
|
.description('Run pending migrations')
|
|
119
137
|
.argument('<target>', 'Connection name or URL')
|
|
120
|
-
.action(runMigrations);
|
|
138
|
+
.action((target) => runMigrations(target, globalOptions));
|
|
121
139
|
|
|
122
140
|
migrate
|
|
123
141
|
.command('down')
|
|
124
142
|
.description('Rollback last migration')
|
|
125
143
|
.argument('<target>', 'Connection name or URL')
|
|
126
|
-
.action(rollbackMigration);
|
|
144
|
+
.action((target) => rollbackMigration(target, globalOptions));
|
|
127
145
|
|
|
128
146
|
// Export command
|
|
129
147
|
program
|
|
@@ -133,7 +151,27 @@ program
|
|
|
133
151
|
.argument('<table>', 'Table name')
|
|
134
152
|
.option('-f, --format <format>', 'Output format (json, csv)', 'json')
|
|
135
153
|
.option('-o, --output <file>', 'Output file path')
|
|
136
|
-
.action(exportData);
|
|
154
|
+
.action((target, table, options) => exportData(target, table, { ...globalOptions, ...options }));
|
|
155
|
+
|
|
156
|
+
// MCP subcommand
|
|
157
|
+
program
|
|
158
|
+
.command('mcp')
|
|
159
|
+
.description('Start MCP (Model Context Protocol) stdio server')
|
|
160
|
+
.action(async () => {
|
|
161
|
+
try {
|
|
162
|
+
const { startMCPServer } = await import('./mcp.js');
|
|
163
|
+
await startMCPServer();
|
|
164
|
+
} catch (err) {
|
|
165
|
+
console.error(JSON.stringify({ error: err.message, code: 'ERR_MCP_START' }));
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Handle --schema before parsing (to avoid argument validation)
|
|
171
|
+
if (process.argv.includes('--schema')) {
|
|
172
|
+
console.log(JSON.stringify(getSchema(), null, 2));
|
|
173
|
+
process.exit(0);
|
|
174
|
+
}
|
|
137
175
|
|
|
138
176
|
// Error handling
|
|
139
177
|
program.exitOverride();
|
|
@@ -6,14 +6,40 @@ import { createConnection } from '../db/connection.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* Handle connect command
|
|
8
8
|
*/
|
|
9
|
-
export async function handleConnect(url, options) {
|
|
9
|
+
export async function handleConnect(url, options = {}) {
|
|
10
10
|
try {
|
|
11
11
|
// Test connection
|
|
12
|
-
|
|
12
|
+
if (!options.quiet && !options.json) {
|
|
13
|
+
console.log(chalk.gray('Testing connection...'));
|
|
14
|
+
}
|
|
15
|
+
|
|
13
16
|
const db = await createConnection(url);
|
|
14
17
|
const info = await db.getInfo();
|
|
15
18
|
await db.disconnect();
|
|
16
19
|
|
|
20
|
+
// Save if requested
|
|
21
|
+
let saved = false;
|
|
22
|
+
if (options.save) {
|
|
23
|
+
saveConnection(options.save, url);
|
|
24
|
+
saved = true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// JSON output
|
|
28
|
+
if (options.json) {
|
|
29
|
+
console.log(JSON.stringify({
|
|
30
|
+
success: true,
|
|
31
|
+
connection: {
|
|
32
|
+
type: info.type,
|
|
33
|
+
database: info.database,
|
|
34
|
+
path: info.path
|
|
35
|
+
},
|
|
36
|
+
saved,
|
|
37
|
+
name: options.save || null
|
|
38
|
+
}, null, 2));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Human-readable output
|
|
17
43
|
console.log(chalk.green('✓ Connection successful'));
|
|
18
44
|
console.log(chalk.gray(` Type: ${info.type}`));
|
|
19
45
|
if (info.database) {
|
|
@@ -23,15 +49,17 @@ export async function handleConnect(url, options) {
|
|
|
23
49
|
console.log(chalk.gray(` Path: ${info.path}`));
|
|
24
50
|
}
|
|
25
51
|
|
|
26
|
-
// Save if requested
|
|
27
52
|
if (options.save) {
|
|
28
|
-
saveConnection(options.save, url);
|
|
29
53
|
console.log(chalk.green(`✓ Saved connection as "${options.save}"`));
|
|
30
54
|
}
|
|
31
55
|
|
|
32
56
|
} catch (err) {
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
if (options.json) {
|
|
58
|
+
console.log(JSON.stringify({ success: false, error: err.message }, null, 2));
|
|
59
|
+
} else {
|
|
60
|
+
console.error(chalk.red('✗ Connection failed'));
|
|
61
|
+
console.error(chalk.red(` ${err.message}`));
|
|
62
|
+
}
|
|
35
63
|
process.exit(1);
|
|
36
64
|
}
|
|
37
65
|
}
|
|
@@ -39,13 +67,27 @@ export async function handleConnect(url, options) {
|
|
|
39
67
|
/**
|
|
40
68
|
* List saved connections
|
|
41
69
|
*/
|
|
42
|
-
export async function listConnections() {
|
|
70
|
+
export async function listConnections(options = {}) {
|
|
43
71
|
const connections = loadConnections();
|
|
44
72
|
|
|
73
|
+
// JSON output
|
|
74
|
+
if (options.json) {
|
|
75
|
+
const connArray = Object.entries(connections).map(([name, conn]) => ({
|
|
76
|
+
name,
|
|
77
|
+
type: conn.type,
|
|
78
|
+
createdAt: new Date(conn.createdAt).toISOString()
|
|
79
|
+
}));
|
|
80
|
+
console.log(JSON.stringify({ connections: connArray }, null, 2));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Human-readable output
|
|
45
85
|
if (Object.keys(connections).length === 0) {
|
|
46
86
|
console.log(chalk.yellow('No saved connections'));
|
|
47
|
-
|
|
48
|
-
|
|
87
|
+
if (!options.quiet) {
|
|
88
|
+
console.log(chalk.gray('\nSave a connection with:'));
|
|
89
|
+
console.log(chalk.gray(' mpx-db connect --save <name> <url>'));
|
|
90
|
+
}
|
|
49
91
|
return;
|
|
50
92
|
}
|
|
51
93
|
|
|
@@ -68,9 +110,20 @@ export async function listConnections() {
|
|
|
68
110
|
/**
|
|
69
111
|
* Delete a saved connection
|
|
70
112
|
*/
|
|
71
|
-
export async function removeConnection(name) {
|
|
113
|
+
export async function removeConnection(name, options = {}) {
|
|
72
114
|
const deleted = deleteConnection(name);
|
|
73
115
|
|
|
116
|
+
// JSON output
|
|
117
|
+
if (options.json) {
|
|
118
|
+
console.log(JSON.stringify({
|
|
119
|
+
success: deleted,
|
|
120
|
+
name,
|
|
121
|
+
message: deleted ? 'Connection deleted' : 'Connection not found'
|
|
122
|
+
}, null, 2));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Human-readable output
|
|
74
127
|
if (deleted) {
|
|
75
128
|
console.log(chalk.green(`✓ Deleted connection "${name}"`));
|
|
76
129
|
} else {
|
package/src/commands/data.js
CHANGED
|
@@ -6,7 +6,7 @@ import { resolveConnection } from './query.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* Export table data to CSV or JSON
|
|
8
8
|
*/
|
|
9
|
-
export async function exportData(target, tableName, options) {
|
|
9
|
+
export async function exportData(target, tableName, options = {}) {
|
|
10
10
|
let db;
|
|
11
11
|
|
|
12
12
|
try {
|
|
@@ -17,12 +17,14 @@ export async function exportData(target, tableName, options) {
|
|
|
17
17
|
const rows = await db.query(`SELECT * FROM ${tableName}`);
|
|
18
18
|
|
|
19
19
|
if (rows.length === 0) {
|
|
20
|
-
|
|
20
|
+
if (!options.quiet) {
|
|
21
|
+
console.log(chalk.yellow('No data to export'));
|
|
22
|
+
}
|
|
21
23
|
return;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const format = options.format || 'json';
|
|
25
|
-
const output = options.output
|
|
27
|
+
const output = options.output;
|
|
26
28
|
|
|
27
29
|
let content;
|
|
28
30
|
|
|
@@ -34,12 +36,23 @@ export async function exportData(target, tableName, options) {
|
|
|
34
36
|
throw new Error(`Unsupported format: ${format}`);
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
// If output file specified, write to file
|
|
40
|
+
if (output) {
|
|
41
|
+
fs.writeFileSync(output, content);
|
|
42
|
+
if (!options.quiet) {
|
|
43
|
+
console.log(chalk.green(`✓ Exported ${rows.length} rows to ${output}`));
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// Write to stdout
|
|
47
|
+
console.log(content);
|
|
48
|
+
}
|
|
40
49
|
|
|
41
50
|
} catch (err) {
|
|
42
|
-
|
|
51
|
+
if (options.json) {
|
|
52
|
+
console.log(JSON.stringify({ error: err.message }, null, 2));
|
|
53
|
+
} else {
|
|
54
|
+
console.error(chalk.red(`✗ Export failed: ${err.message}`));
|
|
55
|
+
}
|
|
43
56
|
process.exit(1);
|
|
44
57
|
} finally {
|
|
45
58
|
if (db) {
|