rushdb_query/
property_predicate.rs1use crate::document::{self, QueryDocumentError};
6use crate::{eval_pred, Expr, Json, Map, QueryError};
7
8pub fn parse_property_predicate(where_: &Json) -> Result<Expr, QueryDocumentError> {
16 fn traverses(expr: &Expr) -> bool {
17 match expr {
18 Expr::And(items) | Expr::Or(items) | Expr::Nor(items) => items.iter().any(traverses),
19 Expr::Xor(a, b) => traverses(a) || traverses(b),
20 Expr::Not(inner) => traverses(inner),
21 Expr::Field(_) => false,
22 Expr::Related(_) => true,
23 }
24 }
25 let expr = document::parse_where(where_)?;
26 if traverses(&expr) {
27 return Err(QueryDocumentError::Parse(
28 "a relationship predicate filters the relationship's own properties; \
29 traversal blocks are not supported"
30 .into(),
31 ));
32 }
33 Ok(expr)
34}
35
36pub fn matches_properties(expr: &Expr, obj: &Map<String, Json>) -> Result<bool, QueryError> {
42 Ok(match expr {
43 Expr::And(items) => {
44 for item in items {
45 if !matches_properties(item, obj)? {
46 return Ok(false);
47 }
48 }
49 true
50 }
51 Expr::Or(items) | Expr::Nor(items) => {
52 let mut any = false;
53 for item in items {
54 if matches_properties(item, obj)? {
55 any = true;
56 break;
57 }
58 }
59 any != matches!(expr, Expr::Nor(_))
60 }
61 Expr::Xor(a, b) => matches_properties(a, obj)? != matches_properties(b, obj)?,
62 Expr::Not(inner) => !matches_properties(inner, obj)?,
63 Expr::Field(pred) => eval_pred(&|_| Ok(None), pred, obj)?,
64 Expr::Related(_) => false,
65 })
66}