mirror of
https://github.com/supabase/supabase.git
synced 2026-09-22 13:37:53 +08:00
501666e504
## Context We previously introduced a behaviour for the explorer home tab's chat form to run a SQL Query if the input is detected to be a SQL query. Adjusting it to shift that behaviour into a secondary action instead <img width="740" height="210" alt="image" src="https://github.com/user-attachments/assets/d4b1fec1-f38c-426f-8108-b50ead1a61ca" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * SQL statements entered in Explorer can be run directly with a dedicated “Run SQL” action. * Assistant forms support context-specific submit icons, labels, tooltips, and accessibility text. * **Bug Fixes** * Improved SQL detection for multi-statement queries. * Prevented mixed SQL and conversational text from being treated as executable SQL. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
49 lines
2.6 KiB
TypeScript
49 lines
2.6 KiB
TypeScript
import { removeCommentsFromSql } from '@/lib/helpers'
|
|
|
|
// [Joshen] `explain` is deliberately excluded even though it's a real SQL keyword - "Explain
|
|
// how RLS works" is a common natural-language prompt, and colliding with it would misroute
|
|
// a normal chat question into a query tab.
|
|
const UNAMBIGUOUS_SQL_STATEMENT_REGEX =
|
|
/^\s*(select|insert|update|delete|alter|drop|truncate|grant|revoke|begin|vacuum|analyze|merge|call|copy|lock|reindex|refresh|execute|prepare|deallocate|comment)\b/i
|
|
|
|
// `create`, `show`, `set`, and `with` are also common natural-language sentence openers
|
|
// ("Create a table for me", "Show me my indexes", "Set up RLS", "With my current schema...").
|
|
// Matching the bare keyword alone would misroute those into a query tab, so each requires
|
|
// syntax that only shows up in the real SQL statement.
|
|
const CREATE_STATEMENT_REGEX =
|
|
/^\s*create\s+(or\s+replace\s+)?(table|unique\s+index|index|view|materialized\s+view|function|procedure|trigger|schema|extension|role|user|policy|type|sequence|database|domain|rule|publication|foreign\s+table)\b/i
|
|
const SHOW_STATEMENT_REGEX = /^\s*show\s+(all|[a-zA-Z_][a-zA-Z0-9_.]*)\s*;?\s*$/i
|
|
const SET_STATEMENT_REGEX =
|
|
/^\s*set\s+(session\s+|local\s+)?(time\s+zone\b|[a-zA-Z_][a-zA-Z0-9_.]*\s*(=|to)\s*\S)/i
|
|
const WITH_STATEMENT_REGEX = /^\s*with\s+(recursive\s+)?[a-zA-Z_][a-zA-Z0-9_]*\s+as\s*\(/i
|
|
|
|
const isSqlLikeSegment = (segment: string): boolean =>
|
|
UNAMBIGUOUS_SQL_STATEMENT_REGEX.test(segment) ||
|
|
CREATE_STATEMENT_REGEX.test(segment) ||
|
|
SHOW_STATEMENT_REGEX.test(segment) ||
|
|
SET_STATEMENT_REGEX.test(segment) ||
|
|
WITH_STATEMENT_REGEX.test(segment)
|
|
|
|
/**
|
|
* Whether `message` looks like a SQL statement rather than a natural-language chat prompt,
|
|
* so the Explorer home tab can route it to a query tab instead of creating an AI chat.
|
|
*/
|
|
export function isSqlStatement(message: string): boolean {
|
|
const sql = removeCommentsFromSql(message).trim()
|
|
|
|
const isSimpleStatement =
|
|
UNAMBIGUOUS_SQL_STATEMENT_REGEX.test(sql) ||
|
|
SHOW_STATEMENT_REGEX.test(sql) ||
|
|
SET_STATEMENT_REGEX.test(sql)
|
|
const isComplexStatement = CREATE_STATEMENT_REGEX.test(sql) || WITH_STATEMENT_REGEX.test(sql)
|
|
|
|
if (isComplexStatement) return true
|
|
if (!isSimpleStatement) return false
|
|
|
|
// Simple statements (select/insert/update/.../show/set) are rarely legitimately
|
|
// multi-paragraph, so a trailing paragraph that doesn't itself look like SQL means
|
|
// this is a chat message that happens to include a query, not a query to run.
|
|
const [, ...trailingParagraphs] = sql.split(/\n\s*\n/)
|
|
return trailingParagraphs.every(isSqlLikeSegment)
|
|
}
|