1 | use crate::parser::model::{Comparable, Comparison, Literal, SingularQuery, SingularQuerySegment};
|
2 | use crate::query::queryable::Queryable;
|
3 | use crate::query::state::{Data, Pointer, State};
|
4 | use crate::query::Query;
|
5 |
|
6 | impl Query for Comparison {
|
7 | fn process<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T> {
|
8 | let root: &'a T = state.root;
|
9 | let (lhs: &Comparable, rhs: &Comparable) = self.vals();
|
10 | let lhs: State<'_, T> = lhs.process(state.clone());
|
11 | let rhs: State<'_, T> = rhs.process(state);
|
12 | match self {
|
13 | Comparison::Eq(..) => State::bool(b:eq(lhs, rhs), root),
|
14 | Comparison::Ne(..) => State::bool(!eq(lhs, rhs), root),
|
15 | Comparison::Gt(..) => State::bool(b:lt(lhs:rhs, rhs:lhs), root),
|
16 | Comparison::Gte(..) => State::bool(b:lt(lhs:rhs.clone(), rhs:lhs.clone()) || eq(lhs, rhs), root),
|
17 | Comparison::Lt(..) => State::bool(b:lt(lhs, rhs), root),
|
18 | Comparison::Lte(..) => State::bool(b:lt(lhs.clone(), rhs.clone()) || eq(lhs, rhs), root),
|
19 | }
|
20 | }
|
21 | }
|
22 |
|
23 | fn lt<'a, T: Queryable>(lhs: State<'a, T>, rhs: State<'a, T>) -> bool {
|
24 | let cmp: impl Fn(&T, &T) -> bool = |lhs: &T, rhs: &T| {
|
25 | let lhs_f64: Option = lhs.as_f64().or_else(|| lhs.as_i64().map(|v: i64| v as f64));
|
26 | let rhs_f64: Option = rhs.as_f64().or_else(|| rhs.as_i64().map(|v: i64| v as f64));
|
27 | if let (Some(lhs_num: f64), Some(rhs_num: f64)) = (lhs_f64, rhs_f64) {
|
28 | lhs_num < rhs_num
|
29 | } else if let (Some(lhs: &str), Some(rhs: &str)) = (lhs.as_str(), rhs.as_str()) {
|
30 | lhs < rhs
|
31 | } else {
|
32 | false
|
33 | }
|
34 | };
|
35 |
|
36 | match (lhs.data, rhs.data) {
|
37 | (Data::Value(lhs: T), Data::Value(rhs: T)) => cmp(&lhs, &rhs),
|
38 | (Data::Value(v: T), Data::Ref(p: Pointer<'_, T>)) => cmp(&v, rhs:p.inner),
|
39 | (Data::Ref(p: Pointer<'_, T>), Data::Value(v: T)) => cmp(lhs:p.inner, &v),
|
40 | (Data::Ref(lhs: Pointer<'_, T>), Data::Ref(rhs: Pointer<'_, T>)) => cmp(lhs.inner, rhs.inner),
|
41 | _ => false,
|
42 | }
|
43 | }
|
44 |
|
45 | fn eq<'a, T: Queryable>(lhs_state: State<'a, T>, rhs_state: State<'a, T>) -> bool {
|
46 | match (lhs_state.data, rhs_state.data) {
|
47 | (Data::Value(lhs: T), Data::Value(rhs: T)) => eq_json(&lhs, &rhs),
|
48 | (Data::Value(v: T), Data::Ref(p: Pointer<'_, T>)) => eq_json(&v, rhs:p.inner),
|
49 | (Data::Ref(p: Pointer<'_, T>), Data::Value(v: T)) => eq_json(&v, rhs:p.inner),
|
50 | (Data::Ref(lhs: Pointer<'_, T>), Data::Ref(rhs: Pointer<'_, T>)) => eq_json(lhs.inner, rhs.inner),
|
51 | (Data::Refs(lhs: Vec>), Data::Refs(rhs: Vec>)) => lhs == rhs,
|
52 | (Data::Ref(r: Pointer<'_, T>), Data::Refs(rhs: Vec>)) => eq_ref_to_array(r, &rhs),
|
53 | (Data::Nothing, Data::Nothing) => true,
|
54 | _ => false,
|
55 | }
|
56 | }
|
57 | /// Compare two JSON values for equality.
|
58 | /// For numbers, it should implement interoperability for integer and float
|
59 | fn eq_json<T: Queryable>(lhs: &T, rhs: &T) -> bool {
|
60 | let lhs_f64: Option = lhs.as_f64().or_else(|| lhs.as_i64().map(|v: i64| v as f64));
|
61 | let rhs_f64: Option = rhs.as_f64().or_else(|| rhs.as_i64().map(|v: i64| v as f64));
|
62 |
|
63 | if let (Some(lhs_num: f64), Some(rhs_num: f64)) = (lhs_f64, rhs_f64) {
|
64 | (lhs_num - rhs_num).abs() < f64::EPSILON
|
65 | } else {
|
66 | lhs == rhs
|
67 | }
|
68 | }
|
69 | fn eq_ref_to_array<T: Queryable>(r: Pointer<T>, rhs: &Vec<Pointer<T>>) -> bool {
|
70 | r.inner.as_array().map_or(default:false, |array: &Vec| {
|
71 | eq_arrays(lhs:array, &rhs.iter().map(|p: &Pointer<'_, T>| p.inner).collect::<Vec<_>>())
|
72 | })
|
73 | }
|
74 |
|
75 | fn eq_arrays<T: Queryable>(lhs: &Vec<T>, rhs: &Vec<&T>) -> bool {
|
76 | lhs.len() == rhs.len() && lhs.iter().zip(rhs.iter()).all(|(a: &T, b: &&T)| eq_json(lhs:a, *b))
|
77 | }
|
78 |
|
79 | #[cfg (test)]
|
80 | mod tests {
|
81 | use crate::parser::model::{
|
82 | Comparable, Comparison, Literal, SingularQuery, SingularQuerySegment,
|
83 | };
|
84 | use crate::query::state::{Data, Pointer, State};
|
85 | use crate::query::Query;
|
86 | use crate::singular_query;
|
87 | use crate::{cmp, comparable, lit, q_segment, q_segments};
|
88 | use serde_json::json;
|
89 | #[test ]
|
90 | fn eq_comp_val() {
|
91 | let data = json!({"key" : "value" });
|
92 | let state = State::root(&data);
|
93 |
|
94 | let comparison = Comparison::Eq(comparable!(lit!(s "key" )), comparable!(lit!(s "key" )));
|
95 | let result = comparison.process(state);
|
96 | assert_eq!(result.ok_val(), Some(json!(true)));
|
97 | }
|
98 |
|
99 | #[test ]
|
100 | fn eq_comp_ref() {
|
101 | let data = json!({"key" : "value" });
|
102 | let state = State::root(&data);
|
103 |
|
104 | let comparison = Comparison::Eq(
|
105 | comparable!(lit!(s "value" )),
|
106 | comparable!(> singular_query!(@ key)),
|
107 | );
|
108 |
|
109 | let result = comparison.process(state);
|
110 | assert_eq!(result.ok_val(), Some(json!(true)));
|
111 | }
|
112 |
|
113 | #[test ]
|
114 | fn eq_comp_queries() {
|
115 | let data = json!({"key" : "value" , "key2" : "value" });
|
116 | let state = State::root(&data);
|
117 |
|
118 | let comparison = Comparison::Eq(
|
119 | comparable!(> singular_query!(@ key)),
|
120 | comparable!(> singular_query!(key2)),
|
121 | );
|
122 | let result = comparison.process(state);
|
123 | assert_eq!(result.ok_val(), Some(json!(true)));
|
124 | }
|
125 |
|
126 | #[test ]
|
127 | fn neq_comp_val() {
|
128 | let data = json!({"key" : "value" });
|
129 | let state = State::root(&data);
|
130 |
|
131 | let comparison = Comparison::Ne(comparable!(lit!(s "key" )), comparable!(lit!(s "key" )));
|
132 | let result = comparison.process(state);
|
133 | assert_eq!(result.ok_val(), Some(json!(false)));
|
134 | }
|
135 |
|
136 | #[test ]
|
137 | fn less_than() {
|
138 | let data = json!({"key" : 3});
|
139 | let state = State::root(&data);
|
140 |
|
141 | let comparison = Comparison::Lt(
|
142 | comparable!(lit!(i 2)),
|
143 | comparable!(> singular_query!(@ key)),
|
144 | );
|
145 | let result = comparison.process(state);
|
146 | assert_eq!(result.ok_val(), Some(json!(true)));
|
147 | }
|
148 |
|
149 | #[test ]
|
150 | fn less_than_false() {
|
151 | let data = json!({"key" : 1});
|
152 | let state = State::root(&data);
|
153 |
|
154 | let comparison = Comparison::Lt(
|
155 | comparable!(lit!(i 2)),
|
156 | comparable!(> singular_query!(@ key)),
|
157 | );
|
158 | let result = comparison.process(state);
|
159 | assert_eq!(result.ok_val(), Some(json!(false)));
|
160 | }
|
161 |
|
162 | #[test ]
|
163 | fn less_true() {
|
164 | let data = json!({"key" : 1});
|
165 | let state = State::root(&data);
|
166 |
|
167 | let comparison = Comparison::Lt(
|
168 | comparable!(> singular_query!(@ key)),
|
169 | comparable!(lit!(i 2)),
|
170 | );
|
171 | let result = comparison.process(state);
|
172 | assert_eq!(result.ok_val(), Some(json!(true)));
|
173 | }
|
174 | }
|
175 | |