@hesed/mysql 0.2.2 → 0.4.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.
Files changed (37) hide show
  1. package/README.md +107 -32
  2. package/dist/commands/mysql/auth/add.d.ts +2 -18
  3. package/dist/commands/mysql/auth/add.js +17 -57
  4. package/dist/commands/mysql/auth/delete.d.ts +2 -0
  5. package/dist/commands/mysql/auth/delete.js +2 -0
  6. package/dist/commands/mysql/auth/list.d.ts +2 -0
  7. package/dist/commands/mysql/auth/list.js +2 -0
  8. package/dist/commands/mysql/auth/profile.d.ts +2 -0
  9. package/dist/commands/mysql/auth/profile.js +2 -0
  10. package/dist/commands/mysql/auth/test.d.ts +2 -12
  11. package/dist/commands/mysql/auth/test.js +17 -41
  12. package/dist/commands/mysql/auth/update.d.ts +2 -18
  13. package/dist/commands/mysql/auth/update.js +17 -74
  14. package/dist/commands/mysql/databases.js +2 -10
  15. package/dist/commands/mysql/describe-table.js +2 -10
  16. package/dist/commands/mysql/explain-query.js +2 -10
  17. package/dist/commands/mysql/indexes.js +2 -10
  18. package/dist/commands/mysql/query.js +2 -10
  19. package/dist/commands/mysql/tables.js +2 -10
  20. package/dist/mysql/config-loader.d.ts +8 -17
  21. package/dist/mysql/config-loader.js +0 -7
  22. package/dist/mysql/database.d.ts +0 -31
  23. package/dist/mysql/database.js +0 -4
  24. package/dist/mysql/formatters.d.ts +5 -0
  25. package/dist/mysql/formatters.js +76 -0
  26. package/dist/mysql/index.d.ts +1 -3
  27. package/dist/mysql/index.js +1 -1
  28. package/dist/mysql/mysql-client.d.ts +8 -57
  29. package/dist/mysql/mysql-client.js +44 -101
  30. package/dist/mysql/mysql-utils.d.ts +1 -51
  31. package/dist/mysql/mysql-utils.js +8 -168
  32. package/dist/mysql/query-validator.d.ts +0 -19
  33. package/dist/mysql/query-validator.js +0 -19
  34. package/oclif.manifest.json +176 -59
  35. package/package.json +3 -2
  36. package/dist/config.d.ts +0 -13
  37. package/dist/config.js +0 -18
@@ -1,11 +1,7 @@
1
- import { encode } from '@toon-format/toon';
2
1
  import mysql from 'mysql2/promise';
3
2
  import { getMySQLConnectionOptions } from './config-loader.js';
3
+ import { FORMATTERS } from './formatters.js';
4
4
  import { analyzeQuery, applyDefaultLimit, checkBlacklist, getQueryType, requiresConfirmation } from './query-validator.js';
5
- /**
6
- * MySQL Database Utility
7
- * Provides core database operations with safety validation and formatting
8
- */
9
5
  export class MySQLUtil {
10
6
  config;
11
7
  connections;
@@ -13,33 +9,17 @@ export class MySQLUtil {
13
9
  this.config = config;
14
10
  this.connections = new Map();
15
11
  }
16
- /**
17
- * Close all connections
18
- */
19
12
  async closeAll() {
20
13
  const entries = [...this.connections.values()];
21
14
  this.connections.clear();
22
15
  await Promise.allSettled(entries.map(async (connPromise) => (await connPromise).end()));
23
16
  }
24
- /**
25
- * Describe table structure
26
- */
27
17
  async describeTable(profileName, table, format = 'table') {
28
18
  try {
29
19
  const connection = await this.getConnection(profileName);
30
20
  const [rows, fields] = await connection.query(`DESCRIBE ${table}`);
31
- let result = '';
32
- if (format === 'json') {
33
- result += this.formatAsJson(rows);
34
- }
35
- else if (format === 'toon') {
36
- result += this.formatAsToon(rows);
37
- }
38
- else {
39
- result += this.formatAsTable(rows, fields);
40
- }
41
21
  return {
42
- result,
22
+ result: this.formatRows(rows, fields, format),
43
23
  structure: rows,
44
24
  success: true,
45
25
  };
@@ -52,9 +32,6 @@ export class MySQLUtil {
52
32
  };
53
33
  }
54
34
  }
55
- /**
56
- * Validate and execute a SQL query
57
- */
58
35
  async executeQuery(profileName, query, format = 'table', skipConfirmation = false) {
59
36
  const blacklistCheck = checkBlacklist(query, this.config.safety.blacklistedOperations);
60
37
  if (!blacklistCheck.allowed) {
@@ -119,26 +96,13 @@ export class MySQLUtil {
119
96
  };
120
97
  }
121
98
  }
122
- /**
123
- * Explain query execution plan
124
- */
125
99
  async explainQuery(profileName, query, format = 'table') {
126
100
  try {
127
101
  const connection = await this.getConnection(profileName);
128
102
  const [rows, fields] = await connection.query(`EXPLAIN ${query}`);
129
- let result = '';
130
- if (format === 'json') {
131
- result += this.formatAsJson(rows);
132
- }
133
- else if (format === 'toon') {
134
- result += this.formatAsToon(rows);
135
- }
136
- else {
137
- result += this.formatAsTable(rows, fields);
138
- }
139
103
  return {
140
104
  plan: rows,
141
- result,
105
+ result: this.formatRows(rows, fields, format),
142
106
  success: true,
143
107
  };
144
108
  }
@@ -150,90 +114,6 @@ export class MySQLUtil {
150
114
  };
151
115
  }
152
116
  }
