mirror of
https://github.com/ankitects/anki.git
synced 2025-09-22 07:52:24 -04:00
support updating multiple cards in one transaction/undo op
This commit is contained in:
parent
cc65196b0a
commit
88a3fd8d7b
5 changed files with 32 additions and 15 deletions
|
@ -10,7 +10,7 @@ import "anki/collection.proto";
|
||||||
|
|
||||||
service CardsService {
|
service CardsService {
|
||||||
rpc GetCard(CardId) returns (Card);
|
rpc GetCard(CardId) returns (Card);
|
||||||
rpc UpdateCard(UpdateCardRequest) returns (collection.OpChanges);
|
rpc UpdateCards(UpdateCardsRequest) returns (collection.OpChanges);
|
||||||
rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty);
|
rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty);
|
||||||
rpc SetDeck(SetDeckRequest) returns (collection.OpChangesWithCount);
|
rpc SetDeck(SetDeckRequest) returns (collection.OpChangesWithCount);
|
||||||
rpc SetFlag(SetFlagRequest) returns (collection.OpChangesWithCount);
|
rpc SetFlag(SetFlagRequest) returns (collection.OpChangesWithCount);
|
||||||
|
@ -44,8 +44,8 @@ message Card {
|
||||||
string data = 18;
|
string data = 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateCardRequest {
|
message UpdateCardsRequest {
|
||||||
Card card = 1;
|
repeated Card cards = 1;
|
||||||
bool skip_undo_entry = 2;
|
bool skip_undo_entry = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,8 +114,8 @@ class Card(DeprecatedNamesMixin):
|
||||||
def flush(self) -> None:
|
def flush(self) -> None:
|
||||||
hooks.card_will_flush(self)
|
hooks.card_will_flush(self)
|
||||||
if self.id != 0:
|
if self.id != 0:
|
||||||
self.col._backend.update_card(
|
self.col._backend.update_cards(
|
||||||
card=self._to_backend_card(), skip_undo_entry=True
|
cards=[self._to_backend_card()], skip_undo_entry=True
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise Exception("card.flush() expects an existing card")
|
raise Exception("card.flush() expects an existing card")
|
||||||
|
|
|
@ -314,10 +314,17 @@ class Collection(DeprecatedNamesMixin):
|
||||||
def get_card(self, id: CardId) -> Card:
|
def get_card(self, id: CardId) -> Card:
|
||||||
return Card(self, id)
|
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.
|
"""Save card changes to database, and add an undo entry.
|
||||||
Unlike card.flush(), this will invalidate any current checkpoint."""
|
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:
|
def get_note(self, id: NoteId) -> Note:
|
||||||
return Note(self, id=id)
|
return Note(self, id=id)
|
||||||
|
|
|
@ -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| {
|
self.with_col(|col| {
|
||||||
let mut card: Card = input.card.ok_or(AnkiError::NotFound)?.try_into()?;
|
let cards = input
|
||||||
col.update_card_maybe_undoable(&mut card, !input.skip_undo_entry)
|
.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)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,19 +159,25 @@ impl Card {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collection {
|
impl Collection {
|
||||||
pub(crate) fn update_card_maybe_undoable(
|
pub(crate) fn update_cards_maybe_undoable(
|
||||||
&mut self,
|
&mut self,
|
||||||
card: &mut Card,
|
cards: Vec<Card>,
|
||||||
undoable: bool,
|
undoable: bool,
|
||||||
) -> Result<OpOutput<()>> {
|
) -> Result<OpOutput<()>> {
|
||||||
let existing = self.storage.get_card(card.id)?.ok_or(AnkiError::NotFound)?;
|
|
||||||
if undoable {
|
if undoable {
|
||||||
self.transact(Op::UpdateCard, |col| {
|
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 {
|
} else {
|
||||||
self.transact_no_undo(|col| {
|
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 {
|
Ok(OpOutput {
|
||||||
output: (),
|
output: (),
|
||||||
changes: OpChanges {
|
changes: OpChanges {
|
||||||
|
|
Loading…
Reference in a new issue