Skip new notetype checks when importing apkg

This commit is contained in:
RumovZ 2021-07-28 21:46:51 +02:00
parent be1b524396
commit c0dd769090
10 changed files with 69 additions and 35 deletions

View file

@ -107,6 +107,7 @@ message Notetype {
message AddOrUpdateNotetypeRequest { message AddOrUpdateNotetypeRequest {
bytes json = 1; bytes json = 1;
bool preserve_usn_and_mtime = 2; bool preserve_usn_and_mtime = 2;
bool skip_checks = 3;
} }
message StockNotetype { message StockNotetype {

View file

@ -235,7 +235,7 @@ class Anki2Importer(Importer):
model = srcModel.copy() model = srcModel.copy()
model["id"] = mid model["id"] = mid
model["usn"] = self.col.usn() model["usn"] = self.col.usn()
self.dst.models.update(model) self.dst.models.update(model, skip_checks=True)
break break
# there's an existing model; do the schemas match? # there's an existing model; do the schemas match?
dstModel = self.dst.models.get(mid) dstModel = self.dst.models.get(mid)
@ -246,7 +246,7 @@ class Anki2Importer(Importer):
model = srcModel.copy() model = srcModel.copy()
model["id"] = mid model["id"] = mid
model["usn"] = self.col.usn() model["usn"] = self.col.usn()
self.dst.models.update(model) self.dst.models.update(model, skip_checks=True)
break break
# as they don't match, try next id # as they don't match, try next id
mid = NotetypeId(mid + 1) mid = NotetypeId(mid + 1)

View file

@ -527,12 +527,19 @@ and notes.mid = ? and cards.ord = ?""",
pass pass
# @deprecated(replaced_by=update_dict) # @deprecated(replaced_by=update_dict)
def update(self, notetype: NotetypeDict, preserve_usn: bool = True) -> None: def update(
self,
notetype: NotetypeDict,
preserve_usn: bool = True,
skip_checks: bool = False,
) -> None:
"Add or update an existing model. Use .update_dict() instead." "Add or update an existing model. Use .update_dict() instead."
self._remove_from_cache(notetype["id"]) self._remove_from_cache(notetype["id"])
self.ensure_name_unique(notetype) self.ensure_name_unique(notetype)
notetype["id"] = self.col._backend.add_or_update_notetype( notetype["id"] = self.col._backend.add_or_update_notetype(
json=to_json_bytes(notetype), preserve_usn_and_mtime=preserve_usn json=to_json_bytes(notetype),
preserve_usn_and_mtime=preserve_usn,
skip_checks=skip_checks,
) )
self.set_current(notetype) self.set_current(notetype)
self._mutate_after_write(notetype) self._mutate_after_write(notetype)

View file

@ -17,7 +17,7 @@ impl NotetypesService for Backend {
let mut notetype: Notetype = input.into(); let mut notetype: Notetype = input.into();
self.with_col(|col| { self.with_col(|col| {
Ok(col Ok(col
.add_notetype(&mut notetype)? .add_notetype(&mut notetype, false)?
.map(|_| notetype.id.0) .map(|_| notetype.id.0)
.into()) .into())
}) })
@ -25,7 +25,7 @@ impl NotetypesService for Backend {
fn update_notetype(&self, input: pb::Notetype) -> Result<pb::OpChanges> { fn update_notetype(&self, input: pb::Notetype) -> Result<pb::OpChanges> {
let mut notetype: Notetype = input.into(); let mut notetype: Notetype = input.into();
self.with_col(|col| col.update_notetype(&mut notetype)) self.with_col(|col| col.update_notetype(&mut notetype, false))
.map(Into::into) .map(Into::into)
} }
@ -34,7 +34,7 @@ impl NotetypesService for Backend {
let mut notetype: Notetype = legacy.into(); let mut notetype: Notetype = legacy.into();
self.with_col(|col| { self.with_col(|col| {
Ok(col Ok(col
.add_notetype(&mut notetype)? .add_notetype(&mut notetype, false)?
.map(|_| notetype.id.0) .map(|_| notetype.id.0)
.into()) .into())
}) })
@ -43,7 +43,7 @@ impl NotetypesService for Backend {
fn update_notetype_legacy(&self, input: pb::Json) -> Result<pb::OpChanges> { fn update_notetype_legacy(&self, input: pb::Json) -> Result<pb::OpChanges> {
let legacy: NotetypeSchema11 = serde_json::from_slice(&input.json)?; let legacy: NotetypeSchema11 = serde_json::from_slice(&input.json)?;
let mut notetype: Notetype = legacy.into(); let mut notetype: Notetype = legacy.into();
self.with_col(|col| col.update_notetype(&mut notetype)) self.with_col(|col| col.update_notetype(&mut notetype, false))
.map(Into::into) .map(Into::into)
} }
@ -58,11 +58,11 @@ impl NotetypesService for Backend {
nt.set_modified(col.usn()?); nt.set_modified(col.usn()?);
} }
if nt.id.0 == 0 { if nt.id.0 == 0 {
col.add_notetype(&mut nt)?; col.add_notetype(&mut nt, input.skip_checks)?;
} else if !input.preserve_usn_and_mtime { } else if !input.preserve_usn_and_mtime {
col.update_notetype(&mut nt)?; col.update_notetype(&mut nt, input.skip_checks)?;
} else { } else {
col.add_or_update_notetype_with_existing_id(&mut nt)?; col.add_or_update_notetype_with_existing_id(&mut nt, input.skip_checks)?;
} }
Ok(pb::NotetypeId { ntid: nt.id.0 }) Ok(pb::NotetypeId { ntid: nt.id.0 })
}) })

View file

@ -273,7 +273,7 @@ impl Collection {
// one note type exists // one note type exists
if self.storage.get_all_notetype_names()?.is_empty() { if self.storage.get_all_notetype_names()?.is_empty() {
let mut nt = all_stock_notetypes(&self.tr).remove(0); let mut nt = all_stock_notetypes(&self.tr).remove(0);
self.add_notetype_inner(&mut nt, usn)?; self.add_notetype_inner(&mut nt, usn, true)?;
} }
if out.card_ords_duplicated > 0 if out.card_ords_duplicated > 0
@ -367,7 +367,7 @@ impl Collection {
for n in 0..extra_cards_required { for n in 0..extra_cards_required {
basic.add_template(&format!("Card {}", n + 2), &qfmt, &afmt); basic.add_template(&format!("Card {}", n + 2), &qfmt, &afmt);
} }
self.add_notetype(&mut basic)?; self.add_notetype(&mut basic, true)?;
Ok(Arc::new(basic)) Ok(Arc::new(basic))
} }

View file

@ -117,11 +117,15 @@ impl Notetype {
impl Collection { impl Collection {
/// Add a new notetype, and allocate it an ID. /// Add a new notetype, and allocate it an ID.
pub fn add_notetype(&mut self, notetype: &mut Notetype) -> Result<OpOutput<()>> { pub fn add_notetype(
&mut self,
notetype: &mut Notetype,
skip_checks: bool,
) -> Result<OpOutput<()>> {
self.transact(Op::AddNotetype, |col| { self.transact(Op::AddNotetype, |col| {
let usn = col.usn()?; let usn = col.usn()?;
notetype.set_modified(usn); notetype.set_modified(usn);
col.add_notetype_inner(notetype, usn) col.add_notetype_inner(notetype, usn, skip_checks)
}) })
} }
@ -130,7 +134,11 @@ impl Collection {
/// ///
/// This does not assign ordinals to the provided notetype, so if you wish /// This does not assign ordinals to the provided notetype, so if you wish
/// to make use of template_idx, the notetype must be fetched again. /// to make use of template_idx, the notetype must be fetched again.
pub fn update_notetype(&mut self, notetype: &mut Notetype) -> Result<OpOutput<()>> { pub fn update_notetype(
&mut self,
notetype: &mut Notetype,
skip_checks: bool,
) -> Result<OpOutput<()>> {
self.transact(Op::UpdateNotetype, |col| { self.transact(Op::UpdateNotetype, |col| {
let original = col let original = col
.storage .storage
@ -138,7 +146,12 @@ impl Collection {
.ok_or(AnkiError::NotFound)?; .ok_or(AnkiError::NotFound)?;
let usn = col.usn()?; let usn = col.usn()?;
notetype.set_modified(usn); notetype.set_modified(usn);
col.add_or_update_notetype_with_existing_id_inner(notetype, Some(original), usn) col.add_or_update_notetype_with_existing_id_inner(
notetype,
Some(original),
usn,
skip_checks,
)
}) })
} }
@ -147,11 +160,12 @@ impl Collection {
pub fn add_or_update_notetype_with_existing_id( pub fn add_or_update_notetype_with_existing_id(
&mut self, &mut self,
notetype: &mut Notetype, notetype: &mut Notetype,
skip_checks: bool,
) -> Result<()> { ) -> Result<()> {
self.transact_no_undo(|col| { self.transact_no_undo(|col| {
let usn = col.usn()?; let usn = col.usn()?;
let existing = col.storage.get_notetype(notetype.id)?; let existing = col.storage.get_notetype(notetype.id)?;
col.add_or_update_notetype_with_existing_id_inner(notetype, existing, usn) col.add_or_update_notetype_with_existing_id_inner(notetype, existing, usn, skip_checks)
}) })
} }
@ -419,7 +433,11 @@ impl Notetype {
self.templates.push(CardTemplate::new(name, qfmt, afmt)); self.templates.push(CardTemplate::new(name, qfmt, afmt));
} }
pub(crate) fn prepare_for_update(&mut self, existing: Option<&Notetype>) -> Result<()> { pub(crate) fn prepare_for_update(
&mut self,
existing: Option<&Notetype>,
skip_checks: bool,
) -> Result<()> {
if self.fields.is_empty() { if self.fields.is_empty() {
return Err(AnkiError::invalid_input("1 field required")); return Err(AnkiError::invalid_input("1 field required"));
} }
@ -450,9 +468,11 @@ impl Notetype {
} }
} }
self.config.reqs = reqs; self.config.reqs = reqs;
self.ensure_template_fronts_unique()?; if !skip_checks {
self.ensure_valid_parsed_templates(&parsed_templates)?; self.ensure_template_fronts_unique()?;
self.ensure_cloze_if_cloze_notetype(&parsed_templates)?; self.ensure_valid_parsed_templates(&parsed_templates)?;
self.ensure_cloze_if_cloze_notetype(&parsed_templates)?;
}
Ok(()) Ok(())
} }
@ -610,8 +630,13 @@ impl Collection {
} }
/// Caller must set notetype as modified if appropriate. /// Caller must set notetype as modified if appropriate.
pub(crate) fn add_notetype_inner(&mut self, notetype: &mut Notetype, usn: Usn) -> Result<()> { pub(crate) fn add_notetype_inner(
notetype.prepare_for_update(None)?; &mut self,
notetype: &mut Notetype,
usn: Usn,
skip_checks: bool,
) -> Result<()> {
notetype.prepare_for_update(None, skip_checks)?;
self.ensure_notetype_name_unique(notetype, usn)?; self.ensure_notetype_name_unique(notetype, usn)?;
self.add_notetype_undoable(notetype)?; self.add_notetype_undoable(notetype)?;
self.set_current_notetype_id(notetype.id) self.set_current_notetype_id(notetype.id)
@ -624,9 +649,10 @@ impl Collection {
notetype: &mut Notetype, notetype: &mut Notetype,
original: Option<Notetype>, original: Option<Notetype>,
usn: Usn, usn: Usn,
skip_checks: bool,
) -> Result<()> { ) -> Result<()> {
let normalize = self.get_config_bool(BoolKey::NormalizeNoteText); let normalize = self.get_config_bool(BoolKey::NormalizeNoteText);
notetype.prepare_for_update(original.as_ref())?; notetype.prepare_for_update(original.as_ref(), skip_checks)?;
self.ensure_notetype_name_unique(notetype, usn)?; self.ensure_notetype_name_unique(notetype, usn)?;
if let Some(original) = original { if let Some(original) = original {
@ -671,7 +697,7 @@ impl Collection {
let all = self.storage.get_all_notetype_names()?; let all = self.storage.get_all_notetype_names()?;
if all.is_empty() { if all.is_empty() {
let mut nt = all_stock_notetypes(&self.tr).remove(0); let mut nt = all_stock_notetypes(&self.tr).remove(0);
self.add_notetype_inner(&mut nt, self.usn()?)?; self.add_notetype_inner(&mut nt, self.usn()?, true)?;
self.set_current_notetype_id(nt.id) self.set_current_notetype_id(nt.id)
} else { } else {
self.set_current_notetype_id(all[0].0) self.set_current_notetype_id(all[0].0)

View file

@ -394,7 +394,7 @@ mod test {
basic.add_field("Text"); // 4 basic.add_field("Text"); // 4
basic.add_field("idx5"); basic.add_field("idx5");
// re-fetch to get ordinals // re-fetch to get ordinals
col.update_notetype(&mut basic)?; col.update_notetype(&mut basic, false)?;
let basic = col.get_notetype(basic.id)?.unwrap(); let basic = col.get_notetype(basic.id)?.unwrap();
// if names match, assignments are out of order; unmatched entries // if names match, assignments are out of order; unmatched entries

View file

@ -258,13 +258,13 @@ mod test {
col.add_note(&mut note, DeckId(1))?; col.add_note(&mut note, DeckId(1))?;
nt.add_field("three"); nt.add_field("three");
col.update_notetype(&mut nt)?; col.update_notetype(&mut nt, false)?;
let note = col.storage.get_note(note.id)?.unwrap(); let note = col.storage.get_note(note.id)?.unwrap();
assert_eq!(note.fields(), &["one".to_string(), "two".into(), "".into()]); assert_eq!(note.fields(), &["one".to_string(), "two".into(), "".into()]);
nt.fields.remove(1); nt.fields.remove(1);
col.update_notetype(&mut nt)?; col.update_notetype(&mut nt, false)?;
let note = col.storage.get_note(note.id)?.unwrap(); let note = col.storage.get_note(note.id)?.unwrap();
assert_eq!(note.fields(), &["one".to_string(), "".into()]); assert_eq!(note.fields(), &["one".to_string(), "".into()]);
@ -281,13 +281,13 @@ mod test {
.unwrap(); .unwrap();
nt.templates[0].config.q_format += "\n{{#Front}}{{some:Front}}{{Back}}{{/Front}}"; nt.templates[0].config.q_format += "\n{{#Front}}{{some:Front}}{{Back}}{{/Front}}";
nt.fields[0].name = "Test".into(); nt.fields[0].name = "Test".into();
col.update_notetype(&mut nt)?; col.update_notetype(&mut nt, false)?;
assert_eq!( assert_eq!(
&nt.templates[0].config.q_format, &nt.templates[0].config.q_format,
"{{Test}}\n{{#Test}}{{some:Test}}{{Back}}{{/Test}}" "{{Test}}\n{{#Test}}{{some:Test}}{{Back}}{{/Test}}"
); );
nt.fields.remove(0); nt.fields.remove(0);
col.update_notetype(&mut nt)?; col.update_notetype(&mut nt, false)?;
assert_eq!(&nt.templates[0].config.q_format, "\n{{Back}}"); assert_eq!(&nt.templates[0].config.q_format, "\n{{Back}}");
Ok(()) Ok(())
@ -313,7 +313,7 @@ mod test {
// add an extra card template // add an extra card template
nt.add_template("card 2", "{{Front}}2", ""); nt.add_template("card 2", "{{Front}}2", "");
col.update_notetype(&mut nt)?; col.update_notetype(&mut nt, false)?;
assert_eq!( assert_eq!(
col.search_cards(note.id, SortMode::NoOrder).unwrap().len(), col.search_cards(note.id, SortMode::NoOrder).unwrap().len(),

View file

@ -15,7 +15,7 @@ use crate::{
impl SqliteStorage { impl SqliteStorage {
pub(crate) fn add_stock_notetypes(&self, tr: &I18n) -> Result<()> { pub(crate) fn add_stock_notetypes(&self, tr: &I18n) -> Result<()> {
for (idx, mut nt) in all_stock_notetypes(tr).into_iter().enumerate() { for (idx, mut nt) in all_stock_notetypes(tr).into_iter().enumerate() {
nt.prepare_for_update(None)?; nt.prepare_for_update(None, true)?;
self.add_notetype(&mut nt)?; self.add_notetype(&mut nt)?;
if idx == Kind::Basic as usize { if idx == Kind::Basic as usize {
self.set_config_entry(&ConfigEntry::boxed( self.set_config_entry(&ConfigEntry::boxed(

View file

@ -1386,7 +1386,7 @@ mod test {
// and a new notetype // and a new notetype
let mut nt = all_stock_notetypes(&col1.tr).remove(0); let mut nt = all_stock_notetypes(&col1.tr).remove(0);
nt.name = "new".into(); nt.name = "new".into();
col1.add_notetype(&mut nt)?; col1.add_notetype(&mut nt, false)?;
// add another note+card+tag // add another note+card+tag
let mut note = nt.new_note(); let mut note = nt.new_note();
@ -1502,7 +1502,7 @@ mod test {
let mut nt = col2.storage.get_notetype(nt.id)?.unwrap(); let mut nt = col2.storage.get_notetype(nt.id)?.unwrap();
nt.name = "newer".into(); nt.name = "newer".into();
col2.update_notetype(&mut nt)?; col2.update_notetype(&mut nt, false)?;
// sync the changes back // sync the changes back
let out = ctx.normal_sync(&mut col2).await; let out = ctx.normal_sync(&mut col2).await;