From 8499c476f9a1097b0a7aebe688c6d98d4b7d227b Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Tue, 20 Jan 2026 22:14:57 +0100 Subject: run: allow selection based on tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miquel Sabaté Solà --- lib/mihi/src/lib.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/mihi/src/lib.rs b/lib/mihi/src/lib.rs index c15e1ed..f563645 100644 --- a/lib/mihi/src/lib.rs +++ b/lib/mihi/src/lib.rs @@ -782,7 +782,7 @@ pub fn find_by(enunciated: &str) -> Result { // `flags` are set for a row. If no flags are given, then an empty string is // returned. Otherwise the string is prepended by an "AND" clause, meaning that // it expects the caller to have other clauses before this one. -fn flags_clause(flags: &Vec) -> String { +fn flags_clause(flags: &[String]) -> String { if flags.is_empty() { return "".to_string(); } @@ -796,15 +796,18 @@ fn flags_clause(flags: &Vec) -> String { } // Select a maximum of `number` words which match a given word `category` and -// have set one of the given boolean `flags`. +// have set one of the given boolean `flags`. You may also pass a `tags` vector +// which contains the name of the tags for which each word must have at least +// one match. pub fn select_relevant_words( category: Category, - flags: &Vec, + flags: &[String], + tags: &[String], number: isize, ) -> Result, String> { let conn = get_connection()?; - let mut stmt = conn - .prepare( + let mut stmt = if tags.is_empty() { + conn.prepare( format!( "SELECT id, enunciated, particle, language_id, declension_id, conjugation_id, \ kind, category, regular, locative, gender, suffix, translation, \ @@ -817,7 +820,26 @@ pub fn select_relevant_words( ) .as_str(), ) - .unwrap(); + .unwrap() + } else { + conn.prepare( + format!( + "SELECT w.id, w.enunciated, w.particle, w.language_id, w.declension_id, w.conjugation_id, \ + w.kind, w.category, w.regular, w.locative, w.gender, w.suffix, w.translation, \ + w.succeeded, w.steps, w.flags, w.weight \ + FROM words w \ + JOIN tag_associations ta ON w.id = ta.word_id \ + JOIN tags t ON t.id = ta.tag_id \ + WHERE w.category = ?1 AND t.name IN ({}) AND w.translation != '{{}}' {} \ + ORDER BY w.weight DESC, w.succeeded ASC, w.updated_at DESC + LIMIT ?2", + tags.iter().map(|t| format!("'{}'", t)).collect::>().join(", "), + flags_clause(flags) + ) + .as_str(), + ) + .unwrap() + }; let mut it = stmt.query([category as isize, number]).unwrap(); let mut res = vec![]; @@ -848,11 +870,13 @@ pub fn select_relevant_words( /// Select a set of words except for the ones passed in the `excluded` /// vector. You have to pass the categories to be selected via the `categories` /// parameter, which cannot be empty. It also accepts a set of boolean `flags` -/// as with functions like `select_relevant_words`. +/// as with functions like `select_relevant_words`; and the `tags` filtering +/// option. pub fn select_words_except( excluded: &[Word], categories: &[Category], - flags: &Vec, + flags: &[String], + tags: &[String], ) -> Result, String> { assert!(!categories.is_empty()); @@ -865,8 +889,8 @@ pub fn select_words_except( .join(", "); let conn = get_connection()?; - let mut stmt = conn - .prepare( + let mut stmt = if tags.is_empty() { + conn.prepare( format!( "SELECT id, enunciated, particle, language_id, declension_id, conjugation_id, \ kind, category, regular, locative, gender, suffix, translation, \ @@ -881,7 +905,28 @@ pub fn select_words_except( ) .as_str(), ) - .unwrap(); + .unwrap() + } else { + conn.prepare( + format!( + "SELECT w.id, w.enunciated, w.particle, w.language_id, w.declension_id, w.conjugation_id, \ + w.kind, w.category, w.regular, w.locative, w.gender, w.suffix, w.translation, \ + w.succeeded, w.steps, w.flags, w.weight \ + FROM words w \ + JOIN tag_associations ta ON w.id = ta.word_id \ + JOIN tags t ON t.id = ta.tag_id \ + WHERE w.id NOT IN ({}) AND t.name IN ({}) AND w.category IN ({}) AND w.translation != '{{}}' {} \ + ORDER BY w.weight DESC, w.succeeded ASC, w.updated_at DESC + LIMIT 5", + placeholders, + tags.iter().map(|t| format!("'{}'", t)).collect::>().join(", "), + cats, + flags_clause(flags) + ) + .as_str(), + ) + .unwrap() + }; let mut it = stmt.query(rusqlite::params_from_iter(ids)).unwrap(); let mut res = vec![]; -- cgit v1.2.3