diff --git a/src/search/facet/facet_condition.rs b/src/search/facet/facet_condition.rs index 92331ee7f..ce4a22119 100644 --- a/src/search/facet/facet_condition.rs +++ b/src/search/facet/facet_condition.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use std::ops::Bound::{self, Included, Excluded}; use std::str::FromStr; +use either::Either; use heed::types::{ByteSlice, DecodeIgnore}; use log::debug; use num_traits::Bounded; @@ -141,6 +142,81 @@ where T: FromStr, } impl FacetCondition { + pub fn from_array( + rtxn: &heed::RoTxn, + index: &Index, + array: I, + ) -> anyhow::Result> + where I: IntoIterator>, + J: IntoIterator, + A: AsRef, + B: AsRef, + { + fn facet_condition( + fields_ids_map: &FieldsIdsMap, + faceted_fields: &HashMap, + key: &str, + value: &str, + ) -> anyhow::Result + { + let fid = fields_ids_map.id(key).unwrap(); + let ftype = faceted_fields.get(&fid).copied().unwrap(); + let (neg, value) = match value.strip_prefix('-') { + Some(value) => (true, value), + None => (false, value), + }; + + let operator = match ftype { + FacetType::String => OperatorString(fid, FacetStringOperator::equal(value)), + FacetType::Float => OperatorF64(fid, FacetNumberOperator::Equal(value.parse()?)), + FacetType::Integer => OperatorI64(fid, FacetNumberOperator::Equal(value.parse()?)), + }; + + if neg { Ok(operator.negate()) } else { Ok(operator) } + } + + let fields_ids_map = index.fields_ids_map(rtxn)?; + let faceted_fields = index.faceted_fields(rtxn)?; + let mut ands = None; + + for either in array { + match either { + Either::Left(array) => { + let mut ors = None; + for rule in array { + let mut iter = rule.as_ref().splitn(2, ':'); + let key = iter.next().unwrap(); + let value = iter.next().unwrap(); + let condition = facet_condition(&fields_ids_map, &faceted_fields, key, value)?; + ors = match ors.take() { + Some(ors) => Some(Or(Box::new(ors), Box::new(condition))), + None => Some(condition), + }; + } + + if let Some(rule) = ors { + ands = match ands.take() { + Some(ands) => Some(And(Box::new(ands), Box::new(rule))), + None => Some(rule), + }; + } + }, + Either::Right(rule) => { + let mut iter = rule.as_ref().splitn(2, ':'); + let key = iter.next().unwrap(); + let value = iter.next().unwrap(); + let condition = facet_condition(&fields_ids_map, &faceted_fields, key, value)?; + ands = match ands.take() { + Some(ands) => Some(And(Box::new(ands), Box::new(condition))), + None => Some(condition), + }; + } + } + } + + Ok(ands) + } + pub fn from_str( rtxn: &heed::RoTxn, index: &Index,