Fixes for sqlite data layer

This commit is contained in:
micialware committed 2026-09-08 00:09:13 +03:00
1 parent 7f9aa11d6e
commit 242b56fc21
9 files changed
+71 -65

No files matched your search

+14 -40
View File
@@ -286,30 +286,17 @@ impl<T: EntityData + Clone, D: DbLayer<T>> DataRepositoryInner<T, D> {
where where
T: Send + Sync, T: Send + Sync,
{ {
let mut cache: Vec<EntityHandle<T>> = self let mut query = Query {
.cache cache: vec![],
.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::<Vec<_>>(),
);
Query {
cache,
rule, rule,
parallel: true, parallel: true,
_marker: PhantomData, _marker: PhantomData,
shift_stamp: self.shifts, shift_stamp: self.shifts,
} };
query.load(self);
query
} }
pub fn query( pub fn query(
@@ -319,30 +306,17 @@ impl<T: EntityData + Clone, D: DbLayer<T>> DataRepositoryInner<T, D> {
where where
T: Send + Sync, T: Send + Sync,
{ {
let mut cache: Vec<EntityHandle<T>> = self let mut query = Query {
.cache cache: vec![],
.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::<Vec<_>>(),
);
Query {
cache,
rule, rule,
parallel: false, parallel: false,
_marker: PhantomData, _marker: PhantomData,
shift_stamp: self.shifts, shift_stamp: self.shifts,
} };
query.load(self);
query
} }
pub fn empty_query(&self) -> Query<T, DataRepositoryInner<T, D>, D> { pub fn empty_query(&self) -> Query<T, DataRepositoryInner<T, D>, D> {
+15 -6
View File
@@ -1,4 +1,5 @@
use crate::data::entities::{CardState, DeckSettings}; use crate::data::entities::{CardState, DeckSettings};
use crate::data::repositories::{DataRepository, DataRepositoryInner};
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet}; use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
use crate::notification::NotificationData::{DbLoadError, DbSaveError}; use crate::notification::NotificationData::{DbLoadError, DbSaveError};
use crate::notification::{MaybeError, NotificationData}; use crate::notification::{MaybeError, NotificationData};
@@ -7,10 +8,11 @@ use fsrs::MemoryState;
use log::info; use log::info;
use rusqlite::{Connection, Error, Params, Row, params}; use rusqlite::{Connection, Error, Params, Row, params};
use std::time::Instant; use std::time::Instant;
use crate::data::repositories::{DataRepository, DataRepositoryInner};
pub type CardStateRepository = DataRepository<CardState, SqliteDbLayer<CardState, CardStatesQuerySet>>; pub type CardStateRepository =
pub type CardStateRepositoryInner = DataRepositoryInner<CardState, SqliteDbLayer<CardState, CardStatesQuerySet>>; DataRepository<CardState, SqliteDbLayer<CardState, CardStatesQuerySet>>;
pub type CardStateRepositoryInner =
DataRepositoryInner<CardState, SqliteDbLayer<CardState, CardStatesQuerySet>>;
#[derive(Clone)] #[derive(Clone)]
pub struct CardStatesQuerySet; pub struct CardStatesQuerySet;
impl TableAccessQuerySet<CardState> for CardStatesQuerySet { impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
@@ -19,11 +21,11 @@ impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
} }
fn save() -> &'static str { 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 { 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 { fn name() -> &'static str {
@@ -58,7 +60,14 @@ impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
} }
fn update_params(entity: &CardState) -> impl Params { 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( pub fn load_stats_of_deck(
+1 -1
View File
@@ -16,7 +16,7 @@ impl TableAccessQuerySet<WordGroup> for CustomFieldsQuerySet {
} }
fn add() -> &'static str { fn add() -> &'static str {
"INSERT INTO word_groups (name) VALUES (?1) RETURNING id" "INSERT INTO word_groups (name) VALUES (?1)"
} }
fn name() -> &'static str { fn name() -> &'static str {
+1 -1
View File
@@ -17,7 +17,7 @@ impl TableAccessQuerySet<DeckSettings> for DeckQuerySet {
} }
fn add() -> &'static str { 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 { fn name() -> &'static str {
+4 -1
View File
@@ -21,13 +21,16 @@ impl TableAccessQuerySet<HistoryNote> for HistoryQuerySet {
} }
fn add() -> &'static str { 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 { fn name() -> &'static str {
"history" "history"
} }
fn id_field() -> &'static str {
"rowid"
}
fn from_sql(row: &Row) -> Result<HistoryNote, Error> { fn from_sql(row: &Row) -> Result<HistoryNote, Error> {
Ok(HistoryNote { Ok(HistoryNote {
id: row.get(0)?, id: row.get(0)?,
+30 -10
View File
@@ -1,8 +1,8 @@
use crate::data::Id; use crate::data::Id;
use crate::data::entities::{EntityData}; use crate::data::entities::EntityData;
use crate::data::repositories::{BatchedDbLayer, DbLayer}; use crate::data::repositories::{BatchedDbLayer, DbLayer};
use crate::notification::MaybeError; use crate::notification::MaybeError;
use crate::notification::NotificationData::{DbLoadError, DbSaveError}; use crate::notification::NotificationData::DbSaveError;
use log::{debug, error}; use log::{debug, error};
use rusqlite::{Connection, Error, Params, Row}; use rusqlite::{Connection, Error, Params, Row};
use std::marker::PhantomData; use std::marker::PhantomData;
@@ -25,6 +25,9 @@ pub trait TableAccessQuerySet<T> {
fn save() -> &'static str; fn save() -> &'static str;
fn add() -> &'static str; fn add() -> &'static str;
fn name() -> &'static str; fn name() -> &'static str;
fn id_field() -> &'static str {
"id"
}
fn from_sql(row: &Row) -> Result<T, Error>; fn from_sql(row: &Row) -> Result<T, Error>;
fn insert_params(entity: &T) -> impl Params; fn insert_params(entity: &T) -> impl Params;
fn update_params(entity: &T) -> impl Params; fn update_params(entity: &T) -> impl Params;
@@ -52,7 +55,10 @@ impl<T: EntityData, Q: TableAccessQuerySet<T>> DbLayer<T> for SqliteDbLayer<T, Q
connection connection
.execute(Q::save(), Q::update_params(entity)) .execute(Q::save(), Q::update_params(entity))
.map_err(|e| {error!("{}", e); DbSaveError})?; .map_err(|e| {
error!("{}", e);
DbSaveError
})?;
debug!("Updated in {} for {:?}", Q::name(), time.elapsed()); debug!("Updated in {} for {:?}", Q::name(), time.elapsed());
Ok(()) Ok(())
} }
@@ -61,8 +67,11 @@ impl<T: EntityData, Q: TableAccessQuerySet<T>> DbLayer<T> for SqliteDbLayer<T, Q
let time = Instant::now(); let time = Instant::now();
let index: u32 = connection let index: u32 = connection
.query_row(Q::add(), Q::insert_params(entity), |row| row.get(0)) .query_row(format!("{} RETURNING {}", Q::add(), Q::id_field()).as_str(), Q::insert_params(entity), |row| row.get(0))
.map_err(|e| {error!("{}", e); DbSaveError})?; .map_err(|e| {
error!("{}", e);
DbSaveError
})?;
entity.set_id(index.into()); entity.set_id(index.into());
debug!("Added into {} for {:?}", Q::name(), time.elapsed()); debug!("Added into {} for {:?}", Q::name(), time.elapsed());
@@ -80,7 +89,10 @@ impl<T: EntityData, Q: TableAccessQuerySet<T>> DbLayer<T> for SqliteDbLayer<T, Q
format!("DELETE FROM {} WHERE id = ?1", Q::name()).as_str(), format!("DELETE FROM {} WHERE id = ?1", Q::name()).as_str(),
(&id,), (&id,),
) )
.map_err(|e| {error!("{}", e); DbSaveError})?; .map_err(|e| {
error!("{}", e);
DbSaveError
})?;
debug!("Deleted from {} for {:?}", Q::name(), time.elapsed()); debug!("Deleted from {} for {:?}", Q::name(), time.elapsed());
Ok(()) Ok(())
} }
@@ -93,7 +105,10 @@ impl<T: EntityData, Q: TableAccessQuerySet<T>> DbLayer<T> for SqliteDbLayer<T, Q
.expect("Failed to prepare state query"); .expect("Failed to prepare state query");
let iter = stmt let iter = stmt
.query_map([], |row| Ok(Q::from_sql(row)?)) .query_map([], |row| Ok(Q::from_sql(row)?))
.map_err(|e| {error!("{}", e); DbSaveError})?; .map_err(|e| {
error!("{}", e);
DbSaveError
})?;
iter.filter_map(|res| res.ok()) iter.filter_map(|res| res.ok())
.for_each(|i| storage.push(i)); .for_each(|i| storage.push(i));
@@ -123,7 +138,10 @@ impl<T: EntityData, Q: TableAccessQuerySet<T>> BatchedDbLayer<T> for SqliteDbLay
format!("DELETE FROM {} WHERE id in ({})", Q::name(), stringed).as_str(), format!("DELETE FROM {} WHERE id in ({})", Q::name(), stringed).as_str(),
(), (),
) )
.map_err(|_| DbSaveError)?; .map_err(|e| {
error!("{}", e);
DbSaveError
})?;
} }
debug!( debug!(
"Deleted {} from {} for {:?}", "Deleted {} from {} for {:?}",
@@ -145,8 +163,10 @@ impl<T: EntityData, Q: TableAccessQuerySet<T>> BatchedDbLayer<T> for SqliteDbLay
{ {
let mut stmt = tx.prepare(Q::add()).expect("Failed to prepare state query"); let mut stmt = tx.prepare(Q::add()).expect("Failed to prepare state query");
for entity in entities.iter() { for entity in entities.iter() {
stmt.execute(Q::insert_params(entity)) stmt.execute(Q::insert_params(entity)).map_err(|e| {
.map_err(|_| DbSaveError)?; error!("{}", e);
DbSaveError
})?;
} }
} }
+1 -1
View File
@@ -19,7 +19,7 @@ impl TableAccessQuerySet<WordGroup> for WordGroupQuerySet {
} }
fn add() -> &'static str { fn add() -> &'static str {
"INSERT INTO word_groups (name) VALUES (?1) RETURNING id" "INSERT INTO word_groups (name) VALUES (?1)"
} }
fn name() -> &'static str { fn name() -> &'static str {
+3 -3
View File
@@ -20,7 +20,7 @@ impl TableAccessQuerySet<WordData> for WordQuerySet {
} }
fn add() -> &'static str { 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 { fn name() -> &'static str {
@@ -63,7 +63,7 @@ impl TableAccessQuerySet<WordData> for WordQuerySet {
pub fn add_word(word: &mut WordData, connection: &Connection) -> MaybeError { pub fn add_word(word: &mut WordData, connection: &Connection) -> MaybeError {
let index : u32 = connection let index : u32 = connection
.query_row( .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.key,
&word.value, &word.value,
@@ -193,7 +193,7 @@ pub fn load_word_groups(connection: &Connection) -> Result<Vec<WordGroup>, Notif
pub fn add_group(group: &mut WordGroup, connection: &Connection) -> MaybeError { pub fn add_group(group: &mut WordGroup, connection: &Connection) -> MaybeError {
let index: u32 = connection let index: u32 = connection
.query_row( .query_row(
"INSERT INTO word_groups (name) VALUES (?1) RETURNING id", "INSERT INTO word_groups (name) VALUES (?1)",
(&group.name,), (&group.name,),
|row| row.get(0), |row| row.get(0),
) )
+2 -2
View File
@@ -382,7 +382,7 @@ impl DictionaryState {
scrollable(col).height(Fill).into() 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 mut line = Row::new().width(Fill).align_y(Center);
let handle = data.handle.clone(); let handle = data.handle.clone();
line = line.push( line = line.push(
@@ -391,7 +391,7 @@ impl DictionaryState {
.spacing(15) .spacing(15)
.on_toggle(move |b| Include(handle, b)), .on_toggle(move |b| Include(handle, b)),
); );
//
line = line.push( line = line.push(
text_input("Слово", &data.key) text_input("Слово", &data.key)
.size(ACCENT_FONT_SIZE) .size(ACCENT_FONT_SIZE)