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"
dependencies = [
"cjdic2-core",
"rusqlite",
"serde",
"serde_json",
"tauri",
"tauri-build",
"tauri-plugin-opener",
@@ -461,6 +458,7 @@ dependencies = [
"rusqlite",
"serde",
"serde_json",
"thiserror 2.0.18",
]
[[package]]
+1
View File
@@ -10,3 +10,4 @@ crate-type = ["cdylib", "rlib"]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
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 service;
pub use error::CJDicError;
pub use models::*;
pub use service::AppService;
pub fn add(left: u64, right: u64) -> u64 {
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]": {
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.formatOnSave": true
}
}
+15 -5
View File
@@ -1,15 +1,24 @@
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core";
import "./App.css";
import './App.css';
import { useEffect, useState } from 'react';
import { invoke } from '@tauri-apps/api/core';
import reactLogo from './assets/react.svg';
function App() {
const [greetMsg, setGreetMsg] = useState("");
const [name, setName] = useState("");
useEffect(() => {
invoke("list_entries").then((r) => {
setGreetMsg(JSON.stringify(r));
});
}, [name]);
async function greet() {
invoke("add_entry", { name });
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
setGreetMsg(await invoke("greet", { name }));
}
return (
@@ -39,6 +48,7 @@ function App() {
<input
id="greet-input"
onChange={(e) => setName(e.currentTarget.value)}
autoComplete="off"
placeholder="Enter a name..."
/>
<button type="submit">Greet</button>
-3
View File
@@ -20,7 +20,4 @@ tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
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" }
+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 rusqlite::Connection;
use std::sync::Mutex;
mod db;
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)
}
mod command;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
@@ -17,31 +10,18 @@ pub fn run() {
.plugin(tauri_plugin_opener::init())
.setup(|app| {
let cfg_dir = app.path().app_config_dir();
let app_dir = cfg_dir
.unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")));
let app_dir = cfg_dir.unwrap_or_else(|_| {
std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."))
});
std::fs::create_dir_all(&app_dir)?;
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(())
})
.invoke_handler(tauri::generate_handler![greet, db::get_db])
.invoke_handler(tauri::generate_handler![add_entry, list_entries])
.build(tauri::generate_context!())
.expect("error while running tauri application")
.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>
}