@hesed/mysql 0.5.0 → 0.5.2
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 +49 -35
- package/dist/base-command.d.ts +10 -0
- package/dist/base-command.js +37 -0
- package/dist/commands/mysql/databases.d.ts +4 -3
- package/dist/commands/mysql/databases.js +7 -6
- package/dist/commands/mysql/describe-table.d.ts +5 -4
- package/dist/commands/mysql/describe-table.js +10 -13
- package/dist/commands/mysql/{explain-query.d.ts → explain.d.ts} +5 -4
- package/dist/commands/mysql/{explain-query.js → explain.js} +10 -13
- package/dist/commands/mysql/indexes.d.ts +5 -4
- package/dist/commands/mysql/indexes.js +10 -13
- package/dist/commands/mysql/query.d.ts +5 -4
- package/dist/commands/mysql/query.js +18 -18
- package/dist/commands/mysql/tables.d.ts +4 -3
- package/dist/commands/mysql/tables.js +7 -6
- package/dist/mysql/database.d.ts +39 -30
- package/dist/mysql/mysql-utils.js +47 -20
- package/oclif.manifest.json +81 -64
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ $ npm install -g @hesed/mysql
|
|
|
26
26
|
$ mq COMMAND
|
|
27
27
|
running command...
|
|
28
28
|
$ mq (--version)
|
|
29
|
-
@hesed/mysql/0.5.
|
|
29
|
+
@hesed/mysql/0.5.2 linux-x64 node-v24.17.0
|
|
30
30
|
$ mq --help [COMMAND]
|
|
31
31
|
USAGE
|
|
32
32
|
$ mq COMMAND
|
|
@@ -45,7 +45,7 @@ USAGE
|
|
|
45
45
|
* [`mq mysql auth update`](#mq-mysql-auth-update)
|
|
46
46
|
* [`mq mysql databases`](#mq-mysql-databases)
|
|
47
47
|
* [`mq mysql describe-table TABLE`](#mq-mysql-describe-table-table)
|
|
48
|
-
* [`mq mysql explain
|
|
48
|
+
* [`mq mysql explain QUERY`](#mq-mysql-explain-query)
|
|
49
49
|
* [`mq mysql indexes TABLE`](#mq-mysql-indexes-table)
|
|
50
50
|
* [`mq mysql query QUERY`](#mq-mysql-query-query)
|
|
51
51
|
* [`mq mysql tables`](#mq-mysql-tables)
|
|
@@ -80,7 +80,7 @@ EXAMPLES
|
|
|
80
80
|
$ mq mysql auth add -p prod
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
_See code: [src/commands/mysql/auth/add.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
83
|
+
_See code: [src/commands/mysql/auth/add.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/auth/add.ts)_
|
|
84
84
|
|
|
85
85
|
## `mq mysql auth delete`
|
|
86
86
|
|
|
@@ -105,7 +105,7 @@ EXAMPLES
|
|
|
105
105
|
$ mq mysql auth delete -p prod
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
_See code: [src/commands/mysql/auth/delete.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
108
|
+
_See code: [src/commands/mysql/auth/delete.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/auth/delete.ts)_
|
|
109
109
|
|
|
110
110
|
## `mq mysql auth list`
|
|
111
111
|
|
|
@@ -125,7 +125,7 @@ EXAMPLES
|
|
|
125
125
|
$ mq mysql auth list
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
_See code: [src/commands/mysql/auth/list.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
128
|
+
_See code: [src/commands/mysql/auth/list.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/auth/list.ts)_
|
|
129
129
|
|
|
130
130
|
## `mq mysql auth profile`
|
|
131
131
|
|
|
@@ -150,7 +150,7 @@ EXAMPLES
|
|
|
150
150
|
$ mq mysql auth profile --default test
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
_See code: [src/commands/mysql/auth/profile.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
153
|
+
_See code: [src/commands/mysql/auth/profile.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/auth/profile.ts)_
|
|
154
154
|
|
|
155
155
|
## `mq mysql auth test`
|
|
156
156
|
|
|
@@ -175,7 +175,7 @@ EXAMPLES
|
|
|
175
175
|
$ mq mysql auth test -p prod
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
_See code: [src/commands/mysql/auth/test.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
178
|
+
_See code: [src/commands/mysql/auth/test.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/auth/test.ts)_
|
|
179
179
|
|
|
180
180
|
## `mq mysql auth update`
|
|
181
181
|
|
|
@@ -207,7 +207,7 @@ EXAMPLES
|
|
|
207
207
|
$ mq mysql auth update -p test
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
-
_See code: [src/commands/mysql/auth/update.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
210
|
+
_See code: [src/commands/mysql/auth/update.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/auth/update.ts)_
|
|
211
211
|
|
|
212
212
|
## `mq mysql databases`
|
|
213
213
|
|
|
@@ -215,11 +215,14 @@ List all databases accessible on the MySQL server
|
|
|
215
215
|
|
|
216
216
|
```
|
|
217
217
|
USAGE
|
|
218
|
-
$ mq mysql databases [-p <value>]
|
|
218
|
+
$ mq mysql databases [--json] [-p <value>]
|
|
219
219
|
|
|
220
220
|
FLAGS
|
|
221
221
|
-p, --profile=<value> Database profile name from config
|
|
222
222
|
|
|
223
|
+
GLOBAL FLAGS
|
|
224
|
+
--json Format output as json.
|
|
225
|
+
|
|
223
226
|
DESCRIPTION
|
|
224
227
|
List all databases accessible on the MySQL server
|
|
225
228
|
|
|
@@ -229,7 +232,7 @@ EXAMPLES
|
|
|
229
232
|
$ mq mysql databases -p staging
|
|
230
233
|
```
|
|
231
234
|
|
|
232
|
-
_See code: [src/commands/mysql/databases.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
235
|
+
_See code: [src/commands/mysql/databases.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/databases.ts)_
|
|
233
236
|
|
|
234
237
|
## `mq mysql describe-table TABLE`
|
|
235
238
|
|
|
@@ -237,15 +240,17 @@ Describe the structure of a MySQL table
|
|
|
237
240
|
|
|
238
241
|
```
|
|
239
242
|
USAGE
|
|
240
|
-
$ mq mysql describe-table TABLE [--
|
|
243
|
+
$ mq mysql describe-table TABLE [--json] [-p <value>] [--toon]
|
|
241
244
|
|
|
242
245
|
ARGUMENTS
|
|
243
246
|
TABLE Table name to describe
|
|
244
247
|
|
|
245
248
|
FLAGS
|
|
246
249
|
-p, --profile=<value> Database profile name from config
|
|
247
|
-
--
|
|
248
|
-
|
|
250
|
+
--toon Format output as toon
|
|
251
|
+
|
|
252
|
+
GLOBAL FLAGS
|
|
253
|
+
--json Format output as json.
|
|
249
254
|
|
|
250
255
|
DESCRIPTION
|
|
251
256
|
Describe the structure of a MySQL table
|
|
@@ -253,37 +258,39 @@ DESCRIPTION
|
|
|
253
258
|
EXAMPLES
|
|
254
259
|
$ mq mysql describe-table users
|
|
255
260
|
|
|
256
|
-
$ mq mysql describe-table orders --
|
|
261
|
+
$ mq mysql describe-table orders --toon -p prod
|
|
257
262
|
```
|
|
258
263
|
|
|
259
|
-
_See code: [src/commands/mysql/describe-table.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
264
|
+
_See code: [src/commands/mysql/describe-table.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/describe-table.ts)_
|
|
260
265
|
|
|
261
|
-
## `mq mysql explain
|
|
266
|
+
## `mq mysql explain QUERY`
|
|
262
267
|
|
|
263
268
|
Show the execution plan for a MySQL query
|
|
264
269
|
|
|
265
270
|
```
|
|
266
271
|
USAGE
|
|
267
|
-
$ mq mysql explain
|
|
272
|
+
$ mq mysql explain QUERY [--json] [-p <value>] [--toon]
|
|
268
273
|
|
|
269
274
|
ARGUMENTS
|
|
270
275
|
QUERY SQL query to explain
|
|
271
276
|
|
|
272
277
|
FLAGS
|
|
273
278
|
-p, --profile=<value> Database profile name from config
|
|
274
|
-
--
|
|
275
|
-
|
|
279
|
+
--toon Format output as toon
|
|
280
|
+
|
|
281
|
+
GLOBAL FLAGS
|
|
282
|
+
--json Format output as json.
|
|
276
283
|
|
|
277
284
|
DESCRIPTION
|
|
278
285
|
Show the execution plan for a MySQL query
|
|
279
286
|
|
|
280
287
|
EXAMPLES
|
|
281
|
-
$ mq mysql explain
|
|
288
|
+
$ mq mysql explain "SELECT * FROM users WHERE id = 1"
|
|
282
289
|
|
|
283
|
-
$ mq mysql explain
|
|
290
|
+
$ mq mysql explain "SELECT * FROM orders JOIN users ON orders.user_id = users.id" --json
|
|
284
291
|
```
|
|
285
292
|
|
|
286
|
-
_See code: [src/commands/mysql/explain
|
|
293
|
+
_See code: [src/commands/mysql/explain.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/explain.ts)_
|
|
287
294
|
|
|
288
295
|
## `mq mysql indexes TABLE`
|
|
289
296
|
|
|
@@ -291,15 +298,17 @@ Show indexes for a MySQL table
|
|
|
291
298
|
|
|
292
299
|
```
|
|
293
300
|
USAGE
|
|
294
|
-
$ mq mysql indexes TABLE [--
|
|
301
|
+
$ mq mysql indexes TABLE [--json] [-p <value>] [--toon]
|
|
295
302
|
|
|
296
303
|
ARGUMENTS
|
|
297
304
|
TABLE Table name to show indexes for
|
|
298
305
|
|
|
299
306
|
FLAGS
|
|
300
307
|
-p, --profile=<value> Database profile name from config
|
|
301
|
-
--
|
|
302
|
-
|
|
308
|
+
--toon Format output as toon
|
|
309
|
+
|
|
310
|
+
GLOBAL FLAGS
|
|
311
|
+
--json Format output as json.
|
|
303
312
|
|
|
304
313
|
DESCRIPTION
|
|
305
314
|
Show indexes for a MySQL table
|
|
@@ -307,10 +316,10 @@ DESCRIPTION
|
|
|
307
316
|
EXAMPLES
|
|
308
317
|
$ mq mysql indexes users
|
|
309
318
|
|
|
310
|
-
$ mq mysql indexes orders --
|
|
319
|
+
$ mq mysql indexes orders --json -p prod
|
|
311
320
|
```
|
|
312
321
|
|
|
313
|
-
_See code: [src/commands/mysql/indexes.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
322
|
+
_See code: [src/commands/mysql/indexes.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/indexes.ts)_
|
|
314
323
|
|
|
315
324
|
## `mq mysql query QUERY`
|
|
316
325
|
|
|
@@ -318,29 +327,31 @@ Execute a SQL query against a MySQL database
|
|
|
318
327
|
|
|
319
328
|
```
|
|
320
329
|
USAGE
|
|
321
|
-
$ mq mysql query QUERY [--
|
|
330
|
+
$ mq mysql query QUERY [--json] [-p <value>] [--skip-confirmation] [--toon]
|
|
322
331
|
|
|
323
332
|
ARGUMENTS
|
|
324
333
|
QUERY SQL query to execute
|
|
325
334
|
|
|
326
335
|
FLAGS
|
|
327
336
|
-p, --profile=<value> Database profile name from config
|
|
328
|
-
--format=<option> [default: table] Output format
|
|
329
|
-
<options: table|json|csv|toon>
|
|
330
337
|
--skip-confirmation Skip confirmation prompt for destructive operations
|
|
338
|
+
--toon Format output as toon
|
|
339
|
+
|
|
340
|
+
GLOBAL FLAGS
|
|
341
|
+
--json Format output as json.
|
|
331
342
|
|
|
332
343
|
DESCRIPTION
|
|
333
344
|
Execute a SQL query against a MySQL database
|
|
334
345
|
|
|
335
346
|
EXAMPLES
|
|
336
|
-
$ mq mysql query "SELECT * FROM users LIMIT 10"
|
|
347
|
+
$ mq mysql query "SELECT * FROM users LIMIT 10" --json
|
|
337
348
|
|
|
338
|
-
$ mq mysql query "UPDATE users SET email = 'user@email.com' WHERE id = 999"
|
|
349
|
+
$ mq mysql query "UPDATE users SET email = 'user@email.com' WHERE id = 999"
|
|
339
350
|
|
|
340
351
|
$ mq mysql query "DELETE FROM sessions" -p prod --skip-confirmation
|
|
341
352
|
```
|
|
342
353
|
|
|
343
|
-
_See code: [src/commands/mysql/query.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
354
|
+
_See code: [src/commands/mysql/query.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/query.ts)_
|
|
344
355
|
|
|
345
356
|
## `mq mysql tables`
|
|
346
357
|
|
|
@@ -348,11 +359,14 @@ List all tables in the current MySQL database
|
|
|
348
359
|
|
|
349
360
|
```
|
|
350
361
|
USAGE
|
|
351
|
-
$ mq mysql tables [-p <value>]
|
|
362
|
+
$ mq mysql tables [--json] [-p <value>]
|
|
352
363
|
|
|
353
364
|
FLAGS
|
|
354
365
|
-p, --profile=<value> Database profile name from config
|
|
355
366
|
|
|
367
|
+
GLOBAL FLAGS
|
|
368
|
+
--json Format output as json.
|
|
369
|
+
|
|
356
370
|
DESCRIPTION
|
|
357
371
|
List all tables in the current MySQL database
|
|
358
372
|
|
|
@@ -362,5 +376,5 @@ EXAMPLES
|
|
|
362
376
|
$ mq mysql tables -p local
|
|
363
377
|
```
|
|
364
378
|
|
|
365
|
-
_See code: [src/commands/mysql/tables.ts](https://github.com/hesedcasa/mysql/blob/v0.5.
|
|
379
|
+
_See code: [src/commands/mysql/tables.ts](https://github.com/hesedcasa/mysql/blob/v0.5.2/src/commands/mysql/tables.ts)_
|
|
366
380
|
<!-- commandsstop -->
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export declare abstract class BaseCommand extends Command {
|
|
3
|
+
static enableJsonFlag: boolean;
|
|
4
|
+
jsonEnabled(): boolean;
|
|
5
|
+
protected parse(options?: any, argv?: string[]): Promise<any>;
|
|
6
|
+
protected parseJsonOutput(output?: string): unknown;
|
|
7
|
+
protected toErrorJson(err: unknown): {
|
|
8
|
+
error: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export class BaseCommand extends Command {
|
|
3
|
+
static enableJsonFlag = true;
|
|
4
|
+
jsonEnabled() {
|
|
5
|
+
const separatorIndex = this.argv.indexOf('--');
|
|
6
|
+
const flagArgs = separatorIndex === -1 ? this.argv : this.argv.slice(0, separatorIndex);
|
|
7
|
+
return flagArgs.includes('--json');
|
|
8
|
+
}
|
|
9
|
+
// oclif sets this.parsed=true only after Parser.parse() returns successfully.
|
|
10
|
+
// When parse() throws (e.g. missing required arg), this.parsed stays false and
|
|
11
|
+
// _run() emits an UnparsedCommand warning. The finally block prevents that.
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
async parse(options, argv) {
|
|
14
|
+
try {
|
|
15
|
+
return await super.parse(options, argv);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
this.parsed = true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
parseJsonOutput(output) {
|
|
22
|
+
if (!output)
|
|
23
|
+
return null;
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(output);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return output;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// oclif's default toErrorJson returns the raw error object which for
|
|
32
|
+
// CLIParseError includes context:this (the full config). Strip it down.
|
|
33
|
+
toErrorJson(err) {
|
|
34
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
35
|
+
return { error: message };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { ApiResult } from '@hesed/plugin-lib';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
3
|
+
export default class MySQLDatabases extends BaseCommand {
|
|
3
4
|
static description: string;
|
|
4
5
|
static examples: string[];
|
|
5
6
|
static flags: {
|
|
6
7
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
};
|
|
8
|
-
run(): Promise<
|
|
9
|
+
run(): Promise<ApiResult>;
|
|
9
10
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
3
|
import { closeConnections, listDatabases } from '../../mysql/index.js';
|
|
3
|
-
export default class MySQLDatabases extends
|
|
4
|
+
export default class MySQLDatabases extends BaseCommand {
|
|
4
5
|
static description = 'List all databases accessible on the MySQL server';
|
|
5
6
|
static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> -p staging'];
|
|
6
7
|
static flags = {
|
|
@@ -11,10 +12,10 @@ export default class MySQLDatabases extends Command {
|
|
|
11
12
|
const result = await listDatabases(this.config, flags.profile);
|
|
12
13
|
await closeConnections();
|
|
13
14
|
if (result.success) {
|
|
14
|
-
this.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this.error(result.error ?? 'Failed to list databases');
|
|
15
|
+
this.log(result.data?.result ?? '');
|
|
16
|
+
delete result.data.result;
|
|
17
|
+
return result;
|
|
18
18
|
}
|
|
19
|
+
this.error(String(result.error ?? 'Failed to list databases'));
|
|
19
20
|
}
|
|
20
21
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { ApiResult } from '@hesed/plugin-lib';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
3
|
+
export default class MySQLDescribeTable extends BaseCommand {
|
|
3
4
|
static args: {
|
|
4
5
|
table: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
6
|
};
|
|
6
7
|
static description: string;
|
|
7
8
|
static examples: string[];
|
|
8
9
|
static flags: {
|
|
9
|
-
format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
toon: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
|
-
run(): Promise<
|
|
13
|
+
run(): Promise<ApiResult>;
|
|
13
14
|
}
|
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
import { Args,
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
3
|
import { closeConnections, describeTable } from '../../mysql/index.js';
|
|
3
|
-
export default class MySQLDescribeTable extends
|
|
4
|
+
export default class MySQLDescribeTable extends BaseCommand {
|
|
4
5
|
static args = {
|
|
5
6
|
table: Args.string({ description: 'Table name to describe', required: true }),
|
|
6
7
|
};
|
|
7
8
|
static description = 'Describe the structure of a MySQL table';
|
|
8
9
|
static examples = [
|
|
9
10
|
'<%= config.bin %> <%= command.id %> users',
|
|
10
|
-
'<%= config.bin %> <%= command.id %> orders --
|
|
11
|
+
'<%= config.bin %> <%= command.id %> orders --toon -p prod',
|
|
11
12
|
];
|
|
12
13
|
static flags = {
|
|
13
|
-
format: Flags.string({
|
|
14
|
-
default: 'table',
|
|
15
|
-
description: 'Output format',
|
|
16
|
-
options: ['table', 'json', 'toon'],
|
|
17
|
-
}),
|
|
18
14
|
profile: Flags.string({ char: 'p', description: 'Database profile name from config', required: false }),
|
|
15
|
+
toon: Flags.boolean({ description: 'Format output as toon', required: false }),
|
|
19
16
|
};
|
|
20
17
|
async run() {
|
|
21
18
|
const { args, flags } = await this.parse(MySQLDescribeTable);
|
|
22
|
-
const result = await describeTable(this.config, args.table, flags.profile, flags.
|
|
19
|
+
const result = await describeTable(this.config, args.table, flags.profile, flags.toon ? 'toon' : flags.json ? 'json' : 'table');
|
|
23
20
|
await closeConnections();
|
|
24
21
|
if (result.success) {
|
|
25
|
-
this.log(result.result ?? '');
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.error(result.error ?? 'Failed to describe table');
|
|
22
|
+
this.log(result.data?.result ?? '');
|
|
23
|
+
delete result.data.result;
|
|
24
|
+
return result;
|
|
29
25
|
}
|
|
26
|
+
this.error(String(result.error ?? 'Failed to describe table'));
|
|
30
27
|
}
|
|
31
28
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { ApiResult } from '@hesed/plugin-lib';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
3
|
+
export default class MySQLExplain extends BaseCommand {
|
|
3
4
|
static args: {
|
|
4
5
|
query: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
6
|
};
|
|
6
7
|
static description: string;
|
|
7
8
|
static examples: string[];
|
|
8
9
|
static flags: {
|
|
9
|
-
format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
toon: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
|
-
run(): Promise<
|
|
13
|
+
run(): Promise<ApiResult>;
|
|
13
14
|
}
|
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
import { Args,
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
3
|
import { closeConnections, explainQuery } from '../../mysql/index.js';
|
|
3
|
-
export default class MySQLExplain extends
|
|
4
|
+
export default class MySQLExplain extends BaseCommand {
|
|
4
5
|
static args = {
|
|
5
6
|
query: Args.string({ description: 'SQL query to explain', required: true }),
|
|
6
7
|
};
|
|
7
8
|
static description = 'Show the execution plan for a MySQL query';
|
|
8
9
|
static examples = [
|
|
9
10
|
'<%= config.bin %> <%= command.id %> "SELECT * FROM users WHERE id = 1"',
|
|
10
|
-
'<%= config.bin %> <%= command.id %> "SELECT * FROM orders JOIN users ON orders.user_id = users.id" --
|
|
11
|
+
'<%= config.bin %> <%= command.id %> "SELECT * FROM orders JOIN users ON orders.user_id = users.id" --json',
|
|
11
12
|
];
|
|
12
13
|
static flags = {
|
|
13
|
-
format: Flags.string({
|
|
14
|
-
default: 'table',
|
|
15
|
-
description: 'Output format',
|
|
16
|
-
options: ['table', 'json', 'toon'],
|
|
17
|
-
}),
|
|
18
14
|
profile: Flags.string({ char: 'p', description: 'Database profile name from config', required: false }),
|
|
15
|
+
toon: Flags.boolean({ description: 'Format output as toon', required: false }),
|
|
19
16
|
};
|
|
20
17
|
async run() {
|
|
21
18
|
const { args, flags } = await this.parse(MySQLExplain);
|
|
22
|
-
const result = await explainQuery(this.config, args.query, flags.profile, flags.
|
|
19
|
+
const result = await explainQuery(this.config, args.query, flags.profile, flags.toon ? 'toon' : flags.json ? 'json' : 'table');
|
|
23
20
|
await closeConnections();
|
|
24
21
|
if (result.success) {
|
|
25
|
-
this.log(result.result ?? '');
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.error(result.error ?? 'Failed to explain query');
|
|
22
|
+
this.log(result.data?.result ?? '');
|
|
23
|
+
delete result.data.result;
|
|
24
|
+
return result;
|
|
29
25
|
}
|
|
26
|
+
this.error(String(result.error ?? 'Failed to explain query'));
|
|
30
27
|
}
|
|
31
28
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { ApiResult } from '@hesed/plugin-lib';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
3
|
+
export default class MySQLIndexes extends BaseCommand {
|
|
3
4
|
static args: {
|
|
4
5
|
table: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
6
|
};
|
|
6
7
|
static description: string;
|
|
7
8
|
static examples: string[];
|
|
8
9
|
static flags: {
|
|
9
|
-
format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
toon: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
|
-
run(): Promise<
|
|
13
|
+
run(): Promise<ApiResult>;
|
|
13
14
|
}
|
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
import { Args,
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
3
|
import { closeConnections, showIndexes } from '../../mysql/index.js';
|
|
3
|
-
export default class MySQLIndexes extends
|
|
4
|
+
export default class MySQLIndexes extends BaseCommand {
|
|
4
5
|
static args = {
|
|
5
6
|
table: Args.string({ description: 'Table name to show indexes for', required: true }),
|
|
6
7
|
};
|
|
7
8
|
static description = 'Show indexes for a MySQL table';
|
|
8
9
|
static examples = [
|
|
9
10
|
'<%= config.bin %> <%= command.id %> users',
|
|
10
|
-
'<%= config.bin %> <%= command.id %> orders --
|
|
11
|
+
'<%= config.bin %> <%= command.id %> orders --json -p prod',
|
|
11
12
|
];
|
|
12
13
|
static flags = {
|
|
13
|
-
format: Flags.string({
|
|
14
|
-
default: 'table',
|
|
15
|
-
description: 'Output format',
|
|
16
|
-
options: ['table', 'json', 'toon'],
|
|
17
|
-
}),
|
|
18
14
|
profile: Flags.string({ char: 'p', description: 'Database profile name from config', required: false }),
|
|
15
|
+
toon: Flags.boolean({ description: 'Format output as toon', required: false }),
|
|
19
16
|
};
|
|
20
17
|
async run() {
|
|
21
18
|
const { args, flags } = await this.parse(MySQLIndexes);
|
|
22
|
-
const result = await showIndexes(this.config, args.table, flags.profile, flags.
|
|
19
|
+
const result = await showIndexes(this.config, args.table, flags.profile, flags.toon ? 'toon' : flags.json ? 'json' : 'table');
|
|
23
20
|
await closeConnections();
|
|
24
21
|
if (result.success) {
|
|
25
|
-
this.log(result.result ?? '');
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.error(result.error ?? 'Failed to show indexes');
|
|
22
|
+
this.log(result.data?.result ?? '');
|
|
23
|
+
delete result.data.result;
|
|
24
|
+
return result;
|
|
29
25
|
}
|
|
26
|
+
this.error(String(result.error ?? 'Failed to show indexes'));
|
|
30
27
|
}
|
|
31
28
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { ApiResult } from '@hesed/plugin-lib';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
3
|
+
export default class MySQLQuery extends BaseCommand {
|
|
3
4
|
static args: {
|
|
4
5
|
query: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
6
|
};
|
|
6
7
|
static description: string;
|
|
7
8
|
static examples: string[];
|
|
8
9
|
static flags: {
|
|
9
|
-
format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
'skip-confirmation': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
toon: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
13
|
};
|
|
13
|
-
run(): Promise<
|
|
14
|
+
run(): Promise<ApiResult>;
|
|
14
15
|
}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { Args,
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
3
|
import { closeConnections, executeQuery } from '../../mysql/index.js';
|
|
3
|
-
export default class MySQLQuery extends
|
|
4
|
+
export default class MySQLQuery extends BaseCommand {
|
|
4
5
|
static args = {
|
|
5
6
|
query: Args.string({ description: 'SQL query to execute', required: true }),
|
|
6
7
|
};
|
|
7
8
|
static description = 'Execute a SQL query against a MySQL database';
|
|
8
9
|
static examples = [
|
|
9
|
-
'<%= config.bin %> <%= command.id %> "SELECT * FROM users LIMIT 10"',
|
|
10
|
-
'<%= config.bin %> <%= command.id %> "UPDATE users SET email = \'user@email.com\' WHERE id = 999"
|
|
10
|
+
'<%= config.bin %> <%= command.id %> "SELECT * FROM users LIMIT 10" --json',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> "UPDATE users SET email = \'user@email.com\' WHERE id = 999"',
|
|
11
12
|
'<%= config.bin %> <%= command.id %> "DELETE FROM sessions" -p prod --skip-confirmation',
|
|
12
13
|
];
|
|
13
14
|
static flags = {
|
|
14
|
-
format: Flags.string({
|
|
15
|
-
default: 'table',
|
|
16
|
-
description: 'Output format',
|
|
17
|
-
options: ['table', 'json', 'csv', 'toon'],
|
|
18
|
-
}),
|
|
19
15
|
profile: Flags.string({ char: 'p', description: 'Database profile name from config', required: false }),
|
|
20
16
|
'skip-confirmation': Flags.boolean({
|
|
21
17
|
default: false,
|
|
22
18
|
description: 'Skip confirmation prompt for destructive operations',
|
|
23
19
|
}),
|
|
20
|
+
toon: Flags.boolean({ description: 'Format output as toon', required: false }),
|
|
24
21
|
};
|
|
25
22
|
async run() {
|
|
26
23
|
const { args, flags } = await this.parse(MySQLQuery);
|
|
27
|
-
const result = await executeQuery(this.config, args.query, flags.profile, flags.
|
|
24
|
+
const result = await executeQuery(this.config, args.query, flags.profile, flags.toon ? 'toon' : flags.json ? 'json' : 'table', flags['skip-confirmation']);
|
|
28
25
|
await closeConnections();
|
|
29
26
|
if (result.success) {
|
|
30
27
|
// Notices (warnings, row counts) go to stderr so machine-readable formats
|
|
31
28
|
// leave stdout as clean, parseable data.
|
|
32
|
-
if (result.notices)
|
|
33
|
-
this.logToStderr(result.notices);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
if (result.data?.notices)
|
|
30
|
+
this.logToStderr(result.data.notices);
|
|
31
|
+
// result is a formatted string for human/csv/toon output; for --json it
|
|
32
|
+
// holds the parsed payload, but jsonEnabled() suppresses log() in that case.
|
|
33
|
+
this.log(typeof result.data?.result === 'string' ? result.data.result : '');
|
|
34
|
+
delete result.data.notices;
|
|
35
|
+
return result;
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
this.
|
|
37
|
+
if (result.data?.requiresConfirmation) {
|
|
38
|
+
this.log(`${result.data?.message ?? 'Destructive operation requires confirmation.'}\nRe-run with --skip-confirmation to proceed.`);
|
|
39
|
+
return result;
|
|
41
40
|
}
|
|
41
|
+
this.error(String(result.error ?? 'Query failed'));
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { ApiResult } from '@hesed/plugin-lib';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
3
|
+
export default class MySQLTables extends BaseCommand {
|
|
3
4
|
static description: string;
|
|
4
5
|
static examples: string[];
|
|
5
6
|
static flags: {
|
|
6
7
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
};
|
|
8
|
-
run(): Promise<
|
|
9
|
+
run(): Promise<ApiResult>;
|
|
9
10
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
3
|
import { closeConnections, listTables } from '../../mysql/index.js';
|
|
3
|
-
export default class MySQLTables extends
|
|
4
|
+
export default class MySQLTables extends BaseCommand {
|
|
4
5
|
static description = 'List all tables in the current MySQL database';
|
|
5
6
|
static examples = ['<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> -p local'];
|
|
6
7
|
static flags = {
|
|
@@ -11,10 +12,10 @@ export default class MySQLTables extends Command {
|
|
|
11
12
|
const result = await listTables(this.config, flags.profile);
|
|
12
13
|
await closeConnections();
|
|
13
14
|
if (result.success) {
|
|
14
|
-
this.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this.error(result.error ?? 'Failed to list tables');
|
|
15
|
+
this.log(result.data?.result ?? '');
|
|
16
|
+
delete result.data.result;
|
|
17
|
+
return result;
|
|
18
18
|
}
|
|
19
|
+
this.error(String(result.error ?? 'Failed to list tables'));
|
|
19
20
|
}
|
|
20
21
|
}
|
package/dist/mysql/database.d.ts
CHANGED
|
@@ -1,49 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import type { ApiResult } from '@hesed/plugin-lib';
|
|
2
|
+
export type OutputFormat = 'csv' | 'json' | 'table' | 'toon';
|
|
3
|
+
export interface QueryData {
|
|
3
4
|
message?: string;
|
|
4
5
|
notices?: string;
|
|
5
6
|
requiresConfirmation?: boolean;
|
|
6
|
-
result?:
|
|
7
|
-
success: boolean;
|
|
7
|
+
result?: unknown;
|
|
8
8
|
}
|
|
9
|
-
export interface
|
|
10
|
-
databases
|
|
11
|
-
error?: string;
|
|
9
|
+
export interface DatabaseListData {
|
|
10
|
+
databases: string[];
|
|
12
11
|
result?: string;
|
|
13
|
-
success: boolean;
|
|
14
12
|
}
|
|
15
|
-
export interface
|
|
16
|
-
error?: string;
|
|
13
|
+
export interface TableListData {
|
|
17
14
|
result?: string;
|
|
18
|
-
|
|
19
|
-
tables?: string[];
|
|
15
|
+
tables: string[];
|
|
20
16
|
}
|
|
21
|
-
export interface
|
|
22
|
-
error?: string;
|
|
17
|
+
export interface TableStructureData {
|
|
23
18
|
result?: string;
|
|
24
|
-
structure
|
|
25
|
-
success: boolean;
|
|
19
|
+
structure: Record<string, unknown>[];
|
|
26
20
|
}
|
|
27
|
-
export interface
|
|
28
|
-
|
|
29
|
-
indexes?: Record<string, unknown>[];
|
|
21
|
+
export interface IndexData {
|
|
22
|
+
indexes: Record<string, unknown>[];
|
|
30
23
|
result?: string;
|
|
31
|
-
success: boolean;
|
|
32
24
|
}
|
|
33
|
-
export interface
|
|
34
|
-
|
|
35
|
-
plan?: Record<string, unknown>[];
|
|
25
|
+
export interface ExplainData {
|
|
26
|
+
plan: Record<string, unknown>[];
|
|
36
27
|
result?: string;
|
|
37
|
-
success: boolean;
|
|
38
28
|
}
|
|
39
|
-
|
|
40
|
-
database
|
|
41
|
-
error?: string;
|
|
29
|
+
interface ConnectionTestData {
|
|
30
|
+
database: string;
|
|
42
31
|
result?: string;
|
|
43
|
-
|
|
44
|
-
version?: string;
|
|
32
|
+
version: string;
|
|
45
33
|
}
|
|
46
|
-
export type
|
|
34
|
+
export type QueryResult = ApiResult & {
|
|
35
|
+
data?: QueryData;
|
|
36
|
+
};
|
|
37
|
+
export type DatabaseListResult = ApiResult & {
|
|
38
|
+
data?: DatabaseListData;
|
|
39
|
+
};
|
|
40
|
+
export type TableListResult = ApiResult & {
|
|
41
|
+
data?: TableListData;
|
|
42
|
+
};
|
|
43
|
+
export type TableStructureResult = ApiResult & {
|
|
44
|
+
data?: TableStructureData;
|
|
45
|
+
};
|
|
46
|
+
export type IndexResult = ApiResult & {
|
|
47
|
+
data?: IndexData;
|
|
48
|
+
};
|
|
49
|
+
export type ExplainResult = ApiResult & {
|
|
50
|
+
data?: ExplainData;
|
|
51
|
+
};
|
|
52
|
+
export type ConnectionTestResult = ApiResult & {
|
|
53
|
+
data?: ConnectionTestData;
|
|
54
|
+
};
|
|
47
55
|
export interface DatabaseUtil {
|
|
48
56
|
closeAll(): Promise<void>;
|
|
49
57
|
describeTable(profileName: string, table: string, format?: OutputFormat): Promise<TableStructureResult>;
|
|
@@ -53,3 +61,4 @@ export interface DatabaseUtil {
|
|
|
53
61
|
listTables(profileName: string): Promise<TableListResult>;
|
|
54
62
|
showIndexes(profileName: string, table: string, format?: OutputFormat): Promise<IndexResult>;
|
|
55
63
|
}
|
|
64
|
+
export {};
|
|
@@ -19,8 +19,10 @@ export class MySQLUtil {
|
|
|
19
19
|
const connection = await this.getConnection(profileName);
|
|
20
20
|
const [rows, fields] = await connection.query(`DESCRIBE ${table}`);
|
|
21
21
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
data: {
|
|
23
|
+
result: this.formatRows(rows, fields, format),
|
|
24
|
+
structure: rows,
|
|
25
|
+
},
|
|
24
26
|
success: true,
|
|
25
27
|
};
|
|
26
28
|
}
|
|
@@ -44,8 +46,10 @@ export class MySQLUtil {
|
|
|
44
46
|
const confirmationCheck = requiresConfirmation(query, this.config.safety.requireConfirmationFor);
|
|
45
47
|
if (confirmationCheck.required) {
|
|
46
48
|
return {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
data: {
|
|
50
|
+
message: `${confirmationCheck.message}\nQuery: ${query}`,
|
|
51
|
+
requiresConfirmation: true,
|
|
52
|
+
},
|
|
49
53
|
success: false,
|
|
50
54
|
};
|
|
51
55
|
}
|
|
@@ -71,15 +75,20 @@ export class MySQLUtil {
|
|
|
71
75
|
const connection = await this.getConnection(profileName);
|
|
72
76
|
const [rows, fields] = await connection.query(finalQuery);
|
|
73
77
|
const isRead = queryType === 'SELECT' || queryType === 'SHOW' || queryType === 'DESCRIBE' || queryType === 'EXPLAIN';
|
|
74
|
-
|
|
78
|
+
let data = isRead
|
|
75
79
|
? this.formatReadResult(rows, fields, format, notices)
|
|
76
|
-
: this.formatWriteResult(rows, notices);
|
|
80
|
+
: this.formatWriteResult(rows, notices, format);
|
|
81
|
+
if (format === 'json') {
|
|
82
|
+
data = JSON.parse(data);
|
|
83
|
+
}
|
|
77
84
|
const notice = notices.join('\n\n');
|
|
78
85
|
// For human (table) output everything stays on stdout, exactly as before.
|
|
79
86
|
// For machine formats the data is returned alone and notices go to stderr.
|
|
80
87
|
return {
|
|
81
|
-
|
|
82
|
-
|
|
88
|
+
data: {
|
|
89
|
+
notices: machineFormat ? notice : undefined,
|
|
90
|
+
result: machineFormat ? data : `${notice}\n\n${data}`,
|
|
91
|
+
},
|
|
83
92
|
success: true,
|
|
84
93
|
};
|
|
85
94
|
}
|
|
@@ -96,8 +105,10 @@ export class MySQLUtil {
|
|
|
96
105
|
const connection = await this.getConnection(profileName);
|
|
97
106
|
const [rows, fields] = await connection.query(`EXPLAIN ${query}`);
|
|
98
107
|
return {
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
data: {
|
|
109
|
+
plan: rows,
|
|
110
|
+
result: this.formatRows(rows, fields, format),
|
|
111
|
+
},
|
|
101
112
|
success: true,
|
|
102
113
|
};
|
|
103
114
|
}
|
|
@@ -115,8 +126,10 @@ export class MySQLUtil {
|
|
|
115
126
|
const [rows] = await connection.query('SHOW DATABASES');
|
|
116
127
|
const databases = rows.map((row) => row.Database);
|
|
117
128
|
return {
|
|
118
|
-
|
|
119
|
-
|
|
129
|
+
data: {
|
|
130
|
+
databases,
|
|
131
|
+
result: `Databases:\n${databases.map((db) => ` • ${db}`).join('\n')}`,
|
|
132
|
+
},
|
|
120
133
|
success: true,
|
|
121
134
|
};
|
|
122
135
|
}
|
|
@@ -136,9 +149,11 @@ export class MySQLUtil {
|
|
|
136
149
|
const tableKey = Object.keys(rowsArray[0])[0];
|
|
137
150
|
const tables = rowsArray.map((row) => row[tableKey]);
|
|
138
151
|
return {
|
|
139
|
-
|
|
152
|
+
data: {
|
|
153
|
+
result: `Tables in database:\n${tables.map((table) => ` • ${table}`).join('\n')}`,
|
|
154
|
+
tables,
|
|
155
|
+
},
|
|
140
156
|
success: true,
|
|
141
|
-
tables,
|
|
142
157
|
};
|
|
143
158
|
}
|
|
144
159
|
catch (error) {
|
|
@@ -154,8 +169,10 @@ export class MySQLUtil {
|
|
|
154
169
|
const connection = await this.getConnection(profileName);
|
|
155
170
|
const [rows, fields] = await connection.query(`SHOW INDEXES FROM ${table}`);
|
|
156
171
|
return {
|
|
157
|
-
|
|
158
|
-
|
|
172
|
+
data: {
|
|
173
|
+
indexes: rows,
|
|
174
|
+
result: this.formatRows(rows, fields, format),
|
|
175
|
+
},
|
|
159
176
|
success: true,
|
|
160
177
|
};
|
|
161
178
|
}
|
|
@@ -173,10 +190,12 @@ export class MySQLUtil {
|
|
|
173
190
|
const [rows] = await connection.query('SELECT VERSION() as version, DATABASE() as current_database');
|
|
174
191
|
const info = rows[0];
|
|
175
192
|
return {
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
data: {
|
|
194
|
+
database: info.current_database,
|
|
195
|
+
result: `Connection successful!\n\nProfile: ${profileName}\nMySQL Version: ${info.version}\nCurrent Database: ${info.current_database}`,
|
|
196
|
+
version: info.version,
|
|
197
|
+
},
|
|
178
198
|
success: true,
|
|
179
|
-
version: info.version,
|
|
180
199
|
};
|
|
181
200
|
}
|
|
182
201
|
catch (error) {
|
|
@@ -195,10 +214,18 @@ export class MySQLUtil {
|
|
|
195
214
|
formatRows(rows, fields, format) {
|
|
196
215
|
return FORMATTERS[format](rows, fields);
|
|
197
216
|
}
|
|
198
|
-
formatWriteResult(rows, notices) {
|
|
217
|
+
formatWriteResult(rows, notices, format) {
|
|
199
218
|
const affectedRows = rows.affectedRows ?? 0;
|
|
200
219
|
const insertId = rows.insertId ?? null;
|
|
201
220
|
notices.push('Query executed successfully.');
|
|
221
|
+
// The caller JSON.parses the result for json output, so emit valid JSON
|
|
222
|
+
// here rather than the human-readable string (which would throw on parse).
|
|
223
|
+
if (format === 'json') {
|
|
224
|
+
const payload = { affectedRows };
|
|
225
|
+
if (insertId)
|
|
226
|
+
payload.insertId = insertId;
|
|
227
|
+
return JSON.stringify(payload, null, 2);
|
|
228
|
+
}
|
|
202
229
|
let data = `Affected rows: ${affectedRows}\n`;
|
|
203
230
|
if (insertId)
|
|
204
231
|
data += `Insert ID: ${insertId}\n`;
|
package/oclif.manifest.json
CHANGED
|
@@ -9,6 +9,13 @@
|
|
|
9
9
|
"<%= config.bin %> <%= command.id %> -p staging"
|
|
10
10
|
],
|
|
11
11
|
"flags": {
|
|
12
|
+
"json": {
|
|
13
|
+
"description": "Format output as json.",
|
|
14
|
+
"helpGroup": "GLOBAL",
|
|
15
|
+
"name": "json",
|
|
16
|
+
"allowNo": false,
|
|
17
|
+
"type": "boolean"
|
|
18
|
+
},
|
|
12
19
|
"profile": {
|
|
13
20
|
"char": "p",
|
|
14
21
|
"description": "Database profile name from config",
|
|
@@ -26,7 +33,7 @@
|
|
|
26
33
|
"pluginName": "@hesed/mysql",
|
|
27
34
|
"pluginType": "core",
|
|
28
35
|
"strict": true,
|
|
29
|
-
"enableJsonFlag":
|
|
36
|
+
"enableJsonFlag": true,
|
|
30
37
|
"isESM": true,
|
|
31
38
|
"relativePath": [
|
|
32
39
|
"dist",
|
|
@@ -47,21 +54,15 @@
|
|
|
47
54
|
"description": "Describe the structure of a MySQL table",
|
|
48
55
|
"examples": [
|
|
49
56
|
"<%= config.bin %> <%= command.id %> users",
|
|
50
|
-
"<%= config.bin %> <%= command.id %> orders --
|
|
57
|
+
"<%= config.bin %> <%= command.id %> orders --toon -p prod"
|
|
51
58
|
],
|
|
52
59
|
"flags": {
|
|
53
|
-
"
|
|
54
|
-
"description": "
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"options": [
|
|
60
|
-
"table",
|
|
61
|
-
"json",
|
|
62
|
-
"toon"
|
|
63
|
-
],
|
|
64
|
-
"type": "option"
|
|
60
|
+
"json": {
|
|
61
|
+
"description": "Format output as json.",
|
|
62
|
+
"helpGroup": "GLOBAL",
|
|
63
|
+
"name": "json",
|
|
64
|
+
"allowNo": false,
|
|
65
|
+
"type": "boolean"
|
|
65
66
|
},
|
|
66
67
|
"profile": {
|
|
67
68
|
"char": "p",
|
|
@@ -71,6 +72,13 @@
|
|
|
71
72
|
"hasDynamicHelp": false,
|
|
72
73
|
"multiple": false,
|
|
73
74
|
"type": "option"
|
|
75
|
+
},
|
|
76
|
+
"toon": {
|
|
77
|
+
"description": "Format output as toon",
|
|
78
|
+
"name": "toon",
|
|
79
|
+
"required": false,
|
|
80
|
+
"allowNo": false,
|
|
81
|
+
"type": "boolean"
|
|
74
82
|
}
|
|
75
83
|
},
|
|
76
84
|
"hasDynamicHelp": false,
|
|
@@ -80,7 +88,7 @@
|
|
|
80
88
|
"pluginName": "@hesed/mysql",
|
|
81
89
|
"pluginType": "core",
|
|
82
90
|
"strict": true,
|
|
83
|
-
"enableJsonFlag":
|
|
91
|
+
"enableJsonFlag": true,
|
|
84
92
|
"isESM": true,
|
|
85
93
|
"relativePath": [
|
|
86
94
|
"dist",
|
|
@@ -89,7 +97,7 @@
|
|
|
89
97
|
"describe-table.js"
|
|
90
98
|
]
|
|
91
99
|
},
|
|
92
|
-
"mysql:explain
|
|
100
|
+
"mysql:explain": {
|
|
93
101
|
"aliases": [],
|
|
94
102
|
"args": {
|
|
95
103
|
"query": {
|
|
@@ -101,21 +109,15 @@
|
|
|
101
109
|
"description": "Show the execution plan for a MySQL query",
|
|
102
110
|
"examples": [
|
|
103
111
|
"<%= config.bin %> <%= command.id %> \"SELECT * FROM users WHERE id = 1\"",
|
|
104
|
-
"<%= config.bin %> <%= command.id %> \"SELECT * FROM orders JOIN users ON orders.user_id = users.id\" --
|
|
112
|
+
"<%= config.bin %> <%= command.id %> \"SELECT * FROM orders JOIN users ON orders.user_id = users.id\" --json"
|
|
105
113
|
],
|
|
106
114
|
"flags": {
|
|
107
|
-
"
|
|
108
|
-
"description": "
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"options": [
|
|
114
|
-
"table",
|
|
115
|
-
"json",
|
|
116
|
-
"toon"
|
|
117
|
-
],
|
|
118
|
-
"type": "option"
|
|
115
|
+
"json": {
|
|
116
|
+
"description": "Format output as json.",
|
|
117
|
+
"helpGroup": "GLOBAL",
|
|
118
|
+
"name": "json",
|
|
119
|
+
"allowNo": false,
|
|
120
|
+
"type": "boolean"
|
|
119
121
|
},
|
|
120
122
|
"profile": {
|
|
121
123
|
"char": "p",
|
|
@@ -125,22 +127,29 @@
|
|
|
125
127
|
"hasDynamicHelp": false,
|
|
126
128
|
"multiple": false,
|
|
127
129
|
"type": "option"
|
|
130
|
+
},
|
|
131
|
+
"toon": {
|
|
132
|
+
"description": "Format output as toon",
|
|
133
|
+
"name": "toon",
|
|
134
|
+
"required": false,
|
|
135
|
+
"allowNo": false,
|
|
136
|
+
"type": "boolean"
|
|
128
137
|
}
|
|
129
138
|
},
|
|
130
139
|
"hasDynamicHelp": false,
|
|
131
140
|
"hiddenAliases": [],
|
|
132
|
-
"id": "mysql:explain
|
|
141
|
+
"id": "mysql:explain",
|
|
133
142
|
"pluginAlias": "@hesed/mysql",
|
|
134
143
|
"pluginName": "@hesed/mysql",
|
|
135
144
|
"pluginType": "core",
|
|
136
145
|
"strict": true,
|
|
137
|
-
"enableJsonFlag":
|
|
146
|
+
"enableJsonFlag": true,
|
|
138
147
|
"isESM": true,
|
|
139
148
|
"relativePath": [
|
|
140
149
|
"dist",
|
|
141
150
|
"commands",
|
|
142
151
|
"mysql",
|
|
143
|
-
"explain
|
|
152
|
+
"explain.js"
|
|
144
153
|
]
|
|
145
154
|
},
|
|
146
155
|
"mysql:indexes": {
|
|
@@ -155,21 +164,15 @@
|
|
|
155
164
|
"description": "Show indexes for a MySQL table",
|
|
156
165
|
"examples": [
|
|
157
166
|
"<%= config.bin %> <%= command.id %> users",
|
|
158
|
-
"<%= config.bin %> <%= command.id %> orders --
|
|
167
|
+
"<%= config.bin %> <%= command.id %> orders --json -p prod"
|
|
159
168
|
],
|
|
160
169
|
"flags": {
|
|
161
|
-
"
|
|
162
|
-
"description": "
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"options": [
|
|
168
|
-
"table",
|
|
169
|
-
"json",
|
|
170
|
-
"toon"
|
|
171
|
-
],
|
|
172
|
-
"type": "option"
|
|
170
|
+
"json": {
|
|
171
|
+
"description": "Format output as json.",
|
|
172
|
+
"helpGroup": "GLOBAL",
|
|
173
|
+
"name": "json",
|
|
174
|
+
"allowNo": false,
|
|
175
|
+
"type": "boolean"
|
|
173
176
|
},
|
|
174
177
|
"profile": {
|
|
175
178
|
"char": "p",
|
|
@@ -179,6 +182,13 @@
|
|
|
179
182
|
"hasDynamicHelp": false,
|
|
180
183
|
"multiple": false,
|
|
181
184
|
"type": "option"
|
|
185
|
+
},
|
|
186
|
+
"toon": {
|
|
187
|
+
"description": "Format output as toon",
|
|
188
|
+
"name": "toon",
|
|
189
|
+
"required": false,
|
|
190
|
+
"allowNo": false,
|
|
191
|
+
"type": "boolean"
|
|
182
192
|
}
|
|
183
193
|
},
|
|
184
194
|
"hasDynamicHelp": false,
|
|
@@ -188,7 +198,7 @@
|
|
|
188
198
|
"pluginName": "@hesed/mysql",
|
|
189
199
|
"pluginType": "core",
|
|
190
200
|
"strict": true,
|
|
191
|
-
"enableJsonFlag":
|
|
201
|
+
"enableJsonFlag": true,
|
|
192
202
|
"isESM": true,
|
|
193
203
|
"relativePath": [
|
|
194
204
|
"dist",
|
|
@@ -208,24 +218,17 @@
|
|
|
208
218
|
},
|
|
209
219
|
"description": "Execute a SQL query against a MySQL database",
|
|
210
220
|
"examples": [
|
|
211
|
-
"<%= config.bin %> <%= command.id %> \"SELECT * FROM users LIMIT 10\"",
|
|
212
|
-
"<%= config.bin %> <%= command.id %> \"UPDATE users SET email = 'user@email.com' WHERE id = 999\"
|
|
221
|
+
"<%= config.bin %> <%= command.id %> \"SELECT * FROM users LIMIT 10\" --json",
|
|
222
|
+
"<%= config.bin %> <%= command.id %> \"UPDATE users SET email = 'user@email.com' WHERE id = 999\"",
|
|
213
223
|
"<%= config.bin %> <%= command.id %> \"DELETE FROM sessions\" -p prod --skip-confirmation"
|
|
214
224
|
],
|
|
215
225
|
"flags": {
|
|
216
|
-
"
|
|
217
|
-
"description": "
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"options": [
|
|
223
|
-
"table",
|
|
224
|
-
"json",
|
|
225
|
-
"csv",
|
|
226
|
-
"toon"
|
|
227
|
-
],
|
|
228
|
-
"type": "option"
|
|
226
|
+
"json": {
|
|
227
|
+
"description": "Format output as json.",
|
|
228
|
+
"helpGroup": "GLOBAL",
|
|
229
|
+
"name": "json",
|
|
230
|
+
"allowNo": false,
|
|
231
|
+
"type": "boolean"
|
|
229
232
|
},
|
|
230
233
|
"profile": {
|
|
231
234
|
"char": "p",
|
|
@@ -241,6 +244,13 @@
|
|
|
241
244
|
"name": "skip-confirmation",
|
|
242
245
|
"allowNo": false,
|
|
243
246
|
"type": "boolean"
|
|
247
|
+
},
|
|
248
|
+
"toon": {
|
|
249
|
+
"description": "Format output as toon",
|
|
250
|
+
"name": "toon",
|
|
251
|
+
"required": false,
|
|
252
|
+
"allowNo": false,
|
|
253
|
+
"type": "boolean"
|
|
244
254
|
}
|
|
245
255
|
},
|
|
246
256
|
"hasDynamicHelp": false,
|
|
@@ -250,7 +260,7 @@
|
|
|
250
260
|
"pluginName": "@hesed/mysql",
|
|
251
261
|
"pluginType": "core",
|
|
252
262
|
"strict": true,
|
|
253
|
-
"enableJsonFlag":
|
|
263
|
+
"enableJsonFlag": true,
|
|
254
264
|
"isESM": true,
|
|
255
265
|
"relativePath": [
|
|
256
266
|
"dist",
|
|
@@ -268,6 +278,13 @@
|
|
|
268
278
|
"<%= config.bin %> <%= command.id %> -p local"
|
|
269
279
|
],
|
|
270
280
|
"flags": {
|
|
281
|
+
"json": {
|
|
282
|
+
"description": "Format output as json.",
|
|
283
|
+
"helpGroup": "GLOBAL",
|
|
284
|
+
"name": "json",
|
|
285
|
+
"allowNo": false,
|
|
286
|
+
"type": "boolean"
|
|
287
|
+
},
|
|
271
288
|
"profile": {
|
|
272
289
|
"char": "p",
|
|
273
290
|
"description": "Database profile name from config",
|
|
@@ -285,7 +302,7 @@
|
|
|
285
302
|
"pluginName": "@hesed/mysql",
|
|
286
303
|
"pluginType": "core",
|
|
287
304
|
"strict": true,
|
|
288
|
-
"enableJsonFlag":
|
|
305
|
+
"enableJsonFlag": true,
|
|
289
306
|
"isESM": true,
|
|
290
307
|
"relativePath": [
|
|
291
308
|
"dist",
|
|
@@ -640,5 +657,5 @@
|
|
|
640
657
|
]
|
|
641
658
|
}
|
|
642
659
|
},
|
|
643
|
-
"version": "0.5.
|
|
660
|
+
"version": "0.5.2"
|
|
644
661
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hesed/mysql",
|
|
3
3
|
"description": "CLI for MySQL database interaction",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.2",
|
|
5
5
|
"author": "Hesed",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mq": "./bin/run.js"
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
],
|
|
50
50
|
"homepage": "https://github.com/hesedcasa/mysql",
|
|
51
51
|
"keywords": [
|
|
52
|
-
"
|
|
52
|
+
"mysql"
|
|
53
53
|
],
|
|
54
54
|
"license": "Apache-2.0",
|
|
55
55
|
"main": "dist/index.js",
|