From cf94fc85c05bb60722cca18328d20ab82ec790aa Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Wed, 12 Jun 2024 15:43:30 -0600 Subject: [PATCH] feat(db-playground): schema visualizer --- .../database-playground/app/api/chat/route.ts | 6 - apps/database-playground/app/layout.tsx | 5 +- apps/database-playground/app/page.tsx | 52 +- .../components/providers.tsx | 10 + .../components/schema/graph.tsx | 291 +++++ .../components/schema/legend.tsx | 37 + .../data/tables/tables-query.ts | 36 + apps/database-playground/lib/pg-meta.ts | 474 +++++++++ apps/database-playground/package.json | 4 + package-lock.json | 990 ++++++++++++++---- 10 files changed, 1660 insertions(+), 245 deletions(-) create mode 100644 apps/database-playground/components/providers.tsx create mode 100644 apps/database-playground/components/schema/graph.tsx create mode 100644 apps/database-playground/components/schema/legend.tsx create mode 100644 apps/database-playground/data/tables/tables-query.ts create mode 100644 apps/database-playground/lib/pg-meta.ts diff --git a/apps/database-playground/app/api/chat/route.ts b/apps/database-playground/app/api/chat/route.ts index 045886608a9..ad175fc8f56 100644 --- a/apps/database-playground/app/api/chat/route.ts +++ b/apps/database-playground/app/api/chat/route.ts @@ -55,7 +55,6 @@ export async function POST(req: Request) { description: codeBlock` Generates a chart using Chart.js for a given SQL query. - Label both axises - - Line charts should default to \`cubicInterpolationMode: 'monotone'\` - Plugins are not available Call \`executeSql\` first. @@ -68,11 +67,6 @@ export async function POST(req: Request) { ), }), }, - appendSqlToMigration: { - description: - 'Appends schema changes to a SQL migration file. Always call this after modifying database structure.', - parameters: z.object({ sql: z.string() }), - }, }, }) diff --git a/apps/database-playground/app/layout.tsx b/apps/database-playground/app/layout.tsx index 694195a8460..7c4c4746c4a 100644 --- a/apps/database-playground/app/layout.tsx +++ b/apps/database-playground/app/layout.tsx @@ -4,6 +4,7 @@ import './globals.css' import type { Metadata } from 'next' import { Inter } from 'next/font/google' import { cn } from 'ui' +import Providers from '~/components/providers' const inter = Inter({ subsets: ['latin'] }) @@ -19,7 +20,9 @@ export default function RootLayout({ }>) { return ( - {children} + + {children} + ) } diff --git a/apps/database-playground/app/page.tsx b/apps/database-playground/app/page.tsx index 72686eabb3e..23e10d82f74 100644 --- a/apps/database-playground/app/page.tsx +++ b/apps/database-playground/app/page.tsx @@ -4,6 +4,7 @@ import 'chartjs-adapter-date-fns' import { PGlite } from '@electric-sql/pglite' import { Editor } from '@monaco-editor/react' +import { useQueryClient } from '@tanstack/react-query' import { nanoid } from 'ai' import { useChat } from 'ai/react' import Chart from 'chart.js/auto' @@ -20,13 +21,14 @@ import remarkMath from 'remark-math' import { format } from 'sql-formatter' import { AiIconAnimation, markdownComponents } from 'ui' import { Button } from 'ui/src/components/shadcn/ui/button' +import SchemaGraph from '~/components/schema/graph' import { Report } from './api/chat/route' const loadFramerFeatures = () => import('./framer-features').then((res) => res.default) // React's double-rendering in dev mode causes pglite errors // Temp: storing single instance in module scope -let db: PGlite = new PGlite('idb://local') +export let db: PGlite = new PGlite('idb://local') function useReportSuggestions(db: PGlite) { const [schema, setSchema] = useState() @@ -87,10 +89,12 @@ export default function Page() { const [isEditorVisible, setIsEditorVisible] = useState(false) const { reports } = useReportSuggestions(db) + const queryClient = useQueryClient() + const { messages, input, setInput, handleInputChange, handleSubmit, append, stop, isLoading } = useChat({ api: 'api/chat', - maxToolRoundtrips: 5, + maxToolRoundtrips: 10, async onToolCall({ toolCall }) { console.log('tool call', toolCall) switch (toolCall.toolName) { @@ -112,6 +116,22 @@ export default function Page() { const { sql } = toolCall.args as any console.log(sql) const results = await db.exec(sql) + + setSql((s) => { + const newSql = (s + '\n' + sql).trim() + return format(newSql, { + language: 'postgresql', + keywordCase: 'lower', + identifierCase: 'lower', + dataTypeCase: 'lower', + functionCase: 'lower', + }) + }) + + queryClient.invalidateQueries({ + queryKey: ['tables'], + }) + console.log(results) return results } catch (err) { @@ -147,24 +167,6 @@ export default function Page() { canvas.remove() } } - case 'appendSqlToMigration': { - const { sql } = toolCall.args as any - setSql((s) => { - const newSql = (s + '\n' + sql).trim() - return format(newSql, { - language: 'postgresql', - keywordCase: 'lower', - identifierCase: 'lower', - dataTypeCase: 'lower', - functionCase: 'lower', - }) - }) - setIsEditorVisible(true) - return { - success: true, - message: 'SQL has successfully been appended to the migration file.', - } - } } }, }) @@ -186,7 +188,10 @@ export default function Page() { return ( -
+
+
+ +
{isEditorVisible && (
)}