153
- /**
154
- * Format query results as CSV
155
- */
156
- formatAsCsv(rows, fields) {
157
- if (!rows || rows.length === 0) {
158
- return '';
159
- }
160
- const columnNames = fields.map((f) => f.name);
161
- let csv = columnNames.join(',') + '\n';
162
- for (const row of rows) {
163
- const values = columnNames.map((name) => {
164
- const value = row[name] ?? '';
165
- const str = String(value);
166
- if (str.includes(',') || str.includes('"') || str.includes('\n')) {
167
- return '"' + str.replaceAll('"', '""') + '"';
168
- }
169
- return str;
170
- });
171
- csv += values.join(',') + '\n';
172
- }
173
- return csv;
174
- }
175
- /**
176
- * Format query results as JSON
177
- */
178
- formatAsJson(rows) {
179
- return JSON.stringify(rows, null, 2);
180
- }
181
- /**
182
- * Format query results as table
183
- */
184
- formatAsTable(rows, fields) {
185
- if (!rows || rows.length === 0) {
186
- return 'No results';
187
- }
188
- const columnNames = fields.map((f) => f.name);
189
- const columnWidths = columnNames.map((name) => {
190
- const dataWidth = Math.max(...rows.map((row) => String(row[name] ?? '').length));
191
- return Math.max(name.length, dataWidth, 3);
192
- });
193
- let table = '┌' + columnWidths.map((w) => '─'.repeat(w + 2)).join('┬') + '┐\n';
194
- table += '│ ' + columnNames.map((name, i) => name.padEnd(columnWidths[i])).join(' │ ') + ' │\n';
195
- table += '├' + columnWidths.map((w) => '─'.repeat(w + 2)).join('┼') + '┤\n';
196
- for (const row of rows) {
197
- table +=
198
- '│ ' +
199
- columnNames
200
- .map((name, i) => {
201
- const value = row[name] ?? 'NULL';
202
- return String(value).padEnd(columnWidths[i]);
203
- })
204
- .join(' │ ') +
205
- ' │\n';
206
- }
207
- table += '└' + columnWidths.map((w) => '─'.repeat(w + 2)).join('┴') + '┘';
208
- return table;
209
- }
210
- /**
211
- * Format query results as TOON
212
- */
213
- formatAsToon(rows) {
214
- if (!rows || rows.length === 0) {
215
- return '';
216
- }
217
- const serializedRows = rows.map((row) => {
218
- const serialized = {};
219
- for (const [key, value] of Object.entries(row)) {
220
- if (value instanceof Date) {
221
- serialized[key] = Number.isNaN(value.getTime()) ? null : value.toISOString();
222
- }
223
- else if (Buffer.isBuffer(value)) {
224
- serialized[key] = value.toString('base64');
225
- }
226
- else {
227
- serialized[key] = value;
228
- }
229
- }
230
- return serialized;
231
- });
232
- return encode(serializedRows);
233
- }
234
- /**
235
- * List all databases
236
- */
237
117
  async listDatabases(profileName) {
238
118
  try {
239
119
  const connection = await this.getConnection(profileName);
@@ -253,9 +133,6 @@ export class MySQLUtil {
253
133
  };
254
134
  }
255
135
  }
