use apollo_compiler::Name;
use serde::Deserialize;
use serde::Serialize;
use crate::json_ext::Path;
use crate::json_ext::PathElement;
use crate::json_ext::Value;
use crate::json_ext::ValueExt;
use crate::spec::Schema;
fn split_path_last_element(path: &Path) -> Option<(Path, &PathElement)> {
path.last().map(|last| (path.parent().unwrap(), last))
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase", tag = "kind")]
pub(crate) enum DataRewrite {
ValueSetter(DataValueSetter),
KeyRenamer(DataKeyRenamer),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DataValueSetter {
pub(crate) path: Path,
pub(crate) set_value_to: Value,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DataKeyRenamer {
pub(crate) path: Path,
pub(crate) rename_key_to: Name,
}
impl DataRewrite {
pub(crate) fn maybe_apply(&self, schema: &Schema, data: &mut Value) {
match self {
DataRewrite::ValueSetter(setter) => {
if let Some((parent, PathElement::Key(k, _))) =
split_path_last_element(&setter.path)
{
data.select_values_and_paths_mut(schema, &parent, |_path, obj| {
if let Some(value) = obj.get_mut(k) {
*value = setter.set_value_to.clone()
}
});
}
}
DataRewrite::KeyRenamer(renamer) => {
if let Some((parent, PathElement::Key(k, _))) =
split_path_last_element(&renamer.path)
{
data.select_values_and_paths_mut(schema, &parent, |_path, selected| {
if let Some(obj) = selected.as_object_mut() {
if let Some(value) = obj.remove(k.as_str()) {
obj.insert(renamer.rename_key_to.as_str(), value);
}
}
if let Some(arr) = selected.as_array_mut() {
for item in arr {
if let Some(obj) = item.as_object_mut() {
if let Some(value) = obj.remove(k.as_str()) {
obj.insert(renamer.rename_key_to.as_str(), value);
}
}
}
}
});
}
}
}
}
}
pub(crate) fn apply_rewrites(
schema: &Schema,
value: &mut Value,
maybe_rewrites: &Option<Vec<DataRewrite>>,
) {
if let Some(rewrites) = maybe_rewrites {
for rewrite in rewrites {
rewrite.maybe_apply(schema, value);
}
}
}
#[cfg(test)]
mod tests {
use apollo_compiler::name;
use serde_json_bytes::json;
use super::*;
const SCHEMA: &str = include_str!("../testdata/minimal_supergraph.graphql");
#[test]
fn test_key_renamer_object() {
let mut data = json!({
"data": {
"__typename": "TestType",
"testField__alias_0": {
"__typename": "TestField",
"field":"thisisatest"
}
}
});
let dr = DataRewrite::KeyRenamer(DataKeyRenamer {
path: "data/testField__alias_0".into(),
rename_key_to: name!("testField"),
});
dr.maybe_apply(
&Schema::parse(SCHEMA, &Default::default()).unwrap(),
&mut data,
);
assert_eq!(
json! {{
"data": {
"__typename": "TestType",
"testField": {
"__typename": "TestField",
"field":"thisisatest"
}
}
}},
data
);
}
#[test]
fn test_key_renamer_array() {
let mut data = json!(
{
"data": [{
"__typename": "TestType",
"testField__alias_0": {
"__typename": "TestField",
"field":"thisisatest"
}
}]
}
);
let dr = DataRewrite::KeyRenamer(DataKeyRenamer {
path: "data/testField__alias_0".into(),
rename_key_to: name!("testField"),
});
dr.maybe_apply(
&Schema::parse(SCHEMA, &Default::default()).unwrap(),
&mut data,
);
assert_eq!(
json! {{
"data": [{
"__typename": "TestType",
"testField": {
"__typename": "TestField",
"field":"thisisatest"
}
}]
}},
data
);
}
}