mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
Fix serialization of the NodeFieldTypeMappings
(#260)
V3_GIT_ORIGIN_REV_ID: 10ff7b35139fc48e618270758d3f805890039c53
This commit is contained in:
parent
048ddbd33d
commit
f53e329eb1
@ -16,6 +16,7 @@ use crate::metadata::resolved;
|
||||
use crate::metadata::resolved::subgraph::Qualified;
|
||||
use crate::schema::types::{GlobalID, NamespaceAnnotation, NodeFieldTypeNameMapping};
|
||||
use crate::schema::GDS;
|
||||
use crate::utils::HashMapWithJsonKey;
|
||||
|
||||
/// IR for the 'select_one' operation on a model
|
||||
#[derive(Serialize, Debug)]
|
||||
@ -39,8 +40,10 @@ pub struct NodeSelect<'n, 's> {
|
||||
|
||||
fn get_relay_node_namespace_typename_mappings<'s>(
|
||||
field_call: &normalized_ast::FieldCall<'s, GDS>,
|
||||
) -> Result<&'s HashMap<Qualified<CustomTypeName>, resolved::model::FilterPermission>, error::Error>
|
||||
{
|
||||
) -> Result<
|
||||
&'s HashMapWithJsonKey<Qualified<CustomTypeName>, resolved::model::FilterPermission>,
|
||||
error::Error,
|
||||
> {
|
||||
field_call
|
||||
.info
|
||||
.namespaced
|
||||
@ -88,7 +91,7 @@ pub(crate) fn relay_node_ir<'n, 's>(
|
||||
let typename_permissions: &'s HashMap<
|
||||
Qualified<CustomTypeName>,
|
||||
resolved::model::FilterPermission,
|
||||
> = get_relay_node_namespace_typename_mappings(field_call)?;
|
||||
> = &get_relay_node_namespace_typename_mappings(field_call)?.0;
|
||||
let typename_mapping = typename_mappings.get(&global_id.typename).ok_or(
|
||||
error::InternalDeveloperError::GlobalIDTypenameMappingNotFound {
|
||||
type_name: global_id.typename.clone(),
|
||||
|
@ -17,6 +17,7 @@ use crate::schema::types::{
|
||||
Annotation, NodeFieldTypeNameMapping, OutputAnnotation, RootFieldAnnotation,
|
||||
};
|
||||
use crate::schema::{Role, GDS};
|
||||
use crate::utils::HashMapWithJsonKey;
|
||||
|
||||
pub(crate) struct RelayNodeFieldOutput {
|
||||
pub relay_node_gql_field: gql_schema::Field<GDS>,
|
||||
@ -111,7 +112,7 @@ pub(crate) fn relay_node_field(
|
||||
relay_node_field_permissions.insert(
|
||||
role.clone(),
|
||||
Some(types::NamespaceAnnotation::NodeFieldTypeMappings(
|
||||
role_type_permission,
|
||||
HashMapWithJsonKey(role_type_permission),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
@ -11,9 +11,12 @@ use std::{
|
||||
|
||||
use open_dds::{commands, models, types};
|
||||
|
||||
use crate::metadata::resolved::{
|
||||
self,
|
||||
subgraph::{Qualified, QualifiedTypeReference},
|
||||
use crate::{
|
||||
metadata::resolved::{
|
||||
self,
|
||||
subgraph::{Qualified, QualifiedTypeReference},
|
||||
},
|
||||
utils::HashMapWithJsonKey,
|
||||
};
|
||||
use strum_macros::Display;
|
||||
|
||||
@ -183,7 +186,7 @@ pub enum NamespaceAnnotation {
|
||||
/// decoding, a typename will be obtained. We need to use that typename to look up the
|
||||
/// Hashmap to get the appropriate `resolved::model::FilterPermission`.
|
||||
NodeFieldTypeMappings(
|
||||
HashMap<Qualified<types::CustomTypeName>, resolved::model::FilterPermission>,
|
||||
HashMapWithJsonKey<Qualified<types::CustomTypeName>, resolved::model::FilterPermission>,
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -1 +1,92 @@
|
||||
pub mod json_ext;
|
||||
use serde::{de::DeserializeOwned, ser::SerializeMap, Deserialize, Serialize};
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
/// HashMapWithJsonKey serializes the key<K> as a String
|
||||
/// during serialization and similarly while deserialization, the keys
|
||||
/// are expected to be Stringified and it is then deserialized into K.
|
||||
/// This type can be helpful when a HashMap<K,V> needs to be serialized,
|
||||
/// where K is a custom struct and which serializes into a JSON object
|
||||
/// by default, serializing such a HashMap into JSON will throw an error
|
||||
/// because JSON spec mandates that the keys in a JSON object be keys.
|
||||
/// So, wrapping the HashMap with this type would serialize the Hashmap's
|
||||
/// keys as strings and deserialize correspondingly.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HashMapWithJsonKey<K: Serialize + Eq + Hash + for<'a> Deserialize<'a>, V>(
|
||||
pub HashMap<K, V>,
|
||||
);
|
||||
|
||||
impl<K: Serialize + for<'a> Deserialize<'a> + Eq + Hash, V: Serialize> Serialize
|
||||
for HashMapWithJsonKey<K, V>
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut map = serializer.serialize_map(Some(self.0.len()))?;
|
||||
for (k, v) in self.0.iter() {
|
||||
let stringified_key = serde_json::to_string(k).map_err(serde::ser::Error::custom)?;
|
||||
map.serialize_entry(&stringified_key, v)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, K: DeserializeOwned + Hash + Eq + Serialize, V: Deserialize<'de>> Deserialize<'de>
|
||||
for HashMapWithJsonKey<K, V>
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let map: HashMap<String, V> = Deserialize::deserialize(deserializer)?;
|
||||
let mut result = HashMap::new();
|
||||
for (k, v) in map.into_iter() {
|
||||
let k_str = serde_json::from_str(&k).map_err(serde::de::Error::custom)?;
|
||||
result.insert(k_str, v);
|
||||
}
|
||||
Ok(HashMapWithJsonKey(result))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::utils::HashMapWithJsonKey;
|
||||
|
||||
#[test]
|
||||
fn test_hashmap_with_serializable_key() {
|
||||
#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Debug, Clone)]
|
||||
struct Foo {
|
||||
x: u32,
|
||||
}
|
||||
|
||||
let mut test_map: HashMap<Foo, String> = HashMap::new();
|
||||
test_map.insert(Foo { x: 1 }, "hello".to_string());
|
||||
|
||||
// The `test_map` cannot be serialized as is because
|
||||
// the key by default is serialized to a JSON object
|
||||
// and the JSON spec mandates that in a JSON object, the
|
||||
// key must be a String.
|
||||
|
||||
assert!(serde_json::to_string(&test_map).is_err());
|
||||
|
||||
let test_map_with_serializable_key = HashMapWithJsonKey(test_map.clone());
|
||||
|
||||
let serialized_test_map_with_serializable_key =
|
||||
serde_json::to_string(&test_map_with_serializable_key).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
serialized_test_map_with_serializable_key,
|
||||
"{\"{\\\"x\\\":1}\":\"hello\"}"
|
||||
);
|
||||
|
||||
let deserialized_test_map_with_serializable_key: HashMapWithJsonKey<Foo, String> =
|
||||
serde_json::from_str(&serialized_test_map_with_serializable_key).unwrap();
|
||||
|
||||
assert_eq!(test_map, deserialized_test_map_with_serializable_key.0);
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,9 @@ pub fn test_execution_expectation_legacy(test_path_string: &str, common_metadata
|
||||
let gds = GDS::new(serde_json::from_value(metadata).unwrap()).unwrap();
|
||||
let schema = GDS::build_schema(&gds).unwrap();
|
||||
|
||||
// Ensure schema is serialized successfully.
|
||||
serde_json::to_string(&schema).unwrap();
|
||||
|
||||
let query = fs::read_to_string(request_path).unwrap();
|
||||
|
||||
let session = {
|
||||
@ -129,6 +132,9 @@ pub fn test_execution_expectation(test_path_string: &str, common_metadata_paths:
|
||||
let gds = GDS::new(serde_json::from_value(metadata).unwrap()).unwrap();
|
||||
let schema = GDS::build_schema(&gds).unwrap();
|
||||
|
||||
// Ensure schema is serialized successfully.
|
||||
serde_json::to_string(&schema).unwrap();
|
||||
|
||||
let query = fs::read_to_string(request_path).unwrap();
|
||||
|
||||
let session_vars_path = &test_path.join("session_variables.json");
|
||||
|
Loading…
Reference in New Issue
Block a user