fraiseql_core/federation/
representation.rs1use serde_json::Value;
4
5use super::types::{EntityRepresentation, FederationMetadata};
6
7pub fn parse_representations(
9 input: &Value,
10 metadata: &FederationMetadata,
11) -> Result<Vec<EntityRepresentation>, String> {
12 let array = input.as_array().ok_or_else(|| "Representations must be array".to_string())?;
13
14 let mut reps = Vec::new();
15
16 for (idx, item) in array.iter().enumerate() {
17 let mut rep = EntityRepresentation::from_any(item)
18 .map_err(|e| format!("Representation {}: {}", idx, e))?;
19
20 if let Some(fed_type) = metadata.types.iter().find(|t| t.name == rep.typename) {
22 if let Some(key) = fed_type.keys.first() {
23 rep.extract_key_fields(&key.fields);
24 }
25 }
26
27 reps.push(rep);
28 }
29
30 Ok(reps)
31}
32
33pub fn validate_representations(
35 reps: &[EntityRepresentation],
36 metadata: &FederationMetadata,
37) -> Result<(), Vec<String>> {
38 let mut errors = Vec::new();
39
40 for rep in reps {
41 if !metadata.types.iter().any(|t| t.name == rep.typename) {
43 errors.push(format!("Type {} not found in federation metadata", rep.typename));
44 continue;
45 }
46
47 if let Some(fed_type) = metadata.types.iter().find(|t| t.name == rep.typename) {
49 if let Some(key) = fed_type.keys.first() {
50 for field in &key.fields {
51 if !rep.key_fields.contains_key(field) {
52 errors.push(format!(
53 "Type {}: key field '{}' missing in representation",
54 rep.typename, field
55 ));
56 }
57 }
58 }
59 }
60 }
61
62 if errors.is_empty() {
63 Ok(())
64 } else {
65 Err(errors)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use serde_json::json;
72
73 use super::*;
74
75 #[test]
76 fn test_parse_representations() {
77 let input = json!([
78 {"__typename": "User", "id": "123"},
79 {"__typename": "User", "id": "456"},
80 ]);
81
82 let metadata = FederationMetadata::default();
83 let reps = parse_representations(&input, &metadata).unwrap();
84
85 assert_eq!(reps.len(), 2);
86 assert_eq!(reps[0].typename, "User");
87 assert_eq!(reps[1].typename, "User");
88 }
89
90 #[test]
91 fn test_parse_representations_invalid() {
92 let input = json!("not an array");
93
94 let metadata = FederationMetadata::default();
95 let result = parse_representations(&input, &metadata);
96
97 assert!(result.is_err());
98 }
99
100 #[test]
101 fn test_parse_representations_missing_typename() {
102 let input = json!([
103 {"id": "123"},
104 ]);
105
106 let metadata = FederationMetadata::default();
107 let result = parse_representations(&input, &metadata);
108
109 assert!(result.is_err());
110 }
111}