Add notes immediately instaed of preparing

This commit is contained in:
RumovZ 2022-04-07 20:49:42 +02:00
parent b9c19273fc
commit 94a6cdd6ed
4 changed files with 55 additions and 44 deletions

View file

@ -7,6 +7,7 @@ use std::{
fs::File,
io::{self},
mem,
sync::Arc,
};
use sha1::Sha1;
@ -35,7 +36,7 @@ struct Context<'a> {
archive: ZipArchive<File>,
guid_map: HashMap<String, NoteMeta>,
remapped_notetypes: HashMap<NotetypeId, NotetypeId>,
existing_notes: HashSet<NoteId>,
remapped_notes: HashMap<NoteId, NoteId>,
data: ExchangeData,
usn: Usn,
/// Map of source media files, that do not already exist in the target.
@ -44,6 +45,7 @@ struct Context<'a> {
/// entry with possibly remapped file name)
used_media_entries: HashMap<String, (bool, SafeMediaEntry)>,
conflicting_notes: HashSet<String>,
normalize_notes: bool,
}
#[derive(Debug, Clone, Copy)]
@ -61,10 +63,6 @@ impl NoteMeta {
notetype_id,
}
}
fn from_note(note: &Note) -> Self {
Self::new(note.id, note.mtime, note.notetype_id)
}
}
impl SafeMediaEntry {
@ -95,8 +93,8 @@ impl Collection {
let mut ctx = Context::new(archive, self, search, with_scheduling)?;
ctx.prepare_media()?;
ctx.prepare_notetypes()?;
ctx.prepare_notes()?;
ctx.import_notetypes()?;
ctx.import_notes()?;
ctx.target_col.insert_data(&ctx.data)?;
ctx.copy_media()?;
@ -136,18 +134,19 @@ impl<'a> Context<'a> {
) -> Result<Self> {
let data = ExchangeData::gather_from_archive(&mut archive, search, with_scheduling)?;
let guid_map = target_col.storage.note_guid_map()?;
let existing_notes = target_col.storage.get_all_note_ids()?;
let usn = target_col.usn()?;
let normalize_notes = target_col.get_config_bool(BoolKey::NormalizeNoteText);
Ok(Self {
target_col,
archive,
data,
guid_map,
existing_notes,
usn,
conflicting_notes: HashSet::new(),
remapped_notetypes: HashMap::new(),
remapped_notes: HashMap::new(),
used_media_entries: HashMap::new(),
normalize_notes,
})
}
@ -169,7 +168,7 @@ impl<'a> Context<'a> {
Ok(())
}
fn prepare_notetypes(&mut self) -> Result<()> {
fn import_notetypes(&mut self) -> Result<()> {
for mut notetype in std::mem::take(&mut self.data.notetypes) {
if let Some(existing) = self.target_col.storage.get_notetype(notetype.id)? {
self.merge_or_remap_notetype(&mut notetype, existing)?;
@ -204,7 +203,6 @@ impl<'a> Context<'a> {
fn update_notetype(&mut self, notetype: &mut Notetype, original: Notetype) -> Result<()> {
notetype.usn = self.usn;
// TODO: make undoable
self.target_col
.add_or_update_notetype_with_existing_id_inner(notetype, Some(original), self.usn, true)
}
@ -218,46 +216,56 @@ impl<'a> Context<'a> {
Ok(())
}
fn prepare_notes(&mut self) -> Result<()> {
fn import_notes(&mut self) -> Result<()> {
for mut note in mem::take(&mut self.data.notes) {
if let Some(notetype_id) = self.remapped_notetypes.get(&note.notetype_id) {
if self.guid_map.contains_key(&note.guid) {
todo!("ignore");
self.conflicting_notes.insert(note.guid);
// TODO: Log ignore
} else {
note.notetype_id = *notetype_id;
self.prepare_new_note(note)?;
self.add_note(&mut note)?;
}
} else if let Some(&meta) = self.guid_map.get(&note.guid) {
self.prepare_existing_note(note, meta)?;
self.maybe_update_note(note, meta)?;
} else {
self.prepare_new_note(note)?;
self.add_note(&mut note)?;
}
}
Ok(())
}
fn add_prepared_note(&mut self, mut note: Note) -> Result<()> {
self.munge_media(&mut note)?;
fn add_note(&mut self, mut note: &mut Note) -> Result<()> {
// TODO: Log add
self.munge_media(note)?;
self.target_col.canonify_note_tags(note, self.usn)?;
let notetype = self.get_expected_notetype(note.notetype_id)?;
note.prepare_for_update(&notetype, self.normalize_notes)?;
note.usn = self.usn;
self.data.notes.push(note);
let old_id = std::mem::take(&mut note.id);
self.target_col.add_note_only_undoable(note)?;
self.remapped_notes.insert(old_id, note.id);
Ok(())
}
fn prepare_new_note(&mut self, mut note: Note) -> Result<()> {
self.to_next_available_note_id(&mut note.id);
self.existing_notes.insert(note.id);
self.guid_map
.insert(note.guid.clone(), NoteMeta::from_note(&note));
self.add_prepared_note(note)
// TODO: Log add
fn get_expected_notetype(&mut self, ntid: NotetypeId) -> Result<Arc<Notetype>> {
self.target_col
.get_notetype(ntid)?
.ok_or(AnkiError::NotFound)
}
fn prepare_existing_note(&mut self, mut note: Note, meta: NoteMeta) -> Result<()> {
fn get_expected_note(&mut self, nid: NoteId) -> Result<Note> {
self.target_col
.storage
.get_note(nid)?
.ok_or(AnkiError::NotFound)
}
fn maybe_update_note(&mut self, mut note: Note, meta: NoteMeta) -> Result<()> {
if meta.mtime < note.mtime {
if meta.notetype_id == note.notetype_id {
note.id = meta.id;
self.add_prepared_note(note)?;
// TODO: Log update
self.update_note(&mut note)?;
} else {
self.conflicting_notes.insert(note.guid);
// TODO: Log ignore
@ -268,6 +276,22 @@ impl<'a> Context<'a> {
Ok(())
}
fn update_note(&mut self, note: &mut Note) -> Result<()> {
// TODO: Log update
self.munge_media(note)?;
let original = self.get_expected_note(note.id)?;
let notetype = self.get_expected_notetype(note.notetype_id)?;
self.target_col.update_note_inner_without_cards(
note,
&original,
&notetype,
self.usn,
true,
self.normalize_notes,
true,
)
}
fn munge_media(&mut self, note: &mut Note) -> Result<()> {
for field in note.fields_mut() {
if let Some(new_field) = self.replace_media_refs(field) {
@ -295,12 +319,6 @@ impl<'a> Context<'a> {
})
}
fn to_next_available_note_id(&self, note_id: &mut NoteId) {
while self.existing_notes.contains(note_id) {
note_id.0 += 999;
}
}
fn copy_media(&mut self) -> Result<()> {
for (used, entry) in self.used_media_entries.values() {
if *used {

View file

@ -320,7 +320,7 @@ fn invalid_char_for_field(c: char) -> bool {
}
impl Collection {
fn canonify_note_tags(&mut self, note: &mut Note, usn: Usn) -> Result<()> {
pub(crate) fn canonify_note_tags(&mut self, note: &mut Note, usn: Usn) -> Result<()> {
if !note.tags.is_empty() {
let tags = std::mem::take(&mut note.tags);
note.tags = self.canonify_tags(tags, usn)?.0;

View file

@ -83,7 +83,7 @@ impl Collection {
}
/// Add a note, not adding any cards.
pub(super) fn add_note_only_undoable(&mut self, note: &mut Note) -> Result<(), AnkiError> {
pub(crate) fn add_note_only_undoable(&mut self, note: &mut Note) -> Result<(), AnkiError> {
self.storage.add_note(note)?;
self.save_undo(UndoableNoteChange::Added(Box::new(note.clone())));

View file

@ -42,13 +42,6 @@ impl super::SqliteStorage {
.transpose()
}
pub fn get_all_note_ids(&self) -> Result<HashSet<NoteId>> {
self.db
.prepare("SELECT id FROM notes")?
.query_and_then([], |row| Ok(row.get(0)?))?
.collect()
}
/// If fields have been modified, caller must call note.prepare_for_update() prior to calling this.
pub(crate) fn update_note(&self, note: &Note) -> Result<()> {
assert!(note.id.0 != 0);