fetch
This commit is contained in:
parent
a08636b3ee
commit
779fc69405
11 changed files with 202 additions and 76 deletions
1
.tokeignore
Normal file
1
.tokeignore
Normal file
|
@ -0,0 +1 @@
|
|||
package-lock.json
|
36
package-lock.json
generated
36
package-lock.json
generated
|
@ -12,7 +12,8 @@
|
|||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^6.11.2",
|
||||
"react-router-dom": "^6.11.2"
|
||||
"react-router-dom": "^6.11.2",
|
||||
"swr": "^2.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.3.1",
|
||||
|
@ -1321,6 +1322,17 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/swr": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-2.1.5.tgz",
|
||||
"integrity": "sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw==",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
|
@ -1385,6 +1397,14 @@
|
|||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.3.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
|
||||
|
@ -2310,6 +2330,14 @@
|
|||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"swr": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-2.1.5.tgz",
|
||||
"integrity": "sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw==",
|
||||
"requires": {
|
||||
"use-sync-external-store": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
|
@ -2341,6 +2369,12 @@
|
|||
"picocolors": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
||||
"requires": {}
|
||||
},
|
||||
"vite": {
|
||||
"version": "4.3.9",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router": "^6.11.2",
|
||||
"react-router-dom": "^6.11.2"
|
||||
"react-router-dom": "^6.11.2",
|
||||
"swr": "^2.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.3.1",
|
||||
|
|
12
src-tauri/Cargo.lock
generated
12
src-tauri/Cargo.lock
generated
|
@ -657,6 +657,17 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
|
@ -1369,6 +1380,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"derivative",
|
||||
"dirs",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -10,8 +10,6 @@ edition = "2021"
|
|||
[workspace]
|
||||
members = ["database-maker"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.3", features = [] }
|
||||
|
||||
|
@ -24,7 +22,7 @@ anyhow = "1.0.71"
|
|||
clap = { version = "4.3.2", features = ["derive"] }
|
||||
sqlx = { version = "0.6.3", features = ["runtime-tokio-rustls", "sqlite"] }
|
||||
tokio = { version = "1.28.2", features = ["full"] }
|
||||
|
||||
derivative = "2.2.0"
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||
|
|
|
@ -3,41 +3,44 @@ use std::path::Path;
|
|||
use anyhow::Result;
|
||||
use sqlx::SqlitePool;
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncBufReadExt, BufReader},
|
||||
fs::File,
|
||||
io::{AsyncBufReadExt, BufReader},
|
||||
};
|
||||
|
||||
const SEPARATOR: char = ':';
|
||||
|
||||
pub async fn process_kradfile(pool: &SqlitePool, path: impl AsRef<Path>) -> Result<()> {
|
||||
let file = File::open(path.as_ref()).await?;
|
||||
pub async fn process_kradfile(
|
||||
pool: &SqlitePool,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<()> {
|
||||
let file = File::open(path.as_ref()).await?;
|
||||
|
||||
let file_reader = BufReader::new(file);
|
||||
let mut lines = file_reader.lines();
|
||||
let file_reader = BufReader::new(file);
|
||||
let mut lines = file_reader.lines();
|
||||
|
||||
loop {
|
||||
let line = match lines.next_line().await? {
|
||||
Some(v) => v,
|
||||
None => break,
|
||||
};
|
||||
loop {
|
||||
let line = match lines.next_line().await? {
|
||||
Some(v) => v,
|
||||
None => break,
|
||||
};
|
||||
|
||||
// Skip comments
|
||||
if line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
let parts = line.split(SEPARATOR).collect::<Vec<_>>();
|
||||
let (kanji, radicals) = match &parts[..] {
|
||||
&[kanji, radicals] => {
|
||||
let kanji = kanji.trim();
|
||||
let radicals = radicals.trim().split_whitespace().collect::<Vec<_>>();
|
||||
(kanji, radicals)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
println!("kanji: {}, radicals: {:?}", kanji, radicals);
|
||||
// Skip comments
|
||||
if line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
let parts = line.split(SEPARATOR).collect::<Vec<_>>();
|
||||
let (kanji, radicals) = match &parts[..] {
|
||||
&[kanji, radicals] => {
|
||||
let kanji = kanji.trim();
|
||||
let radicals = radicals.trim().split_whitespace().collect::<Vec<_>>();
|
||||
(kanji, radicals)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
println!("kanji: {}, radicals: {:?}", kanji, radicals);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,14 +3,45 @@ use tauri::State;
|
|||
|
||||
pub struct KanjiDb(pub SqlitePool);
|
||||
|
||||
#[derive(Debug, Derivative, Serialize, Deserialize)]
|
||||
#[derivative(Default)]
|
||||
pub struct GetKanjiOptions {
|
||||
#[derivative(Default(value = "10"))]
|
||||
how_many: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GetKanjiResult {
|
||||
count: u32,
|
||||
kanji: Vec<String>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_kanji(state: State<'_, KanjiDb>) -> Result<Vec<String>, ()> {
|
||||
let result = sqlx::query("SELECT * FROM KanjiSet LIMIT 5")
|
||||
.fetch_all(&state.0)
|
||||
pub async fn get_kanji(
|
||||
state: State<'_, KanjiDb>,
|
||||
options: Option<GetKanjiOptions>,
|
||||
) -> Result<GetKanjiResult, ()> {
|
||||
let opts = options.unwrap_or_default();
|
||||
|
||||
let result = sqlx::query(
|
||||
r#"SELECT * FROM KanjiSet
|
||||
LEFT JOIN KanjiMeaningSet ON KanjiSet.ID = KanjiMeaningSet.Kanji_ID
|
||||
WHERE MostUsedRank IS NOT NULL
|
||||
ORDER BY MostUsedRank
|
||||
LIMIT ?"#,
|
||||
)
|
||||
.bind(opts.how_many)
|
||||
.fetch_all(&state.0)
|
||||
.await
|
||||
.map_err(|_| ())?;
|
||||
|
||||
let kanji = result.into_iter().map(|row| row.get("Character")).collect();
|
||||
|
||||
let count = sqlx::query("SELECT COUNT(*) FROM KanjiSet")
|
||||
.fetch_one(&state.0)
|
||||
.await
|
||||
.map_err(|_| ())?;
|
||||
let count = count.try_get(0).map_err(|_| ())?;
|
||||
|
||||
let result = result.into_iter().map(|row| row.get("Character")).collect();
|
||||
|
||||
Ok(result)
|
||||
Ok(GetKanjiResult { kanji, count })
|
||||
}
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derivative;
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
mod kanji;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use sqlx::SqlitePool;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
||||
SqlitePool,
|
||||
};
|
||||
|
||||
use crate::kanji::KanjiDb;
|
||||
|
||||
|
@ -16,7 +26,11 @@ fn greet(name: &str) -> String {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let kanji_pool = SqlitePool::connect("./KanjiDatabase.sqlite").await?;
|
||||
let kanji_db_options =
|
||||
SqliteConnectOptions::from_str("./KanjiDatabase.sqlite")?.read_only(true);
|
||||
let kanji_pool = SqlitePoolOptions::new()
|
||||
.connect_with(kanji_db_options)
|
||||
.await?;
|
||||
|
||||
tauri::Builder::default()
|
||||
.manage(KanjiDb(kanji_pool))
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"identifier": "com.tauri.dev",
|
||||
"identifier": "io.mzhang.houhou",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
|
|
45
src/App.tsx
45
src/App.tsx
|
@ -1,27 +1,46 @@
|
|||
import { RouterProvider, createBrowserRouter } from "react-router-dom";
|
||||
import styles from "./App.module.scss"
|
||||
import { Link, RouterProvider, createHashRouter } from "react-router-dom";
|
||||
import styles from "./App.module.scss";
|
||||
import KanjiPane from "./panes/KanjiPane";
|
||||
import HomePane from "./panes/HomePane";
|
||||
import { createBrowserRouter } from "react-router-dom";
|
||||
import { Outlet, Route, createRoutesFromElements } from "react-router";
|
||||
|
||||
export default function App() {
|
||||
const router = createBrowserRouter(routes);
|
||||
|
||||
function Layout() {
|
||||
return (
|
||||
<>
|
||||
<ul className={styles.header}>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/srs">Srs</a></li>
|
||||
<li><a href="/kanji">Kanji</a></li>
|
||||
<li><a href="/vocab">Vocab</a></li>
|
||||
<li><a href="/settings">Settings</a></li>
|
||||
{routes.map((route) => (
|
||||
<li key={route.path}>
|
||||
<Link to={route.path}>{route.title}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<RouterProvider router={router} />
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const router = createBrowserRouter(
|
||||
createRoutesFromElements(
|
||||
<Route path="/" element={<Layout />}>
|
||||
{routes.map((route, idx) => (
|
||||
<Route
|
||||
key={route.path}
|
||||
index={idx === 0}
|
||||
path={route.path}
|
||||
element={route.element}
|
||||
/>
|
||||
))}
|
||||
</Route>
|
||||
)
|
||||
);
|
||||
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
|
||||
const routes = [
|
||||
{ path: "/", element: <HomePane /> },
|
||||
{ path: "/kanji", element: <KanjiPane /> },
|
||||
{ path: "/", title: "Home", element: <HomePane /> },
|
||||
{ path: "/kanji", title: "Kanji", element: <KanjiPane /> },
|
||||
];
|
|
@ -1,23 +1,36 @@
|
|||
import { useState } from "react"
|
||||
import { Kanji } from "../types/Kanji"
|
||||
import { invoke } from '@tauri-apps/api/tauri'
|
||||
import styles from "./KanjiPane.module.scss"
|
||||
import { useState } from "react";
|
||||
import { Kanji } from "../types/Kanji";
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
import useSWR from "swr";
|
||||
import styles from "./KanjiPane.module.scss";
|
||||
|
||||
export default function KanjiPane() {
|
||||
const [selectedKanji, setSelectedKanji] = useState(null);
|
||||
|
||||
const fetchKanji = async () => {
|
||||
const result = await invoke('get_kanji');
|
||||
setSelectedKanji(result);
|
||||
};
|
||||
interface GetKanjiResult {
|
||||
count: number;
|
||||
kanji: string[];
|
||||
}
|
||||
|
||||
function KanjiList({ data }: { data : GetKanjiResult}) {
|
||||
return <>
|
||||
{JSON.stringify(selectedKanji)}
|
||||
Displaying {data.kanji.length} of {data.count} results.
|
||||
|
||||
<div className={styles.kanjiDisplay}>
|
||||
|
||||
</div>
|
||||
|
||||
<button onClick={fetchKanji}>Fetch</button>
|
||||
<ul>
|
||||
{data.kanji.map(kanji => <li key={kanji}>
|
||||
{kanji}
|
||||
</li>)}
|
||||
</ul>
|
||||
</>
|
||||
}
|
||||
|
||||
export default function KanjiPane() {
|
||||
const { data, error, isLoading } = useSWR("get_kanji", invoke<GetKanjiResult>);
|
||||
|
||||
return (
|
||||
<>
|
||||
{JSON.stringify(error)}
|
||||
|
||||
<div className={styles.kanjiDisplay}></div>
|
||||
|
||||
{data && <KanjiList data={data} />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue