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

View file

@ -320,7 +320,7 @@ fn invalid_char_for_field(c: char) -> bool {
} }
impl Collection { 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() { if !note.tags.is_empty() {
let tags = std::mem::take(&mut note.tags); let tags = std::mem::take(&mut note.tags);
note.tags = self.canonify_tags(tags, usn)?.0; note.tags = self.canonify_tags(tags, usn)?.0;

View file

@ -83,7 +83,7 @@ impl Collection {
} }
/// Add a note, not adding any cards. /// 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.storage.add_note(note)?;
self.save_undo(UndoableNoteChange::Added(Box::new(note.clone()))); self.save_undo(UndoableNoteChange::Added(Box::new(note.clone())));

View file

@ -42,13 +42,6 @@ impl super::SqliteStorage {
.transpose() .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. /// 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<()> { pub(crate) fn update_note(&self, note: &Note) -> Result<()> {
assert!(note.id.0 != 0); assert!(note.id.0 != 0);