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