1use jql_parser::{
2 group::split,
3 parser::parse,
4 tokens::Token,
5};
6use rayon::prelude::*;
7use serde_json::{
8 Value,
9 json,
10};
11
12use crate::{
13 array::{
14 get_array_as_indexes,
15 get_array_indexes,
16 get_array_lenses,
17 get_array_range,
18 get_flattened_array,
19 },
20 errors::JqlRunnerError,
21 object::{
22 get_flattened_object,
23 get_object_as_keys,
24 get_object_indexes,
25 get_object_key,
26 get_object_multi_key,
27 get_object_range,
28 },
29};
30
31pub fn raw(input: &str, json: &Value) -> Result<Value, JqlRunnerError> {
39 if input.is_empty() {
40 return Err(JqlRunnerError::EmptyQueryError);
41 }
42
43 let tokens = parse(input)?;
44
45 token(&tokens, json)
46}
47
48pub fn token(tokens: &[Token], json: &Value) -> Result<Value, JqlRunnerError> {
56 let groups = split(tokens);
57
58 let result = groups
59 .par_iter()
60 .try_fold_with(vec![], |mut acc: Vec<Value>, group| {
61 acc.push(group_runner(group, json)?);
62
63 Ok::<Vec<Value>, JqlRunnerError>(acc)
64 })
65 .try_reduce(Vec::new, |mut a, b| {
66 a.extend(b);
67
68 Ok(a)
69 });
70
71 result.map(|group| {
72 if groups.len() == 1 {
73 json!(group[0])
74 } else {
75 json!(group)
76 }
77 })
78}
79
80pub(crate) fn group_runner(tokens: &[&Token], json: &Value) -> Result<Value, JqlRunnerError> {
85 tokens
86 .iter()
87 .try_fold((json.clone(), false), |mut outer_acc, &token| {
90 if outer_acc.1 {
91 let result = outer_acc
92 .0
93 .as_array_mut()
94 .unwrap()
96 .par_iter()
97 .try_fold_with(
98 (vec![], outer_acc.1),
99 |mut inner_acc: (Vec<Value>, bool), inner_value| {
100 let result = matcher((inner_value.clone(), outer_acc.1), token)?;
101
102 inner_acc.0.push(result.0);
103 inner_acc.1 = result.1;
104
105 Ok::<(Vec<Value>, bool), JqlRunnerError>(inner_acc)
106 },
107 )
108 .try_reduce(
109 || (vec![], false),
110 |mut a, b| {
111 a.0.extend(b.0);
112
113 Ok((a.0, b.1))
114 },
115 )?;
116
117 Ok((json!(result.0), result.1))
118 } else {
119 matcher(outer_acc, token)
120 }
121 })
122 .map(|(value, _)| value)
124}
125
126fn matcher(
130 (mut acc, mut piped): (Value, bool),
131 token: &Token,
132) -> Result<(Value, bool), JqlRunnerError> {
133 let result = match token {
134 Token::ArrayIndexSelector(indexes) => get_array_indexes(indexes, &acc),
135 Token::ArrayRangeSelector(range) => get_array_range(range, &mut acc),
136 Token::FlattenOperator => match acc {
137 Value::Array(_) => get_flattened_array(&acc),
138 Value::Object(_) => Ok(get_flattened_object(&acc)),
139 _ => Err(JqlRunnerError::FlattenError(acc)),
140 },
141 Token::KeyOperator => match acc {
142 Value::Array(_) => get_array_as_indexes(&acc),
143 Value::Object(_) => get_object_as_keys(&mut acc),
144 Value::Bool(bool) => Ok(json!(bool)),
146 Value::Number(number) => Ok(json!(number)),
147 Value::String(string) => Ok(json!(string)),
148 Value::Null => Ok(json!(null)),
149 },
150 Token::GroupSeparator => unreachable!(),
151 Token::KeySelector(key) => get_object_key(key, &acc),
152 Token::LensSelector(lenses) => get_array_lenses(lenses, &mut acc),
153 Token::MultiKeySelector(keys) => get_object_multi_key(keys, &mut acc),
154 Token::ObjectIndexSelector(indexes) => get_object_indexes(indexes, &mut acc),
155 Token::ObjectRangeSelector(range) => get_object_range(range, &mut acc),
156 Token::PipeInOperator => {
157 if !acc.is_array() {
158 return Err(JqlRunnerError::PipeInError(acc));
159 }
160
161 piped = true;
162
163 Ok(acc)
164 }
165 Token::PipeOutOperator => {
166 if !piped {
167 return Err(JqlRunnerError::PipeOutError);
168 }
169
170 piped = false;
171
172 Ok(acc)
173 }
174 Token::TruncateOperator => match acc {
175 Value::Array(_) => Ok(json!([])),
176 Value::Object(_) => Ok(json!({})),
177 Value::Bool(_) | Value::Number(_) | Value::String(_) | Value::Null => Ok(acc),
178 },
179 };
180
181 result.map(|value| (value, piped))
182}
183
184#[cfg(test)]
185mod tests {
186 use jql_parser::{
187 errors::JqlParserError,
188 tokens::{
189 Token,
190 View,
191 },
192 };
193 use serde_json::json;
194
195 use super::raw;
196 use crate::errors::JqlRunnerError;
197
198 #[test]
199 fn check_runner_empty_input_error() {
200 assert_eq!(raw("", &json!("")), Err(JqlRunnerError::EmptyQueryError));
201 }
202
203 #[test]
204 fn check_runner_parsing_error() {
205 assert_eq!(
206 raw(r#""a"b"#, &json!({ "a": 1 })),
207 Err(JqlRunnerError::ParsingError(JqlParserError::ParsingError {
208 tokens: [Token::KeySelector("a")].stringify(),
209 unparsed: "b".to_string(),
210 }))
211 );
212 }
213
214 #[test]
215 fn check_runner_no_key_found_error() {
216 let parent = json!({ "a": 1 });
217
218 assert_eq!(
219 raw(r#""b""#, &parent),
220 Err(JqlRunnerError::KeyNotFoundError {
221 key: "b".to_string(),
222 parent
223 })
224 );
225 }
226
227 #[test]
228 fn check_runner_index_not_found_error() {
229 let parent = json!(["a"]);
230
231 assert_eq!(
232 raw("[1]", &parent),
233 Err(JqlRunnerError::IndexOutOfBoundsError { index: 1, parent })
234 );
235 }
236
237 #[test]
238 fn check_runner_success() {
239 assert_eq!(
240 raw(r#""a","b""#, &json!({ "a": 1, "b": 2 })),
241 Ok(json!([1, 2]))
242 );
243 assert_eq!(raw(r#""a""b""#, &json!({ "a": { "b": 2 } })), Ok(json!(2)));
244 assert_eq!(
245 raw("[4,2,0]", &json!(["a", "b", "c", "d", "e"])),
246 Ok(json!(["e", "c", "a"]))
247 );
248 }
249
250 #[test]
251 fn check_runner_pipes() {
252 let value = json!({ "a": [{ "b": { "c": 1 } }, { "b": { "c": 2 }}]});
253
254 assert_eq!(raw(r#""a"|>"b""c"<|[1]"#, &value), Ok(json!(2)));
255 }
256
257 #[test]
258 fn check_runner_truncate() {
259 assert_eq!(raw(r#""a"!"#, &json!({ "a": [1, 2, 3] })), Ok(json!([])));
260 assert_eq!(raw(r#""a"!"#, &json!({ "a": { "b": 1 } })), Ok(json!({})));
261 assert_eq!(raw(r#""a"!"#, &json!({ "a": true })), Ok(json!(true)));
262 assert_eq!(raw(r#""a"!"#, &json!({ "a": 1 })), Ok(json!(1)));
263 assert_eq!(raw(r#""a"!"#, &json!({ "a": "b" })), Ok(json!("b")));
264 assert_eq!(raw(r#""a"!"#, &json!({ "a": null })), Ok(json!(null)));
265 assert_eq!(raw("!", &json!({ "a": null })), Ok(json!({})));
266 assert_eq!(
267 raw(r#""a"!"b""#, &json!({ "a": [1, 2, 3] })),
268 Err(JqlRunnerError::ParsingError(JqlParserError::TruncateError(
269 [
270 Token::KeySelector("a"),
271 Token::TruncateOperator,
272 Token::KeySelector("b")
273 ]
274 .stringify(),
275 )))
276 );
277 }
278
279 #[test]
280 fn check_runner_lens() {
281 let value = json!([
282 { "a": { "b": { "c": 1 }}},
283 { "a": { "b": { "c": 2 }}},
284 ]);
285
286 assert_eq!(
287 raw(r#"|={"a""b""c"=2}"#, &value),
288 Ok(json!([
289 { "a": { "b": { "c": 2 }}}
290 ]))
291 );
292 }
293
294 #[test]
295 fn check_runner_keys() {
296 let value = json!({ "a": { "b": { "c": { "d": 1 }}}});
297
298 assert_eq!(raw(r#""a""b""c"@"#, &value), Ok(json!(["d"])));
299 }
300}