From 97764fb864ae1ab6046749fe5cabe00f508b0c61 Mon Sep 17 00:00:00 2001 From: Mark Cola Date: Tue, 24 Jan 2023 02:47:36 +1100 Subject: move And and Or variants to FilterCondition to support recursive nesting (#52) --- src/models/search.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 84 insertions(+), 14 deletions(-) diff --git a/src/models/search.rs b/src/models/search.rs index 5b2b928..c9e7e91 100644 --- a/src/models/search.rs +++ b/src/models/search.rs @@ -257,17 +257,20 @@ pub enum PropertyCondition { Files(FilesCondition), Relation(RelationCondition), Formula(FormulaCondition), - /// Returns pages when **any** of the filters inside the provided vector match. - Or(Vec), - /// Returns pages when **all** of the filters inside the provided vector match. - And(Vec), } #[derive(Serialize, Debug, Eq, PartialEq, Clone)] -pub struct FilterCondition { - pub property: String, - #[serde(flatten)] - pub condition: PropertyCondition, +#[serde(untagged)] +pub enum FilterCondition { + Property { + property: String, + #[serde(flatten)] + condition: PropertyCondition, + }, + /// Returns pages when **all** of the filters inside the provided vector match. + And { and: Vec }, + /// Returns pages when **any** of the filters inside the provided vector match. + Or { or: Vec }, } #[derive(Serialize, Debug, Eq, PartialEq, Hash, Copy, Clone)] @@ -376,13 +379,15 @@ impl From for SearchRequest { #[cfg(test)] mod tests { mod text_filters { - use crate::models::search::PropertyCondition::RichText; - use crate::models::search::{FilterCondition, TextCondition}; + use crate::models::search::PropertyCondition::{Checkbox, Number, RichText, Select}; + use crate::models::search::{ + CheckboxCondition, FilterCondition, NumberCondition, SelectCondition, TextCondition, + }; use serde_json::json; #[test] fn text_property_equals() -> Result<(), Box> { - let json = serde_json::to_value(&FilterCondition { + let json = serde_json::to_value(&FilterCondition::Property { property: "Name".to_string(), condition: RichText(TextCondition::Equals("Test".to_string())), })?; @@ -396,7 +401,7 @@ mod tests { #[test] fn text_property_contains() -> Result<(), Box> { - let json = serde_json::to_value(&FilterCondition { + let json = serde_json::to_value(&FilterCondition::Property { property: "Name".to_string(), condition: RichText(TextCondition::Contains("Test".to_string())), })?; @@ -410,7 +415,7 @@ mod tests { #[test] fn text_property_is_empty() -> Result<(), Box> { - let json = serde_json::to_value(&FilterCondition { + let json = serde_json::to_value(&FilterCondition::Property { property: "Name".to_string(), condition: RichText(TextCondition::IsEmpty), })?; @@ -424,7 +429,7 @@ mod tests { #[test] fn text_property_is_not_empty() -> Result<(), Box> { - let json = serde_json::to_value(&FilterCondition { + let json = serde_json::to_value(&FilterCondition::Property { property: "Name".to_string(), condition: RichText(TextCondition::IsNotEmpty), })?; @@ -435,5 +440,70 @@ mod tests { Ok(()) } + + #[test] + fn compound_query_and() -> Result<(), Box> { + let json = serde_json::to_value(&FilterCondition::And { + and: vec![ + FilterCondition::Property { + property: "Seen".to_string(), + condition: Checkbox(CheckboxCondition::Equals(false)), + }, + FilterCondition::Property { + property: "Yearly visitor count".to_string(), + condition: Number(NumberCondition::GreaterThan(serde_json::Number::from( + 1000000, + ))), + }, + ], + })?; + assert_eq!( + dbg!(json), + json!({"and":[ + {"property":"Seen","checkbox":{"equals":false}}, + {"property":"Yearly visitor count","number":{"greater_than":1000000}} + ]}) + ); + + Ok(()) + } + + #[test] + fn compound_query_or() -> Result<(), Box> { + let json = serde_json::to_value(&FilterCondition::Or { + or: vec![ + FilterCondition::Property { + property: "Description".to_string(), + condition: RichText(TextCondition::Contains("fish".to_string())), + }, + FilterCondition::And { + and: vec![ + FilterCondition::Property { + property: "Food group".to_string(), + condition: Select(SelectCondition::Equals( + "🥦Vegetable".to_string(), + )), + }, + FilterCondition::Property { + property: "Is protein rich?".to_string(), + condition: Checkbox(CheckboxCondition::Equals(true)), + }, + ], + }, + ], + })?; + assert_eq!( + dbg!(json), + json!({"or":[ + {"property":"Description","rich_text":{"contains":"fish"}}, + {"and":[ + {"property":"Food group","select":{"equals":"🥦Vegetable"}}, + {"property":"Is protein rich?","checkbox":{"equals":true}} + ]} + ]}) + ); + + Ok(()) + } } } -- cgit v1.2.3