fn select()

in guard/src/rules/path_value.rs [363:631]


    fn select(&self, all: bool, query: &[QueryPart<'_>], resolver: &dyn EvaluationContext) -> Result<Vec<&PathAwareValue>, Error> {
        if query.is_empty() {
            return Ok(vec![self])
        }

        match &query[0] {
            QueryPart::This => {
                self.select(all, &query[1..], resolver)
            }

            QueryPart::Key(key) => {
                match key.parse::<i32>() {
                    Ok(index) => {
                        match self {
                            PathAwareValue::List((_, list)) => {
                                PathAwareValue::retrieve_index(self, index, list, query)
                                    .map_or_else(|e| self.map_error_or_empty(all, e),
                                                 |val| val.select(all, &query[1..], resolver))
                            }

                            _ => self.map_some_or_error_all(all, query)
                        }
                    },

                    Err(_) => match self {
                        PathAwareValue::Map((path, map)) => {
                            //
                            // Variable interpolation support.
                            //
                            if query[0].is_variable() {
                                let var = query[0].variable().unwrap();
                                let keys = resolver.resolve_variable(var)?;
                                let mut acc = Vec::with_capacity(keys.len());
                                let keys = if query.len() > 1 {
                                    match query[1] {
                                        QueryPart::AllIndices | QueryPart::Key(_) => keys,
                                        QueryPart::Index(index) => {
                                            let check = if index >= 0 { index } else { -index } as usize;
                                            if check < keys.len() {
                                                vec![keys[check]]
                                            } else {
                                                self.map_some_or_error_all(all, query)?
                                            }
                                        },

                                        _ => return Err(Error::new(ErrorKind::IncompatibleError(
                                            format!("THIS type of variable interpolation is not supported {}, {}", self.type_info(), SliceDisplay(query))
                                        )))
                                    }
                                } else {
                                    keys
                                };
                                for each_key in keys {
                                    if let PathAwareValue::String((_, k)) = each_key {
                                        if let Some(next) = map.values.get(k) {
                                            acc.extend(
                                                next.select(all, &query[1..], resolver)?);
                                        }
                                        else if all {
                                            return Err(Error::new(
                                                ErrorKind::RetrievalError(
                                                    format!("Could not locate key = {} inside object/map = {:?}, Path = {}, remaining query = {}",
                                                            key, self, path, SliceDisplay(query))
                                                )))
                                        }
                                    }
                                    else {
                                       return Err(Error::new(
                                           ErrorKind::NotComparable(
                                               format!("Variable projections inside Query {}, is returning a non-string value for key {}, {:?}",
                                                   SliceDisplay(query),
                                                   each_key.type_info(),
                                                   each_key.self_value()
                                               )
                                           )
                                       ))
                                    }
                                }
                                Ok(acc)
                            }
                            else if let Some(next) = map.values.get(key) {
                                next.select(all, &query[1..], resolver)
                            } else {
                                self.map_some_or_error_all(all, query)
                            }
                        },

                        _ => self.map_some_or_error_all(all, query)
                    }
                }
            },

            QueryPart::Index(array_idx) => {
                match self {
                    PathAwareValue::List((_path, vec)) => {
                        PathAwareValue::retrieve_index(self, *array_idx, vec, query)
                            .map_or_else(|e| self.map_error_or_empty(all, e),
                                         |val| val.select(all, &query[1..], resolver))

                    },

                    _ => self.map_some_or_error_all(all, query)
                }
            },

            QueryPart::AllIndices => {
                match self {
                    PathAwareValue::List((_path, elements)) => {
                        PathAwareValue::accumulate(self, all, &query[1..], elements, resolver)
                    },

                    //
                    // Often in the place where a list of values is accepted
                    // single values often are accepted. So proceed to the next
                    // part of your query
                    //
                    rest => {
                        rest.select(all, &query[1..], resolver)
                    }
                }
            }

            QueryPart::AllValues => {
                match self {
                    //
                    // Supporting old format
                    //
                    PathAwareValue::List((_path, elements)) => {
                        PathAwareValue::accumulate(self, all, &query[1..], elements, resolver)
                    },

                    PathAwareValue::Map((_path, map)) => {
                        let values: Vec<&PathAwareValue> = map.values.values().collect();
                        let mut resolved = Vec::with_capacity(values.len());
                        for each in values {
                            resolved.extend(
                                each.select(all, &query[1..], resolver)?);
                        }
                        Ok(resolved)
                    },

                    //
                    // Often in the place where a list of values is accepted
                    // single values often are accepted. So proceed to the next
                    // part of your query
                    //
                    rest => {
                        rest.select(all, &query[1..], resolver)
                    }
                }
            },

            QueryPart::MapKeyFilter(filter) => {
                match self {
                    PathAwareValue::Map((path, map)) => {
                        let mut selected = Vec::with_capacity(map.values.len());
                        match &filter.compare_with {
                            LetValue::AccessClause(query) => {
                                let values = resolve_query(false, &query.query, self, resolver)?;
                                for key in map.keys.iter() {
                                    if values.contains(&key) {
                                        match key {
                                            PathAwareValue::String((_, v)) => {
                                                selected.push(map.values.get(v).unwrap());
                                            },
                                            _ => unreachable!()
                                        }
                                    }
                                }
                            },

                            LetValue::Value(v) => {
                                let path_value = PathAwareValue::try_from((v, path.clone()))?;
                                for key in map.keys.iter() {
                                    if key == &path_value {
                                        match key {
                                            PathAwareValue::String((_, v)) => {
                                                selected.push(map.values.get(v).unwrap());
                                            },
                                            _ => unreachable!()
                                        }
                                    }
                                }
                            },
                        };
                        if query.len() > 1 {
                            let mut acc = Vec::with_capacity(selected.len());
                            for each in selected {
                                acc.extend(each.select(all, &query[1..], resolver)?)
                            }
                            Ok(acc)
                        } else {
                            Ok(selected)
                        }

                    },

                    _ => self.map_some_or_error_all(all, query)
                }
            },

            QueryPart::Filter(conjunctions) => {
                match self {
                    PathAwareValue::List((path, vec)) => {
                        let mut selected = Vec::with_capacity(vec.len());
                        let context = format!("Path={},Type=Array", path);
                        for each in vec {
                            let mut filter = AutoReport::new(EvaluationType::Filter, resolver, &context);
                            match conjunctions.evaluate(each, resolver) {
                                Err(Error(ErrorKind::RetrievalError(e))) => {
                                    if all {
                                        return Err(Error::new(ErrorKind::RetrievalError(e)))
                                    }
                                    // Else treat is like a filter
                                },
                                Err(Error(ErrorKind::IncompatibleRetrievalError(e))) => {
                                    if all {
                                        return Err(Error::new(ErrorKind::IncompatibleRetrievalError(e)))
                                    }
                                    // Else treat is like a filter
                                },
                                Err(e) => return Err(e),
                                Ok(status) => {
                                    match status {
                                        Status::PASS => {
                                            filter.status(Status::PASS);
                                            let index: usize = if query.len() > 1 {
                                                match &query[1] {
                                                    QueryPart::AllIndices => 2,
                                                    _ => 1
                                                }
                                            } else { 1 };
                                            selected.extend(each.select(all, &query[index..], resolver)?);
                                        },
                                        rest => { filter.status(rest); }
                                    }
                                }
                            }
                        }
                        Ok(selected)
                    },

                    PathAwareValue::Map((path, _map)) => {
                        let context = format!("Path={},Type=MapElement", path);
                        let mut filter = AutoReport::new(EvaluationType::Filter, resolver, &context);
                        conjunctions.evaluate(self, resolver)
                            .map_or_else(
                                |e| self.map_error_or_empty(all, e),
                                |status| {
                                    match status {
                                        Status::PASS => {
                                            filter.status(Status::PASS);
                                            self.select(all, &query[1..], resolver)
                                        },
                                        rest => {
                                            filter.status(rest);
                                            Ok(vec![])
                                        }

                                    }
                                }
                            )
                    }

                    _ => self.map_some_or_error_all(all, query)
                }
            },
        }
    }