Files
jap_learn/src/data_provider/card_states.rs
T
2026-09-09 15:00:52 +03:00

97 lines
3.1 KiB
Rust

use crate::data::entities::CardState;
use crate::data::repositories::{DataRepository, DataRepositoryInner, Query};
use crate::data::Id;
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
use chrono::NaiveDate;
use fsrs::MemoryState;
use rusqlite::{Error, Params, Row};
use std::sync::Arc;
pub type CardStateRepository = DataRepository<CardState, CardStateDbLayer>;
pub type CardStateRepositoryInner = DataRepositoryInner<CardState, CardStateDbLayer>;
pub type CardStateDbLayer = SqliteDbLayer<CardState, CardStatesQuerySet>;
#[derive(Clone)]
pub struct CardStatesQuerySet;
impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
fn load() -> &'static str {
"SELECT id, word_id, deck_id, score, last_opened, fsrs_opened, fsrs_memory, fsrs_open_day FROM states"
}
fn save() -> &'static str {
"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, ?5, ?6, ?7)"
}
fn name() -> &'static str {
"states"
}
fn from_sql(row: &Row) -> Result<CardState, Error> {
Ok(CardState {
id: row.get(0)?,
word_id: row.get(1)?,
deck_id: row.get(2)?,
score: row.get(3)?,
fsrs_opened: NaiveDate::from_epoch_days(row.get::<usize, i32>(5)?)
.expect("Incorrect date encoding"),
fsrs_memory: get_memory(row.get(6)?),
last_open: row.get(4)?,
fsrs_open_day: NaiveDate::from_epoch_days(row.get::<usize, i32>(7)?)
.expect("Incorrect date encoding"),
})
}
fn insert_params(entity: &CardState) -> impl Params {
(
entity.word_id,
entity.deck_id,
entity.score,
entity.last_open.timestamp(),
entity.fsrs_opened.to_epoch_days(),
memory_to_i64(&entity.fsrs_memory),
entity.fsrs_open_day.to_epoch_days(),
)
}
fn update_params(entity: &CardState) -> impl Params {
(
entity.score,
entity.last_open.timestamp(),
entity.fsrs_opened.to_epoch_days(),
memory_to_i64(&entity.fsrs_memory),
entity.fsrs_open_day.to_epoch_days(),
entity.id,
)
}
}
fn get_memory(value: i64) -> Option<MemoryState> {
if value == 0 {
return None;
}
Some(MemoryState {
stability: f32::from_bits(value as u32),
difficulty: f32::from_bits((value >> 32) as u32),
})
}
fn memory_to_i64(value: &Option<MemoryState>) -> i64 {
let Some(value) = &value else {
return 0;
};
value.stability.to_bits() as i64 | ((value.difficulty.to_bits() as i64) << 32)
}
impl CardStateRepositoryInner {
pub fn deck_states(
&self,
deck_id: Id,
) -> Query<CardState, CardStateRepositoryInner, CardStateDbLayer> {
self.query(Arc::new(move |state| state.deck_id == deck_id))
}
}