Skip to content

Commit

Permalink
H-3421: Resolve closed data types on creation/updating (#5361)
Browse files Browse the repository at this point in the history
  • Loading branch information
TimDiekmann authored Oct 11, 2024
1 parent c3e3b30 commit 47d7f70
Show file tree
Hide file tree
Showing 11 changed files with 789 additions and 248 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ humansize = { version = "=2.1.3", default-features = false }
hyper = { version = "=1.4.1", default-features = false }
include_dir = { version = "=0.7.4", default-features = false }
insta = { version = "=1.40.0", default-features = false }
itertools = { version = "0.13.0", default-features = false }
jsonschema = { version = "=0.22.3", default-features = false }
justjson = { version = "=0.3.0", default-features = false }
lexical = { version = "=7.0.2", default-features = false }
Expand Down
4 changes: 1 addition & 3 deletions apps/hash-graph/libs/graph/src/store/ontology.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,11 @@ pub trait DataTypeStore {
params: CountDataTypesParams<'_>,
) -> impl Future<Output = Result<usize, QueryError>> + Send;

/// Get the [`DataTypes`] specified by the [`GetDataTypesParams`].
/// Get the [`DataType`]s specified by the [`GetDataTypesParams`].
///
/// # Errors
///
/// - if the requested [`DataType`] doesn't exist.
///
/// [`DataTypes`]: DataType
fn get_data_types(
&self,
actor_id: AccountId,
Expand Down
10 changes: 5 additions & 5 deletions apps/hash-graph/libs/graph/src/store/postgres/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ use tokio_postgres::{GenericClient, error::SqlState};
use type_system::{
Valid,
schema::{
ClosedEntityType, Conversions, DataType, DataTypeId, DataTypeInheritanceData,
DataTypeReference, EntityType, EntityTypeReference, PropertyType, PropertyTypeReference,
ClosedEntityType, Conversions, DataType, DataTypeId, DataTypeReference,
DataTypeResolveData, EntityType, EntityTypeReference, PropertyType, PropertyTypeReference,
},
url::{BaseUrl, OntologyTypeVersion, VersionedUrl},
};
Expand Down Expand Up @@ -459,9 +459,9 @@ where
pub async fn insert_data_type_references(
&self,
ontology_id: DataTypeId,
metadata: &DataTypeInheritanceData,
metadata: &DataTypeResolveData,
) -> Result<(), InsertionError> {
for (target, depth) in &metadata.inheritance_depths {
for (target, depth) in metadata.inheritance_depths() {
self.as_client()
.query(
"
Expand All @@ -475,7 +475,7 @@ where
$3
);
",
&[&ontology_id, target, depth],
&[&ontology_id, &target, &depth],
)
.await
.change_context(InsertionError)?;
Expand Down
123 changes: 72 additions & 51 deletions apps/hash-graph/libs/graph/src/store/postgres/ontology/data_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ use temporal_versioning::{RightBoundedTemporalInterval, Timestamp, TransactionTi
use tokio_postgres::{GenericClient, Row};
use tracing::instrument;
use type_system::{
Validator,
Valid, Validator,
schema::{
ConversionDefinition, Conversions, DataTypeId, DataTypeInheritanceData, DataTypeValidator,
InheritanceDepth, OntologyTypeResolver,
ClosedDataType, ConversionDefinition, Conversions, DataType, DataTypeEdge, DataTypeId,
DataTypeResolveData, DataTypeValidator, InheritanceDepth, OntologyTypeResolver,
},
url::{BaseUrl, OntologyTypeVersion, VersionedUrl},
};
Expand Down Expand Up @@ -116,27 +116,47 @@ where
async fn get_data_type_inheritance_metadata(
&self,
data_types: &[DataTypeId],
) -> Result<impl Iterator<Item = (DataTypeId, DataTypeInheritanceData)>, QueryError> {
) -> Result<impl Iterator<Item = (DataTypeId, DataTypeResolveData)>, QueryError> {
Ok(self
.as_client()
.query(
"
SELECT source_data_type_ontology_id, target_data_type_ontology_ids, depths
FROM data_type_inherits_from_aggregation
WHERE source_data_type_ontology_id = ANY($1)
SELECT
source_data_type_ontology_id,
array_agg(target_data_type_ontology_id),
array_agg(depth),
array_agg(schema)
FROM (
SELECT *
FROM data_type_inherits_from
JOIN data_types ON target_data_type_ontology_id = ontology_id
WHERE source_data_type_ontology_id = ANY($1)
ORDER BY source_data_type_ontology_id, depth, schema->>'$id'
) AS subquery
GROUP BY source_data_type_ontology_id;
",
&[&data_types],
)
.await
.change_context(QueryError)?
.into_iter()
.map(|row| {
let source: DataTypeId = row.get(0);
let source_id: DataTypeId = row.get(0);
let targets: Vec<DataTypeId> = row.get(1);
let depths: Vec<InheritanceDepth> = row.get(2);
(source, DataTypeInheritanceData {
inheritance_depths: targets.into_iter().zip(depths).collect(),
})
let schemas: Vec<Valid<DataType>> = row.get(3);

let mut resolve_data = DataTypeResolveData::default();
for ((target_id, schema), depth) in targets.into_iter().zip(schemas).zip(depths) {
resolve_data.add_edge(
DataTypeEdge::Inheritance,
Arc::new(schema.into_inner()),
target_id,
depth.inner(),
);
}

(source_id, resolve_data)
}))
}

Expand Down Expand Up @@ -456,7 +476,12 @@ where

let mut ontology_type_resolver = OntologyTypeResolver::default();

for (data_type_id, inserted_data_type) in &inserted_data_types {
ontology_type_resolver.add_unresolved(*data_type_id, Arc::clone(inserted_data_type));
}

let required_parent_ids = data_type_reference_ids.into_iter().collect::<Vec<_>>();

let mut parent_inheritance_data = transaction
.get_data_type_inheritance_metadata(&required_parent_ids)
.await
Expand Down Expand Up @@ -498,35 +523,26 @@ where
if !parent.schema.all_of.is_empty() {
tracing::warn!("No inheritance data found for `{}`", parent.schema.id);
}
ontology_type_resolver.add_open(parent_id, Arc::new(parent.schema));
ontology_type_resolver.add_unresolved(parent_id, Arc::new(parent.schema));
}
});

for (data_type_id, inserted_data_type) in &inserted_data_types {
ontology_type_resolver.add_open(*data_type_id, Arc::clone(inserted_data_type));
}
let schema_metadata = inserted_data_types
let closed_schemas = inserted_data_types
.iter()
.map(|(data_type_id, _)| {
ontology_type_resolver
.map(|(data_type_id, data_type)| {
let closed_metadata = ontology_type_resolver
.resolve_data_type_metadata(*data_type_id)
.change_context(InsertionError)
.change_context(InsertionError)?;
let closed_schema =
ClosedDataType::from_resolve_data((**data_type).clone(), &closed_metadata)
.change_context(InsertionError)?;

Ok((closed_schema, closed_metadata))
})
.collect::<Result<Vec<_>, _>>()?;

let data_type_validator = DataTypeValidator;
for (data_type_id, data_type) in &inserted_data_types {
// TODO: Validate ontology types on creation
// see https://linear.app/hash/issue/H-2976/validate-ontology-types-on-creation
// let closed_schema = data_type_validator
// .validate(
// ontology_type_resolver
// .get_closed_data_type(*data_type_id)
// .change_context(InsertionError)?,
// )
// .await
// .attach(StatusCode::InvalidArgument)
// .change_context(InsertionError)?;
let schema = data_type_validator
.validate_ref(&**data_type)
.await
Expand All @@ -536,10 +552,17 @@ where
.insert_data_type_with_id(*data_type_id, schema)
.await?;
}
for (schema_metadata, (data_type_id, _)) in schema_metadata.iter().zip(&inserted_data_types)
for ((closed_schema, closed_metadata), (data_type_id, _)) in
closed_schemas.iter().zip(&inserted_data_types)
{
data_type_validator
.validate_ref(closed_schema)
.await
.attach(StatusCode::InvalidArgument)
.change_context(InsertionError)?;

transaction
.insert_data_type_references(*data_type_id, schema_metadata)
.insert_data_type_references(*data_type_id, closed_metadata)
.await?;
}

Expand Down Expand Up @@ -809,7 +832,7 @@ where
};

let schema = data_type_validator
.validate_ref(&params.schema)
.validate(params.schema)
.await
.change_context(UpdateError)?;

Expand Down Expand Up @@ -861,37 +884,35 @@ where
if !parent.schema.all_of.is_empty() {
tracing::warn!("No inheritance data found for `{}`", parent.schema.id);
}
ontology_type_resolver.add_open(parent_id, Arc::new(parent.schema));
ontology_type_resolver.add_unresolved(parent_id, Arc::new(parent.schema));
}
});

