1use crate::parser::query::*;
2
3#[derive(Clone, Debug)]
4pub enum Transformed<T> {
5 Keep,
6 Replace(T),
7}
8
9#[derive(Clone, Debug)]
10pub enum TransformedValue<T> {
11 Keep,
12 Replace(T),
13}
14
15impl<T> TransformedValue<T> {
16 pub fn should_keep(&self) -> bool {
17 match self {
18 TransformedValue::Keep => true,
19 TransformedValue::Replace(_) => false,
20 }
21 }
22
23 pub fn replace_or_else<F>(self, f: F) -> T
24 where
25 F: FnOnce() -> T,
26 {
27 match self {
28 TransformedValue::Keep => f(),
29 TransformedValue::Replace(next_value) => next_value,
30 }
31 }
32}
33
34impl<T> From<TransformedValue<T>> for Transformed<T> {
35 fn from(val: TransformedValue<T>) -> Self {
36 match val {
37 TransformedValue::Keep => Transformed::Keep,
38 TransformedValue::Replace(replacement) => Transformed::Replace(replacement),
39 }
40 }
41}
42
43pub trait OperationTransformer<'a, T: Text<'a> + Clone> {
44 fn transform_document(
45 &mut self,
46 document: &Document<'a, T>,
47 ) -> TransformedValue<Document<'a, T>> {
48 self.default_transform_document(document)
49 }
50
51 fn default_transform_document(
52 &mut self,
53 document: &Document<'a, T>,
54 ) -> TransformedValue<Document<'a, T>> {
55 let mut next_document = Document {
56 definitions: Vec::new(),
57 };
58 let mut has_changes = false;
59 for definition in document.definitions.clone() {
60 match self.transform_definition(&definition) {
61 Transformed::Keep => next_document.definitions.push(definition),
62 Transformed::Replace(replacement) => {
63 has_changes = true;
64 next_document.definitions.push(replacement)
65 }
66 }
67 }
68 if has_changes {
69 TransformedValue::Replace(next_document)
70 } else {
71 TransformedValue::Keep
72 }
73 }
74
75 fn transform_definition(
76 &mut self,
77 definition: &Definition<'a, T>,
78 ) -> Transformed<Definition<'a, T>> {
79 self.default_transform_definition(definition)
80 }
81
82 fn default_transform_definition(
83 &mut self,
84 definition: &Definition<'a, T>,
85 ) -> Transformed<Definition<'a, T>> {
86 match definition {
87 Definition::Operation(operation) => match self.transform_operation(operation) {
88 Transformed::Keep => Transformed::Keep,
89 Transformed::Replace(replacement) => {
90 Transformed::Replace(Definition::Operation(replacement))
91 }
92 },
93 Definition::Fragment(fragment) => match self.transform_fragment(fragment) {
94 Transformed::Keep => Transformed::Keep,
95 Transformed::Replace(replacement) => {
96 Transformed::Replace(Definition::Fragment(replacement))
97 }
98 },
99 }
100 }
101
102 fn transform_operation(
103 &mut self,
104 operation: &OperationDefinition<'a, T>,
105 ) -> Transformed<OperationDefinition<'a, T>> {
106 self.default_transform_operation(operation)
107 }
108
109 fn default_transform_operation(
110 &mut self,
111 operation: &OperationDefinition<'a, T>,
112 ) -> Transformed<OperationDefinition<'a, T>> {
113 match operation {
114 OperationDefinition::Query(query) => match self.transform_query(query) {
115 Transformed::Keep => Transformed::Keep,
116 Transformed::Replace(replacement) => {
117 Transformed::Replace(OperationDefinition::Query(replacement))
118 }
119 },
120 OperationDefinition::Mutation(mutation) => match self.transform_mutation(mutation) {
121 Transformed::Keep => Transformed::Keep,
122 Transformed::Replace(replacement) => {
123 Transformed::Replace(OperationDefinition::Mutation(replacement))
124 }
125 },
126 OperationDefinition::Subscription(subscription) => {
127 match self.transform_subscription(subscription) {
128 Transformed::Keep => Transformed::Keep,
129 Transformed::Replace(replacement) => {
130 Transformed::Replace(OperationDefinition::Subscription(replacement))
131 }
132 }
133 }
134 OperationDefinition::SelectionSet(selection_set) => {
135 let items = self.transform_selection_set(selection_set);
136
137 if items.should_keep() {
138 return Transformed::Keep;
139 }
140
141 Transformed::Replace(OperationDefinition::SelectionSet(SelectionSet {
142 items: items.replace_or_else(|| selection_set.items.clone()),
143 span: selection_set.span,
144 }))
145 }
146 }
147 }
148
149 fn transform_query(&mut self, node: &Query<'a, T>) -> Transformed<Query<'a, T>> {
150 self.default_transform_query(node)
151 }
152
153 fn default_transform_query(&mut self, node: &Query<'a, T>) -> Transformed<Query<'a, T>> {
154 let selections = self.transform_selection_set(&node.selection_set);
155 let directives = self.transform_directives(&node.directives);
156 let variable_definitions = self.transform_variable_definitions(&node.variable_definitions);
157
158 if selections.should_keep()
159 && directives.should_keep()
160 && variable_definitions.should_keep()
161 {
162 return Transformed::Keep;
163 }
164
165 Transformed::Replace(Query {
166 directives: directives.replace_or_else(|| node.directives.clone()),
167 selection_set: SelectionSet {
168 items: selections.replace_or_else(|| node.selection_set.items.clone()),
169 span: node.selection_set.span,
170 },
171 variable_definitions: variable_definitions
172 .replace_or_else(|| node.variable_definitions.clone()),
173 position: node.position,
174 name: node.name.clone(),
175 })
176 }
177
178 fn transform_mutation(&mut self, node: &Mutation<'a, T>) -> Transformed<Mutation<'a, T>> {
179 self.default_transform_mutation(node)
180 }
181
182 fn default_transform_mutation(
183 &mut self,
184 node: &Mutation<'a, T>,
185 ) -> Transformed<Mutation<'a, T>> {
186 let selections = self.transform_selection_set(&node.selection_set);
187 let directives = self.transform_directives(&node.directives);
188 let variable_definitions = self.transform_variable_definitions(&node.variable_definitions);
189
190 if selections.should_keep()
191 && directives.should_keep()
192 && variable_definitions.should_keep()
193 {
194 return Transformed::Keep;
195 }
196
197 Transformed::Replace(Mutation {
198 directives: directives.replace_or_else(|| node.directives.clone()),
199 selection_set: SelectionSet {
200 items: selections.replace_or_else(|| node.selection_set.items.clone()),
201 span: node.selection_set.span,
202 },
203 variable_definitions: variable_definitions
204 .replace_or_else(|| node.variable_definitions.clone()),
205 position: node.position,
206 name: node.name.clone(),
207 })
208 }
209
210 fn transform_subscription(
211 &mut self,
212 node: &Subscription<'a, T>,
213 ) -> Transformed<Subscription<'a, T>> {
214 self.default_transform_subscription(node)
215 }
216
217 fn default_transform_subscription(
218 &mut self,
219 node: &Subscription<'a, T>,
220 ) -> Transformed<Subscription<'a, T>> {
221 let selections = self.transform_selection_set(&node.selection_set);
222 let directives = self.transform_directives(&node.directives);
223 let variable_definitions = self.transform_variable_definitions(&node.variable_definitions);
224
225 if selections.should_keep()
226 && directives.should_keep()
227 && variable_definitions.should_keep()
228 {
229 return Transformed::Keep;
230 }
231
232 Transformed::Replace(Subscription {
233 directives: directives.replace_or_else(|| node.directives.clone()),
234 selection_set: SelectionSet {
235 items: selections.replace_or_else(|| node.selection_set.items.clone()),
236 span: node.selection_set.span,
237 },
238 variable_definitions: variable_definitions
239 .replace_or_else(|| node.variable_definitions.clone()),
240 position: node.position,
241 name: node.name.clone(),
242 })
243 }
244
245 fn transform_fragment(
246 &mut self,
247 fragment: &FragmentDefinition<'a, T>,
248 ) -> Transformed<FragmentDefinition<'a, T>> {
249 self.default_transform_fragment(fragment)
250 }
251
252 fn default_transform_fragment(
253 &mut self,
254 fragment: &FragmentDefinition<'a, T>,
255 ) -> Transformed<FragmentDefinition<'a, T>> {
256 let selections = self.transform_selection_set(&fragment.selection_set);
257 let directives = self.transform_directives(&fragment.directives);
258
259 if selections.should_keep() && directives.should_keep() {
260 return Transformed::Keep;
261 }
262
263 Transformed::Replace(FragmentDefinition {
264 directives: directives.replace_or_else(|| fragment.directives.clone()),
265 selection_set: SelectionSet {
266 items: selections.replace_or_else(|| fragment.selection_set.items.clone()),
267 span: fragment.selection_set.span,
268 },
269 position: fragment.position,
270 name: fragment.name.clone(),
271 type_condition: fragment.type_condition.clone(),
272 })
273 }
274
275 fn transform_selection_set(
276 &mut self,
277 selections: &SelectionSet<'a, T>,
278 ) -> TransformedValue<Vec<Selection<'a, T>>> {
279 self.transform_list(&selections.items, Self::transform_selection)
280 }
281
282 fn transform_selection(
283 &mut self,
284 selection: &Selection<'a, T>,
285 ) -> Transformed<Selection<'a, T>> {
286 self.default_transform_selection(selection)
287 }
288
289 fn default_transform_selection(
290 &mut self,
291 selection: &Selection<'a, T>,
292 ) -> Transformed<Selection<'a, T>> {
293 match selection {
294 Selection::FragmentSpread(selection) => self.transform_fragment_spread(selection),
295 Selection::InlineFragment(selection) => self.transform_inline_fragment(selection),
296 Selection::Field(field) => self.transform_field(field),
297 }
298 }
299
300 fn transform_field(&mut self, field: &Field<'a, T>) -> Transformed<Selection<'a, T>> {
301 self.default_transform_field(field)
302 }
303
304 fn default_transform_field(&mut self, field: &Field<'a, T>) -> Transformed<Selection<'a, T>> {
305 let selection_set = self.transform_selection_set(&field.selection_set);
306 let arguments = self.transform_arguments(&field.arguments);
307 let directives = self.transform_directives(&field.directives);
308 if selection_set.should_keep() && arguments.should_keep() && directives.should_keep() {
309 return Transformed::Keep;
310 }
311 Transformed::Replace(Selection::Field(Field {
312 arguments: arguments.replace_or_else(|| field.arguments.clone()),
313 directives: directives.replace_or_else(|| field.directives.clone()),
314 selection_set: SelectionSet {
315 items: selection_set.replace_or_else(|| field.selection_set.items.clone()),
316 span: field.selection_set.span,
317 },
318 position: field.position,
319 alias: field.alias.clone(),
320 name: field.name.clone(),
321 }))
322 }
323
324 fn transform_fragment_spread(
325 &mut self,
326 spread: &FragmentSpread<'a, T>,
327 ) -> Transformed<Selection<'a, T>> {
328 self.default_transform_fragment_spread(spread)
329 }
330 fn default_transform_fragment_spread(
331 &mut self,
332 spread: &FragmentSpread<'a, T>,
333 ) -> Transformed<Selection<'a, T>> {
334 let directives = self.transform_directives(&spread.directives);
335 Transformed::Replace(Selection::FragmentSpread(FragmentSpread {
336 directives: directives.replace_or_else(|| spread.directives.clone()),
337 position: spread.position,
338 fragment_name: spread.fragment_name.clone(),
339 }))
340 }
341
342 fn transform_inline_fragment(
343 &mut self,
344 fragment: &InlineFragment<'a, T>,
345 ) -> Transformed<Selection<'a, T>> {
346 self.default_transform_inline_fragment(fragment)
347 }
348
349 fn default_transform_inline_fragment(
350 &mut self,
351 fragment: &InlineFragment<'a, T>,
352 ) -> Transformed<Selection<'a, T>> {
353 let selections = self.transform_selection_set(&fragment.selection_set);
354 let directives = self.transform_directives(&fragment.directives);
355
356 if selections.should_keep() && directives.should_keep() {
357 return Transformed::Keep;
358 }
359
360 Transformed::Replace(Selection::InlineFragment(InlineFragment {
361 position: fragment.position,
362 type_condition: fragment.type_condition.clone(),
363 directives: directives.replace_or_else(|| fragment.directives.clone()),
364 selection_set: SelectionSet {
365 span: fragment.selection_set.span,
366 items: selections.replace_or_else(|| fragment.selection_set.items.clone()),
367 },
368 }))
369 }
370
371 fn transform_directives(
372 &mut self,
373 directives: &[Directive<'a, T>],
374 ) -> TransformedValue<Vec<Directive<'a, T>>> {
375 self.transform_list(directives, Self::transform_directive)
376 }
377
378 fn transform_directive(
379 &mut self,
380 directive: &Directive<'a, T>,
381 ) -> Transformed<Directive<'a, T>> {
382 self.default_transform_directive(directive)
383 }
384
385 fn default_transform_directive(
386 &mut self,
387 directive: &Directive<'a, T>,
388 ) -> Transformed<Directive<'a, T>> {
389 let arguments = self.transform_arguments(&directive.arguments);
390 match arguments {
391 TransformedValue::Keep => Transformed::Keep,
392 TransformedValue::Replace(replacement) => Transformed::Replace(Directive {
393 position: directive.position,
394 name: directive.name.clone(),
395 arguments: replacement,
396 }),
397 }
398 }
399
400 fn transform_arguments(
401 &mut self,
402 arguments: &[(T::Value, Value<'a, T>)],
403 ) -> TransformedValue<Vec<(T::Value, Value<'a, T>)>> {
404 self.transform_list(arguments, Self::transform_argument)
405 }
406
407 fn transform_argument(
408 &mut self,
409 argument: &(T::Value, Value<'a, T>),
410 ) -> Transformed<(T::Value, Value<'a, T>)> {
411 self.default_transform_argument(argument)
412 }
413
414 fn default_transform_argument(
415 &mut self,
416 argument: &(T::Value, Value<'a, T>),
417 ) -> Transformed<(T::Value, Value<'a, T>)> {
418 let (name, value) = argument;
419
420 match self.transform_value(value) {
421 TransformedValue::Keep => Transformed::Keep,
422 TransformedValue::Replace(replacement) => {
423 Transformed::Replace((name.clone(), replacement))
424 }
425 }
426 }
427
428 fn transform_value(&mut self, value: &Value<'a, T>) -> TransformedValue<Value<'a, T>> {
429 self.default_transform_value(value)
430 }
431
432 fn default_transform_value(&mut self, value: &Value<'a, T>) -> TransformedValue<Value<'a, T>> {
433 match value {
434 Value::Variable(_) => TransformedValue::Keep,
435 Value::List(_) => TransformedValue::Keep,
436 Value::Object(_) => TransformedValue::Keep,
437 Value::Null => TransformedValue::Keep,
438 Value::Boolean(_) => TransformedValue::Keep,
439 Value::Enum(_) => TransformedValue::Keep,
440 Value::Int(_) => TransformedValue::Keep,
441 Value::Float(_) => TransformedValue::Keep,
442 Value::String(_) => TransformedValue::Keep,
443 }
444 }
445
446 fn transform_variable_definitions(
447 &mut self,
448 variable_definitions: &Vec<VariableDefinition<'a, T>>,
449 ) -> TransformedValue<Vec<VariableDefinition<'a, T>>> {
450 self.default_transform_variable_definitions(variable_definitions)
451 }
452
453 fn default_transform_variable_definitions(
454 &mut self,
455 variable_definitions: &[VariableDefinition<'a, T>],
456 ) -> TransformedValue<Vec<VariableDefinition<'a, T>>> {
457 self.transform_list(
458 variable_definitions,
459 Self::default_transform_variable_definition,
460 )
461 }
462
463 fn transform_variable_definition(
464 &mut self,
465 variable_definition: &VariableDefinition<'a, T>,
466 ) -> TransformedValue<VariableDefinition<'a, T>> {
467 self.default_transform_variable_definition(variable_definition)
468 }
469
470 fn default_transform_variable_definition(
471 &mut self,
472 variable_definition: &VariableDefinition<'a, T>,
473 ) -> TransformedValue<VariableDefinition<'a, T>> {
474 if let Some(value) = variable_definition.default_value.clone() {
475 let transformed_default_value = self.transform_value(&value);
476
477 if transformed_default_value.should_keep() {
478 return TransformedValue::Keep;
479 } else {
480 return TransformedValue::Replace(VariableDefinition {
481 position: variable_definition.position,
482 name: variable_definition.name.clone(),
483 var_type: variable_definition.var_type.clone(),
484 default_value: Some(transformed_default_value.replace_or_else(|| value)),
485 });
486 }
487 }
488
489 TransformedValue::Keep
490 }
491
492 fn transform_list<I, F, R>(&mut self, list: &[I], f: F) -> TransformedValue<Vec<I>>
493 where
494 I: Clone,
495 F: Fn(&mut Self, &I) -> R,
496 R: Into<Transformed<I>>,
497 {
498 let mut result = Vec::new();
499 let mut has_changes = false;
500 for (index, prev_item) in list.iter().enumerate() {
501 let next_item: Transformed<_> = f(self, prev_item).into();
502 match next_item {
503 Transformed::Keep => {
504 if has_changes {
505 result.push(prev_item.clone());
506 }
507 }
508 Transformed::Replace(next_item) => {
509 if !has_changes {
510 debug_assert!(result.capacity() == 0);
511 result.reserve(list.len());
512 result.extend(list.iter().take(index).cloned());
513 }
514 result.push(next_item);
515 has_changes = true;
516 }
517 }
518 }
519 if has_changes {
520 TransformedValue::Replace(result)
521 } else {
522 TransformedValue::Keep
523 }
524 }
525}
526
527#[cfg(test)]
528mod tests {
529 #[test]
530 fn transform_fields_and_values() {
531 use super::{
532 parse_query, Field, Number, OperationTransformer, Selection, SelectionSet, Text,
533 Transformed, TransformedValue, Value,
534 };
535
536 let raw = parse_query(
537 r#"
538 query example {
539 foo(bar: "baz")
540 }
541 "#,
542 )
543 .expect("Failed to parse query")
544 .into_static();
545
546 struct RemoveLiteralsTransformer {}
547
548 impl<'a, T: Text<'a> + Clone> OperationTransformer<'a, T> for RemoveLiteralsTransformer {
549 fn transform_value(&mut self, node: &Value<'a, T>) -> TransformedValue<Value<'a, T>> {
550 match node {
551 Value::Float(_) => TransformedValue::Replace(Value::Float(0.0)),
552 Value::Int(_) => TransformedValue::Replace(Value::Int(Number::from(0))),
553 Value::String(_) => TransformedValue::Replace(Value::String(String::from(""))),
554 Value::Variable(_) => TransformedValue::Keep,
555 Value::Boolean(_) => TransformedValue::Keep,
556 Value::Null => TransformedValue::Keep,
557 Value::Enum(_) => TransformedValue::Keep,
558 Value::List(val) => {
559 let items: Vec<Value<'a, T>> = val
560 .iter()
561 .map(|item| self.transform_value(item).replace_or_else(|| item.clone()))
562 .collect();
563
564 TransformedValue::Replace(Value::List(items))
565 }
566 Value::Object(fields) => {
567 let fields: std::collections::BTreeMap<T::Value, Value<'a, T>> = fields
568 .iter()
569 .map(|field| {
570 let (name, value) = field;
571 let new_value = self
572 .transform_value(value)
573 .replace_or_else(|| value.clone());
574 (name.clone(), new_value)
575 })
576 .collect();
577
578 TransformedValue::Replace(Value::Object(fields))
579 }
580 }
581 }
582
583 fn transform_field(
584 &mut self,
585 field: &crate::parser::query::Field<'a, T>,
586 ) -> Transformed<crate::parser::query::Selection<'a, T>> {
587 let selection_set = self.transform_selection_set(&field.selection_set);
588 let arguments = self.transform_arguments(&field.arguments);
589 let directives = self.transform_directives(&field.directives);
590
591 Transformed::Replace(Selection::Field(Field {
592 arguments: arguments.replace_or_else(|| field.arguments.clone()),
593 directives: directives.replace_or_else(|| field.directives.clone()),
594 selection_set: SelectionSet {
595 items: selection_set.replace_or_else(|| field.selection_set.items.clone()),
596 span: field.selection_set.span,
597 },
598 position: field.position,
599 alias: None,
600 name: field.name.clone(),
601 }))
602 }
603 }
604
605 let mut transformer = RemoveLiteralsTransformer {};
606 let transformed = transformer
607 .transform_document(&raw)
608 .replace_or_else(|| raw.clone());
609
610 assert_eq!(
611 format!("{transformed}"),
612 "query example {\n foo(bar: \"\")\n}\n".to_string()
613 );
614 }
615}