Add description (optional) to SQL query

This commit is contained in:
Will Chen
2025-04-23 12:37:30 -07:00
parent 1d0176d1e9
commit 09deb98ba1
6 changed files with 50 additions and 19 deletions

View File

@@ -38,6 +38,7 @@ import {
SuggestedAction,
ProposalResult,
FileChange,
SqlQuery,
} from "@/lib/schemas";
import type { Message } from "@/ipc/ipc_types";
import { isPreviewOpenAtom } from "@/atoms/viewAtoms";
@@ -547,7 +548,7 @@ function ProposalSummary({
packagesAdded = [],
filesChanged = [],
}: {
sqlQueries?: string[];
sqlQueries?: Array<SqlQuery>;
serverFunctions?: FileChange[];
packagesAdded?: string[];
filesChanged?: FileChange[];
@@ -600,9 +601,12 @@ function ProposalSummary({
}
// SQL Query item with expandable functionality
function SqlQueryItem({ query }: { query: string }) {
function SqlQueryItem({ query }: { query: SqlQuery }) {
const [isExpanded, setIsExpanded] = useState(false);
const queryContent = query.content;
const queryDescription = query.description;
return (
<li
className="bg-(--background-lightest) hover:bg-(--background-lighter) rounded-lg px-3 py-2 border border-border cursor-pointer"
@@ -611,7 +615,9 @@ function SqlQueryItem({ query }: { query: string }) {
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Database size={16} className="text-muted-foreground flex-shrink-0" />
<span className="text-sm font-medium">SQL Query</span>
<span className="text-sm font-medium">
{queryDescription || "SQL Query"}
</span>
</div>
<div>
{isExpanded ? (
@@ -623,7 +629,9 @@ function SqlQueryItem({ query }: { query: string }) {
</div>
{isExpanded && (
<div className="mt-2 text-xs max-h-[200px] overflow-auto">
<CodeHighlight className="language-sql ">{query}</CodeHighlight>
<CodeHighlight className="language-sql ">
{queryContent}
</CodeHighlight>
</div>
)}
</li>

View File

@@ -14,16 +14,19 @@ import { CustomTagState } from "./stateTypes";
interface DyadExecuteSqlProps {
children?: ReactNode;
node?: any;
description?: string;
}
export const DyadExecuteSql: React.FC<DyadExecuteSqlProps> = ({
children,
node,
description,
}) => {
const [isContentVisible, setIsContentVisible] = useState(false);
const state = node?.properties?.state as CustomTagState;
const inProgress = state === "pending";
const aborted = state === "aborted";
const queryDescription = description || node?.properties?.description;
return (
<div
@@ -40,7 +43,7 @@ export const DyadExecuteSql: React.FC<DyadExecuteSqlProps> = ({
<div className="flex items-center gap-2">
<Database size={16} />
<span className="text-gray-700 dark:text-gray-300 font-medium text-sm">
SQL Query
{queryDescription || "SQL Query"}
</span>
{inProgress && (
<div className="flex items-center text-amber-600 text-xs">

View File

@@ -3,6 +3,7 @@ import type {
CodeProposal,
FileChange,
ProposalResult,
SqlQuery,
} from "../../lib/schemas";
import { db } from "../../db";
import { messages } from "../../db/schema";
@@ -105,7 +106,11 @@ const getProposalHandler = async (
})),
];
// Check if we have enough information to create a proposal
if (filesChanged.length > 0 || packagesAdded.length > 0) {
if (
filesChanged.length > 0 ||
packagesAdded.length > 0 ||
proposalExecuteSqlQueries.length > 0
) {
const proposal: CodeProposal = {
type: "code-proposal",
// Use parsed title or a default title if summary tag is missing but write tags exist
@@ -113,7 +118,10 @@ const getProposalHandler = async (
securityRisks: [], // Keep empty
filesChanged,
packagesAdded,
sqlQueries: proposalExecuteSqlQueries,
sqlQueries: proposalExecuteSqlQueries.map((query) => ({
content: query.content,
description: query.description,
})),
};
logger.log(
"Generated code proposal. title=",

View File

@@ -15,6 +15,7 @@ import {
executeSupabaseSql,
} from "../../supabase_admin/supabase_management_client";
import { isServerFunction } from "../../supabase_admin/supabase_utils";
import { SqlQuery } from "../../lib/schemas";
const readFile = fs.promises.readFile;
const logger = log.scope("response_processor");
@@ -108,14 +109,18 @@ export function getDyadChatSummaryTag(fullResponse: string): string | null {
return null;
}
export function getDyadExecuteSqlTags(fullResponse: string): string[] {
export function getDyadExecuteSqlTags(fullResponse: string): SqlQuery[] {
const dyadExecuteSqlRegex =
/<dyad-execute-sql>([\s\S]*?)<\/dyad-execute-sql>/g;
/<dyad-execute-sql([^>]*)>([\s\S]*?)<\/dyad-execute-sql>/g;
const descriptionRegex = /description="([^"]+)"/;
let match;
const queries: string[] = [];
const queries: { content: string; description?: string }[] = [];
while ((match = dyadExecuteSqlRegex.exec(fullResponse)) !== null) {
let content = match[1].trim();
const attributesString = match[1] || "";
let content = match[2].trim();
const descriptionMatch = descriptionRegex.exec(attributesString);
const description = descriptionMatch?.[1];
// Handle markdown code blocks if present
const contentLines = content.split("\n");
@@ -127,7 +132,7 @@ export function getDyadExecuteSqlTags(fullResponse: string): string[] {
}
content = contentLines.join("\n");
queries.push(content);
queries.push({ content, description });
}
return queries;
@@ -209,11 +214,11 @@ export async function processFullResponseActions(
try {
const result = await executeSupabaseSql({
supabaseProjectId: chatWithApp.app.supabaseProjectId!,
query,
query: query.content,
});
} catch (error) {
errors.push({
message: `Failed to execute SQL query: ${query}`,
message: `Failed to execute SQL query: ${query.content}`,
error: error,
});
}

View File

@@ -132,13 +132,18 @@ export interface FileChange {
isServerFunction: boolean;
}
export interface SqlQuery {
content: string;
description?: string;
}
export interface CodeProposal {
type: "code-proposal";
title: string;
securityRisks: SecurityRisk[];
filesChanged: FileChange[];
packagesAdded: string[];
sqlQueries: string[];
sqlQueries: SqlQuery[];
}
export interface SuggestedAction {

View File

@@ -89,12 +89,14 @@ function Login() {
## Database
If the user wants to use the database, use the following code:
If the user wants to use the database, use the following syntax:
<dyad-execute-sql>
<dyad-execute-sql description="Get all users">
SELECT * FROM users;
</dyad-execute-sql>
The description should be a short description of what the code is doing and be understandable by semi-technical users.
You will need to setup the database schema.
## Creating User Profiles
@@ -103,7 +105,7 @@ If the user wants to create a user profile, use the following code:
### Create profiles table in public schema
<dyad-execute-sql>
<dyad-execute-sql description="Create profiles table in public schema">
CREATE TABLE public.profiles (
id UUID NOT NULL REFERENCES auth.users ON DELETE CASCADE,
first_name TEXT,
@@ -130,7 +132,7 @@ create policy "Users can update own profile." on profiles for update using ( aut
### Function to insert profile when user signs up
<dyad-execute-sql>
<dyad-execute-sql description="Create function to insert profile when user signs up">
CREATE FUNCTION public.handle_new_user()
RETURNS TRIGGER
LANGUAGE PLPGSQL