mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 07:22:23 -04:00
Try to keep source ids of imported notes
This commit is contained in:
parent
5a76d2211a
commit
2a15ba5404
4 changed files with 79 additions and 3 deletions
|
@ -39,6 +39,7 @@ struct Context<'a> {
|
|||
guid_map: HashMap<String, NoteMeta>,
|
||||
remapped_notetypes: HashMap<NotetypeId, NotetypeId>,
|
||||
remapped_notes: HashMap<NoteId, NoteId>,
|
||||
existing_notes: HashSet<NoteId>,
|
||||
remapped_decks: HashMap<DeckId, DeckId>,
|
||||
remapped_deck_configs: HashMap<DeckConfigId, DeckConfigId>,
|
||||
data: ExchangeData,
|
||||
|
@ -128,6 +129,7 @@ impl<'a> Context<'a> {
|
|||
let guid_map = target_col.storage.note_guid_map()?;
|
||||
let usn = target_col.usn()?;
|
||||
let normalize_notes = target_col.get_config_bool(BoolKey::NormalizeNoteText);
|
||||
let existing_notes = target_col.storage.get_all_note_ids()?;
|
||||
Ok(Self {
|
||||
target_col,
|
||||
archive,
|
||||
|
@ -137,6 +139,7 @@ impl<'a> Context<'a> {
|
|||
conflicting_notes: HashSet::new(),
|
||||
remapped_notetypes: HashMap::new(),
|
||||
remapped_notes: HashMap::new(),
|
||||
existing_notes,
|
||||
remapped_decks: HashMap::new(),
|
||||
remapped_deck_configs: HashMap::new(),
|
||||
added_cards: HashSet::new(),
|
||||
|
@ -248,12 +251,23 @@ impl<'a> Context<'a> {
|
|||
let notetype = self.get_expected_notetype(note.notetype_id)?;
|
||||
note.prepare_for_update(¬etype, self.normalize_notes)?;
|
||||
note.usn = self.usn;
|
||||
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);
|
||||
self.uniquify_note_id(note);
|
||||
|
||||
self.target_col.add_note_only_with_id_undoable(note)?;
|
||||
self.existing_notes.insert(note.id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn uniquify_note_id(&mut self, note: &mut Note) {
|
||||
let original = note.id;
|
||||
while self.existing_notes.contains(¬e.id) {
|
||||
note.id.0 += 999;
|
||||
}
|
||||
if original != note.id {
|
||||
self.remapped_notes.insert(original, note.id);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_expected_notetype(&mut self, ntid: NotetypeId) -> Result<Arc<Notetype>> {
|
||||
self.target_col
|
||||
.get_notetype(ntid)?
|
||||
|
|
|
@ -90,6 +90,16 @@ impl Collection {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a note, not adding any cards. Caller guarantees id is unique.
|
||||
pub(crate) fn add_note_only_with_id_undoable(&mut self, note: &mut Note) -> Result<()> {
|
||||
if self.storage.add_note_if_unique(note)? {
|
||||
self.save_undo(UndoableNoteChange::Added(Box::new(note.clone())));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AnkiError::invalid_input("note id existed"))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_note_tags_undoable(
|
||||
&mut self,
|
||||
tags: &NoteTags,
|
||||
|
|
27
rslib/src/storage/note/add_if_unique.sql
Normal file
27
rslib/src/storage/note/add_if_unique.sql
Normal file
|
@ -0,0 +1,27 @@
|
|||
INSERT
|
||||
OR IGNORE INTO notes (
|
||||
id,
|
||||
guid,
|
||||
mid,
|
||||
mod,
|
||||
usn,
|
||||
tags,
|
||||
flds,
|
||||
sfld,
|
||||
csum,
|
||||
flags,
|
||||
data
|
||||
)
|
||||
VALUES (
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
0,
|
||||
""
|
||||
)
|
|
@ -42,6 +42,13 @@ 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);
|
||||
|
@ -78,6 +85,24 @@ impl super::SqliteStorage {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn add_note_if_unique(&self, note: &Note) -> Result<bool> {
|
||||
self.db
|
||||
.prepare_cached(include_str!("add_if_unique.sql"))?
|
||||
.execute(params![
|
||||
note.id,
|
||||
note.guid,
|
||||
note.notetype_id,
|
||||
note.mtime,
|
||||
note.usn,
|
||||
join_tags(¬e.tags),
|
||||
join_fields(note.fields()),
|
||||
note.sort_field.as_ref().unwrap(),
|
||||
note.checksum.unwrap(),
|
||||
])
|
||||
.map(|added| added == 1)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Add or update the provided note, preserving ID. Used by the syncing code.
|
||||
pub(crate) fn add_or_update_note(&self, note: &Note) -> Result<()> {
|
||||
let mut stmt = self.db.prepare_cached(include_str!("add_or_update.sql"))?;
|
||||
|
|
Loading…
Reference in a new issue