ontology_type_resolver.add_open(new_ontology_id, Arc::new(schema.clone().into_inner()));
let metadata = ontology_type_resolver
ontology_type_resolver
.add_unresolved(new_ontology_id, Arc::new(schema.clone().into_inner()));
let resolve_data = ontology_type_resolver
.resolve_data_type_metadata(new_ontology_id)
.change_context(UpdateError)?;

// TODO: Validate ontology types on creation
// see https://linear.app/hash/issue/H-2976/validate-ontology-types-on-creation
// let closed_schema = data_type_validator
// .validate(
// ontology_type_resolver
// .get_closed_data_type(new_ontology_id)
// .change_context(UpdateError)?,
// )
// .await
// .change_context(UpdateError)?;
let closed_schema = data_type_validator
.validate(
ClosedDataType::from_resolve_data(schema.clone().into_inner(), &resolve_data)
.change_context(UpdateError)?,
)
.await
.change_context(UpdateError)?;
let (ontology_id, owned_by_id, temporal_versioning) = transaction
.update_owned_ontology_id(&schema.id, &provenance.edition)
.await?;

let data_type_id = DataTypeId::from(ontology_id);

transaction
.insert_data_type_with_id(data_type_id, schema)
.insert_data_type_with_id(data_type_id, &schema)
.await
.change_context(UpdateError)?;
transaction
.insert_data_type_references(data_type_id, &metadata)
.insert_data_type_references(data_type_id, &resolve_data)
.await
.change_context(UpdateError)?;

