use crate::data::entities::{WordData, WordGroup}; use crate::notification::NotificationData::{DbLoadError, DbSaveError}; use crate::notification::{MaybeError, NotificationData}; use rusqlite::{Connection, params}; use std::collections::HashMap; 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_group") .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_group (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_group 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_group WHERE id = ?1", (&group.id,)) .map_err(|_| DbSaveError)?; Ok(()) }