diff --git a/prisma/migrations/20231209142417_tool_update_date/migration.sql b/prisma/migrations/20231209142417_tool_update_date/migration.sql new file mode 100644 index 0000000..2435b79 --- /dev/null +++ b/prisma/migrations/20231209142417_tool_update_date/migration.sql @@ -0,0 +1,17 @@ +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Tool" ( + "name" TEXT NOT NULL PRIMARY KEY, + "created" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "lastUsed" DATETIME, + "query" TEXT NOT NULL, + "description" TEXT, + "count" INTEGER NOT NULL DEFAULT 0 +); +INSERT INTO "new_Tool" ("count", "created", "description", "lastUsed", "name", "query") SELECT "count", "created", "description", "lastUsed", "name", "query" FROM "Tool"; +DROP TABLE "Tool"; +ALTER TABLE "new_Tool" RENAME TO "Tool"; +CREATE UNIQUE INDEX "Tool_name_key" ON "Tool"("name"); +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9859e9e..815bbee 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -39,6 +39,7 @@ model History { model Tool { name String @id @unique created DateTime @default(now()) + updated DateTime @default(now()) lastUsed DateTime? query String description String? diff --git a/src/commands/connection/create.ts b/src/commands/connection/create.ts index d87dca7..f590ce4 100644 --- a/src/commands/connection/create.ts +++ b/src/commands/connection/create.ts @@ -10,10 +10,12 @@ export default class Create extends AppCommand { connectionString: Args.string({description: 'Connection string for database', required: true}), } - static description = 'Exec a query on the given database' + static description = 'Create a connection to a database' static examples = [] + static aliases = ['conn:create'] + static flags = { format, description: Flags.string({description: 'Description of connection', required: false, aliases: ['d']}), diff --git a/src/commands/connection/delete.ts b/src/commands/connection/delete.ts index efe3363..5755b3d 100644 --- a/src/commands/connection/delete.ts +++ b/src/commands/connection/delete.ts @@ -13,6 +13,8 @@ export default class Delete extends AppCommand { static examples = [] + static aliases = ['conn:delete'] + static flags = { format, } diff --git a/src/commands/connection/get.ts b/src/commands/connection/get.ts index fce1f0f..c0656a7 100644 --- a/src/commands/connection/get.ts +++ b/src/commands/connection/get.ts @@ -17,6 +17,8 @@ export default class Get extends AppCommand { format, } + static aliases = ['conn:get'] + async run(): Promise { const {flags, args} = await this.parse(Get) const {alias} = args diff --git a/src/commands/connection/list.ts b/src/commands/connection/list.ts index ff7d5a6..e754c19 100644 --- a/src/commands/connection/list.ts +++ b/src/commands/connection/list.ts @@ -7,12 +7,12 @@ import {AppCommand} from '../../AppCommand.js' export default class List extends AppCommand { static args = { search: Args.string({ - description: 'Search for a connection by alias, desciption, and conection string', + description: 'Search for a connection by alias, description, or conection string', required: false, }), } - static aliases = ['ls'] + static aliases = ['connection:ls', 'conn:ls'] static description = 'List all saved connections' diff --git a/src/commands/history/get.ts b/src/commands/history/get.ts index 978415d..a85120c 100644 --- a/src/commands/history/get.ts +++ b/src/commands/history/get.ts @@ -6,10 +6,10 @@ import {AppCommand} from '../../AppCommand.js' export default class Get extends AppCommand { static args = { - id: Args.integer({description: 'ID of item in history list', required: true}), + id: Args.integer({description: 'ID of history entry', required: true}), } - static description = 'Get query from history' + static description = 'Get a history entry' static examples = [] diff --git a/src/commands/history/list.ts b/src/commands/history/list.ts index 0d5e45e..817baec 100644 --- a/src/commands/history/list.ts +++ b/src/commands/history/list.ts @@ -9,7 +9,7 @@ export default class List extends AppCommand { search: Args.string({description: 'Part of a query to search for', required: false}), } - static aliases = ['ls'] + static aliases = ['history:ls'] static description = 'Search query history' diff --git a/src/commands/query/file.ts b/src/commands/query/file.ts index f9410be..7449e81 100644 --- a/src/commands/query/file.ts +++ b/src/commands/query/file.ts @@ -11,7 +11,7 @@ export default class File extends AppCommand { file: Args.file({description: 'Path to file containing SQL query', required: true, exists: true}), } - static description = 'Query data from a database' + static description = 'Query data from a database by file' static examples = [] diff --git a/src/commands/query/history.ts b/src/commands/query/history.ts index 24bbbe5..88f5e77 100644 --- a/src/commands/query/history.ts +++ b/src/commands/query/history.ts @@ -5,11 +5,13 @@ import {AppCommand} from '../../AppCommand.js' export default class SQL extends AppCommand { static args = { - id: Args.integer({description: 'ID of history command to execute', required: true}), + id: Args.integer({description: 'ID of history entry to execute', required: true}), } static description = 'Re-run a previous database query' + static aliases = ['history:query'] + static examples = [] static flags = { diff --git a/src/commands/query/tool.ts b/src/commands/query/tool.ts index d8d1c3b..0dc9a97 100644 --- a/src/commands/query/tool.ts +++ b/src/commands/query/tool.ts @@ -13,6 +13,8 @@ export default class Tool extends AppCommand { static examples = [] + static aliases = ['history:query'] + static flags = { format, confirm: this.confirmFlag, @@ -48,6 +50,18 @@ export default class Tool extends AppCommand { await this.confirmQuery(alias, query, confirm) await this.executeQuery(alias, connection.connectionString, query, format) + + await this.db.tool.update({ + where: { + name, + }, + data: { + count: { + increment: 1, + }, + lastUsed: new Date(), + }, + }) } } function buildQuery(query: string, params: string[] = []) { diff --git a/src/commands/toolbox/create.ts b/src/commands/tool/create.ts similarity index 100% rename from src/commands/toolbox/create.ts rename to src/commands/tool/create.ts diff --git a/src/commands/toolbox/delete.ts b/src/commands/tool/delete.ts similarity index 100% rename from src/commands/toolbox/delete.ts rename to src/commands/tool/delete.ts diff --git a/src/commands/tool/get.ts b/src/commands/tool/get.ts new file mode 100644 index 0000000..138fa50 --- /dev/null +++ b/src/commands/tool/get.ts @@ -0,0 +1,40 @@ +import {Args, Command, Flags, ux} from '@oclif/core' +import {PrismaClient} from '@prisma/client' +import {format, printFormatted} from '../../output.js' +import {sqlqdb} from '../../database.js' +import {AppCommand} from '../../AppCommand.js' + +export default class Get extends AppCommand { + static args = { + name: Args.string({description: 'Name of tool', required: true}), + } + + static description = 'Get a tool' + + static examples = [] + + static flags = { + format, + } + + async run(): Promise { + const {flags, args} = await this.parse(Get) + const {name} = args + const {format} = flags + + const result = await this.load( + 'Searching', + this.db.tool.findFirst({ + where: { + name, + }, + }), + ) + + if (!result) { + ux.error(`Tool with name '${name}' not found`) + } + + printFormatted(format, result) + } +} diff --git a/src/commands/tool/list.ts b/src/commands/tool/list.ts new file mode 100644 index 0000000..35201f7 --- /dev/null +++ b/src/commands/tool/list.ts @@ -0,0 +1,54 @@ +import {Args, Command, Flags, ux} from '@oclif/core' +import {PrismaClient} from '@prisma/client' +import {format, printFormatted} from '../../output.js' +import {sqlqdb} from '../../database.js' +import {AppCommand} from '../../AppCommand.js' + +export default class List extends AppCommand { + static args = { + search: Args.string({description: 'Part of a query to search for', required: false}), + } + + static aliases = ['tool:ls'] + + static description = 'Search tools' + + static examples = [] + + static flags = { + format, + count: Flags.integer({description: 'Maximum number of results to return', required: false, default: 20}), + } + + async run(): Promise { + const {flags, args} = await this.parse(List) + const {search = ''} = args + const {count, format} = flags + + const result = await this.load( + 'Searching', + this.db.tool.findMany({ + take: count, + orderBy: { + lastUsed: 'desc', + }, + where: { + OR: [ + { + query: { + contains: search, + }, + }, + { + description: { + contains: search, + }, + }, + ], + }, + }), + ) + + printFormatted(format, result) + } +} diff --git a/src/commands/tool/update.ts b/src/commands/tool/update.ts new file mode 100644 index 0000000..06b3a0b --- /dev/null +++ b/src/commands/tool/update.ts @@ -0,0 +1,47 @@ +import {Args, Command, Flags, ux} from '@oclif/core' +import {PrismaClient} from '@prisma/client' +import {format, printFormatted} from '../../output.js' +import {sqlqdb} from '../../database.js' +import {AppCommand} from '../../AppCommand.js' + +export default class Create extends AppCommand { + static args = { + name: Args.string({description: 'Name for the tool', required: true}), + query: Args.string({ + description: + 'A query that the tool will run. This may contain parameters in the format of $Index that will be evaluated when the query runs', + required: false, + }), + description: Args.string({ + description: 'Description for the tool', + required: false, + }), + } + + static description = 'Update a tool' + + static examples = [] + + static flags = { + format, + } + + async run(): Promise { + const {args, flags} = await this.parse(Create) + const {name, query, description} = args + const {format} = flags + + const result = await this.db.tool.update({ + where: { + name, + }, + data: { + query, + description, + updated: new Date(), + }, + }) + + printFormatted(format, result) + } +}