json_predicate/predicate/
mod.rs

1use serde::{Deserialize, Serialize};
2
3pub mod first_order;
4use first_order::FirstOrder;
5use serde_json::Value;
6
7use self::{context::PredicateContext, error::PredicateError, second_order::SecondOrder};
8
9pub mod context;
10pub mod second_order;
11
12mod error;
13
14/// A Predicate is an Object whose members describe a testable
15/// condition that evaluates as either true or false.
16///
17/// The essential components of a Predicate include:
18///
19/// - A label identifying the predicate operation,
20/// - A reference to the value being tested, and
21/// - The condition against which the referenced value is to be evaluated.
22///
23/// Predicate objects MUST have exactly one "op" member whose value
24/// indicates the type of predicate operation to perform.  It's value
25/// MUST be one of: "and", "contains", "contains-", "defined", "ends",
26/// "ends-", "in", "in-", "less", "matches", "matches-", "more", "not",
27/// "or", "starts", "starts-", "test", "test-", "type", or "undefined".
28///
29/// The semantics for each are defined in the sections that follow.
30///
31/// Note that the value of the "op" member is case-sensitive and that
32/// each of the operations listed are in lower-case.  The value "Starts",
33/// for example, is not equivalent to "starts".
34///
35/// If the "op" member specifies any value other than one of those listed
36/// above, the evaluation of the predicate operation MUST cease and be
37/// handled as if a boolean value of "false" was returned.  The
38/// application processing the predicate operation MAY signal that an
39/// error condition has occurred depending on the specific requirements
40/// of the application within which JSON Predicates are being used.
41///
42/// The remaining structure of each predicate operation depends on the
43/// specific type.  There are two basic types of predicates.
44///
45/// -  First Order Predicates that are used to test one name value pair
46///    against a single condition, and
47///
48/// -  Second Order Predicates that aggregate one or more subordinate
49///    First or Second Order Predicates.
50///
51/// In addition to the required "op" member, First Order Predicates have
52/// exactly one "path" member whose value MUST be a string containing a
53/// JSON-Pointer [RFC6901](https://datatracker.ietf.org/doc/html/rfc6901)
54/// value referencing the name value pair that is to be tested.  If the
55/// "path" member is not specified within the
56/// predicate object, it's value is assumed to be an empty string.
57///
58/// Second Order Predicates MUST have exactly one "apply" member whose
59/// value is a JSON Array containing one or more First or Second Order
60/// Predicate Objects.
61///
62///
63/// Additional members can be required depending on the specific
64/// predicate operation.  All other members not explicitly defined by
65/// this specification MUST be ignored.
66///
67/// Note that the ordering of members in JSON objects is not significant;
68/// therefore the following operations are equivalent:
69///
70/// ```json
71/// {"op": "contains", "path": "/a/b/c", "value": "ABC"}
72/// {"path": "/a/b/c", "op": "contains", "value": "ABC"}
73/// {"value": "ABC", "path": "/a/b/c", "op": "contains"}
74/// ```
75#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
76#[serde(untagged)]
77pub enum Predicate {
78    FirstOrder(FirstOrder),
79    SecondOrder(SecondOrder),
80}
81
82impl PredicateImpl for Predicate {
83    fn evaluate(&self, data: &Value, ctx: PredicateContext) -> Result<bool, PredicateError> {
84        match self {
85            Predicate::FirstOrder(fo) => fo.evaluate(data, ctx),
86            Predicate::SecondOrder(fo) => fo.evaluate(data, ctx),
87        }
88    }
89}
90
91pub trait PredicateImpl {
92    /// Evaluate the predicate against the provided JSON
93    ///
94    /// The error result means the predicate couldn't be evaluated properly so
95    /// you have to assume it's a false result and you'll also have more information about why it
96    /// didn't validate.
97    fn evaluate(&self, data: &Value, ctx: PredicateContext) -> Result<bool, PredicateError>;
98
99    /// Evaluate the predicate against the provided JSON
100    fn test(&self, data: &Value, ctx: PredicateContext) -> bool {
101        self.evaluate(data, ctx).unwrap_or(false)
102    }
103}