support updating multiple notes in one transaction/undo op

This commit is contained in:
Damien Elmes 2021-08-02 17:07:26 +10:00
parent 88a3fd8d7b
commit 7ba35b7249
5 changed files with 32 additions and 16 deletions

View file

@ -15,7 +15,7 @@ service NotesService {
rpc AddNote(AddNoteRequest) returns (AddNoteResponse); rpc AddNote(AddNoteRequest) returns (AddNoteResponse);
rpc DefaultsForAdding(DefaultsForAddingRequest) returns (DeckAndNotetype); rpc DefaultsForAdding(DefaultsForAddingRequest) returns (DeckAndNotetype);
rpc DefaultDeckForNotetype(notetypes.NotetypeId) returns (decks.DeckId); rpc DefaultDeckForNotetype(notetypes.NotetypeId) returns (decks.DeckId);
rpc UpdateNote(UpdateNoteRequest) returns (collection.OpChanges); rpc UpdateNotes(UpdateNotesRequest) returns (collection.OpChanges);
rpc GetNote(NoteId) returns (Note); rpc GetNote(NoteId) returns (Note);
rpc RemoveNotes(RemoveNotesRequest) returns (collection.OpChangesWithCount); rpc RemoveNotes(RemoveNotesRequest) returns (collection.OpChangesWithCount);
rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteResponse); rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteResponse);
@ -56,8 +56,8 @@ message AddNoteResponse {
collection.OpChanges changes = 2; collection.OpChanges changes = 2;
} }
message UpdateNoteRequest { message UpdateNotesRequest {
Note note = 1; repeated Note notes = 1;
bool skip_undo_entry = 2; bool skip_undo_entry = 2;
} }

View file

@ -329,12 +329,17 @@ class Collection(DeprecatedNamesMixin):
def get_note(self, id: NoteId) -> Note: def get_note(self, id: NoteId) -> Note:
return Note(self, id=id) return Note(self, id=id)
def update_notes(self, notes: Sequence[Note]) -> OpChanges:
"""Save note changes to database, and add an undo entry.
Unlike note.flush(), this will invalidate any current checkpoint."""
return self._backend.update_notes(
notes=[n._to_backend_note() for n in notes], skip_undo_entry=False
)
def update_note(self, note: Note) -> OpChanges: def update_note(self, note: Note) -> OpChanges:
"""Save note changes to database, and add an undo entry. """Save note changes to database, and add an undo entry.
Unlike note.flush(), this will invalidate any current checkpoint.""" Unlike note.flush(), this will invalidate any current checkpoint."""
return self._backend.update_note( return self.update_notes([note])
note=note._to_backend_note(), skip_undo_entry=False
)
getCard = get_card getCard = get_card
getNote = get_note getNote = get_note

View file

@ -79,8 +79,8 @@ class Note(DeprecatedNamesMixin):
"""This preserves any current checkpoint. """This preserves any current checkpoint.
For an undo entry, use col.update_note() instead.""" For an undo entry, use col.update_note() instead."""
assert self.id != 0 assert self.id != 0
self.col._backend.update_note( self.col._backend.update_notes(
note=self._to_backend_note(), skip_undo_entry=True notes=[self._to_backend_note()], skip_undo_entry=True
) )
def joined_fields(self) -> str: def joined_fields(self) -> str:

View file

@ -49,10 +49,14 @@ impl NotesService for Backend {
}) })
} }
fn update_note(&self, input: pb::UpdateNoteRequest) -> Result<pb::OpChanges> { fn update_notes(&self, input: pb::UpdateNotesRequest) -> Result<pb::OpChanges> {
self.with_col(|col| { self.with_col(|col| {
let mut note: Note = input.note.ok_or(AnkiError::NotFound)?.into(); let notes = input
col.update_note_maybe_undoable(&mut note, !input.skip_undo_entry) .notes
.into_iter()
.map(Into::into)
.collect::<Vec<Note>>();
col.update_notes_maybe_undoable(notes, !input.skip_undo_entry)
}) })
.map(Into::into) .map(Into::into)
} }

View file

@ -348,19 +348,26 @@ impl Collection {
#[cfg(test)] #[cfg(test)]
pub(crate) fn update_note(&mut self, note: &mut Note) -> Result<OpOutput<()>> { pub(crate) fn update_note(&mut self, note: &mut Note) -> Result<OpOutput<()>> {
self.update_note_maybe_undoable(note, true) self.transact(Op::UpdateNote, |col| col.update_note_inner(note))
} }
pub(crate) fn update_note_maybe_undoable( pub(crate) fn update_notes_maybe_undoable(
&mut self, &mut self,
note: &mut Note, notes: Vec<Note>,
undoable: bool, undoable: bool,
) -> Result<OpOutput<()>> { ) -> Result<OpOutput<()>> {
if undoable { if undoable {
self.transact(Op::UpdateNote, |col| col.update_note_inner(note)) self.transact(Op::UpdateNote, |col| {
for mut note in notes {
col.update_note_inner(&mut note)?;
}
Ok(())
})
} else { } else {
self.transact_no_undo(|col| { self.transact_no_undo(|col| {
col.update_note_inner(note)?; for mut note in notes {
col.update_note_inner(&mut note)?;
}
Ok(OpOutput { Ok(OpOutput {
output: (), output: (),
changes: OpChanges { changes: OpChanges {