use crate::data::entities::{WordData, WordGroup}; use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet}; use crate::notification::NotificationData::{DbLoadError, DbSaveError}; use crate::notification::{MaybeError, NotificationData}; use litemap::LiteMap; use rusqlite::{Connection, Error, Params, Row, params}; use std::collections::HashMap; use crate::data::repositories::{BatchedDbLayer, DataRepository, DataRepositoryInner}; pub type WordRepository = DataRepository>; pub type WordRepositoryInner = DataRepositoryInner>; pub type WordDataLayer = SqliteDbLayer; #[derive(Clone)] pub struct WordQuerySet; impl TableAccessQuerySet for WordQuerySet { fn load() -> &'static str { "SELECT id, key, value, tags, more, group_id FROM words" } fn save() -> &'static str { "UPDATE words SET key = ?1, value = ?2, tags = ?3, more = ?4 WHERE id = ?5" } fn add() -> &'static str { "INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5)" } fn name() -> &'static str { "words" } fn from_sql(row: &Row) -> Result { let additional: String = row.get(4)?; Ok(WordData { id: row.get(0)?, key: row.get(1)?, value: row.get(2)?, tags: row.get(3)?, additional: serde_json::from_str(&additional).unwrap_or_default(), group_id: row.get(5)?, }) } fn insert_params(entity: &WordData) -> impl Params { ( &entity.key, &entity.value, &entity.tags, serde_json::to_string(&entity.additional).unwrap_or_default(), entity.group_id, ) } fn update_params(entity: &WordData) -> impl Params { ( &entity.key, &entity.value, &entity.tags, serde_json::to_string(&entity.additional).unwrap_or_default(), entity.id, ) } } pub fn add_word(word: &mut WordData, connection: &Connection) -> MaybeError { let index : u32 = connection .query_row( "INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5) RETURNING id", ( &word.key, &word.value, &word.tags, serde_json::to_string(&word.additional).unwrap_or_default(), &word.group_id, ), |row| row.get(0), ).map_err(|_| DbSaveError)?; word.id = index.into(); Ok(()) } pub fn add_words(words: &mut [WordData], connection: &mut Connection) -> MaybeError { let tx = connection.transaction().map_err(|_| DbLoadError)?; let count = words.len(); { let mut stmt = tx .prepare( "INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5)", ) .expect("Failed to prepare statement"); for word in words.iter() { stmt.execute(params![ word.key, word.value, word.tags, serde_json::to_string(&word.additional).unwrap_or_default(), word.group_id ]) .map_err(|_| DbSaveError)?; } } let last_index: u32 = tx.last_insert_rowid() as u32; tx.commit().map_err(|_| DbSaveError)?; let start_index = last_index - (count as u32) + 1; for (index, id) in (start_index..=last_index).enumerate() { words[index].id = id.into(); } Ok(()) } pub fn update_word(word: &mut WordData, connection: &Connection) -> MaybeError { if !word.id.is_valid() { Ok(add_word(word, connection)?) } else { connection .execute( "UPDATE words SET key = ?1, value = ?2, tags = ?3, more = ?4 WHERE id = ?5", ( &word.key, &word.value, &word.tags, serde_json::to_string(&word.additional).map_err(|_| DbSaveError)?, &word.id, ), ) .map_err(|_| DbSaveError)?; Ok(()) } } pub fn delete_word(word: &WordData, connection: &Connection) -> MaybeError { if !word.id.is_valid() { return Err(DbSaveError); } connection .execute("DELETE FROM words WHERE id = ?1", (&word.id,)) .map_err(|_| DbSaveError)?; Ok(()) } pub fn load_words(connection: &Connection) -> Result, NotificationData> { let mut stmt = connection .prepare("SELECT id, key, value, tags, more, group_id FROM words") .expect("Failed to prepare statement"); let word_iter = stmt .query_map([], |row| { let additional: String = row.get(4)?; Ok(WordData { id: row.get(0)?, key: row.get(1)?, value: row.get(2)?, tags: row.get(3)?, additional: serde_json::from_str(&additional).unwrap_or_default(), group_id: row.get(5)?, }) }) .map_err(|_| DbLoadError)?; let mut buffer = Vec::with_capacity(1024); word_iter .filter_map(|res| res.ok()) .for_each(|i| buffer.push(i)); Ok(buffer) } pub fn load_word_groups(connection: &Connection) -> Result, NotificationData> { let mut stmt = connection .prepare("SELECT id, name FROM word_groups") .expect("Failed to prepare statement"); let group_iter = stmt .query_map([], |row| { Ok(WordGroup { id: row.get(0)?, name: row.get(1)?, }) }) .map_err(|_| DbLoadError)?; let mut buffer = Vec::with_capacity(8); group_iter .filter_map(|res| res.ok()) .for_each(|i| buffer.push(i)); Ok(buffer) } pub fn add_group(group: &mut WordGroup, connection: &Connection) -> MaybeError { let index: u32 = connection .query_row( "INSERT INTO word_groups (name) VALUES (?1) RETURNING id", (&group.name,), |row| row.get(0), ) .map_err(|_| DbSaveError)?; group.id = index.into(); Ok(()) } pub fn update_group(group: &mut WordGroup, connection: &Connection) -> MaybeError { if !group.id.is_valid() { Ok(add_group(group, connection)?) } else { connection .execute( "UPDATE word_groups SET name = ?1 WHERE id = ?2", (&group.name, &group.id), ) .map_err(|_| DbSaveError)?; Ok(()) } } pub fn delete_group(group: &WordGroup, connection: &Connection) -> MaybeError { if !group.id.is_valid() { return Err(DbSaveError); } connection .execute("DELETE FROM word_groups WHERE id = ?1", (&group.id,)) .map_err(|_| DbSaveError)?; Ok(()) }