mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
update scheduling ops
- migrate to CollectionOp() - return actual change count when suspending/burying - add helper to convert vec to vec of newtype
This commit is contained in:
parent
2de8cc1a94
commit
84fe309583
15 changed files with 172 additions and 127 deletions
|
@ -16,7 +16,7 @@ from typing import List, Optional, Sequence
|
|||
from anki.cards import CardId
|
||||
from anki.consts import CARD_TYPE_NEW, NEW_CARDS_RANDOM, QUEUE_TYPE_NEW, QUEUE_TYPE_REV
|
||||
from anki.decks import DeckConfigDict, DeckId, DeckTreeNode
|
||||
from anki.notes import Note
|
||||
from anki.notes import NoteId
|
||||
from anki.utils import ids2str, intTime
|
||||
|
||||
CongratsInfo = _pb.CongratsInfoOut
|
||||
|
@ -123,20 +123,31 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l
|
|||
) -> None:
|
||||
self.col._backend.unbury_cards_in_current_deck(mode)
|
||||
|
||||
def suspend_cards(self, ids: Sequence[CardId]) -> OpChanges:
|
||||
def suspend_cards(self, ids: Sequence[CardId]) -> OpChangesWithCount:
|
||||
return self.col._backend.bury_or_suspend_cards(
|
||||
card_ids=ids, mode=BuryOrSuspend.SUSPEND
|
||||
card_ids=ids, note_ids=[], mode=BuryOrSuspend.SUSPEND
|
||||
)
|
||||
|
||||
def bury_cards(self, ids: Sequence[CardId], manual: bool = True) -> OpChanges:
|
||||
def suspend_notes(self, ids: Sequence[NoteId]) -> OpChangesWithCount:
|
||||
return self.col._backend.bury_or_suspend_cards(
|
||||
card_ids=[], note_ids=ids, mode=BuryOrSuspend.SUSPEND
|
||||
)
|
||||
|
||||
def bury_cards(
|
||||
self, ids: Sequence[CardId], manual: bool = True
|
||||
) -> OpChangesWithCount:
|
||||
if manual:
|
||||
mode = BuryOrSuspend.BURY_USER
|
||||
else:
|
||||
mode = BuryOrSuspend.BURY_SCHED
|
||||
return self.col._backend.bury_or_suspend_cards(card_ids=ids, mode=mode)
|
||||
return self.col._backend.bury_or_suspend_cards(
|
||||
card_ids=ids, note_ids=[], mode=mode
|
||||
)
|
||||
|
||||
def bury_note(self, note: Note) -> None:
|
||||
self.bury_cards(note.card_ids())
|
||||
def bury_notes(self, note_ids: Sequence[NoteId]) -> OpChangesWithCount:
|
||||
return self.col._backend.bury_or_suspend_cards(
|
||||
card_ids=[], note_ids=note_ids, mode=BuryOrSuspend.BURY_USER
|
||||
)
|
||||
|
||||
# Resetting/rescheduling
|
||||
##########################################################################
|
||||
|
|
|
@ -501,7 +501,7 @@ def test_misc():
|
|||
col.addNote(note)
|
||||
c = note.cards()[0]
|
||||
# burying
|
||||
col.sched.bury_note(note)
|
||||
col.sched.bury_notes([note.id])
|
||||
col.reset()
|
||||
assert not col.sched.getCard()
|
||||
col.sched.unbury_cards_in_current_deck()
|
||||
|
|
|
@ -732,9 +732,9 @@ where id in %s"""
|
|||
def suspend_selected_cards(self, checked: bool) -> None:
|
||||
cids = self.selected_cards()
|
||||
if checked:
|
||||
suspend_cards(mw=self.mw, card_ids=cids)
|
||||
suspend_cards(parent=self, card_ids=cids).run_in_background()
|
||||
else:
|
||||
unsuspend_cards(mw=self.mw, card_ids=cids)
|
||||
unsuspend_cards(parent=self.mw, card_ids=cids).run_in_background()
|
||||
|
||||
# Exporting
|
||||
######################################################################
|
||||
|
@ -796,25 +796,23 @@ where id in %s"""
|
|||
return
|
||||
|
||||
reposition_new_cards_dialog(
|
||||
mw=self.mw, parent=self, card_ids=self.selected_cards()
|
||||
)
|
||||
parent=self, card_ids=self.selected_cards()
|
||||
).run_in_background()
|
||||
|
||||
@ensure_editor_saved_on_trigger
|
||||
def set_due_date(self) -> None:
|
||||
set_due_date_dialog(
|
||||
mw=self.mw,
|
||||
parent=self,
|
||||
card_ids=self.selected_cards(),
|
||||
config_key=Config.String.SET_DUE_BROWSER,
|
||||
)
|
||||
).run_in_background()
|
||||
|
||||
@ensure_editor_saved_on_trigger
|
||||
def forget_cards(self) -> None:
|
||||
forget_cards(
|
||||
mw=self.mw,
|
||||
parent=self,
|
||||
card_ids=self.selected_cards(),
|
||||
)
|
||||
).run_in_background()
|
||||
|
||||
# Edit: selection
|
||||
######################################################################
|
||||
|
|
|
@ -310,7 +310,9 @@ class FilteredDeckConfigDialog(QDialog):
|
|||
|
||||
gui_hooks.filtered_deck_dialog_will_add_or_update_deck(self, self.deck)
|
||||
|
||||
add_or_update_filtered_deck(mw=self.mw, deck=self.deck, success=success)
|
||||
add_or_update_filtered_deck(parent=self, deck=self.deck).success(
|
||||
success
|
||||
).run_in_background()
|
||||
|
||||
# Step load/save
|
||||
########################################################
|
||||
|
|
|
@ -7,28 +7,32 @@ from typing import Optional, Sequence
|
|||
|
||||
import aqt
|
||||
from anki.cards import CardId
|
||||
from anki.collection import CARD_TYPE_NEW, Config
|
||||
from anki.collection import (
|
||||
CARD_TYPE_NEW,
|
||||
Config,
|
||||
OpChanges,
|
||||
OpChangesWithCount,
|
||||
OpChangesWithId,
|
||||
)
|
||||
from anki.decks import DeckId
|
||||
from anki.notes import NoteId
|
||||
from anki.scheduler import FilteredDeckForUpdate
|
||||
from aqt import AnkiQt
|
||||
from aqt.main import PerformOpOptionalSuccessCallback
|
||||
from aqt.operations import CollectionOp
|
||||
from aqt.qt import *
|
||||
from aqt.utils import disable_help_button, getText, tooltip, tr
|
||||
|
||||
|
||||
def set_due_date_dialog(
|
||||
*,
|
||||
mw: aqt.AnkiQt,
|
||||
parent: QWidget,
|
||||
card_ids: Sequence[CardId],
|
||||
config_key: Optional[Config.String.Key.V],
|
||||
) -> None:
|
||||
) -> Optional[CollectionOp[OpChanges]]:
|
||||
if not card_ids:
|
||||
return
|
||||
return None
|
||||
|
||||
default_text = (
|
||||
mw.col.get_config_string(config_key) if config_key is not None else ""
|
||||
aqt.mw.col.get_config_string(config_key) if config_key is not None else ""
|
||||
)
|
||||
prompt = "\n".join(
|
||||
[
|
||||
|
@ -43,34 +47,35 @@ def set_due_date_dialog(
|
|||
title=tr.actions_set_due_date(),
|
||||
)
|
||||
if not success or not days.strip():
|
||||
return
|
||||
|
||||
mw.perform_op(
|
||||
lambda: mw.col.sched.set_due_date(card_ids, days, config_key),
|
||||
success=lambda _: tooltip(
|
||||
tr.scheduling_set_due_date_done(cards=len(card_ids)),
|
||||
parent=parent,
|
||||
),
|
||||
)
|
||||
return None
|
||||
else:
|
||||
return CollectionOp(
|
||||
parent, lambda col: col.sched.set_due_date(card_ids, days, config_key)
|
||||
).success(
|
||||
lambda _: tooltip(
|
||||
tr.scheduling_set_due_date_done(cards=len(card_ids)),
|
||||
parent=parent,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def forget_cards(
|
||||
*, mw: aqt.AnkiQt, parent: QWidget, card_ids: Sequence[CardId]
|
||||
) -> None:
|
||||
if not card_ids:
|
||||
return
|
||||
|
||||
mw.perform_op(
|
||||
lambda: mw.col.sched.schedule_cards_as_new(card_ids),
|
||||
success=lambda _: tooltip(
|
||||
*, parent: QWidget, card_ids: Sequence[CardId]
|
||||
) -> CollectionOp[OpChanges]:
|
||||
return CollectionOp(
|
||||
parent, lambda col: col.sched.schedule_cards_as_new(card_ids)
|
||||
).success(
|
||||
lambda _: tooltip(
|
||||
tr.scheduling_forgot_cards(cards=len(card_ids)), parent=parent
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def reposition_new_cards_dialog(
|
||||
*, mw: AnkiQt, parent: QWidget, card_ids: Sequence[CardId]
|
||||
) -> None:
|
||||
*, parent: QWidget, card_ids: Sequence[CardId]
|
||||
) -> Optional[CollectionOp[OpChangesWithCount]]:
|
||||
from aqt import mw
|
||||
|
||||
assert mw.col.db
|
||||
row = mw.col.db.first(
|
||||
f"select min(due), max(due) from cards where type={CARD_TYPE_NEW} and odid=0"
|
||||
|
@ -92,15 +97,14 @@ def reposition_new_cards_dialog(
|
|||
|
||||
frm.start.selectAll()
|
||||
if not d.exec_():
|
||||
return
|
||||
return None
|
||||
|
||||
start = frm.start.value()
|
||||
step = frm.step.value()
|
||||
randomize = frm.randomize.isChecked()
|
||||
shift = frm.shift.isChecked()
|
||||
|
||||
reposition_new_cards(
|
||||
mw=mw,
|
||||
return reposition_new_cards(
|
||||
parent=parent,
|
||||
card_ids=card_ids,
|
||||
starting_from=start,
|
||||
|
@ -112,89 +116,80 @@ def reposition_new_cards_dialog(
|
|||
|
||||
def reposition_new_cards(
|
||||
*,
|
||||
mw: AnkiQt,
|
||||
parent: QWidget,
|
||||
card_ids: Sequence[CardId],
|
||||
starting_from: int,
|
||||
step_size: int,
|
||||
randomize: bool,
|
||||
shift_existing: bool,
|
||||
) -> None:
|
||||
mw.perform_op(
|
||||
lambda: mw.col.sched.reposition_new_cards(
|
||||
) -> CollectionOp[OpChangesWithCount]:
|
||||
return CollectionOp(
|
||||
parent,
|
||||
lambda col: col.sched.reposition_new_cards(
|
||||
card_ids=card_ids,
|
||||
starting_from=starting_from,
|
||||
step_size=step_size,
|
||||
randomize=randomize,
|
||||
shift_existing=shift_existing,
|
||||
),
|
||||
success=lambda out: tooltip(
|
||||
).success(
|
||||
lambda out: tooltip(
|
||||
tr.browsing_changed_new_position(count=out.count), parent=parent
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def suspend_cards(
|
||||
*,
|
||||
mw: AnkiQt,
|
||||
parent: QWidget,
|
||||
card_ids: Sequence[CardId],
|
||||
success: PerformOpOptionalSuccessCallback = None,
|
||||
) -> None:
|
||||
mw.perform_op(lambda: mw.col.sched.suspend_cards(card_ids), success=success)
|
||||
) -> CollectionOp[OpChangesWithCount]:
|
||||
return CollectionOp(parent, lambda col: col.sched.suspend_cards(card_ids))
|
||||
|
||||
|
||||
def suspend_note(
|
||||
*,
|
||||
mw: AnkiQt,
|
||||
note_id: NoteId,
|
||||
success: PerformOpOptionalSuccessCallback = None,
|
||||
) -> None:
|
||||
mw.taskman.run_in_background(
|
||||
lambda: mw.col.card_ids_of_note(note_id),
|
||||
lambda future: suspend_cards(mw=mw, card_ids=future.result(), success=success),
|
||||
)
|
||||
parent: QWidget,
|
||||
note_ids: Sequence[NoteId],
|
||||
) -> CollectionOp[OpChangesWithCount]:
|
||||
return CollectionOp(parent, lambda col: col.sched.suspend_notes(note_ids))
|
||||
|
||||
|
||||
def unsuspend_cards(*, mw: AnkiQt, card_ids: Sequence[CardId]) -> None:
|
||||
mw.perform_op(lambda: mw.col.sched.unsuspend_cards(card_ids))
|
||||
def unsuspend_cards(
|
||||
*, parent: QWidget, card_ids: Sequence[CardId]
|
||||
) -> CollectionOp[OpChanges]:
|
||||
return CollectionOp(parent, lambda col: col.sched.unsuspend_cards(card_ids))
|
||||
|
||||
|
||||
def bury_cards(
|
||||
*,
|
||||
mw: AnkiQt,
|
||||
parent: QWidget,
|
||||
card_ids: Sequence[CardId],
|
||||
success: PerformOpOptionalSuccessCallback = None,
|
||||
) -> None:
|
||||
mw.perform_op(lambda: mw.col.sched.bury_cards(card_ids), success=success)
|
||||
) -> CollectionOp[OpChangesWithCount]:
|
||||
return CollectionOp(parent, lambda col: col.sched.bury_cards(card_ids))
|
||||
|
||||
|
||||
def bury_note(
|
||||
def bury_notes(
|
||||
*,
|
||||
mw: AnkiQt,
|
||||
note_id: NoteId,
|
||||
success: PerformOpOptionalSuccessCallback = None,
|
||||
) -> None:
|
||||
mw.taskman.run_in_background(
|
||||
lambda: mw.col.card_ids_of_note(note_id),
|
||||
lambda future: bury_cards(mw=mw, card_ids=future.result(), success=success),
|
||||
)
|
||||
parent: QWidget,
|
||||
note_ids: Sequence[NoteId],
|
||||
) -> CollectionOp[OpChangesWithCount]:
|
||||
return CollectionOp(parent, lambda col: col.sched.bury_notes(note_ids))
|
||||
|
||||
|
||||
def rebuild_filtered_deck(*, mw: AnkiQt, deck_id: DeckId) -> None:
|
||||
mw.perform_op(lambda: mw.col.sched.rebuild_filtered_deck(deck_id))
|
||||
def rebuild_filtered_deck(
|
||||
*, parent: QWidget, deck_id: DeckId
|
||||
) -> CollectionOp[OpChangesWithCount]:
|
||||
return CollectionOp(parent, lambda col: col.sched.rebuild_filtered_deck(deck_id))
|
||||
|
||||
|
||||
def empty_filtered_deck(*, mw: AnkiQt, deck_id: DeckId) -> None:
|
||||
mw.perform_op(lambda: mw.col.sched.empty_filtered_deck(deck_id))
|
||||
def empty_filtered_deck(*, parent: QWidget, deck_id: DeckId) -> CollectionOp[OpChanges]:
|
||||
return CollectionOp(parent, lambda col: col.sched.empty_filtered_deck(deck_id))
|
||||
|
||||
|
||||
def add_or_update_filtered_deck(
|
||||
*,
|
||||
mw: AnkiQt,
|
||||
parent: QWidget,
|
||||
deck: FilteredDeckForUpdate,
|
||||
success: PerformOpOptionalSuccessCallback,
|
||||
) -> None:
|
||||
mw.perform_op(
|
||||
lambda: mw.col.sched.add_or_update_filtered_deck(deck),
|
||||
success=success,
|
||||
)
|
||||
) -> CollectionOp[OpChangesWithId]:
|
||||
return CollectionOp(parent, lambda col: col.sched.add_or_update_filtered_deck(deck))
|
||||
|
|
|
@ -119,12 +119,14 @@ class Overview:
|
|||
return self.mw.col.decks.current()["dyn"]
|
||||
|
||||
def rebuild_current_filtered_deck(self) -> None:
|
||||
if self._current_deck_is_filtered():
|
||||
rebuild_filtered_deck(mw=self.mw, deck_id=self.mw.col.decks.selected())
|
||||
rebuild_filtered_deck(
|
||||
parent=self.mw, deck_id=self.mw.col.decks.selected()
|
||||
).run_in_background()
|
||||
|
||||
def empty_current_filtered_deck(self) -> None:
|
||||
if self._current_deck_is_filtered():
|
||||
empty_filtered_deck(mw=self.mw, deck_id=self.mw.col.decks.selected())
|
||||
empty_filtered_deck(
|
||||
parent=self.mw, deck_id=self.mw.col.decks.selected()
|
||||
).run_in_background()
|
||||
|
||||
def onCustomStudyKey(self) -> None:
|
||||
if not self._current_deck_is_filtered():
|
||||
|
|
|
@ -22,7 +22,7 @@ from aqt.operations.card import set_card_flag
|
|||
from aqt.operations.note import remove_notes
|
||||
from aqt.operations.scheduling import (
|
||||
bury_cards,
|
||||
bury_note,
|
||||
bury_notes,
|
||||
set_due_date_dialog,
|
||||
suspend_cards,
|
||||
suspend_note,
|
||||
|
@ -861,39 +861,34 @@ time = %(time)d;
|
|||
return
|
||||
|
||||
set_due_date_dialog(
|
||||
mw=self.mw,
|
||||
parent=self.mw,
|
||||
card_ids=[self.card.id],
|
||||
config_key=Config.String.SET_DUE_REVIEWER,
|
||||
)
|
||||
).run_in_background()
|
||||
|
||||
def suspend_current_note(self) -> None:
|
||||
suspend_note(
|
||||
mw=self.mw,
|
||||
note_id=self.card.nid,
|
||||
success=lambda _: tooltip(tr.studying_note_suspended()),
|
||||
)
|
||||
parent=self.mw,
|
||||
note_ids=[self.card.nid],
|
||||
).success(lambda _: tooltip(tr.studying_note_suspended())).run_in_background()
|
||||
|
||||
def suspend_current_card(self) -> None:
|
||||
suspend_cards(
|
||||
mw=self.mw,
|
||||
parent=self.mw,
|
||||
card_ids=[self.card.id],
|
||||
success=lambda _: tooltip(tr.studying_card_suspended()),
|
||||
)
|
||||
).success(lambda _: tooltip(tr.studying_card_suspended())).run_in_background()
|
||||
|
||||
def bury_current_note(self) -> None:
|
||||
bury_note(
|
||||
mw=self.mw,
|
||||
note_id=self.card.nid,
|
||||
success=lambda _: tooltip(tr.studying_note_buried()),
|
||||
)
|
||||
bury_notes(
|
||||
parent=self.mw,
|
||||
note_ids=[self.card.nid],
|
||||
).success(lambda _: tooltip(tr.studying_note_buried())).run_in_background()
|
||||
|
||||
def bury_current_card(self) -> None:
|
||||
bury_cards(
|
||||
mw=self.mw,
|
||||
parent=self.mw,
|
||||
card_ids=[self.card.id],
|
||||
success=lambda _: tooltip(tr.studying_card_buried()),
|
||||
)
|
||||
).success(lambda _: tooltip(tr.studying_card_buried())).run_in_background()
|
||||
|
||||
def delete_current_note(self) -> None:
|
||||
# need to check state because the shortcut is global to the main
|
||||
|
|
|
@ -120,7 +120,7 @@ service SchedulingService {
|
|||
rpc CongratsInfo(Empty) returns (CongratsInfoOut);
|
||||
rpc RestoreBuriedAndSuspendedCards(CardIds) returns (OpChanges);
|
||||
rpc UnburyCardsInCurrentDeck(UnburyCardsInCurrentDeckIn) returns (Empty);
|
||||
rpc BuryOrSuspendCards(BuryOrSuspendCardsIn) returns (OpChanges);
|
||||
rpc BuryOrSuspendCards(BuryOrSuspendCardsIn) returns (OpChangesWithCount);
|
||||
rpc EmptyFilteredDeck(DeckId) returns (OpChanges);
|
||||
rpc RebuildFilteredDeck(DeckId) returns (OpChangesWithCount);
|
||||
rpc ScheduleCardsAsNew(ScheduleCardsAsNewIn) returns (OpChanges);
|
||||
|
@ -1314,7 +1314,8 @@ message BuryOrSuspendCardsIn {
|
|||
BURY_USER = 2;
|
||||
}
|
||||
repeated int64 card_ids = 1;
|
||||
Mode mode = 2;
|
||||
repeated int64 note_ids = 2;
|
||||
Mode mode = 3;
|
||||
}
|
||||
|
||||
message ScheduleCardsAsNewIn {
|
||||
|
|
|
@ -131,7 +131,7 @@ impl NotesService for Backend {
|
|||
fn cards_of_note(&self, input: pb::NoteId) -> Result<pb::CardIds> {
|
||||
self.with_col(|col| {
|
||||
col.storage
|
||||
.all_card_ids_of_note(NoteId(input.nid))
|
||||
.all_card_ids_of_note_in_order(NoteId(input.nid))
|
||||
.map(|v| pb::CardIds {
|
||||
cids: v.into_iter().map(Into::into).collect(),
|
||||
})
|
||||
|
|
|
@ -87,10 +87,18 @@ impl SchedulingService for Backend {
|
|||
})
|
||||
}
|
||||
|
||||
fn bury_or_suspend_cards(&self, input: pb::BuryOrSuspendCardsIn) -> Result<pb::OpChanges> {
|
||||
fn bury_or_suspend_cards(
|
||||
&self,
|
||||
input: pb::BuryOrSuspendCardsIn,
|
||||
) -> Result<pb::OpChangesWithCount> {
|
||||
self.with_col(|col| {
|
||||
let mode = input.mode();
|
||||
let cids: Vec<_> = input.card_ids.into_iter().map(CardId).collect();
|
||||
let cids = if input.card_ids.is_empty() {
|
||||
col.storage
|
||||
.card_ids_of_notes(&input.note_ids.into_newtype(NoteId))?
|
||||
} else {
|
||||
input.card_ids.into_newtype(CardId)
|
||||
};
|
||||
col.bury_or_suspend_cards(&cids, mode).map(Into::into)
|
||||
})
|
||||
}
|
||||
|
@ -105,7 +113,7 @@ impl SchedulingService for Backend {
|
|||
|
||||
fn schedule_cards_as_new(&self, input: pb::ScheduleCardsAsNewIn) -> Result<pb::OpChanges> {
|
||||
self.with_col(|col| {
|
||||
let cids: Vec<_> = input.card_ids.into_iter().map(CardId).collect();
|
||||
let cids = input.card_ids.into_newtype(CardId);
|
||||
let log = input.log;
|
||||
col.reschedule_cards_as_new(&cids, log).map(Into::into)
|
||||
})
|
||||
|
@ -114,12 +122,12 @@ impl SchedulingService for Backend {
|
|||
fn set_due_date(&self, input: pb::SetDueDateIn) -> Result<pb::OpChanges> {
|
||||
let config = input.config_key.map(Into::into);
|
||||
let days = input.days;
|
||||
let cids: Vec<_> = input.card_ids.into_iter().map(CardId).collect();
|
||||
let cids = input.card_ids.into_newtype(CardId);
|
||||
self.with_col(|col| col.set_due_date(&cids, &days, config).map(Into::into))
|
||||
}
|
||||
|
||||
fn sort_cards(&self, input: pb::SortCardsIn) -> Result<pb::OpChangesWithCount> {
|
||||
let cids: Vec<_> = input.card_ids.into_iter().map(CardId).collect();
|
||||
let cids = input.card_ids.into_newtype(CardId);
|
||||
let (start, step, random, shift) = (
|
||||
input.starting_from,
|
||||
input.step_size,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
pub(crate) use crate::types::IntoNewtypeVec;
|
||||
pub use crate::{
|
||||
card::{Card, CardId},
|
||||
collection::Collection,
|
||||
|
|
|
@ -33,7 +33,7 @@ mod test {
|
|||
let queued = col.next_card()?.unwrap();
|
||||
let nid = note.id;
|
||||
let cid = queued.card.id;
|
||||
let sibling_cid = col.storage.all_card_ids_of_note(nid)?[1];
|
||||
let sibling_cid = col.storage.all_card_ids_of_note_in_order(nid)?[1];
|
||||
|
||||
let assert_initial_state = |col: &mut Collection| -> Result<()> {
|
||||
let first = col.storage.get_card(cid)?.unwrap();
|
||||
|
|
|
@ -89,7 +89,8 @@ impl Collection {
|
|||
|
||||
/// Bury/suspend cards in search table, and clear it.
|
||||
/// Marks the cards as modified.
|
||||
fn bury_or_suspend_searched_cards(&mut self, mode: BuryOrSuspendMode) -> Result<()> {
|
||||
fn bury_or_suspend_searched_cards(&mut self, mode: BuryOrSuspendMode) -> Result<usize> {
|
||||
let mut count = 0;
|
||||
let usn = self.usn()?;
|
||||
let sched = self.scheduler_version();
|
||||
|
||||
|
@ -113,18 +114,21 @@ impl Collection {
|
|||
card.remove_from_learning();
|
||||
}
|
||||
card.queue = desired_queue;
|
||||
count += 1;
|
||||
self.update_card_inner(&mut card, original, usn)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.storage.clear_searched_cards_table()
|
||||
self.storage.clear_searched_cards_table()?;
|
||||
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
pub fn bury_or_suspend_cards(
|
||||
&mut self,
|
||||
cids: &[CardId],
|
||||
mode: BuryOrSuspendMode,
|
||||
) -> Result<OpOutput<()>> {
|
||||
) -> Result<OpOutput<usize>> {
|
||||
let op = match mode {
|
||||
BuryOrSuspendMode::Suspend => Op::Suspend,
|
||||
BuryOrSuspendMode::BurySched | BuryOrSuspendMode::BuryUser => Op::Bury,
|
||||
|
@ -141,7 +145,7 @@ impl Collection {
|
|||
nid: NoteId,
|
||||
include_new: bool,
|
||||
include_reviews: bool,
|
||||
) -> Result<()> {
|
||||
) -> Result<usize> {
|
||||
self.storage
|
||||
.search_siblings_for_bury(cid, nid, include_new, include_reviews)?;
|
||||
self.bury_or_suspend_searched_cards(BuryOrSuspendMode::BurySched)
|
||||
|
|
|
@ -308,13 +308,26 @@ impl super::SqliteStorage {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn all_card_ids_of_note(&self, nid: NoteId) -> Result<Vec<CardId>> {
|
||||
pub(crate) fn all_card_ids_of_note_in_order(&self, nid: NoteId) -> Result<Vec<CardId>> {
|
||||
self.db
|
||||
.prepare_cached("select id from cards where nid = ? order by ord")?
|
||||
.query_and_then(&[nid], |r| Ok(CardId(r.get(0)?)))?
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn card_ids_of_notes(&self, nids: &[NoteId]) -> Result<Vec<CardId>> {
|
||||
let mut stmt = self
|
||||
.db
|
||||
.prepare_cached("select id from cards where nid = ?")?;
|
||||
let mut cids = vec![];
|
||||
for nid in nids {
|
||||
for cid in stmt.query_map(&[nid], |row| row.get(0))? {
|
||||
cids.push(cid?);
|
||||
}
|
||||
}
|
||||
Ok(cids)
|
||||
}
|
||||
|
||||
/// Place matching card ids into the search table.
|
||||
pub(crate) fn search_siblings_for_bury(
|
||||
&self,
|
||||
|
|
|
@ -68,3 +68,18 @@ macro_rules! define_newtype {
|
|||
}
|
||||
|
||||
define_newtype!(Usn, i32);
|
||||
|
||||
pub(crate) trait IntoNewtypeVec {
|
||||
fn into_newtype<F, T>(self, func: F) -> Vec<T>
|
||||
where
|
||||
F: FnMut(i64) -> T;
|
||||
}
|
||||
|
||||
impl IntoNewtypeVec for Vec<i64> {
|
||||
fn into_newtype<F, T>(self, func: F) -> Vec<T>
|
||||
where
|
||||
F: FnMut(i64) -> T,
|
||||
{
|
||||
self.into_iter().map(func).collect()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue