friends list CRD
This commit is contained in:
Generated
+752
-4
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,7 @@ ed25519-dalek = "3.0.0"
|
|||||||
getrandom = "0.4.3"
|
getrandom = "0.4.3"
|
||||||
device_query = "4.0.1"
|
device_query = "4.0.1"
|
||||||
tokio = "1.53.1"
|
tokio = "1.53.1"
|
||||||
|
sqlx = { version = "0.8.6", features = ["runtime-tokio-rustls", "sqlite", "migrate"] }
|
||||||
tauri-specta = { version = "2.0.0-rc.21", features = ["derive", "typescript"] }
|
tauri-specta = { version = "2.0.0-rc.21", features = ["derive", "typescript"] }
|
||||||
specta = "2.0.0-rc.21"
|
specta = "2.0.0-rc.21"
|
||||||
specta-typescript = { version = "0.0.9" }
|
specta-typescript = { version = "0.0.9" }
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
CREATE TABLE friends (
|
||||||
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
|
display_name TEXT NOT NULL
|
||||||
|
);
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions};
|
||||||
|
use sqlx::{Pool, Sqlite};
|
||||||
|
use std::error::Error;
|
||||||
|
use tauri::{AppHandle, Manager};
|
||||||
|
|
||||||
|
const DATABASE_FILE: &str = "wyd.sqlite";
|
||||||
|
|
||||||
|
pub struct AppDatabase {
|
||||||
|
pool: Pool<Sqlite>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppDatabase {
|
||||||
|
pub fn new(pool: Pool<Sqlite>) -> Self {
|
||||||
|
Self { pool }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pool(&self) -> &Pool<Sqlite> {
|
||||||
|
&self.pool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn init(app: &AppHandle) -> Result<(), Box<dyn Error>> {
|
||||||
|
let app_data_dir = app.path().app_data_dir()?;
|
||||||
|
std::fs::create_dir_all(&app_data_dir)?;
|
||||||
|
|
||||||
|
let db_path = app_data_dir.join(DATABASE_FILE);
|
||||||
|
let options = SqliteConnectOptions::new()
|
||||||
|
.filename(db_path)
|
||||||
|
.create_if_missing(true)
|
||||||
|
.journal_mode(SqliteJournalMode::Wal)
|
||||||
|
.foreign_keys(true);
|
||||||
|
|
||||||
|
let pool = SqlitePoolOptions::new()
|
||||||
|
.max_connections(5)
|
||||||
|
.connect_with(options)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
sqlx::migrate!("./migrations").run(&pool).await?;
|
||||||
|
|
||||||
|
app.manage(AppDatabase::new(pool));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn command_error(error: impl std::fmt::Display) -> String {
|
||||||
|
error.to_string()
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
use crate::db::{self, AppDatabase};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use specta::Type;
|
||||||
|
use tauri::State;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Type, sqlx::FromRow)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Friend {
|
||||||
|
pub id: String,
|
||||||
|
pub display_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
pub async fn create_friend(
|
||||||
|
database: State<'_, AppDatabase>,
|
||||||
|
friend: Friend,
|
||||||
|
) -> Result<Friend, String> {
|
||||||
|
sqlx::query("INSERT INTO friends (id, display_name) VALUES (?1, ?2)")
|
||||||
|
.bind(&friend.id)
|
||||||
|
.bind(&friend.display_name)
|
||||||
|
.execute(database.pool())
|
||||||
|
.await
|
||||||
|
.map_err(db::command_error)?;
|
||||||
|
|
||||||
|
Ok(friend)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
pub async fn list_friends(database: State<'_, AppDatabase>) -> Result<Vec<Friend>, String> {
|
||||||
|
sqlx::query_as::<_, Friend>(
|
||||||
|
"SELECT id, display_name FROM friends ORDER BY display_name COLLATE NOCASE, id",
|
||||||
|
)
|
||||||
|
.fetch_all(database.pool())
|
||||||
|
.await
|
||||||
|
.map_err(db::command_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
pub async fn get_friend(
|
||||||
|
database: State<'_, AppDatabase>,
|
||||||
|
id: String,
|
||||||
|
) -> Result<Option<Friend>, String> {
|
||||||
|
sqlx::query_as::<_, Friend>("SELECT id, display_name FROM friends WHERE id = ?1")
|
||||||
|
.bind(id)
|
||||||
|
.fetch_optional(database.pool())
|
||||||
|
.await
|
||||||
|
.map_err(db::command_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
#[specta::specta]
|
||||||
|
pub async fn delete_friend(database: State<'_, AppDatabase>, id: String) -> Result<bool, String> {
|
||||||
|
let result = sqlx::query("DELETE FROM friends WHERE id = ?1")
|
||||||
|
.bind(id)
|
||||||
|
.execute(database.pool())
|
||||||
|
.await
|
||||||
|
.map_err(db::command_error)?;
|
||||||
|
|
||||||
|
Ok(result.rows_affected() > 0)
|
||||||
|
}
|
||||||
+14
-3
@@ -1,17 +1,28 @@
|
|||||||
mod cursor;
|
mod cursor;
|
||||||
|
mod db;
|
||||||
|
mod friends;
|
||||||
mod ufa;
|
mod ufa;
|
||||||
|
mod windowing;
|
||||||
|
|
||||||
fn launch_app(app: &tauri::App) {
|
async fn launch_app(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let handle = app.handle();
|
let handle = app.handle();
|
||||||
|
crate::db::init(handle).await?;
|
||||||
crate::ufa::init();
|
crate::ufa::init();
|
||||||
crate::cursor::init(handle);
|
crate::cursor::init(handle);
|
||||||
|
crate::windowing::init(handle);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let specta_builder = tauri_specta::Builder::<tauri::Wry>::new()
|
let specta_builder = tauri_specta::Builder::<tauri::Wry>::new()
|
||||||
.error_handling(tauri_specta::ErrorHandlingMode::Throw)
|
.error_handling(tauri_specta::ErrorHandlingMode::Throw)
|
||||||
.commands(tauri_specta::collect_commands![])
|
.commands(tauri_specta::collect_commands![
|
||||||
|
crate::friends::create_friend,
|
||||||
|
crate::friends::list_friends,
|
||||||
|
crate::friends::get_friend,
|
||||||
|
crate::friends::delete_friend
|
||||||
|
])
|
||||||
.events(tauri_specta::collect_events![]);
|
.events(tauri_specta::collect_events![]);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
@@ -26,7 +37,7 @@ pub fn run() {
|
|||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.invoke_handler(specta_builder.invoke_handler())
|
.invoke_handler(specta_builder.invoke_handler())
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
launch_app(app);
|
tauri::async_runtime::block_on(launch_app(app))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.build(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
|
|||||||
+13
-2
@@ -5,7 +5,18 @@
|
|||||||
|
|
||||||
|
|
||||||
export const commands = {
|
export const commands = {
|
||||||
|
async createFriend(friend: Friend) : Promise<Friend> {
|
||||||
|
return await TAURI_INVOKE("create_friend", { friend });
|
||||||
|
},
|
||||||
|
async listFriends() : Promise<Friend[]> {
|
||||||
|
return await TAURI_INVOKE("list_friends");
|
||||||
|
},
|
||||||
|
async getFriend(id: string) : Promise<Friend | null> {
|
||||||
|
return await TAURI_INVOKE("get_friend", { id });
|
||||||
|
},
|
||||||
|
async deleteFriend(id: string) : Promise<boolean> {
|
||||||
|
return await TAURI_INVOKE("delete_friend", { id });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** user-defined events **/
|
/** user-defined events **/
|
||||||
@@ -18,7 +29,7 @@ export const commands = {
|
|||||||
|
|
||||||
/** user-defined types **/
|
/** user-defined types **/
|
||||||
|
|
||||||
|
export type Friend = { id: string; displayName: string }
|
||||||
|
|
||||||
/** tauri-specta globals **/
|
/** tauri-specta globals **/
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user