mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
update searching code to use decks table
This commit is contained in:
parent
3ffb37270d
commit
3339c404b4
2 changed files with 46 additions and 65 deletions
|
@ -31,29 +31,6 @@ pub struct Deck {
|
||||||
pub kind: DeckKind,
|
pub kind: DeckKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
// fixme: needs update
|
|
||||||
pub(crate) fn child_ids<'a>(
|
|
||||||
decks: &'a [DeckSchema11],
|
|
||||||
name: &str,
|
|
||||||
) -> impl Iterator<Item = DeckID> + 'a {
|
|
||||||
let prefix = format!("{}::", name.to_ascii_lowercase());
|
|
||||||
decks
|
|
||||||
.iter()
|
|
||||||
.filter(move |d| d.name().to_ascii_lowercase().starts_with(&prefix))
|
|
||||||
.map(|d| d.id())
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixme: needs update
|
|
||||||
pub(crate) fn get_deck(decks: &[DeckSchema11], id: DeckID) -> Option<&DeckSchema11> {
|
|
||||||
for d in decks {
|
|
||||||
if d.id() == id {
|
|
||||||
return Some(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deck {
|
impl Deck {
|
||||||
pub fn new_normal() -> Deck {
|
pub fn new_normal() -> Deck {
|
||||||
let mut norm = NormalDeck::default();
|
let mut norm = NormalDeck::default();
|
||||||
|
|
|
@ -3,15 +3,14 @@
|
||||||
|
|
||||||
use super::parser::{Node, PropertyKind, SearchNode, StateKind, TemplateKind};
|
use super::parser::{Node, PropertyKind, SearchNode, StateKind, TemplateKind};
|
||||||
use crate::card::CardQueue;
|
use crate::card::CardQueue;
|
||||||
use crate::decks::child_ids;
|
use crate::err::Result;
|
||||||
use crate::decks::get_deck;
|
|
||||||
use crate::err::{AnkiError, Result};
|
|
||||||
use crate::notes::field_checksum;
|
use crate::notes::field_checksum;
|
||||||
use crate::notetype::NoteTypeID;
|
use crate::notetype::NoteTypeID;
|
||||||
use crate::text::matches_wildcard;
|
use crate::text::matches_wildcard;
|
||||||
use crate::text::without_combining;
|
use crate::text::without_combining;
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::Collection, storage::ids_to_string, text::strip_html_preserving_image_filenames,
|
collection::Collection, decks::human_deck_name_to_native,
|
||||||
|
text::strip_html_preserving_image_filenames,
|
||||||
};
|
};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
|
@ -221,44 +220,33 @@ impl SqlWriter<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// fixme: update for new table
|
|
||||||
fn write_deck(&mut self, deck: &str) -> Result<()> {
|
fn write_deck(&mut self, deck: &str) -> Result<()> {
|
||||||
match deck {
|
match deck {
|
||||||
"*" => write!(self.sql, "true").unwrap(),
|
"*" => write!(self.sql, "true").unwrap(),
|
||||||
"filtered" => write!(self.sql, "c.odid > 0").unwrap(),
|
"filtered" => write!(self.sql, "c.odid != 0").unwrap(),
|
||||||
deck => {
|
deck => {
|
||||||
let all_decks: Vec<_> = self
|
// rewrite "current" to the current deck name
|
||||||
.col
|
let deck = if deck == "current" {
|
||||||
.storage
|
let current_did = self.col.get_current_deck_id();
|
||||||
.get_all_decks_as_schema11()?
|
self.col
|
||||||
.into_iter()
|
.storage
|
||||||
.map(|(_, v)| v)
|
.get_deck(current_did)?
|
||||||
.collect();
|
.map(|d| d.name)
|
||||||
let dids_with_children = if deck == "current" {
|
.unwrap_or_else(|| "Default".into())
|
||||||
let current_id = self.col.get_current_deck_id();
|
|
||||||
let mut dids_with_children = vec![current_id];
|
|
||||||
let current = get_deck(&all_decks, current_id)
|
|
||||||
.ok_or_else(|| AnkiError::invalid_input("invalid current deck"))?;
|
|
||||||
for child_did in child_ids(&all_decks, ¤t.name()) {
|
|
||||||
dids_with_children.push(child_did);
|
|
||||||
}
|
|
||||||
dids_with_children
|
|
||||||
} else {
|
} else {
|
||||||
let mut dids_with_children = vec![];
|
deck.into()
|
||||||
for deck in all_decks
|
|
||||||
.iter()
|
|
||||||
.filter(|d| matches_wildcard(&d.name(), deck))
|
|
||||||
{
|
|
||||||
dids_with_children.push(deck.id());
|
|
||||||
for child_id in child_ids(&all_decks, &deck.name()) {
|
|
||||||
dids_with_children.push(child_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dids_with_children
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.sql.push_str("c.did in ");
|
// convert to a regex that includes child decks
|
||||||
ids_to_string(&mut self.sql, &dids_with_children);
|
let human_deck = human_deck_name_to_native(&deck);
|
||||||
|
let re = text_to_re(&human_deck);
|
||||||
|
self.args.push(format!("(?i)^{}($|\x1f)", re));
|
||||||
|
let arg_idx = self.args.len();
|
||||||
|
self.sql.push_str(&format!(concat!(
|
||||||
|
"(c.did in (select id from decks where name regexp ?{n})",
|
||||||
|
" or (c.odid != 0 and c.odid in (select id from decks where name regexp ?{n})))"),
|
||||||
|
n=arg_idx
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -371,17 +359,23 @@ impl SqlWriter<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_word_boundary(&mut self, word: &str) {
|
fn write_word_boundary(&mut self, word: &str) {
|
||||||
let re = glob_to_re(word).unwrap_or_else(|| word.to_string());
|
// fixme: need to escape in the no-glob case as well
|
||||||
|
let re = text_to_re(word);
|
||||||
self.write_regex(&format!(r"\b{}\b", re))
|
self.write_regex(&format!(r"\b{}\b", re))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a string with _, % or * characters into a regex.
|
/// Convert a string with _, % or * characters into a regex.
|
||||||
|
/// If string contains no globbing characters, return None.
|
||||||
fn glob_to_re(glob: &str) -> Option<String> {
|
fn glob_to_re(glob: &str) -> Option<String> {
|
||||||
if !glob.contains(|c| c == '_' || c == '*' || c == '%') {
|
if !glob.contains(|c| c == '_' || c == '*' || c == '%') {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
Some(text_to_re(glob))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Escape text, converting glob characters to regex syntax, then return.
|
||||||
|
fn text_to_re(glob: &str) -> String {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref ESCAPED: Regex = Regex::new(r"(\\\\)?\\\*").unwrap();
|
static ref ESCAPED: Regex = Regex::new(r"(\\\\)?\\\*").unwrap();
|
||||||
static ref GLOB: Regex = Regex::new(r"(\\\\)?[_%]").unwrap();
|
static ref GLOB: Regex = Regex::new(r"(\\\\)?[_%]").unwrap();
|
||||||
|
@ -409,7 +403,7 @@ fn glob_to_re(glob: &str) -> Option<String> {
|
||||||
.to_string()
|
.to_string()
|
||||||
});
|
});
|
||||||
|
|
||||||
text2.into_owned().into()
|
text2.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -488,11 +482,21 @@ mod test {
|
||||||
);
|
);
|
||||||
|
|
||||||
// deck
|
// deck
|
||||||
assert_eq!(s(ctx, "deck:default"), ("(c.did in (1))".into(), vec![],));
|
assert_eq!(
|
||||||
assert_eq!(s(ctx, "deck:current"), ("(c.did in (1))".into(), vec![],));
|
s(ctx, "deck:default"),
|
||||||
assert_eq!(s(ctx, "deck:missing"), ("(c.did in ())".into(), vec![],));
|
(
|
||||||
assert_eq!(s(ctx, "deck:d*"), ("(c.did in (1))".into(), vec![],));
|
"((c.did in (select id from decks where name regexp ?1) or (c.odid != 0 and \
|
||||||
assert_eq!(s(ctx, "deck:filtered"), ("(c.odid > 0)".into(), vec![],));
|
c.odid in (select id from decks where name regexp ?1))))"
|
||||||
|
.into(),
|
||||||
|
vec!["(?i)^default($|\u{1f})".into()]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
s(ctx, "deck:current").1,
|
||||||
|
vec!["(?i)^Default($|\u{1f})".to_string()]
|
||||||
|
);
|
||||||
|
assert_eq!(s(ctx, "deck:d*").1, vec!["(?i)^d.*($|\u{1f})".to_string()]);
|
||||||
|
assert_eq!(s(ctx, "deck:filtered"), ("(c.odid != 0)".into(), vec![],));
|
||||||
|
|
||||||
// card
|
// card
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in a new issue