Skip to main content

fraiseql_core/federation/
representation.rs

1//! Entity representation parsing for _Any scalar.
2
3use serde_json::Value;
4
5use super::types::{EntityRepresentation, FederationMetadata};
6
7/// Parse entity representations from _entities input
8pub 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        // Extract key fields based on metadata
21        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
33/// Validate entity representations
34pub 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        // Check typename exists in schema
42        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        // Check required key fields are present
48        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}