mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Use revlog to determine days_elapsed when studying/for card info
Currently prop searches and the retrievability column will continue to derive the days from the card only, as it's difficulty to integrate revlog upgrade lookups into those code paths, especially in a performant way. One possible way we could solve this in the future is to store last_review_day in the card data, so we can know it even if the due date has been shifted. Check DB could fill it in for existing cards.
This commit is contained in:
parent
66b944b722
commit
0532c1f5b0
6 changed files with 40 additions and 5 deletions
|
@ -112,14 +112,19 @@ impl Card {
|
|||
if self.queue == CardQueue::Learn {
|
||||
Some(TimestampSecs(self.due as i64))
|
||||
} else if self.is_due_in_days() {
|
||||
Some(TimestampSecs::now().adding_secs(
|
||||
((self.original_or_current_due() - timing.days_elapsed as i32).saturating_mul(86400)) as i64,
|
||||
))
|
||||
Some(
|
||||
TimestampSecs::now().adding_secs(
|
||||
((self.original_or_current_due() - timing.days_elapsed as i32)
|
||||
.saturating_mul(86400)) as i64,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// This uses card.due and card.ivl to infer the elapsed time. If 'set due
|
||||
/// date' or an add-on has changed the due date, this won't be accurate.
|
||||
pub(crate) fn days_since_last_review(&self, timing: &SchedTimingToday) -> Option<u32> {
|
||||
if !self.is_due_in_days() {
|
||||
Some(0)
|
||||
|
|
|
@ -364,10 +364,15 @@ impl Collection {
|
|||
let item = single_card_revlog_to_item(revlog, timing.next_day_at);
|
||||
card.set_memory_state(&fsrs, item);
|
||||
}
|
||||
let days_elapsed = self
|
||||
.storage
|
||||
.time_of_last_review(card.id)?
|
||||
.map(|ts| ts.elapsed_days_since(timing.next_day_at))
|
||||
.unwrap_or_default() as u32;
|
||||
Some(fsrs.next_states(
|
||||
card.memory_state.map(Into::into),
|
||||
config.inner.desired_retention,
|
||||
card.days_since_last_review(&timing).unwrap_or_default(),
|
||||
days_elapsed,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -27,9 +27,14 @@ impl Collection {
|
|||
let (average_secs, total_secs) = average_and_total_secs_strings(&revlog);
|
||||
let (due_date, due_position) = self.due_date_and_position(&card)?;
|
||||
let timing = self.timing_today()?;
|
||||
let days_elapsed = self
|
||||
.storage
|
||||
.time_of_last_review(card.id)?
|
||||
.map(|ts| ts.elapsed_days_since(timing.next_day_at))
|
||||
.unwrap_or_default() as u32;
|
||||
let fsrs_retrievability = card
|
||||
.memory_state
|
||||
.zip(card.days_since_last_review(&timing))
|
||||
.zip(Some(days_elapsed))
|
||||
.map(|(state, days)| {
|
||||
FSRS::new(None)
|
||||
.unwrap()
|
||||
|
|
|
@ -7,6 +7,7 @@ use rusqlite::params;
|
|||
use rusqlite::types::FromSql;
|
||||
use rusqlite::types::FromSqlError;
|
||||
use rusqlite::types::ValueRef;
|
||||
use rusqlite::OptionalExtension;
|
||||
use rusqlite::Row;
|
||||
|
||||
use super::SqliteStorage;
|
||||
|
@ -93,6 +94,15 @@ impl SqliteStorage {
|
|||
.transpose()
|
||||
}
|
||||
|
||||
/// Determine the the last review time based on the revlog.
|
||||
pub(crate) fn time_of_last_review(&self, card_id: CardId) -> Result<Option<TimestampSecs>> {
|
||||
self.db
|
||||
.prepare_cached(include_str!("time_of_last_review.sql"))?
|
||||
.query_row([card_id], |row| row.get(0))
|
||||
.optional()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Only intended to be used by the undo code, as Anki can not sync revlog
|
||||
/// deletions.
|
||||
pub(crate) fn remove_revlog_entry(&self, id: RevlogId) -> Result<()> {
|
||||
|
|
6
rslib/src/storage/revlog/time_of_last_review.sql
Normal file
6
rslib/src/storage/revlog/time_of_last_review.sql
Normal file
|
@ -0,0 +1,6 @@
|
|||
SELECT id / 1000
|
||||
FROM revlog
|
||||
WHERE cid = $1
|
||||
AND ease BETWEEN 1 AND 4
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
|
@ -28,6 +28,10 @@ impl TimestampSecs {
|
|||
(Self::now().0 - self.0).max(0) as u64
|
||||
}
|
||||
|
||||
pub fn elapsed_days_since(self, other: TimestampSecs) -> u64 {
|
||||
(other.0 - self.0).max(0) as u64 / 86_400
|
||||
}
|
||||
|
||||
pub fn as_millis(self) -> TimestampMillis {
|
||||
TimestampMillis(self.0 * 1000)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue