mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
add a separate DeckId search for decks with children
- The "unbury deck" option was broken, as it was ignoring child decks. It would be nice if we could use active_decks instead, but plugging that into the old scheduler without breaking undo seems a bit tricky. - Remove the implicit From impl for decks, so we need to be forced to think about whether we want child decks or not.
This commit is contained in:
parent
b9a4908bfb
commit
b412bf97fb
6 changed files with 47 additions and 15 deletions
|
@ -9,7 +9,7 @@ use crate::{
|
|||
card::CardQueue,
|
||||
config::SchedulerVersion,
|
||||
prelude::*,
|
||||
search::{SortMode, StateKind},
|
||||
search::{SearchNode, SortMode, StateKind},
|
||||
};
|
||||
|
||||
impl Card {
|
||||
|
@ -77,7 +77,10 @@ impl Collection {
|
|||
UnburyDeckMode::SchedOnly => StateKind::SchedBuried,
|
||||
};
|
||||
self.transact(Op::UnburyUnsuspend, |col| {
|
||||
col.search_cards_into_table(match_all![deck_id, state], SortMode::NoOrder)?;
|
||||
col.search_cards_into_table(
|
||||
match_all![SearchNode::DeckIdWithChildren(deck_id), state],
|
||||
SortMode::NoOrder,
|
||||
)?;
|
||||
col.unsuspend_or_unbury_searched_cards()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
card::{CardQueue, CardType},
|
||||
deckconfig::NewCardInsertOrder,
|
||||
prelude::*,
|
||||
search::{SortMode, StateKind},
|
||||
search::{SearchNode, SortMode, StateKind},
|
||||
};
|
||||
|
||||
impl Card {
|
||||
|
@ -186,7 +186,10 @@ impl Collection {
|
|||
order: NewCardInsertOrder,
|
||||
usn: Usn,
|
||||
) -> Result<usize> {
|
||||
let cids = self.search_cards(match_all![deck, StateKind::New], SortMode::NoOrder)?;
|
||||
let cids = self.search_cards(
|
||||
match_all![SearchNode::DeckIdWithoutChildren(deck), StateKind::New],
|
||||
SortMode::NoOrder,
|
||||
)?;
|
||||
self.sort_cards_inner(&cids, 1, 1, order.into(), false, usn)
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,11 @@ pub enum SearchNode {
|
|||
EditedInDays(u32),
|
||||
CardTemplate(TemplateKind),
|
||||
Deck(String),
|
||||
DeckId(DeckId),
|
||||
/// Matches cards in a single deck (original_deck_id is not checked).
|
||||
DeckIdWithoutChildren(DeckId),
|
||||
/// Matches cards in a deck or its children (original_deck_id is not
|
||||
/// checked).
|
||||
DeckIdWithChildren(DeckId),
|
||||
IntroducedInDays(u32),
|
||||
NotetypeId(NotetypeId),
|
||||
Notetype(String),
|
||||
|
@ -197,12 +201,6 @@ impl From<NoteId> for Node {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<DeckId> for Node {
|
||||
fn from(id: DeckId) -> Self {
|
||||
Node::Search(SearchNode::DeckId(id))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StateKind> for Node {
|
||||
fn from(k: StateKind) -> Self {
|
||||
Node::Search(SearchNode::State(k))
|
||||
|
@ -619,7 +617,7 @@ fn parse_state(s: &str) -> ParseResult<SearchNode> {
|
|||
}
|
||||
|
||||
fn parse_did(s: &str) -> ParseResult<SearchNode> {
|
||||
parse_i64(s, "did:").map(|n| SearchNode::DeckId(n.into()))
|
||||
parse_i64(s, "did:").map(|n| SearchNode::DeckIdWithoutChildren(n.into()))
|
||||
}
|
||||
|
||||
fn parse_mid(s: &str) -> ParseResult<SearchNode> {
|
||||
|
|
|
@ -140,9 +140,10 @@ impl SqlWriter<'_> {
|
|||
SearchNode::NotetypeId(ntid) => {
|
||||
write!(self.sql, "n.mid = {}", ntid).unwrap();
|
||||
}
|
||||
SearchNode::DeckId(did) => {
|
||||
SearchNode::DeckIdWithoutChildren(did) => {
|
||||
write!(self.sql, "c.did = {}", did).unwrap();
|
||||
}
|
||||
SearchNode::DeckIdWithChildren(did) => self.write_deck_id_with_children(*did)?,
|
||||
SearchNode::Notetype(notetype) => self.write_notetype(&norm(notetype)),
|
||||
SearchNode::Rated { days, ease } => self.write_rated(">", -i64::from(*days), ease)?,
|
||||
|
||||
|
@ -370,6 +371,19 @@ impl SqlWriter<'_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn write_deck_id_with_children(&mut self, deck_id: DeckId) -> Result<()> {
|
||||
if let Some(parent) = self.col.get_deck(deck_id)? {
|
||||
let ids = self.col.storage.deck_id_with_children(&parent)?;
|
||||
let mut buf = String::new();
|
||||
ids_to_string(&mut buf, &ids);
|
||||
write!(self.sql, "c.did in {}", buf,).unwrap();
|
||||
} else {
|
||||
self.sql.push_str("false")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_template(&mut self, template: &TemplateKind) {
|
||||
match template {
|
||||
TemplateKind::Ordinal(n) => {
|
||||
|
@ -567,7 +581,8 @@ impl SearchNode {
|
|||
SearchNode::AddedInDays(_) => RequiredTable::Cards,
|
||||
SearchNode::IntroducedInDays(_) => RequiredTable::Cards,
|
||||
SearchNode::Deck(_) => RequiredTable::Cards,
|
||||
SearchNode::DeckId(_) => RequiredTable::Cards,
|
||||
SearchNode::DeckIdWithoutChildren(_) => RequiredTable::Cards,
|
||||
SearchNode::DeckIdWithChildren(_) => RequiredTable::Cards,
|
||||
SearchNode::Rated { .. } => RequiredTable::Cards,
|
||||
SearchNode::State(_) => RequiredTable::Cards,
|
||||
SearchNode::Flag(_) => RequiredTable::Cards,
|
||||
|
|
|
@ -87,7 +87,9 @@ fn write_search_node(node: &SearchNode) -> String {
|
|||
IntroducedInDays(u) => format!("introduced:{}", u),
|
||||
CardTemplate(t) => write_template(t),
|
||||
Deck(s) => maybe_quote(&format!("deck:{}", s)),
|
||||
DeckId(DeckIdType(i)) => format!("did:{}", i),
|
||||
DeckIdWithoutChildren(DeckIdType(i)) => format!("did:{}", i),
|
||||
// not exposed on the GUI end
|
||||
DeckIdWithChildren(_) => "".to_string(),
|
||||
NotetypeId(NotetypeIdType(i)) => format!("mid:{}", i),
|
||||
Notetype(s) => maybe_quote(&format!("note:{}", s)),
|
||||
Rated { days, ease } => write_rated(days, ease),
|
||||
|
|
|
@ -207,6 +207,17 @@ impl SqliteStorage {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn deck_id_with_children(&self, parent: &Deck) -> Result<Vec<DeckId>> {
|
||||
let prefix_start = format!("{}\x1f", parent.name);
|
||||
let prefix_end = format!("{}\x20", parent.name);
|
||||
self.db
|
||||
.prepare_cached("select id from decks where id = ? or (name >= ? and name < ?)")?
|
||||
.query_and_then(params![parent.id, prefix_start, prefix_end], |row| {
|
||||
row.get(0).map_err(Into::into)
|
||||
})?
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn deck_with_children(&self, deck_id: DeckId) -> Result<Vec<Deck>> {
|
||||
let deck = self.get_deck(deck_id)?.ok_or(AnkiError::NotFound)?;
|
||||
let prefix_start = format!("{}\x1f", deck.name);
|
||||
|
|
Loading…
Reference in a new issue