zwischenstand

This commit is contained in:
Martin Drechsel
2025-05-06 11:09:56 +02:00
parent 410a885d21
commit b729c8ebbe
40 changed files with 2252 additions and 376 deletions

View File

@ -1,13 +1,74 @@
// database/core.rs
use crate::database::DbConnection;
use rusqlite::{Connection, OpenFlags};
use serde_json::json;
use base64::{engine::general_purpose::STANDARD, Engine as _};
use rusqlite::{
types::{Value as RusqliteValue, ValueRef},
Connection, OpenFlags, ToSql,
};
use serde_json::Value as JsonValue;
use std::fs;
use std::path::Path;
use tauri::State;
// --- Hilfsfunktion: Konvertiert JSON Value zu etwas, das rusqlite versteht ---
// Diese Funktion ist etwas knifflig wegen Ownership und Lifetimes.
// Eine einfachere Variante ist oft, direkt rusqlite::types::Value zu erstellen.
// Hier ein Beispiel, das owned Values erstellt (braucht evtl. Anpassung je nach rusqlite-Version/Nutzung)
fn json_to_rusqlite_value(json_val: &JsonValue) -> Result<RusqliteValue, String> {
match json_val {
JsonValue::Null => Ok(RusqliteValue::Null),
JsonValue::Bool(b) => Ok(RusqliteValue::Integer(*b as i64)), // SQLite hat keinen BOOLEAN
JsonValue::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(RusqliteValue::Integer(i))
} else if let Some(f) = n.as_f64() {
Ok(RusqliteValue::Real(f))
} else {
Err("Ungültiger Zahlenwert".to_string())
}
}
JsonValue::String(s) => Ok(RusqliteValue::Text(s.clone())),
JsonValue::Array(_) | JsonValue::Object(_) => {
// SQLite kann Arrays/Objects nicht direkt speichern (außer als TEXT/BLOB)
// Konvertiere sie zu JSON-Strings, wenn das gewünscht ist
Ok(RusqliteValue::Text(
serde_json::to_string(json_val).map_err(|e| e.to_string())?,
))
// Oder gib einen Fehler zurück, wenn Arrays/Objekte nicht erlaubt sind
// Err("Arrays oder Objekte werden nicht direkt als Parameter unterstützt".to_string())
}
}
}
// --- Tauri Command für INSERT/UPDATE/DELETE ---
#[tauri::command]
pub async fn execute(
sql: String,
params: Vec<JsonValue>,
state: &State<'_, DbConnection>,
) -> Result<usize, String> {
// Gibt Anzahl betroffener Zeilen zurück
let params_converted: Vec<RusqliteValue> = params
.iter()
.map(json_to_rusqlite_value)
.collect::<Result<Vec<_>, _>>()?;
let params_sql: Vec<&dyn ToSql> = params_converted.iter().map(|v| v as &dyn ToSql).collect();
let db_lock = state
.0
.lock()
.map_err(|e| format!("Mutex Lock Fehler: {}", e))?;
let conn = db_lock.as_ref().ok_or("Keine Datenbankverbindung")?;
let affected_rows = conn
.execute(&sql, &params_sql[..])
.map_err(|e| format!("SQL Execute Fehler: {}", e))?;
Ok(affected_rows)
}
/// Führt SQL-Schreiboperationen (INSERT, UPDATE, DELETE, CREATE) ohne Berechtigungsprüfung aus
pub async fn execute(
/* pub async fn execute(
sql: &str,
params: &[String],
state: &State<'_, DbConnection>,
@ -26,14 +87,107 @@ pub async fn execute(
"last_insert_id": last_id
}))
.map_err(|e| format!("JSON-Serialisierungsfehler: {}", e))?)
} */
#[tauri::command]
pub async fn select(
sql: String,
params: Vec<JsonValue>, // Parameter als JSON Values empfangen
state: &State<'_, DbConnection>,
) -> Result<Vec<Vec<JsonValue>>, String> {
// Ergebnis als Vec<RowObject>
// Konvertiere JSON Params zu rusqlite Values für die Abfrage
// Wir sammeln sie als owned Values, da `params_from_iter` Referenzen braucht,
// was mit lokalen Konvertierungen schwierig ist.
let params_converted: Vec<RusqliteValue> = params
.iter()
.map(json_to_rusqlite_value)
.collect::<Result<Vec<_>, _>>()?; // Sammle Ergebnisse, gibt Fehler weiter
// Konvertiere zu Slice von ToSql-Referenzen (erfordert, dass die Values leben)
let params_sql: Vec<&dyn ToSql> = params_converted.iter().map(|v| v as &dyn ToSql).collect();
// Zugriff auf die Verbindung (blockierend, okay für SQLite in vielen Fällen)
let db_lock = state
.0
.lock()
.map_err(|e| format!("Mutex Lock Fehler: {}", e))?;
let conn = db_lock.as_ref().ok_or("Keine Datenbankverbindung")?;
let mut stmt = conn
.prepare(&sql)
.map_err(|e| format!("SQL Prepare Fehler: {}", e))?;
let column_names: Vec<String> = stmt
.column_names()
.into_iter()
.map(|s| s.to_string())
.collect();
let num_columns = column_names.len();
let mut rows = stmt
.query(&params_sql[..])
.map_err(|e| format!("SQL Query Fehler: {}", e))?;
let mut result_vec: Vec<Vec<JsonValue>> = Vec::new();
println!();
println!();
println!();
println!();
while let Some(row) = rows.next().map_err(|e| format!("Row Next Fehler: {}", e))? {
//let mut row_map = HashMap::new();
let mut row_data: Vec<JsonValue> = Vec::with_capacity(num_columns);
for i in 0..num_columns {
let col_name = &column_names[i];
println!(
"--- Processing Column --- Index: {}, Name: '{}'",
i, col_name
);
let value_ref = row
.get_ref(i)
.map_err(|e| format!("Get Ref Fehler Spalte {}: {}", i, e))?;
// Wandle rusqlite ValueRef zurück zu serde_json Value
let json_val = match value_ref {
ValueRef::Null => JsonValue::Null,
ValueRef::Integer(i) => JsonValue::Number(i.into()),
ValueRef::Real(f) => JsonValue::Number(
serde_json::Number::from_f64(f).unwrap_or(serde_json::Number::from(0)),
), // Fallback für NaN/Infinity
ValueRef::Text(t) => {
let s = String::from_utf8_lossy(t).to_string();
// Versuche, als JSON zu parsen, falls es ursprünglich ein Array/Objekt war
//serde_json::from_str(&s).unwrap_or(JsonValue::String(s))
JsonValue::String(s)
}
ValueRef::Blob(b) => {
// BLOBs z.B. als Base64-String zurückgeben
JsonValue::String(STANDARD.encode(b))
}
};
println!(
"new row: name: {} with value: {}",
column_names[i].clone(),
json_val,
);
row_data.push(json_val);
//row_map.insert(column_names[i].clone(), json_val);
}
//result_vec.push(row_map);
result_vec.push(row_data);
}
Ok(result_vec)
}
/// Führt SQL-Leseoperationen (SELECT) ohne Berechtigungsprüfung aus
pub async fn select(
/* pub async fn select(
sql: &str,
params: &[String],
state: &State<'_, DbConnection>,
) -> Result<Vec<Vec<String>>, String> {
) -> Result<Vec<Vec<Option<String>>>, String> {
let db = state.0.lock().map_err(|e| format!("Mutex-Fehler: {}", e))?;
let conn = db.as_ref().ok_or("Keine Datenbankverbindung vorhanden")?;
@ -52,16 +206,20 @@ pub async fn select(
{
let mut row_data = Vec::new();
for i in 0..columns {
let value: String = row
let value = row
.get(i)
.map_err(|e| format!("Datentypfehler in Spalte {}: {}", i, e))?;
row_data.push(value);
}
/* println!(
"Select Row Data: {}",
&row_data.clone().join("").to_string()
); */
result.push(row_data);
}
Ok(result)
}
} */
/// Öffnet und initialisiert eine Datenbank mit Verschlüsselung
pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connection, String> {
@ -75,6 +233,9 @@ pub fn open_and_init_db(path: &str, key: &str, create: bool) -> Result<Connectio
conn.pragma_update(None, "key", key)
.map_err(|e| e.to_string())?;
conn.execute_batch("SELECT count(*) from haex_extensions")
.map_err(|e| e.to_string())?;
Ok(conn)
}