1use crate::parser::model::{Comparable, Comparison, Literal, SingularQuery, SingularQuerySegment};
2use crate::query::queryable::Queryable;
3use crate::query::state::{Data, Pointer, State};
4use crate::query::Query;
5
6impl Query for Comparison {
7 fn process<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T> {
8 let root = state.root;
9 let (lhs, rhs) = self.vals();
10 let lhs = lhs.process(state.clone());
11 let rhs = rhs.process(state);
12 match self {
13 Comparison::Eq(..) => State::bool(eq(lhs, rhs), root),
14 Comparison::Ne(..) => State::bool(!eq(lhs, rhs), root),
15 Comparison::Gt(..) => State::bool(lt(rhs, lhs), root),
16 Comparison::Gte(..) => State::bool(lt(rhs.clone(), lhs.clone()) || eq(lhs, rhs), root),
17 Comparison::Lt(..) => State::bool(lt(lhs, rhs), root),
18 Comparison::Lte(..) => State::bool(lt(lhs.clone(), rhs.clone()) || eq(lhs, rhs), root),
19 }
20 }
21}
22
23fn lt<'a, T: Queryable>(lhs: State<'a, T>, rhs: State<'a, T>) -> bool {
24 let cmp = |lhs: &T, rhs: &T| {
25 let lhs_f64 = lhs.as_f64().or_else(|| lhs.as_i64().map(|v| v as f64));
26 let rhs_f64 = rhs.as_f64().or_else(|| rhs.as_i64().map(|v| v as f64));
27 if let (Some(lhs_num), Some(rhs_num)) = (lhs_f64, rhs_f64) {
28 lhs_num < rhs_num
29 } else if let (Some(lhs), Some(rhs)) = (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), Data::Value(rhs)) => cmp(&lhs, &rhs),
38 (Data::Value(v), Data::Ref(p)) => cmp(&v, p.inner),
39 (Data::Ref(p), Data::Value(v)) => cmp(p.inner, &v),
40 (Data::Ref(lhs), Data::Ref(rhs)) => cmp(lhs.inner, rhs.inner),
41 _ => false,
42 }
43}
44
45fn 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), Data::Value(rhs)) => eq_json(&lhs, &rhs),
48 (Data::Value(v), Data::Ref(p)) => eq_json(&v, p.inner),
49 (Data::Ref(p), Data::Value(v)) => eq_json(&v, p.inner),
50 (Data::Ref(lhs), Data::Ref(rhs)) => eq_json(lhs.inner, rhs.inner),
51 (Data::Refs(lhs), Data::Refs(rhs)) => lhs == rhs,
52 (Data::Ref(r), Data::Refs(rhs)) => eq_ref_to_array(r, &rhs),
53 (Data::Nothing, Data::Nothing) => true,
54 _ => false,
55 }
56}
57fn eq_json<T: Queryable>(lhs: &T, rhs: &T) -> bool {
60 let lhs_f64 = lhs.as_f64().or_else(|| lhs.as_i64().map(|v| v as f64));
61 let rhs_f64 = rhs.as_f64().or_else(|| rhs.as_i64().map(|v| v as f64));
62
63 if let (Some(lhs_num), Some(rhs_num)) = (lhs_f64, rhs_f64) {
64 (lhs_num - rhs_num).abs() < f64::EPSILON
65 } else {
66 lhs == rhs
67 }
68}
69fn eq_ref_to_array<T: Queryable>(r: Pointer<T>, rhs: &Vec<Pointer<T>>) -> bool {
70 r.inner.as_array().map_or(false, |array| {
71 eq_arrays(array, &rhs.iter().map(|p| p.inner).collect::<Vec<_>>())
72 })
73}
74
75fn eq_arrays<T: Queryable>(lhs: &Vec<T>, rhs: &Vec<&T>) -> bool {
76 lhs.len() == rhs.len() && lhs.iter().zip(rhs.iter()).all(|(a, b)| eq_json(a, *b))
77}
78
79#[cfg(test)]
80mod 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}