Files
supabase/apps/studio/components/interfaces/SQLEditor/usePrettifyQuery.ts
Charis 3d83e026f9 refactor(sql-editor): finish EditorController/DiffController port (Step 2) (#48166)
## Summary
Step 2 of the SQL Editor testability plan.

`SQLEditorContext` already wrapped the Monaco refs and exposed a few
semantic imperative helpers (`getEditorSql`, `clearHighlights`,
`applyErrorHighlight`, `refocusEditor`, …). This finishes that
abstraction so no hook or controller touches
`editorRef.current`/`diffEditorRef.current` directly anymore — they only
call the port. The port is what will let Step 3's test harness inject a
real in-memory editor adapter instead of mocking Monaco; production
wires it to the real Monaco refs, unchanged.

- Extends the context value with two semantic controllers, backed by the
existing refs:
- `editor: EditorController` — `isReady`, `getValue`,
`getSelectionStartLine`, `getSql` (today's `getEditorSql`), `replaceAll`
(wraps the repeated `executeEdits(...)` pattern), `focus`,
`revealLineInCenter`, `highlightErrorLine` (today's
`applyErrorHighlight`), `clearHighlights`.
- `diff: DiffController` — `isMounted`, `getModifiedValue`, `setDiff`
(the diff-sync effect body), `attach` (today's `handleDiffEditorMount`).
- Migrates every touch point off raw refs onto the port:
`useSqlEditorExecution`, `usePrettifyQuery`, `useSqlEditorShortcuts`,
`SQLEditorControllers`' `readEditorSql`, and `useSqlEditorAi`'s
`acceptAiHandler`/`drainDiffRequest`/`handleDiffEditorMount`/diff-sync
effect.
- `SQLEditorEditorPanel.tsx` is intentionally left untouched — it wires
the raw refs into the real Monaco/DiffEditor React components for
rendering, which isn't decision logic to abstract.

Behavior-preserving.

## Test plan
- [x] `pnpm --filter studio typecheck`
- [x] `pnpm test:studio -- SQLEditor` (265 tests passing)
- [x] `pnpm --filter studio run lint:ratchet`
2026-07-21 16:22:47 -04:00

37 lines
1.2 KiB
TypeScript

import { useCallback } from 'react'
import { useSQLEditorContext } from './SQLEditorContext'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { formatSql } from '@/lib/formatSql'
import {
getSqlEditorV2StateSnapshot,
useSqlEditorV2StateSnapshot,
} from '@/state/sql-editor/sql-editor-state'
/**
* Formats the current editor SQL in place (respecting a selection) and writes
* the formatted SQL back to the snippet store. No-op while a diff is open.
*/
export function usePrettifyQuery({ id, isDiffOpen }: { id: string; isDiffOpen: boolean }) {
const { editor } = useSQLEditorContext()
const { data: project } = useSelectedProjectQuery()
const snapV2 = useSqlEditorV2StateSnapshot()
return useCallback(async () => {
if (isDiffOpen) return
// use the latest state
const state = getSqlEditorV2StateSnapshot()
const snippet = state.snippets[id]
if (editor.isReady() && project) {
const sql = editor.getSql(snippet?.snippet.content?.unchecked_sql)
if (sql === undefined) return
const formattedSql = formatSql(sql)
editor.replaceAll(formattedSql, 'apply-prettify-edit')
snapV2.setSql({ id, sql: formattedSql })
}
}, [editor, id, isDiffOpen, project, snapV2])
}