From 2e42afbb044649eeb5da595879c0d822b1bfedad Mon Sep 17 00:00:00 2001 From: davidemazzocchi Date: Sun, 19 Oct 2025 10:51:38 +0200 Subject: [PATCH] feat: handle comparisons =, >, <, >=, <= for unsigned int condition --- .../heave/src/fun/sqlite_build_params.rs | 1 + .../heave/src/fun/sqlite_build_statement.rs | 18 +++ 01.workspace/heave/src/str/catalog.rs | 106 +++++++++++++----- 01.workspace/heave/src/str/condition.rs | 1 + 01.workspace/heave/src/str/filter.rs | 13 +++ 5 files changed, 112 insertions(+), 27 deletions(-) diff --git a/01.workspace/heave/src/fun/sqlite_build_params.rs b/01.workspace/heave/src/fun/sqlite_build_params.rs index e93ca64..166af0b 100644 --- a/01.workspace/heave/src/fun/sqlite_build_params.rs +++ b/01.workspace/heave/src/fun/sqlite_build_params.rs @@ -8,6 +8,7 @@ pub fn run<'a>(filter: &'a Filter) -> Result>, FailedTo> match condition { Condition::Bool(value) => params.push(Box::new(value)), Condition::SignedInt(value) => params.push(Box::new(value)), + Condition::UnsignedInt(value) => params.push(Box::new(value)), } } Ok(params) diff --git a/01.workspace/heave/src/fun/sqlite_build_statement.rs b/01.workspace/heave/src/fun/sqlite_build_statement.rs index d3106d9..34f7554 100644 --- a/01.workspace/heave/src/fun/sqlite_build_statement.rs +++ b/01.workspace/heave/src/fun/sqlite_build_statement.rs @@ -20,9 +20,11 @@ pub fn run(filter: &Filter) -> Result { let mut statement = String::from(BASE_SELECT); for (i, (name, comparison, condition)) in filter.conditions().enumerate() { let fragment = match (comparison, condition) { + // BOOL (Comparison::Equal, Condition::Bool(_)) => { compose_fragment(name, "value_bool", "=", i + 1) } + // SIGNED INT (Comparison::Equal, Condition::SignedInt(_)) => { compose_fragment(name, "value_int", "=", i + 1) } @@ -38,6 +40,22 @@ pub fn run(filter: &Filter) -> Result { (Comparison::LesserOrEqual, Condition::SignedInt(_)) => { compose_fragment(name, "value_int", "<=", i + 1) } + // UNSIGNED INT + (Comparison::Equal, Condition::UnsignedInt(_)) => { + compose_fragment(name, "value_uint", "=", i + 1) + } + (Comparison::Greater, Condition::UnsignedInt(_)) => { + compose_fragment(name, "value_uint", ">", i + 1) + } + (Comparison::Lesser, Condition::UnsignedInt(_)) => { + compose_fragment(name, "value_uint", "<", i + 1) + } + (Comparison::GreaterOrEqual, Condition::UnsignedInt(_)) => { + compose_fragment(name, "value_uint", ">=", i + 1) + } + (Comparison::LesserOrEqual, Condition::UnsignedInt(_)) => { + compose_fragment(name, "value_uint", "<=", i + 1) + } _ => todo!(), }; statement.push_str(&fragment); diff --git a/01.workspace/heave/src/str/catalog.rs b/01.workspace/heave/src/str/catalog.rs index 82237c0..b77557f 100644 --- a/01.workspace/heave/src/str/catalog.rs +++ b/01.workspace/heave/src/str/catalog.rs @@ -1702,7 +1702,6 @@ mod tests { if path.exists() { std::fs::remove_file(path).unwrap(); } - let mut catalog_setup = Catalog::new(db_path); catalog_setup.init().unwrap(); let items = vec![ @@ -1730,20 +1729,17 @@ mod tests { ]; catalog_setup.insert_many(items).unwrap(); catalog_setup.persist().unwrap(); - // Edge Case 1: Value equal to filter value should not be included. let mut catalog1 = Catalog::new(db_path); let filter1 = Filter::new().with_signed_int("sell_trend", Comparison::Lesser, 10); assert!(catalog1.load_by_filter(&filter1).is_ok()); assert_eq!(catalog1.items.len(), 1); assert!(catalog1.items.contains_key("item-2")); - // Edge Case 2: No values lesser than filter value. let mut catalog2 = Catalog::new(db_path); let filter2 = Filter::new().with_signed_int("sell_trend", Comparison::Lesser, -5); assert!(catalog2.load_by_filter(&filter2).is_ok()); assert!(catalog2.items.is_empty()); - // Edge Case 3: All values lesser than filter value. let mut catalog3 = Catalog::new(db_path); let filter3 = Filter::new().with_signed_int("sell_trend", Comparison::Lesser, 25); @@ -1752,10 +1748,8 @@ mod tests { assert!(catalog3.items.contains_key("item-1")); assert!(catalog3.items.contains_key("item-2")); assert!(catalog3.items.contains_key("item-3")); - std::fs::remove_file(path).unwrap(); } - #[test] fn load_by_filter_should_load_matching_greater_or_equal_sell_trend() { let db_path = "target/test_dbs/lbf_matching_greater_or_equal_sell_trend.db"; @@ -1764,7 +1758,6 @@ mod tests { if path.exists() { std::fs::remove_file(path).unwrap(); } - let mut catalog_setup = Catalog::new(db_path); catalog_setup.init().unwrap(); let items = vec![ @@ -1792,19 +1785,15 @@ mod tests { ]; catalog_setup.insert_many(items).unwrap(); catalog_setup.persist().unwrap(); - let mut catalog = Catalog::new(db_path); let filter = Filter::new().with_signed_int("sell_trend", Comparison::GreaterOrEqual, 10); assert!(catalog.load_by_filter(&filter).is_ok()); - assert_eq!(catalog.items.len(), 2); assert!(catalog.items.contains_key("item-1")); assert!(!catalog.items.contains_key("item-2")); assert!(catalog.items.contains_key("item-3")); - std::fs::remove_file(path).unwrap(); } - #[test] fn load_by_filter_should_load_matching_greater_or_equal_sell_trend_edge_cases() { let db_path = "target/test_dbs/lbf_greater_or_equal_sell_trend_edge_cases.db"; @@ -1813,7 +1802,6 @@ mod tests { if path.exists() { std::fs::remove_file(path).unwrap(); } - let mut catalog_setup = Catalog::new(db_path); catalog_setup.init().unwrap(); let items = vec![ @@ -1841,20 +1829,17 @@ mod tests { ]; catalog_setup.insert_many(items).unwrap(); catalog_setup.persist().unwrap(); - // Edge Case 1: Value equal to filter value should be included. let mut catalog1 = Catalog::new(db_path); let filter1 = Filter::new().with_signed_int("sell_trend", Comparison::GreaterOrEqual, 20); assert!(catalog1.load_by_filter(&filter1).is_ok()); assert_eq!(catalog1.items.len(), 1); assert!(catalog1.items.contains_key("item-3")); - // Edge Case 2: No values greater than or equal to filter value. let mut catalog2 = Catalog::new(db_path); let filter2 = Filter::new().with_signed_int("sell_trend", Comparison::GreaterOrEqual, 21); assert!(catalog2.load_by_filter(&filter2).is_ok()); assert!(catalog2.items.is_empty()); - // Edge Case 3: All values greater than or equal to filter value. let mut catalog3 = Catalog::new(db_path); let filter3 = Filter::new().with_signed_int("sell_trend", Comparison::GreaterOrEqual, -5); @@ -1863,10 +1848,8 @@ mod tests { assert!(catalog3.items.contains_key("item-1")); assert!(catalog3.items.contains_key("item-2")); assert!(catalog3.items.contains_key("item-3")); - std::fs::remove_file(path).unwrap(); } - #[test] fn load_by_filter_should_load_matching_lesser_or_equal_sell_trend() { let db_path = "target/test_dbs/lbf_matching_lesser_or_equal_sell_trend.db"; @@ -1875,7 +1858,6 @@ mod tests { if path.exists() { std::fs::remove_file(path).unwrap(); } - let mut catalog_setup = Catalog::new(db_path); catalog_setup.init().unwrap(); let items = vec![ @@ -1903,19 +1885,15 @@ mod tests { ]; catalog_setup.insert_many(items).unwrap(); catalog_setup.persist().unwrap(); - let mut catalog = Catalog::new(db_path); let filter = Filter::new().with_signed_int("sell_trend", Comparison::LesserOrEqual, 10); assert!(catalog.load_by_filter(&filter).is_ok()); - assert_eq!(catalog.items.len(), 2); assert!(catalog.items.contains_key("item-1")); assert!(catalog.items.contains_key("item-2")); assert!(!catalog.items.contains_key("item-3")); - std::fs::remove_file(path).unwrap(); } - #[test] fn load_by_filter_should_load_matching_lesser_or_equal_sell_trend_edge_cases() { let db_path = "target/test_dbs/lbf_lesser_or_equal_sell_trend_edge_cases.db"; @@ -1924,7 +1902,6 @@ mod tests { if path.exists() { std::fs::remove_file(path).unwrap(); } - let mut catalog_setup = Catalog::new(db_path); catalog_setup.init().unwrap(); let items = vec![ @@ -1952,20 +1929,17 @@ mod tests { ]; catalog_setup.insert_many(items).unwrap(); catalog_setup.persist().unwrap(); - // Edge Case 1: Value equal to filter value should be included. let mut catalog1 = Catalog::new(db_path); let filter1 = Filter::new().with_signed_int("sell_trend", Comparison::LesserOrEqual, -5); assert!(catalog1.load_by_filter(&filter1).is_ok()); assert_eq!(catalog1.items.len(), 1); assert!(catalog1.items.contains_key("item-2")); - // Edge Case 2: No values lesser than or equal to filter value. let mut catalog2 = Catalog::new(db_path); let filter2 = Filter::new().with_signed_int("sell_trend", Comparison::LesserOrEqual, -6); assert!(catalog2.load_by_filter(&filter2).is_ok()); assert!(catalog2.items.is_empty()); - // Edge Case 3: All values lesser than or equal to filter value. let mut catalog3 = Catalog::new(db_path); let filter3 = Filter::new().with_signed_int("sell_trend", Comparison::LesserOrEqual, 20); @@ -1974,7 +1948,6 @@ mod tests { assert!(catalog3.items.contains_key("item-1")); assert!(catalog3.items.contains_key("item-2")); assert!(catalog3.items.contains_key("item-3")); - std::fs::remove_file(path).unwrap(); } // ## Integration Tests @@ -2223,4 +2196,83 @@ mod tests { // Clean up std::fs::remove_file(path).unwrap(); } + #[test] + fn load_by_filter_should_load_unsigned_int_comparisons() { + let db_path = "target/test_dbs/lbf_unsigned_int_comparisons.db"; + let path = std::path::Path::new(db_path); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + if path.exists() { + std::fs::remove_file(path).unwrap(); + } + let mut catalog_setup = Catalog::new(db_path); + catalog_setup.init().unwrap(); + let items = vec![ + Item { + id: "item-1".to_string(), + name: "Item One".to_string(), + price: 100, + sell_trend: 0, + in_stock: true, + }, + Item { + id: "item-2".to_string(), + name: "Item Two".to_string(), + price: 200, + sell_trend: 0, + in_stock: false, + }, + Item { + id: "item-3".to_string(), + name: "Item Three".to_string(), + price: 300, + sell_trend: 0, + in_stock: true, + }, + ]; + catalog_setup.insert_many(items).unwrap(); + catalog_setup.persist().unwrap(); + // Equal + let mut catalog = Catalog::new(db_path); + let filter = Filter::new().with_unsigned_int("price", Comparison::Equal, 200); + assert!(catalog.load_by_filter(&filter).is_ok()); + assert_eq!(catalog.items.len(), 1); + assert!(catalog.items.contains_key("item-2")); + // Greater + let mut catalog = Catalog::new(db_path); + let filter = Filter::new().with_unsigned_int("price", Comparison::Greater, 200); + assert!(catalog.load_by_filter(&filter).is_ok()); + assert_eq!(catalog.items.len(), 1); + assert!(catalog.items.contains_key("item-3")); + // Lesser + let mut catalog = Catalog::new(db_path); + let filter = Filter::new().with_unsigned_int("price", Comparison::Lesser, 200); + assert!(catalog.load_by_filter(&filter).is_ok()); + assert_eq!(catalog.items.len(), 1); + assert!(catalog.items.contains_key("item-1")); + // GreaterOrEqual + let mut catalog = Catalog::new(db_path); + let filter = Filter::new().with_unsigned_int("price", Comparison::GreaterOrEqual, 200); + assert!(catalog.load_by_filter(&filter).is_ok()); + assert_eq!(catalog.items.len(), 2); + assert!(catalog.items.contains_key("item-2")); + assert!(catalog.items.contains_key("item-3")); + // LesserOrEqual + let mut catalog = Catalog::new(db_path); + let filter = Filter::new().with_unsigned_int("price", Comparison::LesserOrEqual, 200); + assert!(catalog.load_by_filter(&filter).is_ok()); + assert_eq!(catalog.items.len(), 2); + assert!(catalog.items.contains_key("item-1")); + assert!(catalog.items.contains_key("item-2")); + // Edge case: No match + let mut catalog = Catalog::new(db_path); + let filter = Filter::new().with_unsigned_int("price", Comparison::Equal, 400); + assert!(catalog.load_by_filter(&filter).is_ok()); + assert!(catalog.items.is_empty()); + // Edge case: All match + let mut catalog = Catalog::new(db_path); + let filter = Filter::new().with_unsigned_int("price", Comparison::GreaterOrEqual, 100); + assert!(catalog.load_by_filter(&filter).is_ok()); + assert_eq!(catalog.items.len(), 3); + std::fs::remove_file(path).unwrap(); + } } diff --git a/01.workspace/heave/src/str/condition.rs b/01.workspace/heave/src/str/condition.rs index 69892e4..15ff996 100644 --- a/01.workspace/heave/src/str/condition.rs +++ b/01.workspace/heave/src/str/condition.rs @@ -2,4 +2,5 @@ pub enum E { Bool(bool), SignedInt(i64), + UnsignedInt(i64), } diff --git a/01.workspace/heave/src/str/filter.rs b/01.workspace/heave/src/str/filter.rs index e77eff6..a358cb9 100644 --- a/01.workspace/heave/src/str/filter.rs +++ b/01.workspace/heave/src/str/filter.rs @@ -32,6 +32,19 @@ impl Filter { )); self } + pub fn with_unsigned_int( + mut self, + attribute_name: &str, + comparison: Comparison, + value: i64, + ) -> Self { + self.conditions.push(( + attribute_name.to_string(), + comparison, + Condition::UnsignedInt(value), + )); + self + } pub(crate) fn conditions(&self) -> impl Iterator { self.conditions.iter() }