Files
supabase/apps/studio/components/interfaces/QueryPerformance/WithStatements/WithStatements.utils.ts
Charis 0433eeb5f5 feat(studio): mark sql provenance for safety (#45336)
Mark provenance of SQL via the branded types SafeSqlFragment and
UntrustedSqlFragment. Only SafeSqlFragment should be executed;
UntrustedSqlFragments require some kind of implicit user approval (show
on screen + user has to click something) before they are promoted to
SafeSqlFragment.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Editor and RLS tester show loading states for inferred/generated SQL
and include a dedicated user SQL editor for safer edits.

* **Refactor**
* Platform-wide SQL handling tightened: snippets and AI-generated SQL
are treated as untrusted/display-only until promoted, improving safety
and consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-04 13:08:06 -04:00

48 lines
1.5 KiB
TypeScript

import {
filterProtectedSchemaIndexAdvisorResult,
queryInvolvesProtectedSchemas,
} from '../IndexAdvisor/index-advisor.utils'
import { QueryPerformanceRow } from '../QueryPerformance.types'
export const transformStatementDataToRows = (
data: QueryPerformanceRow[],
filterIndexAdvisor: boolean = false
): QueryPerformanceRow[] => {
if (!data || data.length === 0) return []
const totalTimeAcrossAllQueries = data.reduce((sum, row) => sum + (row.total_time || 0), 0)
return data
.map((row) => {
const filteredIndexAdvisorResult = row.index_advisor_result
? filterProtectedSchemaIndexAdvisorResult(row.index_advisor_result)
: null
return {
query: row.query,
rolname: row.rolname || undefined,
calls: row.calls || 0,
mean_time: row.mean_time || 0,
min_time: row.min_time || 0,
max_time: row.max_time || 0,
total_time: row.total_time || 0,
rows_read: row.rows_read || 0,
cache_hit_rate: row.cache_hit_rate || 0,
prop_total_time:
totalTimeAcrossAllQueries > 0 ? (row.total_time / totalTimeAcrossAllQueries) * 100 : 0,
index_advisor_result: filteredIndexAdvisorResult,
}
})
.filter((row) => {
if (filterIndexAdvisor) {
const hasValidRecommendations = row.index_advisor_result !== null
const involvesProtectedSchemas = queryInvolvesProtectedSchemas(row.query)
if (involvesProtectedSchemas && !hasValidRecommendations) {
return false
}
}
return true
})
}