import { log } from "@clack/prompts" import { defineCommand } from "../lib/command" import { globalOptions, globalOptionsSchema } from "../lib/global-options" import fs from "node:fs/promises" import { z } from "zod" import { queryExecutionData } from "../lib/execution-data" import { clearSpinner, startSpinner } from "../lib/spinner" import { output } from "../utils" const QUERY_SCHEMA = globalOptionsSchema .extend({ file: z.string().optional(), sql: z.string().optional(), }) .refine((opts) => Boolean(opts.file) !== Boolean(opts.sql), { message: "Pass exactly one of --sql or --file.", }) export const queryCommand = defineCommand({ name: "query", description: "Run SQL against synchronized execution data", options: { ...globalOptions, sql: { type: "string", short: "q", }, file: { type: "string", short: "f", }, }, optionDescriptions: { sql: "SQL statement to execute", file: "SQL file to execute", }, schema: QUERY_SCHEMA, run: queryData, }) /** * Executes a direct statement or SQL file against the active local dataset. * * @param opts - Exactly one direct statement or SQL file. */ async function queryData(opts: z.infer) { startSpinner("Querying execution data") const result = await queryExecutionData( opts.sql ?? (await fs.readFile(opts.file!, "utf8")), ) clearSpinner() output .normal(() => { for (const [index, queryResult] of result.results.entries()) { if (result.results.length > 1) log.info(`Result ${index + 1}`) log.message(JSON.stringify(queryResult.rows, null, 2)) } }) .json(result) }