mirror of
https://github.com/supabase/supabase.git
synced 2026-05-11 19:26:38 +08:00
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 -->
48 lines
1.5 KiB
TypeScript
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
|
|
})
|
|
}
|