diff --git a/lib/src/idx/planner/tree.rs b/lib/src/idx/planner/tree.rs index e80fca07..86ac4569 100644 --- a/lib/src/idx/planner/tree.rs +++ b/lib/src/idx/planner/tree.rs @@ -52,15 +52,15 @@ struct TreeBuilder<'a> { table: &'a Table, with: &'a Option, indexes: Option>, - index_lookup: HashMap, + index_lookup: HashMap>>>, index_map: IndexMap, with_indexes: Vec, } impl<'a> TreeBuilder<'a> { - async fn find_index(&mut self, i: &Idiom) -> Result, Error> { - if let Some(ir) = self.index_lookup.get(i) { - return Ok(Some(*ir)); + async fn find_indexes(&mut self, i: &Idiom) -> Result>>, Error> { + if let Some(irs) = self.index_lookup.get(i) { + return Ok(irs.clone()); } if self.indexes.is_none() { let indexes = self @@ -72,22 +72,28 @@ impl<'a> TreeBuilder<'a> { .await?; self.indexes = Some(indexes); } + let mut irs = Vec::new(); if let Some(indexes) = &self.indexes { for ix in indexes.as_ref() { if ix.cols.len() == 1 && ix.cols[0].eq(i) { - let ir = self.index_lookup.len() as IndexRef; + let ir = self.index_map.definitions.len() as IndexRef; if let Some(With::Index(ixs)) = self.with { if ixs.contains(&ix.name.0) { self.with_indexes.push(ir); } } - self.index_lookup.insert(i.clone(), ir); self.index_map.definitions.insert(ir, ix.clone()); - return Ok(Some(ir)); + irs.push(ir); } } } - Ok(None) + let irs = if irs.is_empty() { + None + } else { + Some(Arc::new(irs)) + }; + self.index_lookup.insert(i.clone(), irs.clone()); + Ok(irs) } #[cfg_attr(not(target_arch = "wasm32"), async_recursion)] @@ -110,11 +116,12 @@ impl<'a> TreeBuilder<'a> { } async fn eval_idiom(&mut self, i: &Idiom) -> Result { - Ok(if let Some(ix) = self.find_index(i).await? { - Node::IndexedField(i.to_owned(), ix) - } else { - Node::NonIndexedField - }) + if let Some(irs) = self.find_indexes(i).await? { + if !irs.is_empty() { + return Ok(Node::IndexedField(i.to_owned(), irs)); + } + } + Ok(Node::NonIndexedField) } async fn eval_expression(&mut self, e: &Expression) -> Result { @@ -138,10 +145,10 @@ impl<'a> TreeBuilder<'a> { }); } let mut io = None; - if let Some((id, ix)) = left.is_indexed_field() { - io = self.lookup_index_option(ix, o, id, &right, e); - } else if let Some((id, ix)) = right.is_indexed_field() { - io = self.lookup_index_option(ix, o, id, &left, e); + if let Some((id, irs)) = left.is_indexed_field() { + io = self.lookup_index_option(irs.as_slice(), o, id, &right, e); + } else if let Some((id, irs)) = right.is_indexed_field() { + io = self.lookup_index_option(irs.as_slice(), o, id, &left, e); }; Ok(Node::Expression { io, @@ -155,32 +162,34 @@ impl<'a> TreeBuilder<'a> { fn lookup_index_option( &mut self, - ir: IndexRef, + irs: &[IndexRef], op: &Operator, id: &Idiom, v: &Node, e: &Expression, ) -> Option { if let Some(v) = v.is_scalar() { - if let Some(ix) = self.index_map.definitions.get(&ir) { - let op = match &ix.index { - Index::Idx => Self::eval_index_operator(op, v), - Index::Uniq => Self::eval_index_operator(op, v), - Index::Search { - .. - } => { - if let Operator::Matches(mr) = op { - Some(IndexOperator::Matches(v.clone().to_raw_string(), *mr)) - } else { - None + for ir in irs { + if let Some(ix) = self.index_map.definitions.get(ir) { + let op = match &ix.index { + Index::Idx => Self::eval_index_operator(op, v), + Index::Uniq => Self::eval_index_operator(op, v), + Index::Search { + .. + } => { + if let Operator::Matches(mr) = op { + Some(IndexOperator::Matches(v.clone().to_raw_string(), *mr)) + } else { + None + } } + Index::MTree(_) => None, + }; + if let Some(op) = op { + let io = IndexOption::new(*ir, id.clone(), op); + self.index_map.options.insert(Arc::new(e.clone()), io.clone()); + return Some(io); } - Index::MTree(_) => None, - }; - if let Some(op) = op { - let io = IndexOption::new(ir, id.clone(), op); - self.index_map.options.insert(Arc::new(e.clone()), io.clone()); - return Some(io); } } } @@ -223,7 +232,7 @@ pub(super) enum Node { right: Box, exp: Arc, }, - IndexedField(Idiom, IndexRef), + IndexedField(Idiom, Arc>), NonIndexedField, Scalar(Value), Unsupported(String), @@ -238,9 +247,9 @@ impl Node { } } - pub(super) fn is_indexed_field(&self) -> Option<(&Idiom, IndexRef)> { - if let Node::IndexedField(id, ix) = self { - Some((id, *ix)) + pub(super) fn is_indexed_field(&self) -> Option<(&Idiom, Arc>)> { + if let Node::IndexedField(id, irs) = self { + Some((id, irs.clone())) } else { None }