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 {
bytes json = 1;
bool preserve_usn_and_mtime = 2;
bool skip_checks = 3;
}
message StockNotetype {

View file

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

View file

@ -527,12 +527,19 @@ and notes.mid = ? and cards.ord = ?""",
pass
# @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."
self._remove_from_cache(notetype["id"])
self.ensure_name_unique(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._mutate_after_write(notetype)

View file

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

View file

@ -273,7 +273,7 @@ impl Collection {
// one note type exists
if self.storage.get_all_notetype_names()?.is_empty() {
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
@ -367,7 +367,7 @@ impl Collection {
for n in 0..extra_cards_required {
basic.add_template(&format!("Card {}", n + 2), &qfmt, &afmt);
}
self.add_notetype(&mut basic)?;
self.add_notetype(&mut basic, true)?;
Ok(Arc::new(basic))
}

View file

@ -117,11 +117,15 @@ impl Notetype {
impl Collection {
/// 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| {
let usn = col.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
/// 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| {
let original = col
.storage
@ -138,7 +146,12 @@ impl Collection {
.ok_or(AnkiError::NotFound)?;
let usn = col.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(
&mut self,
notetype: &mut Notetype,
skip_checks: bool,
) -> Result<()> {
self.transact_no_undo(|col| {
let usn = col.usn()?;
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));
}
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() {
return Err(AnkiError::invalid_input("1 field required"));
}
@ -450,9 +468,11 @@ impl Notetype {
}
}
self.config.reqs = reqs;
self.ensure_template_fronts_unique()?;
self.ensure_valid_parsed_templates(&parsed_templates)?;
self.ensure_cloze_if_cloze_notetype(&parsed_templates)?;
if !skip_checks {
self.ensure_template_fronts_unique()?;
self.ensure_valid_parsed_templates(&parsed_templates)?;
self.ensure_cloze_if_cloze_notetype(&parsed_templates)?;
}
Ok(())
}
@ -610,8 +630,13 @@ impl Collection {
}
/// Caller must set notetype as modified if appropriate.
pub(crate) fn add_notetype_inner(&mut self, notetype: &mut Notetype, usn: Usn) -> Result<()> {
notetype.prepare_for_update(None)?;
pub(crate) fn add_notetype_inner(
&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.add_notetype_undoable(notetype)?;
self.set_current_notetype_id(notetype.id)
@ -624,9 +649,10 @@ impl Collection {
notetype: &mut Notetype,
original: Option<Notetype>,
usn: Usn,
skip_checks: bool,
) -> Result<()> {
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)?;
if let Some(original) = original {
@ -671,7 +697,7 @@ impl Collection {
let all = self.storage.get_all_notetype_names()?;
if all.is_empty() {
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)
} else {
self.set_current_notetype_id(all[0].0)

View file

@ -394,7 +394,7 @@ mod test {
basic.add_field("Text"); // 4
basic.add_field("idx5");
// re-fetch to get ordinals
col.update_notetype(&mut basic)?;
col.update_notetype(&mut basic, false)?;
let basic = col.get_notetype(basic.id)?.unwrap();
// 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))?;
nt.add_field("three");
col.update_notetype(&mut nt)?;
col.update_notetype(&mut nt, false)?;
let note = col.storage.get_note(note.id)?.unwrap();
assert_eq!(note.fields(), &["one".to_string(), "two".into(), "".into()]);
nt.fields.remove(1);
col.update_notetype(&mut nt)?;
col.update_notetype(&mut nt, false)?;
let note = col.storage.get_note(note.id)?.unwrap();
assert_eq!(note.fields(), &["one".to_string(), "".into()]);
@ -281,13 +281,13 @@ mod test {
.unwrap();
nt.templates[0].config.q_format += "\n{{#Front}}{{some:Front}}{{Back}}{{/Front}}";
nt.fields[0].name = "Test".into();
col.update_notetype(&mut nt)?;
col.update_notetype(&mut nt, false)?;
assert_eq!(
&nt.templates[0].config.q_format,
"{{Test}}\n{{#Test}}{{some:Test}}{{Back}}{{/Test}}"
);
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}}");
Ok(())
@ -313,7 +313,7 @@ mod test {
// add an extra card template
nt.add_template("card 2", "{{Front}}2", "");
col.update_notetype(&mut nt)?;
col.update_notetype(&mut nt, false)?;
assert_eq!(
col.search_cards(note.id, SortMode::NoOrder).unwrap().len(),

View file

@ -15,7 +15,7 @@ use crate::{
impl SqliteStorage {
pub(crate) fn add_stock_notetypes(&self, tr: &I18n) -> Result<()> {
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)?;
if idx == Kind::Basic as usize {
self.set_config_entry(&ConfigEntry::boxed(

View file

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