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 && !tc.iter().any(|tc| tc.as_str() == type_name.as_str())
555 {
556 return Value::Null;
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 && let Some(Value::String(type_name)) = o.get("__typename")
590 && tc.iter().any(|tc| tc.as_str() == type_name.as_str())
591 {
592 parent.push(PathElement::Index(i));
593 iterate_path(schema, parent, &path[1..], value, f);
594 parent.pop();
595 }
596
597 if let Value::Array(array) = value {
598 for (i, value) in array.iter().enumerate() {
599 if let Value::Object(o) = value
600 && let Some(Value::String(type_name)) = o.get("__typename")
601 && tc.iter().any(|tc| tc.as_str() == type_name.as_str())
602 {
603 parent.push(PathElement::Index(i));
604 iterate_path(schema, parent, &path[1..], value, f);
605 parent.pop();
606 }
607 }
608 }
609 }
610 } else {
611 parent.push(PathElement::Index(i));
612 iterate_path(schema, parent, &path[1..], value, f);
613 parent.pop();
614 }
615 }
616 }
617 }
618 Some(PathElement::Index(i)) => {
619 if let Value::Array(a) = data
620 && let Some(value) = a.get(*i)
621 {
622 parent.push(PathElement::Index(*i));
623 iterate_path(schema, parent, &path[1..], value, f);
624 parent.pop();
625 }
626 }
627 Some(PathElement::Key(k, type_conditions)) => {
628 if let Some(tc) = type_conditions {
629 if !tc.is_empty() {
630 if let Value::Object(o) = data {
631 if let Some(value) = o.get(k.as_str())
632 && let Some(Value::String(type_name)) = value.get("__typename")
633 && tc.iter().any(|tc| tc.as_str() == type_name.as_str())
634 {
635 parent.push(PathElement::Key(k.to_string(), None));
636 iterate_path(schema, parent, &path[1..], value, f);
637 parent.pop();
638 }
639 } else if let Value::Array(array) = data {
640 for (i, value) in array.iter().enumerate() {
641 if let Value::Object(o) = value
642 && let Some(Value::String(type_name)) = o.get("__typename")
643 && tc.iter().any(|tc| tc.as_str() == type_name.as_str())
644 {
645 parent.push(PathElement::Index(i));
646 iterate_path(schema, parent, path, value, f);
647 parent.pop();
648 }
649 }
650 }
651 }
652 } else if let Value::Object(o) = data {
653 if let Some(value) = o.get(k.as_str()) {
654 parent.push(PathElement::Key(k.to_string(), None));
655 iterate_path(schema, parent, &path[1..], value, f);
656 parent.pop();
657 }
658 } else if let Value::Array(array) = data {
659 for (i, value) in array.iter().enumerate() {
660 parent.push(PathElement::Index(i));
661 iterate_path(schema, parent, path, value, f);
662 parent.pop();
663 }
664 }
665 }
666 Some(PathElement::Fragment(name)) => {
667 if data.is_object_of_type(schema, name) {
668 iterate_path(schema, parent, &path[1..], data, f);
674 } else if let Value::Array(array) = data {
675 for (i, value) in array.iter().enumerate() {
676 parent.push(PathElement::Index(i));
677 iterate_path(schema, parent, path, value, f);
678 parent.pop();
679 }
680 }
681 }
682 }
683}
684
685fn iterate_path_mut<'a, F>(
686 schema: &Schema,
687 parent: &mut Path,
688 path: &'a [PathElement],
689 data: &'a mut Value,
690 f: &mut F,
691) where
692 F: FnMut(&Path, &'a mut Value),
693{
694 match path.first() {
695 None => f(parent, data),
696 Some(PathElement::Flatten(type_conditions)) => {
697 if let Some(array) = data.as_array_mut() {
698 for (i, value) in array.iter_mut().enumerate() {
699 if let Some(tc) = type_conditions {
700 if !tc.is_empty()
701 && let Value::Object(o) = value
702 && let Some(Value::String(type_name)) = o.get("__typename")
703 && tc.iter().any(|tc| tc.as_str() == type_name.as_str())
704 {
705 parent.push(PathElement::Index(i));
706 iterate_path_mut(schema, parent, &path[1..], value, f);
707 parent.pop();
708 }
709 } else {
710 parent.push(PathElement::Index(i));
711 iterate_path_mut(schema, parent, &path[1..], value, f);
712 parent.pop();
713 }
714 }
715 }
716 }
717 Some(PathElement::Index(i)) => {
718 if let Value::Array(a) = data
719 && let Some(value) = a.get_mut(*i)
720 {
721 parent.push(PathElement::Index(*i));
722 iterate_path_mut(schema, parent, &path[1..], value, f);
723 parent.pop();
724 }
725 }
726 Some(PathElement::Key(k, type_conditions)) => {
727 if let Some(tc) = type_conditions {
728 if !tc.is_empty() {
729 if let Value::Object(o) = data {
730 if let Some(value) = o.get_mut(k.as_str())
731 && let Some(Value::String(type_name)) = value.get("__typename")
732 && tc.iter().any(|tc| tc.as_str() == type_name.as_str())
733 {
734 parent.push(PathElement::Key(k.to_string(), None));
735 iterate_path_mut(schema, parent, &path[1..], value, f);
736 parent.pop();
737 }
738 } else if let Value::Array(array) = data {
739 for (i, value) in array.iter_mut().enumerate() {
740 if let Value::Object(o) = value
741 && let Some(Value::String(type_name)) = o.get("__typename")
742 && tc.iter().any(|tc| tc.as_str() == type_name.as_str())
743 {
744 parent.push(PathElement::Index(i));
745 iterate_path_mut(schema, parent, path, value, f);
746 parent.pop();
747 }
748 }
749 }
750 }
751 } else if let Value::Object(o) = data {
752 if let Some(value) = o.get_mut(k.as_str()) {
753 parent.push(PathElement::Key(k.to_string(), None));
754 iterate_path_mut(schema, parent, &path[1..], value, f);
755 parent.pop();
756 }
757 } else if let Value::Array(array) = data {
758 for (i, value) in array.iter_mut().enumerate() {
759 parent.push(PathElement::Index(i));
760 iterate_path_mut(schema, parent, path, value, f);
761 parent.pop();
762 }
763 }
764 }
765 Some(PathElement::Fragment(name)) => {
766 if data.is_object_of_type(schema, name) {
767 iterate_path_mut(schema, parent, &path[1..], data, f);
773 } else if let Value::Array(array) = data {
774 for (i, value) in array.iter_mut().enumerate() {
775 parent.push(PathElement::Index(i));
776 iterate_path_mut(schema, parent, path, value, f);
777 parent.pop();
778 }
779 }
780 }
781 }
782}
783
784#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
787#[serde(untagged)]
788pub enum PathElement {
789 #[serde(
791 deserialize_with = "deserialize_flatten",
792 serialize_with = "serialize_flatten"
793 )]
794 Flatten(Option<TypeConditions>),
795
796 Index(usize),
798
799 #[serde(
801 deserialize_with = "deserialize_fragment",
802 serialize_with = "serialize_fragment"
803 )]
804 Fragment(String),
805
806 #[serde(deserialize_with = "deserialize_key", serialize_with = "serialize_key")]
808 Key(String, Option<TypeConditions>),
809}
810
811type TypeConditions = Vec<String>;
812
813#[derive(Clone, Debug, Eq, PartialEq)]
814pub enum ResponsePathElement<'a> {
815 Index(usize),
817
818 Key(&'a str),
820}
821
822fn deserialize_flatten<'de, D>(deserializer: D) -> Result<Option<TypeConditions>, D::Error>
823where
824 D: serde::Deserializer<'de>,
825{
826 deserializer.deserialize_str(FlattenVisitor)
827}
828
829struct FlattenVisitor;
830
831impl serde::de::Visitor<'_> for FlattenVisitor {
832 type Value = Option<TypeConditions>;
833
834 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
835 write!(
836 formatter,
837 "a string that is '@', potentially followed by type conditions"
838 )
839 }
840
841 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
842 where
843 E: serde::de::Error,
844 {
845 let (path_element, type_conditions) = split_path_element_and_type_conditions(s);
846 if path_element == "@" {
847 Ok(type_conditions)
848 } else {
849 Err(serde::de::Error::invalid_value(
850 serde::de::Unexpected::Str(s),
851 &self,
852 ))
853 }
854 }
855}
856
857fn serialize_flatten<S>(
858 type_conditions: &Option<TypeConditions>,
859 serializer: S,
860) -> Result<S::Ok, S::Error>
861where
862 S: serde::Serializer,
863{
864 let tc_string = if let Some(c) = type_conditions {
865 format!("|[{}]", c.join(","))
866 } else {
867 "".to_string()
868 };
869 let res = format!("@{tc_string}");
870 serializer.serialize_str(res.as_str())
871}
872
873fn deserialize_key<'de, D>(deserializer: D) -> Result<(String, Option<TypeConditions>), D::Error>
874where
875 D: serde::Deserializer<'de>,
876{
877 deserializer.deserialize_str(KeyVisitor)
878}
879
880struct KeyVisitor;
881
882impl serde::de::Visitor<'_> for KeyVisitor {
883 type Value = (String, Option<TypeConditions>);
884
885 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
886 write!(
887 formatter,
888 "a string, potentially followed by type conditions"
889 )
890 }
891
892 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
893 where
894 E: serde::de::Error,
895 {
896 Ok(split_path_element_and_type_conditions(s))
897 }
898}
899
900fn serialize_key<S>(
901 key: &String,
902 type_conditions: &Option<TypeConditions>,
903 serializer: S,
904) -> Result<S::Ok, S::Error>
905where
906 S: serde::Serializer,
907{
908 let tc_string = if let Some(c) = type_conditions {
909 format!("|[{}]", c.join(","))
910 } else {
911 "".to_string()
912 };
913 let res = format!("{key}{tc_string}");
914 serializer.serialize_str(res.as_str())
915}
916
917fn deserialize_fragment<'de, D>(deserializer: D) -> Result<String, D::Error>
918where
919 D: serde::Deserializer<'de>,
920{
921 deserializer.deserialize_str(FragmentVisitor)
922}
923
924struct FragmentVisitor;
925
926impl serde::de::Visitor<'_> for FragmentVisitor {
927 type Value = String;
928
929 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
930 write!(formatter, "a string that begins with '... on '")
931 }
932
933 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
934 where
935 E: serde::de::Error,
936 {
937 s.strip_prefix(FRAGMENT_PREFIX)
938 .map(|v| v.to_string())
939 .ok_or_else(|| serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self))
940 }
941}
942
943fn serialize_fragment<S>(name: &String, serializer: S) -> Result<S::Ok, S::Error>
944where
945 S: serde::Serializer,
946{
947 serializer.serialize_str(format!("{FRAGMENT_PREFIX}{name}").as_str())
948}
949
950fn flatten_from_str(s: &str) -> Result<PathElement, String> {
951 let (path_element, type_conditions) = split_path_element_and_type_conditions(s);
952 if path_element != "@" {
953 return Err("invalid flatten".to_string());
954 }
955 Ok(PathElement::Flatten(type_conditions))
956}
957
958fn key_from_str(s: &str) -> Result<PathElement, String> {
959 let (key, type_conditions) = split_path_element_and_type_conditions(s);
960 Ok(PathElement::Key(key, type_conditions))
961}
962
963#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
967#[serde(transparent)]
968pub struct Path(pub Vec<PathElement>);
969
970impl Path {
971 pub fn from_slice<T: AsRef<str>>(s: &[T]) -> Self {
972 Self(
973 s.iter()
974 .map(|x| x.as_ref())
975 .map(|s| {
976 if let Ok(index) = s.parse::<usize>() {
977 PathElement::Index(index)
978 } else if s.contains('@') {
979 flatten_from_str(s).unwrap_or(PathElement::Flatten(None))
980 } else {
981 s.strip_prefix(FRAGMENT_PREFIX).map_or_else(
982 || key_from_str(s).unwrap_or(PathElement::Key(s.to_string(), None)),
983 |name| PathElement::Fragment(name.to_string()),
984 )
985 }
986 })
987 .collect(),
988 )
989 }
990
991 pub fn from_response_slice(s: &[ResponsePathElement]) -> Self {
992 Self(
993 s.iter()
994 .map(|x| match x {
995 ResponsePathElement::Index(index) => PathElement::Index(*index),
996 ResponsePathElement::Key(s) => PathElement::Key(s.to_string(), None),
997 })
998 .collect(),
999 )
1000 }
1001
1002 pub fn iter(&self) -> impl Iterator<Item = &PathElement> {
1003 self.0.iter()
1004 }
1005
1006 pub fn is_empty(&self) -> bool {
1007 self.0.is_empty()
1008 }
1009
1010 pub fn len(&self) -> usize {
1011 self.0.len()
1012 }
1013
1014 pub fn empty() -> Path {
1015 Path(Default::default())
1016 }
1017
1018 pub fn parent(&self) -> Option<Path> {
1019 if self.is_empty() {
1020 None
1021 } else {
1022 Some(Path(self.iter().take(self.len() - 1).cloned().collect()))
1023 }
1024 }
1025
1026 pub fn join(&self, other: impl AsRef<Self>) -> Self {
1027 let other = other.as_ref();
1028 let mut new = Vec::with_capacity(self.len() + other.len());
1029 new.extend(self.iter().cloned());
1030 new.extend(other.iter().cloned());
1031 Path(new)
1032 }
1033
1034 pub fn push(&mut self, element: PathElement) {
1035 self.0.push(element)
1036 }
1037
1038 pub fn pop(&mut self) -> Option<PathElement> {
1039 self.0.pop()
1040 }
1041
1042 pub fn last(&self) -> Option<&PathElement> {
1043 self.0.last()
1044 }
1045
1046 pub fn last_key(&mut self) -> Option<String> {
1047 self.0.last().and_then(|elem| match elem {
1048 PathElement::Key(key, type_conditions) => {
1049 let mut tc = String::new();
1050 if let Some(c) = type_conditions {
1051 tc = format!("|[{}]", c.join(","));
1052 };
1053 Some(format!("{key}{tc}"))
1054 }
1055 _ => None,
1056 })
1057 }
1058
1059 pub fn starts_with(&self, other: &Path) -> bool {
1060 self.0.starts_with(&other.0[..])
1061 }
1062
1063 pub fn remove_empty_key_root(&self) -> Self {
1065 if let Some(PathElement::Key(k, type_conditions)) = self.0.first()
1066 && k.is_empty()
1067 && type_conditions.is_none()
1068 {
1069 return Path(self.iter().skip(1).cloned().collect());
1070 }
1071
1072 self.clone()
1073 }
1074
1075 pub fn equal_if_flattened(&self, other: &Path) -> bool {
1078 if self.len() != other.len() {
1079 return false;
1080 }
1081
1082 for (elem1, elem2) in self.iter().zip(other.iter()) {
1083 let equal_elements = match (elem1, elem2) {
1084 (PathElement::Index(_), PathElement::Flatten(_)) => true,
1085 (PathElement::Flatten(_), PathElement::Index(_)) => true,
1086 (elem1, elem2) => elem1 == elem2,
1087 };
1088 if !equal_elements {
1089 return false;
1090 }
1091 }
1092
1093 true
1094 }
1095}
1096
1097impl FromIterator<PathElement> for Path {
1098 fn from_iter<T: IntoIterator<Item = PathElement>>(iter: T) -> Self {
1099 Path(iter.into_iter().collect())
1100 }
1101}
1102
1103impl AsRef<Path> for Path {
1104 fn as_ref(&self) -> &Path {
1105 self
1106 }
1107}
1108
1109impl<T> From<T> for Path
1110where
1111 T: AsRef<str>,
1112{
1113 fn from(s: T) -> Self {
1114 Self(
1115 s.as_ref()
1116 .split('/')
1117 .map(|s| {
1118 if let Ok(index) = s.parse::<usize>() {
1119 PathElement::Index(index)
1120 } else if s.contains('@') {
1121 flatten_from_str(s).unwrap()
1122 } else {
1123 s.strip_prefix(FRAGMENT_PREFIX).map_or_else(
1124 || key_from_str(s).unwrap_or(PathElement::Key(s.to_string(), None)),
1125 |name| PathElement::Fragment(name.to_string()),
1126 )
1127 }
1128 })
1129 .collect(),
1130 )
1131 }
1132}
1133
1134impl fmt::Display for Path {
1135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1136 for element in self.iter() {
1137 write!(f, "/")?;
1138 match element {
1139 PathElement::Index(index) => write!(f, "{index}")?,
1140 PathElement::Key(key, type_conditions) => {
1141 write!(f, "{key}")?;
1142 if let Some(c) = type_conditions {
1143 write!(f, "|[{}]", c.join(","))?;
1144 };
1145 }
1146 PathElement::Flatten(type_conditions) => {
1147 write!(f, "@")?;
1148 if let Some(c) = type_conditions {
1149 write!(f, "|[{}]", c.join(","))?;
1150 };
1151 }
1152 PathElement::Fragment(name) => {
1153 write!(f, "{FRAGMENT_PREFIX}{name}")?;
1154 }
1155 }
1156 }
1157 Ok(())
1158 }
1159}
1160
1161#[cfg(test)]
1162mod tests {
1163 use serde_json_bytes::json;
1164
1165 use super::*;
1166
1167 macro_rules! assert_is_subset {
1168 ($a:expr, $b:expr $(,)?) => {
1169 assert!($a.is_subset(&$b));
1170 };
1171 }
1172
1173 macro_rules! assert_is_not_subset {
1174 ($a:expr, $b:expr $(,)?) => {
1175 assert!(!$a.is_subset(&$b));
1176 };
1177 }
1178
1179 fn test_schema() -> Schema {
1183 Schema::parse(
1184 r#"
1185 schema
1186 @link(url: "https://specs.apollo.dev/link/v1.0")
1187 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1188 {
1189 query: Query
1190 }
1191
1192 directive @join__graph(name: String!, url: String!) on ENUM_VALUE
1193 directive @link( url: String as: String for: link__Purpose import: [link__Import]) repeatable on SCHEMA
1194 scalar link__Import
1195
1196 enum join__Graph {
1197 FAKE @join__graph(name:"fake" url: "http://localhost:4001/fake")
1198 }
1199
1200 enum link__Purpose {
1201 SECURITY
1202 EXECUTION
1203 }
1204
1205 type Query {
1206 i: [I]
1207 }
1208
1209 interface I {
1210 x: Int
1211 }
1212
1213 type A implements I {
1214 x: Int
1215 }
1216
1217 type B {
1218 y: Int
1219 }
1220 "#,
1221 &Default::default(),
1222 )
1223 .unwrap()
1224 }
1225
1226 fn select_values<'a>(
1227 schema: &Schema,
1228 path: &'a Path,
1229 data: &'a Value,
1230 ) -> Result<Vec<&'a Value>, FetchError> {
1231 let mut v = Vec::new();
1232 data.select_values_and_paths(schema, path, |_path, value| {
1233 v.push(value);
1234 });
1235 Ok(v)
1236 }
1237
1238 #[test]
1239 fn test_get_at_path() {
1240 let schema = test_schema();
1241 let json = json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}});
1242 let path = Path::from("obj/arr/1/prop1");
1243 let result = select_values(&schema, &path, &json).unwrap();
1244 assert_eq!(result, vec![&Value::Number(2.into())]);
1245 }
1246
1247 #[test]
1248 fn test_get_at_path_flatmap() {
1249 let schema = test_schema();
1250 let json = json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}});
1251 let path = Path::from("obj/arr/@");
1252 let result = select_values(&schema, &path, &json).unwrap();
1253 assert_eq!(result, vec![&json!({"prop1":1}), &json!({"prop1":2})]);
1254 }
1255
1256 #[test]
1257 fn test_get_at_path_flatmap_nested() {
1258 let schema = test_schema();
1259 let json = json!({
1260 "obj": {
1261 "arr": [
1262 {
1263 "prop1": [
1264 {"prop2": {"prop3": 1}, "prop4": -1},
1265 {"prop2": {"prop3": 2}, "prop4": -2},
1266 ],
1267 },
1268 {
1269 "prop1": [
1270 {"prop2": {"prop3": 3}, "prop4": -3},
1271 {"prop2": {"prop3": 4}, "prop4": -4},
1272 ],
1273 },
1274 ],
1275 },
1276 });
1277 let path = Path::from("obj/arr/@/prop1/@/prop2");
1278 let result = select_values(&schema, &path, &json).unwrap();
1279 assert_eq!(
1280 result,
1281 vec![
1282 &json!({"prop3":1}),
1283 &json!({"prop3":2}),
1284 &json!({"prop3":3}),
1285 &json!({"prop3":4}),
1286 ],
1287 );
1288 }
1289
1290 #[test]
1291 fn test_deep_merge() {
1292 let mut json = json!({"obj":{"arr":[{"prop1":1},{"prop2":2}]}});
1293 json.deep_merge(json!({"obj":{"arr":[{"prop1":2,"prop3":3},{"prop4":4}]}}));
1294 assert_eq!(
1295 json,
1296 json!({"obj":{"arr":[{"prop1":2, "prop3":3},{"prop2":2, "prop4":4}]}})
1297 );
1298 }
1299
1300 #[test]
1301 fn interface_typename_merging() {
1302 let schema = Schema::parse(
1303 r#"
1304 schema
1305 @link(url: "https://specs.apollo.dev/link/v1.0")
1306 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1307 {
1308 query: Query
1309 }
1310 directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
1311 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
1312 directive @join__graph(name: String!, url: String!) on ENUM_VALUE
1313
1314 scalar link__Import
1315 scalar join__FieldSet
1316
1317 enum link__Purpose {
1318 SECURITY
1319 EXECUTION
1320 }
1321
1322 enum join__Graph {
1323 TEST @join__graph(name: "test", url: "http://localhost:4001/graphql")
1324 }
1325
1326 interface I {
1327 s: String
1328 }
1329
1330 type C implements I {
1331 s: String
1332 }
1333
1334 type Query {
1335 i: I
1336 }
1337 "#,
1338 &Default::default(),
1339 )
1340 .expect("valid schema");
1341 let mut response1 = json!({
1342 "__typename": "C"
1343 });
1344 let response2 = json!({
1345 "__typename": "I",
1346 "s": "data"
1347 });
1348
1349 response1.type_aware_deep_merge(response2, &schema);
1350
1351 assert_eq!(
1352 response1,
1353 json!({
1354 "__typename": "C",
1355 "s": "data"
1356 })
1357 );
1358 }
1359
1360 #[test]
1361 fn test_is_subset_eq() {
1362 assert_is_subset!(
1363 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1364 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1365 );
1366 }
1367
1368 #[test]
1369 fn test_is_subset_missing_pop() {
1370 assert_is_subset!(
1371 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1372 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1373 );
1374 }
1375
1376 #[test]
1377 fn test_is_subset_array_lengths_differ() {
1378 assert_is_not_subset!(
1379 json!({"obj":{"arr":[{"prop1":1}]}}),
1380 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1381 );
1382 }
1383
1384 #[test]
1385 fn test_is_subset_extra_prop() {
1386 assert_is_not_subset!(
1387 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1388 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1389 );
1390 }
1391
1392 #[test]
1393 fn eq_and_ordered() {
1394 assert!(json!([1, 2, 3]).eq_and_ordered(&json!([1, 2, 3])));
1396 assert!(!json!([1, 3, 2]).eq_and_ordered(&json!([1, 2, 3])));
1397
1398 assert!(json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1400 assert!(!json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":3})));
1401 assert!(!json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":2,"baz":3})));
1402 assert!(!json!({"foo":1,"bar":2,"baz":3}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1403 assert!(!json!({"bar":2,"foo":1}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1404
1405 assert!(json!({"baz":{"foo":1,"bar":2}}).eq_and_ordered(&json!({"baz":{"foo":1,"bar":2}})));
1407 assert!(
1408 !json!({"baz":{"bar":2,"foo":1}}).eq_and_ordered(&json!({"baz":{"foo":1,"bar":2}}))
1409 );
1410 assert!(!json!([1,{"bar":2,"foo":1},2]).eq_and_ordered(&json!([1,{"foo":1,"bar":2},2])));
1411 }
1412
1413 #[test]
1414 fn test_from_path() {
1415 let json = json!([{"prop1":1},{"prop1":2}]);
1416 let path = Path::from("obj/arr");
1417 let result = Value::from_path(&path, json);
1418 assert_eq!(result, json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}}));
1419 }
1420
1421 #[test]
1422 fn test_from_path_index() {
1423 let json = json!({"prop1":1});
1424 let path = Path::from("obj/arr/1");
1425 let result = Value::from_path(&path, json);
1426 assert_eq!(result, json!({"obj":{"arr":[null, {"prop1":1}]}}));
1427 }
1428
1429 #[test]
1430 fn test_from_path_flatten() {
1431 let json = json!({"prop1":1});
1432 let path = Path::from("obj/arr/@/obj2");
1433 let result = Value::from_path(&path, json);
1434 assert_eq!(result, json!({"obj":{"arr":null}}));
1435 }
1436
1437 #[test]
1438 fn test_is_object_of_type() {
1439 let schema = test_schema();
1440
1441 assert!(json!({ "__typename": "A", "x": "42"}).is_object_of_type(&schema, "A"));
1443
1444 assert!(json!({ "__typename": "A", "x": "42"}).is_object_of_type(&schema, "I"));
1446
1447 assert!(json!({ "x": "42"}).is_object_of_type(&schema, "A"));
1449
1450 assert!(!json!([{ "__typename": "A", "x": "42"}]).is_object_of_type(&schema, "A"));
1452 assert!(!json!("foo").is_object_of_type(&schema, "I"));
1453 assert!(!json!(42).is_object_of_type(&schema, "I"));
1454
1455 assert!(!json!({ "__typename": "B", "y": "42"}).is_object_of_type(&schema, "A"));
1457 assert!(!json!({ "__typename": "B", "y": "42"}).is_object_of_type(&schema, "I"));
1458 }
1459
1460 #[test]
1461 fn test_get_at_path_with_conditions() {
1462 let schema = test_schema();
1463 let json = json!({
1464 "i": [
1465 {
1466 "__typename": "A",
1467 "x": 0,
1468 },
1469 {
1470 "__typename": "B",
1471 "y": 1,
1472 },
1473 {
1474 "__typename": "B",
1475 "y": 2,
1476 },
1477 {
1478 "__typename": "A",
1479 "x": 3,
1480 },
1481 ],
1482 });
1483 let path = Path::from("i/... on A");
1484 let result = select_values(&schema, &path, &json).unwrap();
1485 assert_eq!(
1486 result,
1487 vec![
1488 &json!({
1489 "__typename": "A",
1490 "x": 0,
1491 }),
1492 &json!({
1493 "__typename": "A",
1494 "x": 3,
1495 }),
1496 ],
1497 );
1498 }
1499
1500 #[test]
1501 fn path_serde_json() {
1502 let path: Path = serde_json::from_str(
1503 r#"[
1504 "k",
1505 "... on T",
1506 "@",
1507 "arr",
1508 3
1509 ]"#,
1510 )
1511 .unwrap();
1512 assert_eq!(
1513 path.0,
1514 vec![
1515 PathElement::Key("k".to_string(), None),
1516 PathElement::Fragment("T".to_string()),
1517 PathElement::Flatten(None),
1518 PathElement::Key("arr".to_string(), None),
1519 PathElement::Index(3),
1520 ]
1521 );
1522
1523 assert_eq!(
1524 serde_json::to_string(&path).unwrap(),
1525 "[\"k\",\"... on T\",\"@\",\"arr\",3]",
1526 );
1527 }
1528}