consume core in Tauri

This commit is contained in:
polv committed 2026-02-21 23:33:10 +07:00
1 parent 876b879a65
commit 59968e0d6c
14 files changed
+157 -75

No files matched your search

Generated
+1 -3
View File
@@ -446,9 +446,6 @@ name = "cjdic2"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cjdic2-core", "cjdic2-core",
"rusqlite",
"serde",
"serde_json",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-opener", "tauri-plugin-opener",
@@ -461,6 +458,7 @@ dependencies = [
"rusqlite", "rusqlite",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 2.0.18",
] ]
[[package]] [[package]]
+1
View File
@@ -10,3 +10,4 @@ crate-type = ["cdylib", "rlib"]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
rusqlite = { version = "0.38.0", features = ["bundled", "unlock_notify"] } rusqlite = { version = "0.38.0", features = ["bundled", "unlock_notify"] }
thiserror = "2.0.18"
+6
View File
@@ -0,0 +1,6 @@
use crate::{error::CJDicError, service::AppService};
pub fn list_entries_json(service: &AppService) -> Result<String, CJDicError> {
let entries = service.list_entries()?;
Ok(serde_json::to_string(&entries)?)
}
+63
View File
@@ -0,0 +1,63 @@
use std::{path::Path, sync::Mutex};
use rusqlite::{Connection, Result};
use crate::models::Entry;
pub struct Database {
conn: Mutex<Connection>,
}
impl Database {
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {
let conn = Connection::open(path)?;
Ok(Self {
conn: Mutex::new(conn),
})
}
pub fn init(&self) -> Result<()> {
let conn = self.conn.lock().unwrap();
conn.execute_batch(
"
CREATE TABLE IF NOT EXISTS entries (
id INTEGER PRIMARY KEY,
word TEXT NOT NULL,
definition TEXT NOT NULL
)",
)?;
Ok(())
}
pub fn insert_entry(&self, word: &str, definition: &str) -> Result<()> {
let conn = self.conn.lock().unwrap();
conn.execute(
"INSERT INTO entries (word, definition) VALUES (?, ?)",
[word, definition],
)?;
Ok(())
}
pub fn fetch_all_entries(&self) -> Result<Vec<Entry>> {
let conn = self.conn.lock().unwrap();
let mut stmt = conn.prepare("SELECT id, word, definition FROM entries")?;
let rows = stmt.query_map([], |row| {
Ok(Entry {
id: row.get(0)?,
word: row.get(1)?,
definition: row.get(2)?,
})
})?;
let mut entries = Vec::new();
for entry in rows {
entries.push(entry?);
}
Ok(entries)
}
}
+13
View File
@@ -0,0 +1,13 @@
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CJDicError {
#[error("Database error: {0}")]
Database(#[from] rusqlite::Error),
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("Not found")]
NotFound,
}
+8
View File
@@ -1,4 +1,12 @@
pub mod api;
pub mod db;
pub mod error;
pub mod models; pub mod models;
pub mod service;
pub use error::CJDicError;
pub use models::*;
pub use service::AppService;
pub fn add(left: u64, right: u64) -> u64 { pub fn add(left: u64, right: u64) -> u64 {
left + right left + right
+24
View File
@@ -0,0 +1,24 @@
use std::path::Path;
use crate::{db::Database, error::CJDicError, models::Entry};
pub struct AppService {
db: Database,
}
impl AppService {
pub fn new<P: AsRef<Path>>(db_path: P) -> Result<Self, CJDicError> {
let db = Database::new(db_path)?;
db.init()?;
Ok(Self { db })
}
pub fn add_entry(&self, word: &str, definition: &str) -> Result<(), CJDicError> {
self.db.insert_entry(word, definition)?;
Ok(())
}
pub fn list_entries(&self) -> Result<Vec<Entry>, CJDicError> {
Ok(self.db.fetch_all_entries()?)
}
}
+3
View File
@@ -15,5 +15,8 @@
}, },
"[typescriptreact]": { "[typescriptreact]": {
"editor.formatOnSave": true "editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.formatOnSave": true
} }
} }
+15 -5
View File
@@ -1,15 +1,24 @@
import { useState } from "react"; import './App.css';
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core"; import { useEffect, useState } from 'react';
import "./App.css";
import { invoke } from '@tauri-apps/api/core';
import reactLogo from './assets/react.svg';
function App() { function App() {
const [greetMsg, setGreetMsg] = useState(""); const [greetMsg, setGreetMsg] = useState("");
const [name, setName] = useState(""); const [name, setName] = useState("");
useEffect(() => {
invoke("list_entries").then((r) => {
setGreetMsg(JSON.stringify(r));
});
}, [name]);
async function greet() { async function greet() {
invoke("add_entry", { name });
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
setGreetMsg(await invoke("greet", { name }));
} }
return ( return (
@@ -39,6 +48,7 @@ function App() {
<input <input
id="greet-input" id="greet-input"
onChange={(e) => setName(e.currentTarget.value)} onChange={(e) => setName(e.currentTarget.value)}
autoComplete="off"
placeholder="Enter a name..." placeholder="Enter a name..."
/> />
<button type="submit">Greet</button> <button type="submit">Greet</button>
-3
View File
@@ -20,7 +20,4 @@ tauri-build = { version = "2", features = [] }
[dependencies] [dependencies]
tauri = { version = "2", features = [] } tauri = { version = "2", features = [] }
tauri-plugin-opener = "2" tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
rusqlite = { version = "0.38.0", features = ["bundled", "unlock_notify"] }
cjdic2-core = { path = "../src-core" } cjdic2-core = { path = "../src-core" }
+14
View File
@@ -0,0 +1,14 @@
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
use cjdic2_core::{AppService, Entry};
#[tauri::command]
pub fn add_entry(name: &str, state: tauri::State<AppService>) -> Result<(), String> {
state
.add_entry(name, "definition")
.map_err(|e| e.to_string())
}
#[tauri::command]
pub fn list_entries(state: tauri::State<AppService>) -> Result<Vec<Entry>, String> {
state.list_entries().map_err(|e| e.to_string())
}
-29
View File
@@ -1,29 +0,0 @@
use serde::Serialize;
use crate::state;
#[derive(Serialize)]
pub struct SearchRow {
a: i32,
b: i32,
}
#[tauri::command]
pub fn get_db(state: tauri::State<state::AppState>) -> Result<Vec<SearchRow>, String> {
let conn = state.conn.lock().map_err(|e| e.to_string())?;
let mut stmt = conn.prepare("SELECT a, b FROM test").map_err(|e| e.to_string())?;
let rows = stmt.query_map([], |r| {
Ok(SearchRow {
a: r.get(0)?,
b: r.get(1)?,
})
}).map_err(|e| e.to_string())?;
let mut out = Vec::new();
for r in rows {
out.push(r.map_err(|e| e.to_string())?);
}
Ok(out)
}
+9 -29
View File
@@ -1,15 +1,8 @@
use crate::command::*;
use cjdic2_core::*;
use tauri::Manager; use tauri::Manager;
use rusqlite::Connection;
use std::sync::Mutex;
mod db; mod command;
mod state;
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
@@ -17,31 +10,18 @@ pub fn run() {
.plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_opener::init())
.setup(|app| { .setup(|app| {
let cfg_dir = app.path().app_config_dir(); let cfg_dir = app.path().app_config_dir();
let app_dir = cfg_dir let app_dir = cfg_dir.unwrap_or_else(|_| {
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."))); std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."))
});
std::fs::create_dir_all(&app_dir)?; std::fs::create_dir_all(&app_dir)?;
let db_path = app_dir.join("cjdic.db"); let db_path = app_dir.join("cjdic.db");
let is_new = !db_path.exists(); let service = AppService::new(&db_path)?;
app.manage(service);
println!("{}", cjdic2_core::add(1, 2));
let conn = Connection::open(&db_path)?;
if is_new {
conn.execute_batch("CREATE TABLE test (a, b);")?;
let mut stmt = conn.prepare("INSERT INTO test VALUES (?1, ?2)")?;
stmt.insert([1, 2])?;
stmt.insert([3, 4])?;
}
app.manage(state::AppState{
conn: Mutex::new(conn),
});
Ok(()) Ok(())
}) })
.invoke_handler(tauri::generate_handler![greet, db::get_db]) .invoke_handler(tauri::generate_handler![add_entry, list_entries])
.build(tauri::generate_context!()) .build(tauri::generate_context!())
.expect("error while running tauri application") .expect("error while running tauri application")
.run(|_app_handle, event| match event { .run(|_app_handle, event| match event {
-6
View File
@@ -1,6 +0,0 @@
use rusqlite::Connection;
use std::sync::Mutex;
pub struct AppState {
pub conn: Mutex<Connection>
}