From 6c4ca8e6e500e2ac947797b6899ffed681cd8112 Mon Sep 17 00:00:00 2001 From: Michael Ionov Date: Sat, 14 Oct 2023 14:39:38 +0300 Subject: [PATCH] feat: pass data to frontend --- .eslintrc.cjs | 12 +- src-tauri/src/handlers/queries.rs | 2 +- src-tauri/src/queues/query.rs | 65 +++--- src-tauri/src/utils/fs.rs | 2 +- src/App.tsx | 52 +++-- .../Console/Content/QueryTab/QueryTab.tsx | 4 +- .../Content/QueryTab/QueryTextArea.tsx | 91 ++++---- .../Content/QueryTab/ResultesTable.tsx | 165 +++++++------- src/interfaces.ts | 204 +++++++++--------- src/services/Connections.ts | 42 +++- 10 files changed, 361 insertions(+), 278 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ed227d0..d793b77 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -22,8 +22,18 @@ module.exports = { }, plugins: ['@typescript-eslint'], rules: { - indent: ['error', 2], + indent: ['error', 2, { SwitchCase: 1 }], 'linebreak-style': ['error', 'unix'], semi: ['error', 'always'], + 'no-unused-vars': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-unused-vars': [ + 'warn', // or "error" + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }, + ], }, }; diff --git a/src-tauri/src/handlers/queries.rs b/src-tauri/src/handlers/queries.rs index 6074357..da1160c 100644 --- a/src-tauri/src/handlers/queries.rs +++ b/src-tauri/src/handlers/queries.rs @@ -63,7 +63,7 @@ pub async fn enqueue_query( return Ok(QueryTaskEnqueueResult { conn_id, tab_idx, - status: QueryTaskStatus::Queued, + status: QueryTaskStatus::Progress, results_sets: statements.iter().map(|s| s.1.clone()).collect(), }); } diff --git a/src-tauri/src/queues/query.rs b/src-tauri/src/queues/query.rs index fcb547f..f5aa1d0 100644 --- a/src-tauri/src/queues/query.rs +++ b/src-tauri/src/queues/query.rs @@ -21,7 +21,6 @@ impl Events { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum QueryTaskStatus { - Queued, Progress, Completed, Error, @@ -29,7 +28,7 @@ pub enum QueryTaskStatus { impl Default for QueryTaskStatus { fn default() -> Self { - QueryTaskStatus::Queued + QueryTaskStatus::Progress } } @@ -57,7 +56,7 @@ impl QueryTask { tab_idx, query_idx, query: query.to_string(), - status: QueryTaskStatus::Queued, + status: QueryTaskStatus::Progress, } } } @@ -89,38 +88,36 @@ pub async fn async_process_model( while let Some(input) = input_rx.recv().await { let task = input; match task.conn.execute_query(&task.query).await { - Ok(result_set) => { - match write_query(&task.id, result_set) { - Ok(path) => { - output_tx - .send(QueryTaskResult { - conn_id: task.conn.config.id.to_string(), - status: QueryTaskStatus::Completed, - query: task.query, - id: task.id, - query_idx: task.query_idx, - tab_idx: task.tab_idx, - path: Some(path), - error: None, - }) - .await? - } - Err(e) => { - output_tx - .send(QueryTaskResult { - conn_id: task.conn.config.id.to_string(), - status: QueryTaskStatus::Error, - query: task.query, - id: task.id, - query_idx: task.query_idx, - tab_idx: task.tab_idx, - path: None, - error: Some(e.to_string()), - }) - .await? - } + Ok(result_set) => match write_query(&task.id, result_set) { + Ok(path) => { + output_tx + .send(QueryTaskResult { + conn_id: task.conn.config.id.to_string(), + status: QueryTaskStatus::Completed, + query: task.query, + id: task.id, + query_idx: task.query_idx, + tab_idx: task.tab_idx, + path: Some(path), + error: None, + }) + .await? } - } + Err(e) => { + output_tx + .send(QueryTaskResult { + conn_id: task.conn.config.id.to_string(), + status: QueryTaskStatus::Error, + query: task.query, + id: task.id, + query_idx: task.query_idx, + tab_idx: task.tab_idx, + path: None, + error: Some(e.to_string()), + }) + .await? + } + }, Err(e) => { output_tx .send(QueryTaskResult { diff --git a/src-tauri/src/utils/fs.rs b/src-tauri/src/utils/fs.rs index 6759f2b..91765a7 100644 --- a/src-tauri/src/utils/fs.rs +++ b/src-tauri/src/utils/fs.rs @@ -66,7 +66,7 @@ pub fn write_file(path: &PathBuf, content: &str) -> Result<()> { pub fn write_query(id: &str, result_set: ResultSet) -> Result { let rows = json!(result_set.rows).to_string(); let metadata = json!({ - "rows": result_set.rows.len(), + "count": result_set.rows.len(), "affected_rows": result_set.affected_rows, "warnings": result_set.warnings, "info": result_set.info, diff --git a/src/App.tsx b/src/App.tsx index 2517533..092a9be 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,14 +1,15 @@ -import "utils/i18n"; -import "tabulator-tables/dist/css/tabulator_midnight.min.css"; -import "solid-command-palette/pkg-dist/style.css"; -import { Main } from "components/Screens/Main"; -import { CommandPaletteContext } from "components/CommandPalette/CommandPaletteContext"; -import { Loader } from "components/UI"; -import { createEffect, createSignal, onMount } from "solid-js"; -import { useAppSelector } from "services/Context"; -import { listen } from "@tauri-apps/api/event"; -import { Events, QueryTaskResult } from "interfaces"; -import { log } from "utils/utils"; +import 'utils/i18n'; +import 'tabulator-tables/dist/css/tabulator_midnight.min.css'; +import 'solid-command-palette/pkg-dist/style.css'; +import { Main } from 'components/Screens/Main'; +import { CommandPaletteContext } from 'components/CommandPalette/CommandPaletteContext'; +import { Loader } from 'components/UI'; +import { createEffect, createSignal, onMount } from 'solid-js'; +import { useAppSelector } from 'services/Context'; +import { listen } from '@tauri-apps/api/event'; +import { Events, QueryMetadataResult, QueryTaskResult, Row } from 'interfaces'; +import { log } from 'utils/utils'; +import { invoke } from '@tauri-apps/api'; function App() { const [loading, setLoading] = createSignal(true); @@ -16,6 +17,7 @@ function App() { connections: { restoreConnectionStore, getConnection, + updateResultSet, contentStore: { idx }, queryIdx, }, @@ -28,27 +30,45 @@ function App() { }, 500); }); - const getQueryResults = () => { }; + const getQueryMetadata = (path: string) => + invoke('get_query_metadata', { path }); - const compareAndAssign = (event: QueryTaskResult) => { + const getInitialQueryResults = (path: string) => { + // TODO: move page size to global store + return invoke('query_results', { + params: { path, page: 0, page_size: 20 }, + }); + }; + + const compareAndAssign = async (event: QueryTaskResult) => { if ( getConnection().id === event.conn_id && idx === event.tab_idx && queryIdx() === event.query_idx ) { // TODO: should get 0 page of results + if (event.status === 'Completed') { + const res = await getInitialQueryResults(event.path); + const md_res = await getQueryMetadata(event.path); + const rows = JSON.parse(res) as Row[]; + const metadata = JSON.parse(md_res) as QueryMetadataResult; + updateResultSet(event.tab_idx, event.query_idx, { rows, ...metadata }); + } else if (event.status === 'Error') { + updateResultSet(event.tab_idx, event.query_idx, { info: event.error }); + } } + // setContentStore('tabs', idx ?? contentStore.idx, key, data); }; onMount(async () => { - await listen(Events.QueryFinished, (event) => { + await listen(Events.QueryFinished, async (event) => { log(event); - compareAndAssign(event.payload); + await compareAndAssign(event.payload); }); }); onMount(async () => { - const theme = localStorage.getItem("theme") || "dark"; + const theme = localStorage.getItem('theme') || 'dark'; document.documentElement.dataset.theme = theme; await restoreAppStore(); await restoreConnectionStore(); diff --git a/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx b/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx index 9c75272..ebaf18e 100644 --- a/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx +++ b/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx @@ -19,11 +19,11 @@ export const QueryTab = () => { }); return ( -
+
-
+
diff --git a/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx b/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx index 3784d12..af2d3cd 100644 --- a/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx +++ b/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx @@ -2,31 +2,31 @@ import { createCodeMirror, createEditorControlledValue, createEditorFocus, -} from "solid-codemirror"; -import { createEffect, createSignal, Show } from "solid-js"; +} from 'solid-codemirror'; +import { createEffect, createSignal, Show } from 'solid-js'; import { EditorView, drawSelection, highlightWhitespace, highlightActiveLine, -} from "@codemirror/view"; -import { MySQL, sql } from "@codemirror/lang-sql"; -import { dracula } from "@uiw/codemirror-theme-dracula"; -import { vim } from "@replit/codemirror-vim"; -import { format } from "sql-formatter"; -import { invoke } from "@tauri-apps/api"; -import { Copy, EditIcon, FireIcon, VimIcon } from "components/UI/Icons"; -import { useAppSelector } from "services/Context"; -import { QueryTaskEnqueueResult } from "interfaces"; -import { t } from "utils/i18n"; -import { Alert } from "components/UI"; -import { basicSetup } from "codemirror"; -import { createShortcut } from "@solid-primitives/keyboard"; -import { search } from "@codemirror/search"; -import { createStore } from "solid-js/store"; -import { ActionRowButton } from "./components/ActionRowButton"; +} from '@codemirror/view'; +import { MySQL, sql } from '@codemirror/lang-sql'; +import { dracula } from '@uiw/codemirror-theme-dracula'; +import { vim } from '@replit/codemirror-vim'; +import { format } from 'sql-formatter'; +import { invoke } from '@tauri-apps/api'; +import { Copy, EditIcon, FireIcon, VimIcon } from 'components/UI/Icons'; +import { useAppSelector } from 'services/Context'; +import { QueryTaskEnqueueResult } from 'interfaces'; +import { t } from 'utils/i18n'; +import { Alert } from 'components/UI'; +import { basicSetup } from 'codemirror'; +import { createShortcut } from '@solid-primitives/keyboard'; +import { search } from '@codemirror/search'; +import { createStore } from 'solid-js/store'; +import { ActionRowButton } from './components/ActionRowButton'; -import { log } from "utils/utils"; +import { log } from 'utils/utils'; export const QueryTextArea = () => { const { @@ -40,13 +40,13 @@ export const QueryTextArea = () => { }, app: { vimModeOn, toggleVimModeOn }, } = useAppSelector(); - const [code, setCode] = createSignal(""); + const [code, setCode] = createSignal(''); const [schema, setSchema] = createStore({}); const [loading, setLoading] = createSignal(false); const [autoLimit, setAutoLimit] = createSignal(true); const updateQueryText = async (query: string) => { - updateContentTab("data", { query }); + updateContentTab('data', { query }); }; const { ref, editorView, createExtension } = createCodeMirror({ @@ -92,19 +92,28 @@ export const QueryTextArea = () => { if (loading() || !code()) return; setLoading(true); const selectedText = getSelection(); - updateContentTab("error", undefined); + updateContentTab('error', undefined); const activeConnection = getConnection(); try { - const result = await invoke("enqueue_query", { - connId: activeConnection.id, - sql: selectedText || code(), - autoLimit: autoLimit(), - tabIdx, + const { results_sets } = await invoke( + 'enqueue_query', + { + connId: activeConnection.id, + sql: selectedText || code(), + autoLimit: autoLimit(), + tabIdx, + } + ); + updateContentTab('data', { + query: code(), + executed: true, + result_sets: results_sets.map((id) => ({ + id, + })), }); - // updateContentTab("data", { query: code(), executed: true, result_sets }); - log({ result }); + log({ results_sets }); } catch (error) { - updateContentTab("error", String(error)); + updateContentTab('error', String(error)); } finally { setLoading(false); } @@ -115,7 +124,7 @@ export const QueryTextArea = () => { }; createEffect(() => { - setCode(getContentData("Query").query ?? ""); + setCode(getContentData('Query').query ?? ''); setSchema( getSchemaTables().reduce( (acc, table) => ({ @@ -127,40 +136,40 @@ export const QueryTextArea = () => { ); }); - createShortcut(["Control", "e"], onExecute); - createShortcut(["Control", "l"], () => setFocused(true)); - createShortcut(["Control", "Shift", "F"], onFormat); + createShortcut(['Control', 'e'], onExecute); + createShortcut(['Control', 'l'], () => setFocused(true)); + createShortcut(['Control', 'Shift', 'F'], onFormat); return (
} /> } /> } />