diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/mihi/Cargo.toml | 2 | ||||
| -rw-r--r-- | lib/mihi/src/lib.rs | 216 |
2 files changed, 200 insertions, 18 deletions
diff --git a/lib/mihi/Cargo.toml b/lib/mihi/Cargo.toml index 33f3439..4b973d6 100644 --- a/lib/mihi/Cargo.toml +++ b/lib/mihi/Cargo.toml @@ -9,3 +9,5 @@ license.workspace = true [dependencies] rusqlite = { version = "0.35.0", features = ["bundled"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" diff --git a/lib/mihi/src/lib.rs b/lib/mihi/src/lib.rs index 906953d..e464549 100644 --- a/lib/mihi/src/lib.rs +++ b/lib/mihi/src/lib.rs @@ -1,3 +1,4 @@ +use serde_json::Value; use std::fs; use std::fs::File; use std::io::prelude::*; @@ -7,6 +8,138 @@ use rusqlite::{params, Connection}; mod migrate; +#[derive(Debug)] +pub enum Category { + Unknown = 0, + Noun, + Adjective, + Verb, + Pronoun, + Adverb, + Preposition, + Conjunction, + Interjection, + Determiner, +} + +impl std::fmt::Display for Category { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Unknown => write!(f, "unknown"), + Self::Noun => write!(f, "noun"), + Self::Adjective => write!(f, "adjective"), + Self::Verb => write!(f, "verb"), + Self::Pronoun => write!(f, "pronoun"), + Self::Adverb => write!(f, "adverb"), + Self::Preposition => write!(f, "preposition"), + Self::Conjunction => write!(f, "conjunction"), + Self::Interjection => write!(f, "interjection"), + Self::Determiner => write!(f, "determiner"), + } + } +} + +impl std::default::Default for Category { + fn default() -> Self { + Category::Unknown + } +} + +impl TryFrom<usize> for Category { + type Error = &'static str; + + fn try_from(value: usize) -> Result<Self, Self::Error> { + match value { + 0 => Ok(Self::Unknown), + 1 => Ok(Self::Noun), + 2 => Ok(Self::Adjective), + 3 => Ok(Self::Verb), + 4 => Ok(Self::Pronoun), + 5 => Ok(Self::Adverb), + 6 => Ok(Self::Preposition), + 7 => Ok(Self::Conjunction), + 8 => Ok(Self::Interjection), + 9 => Ok(Self::Determiner), + _ => Err("unknonwn category!"), + } + } +} + +#[derive(Debug)] +pub enum Gender { + Masculine = 0, + Feminine, + MasculineOrFeminine, + Neuter, + None, +} + +impl TryFrom<usize> for Gender { + type Error = &'static str; + + fn try_from(value: usize) -> Result<Self, Self::Error> { + match value { + 0 => Ok(Self::Masculine), + 1 => Ok(Self::Feminine), + 2 => Ok(Self::MasculineOrFeminine), + 3 => Ok(Self::Neuter), + 4 => Ok(Self::None), + _ => Err("unknonwn gender!"), + } + } +} + +impl std::fmt::Display for Gender { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Masculine => write!(f, "masculine"), + Self::Feminine => write!(f, "feminine"), + Self::MasculineOrFeminine => write!(f, "masculine or feminine"), + Self::Neuter => write!(f, "neuter"), + Self::None => write!(f, "none"), + } + } +} + +impl std::default::Default for Gender { + fn default() -> Self { + Gender::None + } +} + +#[derive(Debug)] +pub enum Language { + Unknown = 0, + Latin, +} + +impl TryFrom<usize> for Language { + type Error = &'static str; + + fn try_from(value: usize) -> Result<Self, Self::Error> { + match value { + 0 => Ok(Self::Unknown), + 1 => Ok(Self::Latin), + _ => Err("unknonwn language!"), + } + } +} + +impl std::fmt::Display for Language { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Unknown => write!(f, "unknown"), + Self::Latin => write!(f, "latin"), + } + } +} + +impl std::default::Default for Language { + fn default() -> Self { + Language::Unknown + } +} + /// Returns the configuration path for the application, and it even creates it /// if it doesn't exist already. pub fn get_config_path() -> Result<PathBuf, String> { @@ -73,24 +206,23 @@ pub fn init_database() -> Result<(), String> { } } -// #[derive(Debug)] -// struct Word { -// id: i32, -// enunciated: String, -// particle: String, -// language_id: u64, -// declension_id: u64, -// conjugation_id: u64, -// kind: String, -// category: String, -// regular: bool, -// locative: bool, -// gender: u32, -// suffix: String, -// translation: String, -// // TODO: datetime -// // TODO: jsonb -// } +#[derive(Debug)] +pub struct Word { + pub id: i32, + pub enunciated: String, + pub particle: String, + pub language: Language, + pub declension_id: Option<usize>, + pub conjugation_id: Option<usize>, + pub kind: String, + pub category: Category, + pub regular: bool, + pub locative: bool, + pub gender: Gender, + pub suffix: Option<String>, + pub translation: Value, + pub succeeded: usize, +} pub fn select_enunciated(filter: Option<String>) -> Result<Vec<String>, String> { let conn = get_connection()?; @@ -120,6 +252,54 @@ pub fn select_enunciated(filter: Option<String>) -> Result<Vec<String>, String> Ok(res) } +pub fn select_random_words(category: Category, number: usize) -> Result<Vec<Word>, String> { + let conn = get_connection()?; + let mut stmt = conn + .prepare( + "SELECT id, enunciated, particle, language_id, declension_id, conjugation_id, \ + kind, category, regular, locative, gender, suffix, translation, succeeded \ + FROM words \ + WHERE category = ?1 AND translation != '{}' \ + ORDER BY succeeded ASC, updated_at DESC + LIMIT ?2", + ) + .unwrap(); + let mut it = stmt.query([category as usize, number]).unwrap(); + + let mut res = vec![]; + while let Some(row) = it.next().unwrap() { + res.push(Word { + id: row.get(0).unwrap(), + enunciated: row.get(1).unwrap(), + particle: row.get(2).unwrap(), + language: row.get::<usize, usize>(3).unwrap().try_into()?, + declension_id: row.get(4).unwrap(), + conjugation_id: row.get(5).unwrap(), + kind: row.get(6).unwrap(), + category: row.get::<usize, usize>(7).unwrap().try_into()?, + regular: row.get(8).unwrap(), + locative: row.get(9).unwrap(), + gender: row.get::<usize, usize>(10).unwrap().try_into()?, + suffix: row.get(11).unwrap(), + translation: serde_json::from_str(&row.get::<usize, String>(12).unwrap()).unwrap(), + succeeded: row.get(13).unwrap(), + }); + } + Ok(res) +} + +pub fn update_success(word: &Word, success: usize) -> Result<(), String> { + let conn = get_connection()?; + + match conn.execute( + "UPDATE words SET succeeded = ?1, updated_at = datetime('now') WHERE id = ?2", + params![success, word.id], + ) { + Ok(_) => Ok(()), + Err(e) => return Err(format!("could not update '{}': {}", word.enunciated, e)), + } +} + pub fn delete_word(enunciated: &String) -> Result<(), String> { let conn = get_connection()?; |
