Skip to content

Commit

Permalink
feat: save query rows and query metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
invm committed Oct 13, 2023
1 parent 84207be commit 508bdd5
Show file tree
Hide file tree
Showing 24 changed files with 336 additions and 290 deletions.
10 changes: 9 additions & 1 deletion src-tauri/src/database/connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,14 @@ impl ConnectionConfig {
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ResultSet {
pub affected_rows: u64,
pub warnings: u16,
pub info: String,
pub rows: Vec<serde_json::Value>,
}

impl ConnectedConnection {
pub async fn new(config: ConnectionConfig) -> Result<Self> {
match &config.scheme {
Expand Down Expand Up @@ -245,7 +253,7 @@ impl ConnectedConnection {
}
}

pub async fn execute_query(&self, q: &str) -> Result<Value> {
pub async fn execute_query(&self, q: &str) -> Result<ResultSet> {
match &self.pool {
ConnectionPool::Mysql(pool) => engine::mysql::query::execute_query(pool, q),
// ConnectionPool::Postgres(_pool) => todo!(),
Expand Down
23 changes: 10 additions & 13 deletions src-tauri/src/database/engine/mysql/query.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
use anyhow::Result;
use mysql::prelude::Queryable;
use mysql::{from_row, Pool, PooledConn, Row};
use serde::{Deserialize, Serialize};
use serde_json::json;

use crate::database::connections::ResultSet;

use super::utils::convert_value;
#[derive(Debug, Serialize, Deserialize)]
struct ResultSet {
affected_rows: u64,
warnings: u16,
info: String,
rows: Vec<serde_json::Value>,
}

fn row_to_object(row: Row) -> serde_json::Value {
let mut object = json!({});
Expand All @@ -34,10 +28,9 @@ pub fn raw_query(mut conn: PooledConn, query: String) -> Result<serde_json::Valu
return Ok(result);
}

pub fn execute_query(pool: &Pool, query: &str) -> Result<serde_json::Value> {
pub fn execute_query(pool: &Pool, query: &str) -> Result<ResultSet> {
let mut conn = pool.get_conn()?;
let mut results = conn.query_iter(query)?;
let mut sets: Vec<ResultSet> = vec![];
while let Some(result_set) = results.iter() {
let affected_rows = result_set.affected_rows();
let warnings = result_set.warnings();
Expand All @@ -52,9 +45,13 @@ pub fn execute_query(pool: &Pool, query: &str) -> Result<serde_json::Value> {
info: info.to_string(),
rows,
};
sets.push(set);
return Ok(set);
}
let result = json!(sets);

return Ok(result);
return Ok(ResultSet {
affected_rows: 0,
warnings: 0,
info: "".to_string(),
rows: Vec::new(),
});
}
4 changes: 2 additions & 2 deletions src-tauri/src/handlers/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
};
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_json::{Value, json};
use sqlparser::{dialect::dialect_from_str, parser::Parser};
use tauri::{command, AppHandle, State};
use tracing::info;
Expand Down Expand Up @@ -91,7 +91,7 @@ pub async fn execute_query(
) -> CommandResult<Value> {
let connection = app_handle.acquire_connection(conn_id);
let result = connection.execute_query(&query).await?;
Ok(result)
Ok(json!({ "result": result }))
}

#[command]
Expand Down
8 changes: 6 additions & 2 deletions src-tauri/src/queues/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub struct QueryTaskEnqueueResult {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryTaskResult {
pub conn_id: String,
pub status: QueryTaskStatus,
pub query: String,
pub id: String,
Expand All @@ -88,11 +89,12 @@ 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(content) => {
match write_query(&task.id, &content.to_string()) {
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,
Expand All @@ -106,6 +108,7 @@ pub async fn async_process_model(
Err(e) => {
output_tx
.send(QueryTaskResult {
conn_id: task.conn.config.id.to_string(),
status: QueryTaskStatus::Error,
query: task.query,
id: task.id,
Expand All @@ -121,6 +124,7 @@ pub async fn async_process_model(
Err(e) => {
output_tx
.send(QueryTaskResult {
conn_id: task.conn.config.id.to_string(),
status: QueryTaskStatus::Error,
query: task.query,
id: task.id,
Expand Down
19 changes: 15 additions & 4 deletions src-tauri/src/utils/init.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::{fs, path::PathBuf};

use crate::database::database::create_app_db;
use crate::database::{database::create_app_db, connections::ResultSet};
use anyhow::Result;
use serde_json::json;
use tauri::api::dir::with_temp_dir;
use tracing::{debug, error};

Expand Down Expand Up @@ -45,9 +46,19 @@ pub fn write_file(path: &PathBuf, content: &str) -> Result<()> {
Ok(())
}

pub fn write_query(id: &str, content: &str) -> Result<String> {
pub fn write_query(id: &str, result_set: ResultSet) -> Result<String> {
let rows = json!(result_set.rows).to_string();
let metadata = json!({
"rows": result_set.rows.len(),
"affected_rows": result_set.affected_rows,
"warnings": result_set.warnings,
"info": result_set.info,
})
.to_string();
let tmp_dir = get_tmp_dir()?;
let path = tmp_dir + "/" + id;
write_file(&PathBuf::from(&path), content)?;
let path = tmp_dir.clone() + "/" + id;
let metadata_path = tmp_dir + "/" + id + ".metadata";
write_file(&PathBuf::from(&path), &rows)?;
write_file(&PathBuf::from(&metadata_path), &metadata)?;
Ok(path)
}
29 changes: 28 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ import { CommandPaletteContext } from "components/CommandPalette/CommandPaletteC
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";

function App() {
const [loading, setLoading] = createSignal(true);
const {
connections: { restoreConnectionStore },
connections: {
restoreConnectionStore,
getConnection,
contentStore: { idx },
queryIdx,
},
app: { restoreAppStore },
} = useAppSelector();

Expand All @@ -20,6 +28,25 @@ function App() {
}, 500);
});

const getQueryResults = () => { };

const compareAndAssign = (event: QueryTaskResult) => {
if (
getConnection().id === event.conn_id &&
idx === event.tab_idx &&
queryIdx() === event.query_idx
) {
// TODO: should get 0 page of results
}
};

onMount(async () => {
await listen<QueryTaskResult>(Events.QueryFinished, (event) => {
log(event);
compareAndAssign(event.payload);
});
});

onMount(async () => {
const theme = localStorage.getItem("theme") || "dark";
document.documentElement.dataset.theme = theme;
Expand Down
6 changes: 3 additions & 3 deletions src/components/CommandPalette/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import { t } from "utils/i18n";

const focusOn = defineAction({
id: "focus_on",
title: t("command_palette.focus_on"),
title: t('command_palette.focus_on'),
});

const focusQueryTextArea = defineAction({
id: "focus_query_text_area",
title: t("command_palette.focus_query_text_area"),
title: t('command_palette.focus_query_text_area'),
parentActionId: focusOn.id,
/* Condition for allowing action */
shortcut: "$mod+l", // $mod = Command on Mac & Control on Windows.
run: () => {
// document.dispatchEvent(
// new KeyboardEvent("keydown", {
// new KeyboardEvent('keydown', {
// code: "KeyL", // put everything you need in this object.
// ctrlKey: true, // if you aren't going to use them.
// })
Expand Down
2 changes: 1 addition & 1 deletion src/components/Screens/Console/Content/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const Content = () => {
tabindex={0}
onClick={() => setContentIdx(idx())}
>
{t("components.console.query")} #{idx() + 1}
{t('console.query')} #{idx() + 1}
</button>
<Show when={idx() > 0}>
<button
Expand Down
45 changes: 4 additions & 41 deletions src/components/Screens/Console/Content/QueryTab/QueryTab.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import { ResultsTable } from "./ResultesTable";
import { useAppSelector } from "services/Context";
import { createEffect, createSignal, onCleanup, Show } from "solid-js";
import { createEffect, onCleanup } from "solid-js";
import Split from "split.js";
import { QueryTextArea } from "./QueryTextArea";
import { createStore } from "solid-js/store";
import { Row } from "interfaces";
import { createShortcut } from "@solid-primitives/keyboard";

export const QueryTab = () => {
const {
connections: { getContent },
} = useAppSelector();
const [idx, setIdx] = createSignal(0);
createEffect(() => {
const q = Split(["#query", "#results"], {
sizes: [30, 80],
Expand All @@ -26,42 +18,13 @@ export const QueryTab = () => {
});
});

const {
connections: { getContentData },
} = useAppSelector();
const [rows, setRows] = createStore<Row[]>([]);

createEffect(() => {
setRows(getContentData("Query").result_sets[idx()]?.rows || []);
});

const onPrevClick = () => {
setIdx(
(idx() - 1 + getContentData("Query").result_sets.length) %
getContentData("Query").result_sets.length
);
};

const onNextClick = () => {
setIdx((idx() + 1) % getContentData("Query").result_sets.length);
};

createShortcut(["Control", "Shift", "N"], onNextClick);
createShortcut(["Control", "Shift", "P"], onPrevClick);

return (
<div class="flex flex-col h-full overflow-hidden">
<div id="query" class="flex flex-col">
<QueryTextArea
idx={idx}
onPrevClick={onPrevClick}
onNextClick={onNextClick}
/>
<QueryTextArea />
</div>
<div id="results">
<Show when={!getContent().error}>
<ResultsTable rows={rows} />
</Show>
<div id="results" class="flex">
<ResultsTable />
</div>
</div>
);
Expand Down
Loading

0 comments on commit 508bdd5

Please sign in to comment.