Fix card ease being reset on schema upgrade

d20a7d291f introduced a serious regression,
causing cards to be reset to the default ease when upgrading to the latest
schema version. This could also be triggered when exporting a colpkg with
legacy support.
This commit is contained in:
Damien Elmes 2023-02-17 12:15:53 +10:00
parent cdfb84f19a
commit 9e0a6d5bf7
2 changed files with 40 additions and 6 deletions

View File

@ -15,9 +15,11 @@ use crate::deckconfig::DeckConfigId;
use crate::deckconfig::DeckConfigInner; use crate::deckconfig::DeckConfigInner;
use crate::prelude::*; use crate::prelude::*;
fn row_to_deckconf(row: &Row) -> Result<DeckConfig> { fn row_to_deckconf(row: &Row, fix_invalid: bool) -> Result<DeckConfig> {
let mut config = DeckConfigInner::decode(row.get_ref_unwrap(4).as_blob()?)?; let mut config = DeckConfigInner::decode(row.get_ref_unwrap(4).as_blob()?)?;
config.ensure_values_valid(); if fix_invalid {
config.ensure_values_valid();
}
Ok(DeckConfig { Ok(DeckConfig {
id: row.get(0)?, id: row.get(0)?,
name: row.get(1)?, name: row.get(1)?,
@ -31,14 +33,22 @@ impl SqliteStorage {
pub(crate) fn all_deck_config(&self) -> Result<Vec<DeckConfig>> { pub(crate) fn all_deck_config(&self) -> Result<Vec<DeckConfig>> {
self.db self.db
.prepare_cached(include_str!("get.sql"))? .prepare_cached(include_str!("get.sql"))?
.query_and_then([], row_to_deckconf)? .query_and_then([], |row| row_to_deckconf(row, true))?
.collect()
}
/// Does not cap values to those expected by the latest schema.
pub(crate) fn all_deck_config_for_schema16_upgrade(&self) -> Result<Vec<DeckConfig>> {
self.db
.prepare_cached(include_str!("get.sql"))?
.query_and_then([], |row| row_to_deckconf(row, false))?
.collect() .collect()
} }
pub(crate) fn get_deck_config_map(&self) -> Result<HashMap<DeckConfigId, DeckConfig>> { pub(crate) fn get_deck_config_map(&self) -> Result<HashMap<DeckConfigId, DeckConfig>> {
self.db self.db
.prepare_cached(include_str!("get.sql"))? .prepare_cached(include_str!("get.sql"))?
.query_and_then([], row_to_deckconf)? .query_and_then([], |row| row_to_deckconf(row, true))?
.map(|res| res.map(|d| (d.id, d))) .map(|res| res.map(|d| (d.id, d)))
.collect() .collect()
} }
@ -46,7 +56,7 @@ impl SqliteStorage {
pub(crate) fn get_deck_config(&self, dcid: DeckConfigId) -> Result<Option<DeckConfig>> { pub(crate) fn get_deck_config(&self, dcid: DeckConfigId) -> Result<Option<DeckConfig>> {
self.db self.db
.prepare_cached(concat!(include_str!("get.sql"), " where id = ?"))? .prepare_cached(concat!(include_str!("get.sql"), " where id = ?"))?
.query_and_then(params![dcid], row_to_deckconf)? .query_and_then(params![dcid], |row| row_to_deckconf(row, true))?
.next() .next()
.transpose() .transpose()
} }
@ -217,7 +227,7 @@ impl SqliteStorage {
pub(super) fn upgrade_deck_conf_to_schema16(&self, server: bool) -> Result<()> { pub(super) fn upgrade_deck_conf_to_schema16(&self, server: bool) -> Result<()> {
let mut invalid_configs = vec![]; let mut invalid_configs = vec![];
for mut conf in self.all_deck_config()? { for mut conf in self.all_deck_config_for_schema16_upgrade()? {
// schema 16 changed starting ease of 250 to 2.5 // schema 16 changed starting ease of 250 to 2.5
conf.inner.initial_ease /= 100.0; conf.inner.initial_ease /= 100.0;
// new deck configs created with schema 15 had the wrong // new deck configs created with schema 15 had the wrong

View File

@ -78,6 +78,9 @@ impl SqliteStorage {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::collection::CollectionBuilder;
use crate::io::new_tempfile;
use crate::prelude::*;
#[test] #[test]
#[allow(clippy::assertions_on_constants)] #[allow(clippy::assertions_on_constants)]
@ -87,4 +90,25 @@ mod test {
"must implement SqliteStorage::downgrade_to(SchemaVersion::V18)" "must implement SqliteStorage::downgrade_to(SchemaVersion::V18)"
); );
} }
#[test]
fn valid_ease_factor_survives_upgrade_roundtrip() -> Result<()> {
let tempfile = new_tempfile()?;
let mut col = CollectionBuilder::default()
.set_collection_path(tempfile.path())
.build()?;
let nt = col.get_notetype_by_name("Basic")?.unwrap();
let mut note = nt.new_note();
col.add_note(&mut note, DeckId(1))?;
col.storage
.db
.execute("update cards set factor = 1400", [])?;
col.close(Some(SchemaVersion::V11))?;
let col = CollectionBuilder::default()
.set_collection_path(tempfile.path())
.build()?;
let card = &col.storage.get_all_cards()[0];
assert_eq!(card.ease_factor, 1400);
Ok(())
}
} }