Expand Down Expand Up @@ -960,7 +981,7 @@ where
Err(error.change_context(UpdateError))
} else {
let metadata = DataTypeMetadata {
record_id: OntologyTypeRecordId::from(params.schema.id.clone()),
record_id: OntologyTypeRecordId::from(closed_schema.id.clone()),
classification: OntologyTypeClassificationMetadata::Owned { owned_by_id },
temporal_versioning,
provenance,
Expand All @@ -970,7 +991,7 @@ where
if let Some(temporal_client) = &self.temporal_client {
temporal_client
.start_update_data_type_embeddings_workflow(actor_id, &[DataTypeWithMetadata {
schema: params.schema,
schema: schema.into_inner(),
metadata: metadata.clone(),
}])
.await
Expand Down Expand Up @@ -1107,7 +1128,7 @@ where
.map(|data_type| {
let schema = Arc::new(data_type.schema);
let data_type_id = DataTypeId::from_url(&schema.id);
ontology_type_resolver.add_open(data_type_id, Arc::clone(&schema));
ontology_type_resolver.add_unresolved(data_type_id, Arc::clone(&schema));
data_type_id
})
.collect::<Vec<_>>();
Expand Down
1 change: 1 addition & 0 deletions libs/@blockprotocol/type-system/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ uuid = { workspace = true, public = true, features = ["v5", "serde", "std"] }

# Private workspace dependencies
futures = { workspace = true }
itertools = { workspace = true, features = ["use_alloc"] }

# Private third-party dependencies
regex = { workspace = true, features = ["std"] }
Expand Down
Loading

0 comments on commit 47d7f70

Please sign in to comment.