mirror of
https://github.com/ankitects/anki.git
synced 2025-12-12 14:26:55 -05:00
add daily count updating to backend
This commit is contained in:
parent
fee6cdff22
commit
1fe18718f7
10 changed files with 231 additions and 40 deletions
|
|
@ -93,6 +93,9 @@ service BackendService {
|
||||||
rpc SchedTimingToday (Empty) returns (SchedTimingTodayOut);
|
rpc SchedTimingToday (Empty) returns (SchedTimingTodayOut);
|
||||||
rpc StudiedToday (StudiedTodayIn) returns (String);
|
rpc StudiedToday (StudiedTodayIn) returns (String);
|
||||||
rpc CongratsLearnMessage (CongratsLearnMessageIn) returns (String);
|
rpc CongratsLearnMessage (CongratsLearnMessageIn) returns (String);
|
||||||
|
rpc UpdateStats (UpdateStatsIn) returns (Empty);
|
||||||
|
rpc ExtendLimits (ExtendLimitsIn) returns (Empty);
|
||||||
|
rpc CountsForDeckToday (DeckID) returns (CountsForDeckTodayOut);
|
||||||
|
|
||||||
// media
|
// media
|
||||||
|
|
||||||
|
|
@ -250,8 +253,11 @@ message DeckCommon {
|
||||||
uint32 last_day_studied = 3;
|
uint32 last_day_studied = 3;
|
||||||
int32 new_studied = 4;
|
int32 new_studied = 4;
|
||||||
int32 review_studied = 5;
|
int32 review_studied = 5;
|
||||||
|
int32 milliseconds_studied = 7;
|
||||||
|
|
||||||
|
// previously set in the v1 scheduler,
|
||||||
|
// but not currently used for anything
|
||||||
int32 learning_studied = 6;
|
int32 learning_studied = 6;
|
||||||
int32 secs_studied = 7;
|
|
||||||
|
|
||||||
bytes other = 255;
|
bytes other = 255;
|
||||||
}
|
}
|
||||||
|
|
@ -945,3 +951,21 @@ message RemoveNotesIn {
|
||||||
message RemoveCardsIn {
|
message RemoveCardsIn {
|
||||||
repeated int64 card_ids = 1;
|
repeated int64 card_ids = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message UpdateStatsIn {
|
||||||
|
int64 deck_id = 1;
|
||||||
|
int32 new_delta = 2;
|
||||||
|
int32 review_delta = 4;
|
||||||
|
int32 millisecond_delta = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ExtendLimitsIn {
|
||||||
|
int64 deck_id = 1;
|
||||||
|
int32 new_delta = 2;
|
||||||
|
int32 review_delta = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CountsForDeckTodayOut {
|
||||||
|
int32 new = 1;
|
||||||
|
int32 review = 2;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ StockNoteType = pb.StockNoteType
|
||||||
SyncAuth = pb.SyncAuth
|
SyncAuth = pb.SyncAuth
|
||||||
SyncOutput = pb.SyncCollectionOut
|
SyncOutput = pb.SyncCollectionOut
|
||||||
SyncStatus = pb.SyncStatusOut
|
SyncStatus = pb.SyncStatusOut
|
||||||
|
CountsForDeckToday = pb.CountsForDeckTodayOut
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import orjson
|
import orjson
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@ class Scheduler(V2):
|
||||||
# former is for logging new cards, latter also covers filt. decks
|
# former is for logging new cards, latter also covers filt. decks
|
||||||
card.wasNew = card.type == CARD_TYPE_NEW # type: ignore
|
card.wasNew = card.type == CARD_TYPE_NEW # type: ignore
|
||||||
wasNewQ = card.queue == QUEUE_TYPE_NEW
|
wasNewQ = card.queue == QUEUE_TYPE_NEW
|
||||||
|
|
||||||
|
new_delta = 0
|
||||||
|
review_delta = 0
|
||||||
|
|
||||||
if wasNewQ:
|
if wasNewQ:
|
||||||
# came from the new queue, move to learning
|
# came from the new queue, move to learning
|
||||||
card.queue = QUEUE_TYPE_LRN
|
card.queue = QUEUE_TYPE_LRN
|
||||||
|
|
@ -65,17 +69,22 @@ class Scheduler(V2):
|
||||||
# reviews get their ivl boosted on first sight
|
# reviews get their ivl boosted on first sight
|
||||||
card.ivl = self._dynIvlBoost(card)
|
card.ivl = self._dynIvlBoost(card)
|
||||||
card.odue = self.today + card.ivl
|
card.odue = self.today + card.ivl
|
||||||
self._updateStats(card, "new")
|
new_delta = +1
|
||||||
if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
||||||
self._answerLrnCard(card, ease)
|
self._answerLrnCard(card, ease)
|
||||||
if not wasNewQ:
|
|
||||||
self._updateStats(card, "lrn")
|
|
||||||
elif card.queue == QUEUE_TYPE_REV:
|
elif card.queue == QUEUE_TYPE_REV:
|
||||||
self._answerRevCard(card, ease)
|
self._answerRevCard(card, ease)
|
||||||
self._updateStats(card, "rev")
|
review_delta = +1
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid queue '%s'" % card)
|
raise Exception("Invalid queue '%s'" % card)
|
||||||
self._updateStats(card, "time", card.timeTaken())
|
|
||||||
|
self.update_stats(
|
||||||
|
card.did,
|
||||||
|
new_delta=new_delta,
|
||||||
|
review_delta=review_delta,
|
||||||
|
milliseconds_delta=+card.timeTaken(),
|
||||||
|
)
|
||||||
|
|
||||||
card.mod = intTime()
|
card.mod = intTime()
|
||||||
card.usn = self.col.usn()
|
card.usn = self.col.usn()
|
||||||
card.flush()
|
card.flush()
|
||||||
|
|
@ -447,7 +456,7 @@ and due <= ? limit ?)""",
|
||||||
if d["dyn"]:
|
if d["dyn"]:
|
||||||
return self.reportLimit
|
return self.reportLimit
|
||||||
c = self.col.decks.confForDid(d["id"])
|
c = self.col.decks.confForDid(d["id"])
|
||||||
limit = max(0, c["rev"]["perDay"] - self._update_stats(d, "rev", 0))
|
limit = max(0, c["rev"]["perDay"] - self.counts_for_deck_today(d["id"]).review)
|
||||||
return hooks.scheduler_review_limit_for_single_deck(limit, d)
|
return hooks.scheduler_review_limit_for_single_deck(limit, d)
|
||||||
|
|
||||||
def _revForDeck(self, did: int, lim: int) -> int: # type: ignore[override]
|
def _revForDeck(self, did: int, lim: int) -> int: # type: ignore[override]
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,12 @@ from anki import hooks
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.lang import _
|
from anki.lang import _
|
||||||
from anki.rsbackend import DeckTreeNode, FormatTimeSpanContext, SchedTimingToday
|
from anki.rsbackend import (
|
||||||
|
CountsForDeckToday,
|
||||||
|
DeckTreeNode,
|
||||||
|
FormatTimeSpanContext,
|
||||||
|
SchedTimingToday,
|
||||||
|
)
|
||||||
from anki.utils import ids2str, intTime
|
from anki.utils import ids2str, intTime
|
||||||
|
|
||||||
# card types: 0=new, 1=lrn, 2=rev, 3=relrn
|
# card types: 0=new, 1=lrn, 2=rev, 3=relrn
|
||||||
|
|
@ -82,7 +87,6 @@ class Scheduler:
|
||||||
|
|
||||||
self._answerCard(card, ease)
|
self._answerCard(card, ease)
|
||||||
|
|
||||||
self._updateStats(card, "time", card.timeTaken())
|
|
||||||
card.mod = intTime()
|
card.mod = intTime()
|
||||||
card.usn = self.col.usn()
|
card.usn = self.col.usn()
|
||||||
card.flush()
|
card.flush()
|
||||||
|
|
@ -94,24 +98,32 @@ class Scheduler:
|
||||||
|
|
||||||
card.reps += 1
|
card.reps += 1
|
||||||
|
|
||||||
|
new_delta = 0
|
||||||
|
review_delta = 0
|
||||||
|
|
||||||
if card.queue == QUEUE_TYPE_NEW:
|
if card.queue == QUEUE_TYPE_NEW:
|
||||||
# came from the new queue, move to learning
|
# came from the new queue, move to learning
|
||||||
card.queue = QUEUE_TYPE_LRN
|
card.queue = QUEUE_TYPE_LRN
|
||||||
card.type = CARD_TYPE_LRN
|
card.type = CARD_TYPE_LRN
|
||||||
# init reps to graduation
|
# init reps to graduation
|
||||||
card.left = self._startingLeft(card)
|
card.left = self._startingLeft(card)
|
||||||
# update daily limit
|
new_delta = +1
|
||||||
self._updateStats(card, "new")
|
|
||||||
|
|
||||||
if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
if card.queue in (QUEUE_TYPE_LRN, QUEUE_TYPE_DAY_LEARN_RELEARN):
|
||||||
self._answerLrnCard(card, ease)
|
self._answerLrnCard(card, ease)
|
||||||
elif card.queue == QUEUE_TYPE_REV:
|
elif card.queue == QUEUE_TYPE_REV:
|
||||||
self._answerRevCard(card, ease)
|
self._answerRevCard(card, ease)
|
||||||
# update daily limit
|
review_delta = +1
|
||||||
self._updateStats(card, "rev")
|
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid queue '%s'" % card)
|
raise Exception("Invalid queue '%s'" % card)
|
||||||
|
|
||||||
|
self.update_stats(
|
||||||
|
card.did,
|
||||||
|
new_delta=new_delta,
|
||||||
|
review_delta=review_delta,
|
||||||
|
milliseconds_delta=+card.timeTaken(),
|
||||||
|
)
|
||||||
|
|
||||||
# once a card has been answered once, the original due date
|
# once a card has been answered once, the original due date
|
||||||
# no longer applies
|
# no longer applies
|
||||||
if card.odue:
|
if card.odue:
|
||||||
|
|
@ -187,29 +199,33 @@ order by due"""
|
||||||
# Rev/lrn/time daily stats
|
# Rev/lrn/time daily stats
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
def _updateStats(self, card: Card, type: str, cnt: int = 1) -> None:
|
def update_stats(
|
||||||
for g in [self.col.decks.get(card.did)] + self.col.decks.parents(card.did):
|
self, deck_id: int, new_delta=0, review_delta=0, milliseconds_delta=0
|
||||||
self._update_stats(g, type, cnt)
|
):
|
||||||
self.col.decks.save(g)
|
self.col.backend.update_stats(
|
||||||
|
deck_id=deck_id,
|
||||||
|
new_delta=new_delta,
|
||||||
|
review_delta=review_delta,
|
||||||
|
millisecond_delta=milliseconds_delta,
|
||||||
|
)
|
||||||
|
|
||||||
# resets stat if day has changed, applies delta, and returns modified value
|
def counts_for_deck_today(self, deck_id: int) -> CountsForDeckToday:
|
||||||
def _update_stats(self, deck: Dict, type: str, delta: int) -> int:
|
return self.col.backend.counts_for_deck_today(deck_id)
|
||||||
key = type + "Today"
|
|
||||||
if deck[key][0] != self.today:
|
|
||||||
deck[key] = [self.today, 0]
|
|
||||||
deck[key][1] += delta
|
|
||||||
return deck[key][1]
|
|
||||||
|
|
||||||
def extendLimits(self, new: int, rev: int) -> None:
|
def extendLimits(self, new: int, rev: int) -> None:
|
||||||
cur = self.col.decks.current()
|
did = self.col.decks.current()["id"]
|
||||||
parents = self.col.decks.parents(cur["id"])
|
self.col.backend.extend_limits(deck_id=did, new_delta=new, review_delta=rev)
|
||||||
children = [
|
|
||||||
self.col.decks.get(did) for did in self.col.decks.child_ids(cur["name"])
|
# legacy
|
||||||
]
|
|
||||||
for g in [cur] + parents + children:
|
def _updateStats(self, card: Card, type: str, cnt: int = 1) -> None:
|
||||||
self._update_stats(g, "new", -new)
|
did = card.did
|
||||||
self._update_stats(g, "rev", -rev)
|
if type == "new":
|
||||||
self.col.decks.save(g)
|
self.update_stats(did, new_delta=cnt)
|
||||||
|
elif type == "rev":
|
||||||
|
self.update_stats(did, review_delta=cnt)
|
||||||
|
elif type == "time":
|
||||||
|
self.update_stats(did, milliseconds_delta=cnt)
|
||||||
|
|
||||||
# Deck list
|
# Deck list
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
@ -373,7 +389,7 @@ select count() from
|
||||||
if g["dyn"]:
|
if g["dyn"]:
|
||||||
return self.dynReportLimit
|
return self.dynReportLimit
|
||||||
c = self.col.decks.confForDid(g["id"])
|
c = self.col.decks.confForDid(g["id"])
|
||||||
limit = max(0, c["new"]["perDay"] - self._update_stats(g, "new", 0))
|
limit = max(0, c["new"]["perDay"] - self.counts_for_deck_today(g["id"]).new)
|
||||||
return hooks.scheduler_new_limit_for_single_deck(limit, g)
|
return hooks.scheduler_new_limit_for_single_deck(limit, g)
|
||||||
|
|
||||||
def totalNewForCurrentDeck(self) -> int:
|
def totalNewForCurrentDeck(self) -> int:
|
||||||
|
|
@ -766,7 +782,7 @@ and due <= ? limit ?)""",
|
||||||
return self.dynReportLimit
|
return self.dynReportLimit
|
||||||
|
|
||||||
c = self.col.decks.confForDid(d["id"])
|
c = self.col.decks.confForDid(d["id"])
|
||||||
lim = max(0, c["rev"]["perDay"] - self._update_stats(d, "rev", 0))
|
lim = max(0, c["rev"]["perDay"] - self.counts_for_deck_today(d["id"]).review)
|
||||||
|
|
||||||
if parentLimit is not None:
|
if parentLimit is not None:
|
||||||
lim = min(parentLimit, lim)
|
lim = min(parentLimit, lim)
|
||||||
|
|
|
||||||
|
|
@ -467,6 +467,40 @@ impl BackendService for Backend {
|
||||||
Ok(learning_congrats(input.remaining as usize, input.next_due, &self.i18n).into())
|
Ok(learning_congrats(input.remaining as usize, input.next_due, &self.i18n).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_stats(&mut self, input: pb::UpdateStatsIn) -> BackendResult<Empty> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
col.transact(None, |col| {
|
||||||
|
let today = col.current_due_day(0)?;
|
||||||
|
let usn = col.usn()?;
|
||||||
|
col.update_deck_stats(today, usn, input).map(Into::into)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_limits(&mut self, input: pb::ExtendLimitsIn) -> BackendResult<Empty> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
col.transact(None, |col| {
|
||||||
|
let today = col.current_due_day(0)?;
|
||||||
|
let usn = col.usn()?;
|
||||||
|
col.extend_limits(
|
||||||
|
today,
|
||||||
|
usn,
|
||||||
|
input.deck_id.into(),
|
||||||
|
input.new_delta,
|
||||||
|
input.review_delta,
|
||||||
|
)
|
||||||
|
.map(Into::into)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn counts_for_deck_today(
|
||||||
|
&mut self,
|
||||||
|
input: pb::DeckId,
|
||||||
|
) -> BackendResult<pb::CountsForDeckTodayOut> {
|
||||||
|
self.with_col(|col| col.counts_for_deck_today(input.did.into()))
|
||||||
|
}
|
||||||
|
|
||||||
// decks
|
// decks
|
||||||
//-----------------------------------------------
|
//-----------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,17 @@ impl Deck {
|
||||||
kind: DeckKind::Filtered(filt),
|
kind: DeckKind::Filtered(filt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reset_stats_if_day_changed(&mut self, today: u32) {
|
||||||
|
let c = &mut self.common;
|
||||||
|
if c.last_day_studied != today {
|
||||||
|
c.new_studied = 0;
|
||||||
|
c.learning_studied = 0;
|
||||||
|
c.review_studied = 0;
|
||||||
|
c.milliseconds_studied = 0;
|
||||||
|
c.last_day_studied = today;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deck {
|
impl Deck {
|
||||||
|
|
@ -185,7 +196,7 @@ impl From<DeckKind> for pb::deck::Kind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn immediate_parent_name(machine_name: &str) -> Option<&str> {
|
pub(crate) fn immediate_parent_name(machine_name: &str) -> Option<&str> {
|
||||||
machine_name.rsplitn(2, '\x1f').nth(1)
|
machine_name.rsplitn(2, '\x1f').nth(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,6 +476,86 @@ impl Collection {
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply input delta to deck, and its parents.
|
||||||
|
/// Caller should ensure transaction.
|
||||||
|
pub(crate) fn update_deck_stats(
|
||||||
|
&mut self,
|
||||||
|
today: u32,
|
||||||
|
usn: Usn,
|
||||||
|
input: pb::UpdateStatsIn,
|
||||||
|
) -> Result<()> {
|
||||||
|
let did = input.deck_id.into();
|
||||||
|
let mutator = |c: &mut DeckCommon| {
|
||||||
|
c.new_studied += input.new_delta;
|
||||||
|
c.review_studied += input.review_delta;
|
||||||
|
c.milliseconds_studied += input.millisecond_delta;
|
||||||
|
};
|
||||||
|
if let Some(mut deck) = self.storage.get_deck(did)? {
|
||||||
|
self.update_deck_stats_single(today, usn, &mut deck, mutator)?;
|
||||||
|
for mut deck in self.storage.parent_decks(&deck)? {
|
||||||
|
self.update_deck_stats_single(today, usn, &mut deck, mutator)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the deck's limits by adjusting the 'done today' count.
|
||||||
|
/// Positive values increase the limit, negative value decrease it.
|
||||||
|
/// Caller should ensure a transaction.
|
||||||
|
pub(crate) fn extend_limits(
|
||||||
|
&mut self,
|
||||||
|
today: u32,
|
||||||
|
usn: Usn,
|
||||||
|
did: DeckID,
|
||||||
|
new_delta: i32,
|
||||||
|
review_delta: i32,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mutator = |c: &mut DeckCommon| {
|
||||||
|
c.new_studied -= new_delta;
|
||||||
|
c.review_studied -= review_delta;
|
||||||
|
};
|
||||||
|
if let Some(mut deck) = self.storage.get_deck(did)? {
|
||||||
|
self.update_deck_stats_single(today, usn, &mut deck, mutator)?;
|
||||||
|
for mut deck in self.storage.parent_decks(&deck)? {
|
||||||
|
self.update_deck_stats_single(today, usn, &mut deck, mutator)?;
|
||||||
|
}
|
||||||
|
for mut deck in self.storage.child_decks(&deck)? {
|
||||||
|
self.update_deck_stats_single(today, usn, &mut deck, mutator)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn counts_for_deck_today(
|
||||||
|
&mut self,
|
||||||
|
did: DeckID,
|
||||||
|
) -> Result<pb::CountsForDeckTodayOut> {
|
||||||
|
let today = self.current_due_day(0)?;
|
||||||
|
let mut deck = self.storage.get_deck(did)?.ok_or(AnkiError::NotFound)?;
|
||||||
|
deck.reset_stats_if_day_changed(today);
|
||||||
|
Ok(pb::CountsForDeckTodayOut {
|
||||||
|
new: deck.common.new_studied,
|
||||||
|
review: deck.common.review_studied,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_deck_stats_single<F>(
|
||||||
|
&mut self,
|
||||||
|
today: u32,
|
||||||
|
usn: Usn,
|
||||||
|
deck: &mut Deck,
|
||||||
|
mutator: F,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut DeckCommon),
|
||||||
|
{
|
||||||
|
deck.reset_stats_if_day_changed(today);
|
||||||
|
mutator(&mut deck.common);
|
||||||
|
deck.set_modified(usn);
|
||||||
|
self.add_or_update_single_deck(deck, usn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ impl From<&DeckCommonSchema11> for DeckCommon {
|
||||||
new_studied: today.new.amount,
|
new_studied: today.new.amount,
|
||||||
review_studied: today.rev.amount,
|
review_studied: today.rev.amount,
|
||||||
learning_studied: today.lrn.amount,
|
learning_studied: today.lrn.amount,
|
||||||
secs_studied: common.today.time.amount,
|
milliseconds_studied: common.today.time.amount,
|
||||||
other,
|
other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -393,7 +393,7 @@ impl From<&Deck> for DeckTodaySchema11 {
|
||||||
},
|
},
|
||||||
time: TodayAmountSchema11 {
|
time: TodayAmountSchema11 {
|
||||||
day,
|
day,
|
||||||
amount: c.secs_studied,
|
amount: c.milliseconds_studied,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@ use std::{
|
||||||
};
|
};
|
||||||
use unicase::UniCase;
|
use unicase::UniCase;
|
||||||
|
|
||||||
// fixme: handle mixed case of parents
|
|
||||||
|
|
||||||
fn deck_names_to_tree(names: Vec<(DeckID, String)>) -> DeckTreeNode {
|
fn deck_names_to_tree(names: Vec<(DeckID, String)>) -> DeckTreeNode {
|
||||||
let mut top = DeckTreeNode::default();
|
let mut top = DeckTreeNode::default();
|
||||||
let mut it = names.into_iter().peekable();
|
let mut it = names.into_iter().peekable();
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
card::CardID,
|
card::CardID,
|
||||||
card::CardQueue,
|
card::CardQueue,
|
||||||
config::SchedulerVersion,
|
config::SchedulerVersion,
|
||||||
|
decks::immediate_parent_name,
|
||||||
decks::{Deck, DeckCommon, DeckID, DeckKindProto, DeckSchema11, DueCounts},
|
decks::{Deck, DeckCommon, DeckID, DeckKindProto, DeckSchema11, DueCounts},
|
||||||
err::{AnkiError, DBErrorKind, Result},
|
err::{AnkiError, DBErrorKind, Result},
|
||||||
i18n::{I18n, TR},
|
i18n::{I18n, TR},
|
||||||
|
|
@ -152,6 +153,20 @@ impl SqliteStorage {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parent_decks(&self, child: &Deck) -> Result<Vec<Deck>> {
|
||||||
|
let mut decks: Vec<Deck> = vec![];
|
||||||
|
while let Some(parent_name) =
|
||||||
|
immediate_parent_name(decks.last().map(|d| &d.name).unwrap_or_else(|| &child.name))
|
||||||
|
{
|
||||||
|
if let Some(parent_did) = self.get_deck_id(parent_name)? {
|
||||||
|
let parent = self.get_deck(parent_did)?.unwrap();
|
||||||
|
decks.push(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(decks)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn due_counts(
|
pub(crate) fn due_counts(
|
||||||
&self,
|
&self,
|
||||||
sched: SchedulerVersion,
|
sched: SchedulerVersion,
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,9 @@ fn want_release_gil(method: u32) -> bool {
|
||||||
BackendMethod::FullDownload => true,
|
BackendMethod::FullDownload => true,
|
||||||
BackendMethod::RemoveNotes => true,
|
BackendMethod::RemoveNotes => true,
|
||||||
BackendMethod::RemoveCards => true,
|
BackendMethod::RemoveCards => true,
|
||||||
|
BackendMethod::UpdateStats => true,
|
||||||
|
BackendMethod::ExtendLimits => true,
|
||||||
|
BackendMethod::CountsForDeckToday => true,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue