Query Editor

A SQL editor that asks before running an UPDATE or DELETE with no WHERE clause. That is the most expensive mistake anyone makes in a query console, and it is trivial to detect.

src/components/ui/query-editor.tsx

About

From the component's own source, where it was written.

A SQL editor with a run action and a guard on destructive statements.

An UPDATE or DELETE without a WHERE clause requires confirmation. This is the single most expensive mistake anyone makes in a query console, it is trivial to detect, and detecting it is worth far more than syntax highlighting.

Cmd/Ctrl+Enter runs. Anyone who has used a query console expects it, and making them reach for a button breaks the loop that makes a console useful.

The editor is a CodeBlock in editable mode rather than a bare textarea, so the SQL is syntax-highlighted as it is typed. A console where every statement is one undifferentiated grey block is a console people paste out of into a real editor.

Statement count is shown when the buffer holds more than one. "Run" on a multi-statement buffer does something quite different from what a single statement does, and the difference should not be a surprise.

Install

npx astralyx-ui add query-editor

Usage

import { QueryEditor } from '@/components/ui/query-editor'

<QueryEditor value={sql} onValueChange={setSql} onRun={run} />

Composer

Change the props and the source below follows.

PostgreSQL⌘↵
Props
tsx
<QueryEditor
  value={sql}
  onValueChange={setSql}
  onRun={run}
  dialect="PostgreSQL"
/>

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

QueryEditor

Extends Omit<ComponentProps<'div'>, 'onChange' | 'children'>.

PropTypeDefaultDescription
valuestring——
onValueChange(value: string) => void——
onRun(sql: string) => void—Omit to render a read-write editor with no execution.
runningbooleanfalse—
dialectReactNode'SQL'—
rowsnumber8Minimum visible lines. The editor grows past this with the query.
lineNumbersbooleantrue—
runLabelReactNode'Run'—
confirmLabelReactNode'Run anyway'—
cancelLabelReactNode'Cancel'—
editorLabelstring'SQL query'—
unguardedNoteReactNode'This statement has no WHERE clause — it will affect every row in the table.'—
schemaChangeNoteReactNode'This changes the schema and cannot be rolled back on every engine.'—
statementsLabel(count: number) => ReactNodeDEFAULT_STATEMENTS_LABEL—
shortcutKeysstring | null'⌘+↵'Rendered with Kbd, split on +. Cmd/Ctrl+Enter runs — anyone who has used a query console expects it, and reaching for a button breaks the loop. null hides the hint.

Functions

FunctionSignatureDescription
splitStatements(sql: string) => string[]Statement split on semicolons outside quotes — good enough to count.

Behaviour

TopicDetailDescription
highlightingCodeBlock, editableThe editor is a CodeBlock in editable mode, so SQL is highlighted as it is typed. A console where every statement is one grey block is a console people paste out of.
guardautomaticUPDATE or DELETE without a WHERE, and DROP/TRUNCATE/ALTER, require a second click before onRun fires.
statement countshown above oneRunning a multi-statement buffer does something different from running one, and that should not be a surprise.