From 5ec2e11de32da7cf7459cf7cbd4fadbe4b398fcd Mon Sep 17 00:00:00 2001 From: RumovZ Date: Sun, 18 Apr 2021 12:14:18 +0200 Subject: [PATCH] Add search keyword `introduced` Filters for cards that had their first review within the last x days. --- rslib/src/search/parser.rs | 7 +++++++ rslib/src/search/sqlwriter.rs | 14 ++++++++++++++ rslib/src/search/writer.rs | 1 + 3 files changed, 22 insertions(+) diff --git a/rslib/src/search/parser.rs b/rslib/src/search/parser.rs index 9317c450d..fb5d08619 100644 --- a/rslib/src/search/parser.rs +++ b/rslib/src/search/parser.rs @@ -73,6 +73,7 @@ pub enum SearchNode { CardTemplate(TemplateKind), Deck(String), DeckId(DeckId), + IntroducedInDays(u32), NotetypeId(NotetypeId), Notetype(String), Rated { @@ -333,6 +334,7 @@ fn search_node_for_text_with_argument<'a>( "prop" => parse_prop(val)?, "added" => parse_added(val)?, "edited" => parse_edited(val)?, + "introduced" => parse_introduced(val)?, "rated" => parse_rated(val)?, "is" => parse_state(val)?, "did" => parse_did(val)?, @@ -527,6 +529,11 @@ fn parse_edited(s: &str) -> ParseResult { parse_u32(s, "edited:").map(|n| SearchNode::EditedInDays(n.max(1))) } +/// eg introduced:1 +fn parse_introduced(s: &str) -> ParseResult { + parse_u32(s, "introduced:").map(|n| SearchNode::IntroducedInDays(n.max(1))) +} + /// eg rated:3 or rated:10:2 /// second arg must be between 1-4 fn parse_rated(s: &str) -> ParseResult { diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index 793b504aa..f3dee8377 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -128,6 +128,7 @@ impl SqlWriter<'_> { // other SearchNode::AddedInDays(days) => self.write_added(*days)?, SearchNode::EditedInDays(days) => self.write_edited(*days)?, + SearchNode::IntroducedInDays(days) => self.write_introduced(*days)?, SearchNode::CardTemplate(template) => match template { TemplateKind::Ordinal(_) => self.write_template(template), TemplateKind::Name(name) => { @@ -492,6 +493,18 @@ impl SqlWriter<'_> { Ok(()) } + fn write_introduced(&mut self, days: u32) -> Result<()> { + let timing = self.col.timing_today()?; + let cutoff = (timing.next_day_at.0 - (86_400 * (days as i64))) * 1_000; + write!( + self.sql, + "(select min(id) > {} from revlog where cid = c.id)", + cutoff + ) + .unwrap(); + Ok(()) + } + fn write_regex(&mut self, word: &str) { self.sql.push_str("n.flds regexp ?"); self.args.push(format!(r"(?i){}", word)); @@ -546,6 +559,7 @@ impl SearchNode { fn required_table(&self) -> RequiredTable { match self { SearchNode::AddedInDays(_) => RequiredTable::Cards, + SearchNode::IntroducedInDays(_) => RequiredTable::Cards, SearchNode::Deck(_) => RequiredTable::Cards, SearchNode::DeckId(_) => RequiredTable::Cards, SearchNode::Rated { .. } => RequiredTable::Cards, diff --git a/rslib/src/search/writer.rs b/rslib/src/search/writer.rs index f96823830..ffb4acaba 100644 --- a/rslib/src/search/writer.rs +++ b/rslib/src/search/writer.rs @@ -83,6 +83,7 @@ fn write_search_node(node: &SearchNode) -> String { SingleField { field, text, is_re } => write_single_field(field, text, *is_re), AddedInDays(u) => format!("added:{}", u), EditedInDays(u) => format!("edited:{}", u), + IntroducedInDays(u) => format!("introduced:{}", u), CardTemplate(t) => write_template(t), Deck(s) => maybe_quote(&format!("deck:{}", s)), DeckId(DeckIdType(i)) => format!("did:{}", i),