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
1085impl FromIterator<PathElement> for Path {
1086 fn from_iter<T: IntoIterator<Item = PathElement>>(iter: T) -> Self {
1087 Path(iter.into_iter().collect())
1088 }
1089}
1090
1091impl AsRef<Path> for Path {
1092 fn as_ref(&self) -> &Path {
1093 self
1094 }
1095}
1096
1097impl<T> From<T> for Path
1098where
1099 T: AsRef<str>,
1100{
1101 fn from(s: T) -> Self {
1102 Self(
1103 s.as_ref()
1104 .split('/')
1105 .map(|s| {
1106 if let Ok(index) = s.parse::<usize>() {
1107 PathElement::Index(index)
1108 } else if s.contains('@') {
1109 flatten_from_str(s).unwrap()
1110 } else {
1111 s.strip_prefix(FRAGMENT_PREFIX).map_or_else(
1112 || key_from_str(s).unwrap_or(PathElement::Key(s.to_string(), None)),
1113 |name| PathElement::Fragment(name.to_string()),
1114 )
1115 }
1116 })
1117 .collect(),
1118 )
1119 }
1120}
1121
1122impl fmt::Display for Path {
1123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1124 for element in self.iter() {
1125 write!(f, "/")?;
1126 match element {
1127 PathElement::Index(index) => write!(f, "{index}")?,
1128 PathElement::Key(key, type_conditions) => {
1129 write!(f, "{key}")?;
1130 if let Some(c) = type_conditions {
1131 write!(f, "|[{}]", c.join(","))?;
1132 };
1133 }
1134 PathElement::Flatten(type_conditions) => {
1135 write!(f, "@")?;
1136 if let Some(c) = type_conditions {
1137 write!(f, "|[{}]", c.join(","))?;
1138 };
1139 }
1140 PathElement::Fragment(name) => {
1141 write!(f, "{FRAGMENT_PREFIX}{name}")?;
1142 }
1143 }
1144 }
1145 Ok(())
1146 }
1147}
1148
1149#[cfg(test)]
1150mod tests {
1151 use serde_json_bytes::json;
1152
1153 use super::*;
1154
1155 macro_rules! assert_is_subset {
1156 ($a:expr, $b:expr $(,)?) => {
1157 assert!($a.is_subset(&$b));
1158 };
1159 }
1160
1161 macro_rules! assert_is_not_subset {
1162 ($a:expr, $b:expr $(,)?) => {
1163 assert!(!$a.is_subset(&$b));
1164 };
1165 }
1166
1167 fn test_schema() -> Schema {
1171 Schema::parse(
1172 r#"
1173 schema
1174 @link(url: "https://specs.apollo.dev/link/v1.0")
1175 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1176 {
1177 query: Query
1178 }
1179
1180 directive @join__graph(name: String!, url: String!) on ENUM_VALUE
1181 directive @link( url: String as: String for: link__Purpose import: [link__Import]) repeatable on SCHEMA
1182 scalar link__Import
1183
1184 enum join__Graph {
1185 FAKE @join__graph(name:"fake" url: "http://localhost:4001/fake")
1186 }
1187
1188 enum link__Purpose {
1189 SECURITY
1190 EXECUTION
1191 }
1192
1193 type Query {
1194 i: [I]
1195 }
1196
1197 interface I {
1198 x: Int
1199 }
1200
1201 type A implements I {
1202 x: Int
1203 }
1204
1205 type B {
1206 y: Int
1207 }
1208 "#,
1209 &Default::default(),
1210 )
1211 .unwrap()
1212 }
1213
1214 fn select_values<'a>(
1215 schema: &Schema,
1216 path: &'a Path,
1217 data: &'a Value,
1218 ) -> Result<Vec<&'a Value>, FetchError> {
1219 let mut v = Vec::new();
1220 data.select_values_and_paths(schema, path, |_path, value| {
1221 v.push(value);
1222 });
1223 Ok(v)
1224 }
1225
1226 #[test]
1227 fn test_get_at_path() {
1228 let schema = test_schema();
1229 let json = json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}});
1230 let path = Path::from("obj/arr/1/prop1");
1231 let result = select_values(&schema, &path, &json).unwrap();
1232 assert_eq!(result, vec![&Value::Number(2.into())]);
1233 }
1234
1235 #[test]
1236 fn test_get_at_path_flatmap() {
1237 let schema = test_schema();
1238 let json = json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}});
1239 let path = Path::from("obj/arr/@");
1240 let result = select_values(&schema, &path, &json).unwrap();
1241 assert_eq!(result, vec![&json!({"prop1":1}), &json!({"prop1":2})]);
1242 }
1243
1244 #[test]
1245 fn test_get_at_path_flatmap_nested() {
1246 let schema = test_schema();
1247 let json = json!({
1248 "obj": {
1249 "arr": [
1250 {
1251 "prop1": [
1252 {"prop2": {"prop3": 1}, "prop4": -1},
1253 {"prop2": {"prop3": 2}, "prop4": -2},
1254 ],
1255 },
1256 {
1257 "prop1": [
1258 {"prop2": {"prop3": 3}, "prop4": -3},
1259 {"prop2": {"prop3": 4}, "prop4": -4},
1260 ],
1261 },
1262 ],
1263 },
1264 });
1265 let path = Path::from("obj/arr/@/prop1/@/prop2");
1266 let result = select_values(&schema, &path, &json).unwrap();
1267 assert_eq!(
1268 result,
1269 vec![
1270 &json!({"prop3":1}),
1271 &json!({"prop3":2}),
1272 &json!({"prop3":3}),
1273 &json!({"prop3":4}),
1274 ],
1275 );
1276 }
1277
1278 #[test]
1279 fn test_deep_merge() {
1280 let mut json = json!({"obj":{"arr":[{"prop1":1},{"prop2":2}]}});
1281 json.deep_merge(json!({"obj":{"arr":[{"prop1":2,"prop3":3},{"prop4":4}]}}));
1282 assert_eq!(
1283 json,
1284 json!({"obj":{"arr":[{"prop1":2, "prop3":3},{"prop2":2, "prop4":4}]}})
1285 );
1286 }
1287
1288 #[test]
1289 fn interface_typename_merging() {
1290 let schema = Schema::parse(
1291 r#"
1292 schema
1293 @link(url: "https://specs.apollo.dev/link/v1.0")
1294 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1295 {
1296 query: Query
1297 }
1298 directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
1299 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
1300 directive @join__graph(name: String!, url: String!) on ENUM_VALUE
1301
1302 scalar link__Import
1303 scalar join__FieldSet
1304
1305 enum link__Purpose {
1306 SECURITY
1307 EXECUTION
1308 }
1309
1310 enum join__Graph {
1311 TEST @join__graph(name: "test", url: "http://localhost:4001/graphql")
1312 }
1313
1314 interface I {
1315 s: String
1316 }
1317
1318 type C implements I {
1319 s: String
1320 }
1321
1322 type Query {
1323 i: I
1324 }
1325 "#,
1326 &Default::default(),
1327 )
1328 .expect("valid schema");
1329 let mut response1 = json!({
1330 "__typename": "C"
1331 });
1332 let response2 = json!({
1333 "__typename": "I",
1334 "s": "data"
1335 });
1336
1337 response1.type_aware_deep_merge(response2, &schema);
1338
1339 assert_eq!(
1340 response1,
1341 json!({
1342 "__typename": "C",
1343 "s": "data"
1344 })
1345 );
1346 }
1347
1348 #[test]
1349 fn test_is_subset_eq() {
1350 assert_is_subset!(
1351 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1352 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1353 );
1354 }
1355
1356 #[test]
1357 fn test_is_subset_missing_pop() {
1358 assert_is_subset!(
1359 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1360 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1361 );
1362 }
1363
1364 #[test]
1365 fn test_is_subset_array_lengths_differ() {
1366 assert_is_not_subset!(
1367 json!({"obj":{"arr":[{"prop1":1}]}}),
1368 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1369 );
1370 }
1371
1372 #[test]
1373 fn test_is_subset_extra_prop() {
1374 assert_is_not_subset!(
1375 json!({"obj":{"arr":[{"prop1":1,"prop3":3},{"prop4":4}]}}),
1376 json!({"obj":{"arr":[{"prop1":1},{"prop4":4}]}}),
1377 );
1378 }
1379
1380 #[test]
1381 fn eq_and_ordered() {
1382 assert!(json!([1, 2, 3]).eq_and_ordered(&json!([1, 2, 3])));
1384 assert!(!json!([1, 3, 2]).eq_and_ordered(&json!([1, 2, 3])));
1385
1386 assert!(json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1388 assert!(!json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":3})));
1389 assert!(!json!({"foo":1,"bar":2}).eq_and_ordered(&json!({"foo":1,"bar":2,"baz":3})));
1390 assert!(!json!({"foo":1,"bar":2,"baz":3}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1391 assert!(!json!({"bar":2,"foo":1}).eq_and_ordered(&json!({"foo":1,"bar":2})));
1392
1393 assert!(json!({"baz":{"foo":1,"bar":2}}).eq_and_ordered(&json!({"baz":{"foo":1,"bar":2}})));
1395 assert!(
1396 !json!({"baz":{"bar":2,"foo":1}}).eq_and_ordered(&json!({"baz":{"foo":1,"bar":2}}))
1397 );
1398 assert!(!json!([1,{"bar":2,"foo":1},2]).eq_and_ordered(&json!([1,{"foo":1,"bar":2},2])));
1399 }
1400
1401 #[test]
1402 fn test_from_path() {
1403 let json = json!([{"prop1":1},{"prop1":2}]);
1404 let path = Path::from("obj/arr");
1405 let result = Value::from_path(&path, json);
1406 assert_eq!(result, json!({"obj":{"arr":[{"prop1":1},{"prop1":2}]}}));
1407 }
1408
1409 #[test]
1410 fn test_from_path_index() {
1411 let json = json!({"prop1":1});
1412 let path = Path::from("obj/arr/1");
1413 let result = Value::from_path(&path, json);
1414 assert_eq!(result, json!({"obj":{"arr":[null, {"prop1":1}]}}));
1415 }
1416
1417 #[test]
1418 fn test_from_path_flatten() {
1419 let json = json!({"prop1":1});
1420 let path = Path::from("obj/arr/@/obj2");
1421 let result = Value::from_path(&path, json);
1422 assert_eq!(result, json!({"obj":{"arr":null}}));
1423 }
1424
1425 #[test]
1426 fn test_is_object_of_type() {
1427 let schema = test_schema();
1428
1429 assert!(json!({ "__typename": "A", "x": "42"}).is_object_of_type(&schema, "A"));
1431
1432 assert!(json!({ "__typename": "A", "x": "42"}).is_object_of_type(&schema, "I"));
1434
1435 assert!(json!({ "x": "42"}).is_object_of_type(&schema, "A"));
1437
1438 assert!(!json!([{ "__typename": "A", "x": "42"}]).is_object_of_type(&schema, "A"));
1440 assert!(!json!("foo").is_object_of_type(&schema, "I"));
1441 assert!(!json!(42).is_object_of_type(&schema, "I"));
1442
1443 assert!(!json!({ "__typename": "B", "y": "42"}).is_object_of_type(&schema, "A"));
1445 assert!(!json!({ "__typename": "B", "y": "42"}).is_object_of_type(&schema, "I"));
1446 }
1447
1448 #[test]
1449 fn test_get_at_path_with_conditions() {
1450 let schema = test_schema();
1451 let json = json!({
1452 "i": [
1453 {
1454 "__typename": "A",
1455 "x": 0,
1456 },
1457 {
1458 "__typename": "B",
1459 "y": 1,
1460 },
1461 {
1462 "__typename": "B",
1463 "y": 2,
1464 },
1465 {
1466 "__typename": "A",
1467 "x": 3,
1468 },
1469 ],
1470 });
1471 let path = Path::from("i/... on A");
1472 let result = select_values(&schema, &path, &json).unwrap();
1473 assert_eq!(
1474 result,
1475 vec![
1476 &json!({
1477 "__typename": "A",
1478 "x": 0,
1479 }),
1480 &json!({
1481 "__typename": "A",
1482 "x": 3,
1483 }),
1484 ],
1485 );
1486 }
1487
1488 #[test]
1489 fn path_serde_json() {
1490 let path: Path = serde_json::from_str(
1491 r#"[
1492 "k",
1493 "... on T",
1494 "@",
1495 "arr",
1496 3
1497 ]"#,
1498 )
1499 .unwrap();
1500 assert_eq!(
1501 path.0,
1502 vec![
1503 PathElement::Key("k".to_string(), None),
1504 PathElement::Fragment("T".to_string()),
1505 PathElement::Flatten(None),
1506 PathElement::Key("arr".to_string(), None),
1507 PathElement::Index(3),
1508 ]
1509 );
1510
1511 assert_eq!(
1512 serde_json::to_string(&path).unwrap(),
1513 "[\"k\",\"... on T\",\"@\",\"arr\",3]",
1514 );
1515 }
1516}