2026-08-24 18:46:54 +03:00
|
|
|
use crate::data::entities::{WordData, WordGroup};
|
2026-08-30 22:15:03 +03:00
|
|
|
use crate::data_provider::TableAccessQuerySet;
|
2026-08-24 18:46:54 +03:00
|
|
|
use crate::notification::NotificationData::{DbLoadError, DbSaveError};
|
2026-08-25 12:04:07 +03:00
|
|
|
use crate::notification::{MaybeError, NotificationData};
|
2026-08-31 11:26:05 +03:00
|
|
|
use litemap::LiteMap;
|
2026-08-30 22:15:03 +03:00
|
|
|
use rusqlite::{Connection, Error, Params, Row, params};
|
2026-04-13 22:25:58 +03:00
|
|
|
use std::collections::HashMap;
|
2026-08-30 22:15:03 +03:00
|
|
|
|
|
|
|
|
pub struct WordQuerySet;
|
|
|
|
|
impl TableAccessQuerySet<WordData> 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<WordData, Error> {
|
|
|
|
|
let additional: String = row.get(4)?;
|
|
|
|
|
Ok(WordData {
|
|
|
|
|
id: row.get(0)?,
|
|
|
|
|
key: row.get(1)?,
|
|
|
|
|
value: row.get(2)?,
|
|
|
|
|
tags: row.get(3)?,
|
2026-08-31 11:26:05 +03:00
|
|
|
additional: serde_json::from_str(&additional).unwrap_or_default(),
|
2026-08-30 22:15:03 +03:00
|
|
|
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,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-24 23:42:58 +03:00
|
|
|
pub fn add_word(word: &mut WordData, connection: &Connection) -> MaybeError {
|
2026-08-19 23:37:59 +03:00
|
|
|
let index : u32 = connection
|
2026-04-13 22:25:58 +03:00
|
|
|
.query_row(
|
2026-08-14 23:03:15 +03:00
|
|
|
"INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5) RETURNING id",
|
2026-04-13 22:25:58 +03:00
|
|
|
(
|
|
|
|
|
&word.key,
|
|
|
|
|
&word.value,
|
|
|
|
|
&word.tags,
|
2026-08-24 18:46:54 +03:00
|
|
|
serde_json::to_string(&word.additional).unwrap_or_default(),
|
2026-05-05 14:26:34 +03:00
|
|
|
&word.group_id,
|
2026-04-13 22:25:58 +03:00
|
|
|
),
|
|
|
|
|
|row| row.get(0),
|
2026-08-24 18:46:54 +03:00
|
|
|
).map_err(|_| DbSaveError)?;
|
2026-04-13 22:25:58 +03:00
|
|
|
|
2026-08-18 12:47:06 +03:00
|
|
|
word.id = index.into();
|
2026-08-24 18:46:54 +03:00
|
|
|
Ok(())
|
2026-04-13 22:25:58 +03:00
|
|
|
}
|
|
|
|
|
|
2026-08-25 12:04:07 +03:00
|
|
|
pub fn add_words(words: &mut [WordData], connection: &mut Connection) -> MaybeError {
|
2026-08-24 18:46:54 +03:00
|
|
|
let tx = connection.transaction().map_err(|_| DbLoadError)?;
|
2026-08-14 23:03:15 +03:00
|
|
|
let count = words.len();
|
|
|
|
|
|
|
|
|
|
{
|
2026-08-15 21:32:24 +03:00
|
|
|
let mut stmt = tx
|
|
|
|
|
.prepare(
|
|
|
|
|
"INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5)",
|
|
|
|
|
)
|
2026-08-24 18:46:54 +03:00
|
|
|
.expect("Failed to prepare statement");
|
2026-08-14 23:03:15 +03:00
|
|
|
|
|
|
|
|
for word in words.iter() {
|
2026-08-15 21:32:24 +03:00
|
|
|
stmt.execute(params![
|
|
|
|
|
word.key,
|
|
|
|
|
word.value,
|
|
|
|
|
word.tags,
|
2026-08-24 18:46:54 +03:00
|
|
|
serde_json::to_string(&word.additional).unwrap_or_default(),
|
2026-08-15 21:32:24 +03:00
|
|
|
word.group_id
|
|
|
|
|
])
|
2026-08-25 12:04:07 +03:00
|
|
|
.map_err(|_| DbSaveError)?;
|
2026-08-14 23:03:15 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-19 17:33:22 +03:00
|
|
|
let last_index: u32 = tx.last_insert_rowid() as u32;
|
2026-08-24 18:46:54 +03:00
|
|
|
tx.commit().map_err(|_| DbSaveError)?;
|
2026-08-14 23:03:15 +03:00
|
|
|
|
|
|
|
|
let start_index = last_index - (count as u32) + 1;
|
|
|
|
|
|
2026-08-15 13:22:59 +03:00
|
|
|
for (index, id) in (start_index..=last_index).enumerate() {
|
2026-08-18 12:47:06 +03:00
|
|
|
words[index].id = id.into();
|
2026-08-14 23:03:15 +03:00
|
|
|
}
|
2026-08-24 18:46:54 +03:00
|
|
|
|
|
|
|
|
Ok(())
|
2026-08-14 23:03:15 +03:00
|
|
|
}
|
|
|
|
|
|
2026-08-24 23:42:58 +03:00
|
|
|
pub fn update_word(word: &mut WordData, connection: &Connection) -> MaybeError {
|
2026-08-18 17:31:19 +03:00
|
|
|
if !word.id.is_valid() {
|
2026-08-24 18:46:54 +03:00
|
|
|
Ok(add_word(word, connection)?)
|
2026-04-13 22:25:58 +03:00
|
|
|
} else {
|
|
|
|
|
connection
|
|
|
|
|
.execute(
|
|
|
|
|
"UPDATE words SET key = ?1, value = ?2, tags = ?3, more = ?4 WHERE id = ?5",
|
|
|
|
|
(
|
|
|
|
|
&word.key,
|
|
|
|
|
&word.value,
|
|
|
|
|
&word.tags,
|
2026-08-24 23:42:58 +03:00
|
|
|
serde_json::to_string(&word.additional).map_err(|_| DbSaveError)?,
|
2026-04-13 22:25:58 +03:00
|
|
|
&word.id,
|
|
|
|
|
),
|
|
|
|
|
)
|
2026-08-24 18:46:54 +03:00
|
|
|
.map_err(|_| DbSaveError)?;
|
|
|
|
|
Ok(())
|
2026-04-13 22:25:58 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-24 23:42:58 +03:00
|
|
|
pub fn delete_word(word: &WordData, connection: &Connection) -> MaybeError {
|
2026-08-18 17:31:19 +03:00
|
|
|
if !word.id.is_valid() {
|
2026-08-24 18:46:54 +03:00
|
|
|
return Err(DbSaveError);
|
2026-04-13 22:25:58 +03:00
|
|
|
}
|
|
|
|
|
connection
|
|
|
|
|
.execute("DELETE FROM words WHERE id = ?1", (&word.id,))
|
2026-08-24 18:46:54 +03:00
|
|
|
.map_err(|_| DbSaveError)?;
|
|
|
|
|
Ok(())
|
2026-04-13 22:25:58 +03:00
|
|
|
}
|
|
|
|
|
|
2026-08-24 18:46:54 +03:00
|
|
|
pub fn load_words(connection: &Connection) -> Result<Vec<WordData>, NotificationData> {
|
2026-04-13 22:25:58 +03:00
|
|
|
let mut stmt = connection
|
2026-05-05 12:02:59 +03:00
|
|
|
.prepare("SELECT id, key, value, tags, more, group_id FROM words")
|
2026-08-24 18:46:54 +03:00
|
|
|
.expect("Failed to prepare statement");
|
2026-04-13 22:25:58 +03:00
|
|
|
let word_iter = stmt
|
|
|
|
|
.query_map([], |row| {
|
2026-05-05 12:06:17 +03:00
|
|
|
let additional: String = row.get(4)?;
|
2026-05-05 12:02:59 +03:00
|
|
|
Ok(WordData {
|
2026-04-13 22:25:58 +03:00
|
|
|
id: row.get(0)?,
|
|
|
|
|
key: row.get(1)?,
|
|
|
|
|
value: row.get(2)?,
|
|
|
|
|
tags: row.get(3)?,
|
2026-08-31 11:26:05 +03:00
|
|
|
additional: serde_json::from_str(&additional).unwrap_or_default(),
|
2026-05-05 12:02:59 +03:00
|
|
|
group_id: row.get(5)?,
|
2026-04-13 22:25:58 +03:00
|
|
|
})
|
|
|
|
|
})
|
2026-08-24 18:46:54 +03:00
|
|
|
.map_err(|_| DbLoadError)?;
|
2026-04-13 22:25:58 +03:00
|
|
|
|
2026-08-24 18:46:54 +03:00
|
|
|
let mut buffer = Vec::with_capacity(1024);
|
2026-08-25 12:04:07 +03:00
|
|
|
word_iter
|
|
|
|
|
.filter_map(|res| res.ok())
|
|
|
|
|
.for_each(|i| buffer.push(i));
|
2026-04-13 22:25:58 +03:00
|
|
|
|
2026-08-24 18:46:54 +03:00
|
|
|
Ok(buffer)
|
2026-04-13 22:25:58 +03:00
|
|
|
}
|
|
|
|
|
|
2026-08-24 18:46:54 +03:00
|
|
|
pub fn load_word_groups(connection: &Connection) -> Result<Vec<WordGroup>, NotificationData> {
|
2026-05-05 12:02:59 +03:00
|
|
|
let mut stmt = connection
|
2026-08-29 21:31:54 +03:00
|
|
|
.prepare("SELECT id, name FROM word_groups")
|
2026-08-24 18:46:54 +03:00
|
|
|
.expect("Failed to prepare statement");
|
2026-05-05 12:02:59 +03:00
|
|
|
let group_iter = stmt
|
|
|
|
|
.query_map([], |row| {
|
|
|
|
|
Ok(WordGroup {
|
|
|
|
|
id: row.get(0)?,
|
|
|
|
|
name: row.get(1)?,
|
|
|
|
|
})
|
|
|
|
|
})
|
2026-08-24 18:46:54 +03:00
|
|
|
.map_err(|_| DbLoadError)?;
|
2026-04-13 22:25:58 +03:00
|
|
|
|
2026-08-24 18:46:54 +03:00
|
|
|
let mut buffer = Vec::with_capacity(8);
|
2026-08-25 12:04:07 +03:00
|
|
|
group_iter
|
|
|
|
|
.filter_map(|res| res.ok())
|
|
|
|
|
.for_each(|i| buffer.push(i));
|
2026-04-13 22:25:58 +03:00
|
|
|
|
2026-08-24 18:46:54 +03:00
|
|
|
Ok(buffer)
|
2026-05-05 14:26:34 +03:00
|
|
|
}
|
|
|
|
|
|
2026-08-24 23:42:58 +03:00
|
|
|
pub fn add_group(group: &mut WordGroup, connection: &Connection) -> MaybeError {
|
2026-08-19 23:51:41 +03:00
|
|
|
let index: u32 = connection
|
2026-05-05 14:26:34 +03:00
|
|
|
.query_row(
|
2026-08-29 21:31:54 +03:00
|
|
|
"INSERT INTO word_groups (name) VALUES (?1) RETURNING id",
|
2026-05-10 00:09:17 +03:00
|
|
|
(&group.name,),
|
2026-05-05 14:26:34 +03:00
|
|
|
|row| row.get(0),
|
|
|
|
|
)
|
2026-08-24 18:46:54 +03:00
|
|
|
.map_err(|_| DbSaveError)?;
|
2026-05-05 14:26:34 +03:00
|
|
|
|
2026-08-18 12:47:06 +03:00
|
|
|
group.id = index.into();
|
2026-08-24 18:46:54 +03:00
|
|
|
Ok(())
|
2026-05-05 14:26:34 +03:00
|
|
|
}
|
|
|
|
|
|
2026-08-25 12:04:07 +03:00
|
|
|
pub fn update_group(group: &mut WordGroup, connection: &Connection) -> MaybeError {
|
2026-08-18 17:31:19 +03:00
|
|
|
if !group.id.is_valid() {
|
2026-08-24 18:46:54 +03:00
|
|
|
Ok(add_group(group, connection)?)
|
2026-05-05 14:26:34 +03:00
|
|
|
} else {
|
|
|
|
|
connection
|
|
|
|
|
.execute(
|
2026-08-29 21:31:54 +03:00
|
|
|
"UPDATE word_groups SET name = ?1 WHERE id = ?2",
|
2026-05-10 00:09:17 +03:00
|
|
|
(&group.name, &group.id),
|
2026-05-05 14:26:34 +03:00
|
|
|
)
|
2026-08-24 18:46:54 +03:00
|
|
|
.map_err(|_| DbSaveError)?;
|
|
|
|
|
Ok(())
|
2026-05-05 14:26:34 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-24 23:42:58 +03:00
|
|
|
pub fn delete_group(group: &WordGroup, connection: &Connection) -> MaybeError {
|
2026-08-18 17:31:19 +03:00
|
|
|
if !group.id.is_valid() {
|
2026-08-24 18:46:54 +03:00
|
|
|
return Err(DbSaveError);
|
2026-05-05 14:26:34 +03:00
|
|
|
}
|
|
|
|
|
connection
|
2026-08-29 21:31:54 +03:00
|
|
|
.execute("DELETE FROM word_groups WHERE id = ?1", (&group.id,))
|
2026-08-24 18:46:54 +03:00
|
|
|
.map_err(|_| DbSaveError)?;
|
|
|
|
|
Ok(())
|
2026-05-10 00:09:17 +03:00
|
|
|
}
|