mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 09:59:03 +08:00
## What PR **2 of 9** in the SQL-editor query-source (Database vs Logs) stack. **Base:** `charislam/snippet-source-typing` (#48301) — this is a stacked PR; review/merge that one first. Client-side rename only — **the wire format is unchanged** (the platform API still stores and returns `content.sql`). This moves the frontend `LogSqlSnippets.Content` field to the branded `unchecked_sql`, matching `SqlSnippets.Content`, and hardens the remap boundary so the rename can't silently drop saved query text. ## Changes - **`types/userContent.ts`** — `LogSqlSnippets.Content`'s plain `sql: string` becomes `unchecked_sql: UntrustedLogSqlFragment` (the brand added in PR 1). Shape kept minimal: `{ content_id, unchecked_sql, schema_version }`. - **`data/content/content-remap.ts`** — extend `remapSqlContentField`/`unmapSqlContentField` to `log_sql`, branding **per type** (`untrustedLogSql` for logs, `untrustedSql` for database) and never mixing brands. **Defensive unmap**: content missing `unchecked_sql` is never clobbered with `sql: undefined`; a residual raw `sql` field (a missed save-path rename) throws in development to surface the bug loudly, while production no-ops safely. - **Legacy Logs Explorer consumers** updated to the branded field: the explorer save/update paths, `SavedQueriesItem`, `RecentQueriesItem`, and the recent-queries page. - **Two db-only write sites** that leaned on `LogSqlSnippets.Content.sql`: `EditorPanel` now saves `unchecked_sql`, and `MoveQueryModal` switches to the SQL-editor-specific `getSqlSnippetById` so its content is typed as `SqlSnippets.Content` — no narrowing or casting. ## Tests - **content-remap**: `log_sql` remap/unmap round-trip with the logs brand; the defensive-unmap no-op (prod) and dev throw. - **content-upsert-mutation**: a `log_sql` payload reaches the wire as a plain `content.sql` and the response remaps back to `unchecked_sql` (the data-loss-critical round-trip shared by both explorer save-new and `SavedQueriesItem` update). ## Verification - `pnpm --filter studio run typecheck` ✓ - `pnpm --filter studio run lint:ratchet` ✓ (no new warnings) - `pnpm test:studio` for `data/content` + `Settings/Logs` — 139 passing ✓ - Prettier ✓ Nothing is user-visible yet — logs snippet entry points arrive later in the stack behind the `sqlEditorLogsSource` flag. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved handling of saved and recent log queries across the SQL editor and Logs Explorer. - Log SQL now uses `unchecked_sql` (branded as untrusted) consistently when creating, editing, moving, and reopening queries, with correct remapping to/from the API boundary. - Fixed saved-query update payloads to preserve the right query content and omit legacy fields. - **Tests** - Added/expanded Vitest coverage for saved log query editing, recent-log normalization, and `log_sql` remap/upsert request/response behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
import { useMemo } from 'react'
|
|
|
|
import { untrustedLogSql, type UntrustedLogSqlFragment } from '@/data/logs/safe-analytics-sql'
|
|
import { useLocalStorage } from '@/hooks/misc/useLocalStorage'
|
|
import type { LogSqlSnippets } from '@/types'
|
|
|
|
/**
|
|
* Shape of a recent-log-sql entry as it may exist in localStorage. Entries written before the
|
|
* `sql` → `unchecked_sql` rename carry the raw `sql` field; entries written after carry the
|
|
* branded `unchecked_sql`. This tolerant type lets us read both and normalize to the branded
|
|
* frontend shape, so no consumer ever sees an unbranded `sql`.
|
|
*/
|
|
type StoredRecentLogSqlSnippet = Omit<LogSqlSnippets.Content, 'unchecked_sql'> & {
|
|
unchecked_sql?: UntrustedLogSqlFragment
|
|
sql?: string
|
|
}
|
|
|
|
/**
|
|
* Normalizes a stored recent-log-sql entry into the current `LogSqlSnippets.Content` shape,
|
|
* branding a legacy raw `sql` value with `untrustedLogSql`. Prefers an already-branded
|
|
* `unchecked_sql` when present.
|
|
*/
|
|
export function normalizeRecentLogSqlSnippet(
|
|
entry: StoredRecentLogSqlSnippet
|
|
): LogSqlSnippets.Content {
|
|
const { sql, unchecked_sql, ...rest } = entry
|
|
return { ...rest, unchecked_sql: unchecked_sql ?? untrustedLogSql(sql ?? '') }
|
|
}
|
|
|
|
/**
|
|
* localStorage-backed list of recent Logs Explorer queries, always surfaced with the branded
|
|
* `unchecked_sql` field. Reads tolerate the pre-rename `{ sql }` shape and normalize it; writing
|
|
* the normalized value back heals the stored entries over time.
|
|
*/
|
|
export function useRecentLogSqlSnippets(projectRef?: string) {
|
|
const [stored, setStored] = useLocalStorage<StoredRecentLogSqlSnippet[]>(
|
|
`project-content-${projectRef}-recent-log-sql`,
|
|
[]
|
|
)
|
|
|
|
const snippets = useMemo<LogSqlSnippets.Content[]>(
|
|
() => stored.map(normalizeRecentLogSqlSnippet),
|
|
[stored]
|
|
)
|
|
|
|
return [snippets, setStored] as const
|
|
}
|