Refactor card and revlog importing

This commit is contained in:
RumovZ 2022-04-10 11:03:46 +02:00
parent 8348240f80
commit a402879e72
2 changed files with 45 additions and 52 deletions

View file

@ -11,14 +11,14 @@ use crate::{
card::{CardQueue, CardType}, card::{CardQueue, CardType},
config::SchedulerVersion, config::SchedulerVersion,
prelude::*, prelude::*,
revlog::RevlogEntry,
}; };
struct CardContext<'a> { struct CardContext<'a> {
target_col: &'a mut Collection, target_col: &'a mut Collection,
usn: Usn, usn: Usn,
conflicting_notes: &'a HashSet<NoteId>, imported_notes: &'a HashMap<NoteId, NoteId>,
remapped_notes: &'a HashMap<NoteId, NoteId>,
remapped_decks: &'a HashMap<DeckId, DeckId>, remapped_decks: &'a HashMap<DeckId, DeckId>,
/// The number of days the source collection is ahead of the target collection /// The number of days the source collection is ahead of the target collection
@ -37,9 +37,8 @@ impl<'c> CardContext<'c> {
usn: Usn, usn: Usn,
days_elapsed: u32, days_elapsed: u32,
target_col: &'a mut Collection, target_col: &'a mut Collection,
remapped_notes: &'a HashMap<NoteId, NoteId>, imported_notes: &'a HashMap<NoteId, NoteId>,
remapped_decks: &'a HashMap<DeckId, DeckId>, remapped_decks: &'a HashMap<DeckId, DeckId>,
conflicting_notes: &'a HashSet<NoteId>,
) -> Result<Self> { ) -> Result<Self> {
let targets = target_col.storage.all_cards_as_nid_and_ord()?; let targets = target_col.storage.all_cards_as_nid_and_ord()?;
let collection_delta = target_col.collection_delta(days_elapsed)?; let collection_delta = target_col.collection_delta(days_elapsed)?;
@ -48,8 +47,7 @@ impl<'c> CardContext<'c> {
Ok(Self { Ok(Self {
target_col, target_col,
usn, usn,
conflicting_notes, imported_notes,
remapped_notes,
remapped_decks, remapped_decks,
targets, targets,
collection_delta, collection_delta,
@ -68,34 +66,54 @@ impl Collection {
} }
impl<'a> Context<'a> { impl<'a> Context<'a> {
pub(super) fn import_cards(&mut self) -> Result<HashMap<CardId, CardId>> { pub(super) fn import_cards_and_revlog(&mut self) -> Result<()> {
let mut ctx = CardContext::new( let mut ctx = CardContext::new(
self.usn, self.usn,
self.data.days_elapsed, self.data.days_elapsed,
self.target_col, self.target_col,
&self.remapped_notes, &self.imported_notes,
&self.remapped_decks, &self.remapped_decks,
&self.conflicting_notes,
)?; )?;
ctx.import_cards(mem::take(&mut self.data.cards))?; ctx.import_cards(mem::take(&mut self.data.cards))?;
Ok(ctx.imported_cards) ctx.import_revlog(mem::take(&mut self.data.revlog))
} }
} }
impl CardContext<'_> { impl CardContext<'_> {
pub(super) fn import_cards(&mut self, mut cards: Vec<Card>) -> Result<()> { fn import_cards(&mut self, mut cards: Vec<Card>) -> Result<()> {
for card in &mut cards { for card in &mut cards {
if !self.conflicting_notes.contains(&card.note_id) { if self.map_to_imported_note(card) && !self.target_already_exists(card) {
self.remap_note_id(card); self.add_card(card)?;
if !self.targets.contains(&(card.note_id, card.template_idx)) { }
self.add_card(card)?; // TODO: could update existing card
} }
// TODO: maybe update Ok(())
}
fn import_revlog(&mut self, revlog: Vec<RevlogEntry>) -> Result<()> {
for mut entry in revlog {
if let Some(cid) = self.imported_cards.get(&entry.cid) {
entry.cid = *cid;
entry.usn = self.usn;
self.target_col.add_revlog_entry_if_unique_undoable(entry)?;
} }
} }
Ok(()) Ok(())
} }
fn map_to_imported_note(&self, card: &mut Card) -> bool {
if let Some(nid) = self.imported_notes.get(&card.note_id) {
card.note_id = *nid;
true
} else {
false
}
}
fn target_already_exists(&self, card: &Card) -> bool {
self.targets.contains(&(card.note_id, card.template_idx))
}
fn add_card(&mut self, card: &mut Card) -> Result<()> { fn add_card(&mut self, card: &mut Card) -> Result<()> {
card.usn = self.usn; card.usn = self.usn;
self.remap_deck_id(card); self.remap_deck_id(card);
@ -110,12 +128,6 @@ impl CardContext<'_> {
Ok(()) Ok(())
} }
fn remap_note_id(&self, card: &mut Card) {
if let Some(nid) = self.remapped_notes.get(&card.note_id) {
card.note_id = *nid;
}
}
fn uniquify_card_id(&mut self, card: &mut Card) -> CardId { fn uniquify_card_id(&mut self, card: &mut Card) -> CardId {
let original = card.id; let original = card.id;
while self.target_ids.contains(&card.id) { while self.target_ids.contains(&card.id) {

View file

@ -40,7 +40,7 @@ struct Context<'a> {
archive: ZipArchive<File>, archive: ZipArchive<File>,
guid_map: HashMap<String, NoteMeta>, guid_map: HashMap<String, NoteMeta>,
remapped_notetypes: HashMap<NotetypeId, NotetypeId>, remapped_notetypes: HashMap<NotetypeId, NotetypeId>,
remapped_notes: HashMap<NoteId, NoteId>, imported_notes: HashMap<NoteId, NoteId>,
existing_notes: HashSet<NoteId>, existing_notes: HashSet<NoteId>,
remapped_decks: HashMap<DeckId, DeckId>, remapped_decks: HashMap<DeckId, DeckId>,
data: ExchangeData, data: ExchangeData,
@ -50,10 +50,6 @@ struct Context<'a> {
/// original, normalized file name → (refererenced on import material, /// original, normalized file name → (refererenced on import material,
/// entry with possibly remapped file name) /// entry with possibly remapped file name)
used_media_entries: HashMap<String, (bool, SafeMediaEntry)>, used_media_entries: HashMap<String, (bool, SafeMediaEntry)>,
/// Source notes that cannot be imported, because notes with the same guid
/// exist in the target, but their notetypes don't match.
conflicting_notes: HashSet<NoteId>,
remapped_cards: HashMap<CardId, CardId>,
normalize_notes: bool, normalize_notes: bool,
} }
@ -139,12 +135,10 @@ impl<'a> Context<'a> {
data, data,
guid_map, guid_map,
usn, usn,
conflicting_notes: HashSet::new(),
remapped_notetypes: HashMap::new(), remapped_notetypes: HashMap::new(),
remapped_notes: HashMap::new(), imported_notes: HashMap::new(),
existing_notes, existing_notes,
remapped_decks: HashMap::new(), remapped_decks: HashMap::new(),
remapped_cards: HashMap::new(),
used_media_entries: HashMap::new(), used_media_entries: HashMap::new(),
normalize_notes, normalize_notes,
}) })
@ -156,8 +150,7 @@ impl<'a> Context<'a> {
self.import_notes()?; self.import_notes()?;
self.import_deck_configs()?; self.import_deck_configs()?;
self.import_decks()?; self.import_decks()?;
self.import_cards()?; self.import_cards_and_revlog()?;
self.import_revlog()?;
self.copy_media() self.copy_media()
} }
@ -233,7 +226,6 @@ impl<'a> Context<'a> {
for mut note in mem::take(&mut self.data.notes) { for mut note in mem::take(&mut self.data.notes) {
if let Some(notetype_id) = self.remapped_notetypes.get(&note.notetype_id) { if let Some(notetype_id) = self.remapped_notetypes.get(&note.notetype_id) {
if self.guid_map.contains_key(&note.guid) { if self.guid_map.contains_key(&note.guid) {
self.conflicting_notes.insert(note.id);
// TODO: Log ignore // TODO: Log ignore
} else { } else {
note.notetype_id = *notetype_id; note.notetype_id = *notetype_id;
@ -255,21 +247,21 @@ impl<'a> Context<'a> {
let notetype = self.get_expected_notetype(note.notetype_id)?; let notetype = self.get_expected_notetype(note.notetype_id)?;
note.prepare_for_update(&notetype, self.normalize_notes)?; note.prepare_for_update(&notetype, self.normalize_notes)?;
note.usn = self.usn; note.usn = self.usn;
self.uniquify_note_id(note); let old_id = self.uniquify_note_id(note);
self.target_col.add_note_only_with_id_undoable(note)?; self.target_col.add_note_only_with_id_undoable(note)?;
self.existing_notes.insert(note.id); self.existing_notes.insert(note.id);
self.imported_notes.insert(old_id, note.id);
Ok(()) Ok(())
} }
fn uniquify_note_id(&mut self, note: &mut Note) { fn uniquify_note_id(&mut self, note: &mut Note) -> NoteId {
let original = note.id; let original = note.id;
while self.existing_notes.contains(&note.id) { while self.existing_notes.contains(&note.id) {
note.id.0 += 999; note.id.0 += 999;
} }
if original != note.id { original
self.remapped_notes.insert(original, note.id);
}
} }
fn get_expected_notetype(&mut self, ntid: NotetypeId) -> Result<Arc<Notetype>> { fn get_expected_notetype(&mut self, ntid: NotetypeId) -> Result<Arc<Notetype>> {
@ -288,15 +280,15 @@ impl<'a> Context<'a> {
fn maybe_update_note(&mut self, note: &mut Note, meta: NoteMeta) -> Result<()> { fn maybe_update_note(&mut self, note: &mut Note, meta: NoteMeta) -> Result<()> {
if meta.mtime < note.mtime { if meta.mtime < note.mtime {
if meta.notetype_id == note.notetype_id { if meta.notetype_id == note.notetype_id {
self.remapped_notes.insert(note.id, meta.id); self.imported_notes.insert(note.id, meta.id);
note.id = meta.id; note.id = meta.id;
self.update_note(note)?; self.update_note(note)?;
} else { } else {
self.conflicting_notes.insert(note.id);
// TODO: Log ignore // TODO: Log ignore
} }
} else { } else {
// TODO: Log duplicate // TODO: Log duplicate
self.imported_notes.insert(note.id, meta.id);
} }
Ok(()) Ok(())
} }
@ -396,17 +388,6 @@ impl<'a> Context<'a> {
.get_deck_by_name(deck.name.as_native_str()) .get_deck_by_name(deck.name.as_native_str())
} }
fn import_revlog(&mut self) -> Result<()> {
for mut entry in mem::take(&mut self.data.revlog) {
if let Some(cid) = self.remapped_cards.get(&entry.cid) {
entry.cid = *cid;
entry.usn = self.usn;
self.target_col.add_revlog_entry_if_unique_undoable(entry)?;
}
}
Ok(())
}
fn copy_media(&mut self) -> Result<()> { fn copy_media(&mut self) -> Result<()> {
for (used, entry) in self.used_media_entries.values() { for (used, entry) in self.used_media_entries.values() {
if *used { if *used {