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)
}
},
}
}