mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-21 13:14:04 +02:00
feat: move database access to rust
This commit is contained in:
parent
4b3b6eaf21
commit
a94496dbdb
5 changed files with 687 additions and 317 deletions
148
src-tauri/src/db/history.rs
Normal file
148
src-tauri/src/db/history.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
use sqlx::{Row, SqlitePool};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::{thread_rng, Rng};
|
||||
use crate::utils::types::{HistoryItem, ContentType};
|
||||
use std::fs;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
|
||||
pub async fn initialize_history(pool: &SqlitePool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let id: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO history (id, content_type, content, timestamp) VALUES (?, ?, ?, CURRENT_TIMESTAMP)"
|
||||
)
|
||||
.bind(id)
|
||||
.bind("text")
|
||||
.bind("Welcome to your clipboard history!")
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_history(pool: tauri::State<'_, SqlitePool>) -> Result<Vec<HistoryItem>, String> {
|
||||
let rows = sqlx::query(
|
||||
"SELECT id, content_type, content, favicon, timestamp FROM history ORDER BY timestamp DESC"
|
||||
)
|
||||
.fetch_all(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let items = rows.iter().map(|row| HistoryItem {
|
||||
id: row.get("id"),
|
||||
content_type: ContentType::from(row.get::<String, _>("content_type")),
|
||||
content: row.get("content"),
|
||||
favicon: row.get("favicon"),
|
||||
timestamp: row.get("timestamp"),
|
||||
}).collect();
|
||||
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn add_history_item(
|
||||
pool: tauri::State<'_, SqlitePool>,
|
||||
item: HistoryItem,
|
||||
) -> Result<(), String> {
|
||||
let (id, content_type, content, favicon, timestamp) = item.to_row();
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO history (id, content_type, content, favicon, timestamp) VALUES (?, ?, ?, ?, ?)"
|
||||
)
|
||||
.bind(id)
|
||||
.bind(content_type)
|
||||
.bind(content)
|
||||
.bind(favicon)
|
||||
.bind(timestamp)
|
||||
.execute(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn search_history(
|
||||
pool: tauri::State<'_, SqlitePool>,
|
||||
query: String
|
||||
) -> Result<Vec<HistoryItem>, String> {
|
||||
let query = format!("%{}%", query);
|
||||
let rows = sqlx::query(
|
||||
"SELECT id, content_type, content, favicon, timestamp FROM history WHERE content LIKE ? ORDER BY timestamp DESC"
|
||||
)
|
||||
.bind(query)
|
||||
.fetch_all(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let items = rows.iter().map(|row| HistoryItem {
|
||||
id: row.get("id"),
|
||||
content_type: ContentType::from(row.get::<String, _>("content_type")),
|
||||
content: row.get("content"),
|
||||
favicon: row.get("favicon"),
|
||||
timestamp: row.get("timestamp"),
|
||||
}).collect();
|
||||
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn load_history_chunk(
|
||||
pool: tauri::State<'_, SqlitePool>,
|
||||
offset: i64,
|
||||
limit: i64
|
||||
) -> Result<Vec<HistoryItem>, String> {
|
||||
let rows = sqlx::query(
|
||||
"SELECT id, content_type, content, favicon, timestamp FROM history ORDER BY timestamp DESC LIMIT ? OFFSET ?"
|
||||
)
|
||||
.bind(limit)
|
||||
.bind(offset)
|
||||
.fetch_all(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let items = rows.iter().map(|row| HistoryItem {
|
||||
id: row.get("id"),
|
||||
content_type: ContentType::from(row.get::<String, _>("content_type")),
|
||||
content: row.get("content"),
|
||||
favicon: row.get("favicon"),
|
||||
timestamp: row.get("timestamp"),
|
||||
}).collect();
|
||||
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_history_item(
|
||||
pool: tauri::State<'_, SqlitePool>,
|
||||
id: String
|
||||
) -> Result<(), String> {
|
||||
sqlx::query("DELETE FROM history WHERE id = ?")
|
||||
.bind(id)
|
||||
.execute(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn clear_history(pool: tauri::State<'_, SqlitePool>) -> Result<(), String> {
|
||||
sqlx::query("DELETE FROM history")
|
||||
.execute(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn read_image(filename: String) -> Result<String, String> {
|
||||
let bytes = fs::read(filename).map_err(|e| e.to_string())?;
|
||||
Ok(STANDARD.encode(bytes))
|
||||
}
|
100
src-tauri/src/db/settings.rs
Normal file
100
src-tauri/src/db/settings.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::SqlitePool;
|
||||
use serde_json;
|
||||
use tauri::{Emitter, Manager};
|
||||
use sqlx::Row;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct KeybindSetting {
|
||||
keybind: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn initialize_settings(pool: &SqlitePool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let default_keybind = KeybindSetting {
|
||||
keybind: vec!["Meta".to_string(), "V".to_string()],
|
||||
};
|
||||
let json = serde_json::to_string(&default_keybind)?;
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO settings (key, value) VALUES ('keybind', ?)"
|
||||
)
|
||||
.bind(json)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn save_keybind(
|
||||
app_handle: tauri::AppHandle,
|
||||
keybind: Vec<String>,
|
||||
pool: tauri::State<'_, SqlitePool>,
|
||||
) -> Result<(), String> {
|
||||
let json = serde_json::to_string(&keybind).map_err(|e| e.to_string())?;
|
||||
|
||||
sqlx::query("INSERT OR REPLACE INTO settings (key, value) VALUES ('keybind', ?)")
|
||||
.bind(json)
|
||||
.execute(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let keybind_str = keybind.join("+");
|
||||
app_handle
|
||||
.emit("update-shortcut", keybind_str)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_setting(
|
||||
pool: tauri::State<'_, SqlitePool>,
|
||||
key: String
|
||||
) -> Result<String, String> {
|
||||
let row = sqlx::query("SELECT value FROM settings WHERE key = ?")
|
||||
.bind(key)
|
||||
.fetch_optional(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(row.map(|r| r.get("value")).unwrap_or_default())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn save_setting(
|
||||
pool: tauri::State<'_, SqlitePool>,
|
||||
key: String,
|
||||
value: String
|
||||
) -> Result<(), String> {
|
||||
sqlx::query("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)")
|
||||
.bind(key)
|
||||
.bind(value)
|
||||
.execute(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_keybind(
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<Vec<String>, String> {
|
||||
let pool = app_handle.state::<SqlitePool>();
|
||||
|
||||
let row = sqlx::query("SELECT value FROM settings WHERE key = 'keybind'")
|
||||
.fetch_optional(&*pool)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let json = row
|
||||
.map(|r| r.get::<String, _>("value"))
|
||||
.unwrap_or_else(|| {
|
||||
serde_json::to_string(&vec!["Meta".to_string(), "V".to_string()])
|
||||
.expect("Failed to serialize default keybind")
|
||||
});
|
||||
|
||||
serde_json::from_str::<Vec<String>>(&json)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue