mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
Fix 'Expression tree is too large' when user has many decks
+ Allow 'did:' searches to match multiple decks at once
This commit is contained in:
parent
67acdc3034
commit
0e6104a96b
7 changed files with 23 additions and 24 deletions
|
@ -19,6 +19,7 @@ use crate::prelude::*;
|
|||
use crate::scheduler::fsrs::memory_state::UpdateMemoryStateRequest;
|
||||
use crate::search::JoinSearches;
|
||||
use crate::search::SearchNode;
|
||||
use crate::storage::comma_separated_ids;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UpdateDeckConfigsRequest {
|
||||
|
@ -164,7 +165,7 @@ impl Collection {
|
|||
let usn = self.usn()?;
|
||||
let today = self.timing_today()?.days_elapsed;
|
||||
let selected_config = req.configs.last().unwrap();
|
||||
let mut decks_needing_memory_recompute: HashMap<DeckConfigId, Vec<SearchNode>> =
|
||||
let mut decks_needing_memory_recompute: HashMap<DeckConfigId, Vec<DeckId>> =
|
||||
Default::default();
|
||||
let fsrs_toggled = self.get_config_bool(BoolKey::Fsrs) != req.fsrs;
|
||||
if fsrs_toggled {
|
||||
|
@ -216,7 +217,7 @@ impl Collection {
|
|||
decks_needing_memory_recompute
|
||||
.entry(current_config_id)
|
||||
.or_default()
|
||||
.push(SearchNode::DeckIdWithoutChildren(deck_id));
|
||||
.push(deck_id);
|
||||
}
|
||||
|
||||
self.adjust_remaining_steps_in_deck(deck_id, previous_config, current_config, usn)?;
|
||||
|
@ -224,7 +225,7 @@ impl Collection {
|
|||
}
|
||||
|
||||
if !decks_needing_memory_recompute.is_empty() {
|
||||
let input: Vec<(Option<UpdateMemoryStateRequest>, Vec<SearchNode>)> =
|
||||
let input: Vec<(Option<UpdateMemoryStateRequest>, SearchNode)> =
|
||||
decks_needing_memory_recompute
|
||||
.into_iter()
|
||||
.map(|(conf_id, search)| {
|
||||
|
@ -240,7 +241,10 @@ impl Collection {
|
|||
None
|
||||
}
|
||||
});
|
||||
Ok((weights, search))
|
||||
Ok((
|
||||
weights,
|
||||
SearchNode::DeckIdsWithoutChildren(comma_separated_ids(&search)),
|
||||
))
|
||||
})
|
||||
.collect::<Result<_>>()?;
|
||||
self.update_memory_state(input)?;
|
||||
|
|
|
@ -16,7 +16,6 @@ use crate::revlog::RevlogReviewKind;
|
|||
use crate::scheduler::fsrs::weights::single_card_revlog_to_items;
|
||||
use crate::scheduler::fsrs::weights::Weights;
|
||||
use crate::scheduler::states::fuzz::with_review_fuzz;
|
||||
use crate::search::JoinSearches;
|
||||
use crate::search::Negated;
|
||||
use crate::search::SearchNode;
|
||||
use crate::search::StateKind;
|
||||
|
@ -43,13 +42,13 @@ impl Collection {
|
|||
/// memory state should be removed.
|
||||
pub(crate) fn update_memory_state(
|
||||
&mut self,
|
||||
entries: Vec<(Option<UpdateMemoryStateRequest>, Vec<SearchNode>)>,
|
||||
entries: Vec<(Option<UpdateMemoryStateRequest>, SearchNode)>,
|
||||
) -> Result<()> {
|
||||
let timing = self.timing_today()?;
|
||||
let usn = self.usn()?;
|
||||
for (req, search) in entries {
|
||||
let search = SearchBuilder::any(search.into_iter())
|
||||
.and(SearchNode::State(StateKind::New).negated());
|
||||
let search =
|
||||
SearchBuilder::all([search.into(), SearchNode::State(StateKind::New).negated()]);
|
||||
let revlog = self.revlog_for_srs(search)?;
|
||||
let reschedule = req.as_ref().map(|e| e.reschedule).unwrap_or_default();
|
||||
let last_reviews = if reschedule {
|
||||
|
|
|
@ -281,7 +281,7 @@ impl Collection {
|
|||
usn: Usn,
|
||||
) -> Result<usize> {
|
||||
let cids = self.search_cards(
|
||||
SearchNode::DeckIdWithoutChildren(deck).and(StateKind::New),
|
||||
SearchNode::DeckIdsWithoutChildren(deck.to_string()).and(StateKind::New),
|
||||
SortMode::NoOrder,
|
||||
)?;
|
||||
self.sort_cards_inner(&cids, 1, 1, order.into(), false, usn)
|
||||
|
|
|
@ -11,6 +11,7 @@ use super::SearchNode;
|
|||
use super::StateKind;
|
||||
use super::TemplateKind;
|
||||
use crate::prelude::*;
|
||||
use crate::storage::comma_separated_ids;
|
||||
use crate::text::escape_anki_wildcards_for_search_node;
|
||||
|
||||
pub trait Negated {
|
||||
|
@ -123,7 +124,7 @@ impl SearchBuilder {
|
|||
|
||||
/// Construct [SearchBuilder] matching any given deck, excluding children.
|
||||
pub fn from_decks(decks: &[DeckId]) -> Self {
|
||||
Self::any(decks.iter().copied().map(SearchNode::DeckIdWithoutChildren))
|
||||
SearchNode::DeckIdsWithoutChildren(comma_separated_ids(decks)).into()
|
||||
}
|
||||
|
||||
/// Construct [SearchBuilder] matching learning, but not relearning cards.
|
||||
|
@ -160,7 +161,7 @@ impl SearchNode {
|
|||
if with_children {
|
||||
Self::DeckIdWithChildren(did.into())
|
||||
} else {
|
||||
Self::DeckIdWithoutChildren(did.into())
|
||||
Self::DeckIdsWithoutChildren(did.into().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,8 +60,8 @@ pub enum SearchNode {
|
|||
EditedInDays(u32),
|
||||
CardTemplate(TemplateKind),
|
||||
Deck(String),
|
||||
/// Matches cards in a single deck (original_deck_id is not checked).
|
||||
DeckIdWithoutChildren(DeckId),
|
||||
/// Matches cards in a list of decks (original_deck_id is not checked).
|
||||
DeckIdsWithoutChildren(String),
|
||||
/// Matches cards in a deck or its children (original_deck_id is not
|
||||
/// checked).
|
||||
DeckIdWithChildren(DeckId),
|
||||
|
@ -346,7 +346,7 @@ fn search_node_for_text_with_argument<'a>(
|
|||
"introduced" => parse_introduced(val)?,
|
||||
"rated" => parse_rated(val)?,
|
||||
"is" => parse_state(val)?,
|
||||
"did" => parse_did(val)?,
|
||||
"did" => SearchNode::DeckIdsWithoutChildren(check_id_list(val, key)?.into()),
|
||||
"mid" => parse_mid(val)?,
|
||||
"nid" => SearchNode::NoteIds(check_id_list(val, key)?.into()),
|
||||
"cid" => SearchNode::CardIds(check_id_list(val, key)?.into()),
|
||||
|
@ -614,10 +614,6 @@ fn parse_state(s: &str) -> ParseResult<SearchNode> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn parse_did(s: &str) -> ParseResult<SearchNode> {
|
||||
parse_i64(s, "did:").map(|n| SearchNode::DeckIdWithoutChildren(n.into()))
|
||||
}
|
||||
|
||||
fn parse_mid(s: &str) -> ParseResult<SearchNode> {
|
||||
parse_i64(s, "mid:").map(|n| SearchNode::NotetypeId(n.into()))
|
||||
}
|
||||
|
|
|
@ -160,8 +160,8 @@ impl SqlWriter<'_> {
|
|||
SearchNode::NotetypeId(ntid) => {
|
||||
write!(self.sql, "n.mid = {}", ntid).unwrap();
|
||||
}
|
||||
SearchNode::DeckIdWithoutChildren(did) => {
|
||||
write!(self.sql, "c.did = {}", did).unwrap();
|
||||
SearchNode::DeckIdsWithoutChildren(dids) => {
|
||||
write!(self.sql, "c.did in ({})", dids).unwrap();
|
||||
}
|
||||
SearchNode::DeckIdWithChildren(did) => self.write_deck_id_with_children(*did)?,
|
||||
SearchNode::Notetype(notetype) => self.write_notetype(&norm(notetype)),
|
||||
|
@ -965,7 +965,7 @@ impl SearchNode {
|
|||
SearchNode::AddedInDays(_) => RequiredTable::Cards,
|
||||
SearchNode::IntroducedInDays(_) => RequiredTable::Cards,
|
||||
SearchNode::Deck(_) => RequiredTable::Cards,
|
||||
SearchNode::DeckIdWithoutChildren(_) => RequiredTable::Cards,
|
||||
SearchNode::DeckIdsWithoutChildren(_) => RequiredTable::Cards,
|
||||
SearchNode::DeckIdWithChildren(_) => RequiredTable::Cards,
|
||||
SearchNode::Rated { .. } => RequiredTable::Cards,
|
||||
SearchNode::State(_) => RequiredTable::Cards,
|
||||
|
@ -973,6 +973,7 @@ impl SearchNode {
|
|||
SearchNode::CardIds(_) => RequiredTable::Cards,
|
||||
SearchNode::Property { .. } => RequiredTable::Cards,
|
||||
SearchNode::CustomData { .. } => RequiredTable::Cards,
|
||||
SearchNode::Preset(_) => RequiredTable::Cards,
|
||||
|
||||
SearchNode::UnqualifiedText(_) => RequiredTable::Notes,
|
||||
SearchNode::SingleField { .. } => RequiredTable::Notes,
|
||||
|
@ -989,7 +990,6 @@ impl SearchNode {
|
|||
SearchNode::WholeCollection => RequiredTable::CardsOrNotes,
|
||||
|
||||
SearchNode::CardTemplate(_) => RequiredTable::CardsAndNotes,
|
||||
SearchNode::Preset(_) => RequiredTable::Cards,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ use std::mem;
|
|||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::decks::DeckId as DeckIdType;
|
||||
use crate::notetype::NotetypeId as NotetypeIdType;
|
||||
use crate::prelude::*;
|
||||
use crate::search::parser::parse;
|
||||
|
@ -69,7 +68,7 @@ fn write_search_node(node: &SearchNode) -> String {
|
|||
IntroducedInDays(u) => format!("introduced:{}", u),
|
||||
CardTemplate(t) => write_template(t),
|
||||
Deck(s) => maybe_quote(&format!("deck:{}", s)),
|
||||
DeckIdWithoutChildren(DeckIdType(i)) => format!("did:{}", i),
|
||||
DeckIdsWithoutChildren(s) => format!("did:{}", s),
|
||||
// not exposed on the GUI end
|
||||
DeckIdWithChildren(_) => "".to_string(),
|
||||
NotetypeId(NotetypeIdType(i)) => format!("mid:{}", i),
|
||||
|
|
Loading…
Reference in a new issue