Skip to content

Commit

Permalink
H-3331: Validate all data type constraints (#5165)
Browse files Browse the repository at this point in the history
  • Loading branch information
TimDiekmann authored Sep 18, 2024
1 parent ec92342 commit b28fe42
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ pub trait EntityVisitor: Sized + Send + Sync {
/// Visits a leaf value.
///
/// By default, this does nothing.
#[expect(unused_variables, reason = "No-op implementation")]
fn visit_value<P>(
&mut self,
data_type: &DataTypeWithMetadata,
Expand All @@ -99,7 +98,7 @@ pub trait EntityVisitor: Sized + Send + Sync {
where
P: DataTypeProvider + Sync,
{
async { Ok(()) }
walk_value(self, data_type, value, metadata, type_provider)
}

/// Visits a property.
Expand Down Expand Up @@ -205,6 +204,48 @@ macro_rules! extend_report {
};
}

/// Walks through a JSON value using the provided schema.
///
/// For all referenced data types [`EntityVisitor::visit_value`] is called.
///
/// # Errors
///
/// Any error that can be returned by the visitor methods.
pub async fn walk_value<V, P>(
visitor: &mut V,
data_type: &DataTypeWithMetadata,
value: &mut JsonValue,
metadata: &mut ValueMetadata,
type_provider: &P,
) -> Result<(), Report<TraversalError>>
where
V: EntityVisitor,
P: DataTypeProvider + Sync,
{
let mut status = Ok::<_, Report<TraversalError>>(());
for parent in &data_type.schema.all_of {
match type_provider
.provide_type(&parent.url)
.await
.change_context_lazy(|| TraversalError::DataTypeRetrieval { id: parent.clone() })
{
Ok(parent) => {
if let Err(error) = visitor
.visit_value(parent.borrow(), value, metadata, type_provider)
.await
{
extend_report!(status, error);
}
}
Err(error) => {
extend_report!(status, error);
continue;
}
}
}
status
}

/// Walks through a property using the provided schema.
///
/// Depending on the property, [`EntityVisitor::visit_one_of_property`],
Expand Down
38 changes: 33 additions & 5 deletions libs/@local/hash-validation/src/entity_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use graph_types::{
link::LinkData,
property::{
visitor::{
walk_array, walk_object, walk_one_of_property_value, EntityVisitor, TraversalError,
walk_array, walk_object, walk_one_of_property_value, walk_value, EntityVisitor,
TraversalError,
},
PropertyPath, PropertyWithMetadataArray, PropertyWithMetadataObject,
PropertyWithMetadataValue, ValueMetadata,
Expand Down Expand Up @@ -275,6 +276,26 @@ pub struct EntityPreprocessor {
pub components: ValidateEntityComponents,
}

struct ValueValidator;

impl EntityVisitor for ValueValidator {
async fn visit_value<P>(
&mut self,
data_type: &DataTypeWithMetadata,
value: &mut JsonValue,
_: &mut ValueMetadata,
_: &P,
) -> Result<(), Report<TraversalError>>
where
P: DataTypeProvider + Sync,
{
data_type
.schema
.validate_constraints(value)
.change_context(TraversalError::ConstraintUnfulfilled)
}
}

impl EntityVisitor for EntityPreprocessor {
async fn visit_value<P>(
&mut self,
Expand Down Expand Up @@ -329,13 +350,20 @@ impl EntityVisitor for EntityPreprocessor {
extend_report!(status, TraversalError::AmbiguousDataType);
}

if let Err(err) = data_type
.schema
.validate_constraints(value)
.change_context(TraversalError::ConstraintUnfulfilled)
if let Err(err) = ValueValidator
.visit_value(data_type, value, metadata, type_provider)
.await
{
extend_report!(status, err);
}
walk_value(
&mut ValueValidator,
data_type,
value,
metadata,
type_provider,
)
.await?;

status
}
Expand Down
9 changes: 3 additions & 6 deletions tests/hash-graph-http/tests/ambiguous.http
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ X-Authenticated-User-Actor-Id: {{account_id}}
"$id": "http://localhost:3000/@alice/types/data-type/meter/v/1",
"title": "Meter",
"type": "number",
"description": "A unit of length",
"minimum": 0
"description": "A unit of length"
}
],
"conversions": {},
Expand Down Expand Up @@ -96,8 +95,7 @@ X-Authenticated-User-Actor-Id: {{account_id}}
"$id": "http://localhost:3000/@alice/types/data-type/millimeter/v/1",
"title": "Millimeter",
"type": "number",
"description": "A unit of length",
"minimum": 0
"description": "A unit of length"
},
"conversions": {
"http://localhost:3000/@alice/types/data-type/meter/": {
Expand Down Expand Up @@ -133,8 +131,7 @@ X-Authenticated-User-Actor-Id: {{account_id}}
"$id": "http://localhost:3000/@alice/types/data-type/miles/v/1",
"title": "Miles",
"type": "number",
"description": "A unit of length",
"minimum": 0
"description": "A unit of length"
},
"conversions": {
"http://localhost:3000/@alice/types/data-type/meter/": {
Expand Down

0 comments on commit b28fe42

Please sign in to comment.