migrar Alpha a Tauri app con Turso/libsql como BD local
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Mutex;
|
||||
use tauri::State;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Project {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub key: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub status: String,
|
||||
pub start_date: Option<String>,
|
||||
pub end_date: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct WorkItem {
|
||||
pub id: i64,
|
||||
pub project_id: i64,
|
||||
pub code: Option<String>,
|
||||
pub title: String,
|
||||
pub description: Option<String>,
|
||||
#[serde(rename = "type")]
|
||||
pub wi_type: String,
|
||||
pub status: String,
|
||||
pub priority: String,
|
||||
}
|
||||
|
||||
async fn get_conn(db_path: &str) -> Result<libsql::Connection, String> {
|
||||
let db = libsql::Builder::new_local(db_path)
|
||||
.build()
|
||||
.await
|
||||
.map_err(|e| format!("DB open: {e}"))?;
|
||||
|
||||
let conn = db.connect().map_err(|e| format!("Connect: {e}"))?;
|
||||
|
||||
conn.execute_batch(
|
||||
"CREATE TABLE IF NOT EXISTS projects (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
key TEXT,
|
||||
description TEXT,
|
||||
status TEXT DEFAULT 'active',
|
||||
start_date TEXT,
|
||||
end_date TEXT,
|
||||
created_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS work_items (
|
||||
id INTEGER PRIMARY KEY,
|
||||
project_id INTEGER NOT NULL,
|
||||
code TEXT,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
type TEXT DEFAULT 'task',
|
||||
status TEXT DEFAULT 'backlog',
|
||||
priority TEXT DEFAULT 'medium',
|
||||
created_at TEXT DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (project_id) REFERENCES projects(id)
|
||||
);"
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("Migration: {e}"))?;
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub mod commands {
|
||||
use super::*;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_projects(state: State<'_, Mutex<String>>) -> Result<Vec<Project>, String> {
|
||||
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
|
||||
let conn = get_conn(&db_path).await?;
|
||||
|
||||
let mut rows = conn
|
||||
.query("SELECT id, name, key, description, status, start_date, end_date FROM projects ORDER BY name", ())
|
||||
.await
|
||||
.map_err(|e| format!("Query: {e}"))?;
|
||||
|
||||
let mut projects = Vec::new();
|
||||
while let Some(row) = rows.next().await.map_err(|e| format!("Row: {e}"))? {
|
||||
projects.push(Project {
|
||||
id: row.get::<i64>(0).unwrap_or(0),
|
||||
name: row.get::<String>(1).unwrap_or_default(),
|
||||
key: row.get::<String>(2).ok(),
|
||||
description: row.get::<String>(3).ok(),
|
||||
status: row.get::<String>(4).unwrap_or_else(|_| "active".into()),
|
||||
start_date: row.get::<String>(5).ok(),
|
||||
end_date: row.get::<String>(6).ok(),
|
||||
});
|
||||
}
|
||||
Ok(projects)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn save_project(state: State<'_, Mutex<String>>, project: Project) -> Result<i64, String> {
|
||||
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
|
||||
let conn = get_conn(&db_path).await?;
|
||||
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO projects (id, name, key, description, status, start_date, end_date)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
libsql::params![
|
||||
project.id,
|
||||
project.name,
|
||||
project.key,
|
||||
project.description,
|
||||
project.status,
|
||||
project.start_date,
|
||||
project.end_date,
|
||||
],
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("Insert: {e}"))?;
|
||||
|
||||
Ok(conn.last_insert_rowid())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_project(state: State<'_, Mutex<String>>, id: i64) -> Result<(), String> {
|
||||
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
|
||||
let conn = get_conn(&db_path).await?;
|
||||
|
||||
conn.execute("DELETE FROM work_items WHERE project_id = ?1", libsql::params![id])
|
||||
.await
|
||||
.map_err(|e| format!("Delete WIs: {e}"))?;
|
||||
|
||||
conn.execute("DELETE FROM projects WHERE id = ?1", libsql::params![id])
|
||||
.await
|
||||
.map_err(|e| format!("Delete project: {e}"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_work_items(state: State<'_, Mutex<String>>, project_id: i64) -> Result<Vec<WorkItem>, String> {
|
||||
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
|
||||
let conn = get_conn(&db_path).await?;
|
||||
|
||||
let mut rows = conn
|
||||
.query(
|
||||
"SELECT id, project_id, code, title, description, type, status, priority FROM work_items WHERE project_id = ?1 ORDER BY created_at DESC",
|
||||
libsql::params![project_id],
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("Query: {e}"))?;
|
||||
|
||||
let mut items = Vec::new();
|
||||
while let Some(row) = rows.next().await.map_err(|e| format!("Row: {e}"))? {
|
||||
items.push(WorkItem {
|
||||
id: row.get::<i64>(0).unwrap_or(0),
|
||||
project_id: row.get::<i64>(1).unwrap_or(0),
|
||||
code: row.get::<String>(2).ok(),
|
||||
title: row.get::<String>(3).unwrap_or_default(),
|
||||
description: row.get::<String>(4).ok(),
|
||||
wi_type: row.get::<String>(5).unwrap_or_else(|_| "task".into()),
|
||||
status: row.get::<String>(6).unwrap_or_else(|_| "backlog".into()),
|
||||
priority: row.get::<String>(7).unwrap_or_else(|_| "medium".into()),
|
||||
});
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn save_work_item(state: State<'_, Mutex<String>>, item: WorkItem) -> Result<i64, String> {
|
||||
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
|
||||
let conn = get_conn(&db_path).await?;
|
||||
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO work_items (id, project_id, code, title, description, type, status, priority)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
|
||||
libsql::params![
|
||||
item.id,
|
||||
item.project_id,
|
||||
item.code,
|
||||
item.title,
|
||||
item.description,
|
||||
item.wi_type,
|
||||
item.status,
|
||||
item.priority,
|
||||
],
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("Insert: {e}"))?;
|
||||
|
||||
Ok(conn.last_insert_rowid())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_work_item(state: State<'_, Mutex<String>>, id: i64) -> Result<(), String> {
|
||||
let db_path = state.lock().map_err(|e| e.to_string())?.clone();
|
||||
let conn = get_conn(&db_path).await?;
|
||||
|
||||
conn.execute("DELETE FROM work_items WHERE id = ?1", libsql::params![id])
|
||||
.await
|
||||
.map_err(|e| format!("Delete: {e}"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user