256
- /**
257
- * List all tables in current database
258
- */
259
136
  async listTables(profileName) {
260
137
  try {
261
138
  const connection = await this.getConnection(profileName);
@@ -277,26 +154,13 @@ export class MySQLUtil {
277
154
  };
278
155
  }
279
156
  }
280
- /**
281
- * Show table indexes
282
- */
283
157
  async showIndexes(profileName, table, format = 'table') {
284
158
  try {
285
159
  const connection = await this.getConnection(profileName);
286
160
  const [rows, fields] = await connection.query(`SHOW INDEXES FROM ${table}`);
287
- let result = '';
288
- if (format === 'json') {
289
- result += this.formatAsJson(rows);
290
- }
291
- else if (format === 'toon') {
292
- result += this.formatAsToon(rows);
293
- }
294
- else {
295
- result += this.formatAsTable(rows, fields);
296
- }
297
161
  return {
298
162
  indexes: rows,
299
- result,
163
+ result: this.formatRows(rows, fields, format),
300
164
  success: true,
301
165
  };
302
166
  }
@@ -308,9 +172,6 @@ export class MySQLUtil {
308
172
  };
309
173
  }
310
174
  }
311
- /**
312
- * Test database connection
313
- */
314
175
  async testConnection(profileName) {
315
176
  try {
316
177
  const connection = await this.getConnection(profileName);
@@ -331,34 +192,13 @@ export class MySQLUtil {
331
192
  };
332
193
  }
333
194
  }
334
- /**
335
- * Format rows for SELECT/SHOW/DESCRIBE/EXPLAIN query result
336
- */
195
+ formatRows(rows, fields, format) {
196
+ return FORMATTERS[format](rows, fields);
197
+ }
337
198
  formatSelectResult(rows, fields, format) {
338
199
  const rowCount = Array.isArray(rows) ? rows.length : 0;
339
- let result = `Query executed successfully. Rows returned: ${rowCount}\n\n`;
340
- switch (format) {
341
- case 'csv': {
342
- result += this.formatAsCsv(rows, fields);
343
- break;
344
- }
345
- case 'json': {
346
- result += this.formatAsJson(rows);
347
- break;
348
- }
349
- case 'toon': {
350
- result += this.formatAsToon(rows);
351
- break;
352
- }
353
- default: {
354
- result += this.formatAsTable(rows, fields);
355
- }
356
- }
357
- return result;
200
+ return `Query executed successfully. Rows returned: ${rowCount}\n\n` + this.formatRows(rows, fields, format);
358
201
  }
