1use pest::Parser;
6use pest_derive::Parser;
7
8pub mod ast;
9pub mod executor;
10pub mod executor_utils;
11pub mod validator;
12
13#[derive(Parser)]
14#[grammar = "parser/grammar.pest"]
15pub struct AQLParser;
16
17use crate::error::{AqlError, ErrorCode, Result};
18use ast::*;
19use serde_json::Value as JsonValue;
20use std::collections::HashMap;
21
22pub fn parse(input: &str) -> Result<Document> {
24 let pairs = AQLParser::parse(Rule::document, input).map_err(|e| {
25 let (line, col) = match e.line_col {
26 pest::error::LineColLocation::Pos((l, c)) => (l, c),
27 pest::error::LineColLocation::Span((l, c), _) => (l, c),
28 };
29
30 #[cfg(debug_assertions)]
32 eprintln!("Parse error details: {}", e);
33
34 let user_message = format!("Syntax error at line {}, column {}", line, col);
36
37 AqlError::new(ErrorCode::ProtocolError, user_message).with_location(line, col)
38 })?;
39
40 let mut operations = Vec::new();
41
42 for pair in pairs {
43 if pair.as_rule() == Rule::document {
44 for inner in pair.into_inner() {
45 match inner.as_rule() {
46 Rule::operation => {
47 if let Some(op) = parse_operation(inner)? {
48 operations.push(op);
49 }
50 }
51 Rule::fragment_definition => {
52 operations.push(Operation::FragmentDefinition(parse_fragment_definition(
53 inner,
54 )?));
55 }
56 _ => {}
57 }
58 }
59 }
60 }
61
62 Ok(Document { operations })
63}
64
65pub fn parse_with_variables(input: &str, variables: JsonValue) -> Result<Document> {
67 let mut doc = parse(input)?;
68
69 let vars: HashMap<String, Value> = if let JsonValue::Object(map) = variables {
70 map.into_iter()
71 .map(|(k, v)| (k, json_to_aql_value(v)))
72 .collect()
73 } else {
74 HashMap::new()
75 };
76
77 for op in &mut doc.operations {
78 match op {
79 Operation::Query(q) => q.variables_values = vars.clone(),
80 Operation::Mutation(m) => m.variables_values = vars.clone(),
81 Operation::Subscription(s) => s.variables_values = vars.clone(),
82 _ => {}
83 }
84 }
85
86 Ok(doc)
87}
88
89fn json_to_aql_value(json: JsonValue) -> Value {
90 match json {
91 JsonValue::Null => Value::Null,
92 JsonValue::Bool(b) => Value::Boolean(b),
93 JsonValue::Number(n) => {
94 if let Some(i) = n.as_i64() {
95 Value::Int(i)
96 } else if let Some(f) = n.as_f64() {
97 Value::Float(f)
98 } else {
99 Value::Null
100 }
101 }
102 JsonValue::String(s) => Value::String(s),
103 JsonValue::Array(arr) => Value::Array(arr.into_iter().map(json_to_aql_value).collect()),
104 JsonValue::Object(map) => Value::Object(
105 map.into_iter()
106 .map(|(k, v)| (k, json_to_aql_value(v)))
107 .collect(),
108 ),
109 }
110}
111
112fn parse_operation(pair: pest::iterators::Pair<Rule>) -> Result<Option<Operation>> {
113 match pair.as_rule() {
114 Rule::operation => {
115 for inner in pair.into_inner() {
116 return parse_operation(inner);
117 }
118 Ok(None)
119 }
120 Rule::query_operation => Ok(Some(Operation::Query(parse_query(pair)?))),
121 Rule::mutation_operation => Ok(Some(Operation::Mutation(parse_mutation(pair)?))),
122 Rule::subscription_operation => {
123 Ok(Some(Operation::Subscription(parse_subscription(pair)?)))
124 }
125 Rule::schema_operation => Ok(Some(Operation::Schema(parse_schema(pair)?))),
126 Rule::migration_operation => Ok(Some(Operation::Migration(parse_migration(pair)?))),
127 Rule::introspection_query => Ok(Some(Operation::Introspection(parse_introspection_query(
128 pair,
129 )?))),
130 Rule::EOI => Ok(None),
131 _ => Ok(None),
132 }
133}
134
135fn parse_query(pair: pest::iterators::Pair<Rule>) -> Result<Query> {
136 let mut name = None;
137 let mut variable_definitions = Vec::new();
138 let mut directives = Vec::new();
139 let mut selection_set = Vec::new();
140
141 for inner in pair.into_inner() {
142 match inner.as_rule() {
143 Rule::identifier => name = Some(inner.as_str().to_string()),
144 Rule::variable_definitions => variable_definitions = parse_variable_definitions(inner)?,
145 Rule::directives => directives = parse_directives(inner)?,
146 Rule::selection_set => selection_set = parse_selection_set(inner)?,
147 _ => {}
148 }
149 }
150
151 Ok(Query {
152 name,
153 variable_definitions,
154 directives,
155 selection_set,
156 variables_values: HashMap::new(),
157 })
158}
159
160fn parse_mutation(pair: pest::iterators::Pair<Rule>) -> Result<Mutation> {
161 let mut name = None;
162 let mut variable_definitions = Vec::new();
163 let mut directives = Vec::new();
164 let mut operations = Vec::new();
165
166 for inner in pair.into_inner() {
167 match inner.as_rule() {
168 Rule::identifier => name = Some(inner.as_str().to_string()),
169 Rule::variable_definitions => variable_definitions = parse_variable_definitions(inner)?,
170 Rule::directives => directives = parse_directives(inner)?,
171 Rule::mutation_set => operations = parse_mutation_set(inner)?,
172 _ => {}
173 }
174 }
175
176 Ok(Mutation {
177 name,
178 variable_definitions,
179 directives,
180 operations,
181 variables_values: HashMap::new(),
182 })
183}
184
185fn parse_subscription(pair: pest::iterators::Pair<Rule>) -> Result<Subscription> {
186 let mut name = None;
187 let mut variable_definitions = Vec::new();
188 let mut directives = Vec::new();
189 let mut selection_set = Vec::new();
190
191 for inner in pair.into_inner() {
192 match inner.as_rule() {
193 Rule::identifier => name = Some(inner.as_str().to_string()),
194 Rule::variable_definitions => variable_definitions = parse_variable_definitions(inner)?,
195 Rule::directives => directives = parse_directives(inner)?,
196 Rule::subscription_set => selection_set = parse_subscription_set(inner)?,
197 _ => {}
198 }
199 }
200
201 Ok(Subscription {
202 name,
203 variable_definitions,
204 directives,
205 selection_set,
206 variables_values: HashMap::new(),
207 })
208}
209
210fn parse_schema(pair: pest::iterators::Pair<Rule>) -> Result<Schema> {
211 let mut operations = Vec::new();
212 for inner in pair.into_inner() {
213 if inner.as_rule() == Rule::schema_definition {
214 for rule in inner.into_inner() {
215 match rule.as_rule() {
216 Rule::define_collection => operations.push(parse_define_collection(rule)?),
217 Rule::alter_collection => operations.push(parse_alter_collection(rule)?),
218 Rule::drop_collection => operations.push(parse_drop_collection(rule)?),
219 _ => {}
220 }
221 }
222 }
223 }
224 Ok(Schema { operations })
225}
226
227fn parse_define_collection(pair: pest::iterators::Pair<Rule>) -> Result<SchemaOp> {
228 let mut name = String::new();
229 let mut if_not_exists = false;
230 let mut fields = Vec::new();
231 let mut directives = Vec::new();
232
233 for inner in pair.into_inner() {
234 match inner.as_rule() {
235 Rule::identifier => name = inner.as_str().to_string(),
236 Rule::field_definition => fields.push(parse_field_definition(inner)?),
237 Rule::directives => directives = parse_directives(inner)?,
238 _ => {
239 if inner.as_str() == "if" {
240 if_not_exists = true;
242 }
243 }
244 }
245 }
246 Ok(SchemaOp::DefineCollection {
247 name,
248 if_not_exists,
249 fields,
250 directives,
251 })
252}
253
254fn parse_alter_collection(pair: pest::iterators::Pair<Rule>) -> Result<SchemaOp> {
255 let mut name = String::new();
256 let mut actions = Vec::new();
257
258 for inner in pair.into_inner() {
259 match inner.as_rule() {
260 Rule::identifier => name = inner.as_str().to_string(),
261 Rule::alter_action => actions.push(parse_alter_action(inner)?),
262 _ => {}
263 }
264 }
265 Ok(SchemaOp::AlterCollection { name, actions })
266}
267
268fn parse_alter_action(pair: pest::iterators::Pair<Rule>) -> Result<AlterAction> {
269 let input_str = pair.as_str().to_string();
270 for inner in pair.into_inner() {
271 match inner.as_rule() {
272 Rule::add_action => {
273 for field in inner.into_inner() {
274 if field.as_rule() == Rule::field_definition {
275 return Ok(AlterAction::AddField(parse_field_definition(field)?));
276 }
277 }
278 }
279 Rule::drop_action => {
280 for id in inner.into_inner() {
281 if id.as_rule() == Rule::identifier {
282 return Ok(AlterAction::DropField(id.as_str().to_string()));
283 }
284 }
285 }
286 Rule::rename_action => {
287 let mut ids = Vec::new();
288 for id in inner.into_inner() {
289 if id.as_rule() == Rule::identifier {
290 ids.push(id.as_str().to_string());
291 }
292 }
293 if ids.len() == 2 {
294 return Ok(AlterAction::RenameField {
295 from: ids[0].clone(),
296 to: ids[1].clone(),
297 });
298 }
299 }
300 Rule::modify_action => {
301 for field in inner.into_inner() {
302 if field.as_rule() == Rule::field_definition {
303 return Ok(AlterAction::ModifyField(parse_field_definition(field)?));
304 }
305 }
306 }
307 _ => {}
308 }
309 }
310
311 Err(AqlError::new(
312 ErrorCode::ProtocolError,
313 format!("Unknown alter action: {}", input_str),
314 ))
315}
316
317fn parse_drop_collection(pair: pest::iterators::Pair<Rule>) -> Result<SchemaOp> {
319 let mut name = String::new();
320 let mut if_exists = false;
321
322 for inner in pair.into_inner() {
323 match inner.as_rule() {
324 Rule::identifier => name = inner.as_str().to_string(),
325 _ => {
326 if inner.as_str() == "if" {
327 if_exists = true;
328 }
329 }
330 }
331 }
332 Ok(SchemaOp::DropCollection { name, if_exists })
333}
334
335fn parse_field_definition(pair: pest::iterators::Pair<Rule>) -> Result<FieldDef> {
336 let mut name = String::new();
337 let mut field_type = TypeAnnotation {
338 name: "String".to_string(),
339 is_array: false,
340 is_required: false,
341 };
342 let mut directives = Vec::new();
343
344 for inner in pair.into_inner() {
345 match inner.as_rule() {
346 Rule::identifier => name = inner.as_str().to_string(),
347 Rule::type_annotation => field_type = parse_type_annotation(inner)?,
348 Rule::directives => directives = parse_directives(inner)?,
349 _ => {}
350 }
351 }
352
353 Ok(FieldDef {
354 name,
355 field_type,
356 directives,
357 })
358}
359
360fn parse_migration(pair: pest::iterators::Pair<Rule>) -> Result<Migration> {
363 let mut steps = Vec::new();
364 for inner in pair.into_inner() {
365 if inner.as_rule() == Rule::migration_step {
366 steps.push(parse_migration_step(inner)?);
367 }
368 }
369 Ok(Migration { steps })
370}
371
372fn parse_migration_step(pair: pest::iterators::Pair<Rule>) -> Result<MigrationStep> {
373 let mut version = String::new();
374 let mut actions = Vec::new();
375
376 for inner in pair.into_inner() {
377 match inner.as_rule() {
378 Rule::migration_version => {
379 if let Some(s_pair) = inner.into_inner().next() {
381 let s = s_pair.as_str();
383 version = s[1..s.len() - 1].to_string();
384 }
385 }
386 Rule::migration_action => {
387 for act in inner.into_inner() {
388 match act.as_rule() {
389 Rule::define_collection => {
390 actions.push(MigrationAction::Schema(parse_define_collection(act)?))
391 }
392 Rule::alter_collection => {
393 actions.push(MigrationAction::Schema(parse_alter_collection(act)?))
394 }
395 Rule::drop_collection => {
396 actions.push(MigrationAction::Schema(parse_drop_collection(act)?))
397 }
398 Rule::data_migration => {
399 actions.push(MigrationAction::DataMigration(parse_data_migration(act)?))
400 }
401 _ => {}
402 }
403 }
404 }
405 _ => {}
406 }
407 }
408 Ok(MigrationStep { version, actions })
409}
410
411fn parse_data_migration(pair: pest::iterators::Pair<Rule>) -> Result<DataMigration> {
412 let mut collection = String::new();
413 let mut transforms = Vec::new();
414
415 for inner in pair.into_inner() {
416 match inner.as_rule() {
417 Rule::identifier => collection = inner.as_str().to_string(),
418 Rule::data_transform => transforms.push(parse_data_transform(inner)?),
419 _ => {}
420 }
421 }
422 Ok(DataMigration {
423 collection,
424 transforms,
425 })
426}
427
428fn parse_data_transform(pair: pest::iterators::Pair<Rule>) -> Result<DataTransform> {
429 let mut field = String::new();
430 let mut expression = String::new();
431 let mut filter = None;
432
433 for inner in pair.into_inner() {
434 match inner.as_rule() {
435 Rule::identifier => field = inner.as_str().to_string(),
436 Rule::expression => expression = inner.as_str().to_string(),
437 Rule::filter_object => {
438 let filter_value = parse_filter_object_to_value(inner)?;
440 filter = Some(value_to_filter(filter_value).map_err(|e| {
441 AqlError::new(
442 ErrorCode::FilterParseError,
443 format!("Failed to parse filter in data transform: {}", e),
444 )
445 })?);
446 }
447 _ => {}
448 }
449 }
450 Ok(DataTransform {
451 field,
452 expression,
453 filter,
454 })
455}
456
457fn parse_filter_object_to_value(pair: pest::iterators::Pair<Rule>) -> Result<Value> {
459 let mut map = HashMap::new();
460
461 for inner in pair.into_inner() {
462 if inner.as_rule() == Rule::filter_field_list {
463 for filter_field in inner.into_inner() {
464 if filter_field.as_rule() == Rule::filter_field {
465 parse_filter_field_to_map(filter_field, &mut map)?;
466 }
467 }
468 }
469 }
470
471 Ok(Value::Object(map))
472}
473
474fn parse_filter_field_to_map(
476 pair: pest::iterators::Pair<Rule>,
477 map: &mut HashMap<String, Value>,
478) -> Result<()> {
479 for inner in pair.into_inner() {
480 match inner.as_rule() {
481 Rule::logical_operator => {
482 parse_logical_operator_to_map(inner, map)?;
483 }
484 Rule::field_filter | Rule::nested_field_filter => {
485 let mut field_name = String::new();
486 let mut field_ops = HashMap::new();
487
488 for field_inner in inner.into_inner() {
489 match field_inner.as_rule() {
490 Rule::identifier => field_name = field_inner.as_str().to_string(),
491 Rule::string => {
492 let s = field_inner.as_str();
493 field_name = s[1..s.len() - 1].to_string();
494 }
495 Rule::filter_condition => {
496 parse_filter_condition_to_map(field_inner, &mut field_ops)?;
497 }
498 _ => {}
499 }
500 }
501
502 if !field_name.is_empty() {
503 map.insert(field_name, Value::Object(field_ops));
504 }
505 }
506 _ => {}
507 }
508 }
509 Ok(())
510}
511
512fn parse_logical_operator_to_map(
514 pair: pest::iterators::Pair<Rule>,
515 map: &mut HashMap<String, Value>,
516) -> Result<()> {
517 for inner in pair.into_inner() {
518 match inner.as_rule() {
519 Rule::and_operator => {
520 let mut filters = Vec::new();
521 for and_inner in inner.into_inner() {
522 if and_inner.as_rule() == Rule::filter_object {
523 filters.push(parse_filter_object_to_value(and_inner)?);
524 }
525 }
526 map.insert("and".to_string(), Value::Array(filters));
527 }
528 Rule::or_operator => {
529 let mut filters = Vec::new();
530 for or_inner in inner.into_inner() {
531 if or_inner.as_rule() == Rule::filter_object {
532 filters.push(parse_filter_object_to_value(or_inner)?);
533 }
534 }
535 map.insert("or".to_string(), Value::Array(filters));
536 }
537 Rule::not_operator => {
538 for not_inner in inner.into_inner() {
539 if not_inner.as_rule() == Rule::filter_object {
540 map.insert("not".to_string(), parse_filter_object_to_value(not_inner)?);
541 }
542 }
543 }
544 _ => {}
545 }
546 }
547 Ok(())
548}
549
550fn parse_filter_condition_to_map(
552 pair: pest::iterators::Pair<Rule>,
553 map: &mut HashMap<String, Value>,
554) -> Result<()> {
555 for inner in pair.into_inner() {
556 if inner.as_rule() == Rule::filter_operator_list {
557 for op in inner.into_inner() {
558 if op.as_rule() == Rule::filter_operator {
559 parse_filter_operator_to_map(op, map)?;
560 }
561 }
562 }
563 }
564 Ok(())
565}
566
567fn parse_filter_operator_to_map(
569 pair: pest::iterators::Pair<Rule>,
570 map: &mut HashMap<String, Value>,
571) -> Result<()> {
572 for inner in pair.into_inner() {
573 match inner.as_rule() {
574 Rule::eq_operator => {
575 for val in inner.into_inner() {
576 if val.as_rule() == Rule::value {
577 map.insert("eq".to_string(), parse_value(val)?);
578 }
579 }
580 }
581 Rule::ne_operator => {
582 for val in inner.into_inner() {
583 if val.as_rule() == Rule::value {
584 map.insert("ne".to_string(), parse_value(val)?);
585 }
586 }
587 }
588 Rule::gt_operator => {
589 for val in inner.into_inner() {
590 if val.as_rule() == Rule::value {
591 map.insert("gt".to_string(), parse_value(val)?);
592 }
593 }
594 }
595 Rule::gte_operator => {
596 for val in inner.into_inner() {
597 if val.as_rule() == Rule::value {
598 map.insert("gte".to_string(), parse_value(val)?);
599 }
600 }
601 }
602 Rule::lt_operator => {
603 for val in inner.into_inner() {
604 if val.as_rule() == Rule::value {
605 map.insert("lt".to_string(), parse_value(val)?);
606 }
607 }
608 }
609 Rule::lte_operator => {
610 for val in inner.into_inner() {
611 if val.as_rule() == Rule::value {
612 map.insert("lte".to_string(), parse_value(val)?);
613 }
614 }
615 }
616 Rule::in_operator => {
617 for val in inner.into_inner() {
618 if val.as_rule() == Rule::array {
619 map.insert("in".to_string(), parse_value(val)?);
620 }
621 }
622 }
623 Rule::nin_operator => {
624 for val in inner.into_inner() {
625 if val.as_rule() == Rule::array {
626 map.insert("nin".to_string(), parse_value(val)?);
627 }
628 }
629 }
630 Rule::contains_operator => {
631 for val in inner.into_inner() {
632 if val.as_rule() == Rule::value {
633 map.insert("contains".to_string(), parse_value(val)?);
634 }
635 }
636 }
637 Rule::starts_with_operator => {
638 for val in inner.into_inner() {
639 if val.as_rule() == Rule::value {
640 map.insert("startsWith".to_string(), parse_value(val)?);
641 }
642 }
643 }
644 Rule::ends_with_operator => {
645 for val in inner.into_inner() {
646 if val.as_rule() == Rule::value {
647 map.insert("endsWith".to_string(), parse_value(val)?);
648 }
649 }
650 }
651 Rule::is_null_operator => {
652 map.insert("isNull".to_string(), Value::Boolean(true));
653 }
654 Rule::is_not_null_operator => {
655 map.insert("isNotNull".to_string(), Value::Boolean(true));
656 }
657 _ => {}
658 }
659 }
660 Ok(())
661}
662
663fn parse_variable_definitions(
664 pair: pest::iterators::Pair<Rule>,
665) -> Result<Vec<VariableDefinition>> {
666 let mut definitions = Vec::new();
667 for inner in pair.into_inner() {
668 if inner.as_rule() == Rule::variable_definition {
669 definitions.push(parse_variable_definition(inner)?);
670 }
671 }
672 Ok(definitions)
673}
674
675fn parse_variable_definition(pair: pest::iterators::Pair<Rule>) -> Result<VariableDefinition> {
676 let mut name = String::new();
677 let mut var_type = TypeAnnotation {
678 name: "String".to_string(),
679 is_array: false,
680 is_required: false,
681 };
682 let mut default_value = None;
683
684 for inner in pair.into_inner() {
685 match inner.as_rule() {
686 Rule::variable => name = inner.as_str().trim_start_matches('$').to_string(),
687 Rule::type_annotation => var_type = parse_type_annotation(inner)?,
688 Rule::default_value => {
689 for val in inner.into_inner() {
690 if val.as_rule() == Rule::value {
691 default_value = Some(parse_value(val)?);
692 }
693 }
694 }
695 _ => {}
696 }
697 }
698
699 Ok(VariableDefinition {
700 name,
701 var_type,
702 default_value,
703 })
704}
705
706fn parse_type_annotation(pair: pest::iterators::Pair<Rule>) -> Result<TypeAnnotation> {
707 let mut name = String::new();
708 let mut is_array = false;
709 let mut is_required = false;
710
711 for inner in pair.into_inner() {
712 match inner.as_rule() {
713 Rule::type_name => name = inner.as_str().to_string(),
714 Rule::array_type => {
715 is_array = true;
716 for arr_inner in inner.into_inner() {
717 if arr_inner.as_rule() == Rule::type_annotation {
718 let inner_type = parse_type_annotation(arr_inner)?;
719 name = inner_type.name;
720 }
721 }
722 }
723 Rule::type_modifier => is_required = true,
724 _ => name = inner.as_str().to_string(),
725 }
726 }
727
728 Ok(TypeAnnotation {
729 name,
730 is_array,
731 is_required,
732 })
733}
734
735fn parse_directives(pair: pest::iterators::Pair<Rule>) -> Result<Vec<Directive>> {
736 let mut directives = Vec::new();
737 for inner in pair.into_inner() {
738 if inner.as_rule() == Rule::directive {
739 directives.push(parse_directive(inner)?);
740 }
741 }
742 Ok(directives)
743}
744
745fn parse_directive(pair: pest::iterators::Pair<Rule>) -> Result<Directive> {
746 let mut name = String::new();
747 let mut arguments = Vec::new();
748
749 for inner in pair.into_inner() {
750 match inner.as_rule() {
751 Rule::directive_name | Rule::identifier => name = inner.as_str().to_string(),
752 Rule::arguments => arguments = parse_arguments(inner)?,
753 _ => {}
754 }
755 }
756
757 Ok(Directive { name, arguments })
758}
759
760fn parse_selection_set(pair: pest::iterators::Pair<Rule>) -> Result<Vec<Selection>> {
761 let mut selections = Vec::new();
762 for inner in pair.into_inner() {
763 if inner.as_rule() == Rule::field {
764 selections.push(parse_selection(inner)?);
765 }
766 }
767 Ok(selections)
768}
769
770fn parse_subscription_set(pair: pest::iterators::Pair<Rule>) -> Result<Vec<Selection>> {
771 let mut selections = Vec::new();
772 for inner in pair.into_inner() {
773 if inner.as_rule() == Rule::subscription_field {
774 selections.push(parse_selection(inner)?);
775 }
776 }
777 Ok(selections)
778}
779
780fn parse_selection(pair: pest::iterators::Pair<Rule>) -> Result<Selection> {
782 let inner = pair.clone().into_inner().next().unwrap();
787
788 match inner.as_rule() {
789 Rule::fragment_spread => {
790 let name = inner.into_inner().next().unwrap().as_str().to_string();
791 return Ok(Selection::FragmentSpread(name));
792 }
793 Rule::inline_fragment => {
794 let mut type_condition = String::new();
795 let mut selection_set = Vec::new();
796 for child in inner.into_inner() {
797 match child.as_rule() {
798 Rule::identifier => type_condition = child.as_str().to_string(),
799 Rule::selection_set => selection_set = parse_selection_set(child)?,
800 _ => {}
801 }
802 }
803 return Ok(Selection::InlineFragment(ast::InlineFragment {
804 type_condition,
805 selection_set,
806 }));
807 }
808 _ => {
809 return Ok(Selection::Field(parse_field_inner(pair)?));
811 }
812 }
813}
814
815fn parse_field_inner(pair: pest::iterators::Pair<Rule>) -> Result<Field> {
817 let mut alias = None;
818 let mut name = String::new();
819 let mut arguments = Vec::new();
820 let mut directives = Vec::new();
821 let mut selection_set = Vec::new();
822
823 for inner in pair.into_inner() {
824 match inner.as_rule() {
825 Rule::alias_name => {
826 for alias_inner in inner.into_inner() {
827 if alias_inner.as_rule() == Rule::identifier {
828 alias = Some(alias_inner.as_str().to_string());
829 }
830 }
831 }
832 Rule::identifier => name = inner.as_str().to_string(),
833 Rule::arguments => arguments = parse_arguments(inner)?,
834 Rule::directives => directives = parse_directives(inner)?,
835 Rule::sub_selection => {
836 for sel in inner.into_inner() {
837 if sel.as_rule() == Rule::selection_set {
838 selection_set = parse_selection_set(sel)?;
839 }
840 }
841 }
842 Rule::aggregate_with_alias => {
843 name = "aggregate".to_string();
844 for sel in inner.into_inner() {
845 match sel.as_rule() {
846 Rule::alias_name => {
847 for alias_inner in sel.into_inner() {
848 if alias_inner.as_rule() == Rule::identifier {
849 alias = Some(alias_inner.as_str().to_string());
850 }
851 }
852 }
853 Rule::aggregate_field_list => {
854 for agg_field in sel.into_inner() {
855 if agg_field.as_rule() == Rule::aggregate_field {
856 selection_set
857 .push(Selection::Field(parse_aggregate_field(agg_field)?));
858 }
859 }
860 }
861 _ => {}
862 }
863 }
864 }
865 Rule::special_field_selection => {
866 for sel in inner.into_inner() {
867 match sel.as_rule() {
868 Rule::alias_name => {
869 for alias_inner in sel.into_inner() {
870 if alias_inner.as_rule() == Rule::identifier {
871 alias = Some(alias_inner.as_str().to_string());
872 }
873 }
874 }
875 Rule::group_by_selection => {
876 name = "groupBy".to_string();
877 }
878 Rule::lookup_selection => {
879 name = "lookup".to_string();
880 let lookup = parse_lookup_selection(sel)?;
881 arguments.push(ast::Argument {
882 name: "collection".to_string(),
883 value: ast::Value::String(lookup.collection),
884 });
885 arguments.push(ast::Argument {
886 name: "localField".to_string(),
887 value: ast::Value::String(lookup.local_field),
888 });
889 arguments.push(ast::Argument {
890 name: "foreignField".to_string(),
891 value: ast::Value::String(lookup.foreign_field),
892 });
893 if let Some(filter) = lookup.filter {
894 arguments.push(ast::Argument {
895 name: "where".to_string(),
896 value: filter_to_value(&filter),
897 });
898 }
899 selection_set = lookup.selection_set;
900 }
901 Rule::page_info_selection => {
902 name = "pageInfo".to_string();
903 }
904 Rule::edges_selection => {
905 name = "edges".to_string();
906 for edge_inner in sel.into_inner() {
907 if edge_inner.as_rule() == Rule::edge_fields {
908 for edge_field in edge_inner.into_inner() {
909 if edge_field.as_rule() == Rule::edge_field {
910 let edge_str = edge_field.as_str().trim();
911 if edge_str.starts_with("cursor") {
912 selection_set.push(Selection::Field(Field {
913 alias: None,
914 name: "cursor".to_string(),
915 arguments: Vec::new(),
916 directives: Vec::new(),
917 selection_set: Vec::new(),
918 }));
919 } else if edge_str.starts_with("node") {
920 let mut node_selection = Vec::new();
921 for node_inner in edge_field.into_inner() {
922 if node_inner.as_rule() == Rule::selection_set {
923 node_selection =
924 parse_selection_set(node_inner)?;
925 }
926 }
927 selection_set.push(Selection::Field(Field {
928 alias: None,
929 name: "node".to_string(),
930 arguments: Vec::new(),
931 directives: Vec::new(),
932 selection_set: node_selection,
933 }));
934 }
935 }
936 }
937 }
938 }
939 }
940 Rule::downsample_selection => {
941 name = "downsample".to_string();
942 }
943 _ => {}
944 }
945 }
946 }
947 _ => {}
948 }
949 }
950
951 Ok(Field {
952 alias,
953 name,
954 arguments,
955 directives,
956 selection_set,
957 })
958}
959
960fn parse_aggregate_field(pair: pest::iterators::Pair<Rule>) -> Result<Field> {
963 let mut name = String::new();
964 let mut alias = None;
965 let mut arguments = Vec::new();
966 let pair_str = pair.as_str().to_string();
967
968 for inner in pair.into_inner() {
969 match inner.as_rule() {
970 Rule::aggregate_field_alias => {
971 for alias_inner in inner.into_inner() {
973 if alias_inner.as_rule() == Rule::identifier {
974 alias = Some(alias_inner.as_str().to_string());
975 }
976 }
977 }
978 Rule::aggregate_field_value => {
979 let inner_str = inner.as_str().to_string();
981 for val_inner in inner.into_inner() {
982 match val_inner.as_rule() {
983 Rule::aggregate_function => {
984 for fn_inner in val_inner.into_inner() {
986 match fn_inner.as_rule() {
987 Rule::aggregate_name => {
988 name = fn_inner.as_str().to_string();
989 }
990 Rule::aggregate_args => {
991 let mut arg_name = String::new();
993 let mut arg_value = Value::Null;
994
995 for arg_inner in fn_inner.into_inner() {
996 match arg_inner.as_rule() {
997 Rule::string => {
998 let s = arg_inner.as_str();
999 arg_value = Value::String(
1000 s[1..s.len() - 1].to_string(),
1001 );
1002 if arg_name.is_empty() {
1003 arg_name = "field".to_string();
1004 }
1005 }
1006 Rule::array => {
1007 arg_value = parse_value(arg_inner)?;
1008 arg_name = "fields".to_string();
1009 }
1010 _ => {
1011 let text = arg_inner.as_str();
1013 if text == "field" || text == "fields" {
1014 arg_name = text.to_string();
1015 }
1016 }
1017 }
1018 }
1019
1020 if !arg_name.is_empty() && !matches!(arg_value, Value::Null)
1021 {
1022 arguments.push(Argument {
1023 name: arg_name,
1024 value: arg_value,
1025 });
1026 }
1027 }
1028 _ => {}
1029 }
1030 }
1031 }
1032 _ => {
1033 }
1035 }
1036 }
1037
1038 if name.is_empty() {
1040 let text = inner_str.trim();
1041 if text == "count" {
1042 name = "count".to_string();
1043 }
1044 }
1045 }
1046 _ => {}
1047 }
1048 }
1049
1050 if name.is_empty() {
1052 let text = pair_str.trim();
1053 if text == "count" || text.ends_with(": count") || text.contains("count") {
1054 name = "count".to_string();
1055 }
1056 }
1057
1058 Ok(Field {
1059 alias,
1060 name,
1061 arguments,
1062 directives: vec![],
1063 selection_set: vec![],
1064 })
1065}
1066
1067fn parse_mutation_set(pair: pest::iterators::Pair<Rule>) -> Result<Vec<MutationOperation>> {
1068 let mut operations = Vec::new();
1069 for inner in pair.into_inner() {
1070 if inner.as_rule() == Rule::mutation_field {
1071 operations.push(parse_mutation_field(inner)?);
1072 }
1073 }
1074 Ok(operations)
1075}
1076
1077fn parse_mutation_field(pair: pest::iterators::Pair<Rule>) -> Result<MutationOperation> {
1078 let mut alias = None;
1079 let mut operation = MutationOp::Insert {
1080 collection: String::new(),
1081 data: Value::Null,
1082 };
1083 let mut directives = Vec::new();
1084 let mut selection_set = Vec::new();
1085
1086 for inner in pair.into_inner() {
1087 match inner.as_rule() {
1088 Rule::alias_name => {
1089 for alias_inner in inner.into_inner() {
1090 if alias_inner.as_rule() == Rule::identifier {
1091 alias = Some(alias_inner.as_str().to_string());
1092 }
1093 }
1094 }
1095 Rule::mutation_call => {
1096 let (op, sel) = parse_mutation_call(inner)?;
1097 operation = op;
1098 selection_set = sel;
1099 }
1100 Rule::directives => directives = parse_directives(inner)?,
1101 _ => {}
1102 }
1103 }
1104
1105 Ok(MutationOperation {
1106 alias,
1107 operation,
1108 directives,
1109 selection_set,
1110 })
1111}
1112
1113fn parse_mutation_call(pair: pest::iterators::Pair<Rule>) -> Result<(MutationOp, Vec<Selection>)> {
1114 for inner in pair.into_inner() {
1115 match inner.as_rule() {
1116 Rule::insert_mutation => return parse_insert_mutation(inner),
1117 Rule::update_mutation => return parse_update_mutation(inner),
1118 Rule::delete_mutation => return parse_delete_mutation(inner),
1119 Rule::enqueue_job_mutation => return parse_enqueue_job_mutation(inner),
1120 Rule::transaction_block => return parse_transaction_block(inner),
1121 _ => {}
1122 }
1123 }
1124 Err(AqlError::new(
1125 ErrorCode::ProtocolError,
1126 "Unknown mutation type".to_string(),
1127 ))
1128}
1129
1130fn parse_insert_mutation(
1131 pair: pest::iterators::Pair<Rule>,
1132) -> Result<(MutationOp, Vec<Selection>)> {
1133 let mut collection = String::new();
1134 let mut data = Value::Null;
1135 let mut selection_set = Vec::new();
1136
1137 for inner in pair.into_inner() {
1138 match inner.as_rule() {
1139 Rule::insert_args => {
1140 for arg in parse_arguments_list(inner)? {
1141 match arg.name.as_str() {
1142 "collection" => {
1143 if let Value::String(s) = arg.value {
1144 collection = s;
1145 }
1146 }
1147 "data" => data = arg.value,
1148 _ => {}
1149 }
1150 }
1151 }
1152 Rule::sub_selection => {
1153 for sel in inner.into_inner() {
1154 if sel.as_rule() == Rule::selection_set {
1155 selection_set = parse_selection_set(sel)?;
1156 }
1157 }
1158 }
1159 _ => {}
1160 }
1161 }
1162
1163 Ok((MutationOp::Insert { collection, data }, selection_set))
1164}
1165
1166fn parse_update_mutation(
1167 pair: pest::iterators::Pair<Rule>,
1168) -> Result<(MutationOp, Vec<Selection>)> {
1169 let mut collection = String::new();
1170 let mut filter = None;
1171 let mut data = Value::Null;
1172 let mut selection_set = Vec::new();
1173
1174 for inner in pair.into_inner() {
1175 match inner.as_rule() {
1176 Rule::update_args => {
1177 for arg in parse_arguments_list(inner)? {
1178 match arg.name.as_str() {
1179 "collection" => {
1180 if let Value::String(s) = arg.value {
1181 collection = s;
1182 }
1183 }
1184 "where" => filter = Some(value_to_filter(arg.value)?),
1185 "data" | "set" => data = arg.value,
1186 _ => {}
1187 }
1188 }
1189 }
1190 Rule::sub_selection => {
1191 for sel in inner.into_inner() {
1192 if sel.as_rule() == Rule::selection_set {
1193 selection_set = parse_selection_set(sel)?;
1194 }
1195 }
1196 }
1197 _ => {}
1198 }
1199 }
1200
1201 Ok((
1202 MutationOp::Update {
1203 collection,
1204 filter,
1205 data,
1206 },
1207 selection_set,
1208 ))
1209}
1210
1211fn parse_delete_mutation(
1212 pair: pest::iterators::Pair<Rule>,
1213) -> Result<(MutationOp, Vec<Selection>)> {
1214 let mut collection = String::new();
1215 let mut filter = None;
1216 let mut selection_set = Vec::new();
1217
1218 for inner in pair.into_inner() {
1219 match inner.as_rule() {
1220 Rule::delete_args => {
1221 for arg in parse_arguments_list(inner)? {
1222 match arg.name.as_str() {
1223 "collection" => {
1224 if let Value::String(s) = arg.value {
1225 collection = s;
1226 }
1227 }
1228 "where" => filter = Some(value_to_filter(arg.value)?),
1229 _ => {}
1230 }
1231 }
1232 }
1233 Rule::sub_selection => {
1234 for sel in inner.into_inner() {
1235 if sel.as_rule() == Rule::selection_set {
1236 selection_set = parse_selection_set(sel)?;
1237 }
1238 }
1239 }
1240 _ => {}
1241 }
1242 }
1243
1244 Ok((MutationOp::Delete { collection, filter }, selection_set))
1245}
1246
1247fn parse_enqueue_job_mutation(
1248 pair: pest::iterators::Pair<Rule>,
1249) -> Result<(MutationOp, Vec<Selection>)> {
1250 let mut job_type = String::new();
1251 let mut payload = Value::Null;
1252 let mut priority = JobPriority::Normal;
1253 let mut scheduled_at = None;
1254 let mut max_retries = None;
1255 let mut selection_set = Vec::new();
1256
1257 for inner in pair.into_inner() {
1258 match inner.as_rule() {
1259 Rule::job_args => {
1260 for arg in parse_arguments_list(inner)? {
1261 match arg.name.as_str() {
1262 "jobType" => {
1263 if let Value::String(s) = arg.value {
1264 job_type = s;
1265 }
1266 }
1267 "payload" => payload = arg.value,
1268 "priority" => {
1269 if let Value::Enum(s) = arg.value {
1270 priority = match s.as_str() {
1271 "LOW" => JobPriority::Low,
1272 "HIGH" => JobPriority::High,
1273 "CRITICAL" => JobPriority::Critical,
1274 _ => JobPriority::Normal,
1275 };
1276 }
1277 }
1278 "scheduledAt" => {
1279 if let Value::String(s) = arg.value {
1280 scheduled_at = Some(s);
1281 }
1282 }
1283 "maxRetries" => {
1284 if let Value::Int(n) = arg.value {
1285 max_retries = Some(n as u32);
1286 }
1287 }
1288 _ => {}
1289 }
1290 }
1291 }
1292 Rule::sub_selection => {
1293 for sel in inner.into_inner() {
1294 if sel.as_rule() == Rule::selection_set {
1295 selection_set = parse_selection_set(sel)?;
1296 }
1297 }
1298 }
1299 _ => {}
1300 }
1301 }
1302
1303 Ok((
1304 MutationOp::EnqueueJob {
1305 job_type,
1306 payload,
1307 priority,
1308 scheduled_at,
1309 max_retries,
1310 },
1311 selection_set,
1312 ))
1313}
1314
1315fn parse_transaction_block(
1316 pair: pest::iterators::Pair<Rule>,
1317) -> Result<(MutationOp, Vec<Selection>)> {
1318 let mut operations = Vec::new();
1319 for inner in pair.into_inner() {
1320 if inner.as_rule() == Rule::mutation_set {
1321 operations = parse_mutation_set(inner)?;
1322 }
1323 }
1324 Ok((MutationOp::Transaction { operations }, Vec::new()))
1325}
1326
1327fn parse_arguments(pair: pest::iterators::Pair<Rule>) -> Result<Vec<Argument>> {
1328 let mut arguments = Vec::new();
1329 for inner in pair.into_inner() {
1330 match inner.as_rule() {
1331 Rule::argument_list => {
1332 for arg in inner.into_inner() {
1333 if arg.as_rule() == Rule::argument {
1334 arguments.push(parse_argument(arg)?);
1335 }
1336 }
1337 }
1338 Rule::argument => arguments.push(parse_argument(inner)?),
1339 _ => {}
1340 }
1341 }
1342 Ok(arguments)
1343}
1344
1345fn parse_arguments_list(pair: pest::iterators::Pair<Rule>) -> Result<Vec<Argument>> {
1346 let mut arguments = Vec::new();
1347 for inner in pair.into_inner() {
1348 if inner.as_rule() == Rule::argument {
1349 arguments.push(parse_argument(inner)?);
1350 }
1351 }
1352 Ok(arguments)
1353}
1354
1355fn parse_argument(pair: pest::iterators::Pair<Rule>) -> Result<Argument> {
1356 let mut name = String::new();
1357 let mut value = Value::Null;
1358
1359 for inner in pair.into_inner() {
1360 match inner.as_rule() {
1361 Rule::identifier => name = inner.as_str().to_string(),
1362 Rule::value => value = parse_value(inner)?,
1363 _ => {}
1364 }
1365 }
1366
1367 Ok(Argument { name, value })
1368}
1369
1370fn parse_value(pair: pest::iterators::Pair<Rule>) -> Result<Value> {
1371 match pair.as_rule() {
1372 Rule::value => {
1373 for inner in pair.into_inner() {
1374 return parse_value(inner);
1375 }
1376 Ok(Value::Null)
1377 }
1378 Rule::string => {
1379 let s = pair.as_str();
1380 let unquoted = if s.starts_with("\"\"\"") {
1381 &s[3..s.len() - 3]
1382 } else {
1383 &s[1..s.len() - 1]
1384 };
1385 Ok(Value::String(unquoted.to_string()))
1386 }
1387 Rule::number => {
1388 let s = pair.as_str();
1389 if s.contains('.') || s.contains('e') || s.contains('E') {
1390 Ok(Value::Float(s.parse().map_err(|e| {
1391 AqlError::new(ErrorCode::ProtocolError, format!("Invalid float: {}", e))
1392 })?))
1393 } else {
1394 Ok(Value::Int(s.parse().map_err(|e| {
1395 AqlError::new(ErrorCode::ProtocolError, format!("Invalid integer: {}", e))
1396 })?))
1397 }
1398 }
1399 Rule::boolean => Ok(Value::Boolean(pair.as_str() == "true")),
1400 Rule::null => Ok(Value::Null),
1401 Rule::variable => Ok(Value::Variable(
1402 pair.as_str().trim_start_matches('$').to_string(),
1403 )),
1404 Rule::enum_value => Ok(Value::Enum(pair.as_str().to_string())),
1405 Rule::array => {
1406 let mut values = Vec::new();
1407 for inner in pair.into_inner() {
1408 if inner.as_rule() == Rule::array_value_list {
1409 for val in inner.into_inner() {
1410 if val.as_rule() == Rule::value {
1411 values.push(parse_value(val)?);
1412 }
1413 }
1414 }
1415 }
1416 Ok(Value::Array(values))
1417 }
1418 Rule::object => {
1419 let mut map = HashMap::new();
1420 for inner in pair.into_inner() {
1421 if inner.as_rule() == Rule::object_field_list {
1422 for field in inner.into_inner() {
1423 if field.as_rule() == Rule::object_field {
1424 let (key, val) = parse_object_field(field)?;
1425 map.insert(key, val);
1426 }
1427 }
1428 }
1429 }
1430 Ok(Value::Object(map))
1431 }
1432 _ => Ok(Value::Null),
1433 }
1434}
1435
1436fn parse_object_field(pair: pest::iterators::Pair<Rule>) -> Result<(String, Value)> {
1437 let mut key = String::new();
1438 let mut value = Value::Null;
1439
1440 for inner in pair.into_inner() {
1441 match inner.as_rule() {
1442 Rule::identifier => key = inner.as_str().to_string(),
1443 Rule::string => {
1444 let s = inner.as_str();
1445 key = s[1..s.len() - 1].to_string();
1446 }
1447 Rule::value => value = parse_value(inner)?,
1448 _ => {}
1449 }
1450 }
1451
1452 Ok((key, value))
1453}
1454
1455fn value_to_filter(value: Value) -> Result<Filter> {
1456 match value {
1457 Value::Object(map) => {
1458 let mut filters = Vec::new();
1459 for (key, val) in map {
1460 match key.as_str() {
1461 "and" => {
1462 if let Value::Array(arr) = val {
1463 let sub: Result<Vec<_>> =
1464 arr.into_iter().map(value_to_filter).collect();
1465 filters.push(Filter::And(sub?));
1466 }
1467 }
1468 "or" => {
1469 if let Value::Array(arr) = val {
1470 let sub: Result<Vec<_>> =
1471 arr.into_iter().map(value_to_filter).collect();
1472 filters.push(Filter::Or(sub?));
1473 }
1474 }
1475 "not" => filters.push(Filter::Not(Box::new(value_to_filter(val)?))),
1476 field => {
1477 if let Value::Object(ops) = val {
1478 for (op, op_val) in ops {
1479 let f = match op.as_str() {
1480 "eq" => Filter::Eq(field.to_string(), op_val),
1481 "ne" => Filter::Ne(field.to_string(), op_val),
1482 "gt" => Filter::Gt(field.to_string(), op_val),
1483 "gte" => Filter::Gte(field.to_string(), op_val),
1484 "lt" => Filter::Lt(field.to_string(), op_val),
1485 "lte" => Filter::Lte(field.to_string(), op_val),
1486 "in" => Filter::In(field.to_string(), op_val),
1487 "nin" => Filter::NotIn(field.to_string(), op_val),
1488 "contains" => Filter::Contains(field.to_string(), op_val),
1489 "startsWith" => Filter::StartsWith(field.to_string(), op_val),
1490 "endsWith" => Filter::EndsWith(field.to_string(), op_val),
1491 "isNull" => Filter::IsNull(field.to_string()),
1492 "isNotNull" => Filter::IsNotNull(field.to_string()),
1493 _ => {
1494 return Err(AqlError::new(
1495 ErrorCode::ProtocolError,
1496 format!("Unknown filter operator: {}", op.as_str()),
1497 ));
1498 }
1499 };
1500 filters.push(f);
1501 }
1502 }
1503 }
1504 }
1505 }
1506 if filters.len() == 1 {
1507 Ok(filters.remove(0))
1508 } else {
1509 Ok(Filter::And(filters))
1510 }
1511 }
1512 _ => Err(AqlError::new(
1513 ErrorCode::ProtocolError,
1514 "Filter must be an object".to_string(),
1515 )),
1516 }
1517}
1518
1519fn filter_to_value(filter: &Filter) -> Value {
1521 use std::collections::HashMap;
1522 match filter {
1523 Filter::Eq(field, val) => {
1524 let mut inner = HashMap::new();
1525 inner.insert("eq".to_string(), val.clone());
1526 let mut outer = HashMap::new();
1527 outer.insert(field.clone(), Value::Object(inner));
1528 Value::Object(outer)
1529 }
1530 Filter::Ne(field, val) => {
1531 let mut inner = HashMap::new();
1532 inner.insert("ne".to_string(), val.clone());
1533 let mut outer = HashMap::new();
1534 outer.insert(field.clone(), Value::Object(inner));
1535 Value::Object(outer)
1536 }
1537 Filter::Gt(field, val) => {
1538 let mut inner = HashMap::new();
1539 inner.insert("gt".to_string(), val.clone());
1540 let mut outer = HashMap::new();
1541 outer.insert(field.clone(), Value::Object(inner));
1542 Value::Object(outer)
1543 }
1544 Filter::Gte(field, val) => {
1545 let mut inner = HashMap::new();
1546 inner.insert("gte".to_string(), val.clone());
1547 let mut outer = HashMap::new();
1548 outer.insert(field.clone(), Value::Object(inner));
1549 Value::Object(outer)
1550 }
1551 Filter::Lt(field, val) => {
1552 let mut inner = HashMap::new();
1553 inner.insert("lt".to_string(), val.clone());
1554 let mut outer = HashMap::new();
1555 outer.insert(field.clone(), Value::Object(inner));
1556 Value::Object(outer)
1557 }
1558 Filter::Lte(field, val) => {
1559 let mut inner = HashMap::new();
1560 inner.insert("lte".to_string(), val.clone());
1561 let mut outer = HashMap::new();
1562 outer.insert(field.clone(), Value::Object(inner));
1563 Value::Object(outer)
1564 }
1565 Filter::In(field, val) => {
1566 let mut inner = HashMap::new();
1567 inner.insert("in".to_string(), val.clone());
1568 let mut outer = HashMap::new();
1569 outer.insert(field.clone(), Value::Object(inner));
1570 Value::Object(outer)
1571 }
1572 Filter::NotIn(field, val) => {
1573 let mut inner = HashMap::new();
1574 inner.insert("nin".to_string(), val.clone());
1575 let mut outer = HashMap::new();
1576 outer.insert(field.clone(), Value::Object(inner));
1577 Value::Object(outer)
1578 }
1579 Filter::Contains(field, val) => {
1580 let mut inner = HashMap::new();
1581 inner.insert("contains".to_string(), val.clone());
1582 let mut outer = HashMap::new();
1583 outer.insert(field.clone(), Value::Object(inner));
1584 Value::Object(outer)
1585 }
1586 Filter::StartsWith(field, val) => {
1587 let mut inner = HashMap::new();
1588 inner.insert("startsWith".to_string(), val.clone());
1589 let mut outer = HashMap::new();
1590 outer.insert(field.clone(), Value::Object(inner));
1591 Value::Object(outer)
1592 }
1593 Filter::EndsWith(field, val) => {
1594 let mut inner = HashMap::new();
1595 inner.insert("endsWith".to_string(), val.clone());
1596 let mut outer = HashMap::new();
1597 outer.insert(field.clone(), Value::Object(inner));
1598 Value::Object(outer)
1599 }
1600 Filter::Matches(field, val) => {
1601 let mut inner = HashMap::new();
1602 inner.insert("matches".to_string(), val.clone());
1603 let mut outer = HashMap::new();
1604 outer.insert(field.clone(), Value::Object(inner));
1605 Value::Object(outer)
1606 }
1607 Filter::IsNull(field) => {
1608 let mut inner = HashMap::new();
1609 inner.insert("isNull".to_string(), Value::Boolean(true));
1610 let mut outer = HashMap::new();
1611 outer.insert(field.clone(), Value::Object(inner));
1612 Value::Object(outer)
1613 }
1614 Filter::IsNotNull(field) => {
1615 let mut inner = HashMap::new();
1616 inner.insert("isNotNull".to_string(), Value::Boolean(true));
1617 let mut outer = HashMap::new();
1618 outer.insert(field.clone(), Value::Object(inner));
1619 Value::Object(outer)
1620 }
1621 Filter::And(filters) => {
1622 let arr: Vec<Value> = filters.iter().map(filter_to_value).collect();
1623 let mut map = HashMap::new();
1624 map.insert("and".to_string(), Value::Array(arr));
1625 Value::Object(map)
1626 }
1627 Filter::Or(filters) => {
1628 let arr: Vec<Value> = filters.iter().map(filter_to_value).collect();
1629 let mut map = HashMap::new();
1630 map.insert("or".to_string(), Value::Array(arr));
1631 Value::Object(map)
1632 }
1633 Filter::Not(inner) => {
1634 let mut map = HashMap::new();
1635 map.insert("not".to_string(), filter_to_value(inner));
1636 Value::Object(map)
1637 }
1638 }
1639}
1640
1641fn parse_fragment_definition(pair: pest::iterators::Pair<Rule>) -> Result<ast::FragmentDef> {
1643 let mut name = String::new();
1644 let mut type_condition = String::new();
1645 let mut selection_set = Vec::new();
1646
1647 for inner in pair.into_inner() {
1648 match inner.as_rule() {
1649 Rule::identifier => {
1650 if name.is_empty() {
1651 name = inner.as_str().to_string();
1652 } else {
1653 type_condition = inner.as_str().to_string();
1654 }
1655 }
1656 Rule::selection_set => {
1657 selection_set = parse_selection_set(inner)?;
1658 }
1659 _ => {}
1660 }
1661 }
1662
1663 Ok(ast::FragmentDef {
1664 name,
1665 type_condition,
1666 selection_set,
1667 })
1668}
1669
1670fn parse_introspection_query(pair: pest::iterators::Pair<Rule>) -> Result<ast::IntrospectionQuery> {
1671 let mut arguments = Vec::new();
1672 let mut fields = Vec::new();
1673
1674 for inner in pair.into_inner() {
1675 match inner.as_rule() {
1676 Rule::arguments => {
1677 arguments = parse_arguments(inner)?;
1678 }
1679 Rule::introspection_fields => {
1680 for field in inner.into_inner() {
1681 if field.as_rule() == Rule::introspection_field {
1682 fields.push(field.as_str().to_string());
1683 }
1684 }
1685 }
1686 _ => {}
1687 }
1688 }
1689
1690 Ok(ast::IntrospectionQuery { arguments, fields })
1691}
1692
1693fn parse_lookup_selection(pair: pest::iterators::Pair<Rule>) -> Result<ast::LookupSelection> {
1694 let mut collection = String::new();
1695 let mut local_field = String::new();
1696 let mut foreign_field = String::new();
1697 let mut filter = None;
1698 let mut selection_set = Vec::new();
1699
1700 for inner in pair.into_inner() {
1701 match inner.as_rule() {
1702 Rule::lookup_args => {
1703 for arg in inner.into_inner() {
1704 match arg.as_rule() {
1705 Rule::string => {
1706 let s = arg.as_str();
1707 let unquoted = &s[1..s.len() - 1];
1708 if collection.is_empty() {
1709 collection = unquoted.to_string();
1710 } else if local_field.is_empty() {
1711 local_field = unquoted.to_string();
1712 } else if foreign_field.is_empty() {
1713 foreign_field = unquoted.to_string();
1714 }
1715 }
1716 Rule::filter_object => {
1717 if let Ok(filter_value) = parse_filter_object_to_value(arg) {
1718 filter = Some(value_to_filter(filter_value)?);
1719 }
1720 }
1721 _ => {}
1722 }
1723 }
1724 }
1725 Rule::sub_selection => {
1726 for sel in inner.into_inner() {
1727 if sel.as_rule() == Rule::selection_set {
1728 let fields = parse_selection_set(sel)?;
1729 selection_set = fields;
1730 }
1731 }
1732 }
1733 _ => {}
1734 }
1735 }
1736
1737 if collection.is_empty() || local_field.is_empty() || foreign_field.is_empty() {
1738 return Err(AqlError::new(
1739 ErrorCode::ProtocolError,
1740 "Lookup must specify collection, localField, and foreignField".to_string(),
1741 ));
1742 }
1743
1744 Ok(ast::LookupSelection {
1745 collection,
1746 local_field,
1747 foreign_field,
1748 filter,
1749 selection_set,
1750 })
1751}
1752
1753#[cfg(test)]
1754mod tests {
1755 use super::*;
1756
1757 #[test]
1758 fn test_parse_simple_query() {
1759 let query = r#"query { users { id name email } }"#;
1760 let result = parse(query);
1761 assert!(result.is_ok());
1762 let doc = result.unwrap();
1763 assert_eq!(doc.operations.len(), 1);
1764 }
1765
1766 #[test]
1767 fn test_parse_query_with_filter() {
1768 let query =
1769 r#"query GetActiveUsers { users(where: { active: { eq: true } }) { id name } }"#;
1770 let result = parse(query);
1771 assert!(result.is_ok());
1772 }
1773
1774 #[test]
1775 fn test_parse_mutation() {
1776 let query =
1777 r#"mutation { insertInto(collection: "users", data: { name: "John" }) { id } }"#;
1778 let result = parse(query);
1779 assert!(result.is_ok());
1780 }
1781
1782 #[test]
1783 fn test_parse_alter_collection() {
1784 let schema = r#"
1785 schema {
1786 alter collection users {
1787 add age: Int
1788 drop legacy_field
1789 rename name to full_name
1790 modify active: Boolean
1791 }
1792 }
1793 "#;
1794 let result = parse(schema);
1795 assert!(
1796 result.is_ok(),
1797 "Failed to parse alter collection: {:?}",
1798 result.err()
1799 );
1800
1801 let doc = result.unwrap();
1802 if let Operation::Schema(Schema { operations }) = &doc.operations[0] {
1803 if let SchemaOp::AlterCollection { name, actions } = &operations[0] {
1804 assert_eq!(name, "users");
1805 assert_eq!(actions.len(), 4);
1806
1807 match &actions[0] {
1809 AlterAction::AddField(field) => {
1810 assert_eq!(field.name, "age");
1811 assert_eq!(field.field_type.name, "Int");
1812 }
1813 _ => panic!("Expected AddField"),
1814 }
1815
1816 match &actions[1] {
1818 AlterAction::DropField(name) => assert_eq!(name, "legacy_field"),
1819 _ => panic!("Expected DropField"),
1820 }
1821
1822 match &actions[2] {
1824 AlterAction::RenameField { from, to } => {
1825 assert_eq!(from, "name");
1826 assert_eq!(to, "full_name");
1827 }
1828 _ => panic!("Expected RenameField"),
1829 }
1830
1831 match &actions[3] {
1833 AlterAction::ModifyField(field) => {
1834 assert_eq!(field.name, "active");
1835 assert_eq!(field.field_type.name, "Boolean");
1836 }
1837 _ => panic!("Expected ModifyField"),
1838 }
1839 } else {
1840 panic!("Expected AlterCollection operation");
1841 }
1842 } else {
1843 panic!("Expected Schema operation");
1844 }
1845 }
1846
1847 #[test]
1848 fn test_parse_fragment_definition() {
1849 let query = r#"
1850 fragment UserFields on User {
1851 id
1852 name
1853 email
1854 }
1855 "#;
1856 let result = parse(query);
1857 assert!(
1858 result.is_ok(),
1859 "Failed to parse fragment: {:?}",
1860 result.err()
1861 );
1862 let doc = result.unwrap();
1863 assert_eq!(doc.operations.len(), 1);
1864
1865 if let Operation::FragmentDefinition(frag) = &doc.operations[0] {
1866 assert_eq!(frag.name, "UserFields");
1867 assert_eq!(frag.type_condition, "User");
1868 assert_eq!(frag.selection_set.len(), 3);
1869 } else {
1870 panic!("Expected FragmentDefinition");
1871 }
1872 }
1873
1874 #[test]
1875 fn test_parse_introspection() {
1876 let query = r#"__schema { collections, fields }"#;
1877 let result = parse(query);
1878 assert!(
1879 result.is_ok(),
1880 "Failed to parse introspection: {:?}",
1881 result.err()
1882 );
1883 let doc = result.unwrap();
1884 assert_eq!(doc.operations.len(), 1);
1885
1886 if let Operation::Introspection(intro) = &doc.operations[0] {
1887 assert_eq!(intro.fields.len(), 2);
1888 } else {
1889 panic!("Expected Introspection");
1890 }
1891 }
1892
1893 #[test]
1894 fn test_parse_fragment_with_query() {
1895 let query = r#"
1896 fragment UserFields on User {
1897 id
1898 name
1899 }
1900
1901 query GetUsers {
1902 users {
1903 ...UserFields
1904 }
1905 }
1906 "#;
1907 let result = parse(query);
1908 assert!(
1909 result.is_ok(),
1910 "Failed to parse fragment with query: {:?}",
1911 result.err()
1912 );
1913 let doc = result.unwrap();
1914 assert_eq!(doc.operations.len(), 2);
1915 }
1916
1917 #[test]
1918 fn test_parse_aggregate_with_alias() {
1919 let query = r#"
1920 query {
1921 products {
1922 stats: aggregate {
1923 totalStock: sum(field: "stock")
1924 avgPrice: avg(field: "price")
1925 count
1926 }
1927 }
1928 }
1929 "#;
1930 let result = parse(query);
1931 assert!(
1932 result.is_ok(),
1933 "Failed to parse aggregate: {:?}",
1934 result.err()
1935 );
1936
1937 let doc = result.unwrap();
1938 if let Operation::Query(q) = &doc.operations[0] {
1939 if let Selection::Field(products_field) = &q.selection_set[0] {
1940 assert_eq!(products_field.name, "products");
1941
1942 if let Selection::Field(agg_field) = &products_field.selection_set[0] {
1944 assert_eq!(agg_field.alias, Some("stats".to_string()));
1945 assert_eq!(agg_field.name, "aggregate");
1946
1947 assert_eq!(agg_field.selection_set.len(), 3, "Expected 3 agg functions");
1949
1950 if let Selection::Field(total_stock) = &agg_field.selection_set[0] {
1952 assert_eq!(
1953 total_stock.alias,
1954 Some("totalStock".to_string()),
1955 "Expected totalStock alias"
1956 );
1957 assert_eq!(total_stock.name, "sum");
1958 assert_eq!(total_stock.arguments.len(), 1);
1959 assert_eq!(total_stock.arguments[0].name, "field");
1960 } else {
1961 panic!("Expected Field for total_stock");
1962 }
1963
1964 if let Selection::Field(count) = &agg_field.selection_set[2] {
1966 assert_eq!(count.name, "count");
1967 } else {
1968 panic!("Expected Field for count");
1969 }
1970 } else {
1971 panic!("Expected Field for aggregate");
1972 }
1973 } else {
1974 panic!("Expected Field for products");
1975 }
1976 } else {
1977 panic!("Expected Query operation");
1978 }
1979 }
1980
1981 #[test]
1982 fn test_parse_lookup_selection() {
1983 let query = r#"
1984 query {
1985 orders {
1986 id
1987 total
1988 lookup(collection: "users", localField: "user_id", foreignField: "id") {
1989 name
1990 email
1991 }
1992 }
1993 }
1994 "#;
1995 let result = parse(query);
1996 assert!(result.is_ok(), "Failed to parse lookup: {:?}", result.err());
1997
1998 let doc = result.unwrap();
1999 if let Operation::Query(q) = &doc.operations[0] {
2000 if let Selection::Field(orders_field) = &q.selection_set[0] {
2001 assert_eq!(orders_field.name, "orders");
2002
2003 let lookup_selection = orders_field
2005 .selection_set
2006 .iter()
2007 .find(|f| match f {
2008 Selection::Field(field) => field.name == "lookup",
2009 _ => false,
2010 })
2011 .expect("Should have lookup field");
2012
2013 if let Selection::Field(lookup_field) = lookup_selection {
2014 assert!(
2016 lookup_field
2017 .arguments
2018 .iter()
2019 .any(|a| a.name == "collection"),
2020 "Should have collection argument"
2021 );
2022 assert!(
2023 lookup_field
2024 .arguments
2025 .iter()
2026 .any(|a| a.name == "localField"),
2027 "Should have localField argument"
2028 );
2029 assert!(
2030 lookup_field
2031 .arguments
2032 .iter()
2033 .any(|a| a.name == "foreignField"),
2034 "Should have foreignField argument"
2035 );
2036
2037 let collection_arg = lookup_field
2039 .arguments
2040 .iter()
2041 .find(|a| a.name == "collection")
2042 .unwrap();
2043 if let ast::Value::String(val) = &collection_arg.value {
2044 assert_eq!(val, "users");
2045 } else {
2046 panic!("collection should be a string");
2047 }
2048
2049 assert_eq!(lookup_field.selection_set.len(), 2);
2051 if let Selection::Field(f) = &lookup_field.selection_set[0] {
2052 assert_eq!(f.name, "name");
2053 }
2054 if let Selection::Field(f) = &lookup_field.selection_set[1] {
2055 assert_eq!(f.name, "email");
2056 }
2057 } else {
2058 panic!("Lookup should be a Field");
2059 }
2060 } else {
2061 panic!("Expected Field for orders");
2062 }
2063 } else {
2064 panic!("Expected Query operation");
2065 }
2066 }
2067
2068 #[test]
2069 fn test_parse_lookup_with_filter() {
2070 let query = r#"
2071 query {
2072 orders {
2073 id
2074 lookup(collection: "users", localField: "user_id", foreignField: "id", where: { active: { eq: true } }) {
2075 name
2076 }
2077 }
2078 }
2079 "#;
2080 let result = parse(query);
2081 assert!(
2082 result.is_ok(),
2083 "Failed to parse lookup with filter: {:?}",
2084 result.err()
2085 );
2086
2087 let doc = result.unwrap();
2088 if let Operation::Query(q) = &doc.operations[0] {
2089 if let Selection::Field(orders_field) = &q.selection_set[0] {
2090 let lookup_selection = orders_field
2091 .selection_set
2092 .iter()
2093 .find(|f| match f {
2094 Selection::Field(field) => field.name == "lookup",
2095 _ => false,
2096 })
2097 .expect("Should have lookup field");
2098
2099 if let Selection::Field(lookup_field) = lookup_selection {
2100 assert!(
2102 lookup_field.arguments.iter().any(|a| a.name == "where"),
2103 "Should have where argument for filter"
2104 );
2105 } else {
2106 panic!("Expected Field for lookup");
2107 }
2108 } else {
2109 panic!("Expected Field for orders");
2110 }
2111 } else {
2112 panic!("Expected Query operation");
2113 }
2114 }
2115}