From d8a807a97b36f2dcd7f12317ec9cbd3a90f0cb78 Mon Sep 17 00:00:00 2001 From: Daniel Boros Date: Tue, 21 May 2024 20:06:23 +0200 Subject: [PATCH] feat: add project and and rework data storing --- .vscode/settings.json | 1 + common/src/types/mod.rs | 5 +++ src-tauri/Cargo.toml | 1 + src-tauri/src/dbs/project.rs | 9 ++-- src-tauri/src/drivers/pgsql.rs | 25 +++++------ src/app.rs | 8 +++- src/dashboard/query_editor.rs | 5 +-- src/databases/pgsql/driver.rs | 31 ++++++++------ src/databases/pgsql/index.rs | 39 ++++++++++-------- src/invoke.rs | 4 +- src/lib.rs | 49 +++++++++++++++++++++- src/modals/add_pgsql_connection.rs | 66 +++++++++--------------------- src/sidebar/index.rs | 2 +- src/store/atoms.rs | 27 ++++++++++++ src/store/mod.rs | 6 --- src/store/projects.rs | 26 ++++++------ src/store/queries.rs | 8 ++-- 17 files changed, 185 insertions(+), 127 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2275697..62e1e54 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "editor.semanticHighlighting.enabled": false }, "rust-analyzer.rustfmt.overrideCommand": ["leptosfmt", "--stdin", "--rustfmt"], + "rust-analyzer.procMacro.attributes.enable": true, "editor.tokenColorCustomizations": { "[LaserWave High Contrast]": { "textMateRules": [ diff --git a/common/src/types/mod.rs b/common/src/types/mod.rs index 173f9d2..5166ad4 100644 --- a/common/src/types/mod.rs +++ b/common/src/types/mod.rs @@ -1,2 +1,7 @@ +use std::collections::BTreeMap; + pub mod pgsql; +pub type BTreeStore = BTreeMap; +pub type BTreeVecStore = BTreeMap>; + diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8e52d82..c475b5c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -25,6 +25,7 @@ anyhow = "1.0.83" tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["fmt"] } ahash = { version = "0.8.11", features = ["serde"] } +bincode = "1.3.3" diff --git a/src-tauri/src/dbs/project.rs b/src-tauri/src/dbs/project.rs index 8eab5c3..5f946b4 100644 --- a/src-tauri/src/dbs/project.rs +++ b/src-tauri/src/dbs/project.rs @@ -3,9 +3,10 @@ use std::collections::BTreeMap; use tauri::{Result, State}; use crate::AppState; +use common::types::BTreeVecStore; #[tauri::command(rename_all = "snake_case")] -pub async fn project_db_select(app_state: State<'_, AppState>) -> Result> { +pub async fn project_db_select(app_state: State<'_, AppState>) -> Result { let project_db = app_state.project_db.lock().await; let db = project_db.clone().unwrap(); let mut projects = BTreeMap::new(); @@ -20,7 +21,7 @@ pub async fn project_db_select(app_state: State<'_, AppState>) -> Result) -> Result, app_state: State<'_, AppState>, ) -> Result<()> { let project_db = app_state.project_db.lock().await; let db = project_db.clone().unwrap(); + let project_details = bincode::serialize(&project_details).unwrap(); + // project_id - [driver, user, password, host, port] db.insert(project_id, project_details).unwrap(); Ok(()) } diff --git a/src-tauri/src/drivers/pgsql.rs b/src-tauri/src/drivers/pgsql.rs index 6c48f7d..55d5135 100644 --- a/src-tauri/src/drivers/pgsql.rs +++ b/src-tauri/src/drivers/pgsql.rs @@ -13,7 +13,7 @@ use crate::{utils::reflective_get, AppState}; #[tauri::command(rename_all = "snake_case")] pub async fn pgsql_connector( project_id: &str, - key: Option<&str>, + key: Option<[&str; 4]>, app: AppHandle, ) -> Result { let app_state = app.state::(); @@ -26,24 +26,21 @@ pub async fn pgsql_connector( } let key = match key { - Some(key) => key.to_string(), + Some(key) => format!( + "user={} password={} host={} port={}", + key[0], key[1], key[2], key[3] + ), None => { let projects_db = app_state.project_db.lock().await; let projects_db = projects_db.as_ref().unwrap(); - let project_details = projects_db.get(project_id).unwrap().unwrap().to_vec(); - let project_details = String::from_utf8(project_details).unwrap(); - let project_details = project_details.split(":").collect::>(); - let project_details = project_details - .into_iter() - .skip(1) - .map(|s| { - let kv = s.split('=').collect::>(); - kv[1].to_owned() - }) - .collect::>(); + let project_details = projects_db.get(project_id).unwrap(); + let project_details = match project_details { + Some(bytes) => bincode::deserialize::>(&bytes).unwrap(), + _ => Vec::new(), + }; let project_details = format!( "user={} password={} host={} port={}", - project_details[0], project_details[1], project_details[2], project_details[3] + project_details[1], project_details[2], project_details[3], project_details[4] ); project_details } diff --git a/src/app.rs b/src/app.rs index 51d2ee3..9bc39bb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -10,7 +10,10 @@ use crate::{ performane::Performance, sidebar::index::Sidebar, store::{ - atoms::{QueryPerformanceAtom, QueryPerformanceContext, RunQueryAtom, RunQueryContext}, + atoms::{ + PgsqlConnectionDetailsAtom, PgsqlConnectionDetailsContext, QueryPerformanceAtom, + QueryPerformanceContext, RunQueryAtom, RunQueryContext, + }, projects::ProjectsStore, queries::QueriesStore, tabs::TabsStore, @@ -29,6 +32,9 @@ pub fn App() -> impl IntoView { RwSignal::new(VecDeque::::new()), ); provide_context::(RwSignal::new(RunQueryAtom::default())); + provide_context::(RwSignal::new( + PgsqlConnectionDetailsAtom::default(), + )); provide_context(TabsStore::default()); view! { diff --git a/src/dashboard/query_editor.rs b/src/dashboard/query_editor.rs index 59edf6a..90eb067 100644 --- a/src/dashboard/query_editor.rs +++ b/src/dashboard/query_editor.rs @@ -23,10 +23,7 @@ pub const MODE_ID: &str = "pgsql"; #[component] pub fn QueryEditor(index: usize) -> impl IntoView { let tabs_store = expect_context::(); - let active_project = move || match tabs_store.selected_projects.get().get(index) { - Some(project) => Some(project.clone()), - _ => None, - }; + let active_project = move || tabs_store.selected_projects.get().get(index).cloned(); let projects_store = expect_context::(); let project_driver = projects_store.select_driver_by_project(active_project().as_deref()); let tabs_store_rc = Rc::new(RefCell::new(tabs_store)); diff --git a/src/databases/pgsql/driver.rs b/src/databases/pgsql/driver.rs index c279834..9a1d6b0 100644 --- a/src/databases/pgsql/driver.rs +++ b/src/databases/pgsql/driver.rs @@ -13,7 +13,10 @@ use crate::{ InvokePgsqlRunQueryArgs, }, store::{ - atoms::{QueryPerformanceAtom, QueryPerformanceContext, RunQueryAtom, RunQueryContext}, + atoms::{ + PgsqlConnectionDetailsContext, QueryPerformanceAtom, QueryPerformanceContext, RunQueryAtom, + RunQueryContext, + }, tabs::TabsStore, }, }; @@ -48,12 +51,16 @@ impl<'a> Pgsql<'a> { self .status .update(|prev| *prev = ProjectConnectionStatus::Connecting); - let connection_string = self.generate_connection_string(); let status = invoke::<_, ProjectConnectionStatus>( Invoke::PgsqlConnector.as_ref(), &InvokePgsqlConnectorArgs { project_id: &self.project_id.get(), - key: Some(&connection_string), + key: Some([ + self.user.unwrap(), + self.password.unwrap(), + self.host.unwrap(), + self.port.unwrap(), + ]), }, ) .await @@ -158,15 +165,15 @@ impl<'a> Pgsql<'a> { self.port = Some(port); } - fn generate_connection_string(&self) -> String { - let connection_string = format!( - "user={} password={} host={} port={}", - self.user.as_ref().unwrap(), - self.password.as_ref().unwrap(), - self.host.as_ref().unwrap(), - self.port.as_ref().unwrap(), - ); - connection_string + pub fn edit_connection_details(&self) { + let atom = expect_context::(); + atom.update(|prev| { + prev.project_id = self.project_id.get().clone(); + prev.user = self.user.unwrap().to_string(); + prev.password = self.password.unwrap().to_string(); + prev.host = self.host.unwrap().to_string(); + prev.port = self.port.unwrap().to_string(); + }); } } diff --git a/src/databases/pgsql/index.rs b/src/databases/pgsql/index.rs index d466fba..2001a30 100644 --- a/src/databases/pgsql/index.rs +++ b/src/databases/pgsql/index.rs @@ -5,7 +5,10 @@ use leptos_icons::*; use leptos_toaster::{Toast, ToastId, ToastVariant, Toasts}; use super::{driver::Pgsql, schema::Schema}; -use crate::store::{projects::ProjectsStore, tabs::TabsStore}; +use crate::{ + modals::add_pgsql_connection::AddPgsqlConnection, + store::{projects::ProjectsStore, tabs::TabsStore}, +}; use common::enums::ProjectConnectionStatus; #[component] @@ -14,29 +17,18 @@ pub fn Pgsql(project_id: String) -> impl IntoView { let tabs_store = expect_context::(); let projects_store = expect_context::(); let project_details = projects_store.select_project_by_name(&project_id).unwrap(); - let connection_params = project_details - .split(':') - .map(String::from) - .collect::>(); - let connection_params = connection_params - .into_iter() - .skip(1) - .map(|s| { - let kv = s.split('=').collect::>(); - kv[1].to_owned() - }) - .collect::>(); - let connection_params = Box::leak(connection_params.into_boxed_slice()); + let project_details = Box::leak(Box::new(project_details)); // [user, password, host, port] let mut pgsql = Pgsql::new(project_id.clone().to_string()); { pgsql.load_connection_details( - &connection_params[0], - &connection_params[1], - &connection_params[2], - &connection_params[3], + &project_details[1], + &project_details[2], + &project_details[3], + &project_details[4], ); } + let show = create_rw_signal(false); let toast_context = expect_context::(); let create_toast = move |variant: ToastVariant, title: String| { let toast_id = ToastId::new(); @@ -80,6 +72,7 @@ pub fn Pgsql(project_id: String) -> impl IntoView { view! { +
+
diff --git a/src/sidebar/index.rs b/src/sidebar/index.rs index 731a183..62a88f9 100644 --- a/src/sidebar/index.rs +++ b/src/sidebar/index.rs @@ -45,7 +45,7 @@ pub fn Sidebar() -> impl IntoView { each=move || projects_store.get() key=|(project, _)| project.clone() children=|(project_id, project_details)| { - if project_details.contains(Drivers::PGSQL.as_ref()) { + if project_details.first().unwrap() == Drivers::PGSQL.as_ref() { view! {
diff --git a/src/store/atoms.rs b/src/store/atoms.rs index 4e16d10..e6e59e9 100644 --- a/src/store/atoms.rs +++ b/src/store/atoms.rs @@ -1,6 +1,8 @@ use std::collections::VecDeque; +use common::enums::Drivers; use leptos::RwSignal; +use rsql::StructIntoIterator; #[derive(Debug, Default, Clone)] pub struct QueryPerformanceAtom { @@ -31,3 +33,28 @@ pub struct RunQueryAtom { pub type RunQueryContext = RwSignal; +#[derive(Clone, StructIntoIterator)] +pub struct PgsqlConnectionDetailsAtom { + pub project_id: String, + pub driver: Drivers, + pub user: String, + pub password: String, + pub host: String, + pub port: String, +} + +impl Default for PgsqlConnectionDetailsAtom { + fn default() -> Self { + Self { + project_id: String::new(), + driver: Drivers::PGSQL, + user: String::new(), + password: String::new(), + host: String::new(), + port: String::new(), + } + } +} + +pub type PgsqlConnectionDetailsContext = RwSignal; + diff --git a/src/store/mod.rs b/src/store/mod.rs index 8fba340..1ee5f61 100644 --- a/src/store/mod.rs +++ b/src/store/mod.rs @@ -1,11 +1,5 @@ -use std::collections::BTreeMap; - -use leptos::RwSignal; - pub mod atoms; pub mod projects; pub mod queries; pub mod tabs; -pub type BTreeStore = RwSignal>; - diff --git a/src/store/projects.rs b/src/store/projects.rs index f45cfe0..a25e239 100644 --- a/src/store/projects.rs +++ b/src/store/projects.rs @@ -3,16 +3,14 @@ use std::{ ops::{Deref, DerefMut}, }; -use common::enums::Drivers; +use common::{enums::Drivers, types::BTreeVecStore}; use leptos::{RwSignal, SignalGet, SignalSet}; use tauri_sys::tauri::invoke; use crate::invoke::{Invoke, InvokeProjectDbDeleteArgs, InvokeProjectDbInsertArgs}; -use super::BTreeStore; - #[derive(Clone, Copy, Debug)] -pub struct ProjectsStore(pub BTreeStore); +pub struct ProjectsStore(pub RwSignal); impl Default for ProjectsStore { fn default() -> Self { @@ -21,7 +19,7 @@ impl Default for ProjectsStore { } impl Deref for ProjectsStore { - type Target = BTreeStore; + type Target = RwSignal; fn deref(&self) -> &Self::Target { &self.0 @@ -40,7 +38,7 @@ impl ProjectsStore { Self(RwSignal::default()) } - pub fn select_project_by_name(&self, project_id: &str) -> Option { + pub fn select_project_by_name(&self, project_id: &str) -> Option> { self.get().get(project_id).cloned() } @@ -50,23 +48,23 @@ impl ProjectsStore { } let project = self.select_project_by_name(project_id.unwrap()).unwrap(); - let driver = project.split(':').next().unwrap(); - let driver = driver.split('=').last(); + let driver = project.first().unwrap(); - match driver { - Some("PGSQL") => Drivers::PGSQL, + match driver.as_str() { + "PGSQL" => Drivers::PGSQL, _ => unreachable!(), } } pub async fn load_projects(&self) { - let projects = invoke::<_, BTreeMap>(Invoke::ProjectDbSelect.as_ref(), &()) - .await - .unwrap(); + let projects = + invoke::<_, BTreeMap>>(Invoke::ProjectDbSelect.as_ref(), &()) + .await + .unwrap(); self.set(projects); } - pub async fn insert_project(&self, project_id: &str, project_details: &str) { + pub async fn insert_project(&self, project_id: &str, project_details: Vec) { let _ = invoke::<_, ()>( Invoke::ProjectDbInsert.as_ref(), &InvokeProjectDbInsertArgs { diff --git a/src/store/queries.rs b/src/store/queries.rs index f4f469e..c14ce4c 100644 --- a/src/store/queries.rs +++ b/src/store/queries.rs @@ -3,16 +3,16 @@ use std::{ ops::{Deref, DerefMut}, }; -use common::enums::Drivers; +use common::{enums::Drivers, types::BTreeStore}; use leptos::*; use tauri_sys::tauri::invoke; use crate::invoke::{Invoke, InvokeQueryDbDeleteArgs, InvokeQueryDbInsertArgs}; -use super::{tabs::TabsStore, BTreeStore}; +use super::tabs::TabsStore; #[derive(Clone, Copy, Debug)] -pub struct QueriesStore(pub BTreeStore); +pub struct QueriesStore(pub RwSignal); impl Default for QueriesStore { fn default() -> Self { @@ -21,7 +21,7 @@ impl Default for QueriesStore { } impl Deref for QueriesStore { - type Target = BTreeStore; + type Target = RwSignal; fn deref(&self) -> &Self::Target { &self.0