From 49b246089affe44461cde8d619240ab918c7675c Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Fri, 7 Jun 2024 16:17:38 -0600 Subject: [PATCH] feat(db-playground): pglite poc --- apps/database-playground/app/globals.css | 9 - apps/database-playground/app/page.tsx | 230 ++++++++++++++++------- apps/database-playground/next.config.mjs | 16 +- 3 files changed, 177 insertions(+), 78 deletions(-) diff --git a/apps/database-playground/app/globals.css b/apps/database-playground/app/globals.css index 2c606eb7f3e..29e8149ae1c 100644 --- a/apps/database-playground/app/globals.css +++ b/apps/database-playground/app/globals.css @@ -139,15 +139,6 @@ main { } } -.monaco-editor, -.monaco-diff-editor { - --vscode-editor-background: hsl(var(--background-alternative)) !important; - --vscode-editorGutter-background: hsl(var(--background-alternative)) !important; - padding-top: 12px; -} - -/* .monaco-editor .overflow-guard */ - .shimmering-loader { animation: shimmer 2s infinite linear; background: linear-gradient( diff --git a/apps/database-playground/app/page.tsx b/apps/database-playground/app/page.tsx index 34d926bff6c..ab426d06540 100644 --- a/apps/database-playground/app/page.tsx +++ b/apps/database-playground/app/page.tsx @@ -1,20 +1,68 @@ 'use client' +import { PGlite } from '@electric-sql/pglite' +import { Editor } from '@monaco-editor/react' import { FunctionBinding, executeJS } from 'ai-sandbox' import { useChat } from 'ai/react' +import { codeBlock } from 'common-tags' import { ArrowUp } from 'lucide-react' -import { useMemo } from 'react' +import { useMemo, useState } from 'react' import ReactMarkdown from 'react-markdown' import rehypeKatex from 'rehype-katex' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' +import { format } from 'sql-formatter' import { CodeBlock, markdownComponents } from 'ui' import { Button } from 'ui/src/components/shadcn/ui/button' import { Input } from 'ui/src/components/shadcn/ui/input' +// 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 default function Page() { + const [sql, setSql] = useState('') + const functionBindings: Record = useMemo(() => { - return {} + return { + runSql: { + description: codeBlock` + Runs Postgres SQL. + + type Row = T; + type Results = { + rows: Row[]; + affectedRows?: number; + fields: { + name: string; + dataTypeID: number; + }[]; + }; + `, + typeDef: '(sql: string): Promise', + fn: async (sql: string) => { + setSql((s) => { + const newSql = (s + '\n' + sql).trim() + return format(newSql, { + language: 'postgresql', + keywordCase: 'lower', + identifierCase: 'lower', + dataTypeCase: 'lower', + functionCase: 'lower', + }) + }) + + console.log('about to exec') + const results = await db.exec(sql) + console.log('after exec') + return results + }, + }, + } }, []) const expose = useMemo(() => { @@ -56,78 +104,126 @@ export default function Page() { }) return ( -
-
-
- {messages.map((message) => { - switch (message.role) { - case 'user': - return ( -
- {message.content} -
- ) - case 'assistant': - return ( -
- +
+ { + // Register pgsql formatter + monaco.languages.registerDocumentFormattingEditProvider('pgsql', { + async provideDocumentFormattingEdits(model) { + const currentCode = editor.getValue() + const formattedCode = format(currentCode, { + language: 'postgresql', + keywordCase: 'lower', + }) + return [ + { + range: model.getFullModelRange(), + text: formattedCode, + }, + ] + }, + }) + + // Format on cmd+s + editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, async () => { + await editor.getAction('editor.action.formatDocument').run() + }) + + // Run format on the initial value + await editor.getAction('editor.action.formatDocument').run() + }} + /> +
+
+
+
+ {messages.map((message) => { + switch (message.role) { + case 'user': + return ( +
{message.content} - - {message.toolInvocations && - message.toolInvocations.map((invocation) => ( -
-
-

JavaScript (Interpreter)

-
-
-
- - {invocation.args.source} - +
+ ) + case 'assistant': + return ( +
+ + {message.content} + + {message.toolInvocations && + message.toolInvocations.map((invocation) => ( +
+
+

JavaScript (Interpreter)

- {'result' in invocation && ( -
- - {JSON.stringify(invocation.result, undefined, 2)} +
+
+ + {invocation.args.source}
- )} + {'result' in invocation && ( +
+ + {JSON.stringify(invocation.result, undefined, 2)} + +
+ )} +
-
- ))} -
- ) - } - })} + ))} +
+ ) + } + })} +
-
-
-
- - -
-
- AI can make mistakes. Check import information. +
+
+ + +
+
+ AI can make mistakes. Check import information. +
diff --git a/apps/database-playground/next.config.mjs b/apps/database-playground/next.config.mjs index 4678774e6d6..49ccd0f779e 100644 --- a/apps/database-playground/next.config.mjs +++ b/apps/database-playground/next.config.mjs @@ -1,4 +1,16 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + webpack: (config) => { + config.resolve = { + ...config.resolve, + fallback: { + fs: false, + module: false, + }, + } -export default nextConfig; + return config + }, +} + +export default nextConfig