mirror of
https://github.com/ByteAtATime/raycast-linux.git
synced 2025-09-10 16:06:26 +00:00
refactor(backend): abstract database logic into generic Store
This commit introduces a generic `Store` struct to handle all common database operations, such as connection management and schema initialization. All existing manager structs (`QuicklinkManager`, `SnippetManager`, `FrecencyManager`, `ClipboardHistoryManager`, `AiUsageManager`) have been refactored to use this new abstraction.
This commit is contained in:
parent
23c222a956
commit
7156827585
7 changed files with 186 additions and 223 deletions
|
@ -1,70 +1,64 @@
|
|||
use crate::error::AppError;
|
||||
use crate::snippets::types::Snippet;
|
||||
use crate::store::Store;
|
||||
use chrono::{DateTime, Utc};
|
||||
use rusqlite::{params, Connection, Result as RusqliteResult};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tauri::{AppHandle, Manager};
|
||||
use rusqlite::params;
|
||||
use std::sync::Arc;
|
||||
use tauri::AppHandle;
|
||||
|
||||
const SNIPPETS_SCHEMA: &str = "CREATE TABLE IF NOT EXISTS snippets (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
keyword TEXT NOT NULL UNIQUE,
|
||||
content TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SnippetManager {
|
||||
db: Arc<Mutex<Connection>>,
|
||||
store: Arc<Store>,
|
||||
}
|
||||
|
||||
impl SnippetManager {
|
||||
pub fn new(app_handle: AppHandle) -> Result<Self, AppError> {
|
||||
let data_dir = app_handle
|
||||
.path()
|
||||
.app_local_data_dir()
|
||||
.map_err(|_| AppError::DirectoryNotFound)?;
|
||||
let db_path = data_dir.join("snippets.sqlite");
|
||||
let db = Connection::open(db_path)?;
|
||||
pub fn new(app_handle: &AppHandle) -> Result<Self, AppError> {
|
||||
let store = Store::new(app_handle, "snippets.sqlite")?;
|
||||
store.init_table(SNIPPETS_SCHEMA)?;
|
||||
|
||||
// Handle simple schema migrations in a block to drop the lock
|
||||
{
|
||||
let db = store.conn();
|
||||
let mut stmt = db.prepare("PRAGMA table_info(snippets)")?;
|
||||
let columns: Vec<String> = stmt
|
||||
.query_map([], |row| row.get(1))?
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
if !columns.contains(&"times_used".to_string()) {
|
||||
db.execute(
|
||||
"ALTER TABLE snippets ADD COLUMN times_used INTEGER NOT NULL DEFAULT 0",
|
||||
[],
|
||||
)?;
|
||||
}
|
||||
if !columns.contains(&"last_used_at".to_string()) {
|
||||
db.execute(
|
||||
"ALTER TABLE snippets ADD COLUMN last_used_at INTEGER NOT NULL DEFAULT 0",
|
||||
[],
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
db: Arc::new(Mutex::new(db)),
|
||||
store: Arc::new(store),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn init_db(&self) -> RusqliteResult<()> {
|
||||
let db = self.db.lock().unwrap();
|
||||
db.execute(
|
||||
"CREATE TABLE IF NOT EXISTS snippets (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
keyword TEXT NOT NULL UNIQUE,
|
||||
content TEXT NOT NULL,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
let mut stmt = db.prepare("PRAGMA table_info(snippets)")?;
|
||||
let columns: Vec<String> = stmt
|
||||
.query_map([], |row| row.get(1))?
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
if !columns.contains(&"times_used".to_string()) {
|
||||
db.execute(
|
||||
"ALTER TABLE snippets ADD COLUMN times_used INTEGER NOT NULL DEFAULT 0",
|
||||
[],
|
||||
)?;
|
||||
}
|
||||
if !columns.contains(&"last_used_at".to_string()) {
|
||||
db.execute(
|
||||
"ALTER TABLE snippets ADD COLUMN last_used_at INTEGER NOT NULL DEFAULT 0",
|
||||
[],
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_snippet(
|
||||
&self,
|
||||
name: String,
|
||||
keyword: String,
|
||||
content: String,
|
||||
) -> Result<i64, AppError> {
|
||||
let db = self.db.lock().unwrap();
|
||||
let db = self.store.conn();
|
||||
let now = Utc::now().timestamp();
|
||||
db.execute(
|
||||
"INSERT INTO snippets (name, keyword, content, created_at, updated_at, times_used, last_used_at)
|
||||
|
@ -75,7 +69,7 @@ impl SnippetManager {
|
|||
}
|
||||
|
||||
pub fn list_snippets(&self, search_term: Option<String>) -> Result<Vec<Snippet>, AppError> {
|
||||
let db = self.db.lock().unwrap();
|
||||
let db = self.store.conn();
|
||||
let mut query = "SELECT id, name, keyword, content, created_at, updated_at, times_used, last_used_at FROM snippets".to_string();
|
||||
let mut params_vec: Vec<Box<dyn rusqlite::ToSql>> = vec![];
|
||||
|
||||
|
@ -119,7 +113,7 @@ impl SnippetManager {
|
|||
keyword: String,
|
||||
content: String,
|
||||
) -> Result<(), AppError> {
|
||||
let db = self.db.lock().unwrap();
|
||||
let db = self.store.conn();
|
||||
let now = Utc::now().timestamp();
|
||||
db.execute(
|
||||
"UPDATE snippets SET name = ?1, keyword = ?2, content = ?3, updated_at = ?4 WHERE id = ?5",
|
||||
|
@ -129,13 +123,13 @@ impl SnippetManager {
|
|||
}
|
||||
|
||||
pub fn delete_snippet(&self, id: i64) -> Result<(), AppError> {
|
||||
let db = self.db.lock().unwrap();
|
||||
let db = self.store.conn();
|
||||
db.execute("DELETE FROM snippets WHERE id = ?1", params![id])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn snippet_was_used(&self, id: i64) -> Result<(), AppError> {
|
||||
let db = self.db.lock().unwrap();
|
||||
let db = self.store.conn();
|
||||
let now = Utc::now().timestamp();
|
||||
db.execute(
|
||||
"UPDATE snippets SET times_used = times_used + 1, last_used_at = ?1 WHERE id = ?2",
|
||||
|
@ -145,7 +139,7 @@ impl SnippetManager {
|
|||
}
|
||||
|
||||
pub fn find_snippet_by_keyword(&self, keyword: &str) -> Result<Option<Snippet>, AppError> {
|
||||
let db = self.db.lock().unwrap();
|
||||
let db = self.store.conn();
|
||||
let mut stmt = db.prepare("SELECT id, name, keyword, content, created_at, updated_at, times_used, last_used_at FROM snippets WHERE keyword = ?1")?;
|
||||
let mut rows = stmt.query_map(params![keyword], |row| {
|
||||
let created_at_ts: i64 = row.get(4)?;
|
||||
|
@ -171,7 +165,7 @@ impl SnippetManager {
|
|||
}
|
||||
|
||||
pub fn find_snippet_by_name(&self, name: &str) -> Result<Option<Snippet>, AppError> {
|
||||
let db = self.db.lock().unwrap();
|
||||
let db = self.store.conn();
|
||||
let mut stmt = db.prepare("SELECT id, name, keyword, content, created_at, updated_at, times_used, last_used_at FROM snippets WHERE name = ?1 ORDER BY updated_at DESC LIMIT 1")?;
|
||||
let mut rows = stmt.query_map(params![name], |row| {
|
||||
let created_at_ts: i64 = row.get(4)?;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue