diff --git a/src-tauri/src/database/connections.rs b/src-tauri/src/database/connections.rs index ff855a0..536b71d 100644 --- a/src-tauri/src/database/connections.rs +++ b/src-tauri/src/database/connections.rs @@ -200,6 +200,14 @@ impl ConnectedConnection { // ConnectionPool::Sqlite(_pool) => todo!(), } } + + pub async fn execute_query(&self, q: String) -> Result { + match &self.pool { + ConnectionPool::Mysql(pool) => engine::mysql::query::execute_query(pool, q), + // ConnectionPool::Postgres(_pool) => todo!(), + // ConnectionPool::Sqlite(_pool) => todo!(), + } + } } pub fn add_connection(db: &Connection, conn: &ConnectionConfig) -> Result<()> { diff --git a/src-tauri/src/database/engine/mysql/query.rs b/src-tauri/src/database/engine/mysql/query.rs index 488f050..ac642b5 100644 --- a/src-tauri/src/database/engine/mysql/query.rs +++ b/src-tauri/src/database/engine/mysql/query.rs @@ -1,6 +1,6 @@ use anyhow::Result; use mysql::prelude::Queryable; -use mysql::{PooledConn, Row}; +use mysql::{PooledConn, Row, Pool}; use serde_json::json; use super::utils::convert_value; @@ -17,6 +17,24 @@ pub fn raw_query(mut conn: PooledConn, query: String) -> Result Result { + let mut conn = pool.get_conn()?; + let rows: Vec = conn.query(&query)?; + let mut result = Vec::new(); + for row in rows { + let mut object = json!({}); + for column in row.columns_ref() { + let column_value = &row[column.name_str().as_ref()]; + let value = convert_value(column_value); + object[column.name_str().as_ref()] = value; + } + result.push(object); + } + let result = json!({ "result": result }); + return Ok(result); +} + diff --git a/src-tauri/src/handlers/queries.rs b/src-tauri/src/handlers/queries.rs index 34517b7..058ab9b 100644 --- a/src-tauri/src/handlers/queries.rs +++ b/src-tauri/src/handlers/queries.rs @@ -3,43 +3,42 @@ use crate::{ state::ServiceAccess, utils::error::CommandResult, }; -use log::info; use serde_json::Value; use tauri::{command, AppHandle}; #[command] -pub fn execute_query(_app_handle: AppHandle, query: String) -> CommandResult<()> { - info!("execute_query: {}", query); - println!("{}", sql_lexer::sanitize_string(query.to_string())); - Ok(()) +pub async fn execute_query(app_handle: AppHandle, conn_id: String, query: String) -> CommandResult { + let connection = app_handle.acquire_connection(conn_id); + let result = connection.execute_query(query).await?; + Ok(result) } #[command] pub async fn get_columns(app_handle: AppHandle, conn_id: String) -> CommandResult { let connection = app_handle.acquire_connection(conn_id); - let stats = connection.get_columns().await?; - Ok(stats) + let result = connection.get_columns().await?; + Ok(result) } #[command] pub async fn get_constraints(app_handle: AppHandle, conn_id: String) -> CommandResult { let connection = app_handle.acquire_connection(conn_id); - let stats = connection.get_constraints().await?; - Ok(stats) + let result = connection.get_constraints().await?; + Ok(result) } #[command] pub async fn get_triggers(app_handle: AppHandle, conn_id: String) -> CommandResult { let connection = app_handle.acquire_connection(conn_id); - let stats = connection.get_triggers().await?; - Ok(stats) + let result = connection.get_triggers().await?; + Ok(result) } #[command] pub async fn get_functions(app_handle: AppHandle, conn_id: String) -> CommandResult { let connection = app_handle.acquire_connection(conn_id); - let stats = connection.get_functions().await?; - Ok(stats) + let result = connection.get_functions().await?; + Ok(result) } #[command] diff --git a/src/components/Screens/Console/Content/Content.tsx b/src/components/Screens/Console/Content/Content.tsx index 3c4111f..e0a8070 100644 --- a/src/components/Screens/Console/Content/Content.tsx +++ b/src/components/Screens/Console/Content/Content.tsx @@ -4,7 +4,7 @@ import { AddIcon, CloseIcon } from "components/UI/Icons"; import { t } from "utils/i18n"; import { QueryTab } from "./QueryTab/QueryTab"; import { TableStructureTab } from "./TableStructureTab"; -import { ContentComponent, ContentTab, ContentTabData, NEW_QUERY_TAB } from "services/ConnectionTabs"; +import { ContentComponent, NEW_QUERY_TAB } from "services/ConnectionTabs"; export const Content = () => { const { connectionsService: { contentStore, setContentStore } } = useAppSelector() @@ -14,13 +14,6 @@ export const Content = () => { setContentStore('idx', contentStore.tabs.length - 1) } - const updateQueryText = async (query: string) => { - setContentStore('tabs', contentStore.tabs.map((t, idx) => idx === contentStore.idx ? { - ...t, - data: { ...t.data, query } - } as ContentTab<'QueryTab'> : t)) - } - const closeTab = async (idx: number) => { if (!idx) return; setContentStore('tabs', contentStore.tabs.filter((_t, i) => i !== idx)); @@ -48,7 +41,7 @@ export const Content = () => {
- + diff --git a/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx b/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx index 193ac15..ebf4b01 100644 --- a/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx +++ b/src/components/Screens/Console/Content/QueryTab/QueryTab.tsx @@ -3,7 +3,7 @@ import Split from "split.js" import { QueryTextArea } from "./QueryTextArea" import { ResultsArea } from "./ResultsArea" -export const QueryTab = (props: { query: string, updateQueryText: (s: string) => void }) => { +export const QueryTab = () => { createEffect(() => { const q = Split(['#query', '#results'], { @@ -20,7 +20,7 @@ export const QueryTab = (props: { query: string, updateQueryText: (s: string) => return (
- +
diff --git a/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx b/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx index 36679af..33f1b01 100644 --- a/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx +++ b/src/components/Screens/Console/Content/QueryTab/QueryTextArea.tsx @@ -1,5 +1,5 @@ import { createCodeMirror, createEditorControlledValue } from "solid-codemirror"; -import { createSignal } from "solid-js"; +import { createEffect, createSignal } from "solid-js"; import { lineNumbers } from '@codemirror/view'; import { sql } from '@codemirror/lang-sql' import { dracula } from '@uiw/codemirror-theme-dracula' @@ -7,14 +7,28 @@ import { format } from 'sql-formatter'; import { t } from "i18next"; import { invoke } from '@tauri-apps/api'; import { EditIcon, FireIcon } from "components/UI/Icons"; +import { useAppSelector } from "services/Context"; +import { ContentTab, ContentTabData } from "services/ConnectionTabs"; +import { QueryResult } from "interfaces"; + +export const QueryTextArea = () => { + const { connectionsService: { setActiveContentQueryTabData, contentStore, + setContentStore, getActiveConnection, getActiveContentTab } } = + useAppSelector() + + const updateQueryText = async (query: string) => { + setContentStore('tabs', contentStore.tabs.map((t, idx) => idx === contentStore.idx ? { + ...t, + data: { ...t.data, query } + } as ContentTab<'QueryTab'> : t)) + } -export const QueryTextArea = (props: { query: string, updateQueryText: (s: string) => void }) => { const onInput = (q: string) => { - props.updateQueryText(q) + updateQueryText(q) setCode(q) } - const [code, setCode] = createSignal(props.query); + const [code, setCode] = createSignal(''); const { ref, editorView, createExtension } = createCodeMirror({ onValueChange: onInput }); createEditorControlledValue(editorView, code); createExtension(() => lineNumbers()); @@ -27,9 +41,15 @@ export const QueryTextArea = (props: { query: string, updateQueryText: (s: strin } const onExecute = async () => { - await invoke('execute_query', { query: code() }) + const activeConnection = getActiveConnection() + const { result } = await invoke('execute_query', { connId: activeConnection.id, query: code() }) + setActiveContentQueryTabData({ data: { query: code, results: result } }) } + createEffect(() => { + setCode((getActiveContentTab()?.data as ContentTabData['QueryTab']).query ?? '') + }) + return (
diff --git a/src/components/Screens/Console/Content/QueryTab/ResultsArea.tsx b/src/components/Screens/Console/Content/QueryTab/ResultsArea.tsx index d7eb9fb..7270a63 100644 --- a/src/components/Screens/Console/Content/QueryTab/ResultsArea.tsx +++ b/src/components/Screens/Console/Content/QueryTab/ResultsArea.tsx @@ -1,4 +1,5 @@ -import { For } from "solid-js" +import { useAppSelector } from "services/Context" +import { createEffect, For } from "solid-js" const rows = [ { id: 1, name: 'Snow', calories: 159, fat: 6.0, carbs: 24, protein: 4.0 }, @@ -14,6 +15,10 @@ const rows = [ { id: 11, name: 'Lannister', calories: 237, fat: 9.0, carbs: 37, protein: 4.3 }, ] export const ResultsArea = () => { + const { connectionsService: { getActiveContentTab } } = useAppSelector() + createEffect(() => { + console.log(getActiveContentTab().data) + }) return (
Results
diff --git a/src/components/Screens/Console/Sidebar.tsx b/src/components/Screens/Console/Sidebar.tsx index 3eb9204..b4bc18f 100644 --- a/src/components/Screens/Console/Sidebar.tsx +++ b/src/components/Screens/Console/Sidebar.tsx @@ -1,3 +1,4 @@ +import { Collapse } from "components/UI" import { useAppSelector } from "services/Context" import { createSignal, For, onMount } from "solid-js" import { createStore } from "solid-js/store" @@ -10,18 +11,24 @@ type Table = { }[] } +// TODO: change to icons const TypeToEmoji = { - int: '💯', - char: '🅰️', - json: '📄', - decimal: '💰', - enum: '📚', - varbinary: '📟', + int: '#', + char: 'C', + json: 'J', + decimal: '%', + enum: '@', + varbinary: '*', + datetime: 'D', + tinyint: 'T', + bigint: 'B', + varchar: 'V', + text: 'T', } export const Sidebar = () => { - const { connectionsService: { connectionStore } } = useAppSelector() - const getSchema = () => connectionStore.tabs[connectionStore.idx - 1]?.schema + const { connectionsService: { getActiveConnection } } = useAppSelector() + const getSchema = () => getActiveConnection().schema const [displayedSchema, setDisplayedSchema] = createSignal('') const [tables, setTables] = createStore([]) @@ -48,11 +55,11 @@ export const Sidebar = () => { const emojiType = (t: string) => { const type = t.split('(')[0] - return TypeToEmoji[type as keyof typeof TypeToEmoji] || '📄' + return TypeToEmoji[type as keyof typeof TypeToEmoji] || '' } return ( -
+