From 9ea057e9436fb03a0fa6baadd936345704087720 Mon Sep 17 00:00:00 2001 From: haex Date: Tue, 21 Oct 2025 16:29:13 +0200 Subject: [PATCH] fixed drizzle rust logic --- src-tauri/src/database/core.rs | 28 +++-- src-tauri/src/database/mod.rs | 9 ++ src-tauri/src/extension/core/manager.rs | 110 +++++++++--------- src-tauri/src/extension/database/executor.rs | 56 ++++----- src-tauri/src/lib.rs | 5 +- src/components/haex/desktop/index.vue | 1 + .../haex/extension/marketplace-card.vue | 16 ++- src/components/haex/system/marketplace.vue | 15 +-- src/components/haex/system/settings.vue | 8 +- src/components/haex/window/index.vue | 3 +- src/components/haex/workspace/card.vue | 4 +- src/stores/desktop/workspace.ts | 1 + src/stores/vault/index.ts | 7 +- 13 files changed, 151 insertions(+), 112 deletions(-) diff --git a/src-tauri/src/database/core.rs b/src-tauri/src/database/core.rs index 2125d25..6f13e1d 100644 --- a/src-tauri/src/database/core.rs +++ b/src-tauri/src/database/core.rs @@ -164,9 +164,11 @@ pub fn execute( if has_returning { // Use prepare + query for RETURNING statements - let mut stmt = conn.prepare(&sql).map_err(|e| DatabaseError::PrepareError { - reason: e.to_string(), - })?; + let mut stmt = conn + .prepare(&sql) + .map_err(|e| DatabaseError::PrepareError { + reason: e.to_string(), + })?; let num_columns = stmt.column_count(); let mut rows = stmt @@ -183,11 +185,11 @@ pub fn execute( let mut row_values: Vec = Vec::with_capacity(num_columns); for i in 0..num_columns { - let value_ref = row.get_ref(i).map_err(|e| { - DatabaseError::RowProcessingError { - reason: format!("Failed to get column {}: {}", i, e), - } - })?; + let value_ref = + row.get_ref(i) + .map_err(|e| DatabaseError::RowProcessingError { + reason: format!("Failed to get column {}: {}", i, e), + })?; let json_val = convert_value_ref_to_json(value_ref)?; row_values.push(json_val); @@ -274,6 +276,16 @@ pub fn select( }) } +pub fn select_with_crdt( + sql: String, + params: Vec, + connection: &DbConnection, +) -> Result>, DatabaseError> { + with_connection(&connection, |conn| { + SqlExecutor::select_internal(conn, &sql, ¶ms) + }) +} + /// Konvertiert rusqlite ValueRef zu JSON pub fn convert_value_ref_to_json(value_ref: ValueRef) -> Result { let json_val = match value_ref { diff --git a/src-tauri/src/database/mod.rs b/src-tauri/src/database/mod.rs index 0b0e470..bb10942 100644 --- a/src-tauri/src/database/mod.rs +++ b/src-tauri/src/database/mod.rs @@ -43,6 +43,15 @@ pub fn sql_execute( core::execute(sql, params, &state.db) } +#[tauri::command] +pub fn sql_select_with_crdt( + sql: String, + params: Vec, + state: State<'_, AppState>, +) -> Result>, DatabaseError> { + core::select_with_crdt(sql, params, &state.db) +} + #[tauri::command] pub fn sql_execute_with_crdt( sql: String, diff --git a/src-tauri/src/extension/core/manager.rs b/src-tauri/src/extension/core/manager.rs index 4eacf99..0c5d76b 100644 --- a/src-tauri/src/extension/core/manager.rs +++ b/src-tauri/src/extension/core/manager.rs @@ -167,7 +167,6 @@ impl ExtensionManager { Ok(specific_extension_dir) } - pub fn add_production_extension(&self, extension: Extension) -> Result<(), ExtensionError> { if extension.id.is_empty() { return Err(ExtensionError::ValidationError { @@ -223,11 +222,12 @@ impl ExtensionManager { name: &str, ) -> Result, ExtensionError> { // 1. Check dev extensions first (higher priority) - let dev_extensions = self.dev_extensions.lock().map_err(|e| { - ExtensionError::MutexPoisoned { - reason: e.to_string(), - } - })?; + let dev_extensions = + self.dev_extensions + .lock() + .map_err(|e| ExtensionError::MutexPoisoned { + reason: e.to_string(), + })?; for (id, ext) in dev_extensions.iter() { if ext.manifest.public_key == public_key && ext.manifest.name == name { @@ -236,11 +236,12 @@ impl ExtensionManager { } // 2. Check production extensions - let prod_extensions = self.production_extensions.lock().map_err(|e| { - ExtensionError::MutexPoisoned { - reason: e.to_string(), - } - })?; + let prod_extensions = + self.production_extensions + .lock() + .map_err(|e| ExtensionError::MutexPoisoned { + reason: e.to_string(), + })?; for (id, ext) in prod_extensions.iter() { if ext.manifest.public_key == public_key && ext.manifest.name == name { @@ -262,11 +263,7 @@ impl ExtensionManager { .map(|(_, ext)| ext)) } - pub fn remove_extension( - &self, - public_key: &str, - name: &str, - ) -> Result<(), ExtensionError> { + pub fn remove_extension(&self, public_key: &str, name: &str) -> Result<(), ExtensionError> { let (id, _) = self .find_extension_id_by_public_key_and_name(public_key, name)? .ok_or_else(|| ExtensionError::NotFound { @@ -276,11 +273,12 @@ impl ExtensionManager { // Remove from dev extensions first { - let mut dev_extensions = self.dev_extensions.lock().map_err(|e| { - ExtensionError::MutexPoisoned { - reason: e.to_string(), - } - })?; + let mut dev_extensions = + self.dev_extensions + .lock() + .map_err(|e| ExtensionError::MutexPoisoned { + reason: e.to_string(), + })?; if dev_extensions.remove(&id).is_some() { return Ok(()); } @@ -288,11 +286,12 @@ impl ExtensionManager { // Remove from production extensions { - let mut prod_extensions = self.production_extensions.lock().map_err(|e| { - ExtensionError::MutexPoisoned { - reason: e.to_string(), - } - })?; + let mut prod_extensions = + self.production_extensions + .lock() + .map_err(|e| ExtensionError::MutexPoisoned { + reason: e.to_string(), + })?; prod_extensions.remove(&id); } @@ -316,7 +315,10 @@ impl ExtensionManager { })?; eprintln!("DEBUG: Removing extension with ID: {}", extension.id); - eprintln!("DEBUG: Extension name: {}, version: {}", extension_name, extension_version); + eprintln!( + "DEBUG: Extension name: {}, version: {}", + extension_name, extension_version + ); // Lösche Permissions und Extension-Eintrag in einer Transaktion with_connection(&state.db, |conn| { @@ -327,12 +329,11 @@ impl ExtensionManager { })?; // Lösche alle Permissions mit extension_id - eprintln!("DEBUG: Deleting permissions for extension_id: {}", extension.id); - PermissionManager::delete_permissions_in_transaction( - &tx, - &hlc_service, - &extension.id, - )?; + eprintln!( + "DEBUG: Deleting permissions for extension_id: {}", + extension.id + ); + PermissionManager::delete_permissions_in_transaction(&tx, &hlc_service, &extension.id)?; // Lösche Extension-Eintrag mit extension_id let sql = format!("DELETE FROM {} WHERE id = ?", TABLE_EXTENSIONS); @@ -573,6 +574,7 @@ impl ExtensionManager { app_handle: &AppHandle, state: &State<'_, AppState>, ) -> Result, ExtensionError> { + // Clear existing data self.production_extensions .lock() .map_err(|e| ExtensionError::MutexPoisoned { @@ -592,19 +594,22 @@ impl ExtensionManager { })? .clear(); - // Schritt 1: Alle Daten aus der Datenbank in einem Rutsch laden. + // Lade alle Daten aus der Datenbank let extensions = with_connection(&state.db, |conn| { let sql = format!( - "SELECT id, name, version, author, entry, icon, public_key, signature, homepage, description, enabled FROM {}", - TABLE_EXTENSIONS - ); + "SELECT id, name, version, author, entry, icon, public_key, signature, homepage, description, enabled FROM {}", + TABLE_EXTENSIONS + ); eprintln!("DEBUG: SQL Query before transformation: {}", sql); + + // select_internal gibt jetzt Vec> zurück let results = SqlExecutor::select_internal(conn, &sql, &[])?; eprintln!("DEBUG: Query returned {} results", results.len()); let mut data = Vec::new(); - for result in results { - let id = result["id"] + for row in results { + // Wir erwarten die Werte in der Reihenfolge der SELECT-Anweisung + let id = row[0] .as_str() .ok_or_else(|| DatabaseError::SerializationError { reason: "Missing id field".to_string(), @@ -612,31 +617,31 @@ impl ExtensionManager { .to_string(); let manifest = ExtensionManifest { - name: result["name"] + name: row[1] .as_str() .ok_or_else(|| DatabaseError::SerializationError { reason: "Missing name field".to_string(), })? .to_string(), - version: result["version"] + version: row[2] .as_str() .ok_or_else(|| DatabaseError::SerializationError { reason: "Missing version field".to_string(), })? .to_string(), - author: result["author"].as_str().map(String::from), - entry: result["entry"].as_str().unwrap_or("index.html").to_string(), - icon: result["icon"].as_str().map(String::from), - public_key: result["public_key"].as_str().unwrap_or("").to_string(), - signature: result["signature"].as_str().unwrap_or("").to_string(), + author: row[3].as_str().map(String::from), + entry: row[4].as_str().unwrap_or("index.html").to_string(), + icon: row[5].as_str().map(String::from), + public_key: row[6].as_str().unwrap_or("").to_string(), + signature: row[7].as_str().unwrap_or("").to_string(), permissions: ExtensionPermissions::default(), - homepage: result["homepage"].as_str().map(String::from), - description: result["description"].as_str().map(String::from), + homepage: row[8].as_str().map(String::from), + description: row[9].as_str().map(String::from), }; - let enabled = result["enabled"] + let enabled = row[10] .as_bool() - .or_else(|| result["enabled"].as_i64().map(|v| v != 0)) + .or_else(|| row[10].as_i64().map(|v| v != 0)) .unwrap_or(false); data.push(ExtensionDataFromDb { @@ -684,10 +689,7 @@ impl ExtensionManager { continue; } - eprintln!( - "DEBUG: Extension loaded successfully: {}", - extension_id - ); + eprintln!("DEBUG: Extension loaded successfully: {}", extension_id); let extension = Extension { id: extension_id.clone(), diff --git a/src-tauri/src/extension/database/executor.rs b/src-tauri/src/extension/database/executor.rs index c38ffa4..3e4be69 100644 --- a/src-tauri/src/extension/database/executor.rs +++ b/src-tauri/src/extension/database/executor.rs @@ -5,6 +5,8 @@ use crate::crdt::transformer::CrdtTransformer; use crate::crdt::trigger; use crate::database::core::{convert_value_ref_to_json, parse_sql_statements, ValueConverter}; use crate::database::error::DatabaseError; +use crate::database::DbConnection; +use rusqlite::Connection; use rusqlite::{params_from_iter, types::Value as SqliteValue, ToSql, Transaction}; use serde_json::Value as JsonValue; use sqlparser::ast::{Insert, Statement, TableObject}; @@ -423,10 +425,10 @@ impl SqlExecutor { /// Führt SELECT aus (mit CRDT-Transformation) - OHNE Permission-Check pub fn select_internal( - conn: &rusqlite::Connection, + conn: &Connection, sql: &str, params: &[JsonValue], - ) -> Result, DatabaseError> { + ) -> Result>, DatabaseError> { // Parameter validation let total_placeholders = sql.matches('?').count(); if total_placeholders != params.len() { @@ -457,42 +459,40 @@ impl SqlExecutor { let sql_params = ValueConverter::convert_params(params)?; let transformer = CrdtTransformer::new(); - let last_statement = ast_vec.pop().unwrap(); - let mut stmt_to_execute = last_statement; - + let mut stmt_to_execute = ast_vec.pop().unwrap(); transformer.transform_select_statement(&mut stmt_to_execute)?; let transformed_sql = stmt_to_execute.to_string(); - let mut prepared_stmt = - conn.prepare(&transformed_sql) - .map_err(|e| DatabaseError::ExecutionError { - sql: transformed_sql.clone(), - reason: e.to_string(), - table: None, - })?; + let mut prepared_stmt = conn.prepare(&transformed_sql)?; + let num_columns = prepared_stmt.column_count(); - let column_names: Vec = prepared_stmt - .column_names() - .into_iter() - .map(|s| s.to_string()) - .collect(); - - let rows = prepared_stmt - .query_map(params_from_iter(sql_params.iter()), |row| { - crate::extension::database::row_to_json_value(row, &column_names) - }) + let mut rows = prepared_stmt + .query(params_from_iter(sql_params.iter())) .map_err(|e| DatabaseError::QueryError { reason: e.to_string(), })?; - let mut results = Vec::new(); - for row_result in rows { - results.push(row_result.map_err(|e| DatabaseError::RowProcessingError { - reason: e.to_string(), - })?); + let mut result_vec: Vec> = Vec::new(); + + while let Some(row) = rows.next().map_err(|e| DatabaseError::RowProcessingError { + reason: format!("Row iteration error: {}", e), + })? { + let mut row_values: Vec = Vec::with_capacity(num_columns); + + for i in 0..num_columns { + let value_ref = row + .get_ref(i) + .map_err(|e| DatabaseError::RowProcessingError { + reason: format!("Failed to get column {}: {}", i, e), + })?; + + let json_val = convert_value_ref_to_json(value_ref)?; + row_values.push(json_val); + } + result_vec.push(row_values); } - Ok(results) + Ok(result_vec) } /// Führt SQL mit CRDT-Transformation aus und gibt RETURNING-Ergebnisse zurück diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 04ed808..a03a817 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -70,15 +70,16 @@ pub fn run() { database::delete_vault, database::list_vaults, database::open_encrypted_database, - database::sql_execute, database::sql_execute_with_crdt, + database::sql_execute, database::sql_query_with_crdt, + database::sql_select_with_crdt, database::sql_select, database::vault_exists, extension::database::extension_sql_execute, extension::database::extension_sql_select, - extension::get_all_extensions, extension::get_all_dev_extensions, + extension::get_all_extensions, extension::get_extension_info, extension::install_extension_with_permissions, extension::is_extension_installed, diff --git a/src/components/haex/desktop/index.vue b/src/components/haex/desktop/index.vue index 2723e9a..8188548 100644 --- a/src/components/haex/desktop/index.vue +++ b/src/components/haex/desktop/index.vue @@ -17,6 +17,7 @@ class="w-full h-full" @swiper="onSwiperInit" @slide-change="onSlideChange" + direction="vertical" > {{ extension.description }}

@@ -67,7 +67,9 @@ > {{ t('installed') }} - {{ t('installedVersion', { version: extension.installedVersion }) }} + {{ + t('installedVersion', { version: extension.installedVersion }) + }}
-
+

@@ -14,14 +14,14 @@