359
- /**
360
- * Get or create MySQL connection for a profile
361
- */
362
202
  async getConnection(profileName) {
363
203
  const existing = this.connections.get(profileName);
364
204
  if (existing) {
@@ -1,7 +1,3 @@
1
- /**
2
- * Query Validation and Safety Module
3
- * Provides SQL query analysis and safety checks
4
- */
5
1
  interface BlacklistCheckResult {
6
2
  allowed: boolean;
7
3
  reason?: string;
@@ -15,24 +11,9 @@ interface QueryWarning {
15
11
  message: string;
16
12
  suggestion: string;
17
13
  }
18
- /**
19
- * Check if query contains blacklisted operations
20
- */
21
14
  export declare function checkBlacklist(query: string, blacklistedOperations: string[]): BlacklistCheckResult;
22
- /**
23
- * Check if query requires user confirmation
24
- */
25
15
  export declare function requiresConfirmation(query: string, confirmationOperations: string[]): ConfirmationCheckResult;
26
- /**
27
- * Get query type (SELECT, INSERT, UPDATE, etc.)
28
- */
29
16
  export declare function getQueryType(query: string): string;
30
- /**
31
- * Analyze query for potential issues and provide warnings
32
- */
33
17
  export declare function analyzeQuery(query: string): QueryWarning[];
34
- /**
35
- * Apply default LIMIT to SELECT queries if not present
36
- */
37
18
  export declare function applyDefaultLimit(query: string, defaultLimit: number): string;
38
19
  export {};
@@ -1,10 +1,3 @@
1
- /**
2
- * Query Validation and Safety Module
3
- * Provides SQL query analysis and safety checks
4
- */
5
- /**
6
- * Check if query contains blacklisted operations
7
- */
8
1
  export function checkBlacklist(query, blacklistedOperations) {
9
2
  const normalizedQuery = query.trim().toUpperCase();
10
3
  for (const operation of blacklistedOperations) {
@@ -18,9 +11,6 @@ export function checkBlacklist(query, blacklistedOperations) {
18
11
  }
19
12
  return { allowed: true };
20
13
  }
21
- /**
22
- * Check if query requires user confirmation
23
- */
24
14
  export function requiresConfirmation(query, confirmationOperations) {
25
15
  const normalizedQuery = query.trim().toUpperCase();
26
16
  for (const operation of confirmationOperations) {
@@ -34,9 +24,6 @@ export function requiresConfirmation(query, confirmationOperations) {
34
24
  }
35
25
  return { required: false };
36
26
  }
37
- /**
38
- * Get query type (SELECT, INSERT, UPDATE, etc.)
39
- */
40
27
  export function getQueryType(query) {
41
28
  const normalizedQuery = query.trim().toUpperCase();
42
29
  const firstWord = normalizedQuery.split(/\s+/)[0];
@@ -58,9 +45,6 @@ export function getQueryType(query) {
58
45
  }
59
46
  return 'UNKNOWN';
60
47
  }
61
- /**
62
- * Analyze query for potential issues and provide warnings
63
- */
64
48
  export function analyzeQuery(query) {
65
49
  const warnings = [];
66
50
  const normalizedQuery = query.trim().toUpperCase();
@@ -91,9 +75,6 @@ export function analyzeQuery(query) {
91
75
  }
92
76
  return warnings;
93
77
  }
94
- /**
95
- * Apply default LIMIT to SELECT queries if not present
96
- */
97
78
  export function applyDefaultLimit(query, defaultLimit) {
98
79
  const normalizedQuery = query.trim().toUpperCase();
99
80
  if (normalizedQuery.startsWith('SELECT') && !normalizedQuery.includes('LIMIT')) {
@@ -291,10 +291,10 @@
291
291
  "mysql:auth:add": {
292
292
  "aliases": [],
293
293
  "args": {},
294
- "description": "Add a MySQL connection profile",
294
+ "description": "Add MySQL authentication",
295
295
  "examples": [
296
296
  "<%= config.bin %> <%= command.id %>",
297
- "<%= config.bin %> <%= command.id %> --no-ssl"
297
+ "<%= config.bin %> <%= command.id %> -p prod"
298
298
  ],
299
299
  "flags": {
300
300
  "json": {
@@ -304,10 +304,10 @@
304
304
  "allowNo": false,
305
305
  "type": "boolean"
306
306
  },
307
- "database": {
308
- "char": "d",
309
- "description": "Database name",
310
- "name": "database",
307
+ "profile": {
308
+ "char": "p",
309
+ "description": "Profile name",
310
+ "name": "profile",
311
311
  "required": true,
312
312
  "hasDynamicHelp": false,
313
313
  "multiple": false,
@@ -321,27 +321,35 @@
321
321
  "multiple": false,
322
322
  "type": "option"
323
323
  },
324
- "password": {
325
- "char": "p",
326
- "description": "Password",
327
- "name": "password",
324
+ "port": {
325
+ "description": "MySQL port",
326
+ "name": "port",
328
327
  "required": true,
329
328
  "hasDynamicHelp": false,
330
329
  "multiple": false,
331
330
  "type": "option"
332
331
  },
333
- "port": {
334
- "char": "P",
335
- "description": "MySQL port",
336
- "name": "port",
332
+ "user": {
333
+ "char": "u",
334
+ "description": "Username",
335
+ "name": "user",
337
336
  "required": true,
338
337
  "hasDynamicHelp": false,
339
338
  "multiple": false,
340
339
  "type": "option"
341
340
  },
342
- "profile": {
343
- "description": "Profile name",
344
- "name": "profile",
341
+ "password": {
342
+ "description": "Password",
343
+ "name": "password",
344
+ "required": true,
345
+ "hasDynamicHelp": false,
346
+ "multiple": false,
347
+ "type": "option"
348
+ },
349
+ "database": {
350
+ "char": "d",
351
+ "description": "Database name",
352
+ "name": "database",
345
353
  "required": true,
346
354
  "hasDynamicHelp": false,
347
355
  "multiple": false,
@@ -350,15 +358,124 @@
350
358
  "ssl": {
351
359
  "description": "Use SSL",
352
360
  "name": "ssl",
361
+ "required": true,
362
+ "allowNo": false,
363
+ "type": "boolean"
364
+ }
365
+ },
366
+ "hasDynamicHelp": false,
367
+ "hiddenAliases": [],
368
+ "id": "mysql:auth:add",
369
+ "pluginAlias": "@hesed/mysql",
370
+ "pluginName": "@hesed/mysql",
371
+ "pluginType": "core",
372
+ "strict": true,
373
+ "enableJsonFlag": true,
374
+ "isESM": true,
375
+ "relativePath": [
376
+ "dist",
377
+ "commands",
378
+ "mysql",
379
+ "auth",
380
+ "add.js"
381
+ ]
382
+ },
383
+ "mysql:auth:delete": {
384
+ "aliases": [],
385
+ "args": {},
386
+ "description": "Delete an authentication profile",
387
+ "examples": [
388
+ "<%= config.bin %> <%= command.id %>",
389
+ "<%= config.bin %> <%= command.id %> -p prod"
390
+ ],
391
+ "flags": {
392
+ "json": {
393
+ "description": "Format output as json.",
394
+ "helpGroup": "GLOBAL",
395
+ "name": "json",
396
+ "allowNo": false,
397
+ "type": "boolean"
398
+ },
399
+ "profile": {
400
+ "char": "p",
401
+ "description": "Profile to delete",
402
+ "name": "profile",
353
403
  "required": false,
354
- "allowNo": true,
404
+ "hasDynamicHelp": false,
405
+ "multiple": false,
406
+ "type": "option"
407
+ }
408
+ },
409
+ "hasDynamicHelp": false,
410
+ "hiddenAliases": [],
411
+ "id": "mysql:auth:delete",
412
+ "pluginAlias": "@hesed/mysql",
413
+ "pluginName": "@hesed/mysql",
414
+ "pluginType": "core",
415
+ "strict": true,
416
+ "enableJsonFlag": true,
417
+ "isESM": true,
418
+ "relativePath": [
419
+ "dist",
420
+ "commands",
421
+ "mysql",
422
+ "auth",
423
+ "delete.js"
424
+ ]
425
+ },
426
+ "mysql:auth:list": {
427
+ "aliases": [],
428
+ "args": {},
429
+ "description": "List authentication profiles",
430
+ "examples": [
431
+ "<%= config.bin %> <%= command.id %>"
432
+ ],
433
+ "flags": {
434
+ "json": {
435
+ "description": "Format output as json.",
436
+ "helpGroup": "GLOBAL",
437
+ "name": "json",
438
+ "allowNo": false,
439
+ "type": "boolean"
440
+ }
441
+ },
442
+ "hasDynamicHelp": false,
443
+ "hiddenAliases": [],
444
+ "id": "mysql:auth:list",
445
+ "pluginAlias": "@hesed/mysql",
446
+ "pluginName": "@hesed/mysql",
447
+ "pluginType": "core",
448
+ "strict": true,
449
+ "enableJsonFlag": true,
450
+ "isESM": true,
451
+ "relativePath": [
452
+ "dist",
453
+ "commands",
454
+ "mysql",
455
+ "auth",
456
+ "list.js"
457
+ ]
458
+ },
459
+ "mysql:auth:profile": {
460
+ "aliases": [],
461
+ "args": {},
462
+ "description": "Set or show the default authentication profile",
463
+ "examples": [
464
+ "<%= config.bin %> <%= command.id %>",
465
+ "<%= config.bin %> <%= command.id %> --default test"
466
+ ],
467
+ "flags": {
468
+ "json": {
469
+ "description": "Format output as json.",
470
+ "helpGroup": "GLOBAL",
471
+ "name": "json",
472
+ "allowNo": false,
355
473
  "type": "boolean"
356
474
  },
357
- "user": {
358
- "char": "u",
359
- "description": "Username",
360
- "name": "user",
361
- "required": true,
475
+ "default": {
476
+ "description": "Profile to set as default",
477
+ "name": "default",
478
+ "required": false,
362
479
  "hasDynamicHelp": false,
363
480
  "multiple": false,
364
481
  "type": "option"
@@ -366,7 +483,7 @@
366
483
  },
367
484
  "hasDynamicHelp": false,
368
485
  "hiddenAliases": [],
369
- "id": "mysql:auth:add",
486
+ "id": "mysql:auth:profile",
370
487
  "pluginAlias": "@hesed/mysql",
371
488
  "pluginName": "@hesed/mysql",
372
489
  "pluginType": "core",
@@ -378,16 +495,16 @@
378
495
  "commands",
379
496
  "mysql",
380
497
  "auth",
381
- "add.js"
498
+ "profile.js"
382
499
  ]
383
500
  },
384
501
  "mysql:auth:test": {
385
502
  "aliases": [],
386
503
  "args": {},
387
- "description": "Test MySQL database connection",
504
+ "description": "Test authentication and connection",
388
505
  "examples": [
389
506
  "<%= config.bin %> <%= command.id %>",
390
- "<%= config.bin %> <%= command.id %> --profile staging"
507
+ "<%= config.bin %> <%= command.id %> -p prod"
391
508
  ],
392
509
  "flags": {
393
510
  "json": {
@@ -398,7 +515,8 @@
398
515
  "type": "boolean"
399
516
  },
400
517
  "profile": {
401
- "description": "Profile name to test",
518
+ "char": "p",
519
+ "description": "Authentication profile name",
402
520
  "name": "profile",
403
521
  "required": false,
404
522
  "hasDynamicHelp": false,
@@ -426,10 +544,10 @@
426
544
  "mysql:auth:update": {
427
545
  "aliases": [],
428
546
  "args": {},
429
- "description": "Update an existing MySQL connection profile",
547
+ "description": "Update MySQL authentication",
430
548
  "examples": [
431
- "<%= config.bin %> <%= command.id %> --ssl",
432
- "<%= config.bin %> <%= command.id %> --profile staging"
549
+ "<%= config.bin %> <%= command.id %>",
550
+ "<%= config.bin %> <%= command.id %> -p test"
433
551
  ],
434
552
  "flags": {
435
553
  "json": {
@@ -439,10 +557,10 @@
439
557
  "allowNo": false,
440
558
  "type": "boolean"
441
559
  },
442
- "database": {
443
- "char": "d",
444
- "description": "Database name",
445
- "name": "database",
560
+ "profile": {
561
+ "char": "p",
562
+ "description": "Profile name",
563
+ "name": "profile",
446
564
  "required": true,
447
565
  "hasDynamicHelp": false,
448
566
  "multiple": false,
@@ -456,47 +574,46 @@
456
574
  "multiple": false,
457
575
  "type": "option"
458
576
  },
459
- "password": {
460
- "char": "p",
461
- "description": "Password",
462
- "name": "password",
577
+ "port": {
578
+ "description": "MySQL port",
579
+ "name": "port",
463
580
  "required": true,
464
581
  "hasDynamicHelp": false,
465
582
  "multiple": false,
466
583
  "type": "option"
467
584
  },
468
- "port": {
469
- "char": "P",
470
- "description": "MySQL port",
471
- "name": "port",
585
+ "user": {
586
+ "char": "u",
587
+ "description": "Username",
588
+ "name": "user",
472
589
  "required": true,
473
590
  "hasDynamicHelp": false,
474
591
  "multiple": false,
475
592
  "type": "option"
476
593
  },
477
- "profile": {
478
- "description": "Profile name to update",
479
- "name": "profile",
480
- "required": false,
594
+ "password": {
595
+ "description": "Password",
596
+ "name": "password",
597
+ "required": true,
481
598
  "hasDynamicHelp": false,
482
599
  "multiple": false,
483
600
  "type": "option"
484
601
  },
485
- "ssl": {
486
- "description": "Use SSL",
487
- "name": "ssl",
488
- "required": false,
489
- "allowNo": true,
490
- "type": "boolean"
491
- },
492
- "user": {
493
- "char": "u",
494
- "description": "Username",
495
- "name": "user",
602
+ "database": {
603
+ "char": "d",
604
+ "description": "Database name",
605
+ "name": "database",
496
606
  "required": true,
497
607
  "hasDynamicHelp": false,
498
608
  "multiple": false,
499
609
  "type": "option"
610
+ },
611
+ "ssl": {
612
+ "description": "Use SSL",
613
+ "name": "ssl",
614
+ "required": true,
615
+ "allowNo": false,
616
+ "type": "boolean"
500
617
  }
501
618
  },
502
619
  "hasDynamicHelp": false,
@@ -517,5 +634,5 @@
517
634
  ]
518
635
  }
519
636
  },
520
- "version": "0.2.2"
637
+ "version": "0.4.0"
521
638
  }