From 242b56fc214f37ab1e52bb947c606b8fb9f3fb69 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 8 Sep 2026 00:09:13 +0300 Subject: [PATCH] Fixes for sqlite data layer --- src/data/repositories.rs | 54 ++++++++---------------------- src/data_provider/card_states.rs | 21 ++++++++---- src/data_provider/custom_fields.rs | 2 +- src/data_provider/decks.rs | 2 +- src/data_provider/history.rs | 5 ++- src/data_provider/mod.rs | 44 +++++++++++++++++------- src/data_provider/word_groups.rs | 2 +- src/data_provider/words.rs | 6 ++-- src/pages/dictionary.rs | 4 +-- 9 files changed, 73 insertions(+), 67 deletions(-) diff --git a/src/data/repositories.rs b/src/data/repositories.rs index 56b5dd1..4cd83d4 100644 --- a/src/data/repositories.rs +++ b/src/data/repositories.rs @@ -286,30 +286,17 @@ impl> DataRepositoryInner { where T: Send + Sync, { - let mut cache: Vec> = self - .cache - .par_iter() - .enumerate() - .filter(|(_, entity)| rule(entity)) - .map(|(i, entity)| EntityHandle::new(entity.id(), i, true)) - .collect(); - - cache.extend( - self.temporal - .iter() - .enumerate() - .filter(|(_, entity)| rule(entity)) - .map(|(i, entity)| EntityHandle::new(entity.id(), i, false)) - .collect::>(), - ); - - Query { - cache, + let mut query = Query { + cache: vec![], rule, parallel: true, _marker: PhantomData, shift_stamp: self.shifts, - } + }; + + query.load(self); + + query } pub fn query( @@ -319,30 +306,17 @@ impl> DataRepositoryInner { where T: Send + Sync, { - let mut cache: Vec> = self - .cache - .iter() - .enumerate() - .filter(|(_, entity)| rule(entity)) - .map(|(i, entity)| EntityHandle::new(entity.id(), i, true)) - .collect(); - - cache.extend( - self.temporal - .iter() - .enumerate() - .filter(|(_, entity)| rule(entity)) - .map(|(i, entity)| EntityHandle::new(entity.id(), i, false)) - .collect::>(), - ); - - Query { - cache, + let mut query = Query { + cache: vec![], rule, parallel: false, _marker: PhantomData, shift_stamp: self.shifts, - } + }; + + query.load(self); + + query } pub fn empty_query(&self) -> Query, D> { diff --git a/src/data_provider/card_states.rs b/src/data_provider/card_states.rs index ff50ce3..975385b 100644 --- a/src/data_provider/card_states.rs +++ b/src/data_provider/card_states.rs @@ -1,4 +1,5 @@ use crate::data::entities::{CardState, DeckSettings}; +use crate::data::repositories::{DataRepository, DataRepositoryInner}; use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet}; use crate::notification::NotificationData::{DbLoadError, DbSaveError}; use crate::notification::{MaybeError, NotificationData}; @@ -7,10 +8,11 @@ use fsrs::MemoryState; use log::info; use rusqlite::{Connection, Error, Params, Row, params}; use std::time::Instant; -use crate::data::repositories::{DataRepository, DataRepositoryInner}; -pub type CardStateRepository = DataRepository>; -pub type CardStateRepositoryInner = DataRepositoryInner>; +pub type CardStateRepository = + DataRepository>; +pub type CardStateRepositoryInner = + DataRepositoryInner>; #[derive(Clone)] pub struct CardStatesQuerySet; impl TableAccessQuerySet for CardStatesQuerySet { @@ -19,11 +21,11 @@ impl TableAccessQuerySet for CardStatesQuerySet { } fn save() -> &'static str { - "UPDATE states SET score = ?1, last_opened = ?2 WHERE id = ?3" + "UPDATE states SET score = ?1, last_opened = ?2, fsrs_opened = ?3, fsrs_memory = ?4, fsrs_open_day = ?5 WHERE id = ?6" } fn add() -> &'static str { - "INSERT INTO states (word_id, deck_id, score, last_opened, fsrs_opened, fsrs_memory, fsrs_open_day) VALUES (?1, ?2, ?3, ?4) RETURNING id" + "INSERT INTO states (word_id, deck_id, score, last_opened, fsrs_opened, fsrs_memory, fsrs_open_day) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)" } fn name() -> &'static str { @@ -58,7 +60,14 @@ impl TableAccessQuerySet for CardStatesQuerySet { } fn update_params(entity: &CardState) -> impl Params { - (entity.score, entity.last_open.timestamp(), entity.id) + ( + entity.score, + entity.last_open.timestamp(), + entity.id, + entity.fsrs_opened, + memory_to_i64(&entity.fsrs_memory), + entity.fsrs_open_day, + ) } } pub fn load_stats_of_deck( diff --git a/src/data_provider/custom_fields.rs b/src/data_provider/custom_fields.rs index 219790f..6f09efa 100644 --- a/src/data_provider/custom_fields.rs +++ b/src/data_provider/custom_fields.rs @@ -16,7 +16,7 @@ impl TableAccessQuerySet for CustomFieldsQuerySet { } fn add() -> &'static str { - "INSERT INTO word_groups (name) VALUES (?1) RETURNING id" + "INSERT INTO word_groups (name) VALUES (?1)" } fn name() -> &'static str { diff --git a/src/data_provider/decks.rs b/src/data_provider/decks.rs index 811edb4..d647467 100644 --- a/src/data_provider/decks.rs +++ b/src/data_provider/decks.rs @@ -17,7 +17,7 @@ impl TableAccessQuerySet for DeckQuerySet { } fn add() -> &'static str { - "INSERT INTO decks (name, forward, backward, filter) VALUES (?1, ?2, ?3, ?4) RETURNING id" + "INSERT INTO decks (name, forward, backward, filter) VALUES (?1, ?2, ?3, ?4)" } fn name() -> &'static str { diff --git a/src/data_provider/history.rs b/src/data_provider/history.rs index 04b68ec..889c768 100644 --- a/src/data_provider/history.rs +++ b/src/data_provider/history.rs @@ -21,13 +21,16 @@ impl TableAccessQuerySet for HistoryQuerySet { } fn add() -> &'static str { - "INSERT INTO history (deck_id, state_id, timestamp, answer, before, after, fsrs) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) RETURNING rowid" + "INSERT INTO history (deck_id, state_id, timestamp, answer, before, after, fsrs) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)" } fn name() -> &'static str { "history" } + fn id_field() -> &'static str { + "rowid" + } fn from_sql(row: &Row) -> Result { Ok(HistoryNote { id: row.get(0)?, diff --git a/src/data_provider/mod.rs b/src/data_provider/mod.rs index 6746198..31e0e22 100644 --- a/src/data_provider/mod.rs +++ b/src/data_provider/mod.rs @@ -1,8 +1,8 @@ use crate::data::Id; -use crate::data::entities::{EntityData}; +use crate::data::entities::EntityData; use crate::data::repositories::{BatchedDbLayer, DbLayer}; use crate::notification::MaybeError; -use crate::notification::NotificationData::{DbLoadError, DbSaveError}; +use crate::notification::NotificationData::DbSaveError; use log::{debug, error}; use rusqlite::{Connection, Error, Params, Row}; use std::marker::PhantomData; @@ -25,6 +25,9 @@ pub trait TableAccessQuerySet { fn save() -> &'static str; fn add() -> &'static str; fn name() -> &'static str; + fn id_field() -> &'static str { + "id" + } fn from_sql(row: &Row) -> Result; fn insert_params(entity: &T) -> impl Params; fn update_params(entity: &T) -> impl Params; @@ -38,9 +41,9 @@ where _phantom: PhantomData<(T, Q)>, } -impl> Default for SqliteDbLayer{ +impl> Default for SqliteDbLayer { fn default() -> Self { - Self{ + Self { _phantom: PhantomData, } } @@ -52,7 +55,10 @@ impl> DbLayer for SqliteDbLayer> DbLayer for SqliteDbLayer> DbLayer for SqliteDbLayer> DbLayer for SqliteDbLayer> BatchedDbLayer for SqliteDbLay format!("DELETE FROM {} WHERE id in ({})", Q::name(), stringed).as_str(), (), ) - .map_err(|_| DbSaveError)?; + .map_err(|e| { + error!("{}", e); + DbSaveError + })?; } debug!( "Deleted {} from {} for {:?}", @@ -145,8 +163,10 @@ impl> BatchedDbLayer for SqliteDbLay { let mut stmt = tx.prepare(Q::add()).expect("Failed to prepare state query"); for entity in entities.iter() { - stmt.execute(Q::insert_params(entity)) - .map_err(|_| DbSaveError)?; + stmt.execute(Q::insert_params(entity)).map_err(|e| { + error!("{}", e); + DbSaveError + })?; } } diff --git a/src/data_provider/word_groups.rs b/src/data_provider/word_groups.rs index b94c0ba..450f73c 100644 --- a/src/data_provider/word_groups.rs +++ b/src/data_provider/word_groups.rs @@ -19,7 +19,7 @@ impl TableAccessQuerySet for WordGroupQuerySet { } fn add() -> &'static str { - "INSERT INTO word_groups (name) VALUES (?1) RETURNING id" + "INSERT INTO word_groups (name) VALUES (?1)" } fn name() -> &'static str { diff --git a/src/data_provider/words.rs b/src/data_provider/words.rs index 19089e2..4ea6bdf 100644 --- a/src/data_provider/words.rs +++ b/src/data_provider/words.rs @@ -20,7 +20,7 @@ impl TableAccessQuerySet for WordQuerySet { } fn add() -> &'static str { - "INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5) RETURNING id" + "INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5)" } fn name() -> &'static str { @@ -63,7 +63,7 @@ impl TableAccessQuerySet for WordQuerySet { 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", + "INSERT INTO words (key, value, tags, more, group_id) VALUES (?1, ?2, ?3, ?4, ?5)", ( &word.key, &word.value, @@ -193,7 +193,7 @@ pub fn load_word_groups(connection: &Connection) -> Result, Notif 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", + "INSERT INTO word_groups (name) VALUES (?1)", (&group.name,), |row| row.get(0), ) diff --git a/src/pages/dictionary.rs b/src/pages/dictionary.rs index 21e3515..59c485d 100644 --- a/src/pages/dictionary.rs +++ b/src/pages/dictionary.rs @@ -382,7 +382,7 @@ impl DictionaryState { scrollable(col).height(Fill).into() } - pub fn word_line<'a>(data: &WordLineState) -> Row<'a, DictionaryMessage> { + fn word_line<'a>(data: &WordLineState) -> Row<'a, DictionaryMessage> { let mut line = Row::new().width(Fill).align_y(Center); let handle = data.handle.clone(); line = line.push( @@ -391,7 +391,7 @@ impl DictionaryState { .spacing(15) .on_toggle(move |b| Include(handle, b)), ); - // + line = line.push( text_input("Слово", &data.key) .size(ACCENT_FONT_SIZE)