## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Feature (+ a small refactor and a docs/convention note). PR 4 of the
stacked SQL-editor query-source series (Database vs Logs).
## What is the current behavior?
The SQL editor has no representation of a logs query's time range:
`querySource.ts` only knows how to map a snippet type to a source
(`getSnippetSource`), and session state (`sql-editor-session-state.ts`)
tracks results and the row limit but not a per-snippet time range. The
Logs date picker's pure range helpers (`parseCustomInput`,
`generateDynamicHelper`, the `Unit` type) are trapped inside the
`Logs.DatePickers.tsx` React component.
## What is the new behavior?
- **Logs time-range domain** in `querySource.ts`: branded
`IsoDateTimeString` + `isoDateTimeString()`, `RelativeTimeUnit`, a
`LogDateRange` discriminated union (relative/absolute),
`DEFAULT_LOG_DATE_RANGE`, a single date-picker parser
(`datePickerValueToLogDateRange` / `logDateRangeToDatePickerValue` —
handles the five presets *and* dynamic `2h`/`30m` helpers; `calcTo ===
''` means "now"; unparseable helpers degrade to absolute), and
`resolveLogRunRange` which re-resolves relative ranges against `now` at
run time (reusing the existing `ResolvedLogDateRange` shape).
- **Session state**: per-snippet `logRange` + `setLogRange` —
session-only, never written to snippet content, so it works on read-only
shared snippets and is cleaned up in `clearForSnippet`.
- **Refactor**: extracted the picker's framework-free helpers into a new
pure `Logs.datePickerHelpers.ts`; the logs domain now shares the `Unit`
type and reuses `generateDynamicHelper` instead of duplicating them.
Importers point at the new module directly (no re-export shim). Hardened
the amount parse against `NaN`.
- **Full unit coverage** in `querySource.test.ts`. Recorded the no-shim
refactoring convention in the `studio-best-practices` skill.
Verification: `pnpm typecheck` clean, lint ratchet improved, 43 tests
pass (querySource + Logs.Datepickers), Prettier clean.
## Additional context
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added robust Logs date-range modeling with support for relative (e.g.,
last N units) and absolute time periods.
- SQL Editor sessions now remember log date ranges per snippet.
- **Bug Fixes**
- Safer handling of invalid or missing date inputs, with sensible
fallback to default/current time.
- **Tests**
- Added/expanded automated coverage for date-range conversion, helper
parsing, and resolution behavior.
- **Refactor**
- Centralized date-picker helper utilities for reuse across the Logs and
SQL query experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
Part 2/6 of the SQL Editor testability follow-up, stacked on #47980 (the
analyzeQueryIssues/resolveConnectionString PR).
- Extracts `shouldAutoGenerateTitle` and `buildExecuteParams` out of
`useSqlEditorExecution`'s inline logic into `SQLEditor.utils.ts`.
- Merges `checkIfAppendLimitRequired` and `suffixWithLimit` into a
single `applyAutoLimit` function — the two were only ever called
together and re-parsed the same query twice at every call site.
`applyAutoLimit` only accepts `SafeSqlFragment` (never a plain string)
and composes the `LIMIT` suffix through `safeSql`/`literal` rather than
raw template concatenation, so the only place in the file that reasserts
the `SafeSqlFragment` brand on a derived string is the small, dedicated
`trimTrailingSemicolons` helper — removing existing terminators can't
introduce unsafe content, unlike gluing new text onto the fragment.
- Updates the two other `checkIfAppendLimitRequired`/`suffixWithLimit`
call sites (`EditorPanel.tsx`, `ReportBlock.tsx`) accordingly;
`ReportBlock` now promotes its report SQL once and reuses the result for
both its display-only auto-limit hint and its execution, instead of
promoting twice.
## Test plan
- [x] `pnpm --filter studio typecheck`
- [x] `pnpm test:studio -- SQLEditor ReportBlock EditorPanel` (239 tests
passing)
Removes the SQL Editor Pretty Explain feature — the Explain tab, the Run
EXPLAIN ANALYZE action + shortcut, and its dead plumbing. It's been
gated off behind the `DisablePrettyExplainOnSqlEditor` kill switch for
weeks with no usage or complaints.
`ExplainVisualizer` / `isExplainQuery` are kept — they're used
independently by Query Insights, Query Performance, and the EditorPanel
quick-runner. Manually-run `EXPLAIN` queries still render as raw rows in
the Results tab.
Typecheck, lint, and all affected unit tests pass.
Closes FE-3930
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Changes**
* Removed the SQL editor’s EXPLAIN execution workflow, including its
toolbar action, keyboard shortcut, utility tab, and visual query-plan
display.
* Simplified query execution to focus on standard results and charts.
* Improved result clearing when switching databases and refined
execution error handling.
* Updated SQL editor state and tests to reflect the streamlined
experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What
PR 6 of the SQL editor state re-layering stack. Moves ephemeral,
never-persisted SQL editor state out of the snippet/folder "god store".
**Session store** — `state/sql-editor/sql-editor-session-state.ts` holds
per-snippet, read-by-many session state:
- query `results`
- `explainResults`
- the row `limit`
…with their mutators (`addResult`/`addResultError`/`resetResult`,
`addExplainResult`/`addExplainResultError`/`resetExplainResult`,
`resetResults`, `setLimit`). `removeSnippet` drops a snippet's session
entries via `clearForSnippet(id)`.
**Diff-request slice** — `state/sql-editor/sql-editor-diff-request.ts`.
The Assistant's "Insert code" / "Replace code" diff is *not* per-snippet
session state: it's a transient, fire-and-forget command produced
outside the editor (e.g. query blocks / assistant) and consumed exactly
once by whichever editor is active. It's modeled as a consume-once
request (`requestDiff` / `consumeDiffRequest`) rather than durable state
— the editor drains it on apply, so a stale diff can't leak into a later
editor or session. (Previously this was `diffContent` in the god store:
never cleared and triggered by object-reference identity.)
Consumers read session state from `useSqlEditorSessionSnapshot` and the
diff channel from `useSqlEditorDiffRequestSnapshot`, keeping
`useSqlEditorV2StateSnapshot` only for snippets/folders.
### Why not the TanStack Query cache for results/explain?
Editor execution is a **mutation**, not a keyed query — `mutation.data`
is per-hook-instance and not keyed by snippet id, and there's no caching
value to capture (re-running SQL must return *fresh* data, never a
cached result). `EXPLAIN ANALYZE` actually executes the statement, so a
declarative/auto-refetching `useQuery` is semantically wrong.
Results/explain are imperative mutation outputs, scoped to the session,
read by several decoupled consumers keyed by snippet id — exactly what a
small in-memory keyed store models honestly.
## Consumers migrated
- `SQLEditor.tsx` — results/explain/limit reads +
`addResult`/`addResultError`/`addExplainResult`/`addExplainResultError`/`setLimit`;
diff-apply effect now drains a consume-once request
- `UtilityPanel.tsx`, `UtilityTabResults.tsx`, `UtilityTabExplain.tsx`,
`UtilityActions.tsx`
- `QueryBlock/EditQueryButton.tsx` — produces via `requestDiff`
## Notes
- Result/explain types are kept verbatim from the god store
(pre-existing `any` row/error types come along unchanged; tightening
them is out of scope for this move).
- `ref()` on result rows is preserved to avoid Valtio proxying large row
sets.
## Tests
- `sql-editor-session-state.test.ts` — result/explain mutators,
`resetResults`, `clearForSnippet`, `limit`
- `sql-editor-diff-request.test.ts` — `requestDiff`,
`consumeDiffRequest` (drain + queue-of-one)
Validation:
- `pnpm --filter studio typecheck` ✅
- `pnpm exec vitest --run state/sql-editor/` ✅ (110 passed)
- lint ✅ (no new errors)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* SQL editor query results, EXPLAIN output, and the “Limit results to”
setting now persist more reliably across a session.
* AI-assisted SQL insert/replace actions now use a pending diff workflow
to apply updates more consistently.
* **Bug Fixes**
* Results/EXPLAIN rendering and downloads stay in sync with the latest
executed data.
* Switching databases/snippets now clears the correct temporary results.
* Diff application is more resilient when an editor is still loading,
including empty-vs-non-empty editor cases.
* **Tests**
* Added coverage for the session and diff-request state logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>