mirror of
https://github.com/patarapolw/cjdic2.git
synced 2026-11-09 17:39:35 +00:00
consume core in Tauri
This commit is contained in:
1 parent
876b879a65
commit
59968e0d6c
14 files changed
+157
-75
No files matched your search
Generated
+1
-3
@@ -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]]
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -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)?)
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+3
@@ -15,5 +15,8 @@
|
|||||||
},
|
},
|
||||||
"[typescriptreact]": {
|
"[typescriptreact]": {
|
||||||
"editor.formatOnSave": true
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"[javascriptreact]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-5
@@ -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>
|
||||||
|
|||||||
@@ -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" }
|
||||||
@@ -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())
|
||||||
|
}
|
||||||
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
use rusqlite::Connection;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
pub struct AppState {
|
|
||||||
pub conn: Mutex<Connection>
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user