dev-manager-tauri/src-tauri/src/commands/cloud_products.rs
2026-09-21 12:52:37 +09:00

175 lines
5.6 KiB
Rust

use rusqlite::{params, Connection};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CloudProduct {
pub id: String,
pub vendor: String,
pub product_type: String,
pub name: String,
pub region: Option<String>,
pub instance_id: Option<String>,
pub endpoint: Option<String>,
pub expire_at: Option<String>,
pub status: String,
pub config_data: String,
pub notes: Option<String>,
pub sort_order: i32,
pub created_at: Option<String>,
pub updated_at: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct SaveCloudProductInput {
pub vendor: String,
pub product_type: String,
pub name: String,
pub region: Option<String>,
pub instance_id: Option<String>,
pub endpoint: Option<String>,
pub expire_at: Option<String>,
pub status: String,
pub config_data: Option<String>,
pub notes: Option<String>,
pub sort_order: Option<i32>,
}
fn row_to_cloud_product(row: &rusqlite::Row<'_>) -> rusqlite::Result<CloudProduct> {
Ok(CloudProduct {
id: row.get(0)?,
vendor: row.get(1)?,
product_type: row.get(2)?,
name: row.get(3)?,
region: row.get(4)?,
instance_id: row.get(5)?,
endpoint: row.get(6)?,
expire_at: row.get(7)?,
status: row.get(8)?,
config_data: row.get(9)?,
notes: row.get(10)?,
sort_order: row.get(11)?,
created_at: row.get(12)?,
updated_at: row.get(13)?,
})
}
const SELECT_COLS: &str =
"id, vendor, product_type, name, region, instance_id, endpoint, expire_at, \
status, config_data, notes, sort_order, created_at, updated_at";
pub fn list_cloud_products(conn: &Connection) -> Vec<CloudProduct> {
let sql = format!("SELECT {SELECT_COLS} FROM cloud_products ORDER BY vendor, sort_order, name");
let mut stmt = match conn.prepare(&sql) {
Ok(s) => s,
Err(_) => return vec![],
};
stmt.query_map([], row_to_cloud_product)
.map(|iter| iter.filter_map(|r| r.ok()).collect())
.unwrap_or_default()
}
fn get_cloud_product_by_id(conn: &Connection, id: &str) -> Option<CloudProduct> {
let sql = format!("SELECT {SELECT_COLS} FROM cloud_products WHERE id = ?1");
conn.query_row(&sql, params![id], row_to_cloud_product).ok()
}
pub fn create_cloud_product(
conn: &Connection,
input: &SaveCloudProductInput,
) -> Result<CloudProduct, String> {
let id = format!("cp-{}", uuid::Uuid::new_v4());
let config_data = input.config_data.as_deref().unwrap_or("{}");
conn.execute(
"INSERT INTO cloud_products
(id, vendor, product_type, name, region, instance_id, endpoint, expire_at,
status, config_data, notes, sort_order)
VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12)",
params![
id,
input.vendor,
input.product_type,
input.name,
input.region,
input.instance_id,
input.endpoint,
input.expire_at,
input.status,
config_data,
input.notes,
input.sort_order.unwrap_or(0)
],
)
.map_err(|e| e.to_string())?;
get_cloud_product_by_id(conn, &id).ok_or_else(|| "创建后查询失败".into())
}
pub fn update_cloud_product(
conn: &Connection,
id: &str,
input: &SaveCloudProductInput,
) -> Result<CloudProduct, String> {
let config_data = input.config_data.as_deref().unwrap_or("{}");
let rows = conn
.execute(
"UPDATE cloud_products
SET vendor=?1, product_type=?2, name=?3, region=?4, instance_id=?5,
endpoint=?6, expire_at=?7, status=?8, config_data=?9, notes=?10,
sort_order=?11, updated_at=datetime('now')
WHERE id=?12",
params![
input.vendor,
input.product_type,
input.name,
input.region,
input.instance_id,
input.endpoint,
input.expire_at,
input.status,
config_data,
input.notes,
input.sort_order.unwrap_or(0),
id
],
)
.map_err(|e| e.to_string())?;
if rows == 0 {
return Err(format!("云产品 {} 不存在", id));
}
get_cloud_product_by_id(conn, id).ok_or_else(|| "更新后查询失败".into())
}
pub fn delete_cloud_product_fn(conn: &Connection, id: &str) -> Result<(), String> {
conn.execute("DELETE FROM cloud_products WHERE id=?1", params![id])
.map_err(|e| e.to_string())?;
Ok(())
}
// ── Tauri commands ───────────────────────────────────────────────────────────
#[tauri::command]
pub fn get_cloud_products() -> Result<Vec<CloudProduct>, String> {
let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
Ok(list_cloud_products(&conn))
}
#[tauri::command]
pub fn add_cloud_product(input: SaveCloudProductInput) -> Result<CloudProduct, String> {
let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
create_cloud_product(&conn, &input)
}
#[tauri::command]
pub fn edit_cloud_product(
id: String,
input: SaveCloudProductInput,
) -> Result<CloudProduct, String> {
let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
update_cloud_product(&conn, &id, &input)
}
#[tauri::command]
pub fn delete_cloud_product(id: String) -> Result<(), String> {
let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
delete_cloud_product_fn(&conn, &id)
}