mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 15:32:23 -04:00
Fix Cards with Missing Last Review Time During Database Check
This commit is contained in:
parent
d13c117e80
commit
d71a3c7413
6 changed files with 44 additions and 11 deletions
|
@ -5,6 +5,11 @@ database-check-card-properties =
|
||||||
[one] Fixed { $count } invalid card property.
|
[one] Fixed { $count } invalid card property.
|
||||||
*[other] Fixed { $count } invalid card properties.
|
*[other] Fixed { $count } invalid card properties.
|
||||||
}
|
}
|
||||||
|
database-check-card-last-review-time-empty =
|
||||||
|
{ $count ->
|
||||||
|
[one] Fixed { $count } card with no last review time.
|
||||||
|
*[other] Fixed { $count } cards with no last review time.
|
||||||
|
}
|
||||||
database-check-missing-templates =
|
database-check-missing-templates =
|
||||||
{ $count ->
|
{ $count ->
|
||||||
[one] Deleted { $count } card with missing template.
|
[one] Deleted { $count } card with missing template.
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub struct CheckDatabaseOutput {
|
||||||
notetypes_recovered: usize,
|
notetypes_recovered: usize,
|
||||||
invalid_utf8: usize,
|
invalid_utf8: usize,
|
||||||
invalid_ids: usize,
|
invalid_ids: usize,
|
||||||
|
card_last_review_time_empty: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
@ -69,6 +70,11 @@ impl CheckDatabaseOutput {
|
||||||
if self.card_properties_invalid > 0 {
|
if self.card_properties_invalid > 0 {
|
||||||
probs.push(tr.database_check_card_properties(self.card_properties_invalid));
|
probs.push(tr.database_check_card_properties(self.card_properties_invalid));
|
||||||
}
|
}
|
||||||
|
if self.card_last_review_time_empty > 0 {
|
||||||
|
probs.push(
|
||||||
|
tr.database_check_card_last_review_time_empty(self.card_last_review_time_empty),
|
||||||
|
);
|
||||||
|
}
|
||||||
if self.cards_missing_note > 0 {
|
if self.cards_missing_note > 0 {
|
||||||
probs.push(tr.database_check_card_missing_note(self.cards_missing_note));
|
probs.push(tr.database_check_card_missing_note(self.cards_missing_note));
|
||||||
}
|
}
|
||||||
|
@ -158,7 +164,7 @@ impl Collection {
|
||||||
|
|
||||||
fn check_card_properties(&mut self, out: &mut CheckDatabaseOutput) -> Result<()> {
|
fn check_card_properties(&mut self, out: &mut CheckDatabaseOutput) -> Result<()> {
|
||||||
let timing = self.timing_today()?;
|
let timing = self.timing_today()?;
|
||||||
let (new_cnt, other_cnt) = self.storage.fix_card_properties(
|
let (new_cnt, other_cnt, last_review_time_cnt) = self.storage.fix_card_properties(
|
||||||
timing.days_elapsed,
|
timing.days_elapsed,
|
||||||
TimestampSecs::now(),
|
TimestampSecs::now(),
|
||||||
self.usn()?,
|
self.usn()?,
|
||||||
|
@ -166,6 +172,7 @@ impl Collection {
|
||||||
)?;
|
)?;
|
||||||
out.card_position_too_high = new_cnt;
|
out.card_position_too_high = new_cnt;
|
||||||
out.card_properties_invalid += other_cnt;
|
out.card_properties_invalid += other_cnt;
|
||||||
|
out.card_last_review_time_empty = last_review_time_cnt;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,16 @@ impl RevlogEntry {
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the review entry is not manually rescheduled and not
|
||||||
|
/// cramming. Used to filter out entries that shouldn't be considered
|
||||||
|
/// for statistics and scheduling.
|
||||||
|
pub(crate) fn has_rating_and_affect_scheduling(&self) -> bool {
|
||||||
|
// not rescheduled/set due date/reset
|
||||||
|
self.button_chosen > 0
|
||||||
|
// not cramming
|
||||||
|
&& (self.review_kind != RevlogReviewKind::Filtered || self.ease_factor != 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collection {
|
impl Collection {
|
||||||
|
|
|
@ -306,15 +306,15 @@ pub(crate) fn fsrs_items_for_memory_states(
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LastRevlogInfo {
|
pub(crate) struct LastRevlogInfo {
|
||||||
/// Used to determine the actual elapsed time between the last time the user
|
/// Used to determine the actual elapsed time between the last time the user
|
||||||
/// reviewed the card and now, so that we can determine an accurate period
|
/// reviewed the card and now, so that we can determine an accurate period
|
||||||
/// when the card has subsequently been rescheduled to a different day.
|
/// when the card has subsequently been rescheduled to a different day.
|
||||||
last_reviewed_at: Option<TimestampSecs>,
|
pub(crate) last_reviewed_at: Option<TimestampSecs>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a map of cards to info about last review/reschedule.
|
/// Return a map of cards to info about last review/reschedule.
|
||||||
fn get_last_revlog_info(revlogs: &[RevlogEntry]) -> HashMap<CardId, LastRevlogInfo> {
|
pub(crate) fn get_last_revlog_info(revlogs: &[RevlogEntry]) -> HashMap<CardId, LastRevlogInfo> {
|
||||||
let mut out = HashMap::new();
|
let mut out = HashMap::new();
|
||||||
revlogs
|
revlogs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -323,7 +323,7 @@ fn get_last_revlog_info(revlogs: &[RevlogEntry]) -> HashMap<CardId, LastRevlogIn
|
||||||
.for_each(|(card_id, group)| {
|
.for_each(|(card_id, group)| {
|
||||||
let mut last_reviewed_at = None;
|
let mut last_reviewed_at = None;
|
||||||
for e in group.into_iter() {
|
for e in group.into_iter() {
|
||||||
if e.button_chosen >= 1 {
|
if e.has_rating_and_affect_scheduling() {
|
||||||
last_reviewed_at = Some(e.id.as_secs());
|
last_reviewed_at = Some(e.id.as_secs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,10 +53,7 @@ impl GraphsContext {
|
||||||
self.revlog
|
self.revlog
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|review| {
|
.filter(|review| {
|
||||||
// not rescheduled/set due date/reset
|
review.has_rating_and_affect_scheduling()
|
||||||
review.button_chosen > 0
|
|
||||||
// not cramming
|
|
||||||
&& (review.review_kind != RevlogReviewKind::Filtered || review.ease_factor != 0)
|
|
||||||
// cards with an interval ≥ 1 day
|
// cards with an interval ≥ 1 day
|
||||||
&& (review.review_kind == RevlogReviewKind::Review
|
&& (review.review_kind == RevlogReviewKind::Review
|
||||||
|| review.last_interval <= -86400
|
|| review.last_interval <= -86400
|
||||||
|
|
|
@ -33,6 +33,7 @@ use crate::decks::DeckKind;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::notes::NoteId;
|
use crate::notes::NoteId;
|
||||||
use crate::scheduler::congrats::CongratsInfo;
|
use crate::scheduler::congrats::CongratsInfo;
|
||||||
|
use crate::scheduler::fsrs::memory_state::get_last_revlog_info;
|
||||||
use crate::scheduler::queue::BuryMode;
|
use crate::scheduler::queue::BuryMode;
|
||||||
use crate::scheduler::queue::DueCard;
|
use crate::scheduler::queue::DueCard;
|
||||||
use crate::scheduler::queue::DueCardKind;
|
use crate::scheduler::queue::DueCardKind;
|
||||||
|
@ -365,7 +366,7 @@ impl super::SqliteStorage {
|
||||||
mtime: TimestampSecs,
|
mtime: TimestampSecs,
|
||||||
usn: Usn,
|
usn: Usn,
|
||||||
v1_sched: bool,
|
v1_sched: bool,
|
||||||
) -> Result<(usize, usize)> {
|
) -> Result<(usize, usize, usize)> {
|
||||||
let new_cnt = self
|
let new_cnt = self
|
||||||
.db
|
.db
|
||||||
.prepare(include_str!("fix_due_new.sql"))?
|
.prepare(include_str!("fix_due_new.sql"))?
|
||||||
|
@ -390,7 +391,20 @@ impl super::SqliteStorage {
|
||||||
.db
|
.db
|
||||||
.prepare(include_str!("fix_ordinal.sql"))?
|
.prepare(include_str!("fix_ordinal.sql"))?
|
||||||
.execute(params![mtime, usn])?;
|
.execute(params![mtime, usn])?;
|
||||||
Ok((new_cnt, other_cnt))
|
let mut last_review_time_cnt = 0;
|
||||||
|
let revlog = self.get_all_revlog_entries_in_card_order()?;
|
||||||
|
let last_revlog_info = get_last_revlog_info(&revlog);
|
||||||
|
for (card_id, last_revlog_info) in last_revlog_info {
|
||||||
|
let card = self.get_card(card_id)?;
|
||||||
|
if let Some(mut card) = card {
|
||||||
|
if card.ctype != CardType::New && card.last_review_time.is_none() {
|
||||||
|
card.last_review_time = last_revlog_info.last_reviewed_at;
|
||||||
|
self.update_card(&mut card)?;
|
||||||
|
last_review_time_cnt += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((new_cnt, other_cnt, last_review_time_cnt))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn delete_orphaned_cards(&self) -> Result<usize> {
|
pub(crate) fn delete_orphaned_cards(&self) -> Result<usize> {
|
||||||
|
|
Loading…
Reference in a new issue