graphql_federated_graph/federated_graph/directives/
override.rs

1use crate::{StringId, SubgraphId};
2
3/// Represents an `@override(graph: .., from: ...)` directive on a field in a subgraph.
4#[derive(serde::Serialize, serde::Deserialize, Clone)]
5pub struct Override {
6    pub graph: SubgraphId,
7    /// Points to a subgraph referenced by name, but this is _not_ validated to allow easier field
8    /// migrations between subgraphs.
9    pub from: OverrideSource,
10    #[serde(default)]
11    pub label: OverrideLabel,
12}
13
14#[derive(serde::Serialize, serde::Deserialize, Clone, Default, Debug, PartialEq, PartialOrd)]
15pub enum OverrideLabel {
16    Percent(u8),
17    #[serde(other)]
18    #[default]
19    Unknown,
20}
21
22impl OverrideLabel {
23    pub fn as_percent(&self) -> Option<u8> {
24        if let Self::Percent(v) = self { Some(*v) } else { None }
25    }
26}
27
28impl std::fmt::Display for OverrideLabel {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        match self {
31            OverrideLabel::Percent(percent) => {
32                f.write_str("percent(")?;
33                percent.fmt(f)?;
34                f.write_str(")")
35            }
36            OverrideLabel::Unknown => Ok(()),
37        }
38    }
39}
40
41impl std::str::FromStr for OverrideLabel {
42    type Err = &'static str;
43
44    fn from_str(s: &str) -> Result<Self, Self::Err> {
45        if let Some(percent) = s
46            .strip_prefix("percent(")
47            .and_then(|suffix| suffix.strip_suffix(')'))
48            .and_then(|percent| u8::from_str(percent).ok())
49        {
50            Ok(OverrideLabel::Percent(percent))
51        } else {
52            Err(r#"Expected a field of the format "percent(<number>)" "#)
53        }
54    }
55}
56
57#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, PartialOrd)]
58pub enum OverrideSource {
59    Subgraph(SubgraphId),
60    Missing(StringId),
61}