mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-10-03 21:37:40 +03:00
Introduce Spanned
type (#1147)
<!-- The PR description should answer 2 important questions: --> ### What This PR adds the `Spanned` type: an OpenDD wrapper that can be placed inside the Metadata. It's basically a pair of the value and the path to the value in the original metadata. This allows us to do things like source maps. <!-- What is this PR trying to accomplish (and why, if it's not obvious)? --> <!-- Consider: do we need to add a changelog entry? --> <!-- Does this PR introduce new validation that might break old builds? --> <!-- Consider: do we need to put new checks behind a flag? --> ### How It's almost exactly what @danieljharvey proposed originally. <!-- How is it trying to accomplish it (what are the implementation steps)? --> --------- Co-authored-by: Daniel Harvey <danieljamesharvey@gmail.com> V3_GIT_ORIGIN_REV_ID: 4f037686b6981fffc4b0a8ac8f95c2f9c623af67
This commit is contained in:
parent
0e4a3afbca
commit
4630ade31e
@ -407,7 +407,7 @@ fn make_order_by_expression(
|
||||
) -> Result<Qualified<OrderByExpressionIdentifier>, ModelsError> {
|
||||
let identifier = Qualified::new(
|
||||
subgraph.clone(),
|
||||
OrderByExpressionIdentifier::FromModel(model_v1.name.clone()),
|
||||
OrderByExpressionIdentifier::FromModel(model_v1.name.value.clone()),
|
||||
);
|
||||
let ordered_type = Qualified::new(subgraph.clone(), model_v1.object_type.clone());
|
||||
let open_dds_orderable_fields = model_v1
|
||||
|
@ -2657,12 +2657,11 @@
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$id": "https://hasura.io/jsonschemas/metadata/ModelName",
|
||||
"title": "ModelName",
|
||||
"description": "The name of the data model.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ModelName"
|
||||
}
|
||||
]
|
||||
"type": "string",
|
||||
"pattern": "^[_a-zA-Z][_a-zA-Z0-9]*$"
|
||||
},
|
||||
"objectType": {
|
||||
"description": "The type of the objects of which this model is a collection.",
|
||||
|
@ -19,6 +19,7 @@ pub mod plugins;
|
||||
pub mod query;
|
||||
pub mod relationships;
|
||||
pub mod session_variables;
|
||||
pub mod spanned;
|
||||
pub mod test_utils;
|
||||
pub mod traits;
|
||||
pub mod types;
|
||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||
data_connector::{CollectionName, DataConnectorName},
|
||||
identifier::Identifier,
|
||||
order_by_expression::OrderByExpressionName,
|
||||
spanned::Spanned,
|
||||
str_newtype,
|
||||
traits::{OpenDd, OpenDdDeserializeError},
|
||||
types::{CustomTypeName, Deprecated, FieldName, GraphQlFieldName, GraphQlTypeName},
|
||||
@ -100,8 +101,8 @@ impl Model {
|
||||
|
||||
pub fn name(&self) -> &ModelName {
|
||||
match self {
|
||||
Model::V1(v1) => &v1.name,
|
||||
Model::V2(v2) => &v2.name,
|
||||
Model::V1(v1) => &v1.name.value,
|
||||
Model::V2(v2) => &v2.name.value,
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +170,7 @@ impl Model {
|
||||
/// A data model is a collection of objects of a particular type. Models can support one or more CRUD operations.
|
||||
pub struct ModelV1 {
|
||||
/// The name of the data model.
|
||||
pub name: ModelName,
|
||||
pub name: Spanned<ModelName>,
|
||||
/// The type of the objects of which this model is a collection.
|
||||
pub object_type: CustomTypeName,
|
||||
/// Whether this model should be used as the global ID source for all objects of its type.
|
||||
@ -201,7 +202,7 @@ pub struct ModelV1 {
|
||||
/// ModelV2 implements the changes described in rfcs/open-dd-expression-type-changes.md.
|
||||
pub struct ModelV2 {
|
||||
/// The name of the data model.
|
||||
pub name: ModelName,
|
||||
pub name: Spanned<ModelName>,
|
||||
/// The type of the objects of which this model is a collection.
|
||||
pub object_type: CustomTypeName,
|
||||
/// Whether this model should be used as the global ID source for all objects of its type.
|
||||
|
88
v3/crates/open-dds/src/spanned.rs
Normal file
88
v3/crates/open-dds/src/spanned.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use crate::traits::{OpenDd, OpenDdDeserializeError};
|
||||
use core::ops::Deref;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
/// Wrapper that combines an item with its parsed JSONPath
|
||||
/// for use in error reporting
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Spanned<T> {
|
||||
pub path: jsonpath::JSONPath,
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
impl<T> Deref for Spanned<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Serialize> Serialize for Spanned<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.value.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: OpenDd> OpenDd for Spanned<T> {
|
||||
fn deserialize(
|
||||
json: serde_json::Value,
|
||||
path: jsonpath::JSONPath,
|
||||
) -> Result<Self, OpenDdDeserializeError> {
|
||||
Ok(Spanned {
|
||||
value: T::deserialize(json, path.clone())?,
|
||||
path,
|
||||
})
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
T::json_schema(gen)
|
||||
}
|
||||
|
||||
fn _schema_name() -> String {
|
||||
"Spanned".to_string()
|
||||
}
|
||||
|
||||
fn _schema_is_referenceable() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn test_spanned_path() {
|
||||
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/reference.json");
|
||||
let metadata =
|
||||
open_dds::Metadata::from_json_str(&std::fs::read_to_string(path).unwrap()).unwrap();
|
||||
|
||||
// Very deliberate tree-walking in the absence of optics.
|
||||
let open_dds::Metadata::Versioned(versioned) = metadata else {
|
||||
todo!("Test not implemented for unversioned metadata")
|
||||
};
|
||||
|
||||
let open_dds::MetadataWithVersion::V2(metadata_v2) = versioned else {
|
||||
todo!("Test not implemented for non-V2 metadata")
|
||||
};
|
||||
|
||||
for (subgraph_index, subgraph) in metadata_v2.subgraphs.iter().enumerate() {
|
||||
for (object_index, object) in subgraph.objects.iter().enumerate() {
|
||||
if let open_dds::OpenDdSubgraphObject::Model(model) = object {
|
||||
let path = match model {
|
||||
open_dds::models::Model::V1(model) => model.name.path.to_string(),
|
||||
open_dds::models::Model::V2(model) => model.name.path.to_string(),
|
||||
};
|
||||
|
||||
let expected = format!(
|
||||
"$.subgraphs[{subgraph_index}].objects[{object_index}].definition.name"
|
||||
);
|
||||
assert_eq!(path, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user