mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 23:42: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>,
|
guid_map: HashMap<String, NoteMeta>,
|
||||||
remapped_notetypes: HashMap<NotetypeId, NotetypeId>,
|
remapped_notetypes: HashMap<NotetypeId, NotetypeId>,
|
||||||
remapped_notes: HashMap<NoteId, NoteId>,
|
remapped_notes: HashMap<NoteId, NoteId>,
|
||||||
|
existing_notes: HashSet<NoteId>,
|
||||||
remapped_decks: HashMap<DeckId, DeckId>,
|
remapped_decks: HashMap<DeckId, DeckId>,
|
||||||
remapped_deck_configs: HashMap<DeckConfigId, DeckConfigId>,
|
remapped_deck_configs: HashMap<DeckConfigId, DeckConfigId>,
|
||||||
data: ExchangeData,
|
data: ExchangeData,
|
||||||
|
@ -128,6 +129,7 @@ impl<'a> Context<'a> {
|
||||||
let guid_map = target_col.storage.note_guid_map()?;
|
let guid_map = target_col.storage.note_guid_map()?;
|
||||||
let usn = target_col.usn()?;
|
let usn = target_col.usn()?;
|
||||||
let normalize_notes = target_col.get_config_bool(BoolKey::NormalizeNoteText);
|
let normalize_notes = target_col.get_config_bool(BoolKey::NormalizeNoteText);
|
||||||
|
let existing_notes = target_col.storage.get_all_note_ids()?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
target_col,
|
target_col,
|
||||||
archive,
|
archive,
|
||||||
|
@ -137,6 +139,7 @@ impl<'a> Context<'a> {
|
||||||
conflicting_notes: HashSet::new(),
|
conflicting_notes: HashSet::new(),
|
||||||
remapped_notetypes: HashMap::new(),
|
remapped_notetypes: HashMap::new(),
|
||||||
remapped_notes: HashMap::new(),
|
remapped_notes: HashMap::new(),
|
||||||
|
existing_notes,
|
||||||
remapped_decks: HashMap::new(),
|
remapped_decks: HashMap::new(),
|
||||||
remapped_deck_configs: HashMap::new(),
|
remapped_deck_configs: HashMap::new(),
|
||||||
added_cards: HashSet::new(),
|
added_cards: HashSet::new(),
|
||||||
|
@ -248,12 +251,23 @@ 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(¬etype, self.normalize_notes)?;
|
note.prepare_for_update(¬etype, self.normalize_notes)?;
|
||||||
note.usn = self.usn;
|
note.usn = self.usn;
|
||||||
let old_id = std::mem::take(&mut note.id);
|
self.uniquify_note_id(note);
|
||||||
self.target_col.add_note_only_undoable(note)?;
|
|
||||||
self.remapped_notes.insert(old_id, note.id);
|
self.target_col.add_note_only_with_id_undoable(note)?;
|
||||||
|
self.existing_notes.insert(note.id);
|
||||||
Ok(())
|
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>> {
|
fn get_expected_notetype(&mut self, ntid: NotetypeId) -> Result<Arc<Notetype>> {
|
||||||
self.target_col
|
self.target_col
|
||||||
.get_notetype(ntid)?
|
.get_notetype(ntid)?
|
||||||
|
|
|
@ -90,6 +90,16 @@ impl Collection {
|
||||||
Ok(())
|
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(
|
pub(crate) fn update_note_tags_undoable(
|
||||||
&mut self,
|
&mut self,
|
||||||
tags: &NoteTags,
|
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()
|
.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);
|
||||||
|
@ -78,6 +85,24 @@ impl super::SqliteStorage {
|
||||||
Ok(())
|
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.
|
/// Add or update the provided note, preserving ID. Used by the syncing code.
|
||||||
pub(crate) fn add_or_update_note(&self, note: &Note) -> Result<()> {
|
pub(crate) fn add_or_update_note(&self, note: &Note) -> Result<()> {
|
||||||
let mut stmt = self.db.prepare_cached(include_str!("add_or_update.sql"))?;
|
let mut stmt = self.db.prepare_cached(include_str!("add_or_update.sql"))?;
|
||||||
|
|
Loading…
Reference in a new issue