1#![allow(missing_docs)] use std::cmp::min;
6use std::fmt;
7
8use num_traits::ToPrimitive;
9use once_cell::sync::Lazy;
10use regex::Captures;
11use regex::Regex;
12use serde::Deserialize;
13use serde::Serialize;
14use serde_json_bytes::ByteString;
15use serde_json_bytes::Entry;
16use serde_json_bytes::Map;
17pub(crate) use serde_json_bytes::Value;
18
19use crate::error::FetchError;
20use crate::spec::Schema;
21use crate::spec::TYPENAME;
22
23pub(crate) type Object = Map<ByteString, Value>;
25
26const FRAGMENT_PREFIX: &str = "... on ";
27
28static TYPE_CONDITIONS_REGEX: Lazy<Regex> = Lazy::new(|| {
29 Regex::new(r"\|\[(?<condition>.+?)?\]")
30 .expect("this regex to check for type conditions is valid")
31});
32
33fn extract_matched_conditions(caps: &Captures) -> TypeConditions {
35 caps.name("condition")
36 .map(|c| c.as_str().split(',').map(|s| s.to_string()).collect())
37 .unwrap_or_default()
38}
39
40fn split_path_element_and_type_conditions(s: &str) -> (String, Option<TypeConditions>) {
41 let mut type_conditions = None;
42 let path_element = TYPE_CONDITIONS_REGEX.replace(s, |caps: &Captures| {
43 type_conditions = Some(extract_matched_conditions(caps));
44 ""
45 });
46 (path_element.to_string(), type_conditions)
47}
48
49macro_rules! extract_key_value_from_object {
50 ($object:expr, $key:literal, $pattern:pat => $var:ident) => {{
51 match $object.remove($key) {
52 Some($pattern) => Ok(Some($var)),
53 None | Some(crate::json_ext::Value::Null) => Ok(None),
54 _ => Err(concat!("invalid type for key: ", $key)),
55 }
56 }};
57 ($object:expr, $key:literal) => {{
58 match $object.remove($key) {
59 None | Some(crate::json_ext::Value::Null) => None,
60 Some(value) => Some(value),
61 }
62 }};
63}
64
65macro_rules! ensure_array {
66 ($value:expr) => {{
67 match $value {
68 crate::json_ext::Value::Array(a) => Ok(a),
69 _ => Err("invalid type, expected an array"),
70 }
71 }};
72}
73
74macro_rules! ensure_object {
75 ($value:expr) => {{
76 match $value {
77 crate::json_ext::Value::Object(o) => Ok(o),
78 _ => Err("invalid type, expected an object"),
79 }
80 }};
81}
82
83#[doc(hidden)]
84pub(crate) trait ValueExt {
86 #[track_caller]
89 fn deep_merge(&mut self, other: Self);
90
91 #[track_caller]
95 fn type_aware_deep_merge(&mut self, other: Self, schema: &Schema);
96
97 #[cfg(test)]
101 fn eq_and_ordered(&self, other: &Self) -> bool;
102
103 #[track_caller]
106 #[cfg(test)]
107 fn is_subset(&self, superset: &Value) -> bool;
108
109 #[track_caller]
115 fn from_path(path: &Path, value: Value) -> Value;
116
117 #[track_caller]
119 fn insert(&mut self, path: &Path, value: Value) -> Result<(), FetchError>;
120
121 #[track_caller]
123 fn get_path<'a>(&'a self, schema: &Schema, path: &'a Path) -> Result<&'a Value, FetchError>;
124
125 #[track_caller]
130 fn select_values_and_paths<'a, F>(&'a self, schema: &Schema, path: &'a Path, f: F)
131 where
132 F: FnMut(&Path, &'a Value);
133
134 #[track_caller]
138 fn select_values_and_paths_mut<'a, F>(&'a mut self, schema: &Schema, path: &'a Path, f: F)
139 where
140 F: FnMut(&Path, &'a mut Value);
141
142 #[track_caller]
143 fn is_valid_float_input(&self) -> bool;
144
145 #[track_caller]
146 fn is_valid_int_input(&self) -> bool;
147
148 #[track_caller]
149 fn is_valid_id_input(&self) -> bool;
150
151 #[track_caller]
169 fn is_object_of_type(&self, schema: &Schema, maybe_type: &str) -> bool;
170
171 fn as_i32(&self) -> Option<i32>;
172}
173
174impl ValueExt for Value {
175 fn deep_merge(&mut self, other: Self) {
176 match (self, other) {
177 (Value::Object(a), Value::Object(b)) => {
178 for (key, value) in b.into_iter() {
179 match a.entry(key) {
180 Entry::Vacant(e) => {
181 e.insert(value);
182 }
183 Entry::Occupied(e) => {
184 e.into_mut().deep_merge(value);
185 }
186 }
187 }
188 }
189 (Value::Array(a), Value::Array(mut b)) => {
190 for (b_value, a_value) in b.drain(..min(a.len(), b.len())).zip(a.iter_mut()) {
191 a_value.deep_merge(b_value);
192 }
193
194 a.extend(b);
195 }
196 (_, Value::Null) => {}
197 (Value::Object(_), Value::Array(_)) => {
198 failfast_debug!("trying to replace an object with an array");
199 }
200 (Value::Array(_), Value::Object(_)) => {
201 failfast_debug!("trying to replace an array with an object");
202 }
203 (a, b) => {
204 if b != Value::Null {
205 *a = b;
206 }
207 }
208 }
209 }
210
211 fn type_aware_deep_merge(&mut self, other: Self, schema: &Schema) {
212 match (self, other) {
213 (Value::Object(a), Value::Object(b)) => {
214 for (key, value) in b.into_iter() {
215 let k = key.clone();
216 match a.entry(key) {
217 Entry::Vacant(e) => {
218 e.insert(value);
219 }
220 Entry::Occupied(e) => match (e.into_mut(), value) {
221 (Value::String(type1), Value::String(type2))
222 if k.as_str() == TYPENAME =>
223 {
224 if !schema.is_subtype(type2.as_str(), type1.as_str()) {
228 *type1 = type2;
229 }
230 }
231 (t, s) => t.type_aware_deep_merge(s, schema),
232 },
233 }
234 }
235 }
236 (Value::Array(a), Value::Array(mut b)) => {
237 for (b_value, a_value) in b.drain(..min(a.len(), b.len())).zip(a.iter_mut()) {
238 a_value.type_aware_deep_merge(b_value, schema);
239 }
240
241 a.extend(b);
242 }
243 (_, Value::Null) => {}
244 (Value::Object(_), Value::Array(_)) => {
245 failfast_debug!("trying to replace an object with an array");
246 }
247 (Value::Array(_), Value::Object(_)) => {
248 failfast_debug!("trying to replace an array with an object");
249 }
250 (a, b) => {
251 if b != Value::Null {
252 *a = b;
253 }
254 }
255 }
256 }
257
258 #[cfg(test)]
259 fn eq_and_ordered(&self, other: &Self) -> bool {
260 match (self, other) {
261 (Value::Object(a), Value::Object(b)) => {
262 let mut it_a = a.iter();
263 let mut it_b = b.iter();
264
265 loop {
266 match (it_a.next(), it_b.next()) {
267 (Some(_), None) | (None, Some(_)) => break false,
268 (None, None) => break true,
269 (Some((field_a, value_a)), Some((field_b, value_b)))
270 if field_a == field_b && ValueExt::eq_and_ordered(value_a, value_b) =>
271 {
272 continue;
273 }
274 (Some(_), Some(_)) => break false,
275 }
276 }
277 }
278 (Value::Array(a), Value::Array(b)) => {
279 let mut it_a = a.iter();
280 let mut it_b = b.iter();
281
282 loop {
283 match (it_a.next(), it_b.next()) {
284 (Some(_), None) | (None, Some(_)) => break false,
285 (None, None) => break true,
286 (Some(value_a), Some(value_b))
287 if ValueExt::eq_and_ordered(value_a, value_b) =>
288 {
289 continue;
290 }
291 (Some(_), Some(_)) => break false,
292 }
293 }
294 }
295 (a, b) => a == b,
296 }
297 }
298
299 #[cfg(test)]
300 fn is_subset(&self, superset: &Value) -> bool {
301 match (self, superset) {
302 (Value::Object(subset), Value::Object(superset)) => {
303 subset.iter().all(|(key, value)| {
304 if let Some(other) = superset.get(key) {
305 value.is_subset(other)
306 } else {
307 false
308 }
309 })
310 }
311 (Value::Array(subset), Value::Array(superset)) => {
312 subset.len() == superset.len()
313 && subset.iter().enumerate().all(|(index, value)| {
314 if let Some(other) = superset.get(index) {
315 value.is_subset(other)
316 } else {
317 false
318 }
319 })
320 }
321 (a, b) => a == b,
322 }
323 }
324
325 #[track_caller]
326 fn from_path(path: &Path, value: Value) -> Value {
327 let mut res_value = Value::default();
328 let mut current_node = &mut res_value;
329
330 for p in path.iter() {
331 match p {
332 PathElement::Flatten(_) => {
334 return res_value;
335 }
336
337 &PathElement::Index(index) => match current_node {
338 Value::Array(a) => {
339 for _ in 0..index {
340 a.push(Value::default());
341 }
342 a.push(Value::default());
343 current_node = a
344 .get_mut(index)
345 .expect("we just created the value at that index");
346 }
347 Value::Null => {
348 let mut a = Vec::new();
349 for _ in 0..index {
350 a.push(Value::default());
351 }
352 a.push(Value::default());
353
354 *current_node = Value::Array(a);
355 current_node = current_node
356 .as_array_mut()
357 .expect("current_node was just set to a Value::Array")
358 .get_mut(index)
359 .expect("we just created the value at that index");
360 }
361 other => unreachable!("unreachable node: {:?}", other),
362 },
363 PathElement::Key(k, _) => {
365 let mut m = Map::new();
366 m.insert(k.as_str(), Value::default());
367
368 *current_node = Value::Object(m);
369 current_node = current_node
370 .as_object_mut()
371 .expect("current_node was just set to a Value::Object")
372 .get_mut(k.as_str())
373 .expect("the value at that key was just inserted");
374 }
375 PathElement::Fragment(_) => {}
376 }
377 }
378
379 *current_node = value;
380 res_value
381 }
382
383 #[track_caller]
385 fn insert(&mut self, path: &Path, mut value: Value) -> Result<(), FetchError> {
386 let mut current_node = self;
387
388 for p in path.iter() {
389 match p {
390 PathElement::Flatten(type_conditions) => {
391 value = filter_type_conditions(value, type_conditions);
392 if current_node.is_null() {
393 let a = Vec::new();
394 *current_node = Value::Array(a);
395 } else if !current_node.is_array() {
396 return Err(FetchError::ExecutionPathNotFound {
397 reason: "expected an array".to_string(),
398 });
399 }
400 }
401
402 &PathElement::Index(index) => match current_node {
403 Value::Array(a) => {
404 for _ in a.len()..index + 1 {
406 a.push(Value::default());
407 }
408 current_node = a
409 .get_mut(index)
410 .expect("we just created the value at that index");
411 }
412 Value::Null => {
413 let mut a = Vec::new();
414 for _ in 0..index + 1 {
415 a.push(Value::default());
416 }
417
418 *current_node = Value::Array(a);
419 current_node = current_node
420 .as_array_mut()
421 .expect("current_node was just set to a Value::Array")
422 .get_mut(index)
423 .expect("we just created the value at that index");
424 }
425 _other => {
426 return Err(FetchError::ExecutionPathNotFound {
427 reason: "expected an array".to_string(),
428 });
429 }
430 },
431 PathElement::Key(k, type_conditions) => {
432 value = filter_type_conditions(value, type_conditions);
433 match current_node {
434 Value::Object(o) => {
435 current_node = o
436 .get_mut(k.as_str())
437 .expect("the value at that key was just inserted");
438 }
439 Value::Null => {
440 let mut m = Map::new();
441 m.insert(k.as_str(), Value::default());
442
443 *current_node = Value::Object(m);
444 current_node = current_node
445 .as_object_mut()
446 .expect("current_node was just set to a Value::Object")
447 .get_mut(k.as_str())
448 .expect("the value at that key was just inserted");
449 }
450 _other => {
451 return Err(FetchError::ExecutionPathNotFound {
452 reason: "expected an object".to_string(),
453 });
454 }
455 }
456 }
457 PathElement::Fragment(_) => {}
458 }
459 }
460
461 *current_node = value;
462 Ok(())
463 }
464
465 #[track_caller]
467 fn get_path<'a>(&'a self, schema: &Schema, path: &'a Path) -> Result<&'a Value, FetchError> {
468 let mut res = Err(FetchError::ExecutionPathNotFound {
469 reason: "value not found".to_string(),
470 });
471 iterate_path(
472 schema,
473 &mut Path::default(),
474 &path.0,
475 self,
476 &mut |_path, value| {
477 res = Ok(value);
478 },
479 );
480 res
481 }
482
483 #[track_caller]
484 fn select_values_and_paths<'a, F>(&'a self, schema: &Schema, path: &'a Path, mut f: F)
485 where
486 F: FnMut(&Path, &'a Value),
487 {
488 iterate_path(schema, &mut Path::default(), &path.0, self, &mut f)
489 }
490
491 #[track_caller]
492 fn select_values_and_paths_mut<'a, F>(&'a mut self, schema: &Schema, path: &'a Path, mut f: F)
493 where
494 F: FnMut(&Path, &'a mut Value),
495 {
496 iterate_path_mut(schema, &mut Path::default(), &path.0, self, &mut f)
497 }
498
499 #[track_caller]
500 fn is_valid_id_input(&self) -> bool {
501 match self {
503 Value::String(_) => true,
505 Value::Number(n) => n.is_i64() || n.is_u64(),
506 _ => false,
507 }
508 }
509
510 #[track_caller]
511 fn is_valid_float_input(&self) -> bool {
512 match self {
514 Value::Number(n) if n.is_f64() => true,
516 Value::Number(n) => n.is_i64(),
518 _ => false,
520 }
521 }
522
523 #[track_caller]
524 fn is_valid_int_input(&self) -> bool {
525 self.as_i64().and_then(|x| i32::try_from(x).ok()).is_some()
530 || self.as_u64().and_then(|x| i32::try_from(x).ok()).is_some()
531 }
532
533 #[track_caller]
534 fn is_object_of_type(&self, schema: &Schema, maybe_type: &str) -> bool {
535 self.is_object()
536 && self
537 .get(TYPENAME)
538 .and_then(|v| v.as_str())
539 .is_none_or(|typename| {
540 typename == maybe_type || schema.is_subtype(maybe_type, typename)
541 })
542 }
543
544 fn as_i32(&self) -> Option<i32> {
545 self.as_i64()?.to_i32()
546 }
547}
548
549fn filter_type_conditions(value: Value, type_conditions: &Option<TypeConditions>) -> Value {
550 if let Some(tc) = type_conditions {
551 match value {
552 Value::Object(ref o) => {
553 if let Some(Value::String(type_name)) = &o.get("__typename") {
554 if !tc.iter().any(|tc| tc.as_str() == type_name.as_str()) {
555 return Value::Null;
556 }
557 }
558 }
559 Value::Array(v) => {
560 return Value::Array(
561 v.into_iter()
562 .map(|v| filter_type_conditions(v, type_conditions))
563 .collect(),
564 );
565 }
566 _ => {}
567 }
568 }
569 value
570}
571
572fn iterate_path<'a, F>(
573 schema: &Schema,
574 parent: &mut Path,
575 path: &'a [PathElement],
576 data: &'a Value,
577 f: &mut F,
578) where
579 F: FnMut(&Path, &'a Value),
580{
581 match path.first() {
582 None => f(parent, data),
583 Some(PathElement::Flatten(type_conditions)) => {
584 if let Some(array) = data.as_array() {
585 for (i, value) in array.iter().enumerate() {
586 if let Some(tc) = type_conditions {
587 if !tc.is_empty() {
588 if let Value::Object(o) = value {
589 if let Some(Value::String(type_name)) = o.get("__typename") {
590 if tc.iter().any(|tc| tc.as_str() == type_name.as_str()) {
591 parent.push(PathElement::Index(i));
592 iterate_path(schema, parent, &path[1..], value, f);
593 parent.pop();
594 }
595 }
596 }
597
598 if let Value::Array(array) = value {
599 for (i, value) in array.iter().enumerate() {
600 if let Value::Object(o) = value {
601 if let Some(Value::String(type_name)) = o.get("__typename")
602 {
603 if tc.iter().any(|tc| tc.as_str() == type_name.as_str())
604 {
605 parent.push(PathElement::Index(i));
606 iterate_path(schema, parent, &path[1..], value, f);
607 parent.pop();
608 }
609 }
610 }
611 }
612 }
613 }
614 } else {
615 parent.push(PathElement::Index(i));
616 iterate_path(schema, parent, &path[1..], value, f);
617 parent.pop();
618 }
619 }
620 }
621 }
622 Some(PathElement::Index(i)) => {
623 if let Value::Array(a) = data {
624 if let Some(value) = a.get(*i) {
625 parent.push(PathElement::Index(*i));
626 iterate_path(schema, parent, &path[1..], value, f);
627 parent.pop();
628 }
629 }
630 }
631 Some(PathElement::Key(k, type_conditions)) => {
632 if let Some(tc) = type_conditions {
633 if !tc.is_empty() {
634 if let Value::Object(o) = data {
635 if let Some(value) = o.get(k.as_str()) {
636 if let Some(Value::String(type_name)) = value.get("__typename") {
637 if tc.iter().any(|tc| tc.as_str() == type_name.as_str()) {
638 parent.push(PathElement::Key(k.to_string(), None));
639 iterate_path(schema, parent, &path[1..], value, f);
640 parent.pop();
641 }
642 }
643 }
644 } else if let Value::Array(array) = data {
645 for (i, value) in array.iter().enumerate() {
646 if let Value::Object(o) = value {
647 if let Some(Value::String(type_name)) = o.get("__typename") {
648 if tc.iter().any(|tc| tc.as_str() == type_name.as_str()) {
649 parent.push(PathElement::Index(i));
650 iterate_path(schema, parent, path, value, f);
651 parent.pop();
652 }
653 }
654 }
655 }
656 }
657 }
658 } else if let Value::Object(o) = data {
659 if let Some(value) = o.get(k.as_str()) {
660 parent.push(PathElement::Key(k.to_string(), None));
661 iterate_path(schema, parent, &path[1..], value, f);
662 parent.pop();
663 }
664 } else if let Value::Array(array) = data {
665 for (i, value) in array.iter().enumerate() {
666 parent.push(PathElement::Index(i));
667 iterate_path(schema, parent, path, value, f);
668 parent.pop();
669 }
670 }
671 }
672 Some(PathElement::Fragment(name)) => {
673 if data.is_object_of_type(schema, name) {
674 iterate_path(schema, parent, &path[1..], data, f);
680 } else if let Value::Array(array) = data {
681 for (i, value) in array.iter().enumerate() {
682 parent.push(PathElement::Index(i));
683 iterate_path(schema, parent, path, value, f);
684 parent.pop();
685 }
686 }
687 }
688 }
689}
690
691fn iterate_path_mut<'a, F>(
692 schema: &Schema,
693 parent: &mut Path,
694 path: &'a [PathElement],
695 data: &'a mut Value,
696 f: &mut F,
697) where
698 F: FnMut(&Path, &'a mut Value),
699{
700 match path.first() {
701 None => f(parent, data),
702 Some(PathElement::Flatten(type_conditions)) => {
703 if let Some(array) = data.as_array_mut() {
704 for (i, value) in array.iter_mut().enumerate() {
705 if let Some(tc) = type_conditions {
706 if !tc.is_empty() {
707 if let Value::Object(o) = value {
708 if let Some(Value::String(type_name)) = o.get("__typename") {
709 if tc.iter().any(|tc| tc.as_str() == type_name.as_str()) {
710 parent.push(PathElement::Index(i));
711 iterate_path_mut(schema, parent, &path[1..], value, f);
712 parent.pop();
713 }
714 }
715 }
716 }
717 } else {
718 parent.push(PathElement::Index(i));
719 iterate_path_mut(schema, parent, &path[1..], value, f);
720 parent.pop();
721 }
722 }
723 }
724 }
725 Some(PathElement::Index(i)) => {
726 if let Value::Array(a) = data {
727 if let Some(value) = a.get_mut(*i) {
728 parent.push(PathElement::Index(*i));
729 iterate_path_mut(schema, parent, &path[1..], value, f);
730 parent.pop();
731 }
732 }
733 }
734 Some(PathElement::Key(k, type_conditions)) => {
735 if let Some(tc) = type_conditions {
736 if !tc.is_empty() {
737 if let Value::Object(o) = data {
738 if let Some(value) = o.get_mut(k.as_str()) {
739 if let Some(Value::String(type_name)) = value.get("__typename") {
740 if tc.iter().any(|tc| tc.as_str() == type_name.as_str()) {
741 parent.push(PathElement::Key(k.to_string(), None));
742 iterate_path_mut(schema, parent, &path[1..], value, f);
743 parent.pop();
744 }
745 }
746 }
747 } else if let Value::Array(array) = data {
748 for (i, value) in array.iter_mut().enumerate() {
749 if let Value::Object(o) = value {
750 if let Some(Value::String(type_name)) = o.get("__typename") {
751 if tc.iter().any(|tc| tc.as_str() == type_name.as_str()) {
752 parent.push(PathElement::Index(i));
753 iterate_path_mut(schema, parent, path, value, f);
754 parent.pop();
755 }
756 }
757 }
758 }
759 }
760 }
761 } else if let Value::Object(o) = data {
762 if let Some(value) = o.get_mut(k.as_str()) {
763 parent.push(PathElement::Key(k.to_string(), None));
764 iterate_path_mut(schema, parent, &path[1..], value, f);
765 parent.pop();
766 }
767 } else if let Value::Array(array) = data {
768 for (i, value) in array.iter_mut().enumerate() {
769 parent.push(PathElement::Index(i));
770 iterate_path_mut(schema, parent, path, value, f);
771 parent.pop();
772 }
773 }
774 }
775 Some(PathElement::Fragment(name)) => {
776 if data.is_object_of_type(schema, name) {
777 iterate_path_mut(schema, parent, &path[1..], data, f);
783 } else if let Value::Array(array) = data {
784 for (i, value) in array.iter_mut().enumerate() {
785 parent.push(PathElement::Index(i));
786 iterate_path_mut(schema, parent, path, value, f);
787 parent.pop();
788 }
789 }
790 }
791 }
792}
793
794#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
797#[serde(untagged)]
798pub enum PathElement {
799 #[serde(
801 deserialize_with = "deserialize_flatten",
802 serialize_with = "serialize_flatten"
803 )]
804 Flatten(Option<TypeConditions>),
805
806 Index(usize),
808
809 #[serde(
811 deserialize_with = "deserialize_fragment",
812 serialize_with = "serialize_fragment"
813 )]
814 Fragment(String),
815
816 #[serde(deserialize_with = "deserialize_key", serialize_with = "serialize_key")]
818 Key(String, Option<TypeConditions>),
819}
820
821type TypeConditions = Vec<String>;
822
823#[derive(Clone, Debug, Eq, PartialEq)]
824pub enum ResponsePathElement<'a> {
825 Index(usize),
827
828 Key(&'a str),
830}
831
832fn deserialize_flatten<'de, D>(deserializer: D) -> Result<Option<TypeConditions>, D::Error>
833where
834 D: serde::Deserializer<'de>,
835{
836 deserializer.deserialize_str(FlattenVisitor)
837}
838
839struct FlattenVisitor;
840
841impl serde::de::Visitor<'_> for FlattenVisitor {
842 type Value = Option<TypeConditions>;
843
844 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
845 write!(
846 formatter,
847 "a string that is '@', potentially followed by type conditions"
848 )
849 }
850
851 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
852 where
853 E: serde::de::Error,
854 {
855 let (path_element, type_conditions) = split_path_element_and_type_conditions(s);
856 if path_element == "@" {
857 Ok(type_conditions)
858 } else {
859 Err(serde::de::Error::invalid_value(
860 serde::de::Unexpected::Str(s),
861 &self,
862 ))
863 }
864 }
865}
866
867fn serialize_flatten<S>(
868 type_conditions: &Option<TypeConditions>,
869 serializer: S,
870) -> Result<S::Ok, S::Error>
871where
872 S: serde::Serializer,
873{
874 let tc_string = if let Some(c) = type_conditions {
875 format!("|[{}]", c.join(","))
876 } else {
877 "".to_string()
878 };
879 let res = format!("@{}", tc_string);
880 serializer.serialize_str(res.as_str())
881}
882
883fn deserialize_key<'de, D>(deserializer: D) -> Result<(String, Option<TypeConditions>), D::Error>
884where
885 D: serde::Deserializer<'de>,
886{
887 deserializer.deserialize_str(KeyVisitor)
888}
889
890struct KeyVisitor;
891
892impl serde::de::Visitor<'_> for KeyVisitor {
893 type Value = (String, Option<TypeConditions>);
894
895 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
896 write!(
897 formatter,
898 "a string, potentially followed by type conditions"
899 )
900 }
901
902 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
903 where
904 E: serde::de::Error,
905 {
906 Ok(split_path_element_and_type_conditions(s))
907 }
908}
909
910fn serialize_key<S>(
911 key: &String,
912 type_conditions: &Option<TypeConditions>,
913 serializer: S,
914) -> Result<S::Ok, S::Error>
915where
916 S: serde::Serializer,
917{
918 let tc_string = if let Some(c) = type_conditions {
919 format!("|[{}]", c.join(","))
920 } else {
921 "".to_string()
922 };
923 let res = format!("{}{}", key, tc_string);
924 serializer.serialize_str(res.as_str())
925}
926
927fn deserialize_fragment<'de, D>(deserializer: D) -> Result<String, D::Error>
928where
929 D: serde::Deserializer<'de>,
930{
931 deserializer.deserialize_str(FragmentVisitor)
932}
933
934struct FragmentVisitor;
935
936impl serde::de::Visitor<'_> for FragmentVisitor {
937 type Value = String;
938
939 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
940 write!(formatter, "a string that begins with '... on '")
941 }
942
943 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
944 where
945 E: serde::de::Error,
946 {
947 s.strip_prefix(FRAGMENT_PREFIX)
948 .map(|v| v.to_string())
949 .ok_or_else(|| serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self))
950 }
951}
952
953fn serialize_fragment<S>(name: &String, serializer: S) -> Result<S::Ok, S::Error>
954where
955 S: serde::Serializer,
956{
957 serializer.serialize_str(format!("{FRAGMENT_PREFIX}{name}").as_str())
958}
959
960fn flatten_from_str(s: &str) -> Result<PathElement, String> {
961 let (path_element, type_conditions) = split_path_element_and_type_conditions(s);
962 if path_element != "@" {
963 return Err("invalid flatten".to_string());
964 }
965 Ok(PathElement::Flatten(type_conditions))
966}
967
968fn key_from_str(s: &str) -> Result<PathElement, String> {
969 let (key, type_conditions) = split_path_element_and_type_conditions(s);
970 Ok(PathElement::Key(key, type_conditions))
971}
972
973#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
977#[serde(transparent)]
978pub struct Path(pub Vec<PathElement>);
979
980impl Path {
981 pub fn from_slice<T: AsRef<str>>(s: &[T]) -> Self {
982 Self(
983 s.iter()
984 .map(|x| x.as_ref())
985 .map(|s| {
986 if let Ok(index) = s.parse::<usize>() {
987 PathElement::Index(index)
988 } else if s.contains('@') {
989 flatten_from_str(s).unwrap_or(PathElement::Flatten(None))
990 } else {
991 s.strip_prefix(FRAGMENT_PREFIX).map_or_else(
992 || key_from_str(s).unwrap_or(PathElement::Key(s.to_string(), None)),
993 |name| PathElement::Fragment(name.to_string()),
994 )
995 }
996 })
997 .collect(),
998 )
999 }
1000
1001 pub fn from_response_slice(s: &[ResponsePathElement]) -> Self {
1002 Self(
1003 s.iter()
1004 .map(|x| match x {
1005 ResponsePathElement::Index(index) => PathElement::Index(*index),
1006 ResponsePathElement::Key(s) => PathElement::Key(s.to_string(), None),
1007 })
1008 .collect(),
1009 )
1010 }
1011
1012 pub fn iter(&self) -> impl Iterator<Item = &PathElement> {
1013 self.0.iter()
1014 }
1015
1016 pub fn is_empty(&self) -> bool {
1017 self.0.is_empty()
1018 }
1019
1020 pub fn len(&self) -> usize {
1021 self.0.len()
1022 }
1023
1024 pub fn empty() -> Path {
1025 Path(Default::default())
1026 }
1027
1028 pub fn parent(&self) -> Option<Path> {
1029 if self.is_empty() {
1030 None
1031 } else {
1032 Some(Path(self.iter().take(self.len() - 1).cloned().collect()))
1033 }
1034 }
1035
1036 pub fn join(&self, other: impl AsRef<Self>) -> Self {
1037 let other = other.as_ref();
1038 let mut new = Vec::with_capacity(self.len() + other.len());
1039 new.extend(self.iter().cloned());
1040 new.extend(other.iter().cloned());
1041 Path(new)
1042 }
1043
1044 pub fn push(&mut self, element: PathElement) {
1045 self.0.push(element)
1046 }
1047
1048 pub fn pop(&mut self) -> Option<PathElement> {
1049 self.0.pop()
1050 }
1051
1052 pub fn last(&self) -> Option<&PathElement> {
1053 self.0.last()
1054 }
1055
1056 pub fn last_key(&mut self) -> Option<String> {
1057 self.0.last().and_then(|elem| match elem {
1058 PathElement::Key(key, type_conditions) => {
1059 let mut tc = String::new();
1060 if let Some(c) = type_conditions {
1061 tc = format!("|[{}]", c.join(","));
1062 };
1063 Some(format!("{}{}", key, tc))
1064 }
1065 _ => None,
1066 })
1067 }
1068
1069 pub fn starts_with(&self, other: &Path) -> bool {
1070 self.0.starts_with(&other.0[..])
1071 }
1072
1073 pub fn remove_empty_key_root(&self) -> Self {
1075 if let Some(PathElement::Key(k, type_conditions)) = self.0.first() {
1076 if k.is_empty() && type_conditions.is_none() {
1077 return Path(self.iter().skip(1).cloned().collect());
1078 }
1079 }
1080
1081 self.clone()
1082 }
1083
1084 pub fn equal_if_flattened(&self, other: &Path) -> bool {
1087 if self.len() != other.len() {
1088 return false;
1089 }
1090
1091 for (elem1, elem2) in self.iter().zip(other.iter()) {
1092 let equal_elements = match (elem1, elem2) {
1093 (PathElement::Index(_), PathElement::Flatten(_)) => true,
1094 (PathElement::Flatten(_), PathElement::Index(_)) => true,
1095 (elem1, elem2) => elem1 == elem2,
1096 };
1097 if !equal_elements {
1098 return false;
1099 }
1100 }
1101
1102 true
1103 }
1104}
1105
1106impl FromIterator<PathElement> for Path {
1107 fn from_iter<T: IntoIterator<Item = PathElement>>(iter: T) -> Self {
1108 Path(iter.into_iter().collect())
1109 }
1110}
1111
1112impl AsRef<Path> for Path {
1113 fn as_ref(&self) -> &Path {
1114 self
1115 }
1116}
1117
1118impl<T> From<T> for Path
1119where
1120 T: AsRef<str>,
1121{
1122 fn from(s: T) -> Self {
1123 Self(
1124 s.as_ref()
1125 .split('/')
1126 .map(|s| {
1127 if let Ok(index) = s.parse::<usize>() {
1128 PathElement::Index(index)
1129 } else if s.contains('@') {
1130 flatten_from_str(s).unwrap()
1131 } else {
1132 s.strip_prefix(FRAGMENT_PREFIX).map_or_else(
1133 || key_from_str(s).unwrap_or(PathElement::Key(s.to_string(), None)),
1134 |name| PathElement::Fragment(name.to_string()),
1135 )
1136 }
1137 })
1138 .collect(),
1139 )
1140 }
1141}
1142
1143impl fmt::Display for Path {
1144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1145 for element in self.iter() {
1146 write!(f, "/")?;
1147 match element {
1148 PathElement::Index(index) => write!(f, "{index}")?,
1149 PathElement::Key(key, type_conditions) => {
1150 write!(f, "{key}")?;
1151 if let Some(c) = type_conditions {
1152 write!(f, "|[{}]", c.join(","))?;
1153 };
1154 }
1155 PathElement::Flatten(type_conditions) => {
1156 write!(f, "@")?;
1157 if let Some(c) = type_conditions {
1158 write!(f, "|[{}]", c.join(","))?;
1159 };
1160 }
1161 PathElement::Fragment(name) => {
1162 write!(f, "{FRAGMENT_PREFIX}{name}")?;
1163 }
1164 }
1165 }
1166 Ok(())
1167 }
1168}
1169
1170#[cfg(test)]
1171mod tests {
1172 use serde_json_bytes::json;
1173
1174 use super::*;
1175
1176 macro_rules! assert_is_subset {
1177 ($a:expr, $b:expr $(,)?) => {
1178 assert!($a.is_subset(&$b));
1179 };
1180 }
1181
1182 macro_rules! assert_is_not_subset {
1183 ($a:expr, $b:expr $(,)?) => {
1184 assert!(!$a.is_subset(&$b));
1185 };
1186 }
1187
1188 fn test_schema() -> Schema {
1192 Schema::parse(
1193 r#"
1194 schema
1195 @link(url: "https://specs.apollo.dev/link/v1.0")
1196 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1197 {
1198 query: Query
1199 }
1200
1201 directive @join__graph(name: String!, url: String!) on ENUM_VALUE
1202 directive @link( url: String as: String for: link__Purpose import: [link__Import]) repeatable on SCHEMA
1203 scalar link__Import
1204
1205 enum join__Graph {
1206 FAKE @join__graph(name:"fake" url: "http://localhost:4001/fake")
1207 }
1208
1209 enum link__Purpose {
1210 SECURITY
1211 EXECUTION
1212 }
1213
1214 type Query {
1215 i: [I]
1216 }
1217
1218 interface I {
1219 x: Int
1220 }
1221
1222 type A implements I {
1223 x: Int
1224 }
1225
1226 type B {
1227 y: Int
1228 }
1229 "#,
1230 &Default::default(),
1231 )
1232 .unwrap()
1233 }
1234
1235 fn select_values<'a>(
1236 schema: &Schema,
1237 path: &'a Path,
1238 data: &'a Value,
1239 ) -> Result<Vec<&'a Value>, FetchError> {
1240 let mut v = Vec::new();
1241 data.select_values_and_paths(schema, path, |_path, value| {
1242 v.push(value);
1243 });
1244 Ok(v)
1245 }
1246
1247 #[test]
1248 fn test_get_at_path() {
1249 let schema = test_schema();
1250 let json = json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}});
1251 let path = Path::from("obj/arr/1/prop1");
1252 let result = select_values(&schema, &path, &json).unwrap();
1253 assert_eq!(result, vec![&Value::Number(2.into())]);
1254 }
1255
1256 #[test]
1257 fn test_get_at_path_flatmap() {
1258 let schema = test_schema();
1259 let json = json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}});
1260 let path = Path::from("obj/arr/@");
1261 let result = select_values(&schema, &path, &json).unwrap();
1262 assert_eq!(result, vec![&json!({"prop1":1}), &json!({"prop1":2})]);
1263 }
1264
1265 #[test]
1266 fn test_get_at_path_flatmap_nested() {
1267 let schema = test_schema();
1268 let json = json!({
1269 "obj": {
1270 "arr": [
1271 {
1272 "prop1": [
1273 {"prop2": {"prop3": 1}, "prop4": -1},
1274 {"prop2": {"prop3": 2}, "prop4": -2},
1275 ],
1276 },
1277 {
1278 "prop1": [
1279 {"prop2": {"prop3": 3}, "prop4": -3},
1280 {"prop2": {"prop3": 4}, "prop4": -4},
1281 ],
1282 },
1283 ],
1284 },
1285 });
1286 let path = Path::from("obj/arr/@/prop1/@/prop2");
1287 let result = select_values(&schema, &path, &json).unwrap();
1288 assert_eq!(
1289 result,
1290 vec![
1291 &json!({"prop3":1}),
1292 &json!({"prop3":2}),
1293 &json!({"prop3":3}),
1294 &json!({"prop3":4}),
1295 ],
1296 );
1297 }
1298
1299 #[test]
1300 fn test_deep_merge() {
1301 let mut json = json!({"obj":{"arr":[{"prop1":1},{"prop2":2}]}});
1302 json.deep_merge(json!({"obj":{"arr":[{"prop1":2,"prop3":3},{"prop4":4}]}}));
1303 assert_eq!(
1304 json,
1305 json!({"obj":{"arr":[{"prop1":2, "prop3":3},{"prop2":2, "prop4":4}]}})
1306 );
1307 }
1308
1309 #[test]
1310 fn interface_typename_merging() {
1311 let schema = Schema::parse(
1312 r#"
1313 schema
1314 @link(url: "https://specs.apollo.dev/link/v1.0")
1315 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1316 {
1317 query: Query
1318 }
1319 directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
1320 directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false, resolvable: Boolean! = true, isInterfaceObject: Boolean! = false) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR
1321 directive @join__graph(name: String!, url: String!) on ENUM_VALUE
1322
1323 scalar link__Import
1324 scalar join__FieldSet
1325
1326 enum link__Purpose {
1327 SECURITY
1328 EXECUTION
1329 }
1330
1331 enum join__Graph {
1332 TEST @join__graph(name: "test", url: "http://localhost:4001/graphql")
1333 }
1334
1335 interface I {
1336 s: String
1337 }
1338
1339 type C implements I {
1340 s: String
1341 }
1342
1343 type Query {
1344 i: I
1345 }
1346 "#,
1347 &Default::default(),
1348 )
1349 .expect("valid schema");
1350 let mut response1 = json!({
1351 "__typename": "C"
1352 });
1353 let response2 = json!({
1354 "__typename": "I",
1355 "s": "data"
1356 });
1357
1358 response1.type_aware_deep_merge(response2, &schema);
1359
1360 assert_eq!(
1361 response1,
1362 json!({
1363 "__typename": "C",
1364 "s": "data"
1365 })
1366 );
1367 }
1368
1369 #[test]
1370 fn test_is_subset_eq() {
1371 assert_is_subset!(
1372 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1373 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1374 );
1375 }
1376
1377 #[test]
1378 fn test_is_subset_missing_pop() {
1379 assert_is_subset!(
1380 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1381 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1382 );
1383 }
1384
1385 #[test]
1386 fn test_is_subset_array_lengths_differ() {
1387 assert_is_not_subset!(
1388 json!({"obj":{"arr":[{"prop1":1}]}}),
1389 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1390 );
1391 }
1392
1393 #[test]
1394 fn test_is_subset_extra_prop() {
1395 assert_is_not_subset!(
1396 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1397 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1398 );
1399 }
1400
1401 #[test]
1402 fn eq_and_ordered() {
1403 assert!(json!([1, 2, 3]).eq_and_ordered(&json!([1, 2, 3])));
1405 assert!(!json!([1, 3, 2]).eq_and_ordered(&json!([1, 2, 3])));
1406
1407 assert!(json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1409 assert!(!json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":3})));
1410 assert!(!json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":2,"baz":3})));
1411 assert!(!json!({"foo":1,"bar":2,"baz":3}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1412 assert!(!json!({"bar":2,"foo":1}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1413
1414 assert!(json!({"baz":{"foo":1,"bar":2}}).eq_and_ordered(&json!({"baz":{"foo":1,"bar":2}})));
1416 assert!(
1417 !json!({"baz":{"bar":2,"foo":1}}).eq_and_ordered(&json!({"baz":{"foo":1,"bar":2}}))
1418 );
1419 assert!(!json!([1,{"bar":2,"foo":1},2]).eq_and_ordered(&json!([1,{"foo":1,"bar":2},2])));
1420 }
1421
1422 #[test]
1423 fn test_from_path() {
1424 let json = json!([{"prop1":1},{"prop1":2}]);
1425 let path = Path::from("obj/arr");
1426 let result = Value::from_path(&path, json);
1427 assert_eq!(result, json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}}));
1428 }
1429
1430 #[test]
1431 fn test_from_path_index() {
1432 let json = json!({"prop1":1});
1433 let path = Path::from("obj/arr/1");
1434 let result = Value::from_path(&path, json);
1435 assert_eq!(result, json!({"obj":{"arr":[null, {"prop1":1}]}}));
1436 }
1437
1438 #[test]
1439 fn test_from_path_flatten() {
1440 let json = json!({"prop1":1});
1441 let path = Path::from("obj/arr/@/obj2");
1442 let result = Value::from_path(&path, json);
1443 assert_eq!(result, json!({"obj":{"arr":null}}));
1444 }
1445
1446 #[test]
1447 fn test_is_object_of_type() {
1448 let schema = test_schema();
1449
1450 assert!(json!({ "__typename": "A", "x": "42"}).is_object_of_type(&schema, "A"));
1452
1453 assert!(json!({ "__typename": "A", "x": "42"}).is_object_of_type(&schema, "I"));
1455
1456 assert!(json!({ "x": "42"}).is_object_of_type(&schema, "A"));
1458
1459 assert!(!json!([{ "__typename": "A", "x": "42"}]).is_object_of_type(&schema, "A"));
1461 assert!(!json!("foo").is_object_of_type(&schema, "I"));
1462 assert!(!json!(42).is_object_of_type(&schema, "I"));
1463
1464 assert!(!json!({ "__typename": "B", "y": "42"}).is_object_of_type(&schema, "A"));
1466 assert!(!json!({ "__typename": "B", "y": "42"}).is_object_of_type(&schema, "I"));
1467 }
1468
1469 #[test]
1470 fn test_get_at_path_with_conditions() {
1471 let schema = test_schema();
1472 let json = json!({
1473 "i": [
1474 {
1475 "__typename": "A",
1476 "x": 0,
1477 },
1478 {
1479 "__typename": "B",
1480 "y": 1,
1481 },
1482 {
1483 "__typename": "B",
1484 "y": 2,
1485 },
1486 {
1487 "__typename": "A",
1488 "x": 3,
1489 },
1490 ],
1491 });
1492 let path = Path::from("i/... on A");
1493 let result = select_values(&schema, &path, &json).unwrap();
1494 assert_eq!(
1495 result,
1496 vec![
1497 &json!({
1498 "__typename": "A",
1499 "x": 0,
1500 }),
1501 &json!({
1502 "__typename": "A",
1503 "x": 3,
1504 }),
1505 ],
1506 );
1507 }
1508
1509 #[test]
1510 fn path_serde_json() {
1511 let path: Path = serde_json::from_str(
1512 r#"[
1513 "k",
1514 "... on T",
1515 "@",
1516 "arr",
1517 3
1518 ]"#,
1519 )
1520 .unwrap();
1521 assert_eq!(
1522 path.0,
1523 vec![
1524 PathElement::Key("k".to_string(), None),
1525 PathElement::Fragment("T".to_string()),
1526 PathElement::Flatten(None),
1527 PathElement::Key("arr".to_string(), None),
1528 PathElement::Index(3),
1529 ]
1530 );
1531
1532 assert_eq!(
1533 serde_json::to_string(&path).unwrap(),
1534 "[\"k\",\"... on T\",\"@\",\"arr\",3]",
1535 );
1536 }
1537}