mirror of
https://github.com/ankitects/anki.git
synced 2025-12-21 10:52:57 -05:00
Fix/Retrievability SQL (#4424)
* Fix/SQL Retrievability Underflow * Added: Reminder * ./check * Apply code diff changes Co-authored-by: user1823 <92206575+user1823@users.noreply.github.com> * Slight cleanup * fix bug again * extra label comment * Update rslib/src/storage/sqlite.rs Co-authored-by: user1823 <92206575+user1823@users.noreply.github.com> * Fix: Ignore new cards * use const --------- Co-authored-by: user1823 <92206575+user1823@users.noreply.github.com>
This commit is contained in:
parent
a245f8ce61
commit
62252f7216
4 changed files with 38 additions and 34 deletions
|
|
@ -434,9 +434,10 @@ impl SqlWriter<'_> {
|
||||||
let timing = self.col.timing_today()?;
|
let timing = self.col.timing_today()?;
|
||||||
(timing.days_elapsed, timing.next_day_at, timing.now)
|
(timing.days_elapsed, timing.next_day_at, timing.now)
|
||||||
};
|
};
|
||||||
|
const NEW_TYPE: i8 = CardType::New as i8;
|
||||||
write!(
|
write!(
|
||||||
self.sql,
|
self.sql,
|
||||||
"extract_fsrs_retrievability(c.data, case when c.odue !=0 then c.odue else c.due end, c.ivl, {elap}, {next_day_at}, {now}) {op} {r}"
|
"case when c.type = {NEW_TYPE} then false else (extract_fsrs_retrievability(c.data, case when c.odue !=0 then c.odue else c.due end, c.ivl, {elap}, {next_day_at}, {now}) {op} {r}) end"
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ fn build_retrievability_query(
|
||||||
) -> String {
|
) -> String {
|
||||||
if fsrs {
|
if fsrs {
|
||||||
format!(
|
format!(
|
||||||
"extract_fsrs_relative_retrievability(c.data, case when c.odue !=0 then c.odue else c.due end, {today}, ivl, {next_day_at}, {now}) {order}"
|
"extract_fsrs_relative_retrievability(c.data, case when c.odue !=0 then c.odue else c.due end, ivl, {today}, {next_day_at}, {now}) {order}"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
|
|
|
||||||
|
|
@ -837,7 +837,7 @@ impl fmt::Display for ReviewOrderSubclause {
|
||||||
let next_day_at = timing.next_day_at.0;
|
let next_day_at = timing.next_day_at.0;
|
||||||
let now = timing.now.0;
|
let now = timing.now.0;
|
||||||
temp_string =
|
temp_string =
|
||||||
format!("extract_fsrs_relative_retrievability(data, case when odue !=0 then odue else due end, {today}, ivl, {next_day_at}, {now}) {order}");
|
format!("extract_fsrs_relative_retrievability(data, case when odue !=0 then odue else due end, ivl, {today}, {next_day_at}, {now}) {order}");
|
||||||
&temp_string
|
&temp_string
|
||||||
}
|
}
|
||||||
ReviewOrderSubclause::Added => "nid asc, ord asc",
|
ReviewOrderSubclause::Added => "nid asc, ord asc",
|
||||||
|
|
|
||||||
|
|
@ -332,23 +332,30 @@ fn add_extract_fsrs_retrievability(db: &Connection) -> rusqlite::Result<()> {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let seconds_elapsed = if let Some(last_review_time) = card_data.last_review_time {
|
let seconds_elapsed = if let Some(last_review_time) = card_data.last_review_time {
|
||||||
now.saturating_sub(last_review_time.0) as u32
|
// This and any following
|
||||||
|
// (x as u32).saturating_sub(y as u32)
|
||||||
|
// must not be changed to
|
||||||
|
// x.saturating_sub(y) as u32
|
||||||
|
// as x and y are i64's and saturating_sub will therfore allow negative numbers
|
||||||
|
// before converting to u32 in the latter example.
|
||||||
|
(now as u32).saturating_sub(last_review_time.0 as u32)
|
||||||
} else if due > 365_000 {
|
} else if due > 365_000 {
|
||||||
// (re)learning card in seconds
|
// (re)learning card in seconds
|
||||||
let Ok(ivl) = ctx.get_raw(2).as_i64() else {
|
let Ok(ivl) = ctx.get_raw(2).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let last_review_time = due.saturating_sub(ivl);
|
let last_review_time = (due as u32).saturating_sub(ivl as u32);
|
||||||
now.saturating_sub(last_review_time) as u32
|
(now as u32).saturating_sub(last_review_time)
|
||||||
} else {
|
} else {
|
||||||
let Ok(ivl) = ctx.get_raw(2).as_i64() else {
|
let Ok(ivl) = ctx.get_raw(2).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let Ok(days_elapsed) = ctx.get_raw(3).as_i64() else {
|
// timing.days_elapsed
|
||||||
|
let Ok(today) = ctx.get_raw(3).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let review_day = due.saturating_sub(ivl);
|
let review_day = (due as u32).saturating_sub(ivl as u32);
|
||||||
days_elapsed.saturating_sub(review_day) as u32 * 86_400
|
(today as u32).saturating_sub(review_day) * 86_400
|
||||||
};
|
};
|
||||||
let decay = card_data.decay.unwrap_or(FSRS5_DEFAULT_DECAY);
|
let decay = card_data.decay.unwrap_or(FSRS5_DEFAULT_DECAY);
|
||||||
let retrievability = card_data.memory_state().map(|state| {
|
let retrievability = card_data.memory_state().map(|state| {
|
||||||
|
|
@ -364,7 +371,7 @@ fn add_extract_fsrs_retrievability(db: &Connection) -> rusqlite::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// eg. extract_fsrs_relative_retrievability(card.data, card.due,
|
/// eg. extract_fsrs_relative_retrievability(card.data, card.due,
|
||||||
/// timing.days_elapsed, card.ivl, timing.next_day_at, timing.now) -> float |
|
/// card.ivl, timing.days_elapsed, timing.next_day_at, timing.now) -> float |
|
||||||
/// null. The higher the number, the higher the card's retrievability relative
|
/// null. The higher the number, the higher the card's retrievability relative
|
||||||
/// to the configured desired retention.
|
/// to the configured desired retention.
|
||||||
fn add_extract_fsrs_relative_retrievability(db: &Connection) -> rusqlite::Result<()> {
|
fn add_extract_fsrs_relative_retrievability(db: &Connection) -> rusqlite::Result<()> {
|
||||||
|
|
@ -378,25 +385,32 @@ fn add_extract_fsrs_relative_retrievability(db: &Connection) -> rusqlite::Result
|
||||||
let Ok(due) = ctx.get_raw(1).as_i64() else {
|
let Ok(due) = ctx.get_raw(1).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let Ok(interval) = ctx.get_raw(3).as_i64() else {
|
let Ok(interval) = ctx.get_raw(2).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
|
// Unused
|
||||||
let Ok(next_day_at) = ctx.get_raw(4).as_i64() else {
|
let Ok(next_day_at) = ctx.get_raw(4).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
let Ok(now) = ctx.get_raw(5).as_i64() else {
|
let Ok(now) = ctx.get_raw(5).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let days_elapsed = if due > 365_000 {
|
let secs_elapsed = if due > 365_000 {
|
||||||
// (re)learning
|
// (re)learning card with due in seconds
|
||||||
(next_day_at as u32).saturating_sub(due as u32) / 86_400
|
|
||||||
|
// Don't change this to now.subtracting_sub(due) as u32
|
||||||
|
// for the same reasons listed in the comment
|
||||||
|
// in add_extract_fsrs_retrievability
|
||||||
|
(now as u32).saturating_sub(due as u32)
|
||||||
} else {
|
} else {
|
||||||
let Ok(days_elapsed) = ctx.get_raw(2).as_i64() else {
|
// timing.days_elapsed
|
||||||
|
let Ok(today) = ctx.get_raw(3).as_i64() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
let review_day = due.saturating_sub(interval);
|
let review_day = due.saturating_sub(interval);
|
||||||
|
(today as u32).saturating_sub(review_day as u32) * 86_400
|
||||||
(days_elapsed as u32).saturating_sub(review_day as u32)
|
|
||||||
};
|
};
|
||||||
if let Ok(card_data) = ctx.get_raw(0).as_str() {
|
if let Ok(card_data) = ctx.get_raw(0).as_str() {
|
||||||
if !card_data.is_empty() {
|
if !card_data.is_empty() {
|
||||||
|
|
@ -410,23 +424,12 @@ fn add_extract_fsrs_relative_retrievability(db: &Connection) -> rusqlite::Result
|
||||||
|
|
||||||
let seconds_elapsed =
|
let seconds_elapsed =
|
||||||
if let Some(last_review_time) = card_data.last_review_time {
|
if let Some(last_review_time) = card_data.last_review_time {
|
||||||
now.saturating_sub(last_review_time.0) as u32
|
// Don't change this to now.subtracting_sub(due) as u32
|
||||||
} else if due > 365_000 {
|
// for the same reasons listed in the comment
|
||||||
// (re)learning card in seconds
|
// in add_extract_fsrs_retrievability
|
||||||
let Ok(ivl) = ctx.get_raw(2).as_i64() else {
|
(now as u32).saturating_sub(last_review_time.0 as u32)
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
let last_review_time = due.saturating_sub(ivl);
|
|
||||||
now.saturating_sub(last_review_time) as u32
|
|
||||||
} else {
|
} else {
|
||||||
let Ok(ivl) = ctx.get_raw(2).as_i64() else {
|
secs_elapsed
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
let Ok(days_elapsed) = ctx.get_raw(3).as_i64() else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
let review_day = due.saturating_sub(ivl);
|
|
||||||
days_elapsed.saturating_sub(review_day) as u32 * 86_400
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let current_retrievability = FSRS::new(None)
|
let current_retrievability = FSRS::new(None)
|
||||||
|
|
@ -441,7 +444,7 @@ fn add_extract_fsrs_relative_retrievability(db: &Connection) -> rusqlite::Result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let days_elapsed = secs_elapsed / 86_400;
|
||||||
// FSRS data missing; fall back to SM2 ordering
|
// FSRS data missing; fall back to SM2 ordering
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
-((days_elapsed as f32) + 0.001) / (interval as f32).max(1.0),
|
-((days_elapsed as f32) + 0.001) / (interval as f32).max(1.0),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue