diff --git a/core/src/databases/database.rs b/core/src/databases/database.rs index bff04be3c5f8..6cb37c9a8c0f 100644 --- a/core/src/databases/database.rs +++ b/core/src/databases/database.rs @@ -63,7 +63,7 @@ impl Database { .par_iter() .map(|(table, r)| { Ok(( - table.table_id().to_string(), + table.name().to_string(), DatabaseSchemaTable::new(table.clone(), TableSchema::from_rows(&r)?), )) }) @@ -95,7 +95,7 @@ impl Database { let rows_by_table = match self.get_rows(store.clone()).await { Ok(rows) => Ok(rows .into_iter() - .map(|(table, rows)| (table.table_id().to_string(), rows)) + .map(|(table, rows)| (table.name().to_string(), rows)) .collect::>()), _ => Err(anyhow!("Error retrieving rows from database.")), }?; diff --git a/front/components/app/NewBlock.tsx b/front/components/app/NewBlock.tsx index 2fa21d8f0993..2a68f74fb9eb 100644 --- a/front/components/app/NewBlock.tsx +++ b/front/components/app/NewBlock.tsx @@ -95,6 +95,12 @@ export default function NewBlock({ name: "While End", description: "Loop over a set of blocks until a condition is met.", }, + { + type: "database", + typeNames: ["database"], + name: "Database", + description: "Query a database.", + }, { type: "database_schema", typeNames: ["database_schema"], diff --git a/front/components/app/SpecRunView.tsx b/front/components/app/SpecRunView.tsx index fd002e36976a..0ef5d9652eb0 100644 --- a/front/components/app/SpecRunView.tsx +++ b/front/components/app/SpecRunView.tsx @@ -11,6 +11,7 @@ import Chat from "./blocks/Chat"; import Code from "./blocks/Code"; import Curl from "./blocks/Curl"; import Data from "./blocks/Data"; +import Database from "./blocks/Database"; import DatabaseSchema from "./blocks/DatabaseSchema"; import DataSource from "./blocks/DataSource"; import Input from "./blocks/Input"; @@ -356,6 +357,26 @@ export default function SpecRunView({ /> ); + case "database": + return ( + handleSetBlock(idx, block)} + onBlockDelete={() => handleDeleteBlock(idx)} + onBlockUp={() => handleMoveBlockUp(idx)} + onBlockDown={() => handleMoveBlockDown(idx)} + onBlockNew={(blockType) => handleNewBlock(idx, blockType)} + /> + ); + default: return ((t: never) => (
diff --git a/front/components/app/blocks/Database.tsx b/front/components/app/blocks/Database.tsx new file mode 100644 index 000000000000..5c39a719b1c8 --- /dev/null +++ b/front/components/app/blocks/Database.tsx @@ -0,0 +1,164 @@ +import "@uiw/react-textarea-code-editor/dist.css"; + +import dynamic from "next/dynamic"; + +import DataSourcePicker from "@app/components/data_source/DataSourcePicker"; +import DatabasePicker from "@app/components/database/DatabasePicker"; +import { classNames, shallowBlockClone } from "@app/lib/utils"; +import { SpecificationBlockType, SpecificationType } from "@app/types/app"; +import { AppType } from "@app/types/app"; +import { BlockType } from "@app/types/run"; +import { RunType } from "@app/types/run"; +import { WorkspaceType } from "@app/types/user"; + +import Block from "./Block"; + +const CodeEditor = dynamic( + () => import("@uiw/react-textarea-code-editor").then((mod) => mod.default), + { ssr: false } +); + +export default function Database({ + owner, + app, + spec, + run, + block, + status, + running, + readOnly, + onBlockUpdate, + onBlockDelete, + onBlockUp, + onBlockDown, + onBlockNew, +}: React.PropsWithChildren<{ + owner: WorkspaceType; + app: AppType; + spec: SpecificationType; + run: RunType | null; + block: SpecificationBlockType; + status: any; + running: boolean; + readOnly: boolean; + onBlockUpdate: (block: SpecificationBlockType) => void; + onBlockDelete: () => void; + onBlockUp: () => void; + onBlockDown: () => void; + onBlockNew: (blockType: BlockType | "map_reduce" | "while_end") => void; +}>) { + return ( + +
+
+
+
+ Database: +
+
+ { + if (dataSources.length === 0) { + return; + } + const ds = dataSources[0]; + const b = shallowBlockClone(block); + b.config.database = { + workspace_id: ds.workspace_id, + data_source_id: ds.data_source_id, + }; + onBlockUpdate(b); + }} + /> +
+
+ {block.config.database?.data_source_id && ( +
+
+ { + const b = shallowBlockClone(block); + b.config.database.database_id = database.database_id; + onBlockUpdate(b); + }} + /> +
+
+ )} +
+ {block.config.database?.database_id && ( +
+
+ query: +
+
+
+
+ { + const b = shallowBlockClone(block); + b.spec.query = e.target.value; + onBlockUpdate(b); + }} + padding={3} + style={{ + color: "rgb(55 65 81)", + fontSize: 13, + fontFamily: + "ui-monospace, SFMono-Regular, SF Mono, Consolas, Liberation Mono, Menlo, monospace", + backgroundColor: "rgb(241 245 249)", + }} + /> +
+
+
+
+ )} +
+
+ ); +} diff --git a/front/lib/config.ts b/front/lib/config.ts index 0e02d7773f00..97a421cf4afb 100644 --- a/front/lib/config.ts +++ b/front/lib/config.ts @@ -97,6 +97,12 @@ export function extractConfig(spec: SpecificationType): BlockRunConfig { database: spec[i].config?.database, }; break; + case "database": + c[spec[i].name] = { + type: "database", + database: spec[i].config?.database, + }; + break; case "data": case "code": case "map": diff --git a/front/lib/specification.ts b/front/lib/specification.ts index 81086a95363c..f2fb1a1cfd42 100644 --- a/front/lib/specification.ts +++ b/front/lib/specification.ts @@ -251,6 +251,17 @@ export function addBlock( config: {}, }); break; + case "database": + s.splice(idx + 1, 0, { + type: "database", + name: getNextName(spec, "DATABASE"), + indent: 0, + spec: { + query: "", + }, + config: {}, + }); + break; default: s.splice(idx + 1, 0, { type: blockType, @@ -568,6 +579,15 @@ export function dumpSpecification( out += "\n"; break; } + case "database": { + out += `database ${block.name} {\n`; + out += ` query: \n\`\`\`\n${escapeTripleBackticks( + block.spec.query + )}\n\`\`\`\n`; + out += `}\n`; + out += "\n"; + break; + } default: ((t: never) => { console.error(`Unknown block type: ${t}`); diff --git a/front/types/run.ts b/front/types/run.ts index 3eabf91aab40..e1feb358f4b9 100644 --- a/front/types/run.ts +++ b/front/types/run.ts @@ -14,7 +14,8 @@ export type BlockType = | "search" | "curl" | "browser" - | "database_schema"; + | "database_schema" + | "database"; export type RunRunType = "deploy" | "local" | "execute"; type Status = "running" | "succeeded" | "errored";