update schema to fix default initial ease in deck configs

Closes #766

- changes the on-disk representation from % to a multiplier,
eg 250 -> 2.5, as this is consistent with the other options
- resets deck configs at or below 1.3 to 2.5
- for any cards that were using a reset deck config, reset their
current factor if it's at or below 2.0x. The cutoff is arbitrary,
and just intended to make sure we catch cards the user has rated
Easy on multiple times. The existing due dates are left alone.
This commit is contained in:
Damien Elmes 2020-09-22 08:52:48 +10:00
parent 54996e46f4
commit 87c6686930
9 changed files with 85 additions and 7 deletions

View file

@ -237,7 +237,7 @@ impl From<DeckConfSchema11> for DeckConf {
reviews_per_day: c.rev.per_day, reviews_per_day: c.rev.per_day,
bury_new: c.new.bury, bury_new: c.new.bury,
bury_reviews: c.rev.bury, bury_reviews: c.rev.bury,
initial_ease: (c.new.initial_factor as f32) / 10.0, initial_ease: (c.new.initial_factor as f32) / 1000.0,
easy_multiplier: c.rev.ease4, easy_multiplier: c.rev.ease4,
hard_multiplier: c.rev.hard_factor, hard_multiplier: c.rev.hard_factor,
lapse_multiplier: c.lapse.mult, lapse_multiplier: c.lapse.mult,
@ -298,7 +298,7 @@ impl From<DeckConf> for DeckConfSchema11 {
new: NewConfSchema11 { new: NewConfSchema11 {
bury: i.bury_new, bury: i.bury_new,
delays: i.learn_steps, delays: i.learn_steps,
initial_factor: (i.initial_ease * 10.0) as u16, initial_factor: (i.initial_ease * 1000.0) as u16,
ints: NewCardIntervals { ints: NewCardIntervals {
good: i.graduating_interval_good as u16, good: i.graduating_interval_good as u16,
easy: i.graduating_interval_easy as u16, easy: i.graduating_interval_easy as u16,

View file

0
rslib/src/sched/new.rs Normal file
View file

View file

View file

@ -0,0 +1,10 @@
update cards
set factor = 2500,
usn = ?,
mod = ?
where factor != 0
and factor <= 2000
and (
did in DECK_IDS
or odid in DECK_IDS
)

View file

@ -3,7 +3,8 @@
use crate::{ use crate::{
card::{Card, CardID, CardQueue, CardType}, card::{Card, CardID, CardQueue, CardType},
decks::DeckID, deckconf::DeckConfID,
decks::{Deck, DeckID, DeckKind},
err::Result, err::Result,
notes::NoteID, notes::NoteID,
timestamp::{TimestampMillis, TimestampSecs}, timestamp::{TimestampMillis, TimestampSecs},
@ -16,6 +17,8 @@ use rusqlite::{
}; };
use std::{collections::HashSet, convert::TryFrom, result}; use std::{collections::HashSet, convert::TryFrom, result};
use super::ids_to_string;
impl FromSql for CardType { impl FromSql for CardType {
fn column_result(value: ValueRef<'_>) -> std::result::Result<Self, FromSqlError> { fn column_result(value: ValueRef<'_>) -> std::result::Result<Self, FromSqlError> {
if let ValueRef::Integer(i) = value { if let ValueRef::Integer(i) = value {
@ -277,6 +280,40 @@ impl super::SqliteStorage {
Ok(()) Ok(())
} }
/// Fix cards with low eases due to schema 15 bug.
/// Deck configs were defaulting to 2.5% ease, which was capped to
/// 130% when the deck options were edited for the first time.
pub(crate) fn fix_low_card_eases_for_configs(
&self,
configs: &[DeckConfID],
server: bool,
) -> Result<()> {
let mut affected_decks = vec![];
for conf in configs {
for (deck_id, _name) in self.get_all_deck_names()? {
if let Some(deck) = self.get_deck(deck_id)? {
if let DeckKind::Normal(normal) = &deck.kind {
if normal.config_id == conf.0 {
affected_decks.push(deck.id);
}
}
}
}
}
let mut ids = String::new();
ids_to_string(&mut ids, &affected_decks);
let sql = include_str!("fix_low_ease.sql").replace("DECK_IDS", &ids);
self.db
.prepare(&sql)?
.execute(params![self.usn(server)?, TimestampSecs::now()])?;
Ok(())
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -159,13 +159,35 @@ impl SqliteStorage {
pub(super) fn upgrade_deck_conf_to_schema15(&self) -> Result<()> { pub(super) fn upgrade_deck_conf_to_schema15(&self) -> Result<()> {
for conf in self.all_deck_config_schema14()? { for conf in self.all_deck_config_schema14()? {
let conf: DeckConf = conf.into(); let mut conf: DeckConf = conf.into();
// schema 15 stored starting ease of 2.5 as 250
conf.inner.initial_ease *= 100.0;
self.update_deck_conf(&conf)?; self.update_deck_conf(&conf)?;
} }
Ok(()) Ok(())
} }
// schema 15->16
pub(super) fn upgrade_deck_conf_to_schema16(&self, server: bool) -> Result<()> {
let mut invalid_configs = vec![];
for mut conf in self.all_deck_config()? {
// schema 16 changed starting ease of 250 to 2.5
conf.inner.initial_ease /= 100.0;
// new deck configs created with schema 15 had the wrong
// ease set - reset any deck configs at the minimum ease
// to the default 250%
if conf.inner.initial_ease <= 1.3 {
conf.inner.initial_ease = 2.5;
invalid_configs.push(conf.id);
}
self.update_deck_conf(&conf)?;
}
self.fix_low_card_eases_for_configs(&invalid_configs, server)
}
// schema 15->11 // schema 15->11
pub(super) fn downgrade_deck_conf_from_schema15(&self) -> Result<()> { pub(super) fn downgrade_deck_conf_from_schema15(&self) -> Result<()> {

View file

@ -12,9 +12,7 @@ use std::cmp::Ordering;
use std::{borrow::Cow, path::Path, sync::Arc}; use std::{borrow::Cow, path::Path, sync::Arc};
use unicase::UniCase; use unicase::UniCase;
const SCHEMA_MIN_VERSION: u8 = 11; use super::upgrades::{SCHEMA_MAX_VERSION, SCHEMA_MIN_VERSION, SCHEMA_STARTING_VERSION};
const SCHEMA_STARTING_VERSION: u8 = 11;
const SCHEMA_MAX_VERSION: u8 = 15;
fn unicase_compare(s1: &str, s2: &str) -> Ordering { fn unicase_compare(s1: &str, s2: &str) -> Ordering {
UniCase::new(s1).cmp(&UniCase::new(s2)) UniCase::new(s1).cmp(&UniCase::new(s2))

View file

@ -1,6 +1,13 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
/// The minimum schema version we can open.
pub(super) const SCHEMA_MIN_VERSION: u8 = 11;
/// The version new files are initially created with.
pub(super) const SCHEMA_STARTING_VERSION: u8 = 11;
/// The maximum schema version we can open.
pub(super) const SCHEMA_MAX_VERSION: u8 = 16;
use super::SqliteStorage; use super::SqliteStorage;
use crate::err::Result; use crate::err::Result;
@ -20,6 +27,10 @@ impl SqliteStorage {
self.upgrade_decks_to_schema15(server)?; self.upgrade_decks_to_schema15(server)?;
self.upgrade_deck_conf_to_schema15()?; self.upgrade_deck_conf_to_schema15()?;
} }
if ver < 16 {
self.upgrade_deck_conf_to_schema16(server)?;
self.db.execute_batch("update col set ver = 16")?;
}
Ok(()) Ok(())
} }