From 779fc6940528fd3cd58db68db0fc5476e48110b6 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Sun, 11 Jun 2023 15:08:15 -0500 Subject: [PATCH] fetch --- .tokeignore | 1 + package-lock.json | 36 ++++++++++++++- package.json | 5 +- src-tauri/Cargo.lock | 12 +++++ src-tauri/Cargo.toml | 4 +- src-tauri/database-maker/src/kradfile.rs | 59 +++++++++++++----------- src-tauri/src/kanji.rs | 43 ++++++++++++++--- src-tauri/src/main.rs | 18 +++++++- src-tauri/tauri.conf.json | 4 +- src/App.tsx | 47 +++++++++++++------ src/panes/KanjiPane.tsx | 49 ++++++++++++-------- 11 files changed, 202 insertions(+), 76 deletions(-) create mode 100644 .tokeignore diff --git a/.tokeignore b/.tokeignore new file mode 100644 index 0000000..483a9c4 --- /dev/null +++ b/.tokeignore @@ -0,0 +1 @@ +package-lock.json \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9888693..715a7bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index cd1ec6a..5f4691e 100644 --- a/package.json +++ b/package.json @@ -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", @@ -26,4 +27,4 @@ "typescript": "^4.9.5", "vite": "^4.2.1" } -} \ No newline at end of file +} diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b868cff..2839f52 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -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", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3860680..416a401 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -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 diff --git a/src-tauri/database-maker/src/kradfile.rs b/src-tauri/database-maker/src/kradfile.rs index 4309843..877804b 100644 --- a/src-tauri/database-maker/src/kradfile.rs +++ b/src-tauri/database-maker/src/kradfile.rs @@ -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) -> Result<()> { - let file = File::open(path.as_ref()).await?; +pub async fn process_kradfile( + pool: &SqlitePool, + path: impl AsRef, +) -> 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::>(); - let (kanji, radicals) = match &parts[..] { - &[kanji, radicals] => { - let kanji = kanji.trim(); - let radicals = radicals.trim().split_whitespace().collect::>(); - (kanji, radicals) - } - _ => continue, - }; - - println!("kanji: {}, radicals: {:?}", kanji, radicals); + // Skip comments + if line.starts_with('#') { + continue; } - Ok(()) + let parts = line.split(SEPARATOR).collect::>(); + let (kanji, radicals) = match &parts[..] { + &[kanji, radicals] => { + let kanji = kanji.trim(); + let radicals = radicals.trim().split_whitespace().collect::>(); + (kanji, radicals) + } + _ => continue, + }; + + println!("kanji: {}, radicals: {:?}", kanji, radicals); + } + + Ok(()) } diff --git a/src-tauri/src/kanji.rs b/src-tauri/src/kanji.rs index 9ac57ea..a5a1ee0 100644 --- a/src-tauri/src/kanji.rs +++ b/src-tauri/src/kanji.rs @@ -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, +} + #[tauri::command] -pub async fn get_kanji(state: State<'_, KanjiDb>) -> Result, ()> { - let result = sqlx::query("SELECT * FROM KanjiSet LIMIT 5") - .fetch_all(&state.0) +pub async fn get_kanji( + state: State<'_, KanjiDb>, + options: Option, +) -> Result { + 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 }) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 4dd3a3e..baffec7 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -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)) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 094f9af..6e2338f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -21,7 +21,7 @@ "bundle": { "active": true, "targets": "all", - "identifier": "com.tauri.dev", + "identifier": "io.mzhang.houhou", "icon": [ "icons/32x32.png", "icons/128x128.png", @@ -43,4 +43,4 @@ } ] } -} \ No newline at end of file +} diff --git a/src/App.tsx b/src/App.tsx index e99672c..979fcca 100644 --- a/src/App.tsx +++ b/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 ( <> - + ); } +export default function App() { + const router = createBrowserRouter( + createRoutesFromElements( + }> + {routes.map((route, idx) => ( + + ))} + + ) + ); + + return ; +} + const routes = [ - { path: "/", element: }, - { path: "/kanji", element: }, -]; \ No newline at end of file + { path: "/", title: "Home", element: }, + { path: "/kanji", title: "Kanji", element: }, +]; diff --git a/src/panes/KanjiPane.tsx b/src/panes/KanjiPane.tsx index a9faec3..334d5f8 100644 --- a/src/panes/KanjiPane.tsx +++ b/src/panes/KanjiPane.tsx @@ -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"; + +interface GetKanjiResult { + count: number; + kanji: string[]; +} + +function KanjiList({ data }: { data : GetKanjiResult}) { + return <> + Displaying {data.kanji.length} of {data.count} results. + +
    + {data.kanji.map(kanji =>
  • + {kanji} +
  • )} +
+ +} export default function KanjiPane() { - const [selectedKanji, setSelectedKanji] = useState(null); + const { data, error, isLoading } = useSWR("get_kanji", invoke); - const fetchKanji = async () => { - const result = await invoke('get_kanji'); - setSelectedKanji(result); - }; + return ( + <> + {JSON.stringify(error)} - return <> - {JSON.stringify(selectedKanji)} +
-
- -
- - - -} \ No newline at end of file + {data && } + + ); +}