support updating multiple cards in one transaction/undo op

This commit is contained in:
Damien Elmes 2021-08-02 16:47:05 +10:00
parent cc65196b0a
commit 88a3fd8d7b
5 changed files with 32 additions and 15 deletions

View file

@ -10,7 +10,7 @@ import "anki/collection.proto";
service CardsService {
rpc GetCard(CardId) returns (Card);
rpc UpdateCard(UpdateCardRequest) returns (collection.OpChanges);
rpc UpdateCards(UpdateCardsRequest) returns (collection.OpChanges);
rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty);
rpc SetDeck(SetDeckRequest) returns (collection.OpChangesWithCount);
rpc SetFlag(SetFlagRequest) returns (collection.OpChangesWithCount);
@ -44,8 +44,8 @@ message Card {
string data = 18;
}
message UpdateCardRequest {
Card card = 1;
message UpdateCardsRequest {
repeated Card cards = 1;
bool skip_undo_entry = 2;
}

View file

@ -114,8 +114,8 @@ class Card(DeprecatedNamesMixin):
def flush(self) -> None:
hooks.card_will_flush(self)
if self.id != 0:
self.col._backend.update_card(
card=self._to_backend_card(), skip_undo_entry=True
self.col._backend.update_cards(
cards=[self._to_backend_card()], skip_undo_entry=True
)
else:
raise Exception("card.flush() expects an existing card")

View file

@ -314,10 +314,17 @@ class Collection(DeprecatedNamesMixin):
def get_card(self, id: CardId) -> Card:
return Card(self, id)
def update_card(self, card: Card) -> None:
def update_cards(self, cards: Sequence[Card]) -> OpChanges:
"""Save card changes to database, and add an undo entry.
Unlike card.flush(), this will invalidate any current checkpoint."""
self._backend.update_card(card=card._to_backend_card(), skip_undo_entry=False)
return self._backend.update_cards(
cards=[c._to_backend_card() for c in cards], skip_undo_entry=False
)
def update_card(self, card: Card) -> OpChanges:
"""Save card changes to database, and add an undo entry.
Unlike card.flush(), this will invalidate any current checkpoint."""
return self.update_cards([card])
def get_note(self, id: NoteId) -> Note:
return Note(self, id=id)

View file

@ -21,10 +21,14 @@ impl CardsService for Backend {
})
}
fn update_card(&self, input: pb::UpdateCardRequest) -> Result<pb::OpChanges> {
fn update_cards(&self, input: pb::UpdateCardsRequest) -> Result<pb::OpChanges> {
self.with_col(|col| {
let mut card: Card = input.card.ok_or(AnkiError::NotFound)?.try_into()?;
col.update_card_maybe_undoable(&mut card, !input.skip_undo_entry)
let cards = input
.cards
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Card>, AnkiError>>()?;
col.update_cards_maybe_undoable(cards, !input.skip_undo_entry)
})
.map(Into::into)
}

View file

@ -159,19 +159,25 @@ impl Card {
}
impl Collection {
pub(crate) fn update_card_maybe_undoable(
pub(crate) fn update_cards_maybe_undoable(
&mut self,
card: &mut Card,
cards: Vec<Card>,
undoable: bool,
) -> Result<OpOutput<()>> {
let existing = self.storage.get_card(card.id)?.ok_or(AnkiError::NotFound)?;
if undoable {
self.transact(Op::UpdateCard, |col| {
col.update_card_inner(card, existing, col.usn()?)
for mut card in cards {
let existing = col.storage.get_card(card.id)?.ok_or(AnkiError::NotFound)?;
col.update_card_inner(&mut card, existing, col.usn()?)?
}
Ok(())
})
} else {
self.transact_no_undo(|col| {
col.update_card_inner(card, existing, col.usn()?)?;
for mut card in cards {
let existing = col.storage.get_card(card.id)?.ok_or(AnkiError::NotFound)?;
col.update_card_inner(&mut card, existing, col.usn()?)?;
}
Ok(OpOutput {
output: (),
changes: OpChanges {