Skip to content

Commit

Permalink
SubSelectionKey needs a custom serializer
Browse files Browse the repository at this point in the history
it is used as key in a HashMap, and in JSON keys must be serialized as
strings
  • Loading branch information
Geal committed Jul 28, 2023
1 parent b8025de commit 55cdb30
Showing 1 changed file with 59 additions and 1 deletion.
60 changes: 59 additions & 1 deletion apollo-router/src/spec/query/subselections.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;

use serde::de::Visitor;
use serde::Deserialize;
use serde::Serialize;
use serde_json_bytes::ByteString;
Expand All @@ -14,12 +15,69 @@ use crate::spec::IncludeSkip;
use crate::spec::SpecError;
use crate::Configuration;

#[derive(Debug, Serialize, Deserialize, PartialEq, Hash, Eq)]
#[derive(Debug, PartialEq, Hash, Eq)]
pub(crate) struct SubSelectionKey {
pub(crate) defer_label: Option<String>,
pub(crate) defer_conditions: BooleanValues,
}

// Do not replace this with a derived Serialize implementation
// SubSelectionKey must serialize to a string because it is used as a JSON object key
impl Serialize for SubSelectionKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let s = format!(
"{:?}|{}",
self.defer_conditions.bits,
self.defer_label.as_deref().unwrap_or("")
);
serializer.serialize_str(&s)
}
}

impl<'de> Deserialize<'de> for SubSelectionKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_str(SubSelectionKeyVisitor)
}
}

struct SubSelectionKeyVisitor;
impl<'de> Visitor<'de> for SubSelectionKeyVisitor {
type Value = SubSelectionKey;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter
.write_str("a string containing the defer label and defer conditions separated by |")
}

fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if let Some((bits_str, label)) = s.split_once('|') {
Ok(SubSelectionKey {
defer_conditions: BooleanValues {
bits: bits_str
.parse::<u32>()
.map_err(|_| E::custom("expected a number"))?,
},
defer_label: if label.is_empty() {
None
} else {
Some(label.to_string())
},
})
} else {
Err(E::custom("invalid subselection"))
}
}
}

#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct SubSelectionValue {
pub(crate) selection_set: Vec<Selection>,
Expand Down

0 comments on commit 55cdb30

Please sign in to comment.