diff --git a/packages/graph/clients/typescript/api.ts b/packages/graph/clients/typescript/api.ts index ea33dd62a94..6313c6f7eba 100644 --- a/packages/graph/clients/typescript/api.ts +++ b/packages/graph/clients/typescript/api.ts @@ -467,43 +467,6 @@ export const EntityTypeTypeEnum = { export type EntityTypeTypeEnum = typeof EntityTypeTypeEnum[keyof typeof EntityTypeTypeEnum]; -/** - * - * @export - * @interface EntityTypeRootedSubgraph - */ -export interface EntityTypeRootedSubgraph { - /** - * - * @type {PersistedEntityType} - * @memberof EntityTypeRootedSubgraph - */ - entityType: PersistedEntityType; - /** - * - * @type {Array} - * @memberof EntityTypeRootedSubgraph - */ - referencedDataTypes: Array; - /** - * - * @type {Array} - * @memberof EntityTypeRootedSubgraph - */ - referencedEntityTypes: Array; - /** - * - * @type {Array} - * @memberof EntityTypeRootedSubgraph - */ - referencedLinkTypes: Array; - /** - * - * @type {Array} - * @memberof EntityTypeRootedSubgraph - */ - referencedPropertyTypes: Array; -} /** * @type GraphElementIdentifier * @export @@ -3559,10 +3522,7 @@ export const EntityTypeApiFp = function (configuration?: Configuration) { structuralQuery: StructuralQuery, options?: AxiosRequestConfig, ): Promise< - ( - axios?: AxiosInstance, - basePath?: string, - ) => AxiosPromise> + (axios?: AxiosInstance, basePath?: string) => AxiosPromise > { const localVarAxiosArgs = await localVarAxiosParamCreator.getEntityTypesByQuery( @@ -3676,7 +3636,7 @@ export const EntityTypeApiFactory = function ( getEntityTypesByQuery( structuralQuery: StructuralQuery, options?: any, - ): AxiosPromise> { + ): AxiosPromise { return localVarFp .getEntityTypesByQuery(structuralQuery, options) .then((request) => request(axios, basePath)); @@ -3750,7 +3710,7 @@ export interface EntityTypeApiInterface { getEntityTypesByQuery( structuralQuery: StructuralQuery, options?: AxiosRequestConfig, - ): AxiosPromise>; + ): AxiosPromise; /** * @@ -5671,10 +5631,7 @@ export const GraphApiFp = function (configuration?: Configuration) { structuralQuery: StructuralQuery, options?: AxiosRequestConfig, ): Promise< - ( - axios?: AxiosInstance, - basePath?: string, - ) => AxiosPromise> + (axios?: AxiosInstance, basePath?: string) => AxiosPromise > { const localVarAxiosArgs = await localVarAxiosParamCreator.getEntityTypesByQuery( @@ -6282,7 +6239,7 @@ export const GraphApiFactory = function ( getEntityTypesByQuery( structuralQuery: StructuralQuery, options?: any, - ): AxiosPromise> { + ): AxiosPromise { return localVarFp .getEntityTypesByQuery(structuralQuery, options) .then((request) => request(axios, basePath)); @@ -6667,7 +6624,7 @@ export interface GraphApiInterface { getEntityTypesByQuery( structuralQuery: StructuralQuery, options?: AxiosRequestConfig, - ): AxiosPromise>; + ): AxiosPromise; /** * diff --git a/packages/graph/hash_graph/lib/graph/src/api/rest/entity_type.rs b/packages/graph/hash_graph/lib/graph/src/api/rest/entity_type.rs index e5774bb55d2..c7a5b1afb9e 100644 --- a/packages/graph/hash_graph/lib/graph/src/api/rest/entity_type.rs +++ b/packages/graph/hash_graph/lib/graph/src/api/rest/entity_type.rs @@ -18,15 +18,15 @@ use crate::{ api::rest::{api_resource::RoutedResource, read_from_store, report_to_status_code}, ontology::{ domain_validator::{DomainValidator, ValidateOntologyType}, - patch_id_and_parse, AccountId, EntityTypeRootedSubgraph, PersistedEntityType, - PersistedOntologyIdentifier, PersistedOntologyMetadata, + patch_id_and_parse, AccountId, PersistedEntityType, PersistedOntologyIdentifier, + PersistedOntologyMetadata, }, store::{ error::{BaseUriAlreadyExists, BaseUriDoesNotExist}, query::Expression, EntityTypeStore, StorePool, }, - subgraph::StructuralQuery, + subgraph::{StructuralQuery, Subgraph}, }; #[derive(OpenApi)] @@ -47,7 +47,7 @@ use crate::{ PersistedOntologyMetadata, PersistedEntityType, StructuralQuery, - EntityTypeRootedSubgraph, + Subgraph, ) ), tags( @@ -149,7 +149,7 @@ async fn create_entity_type( request_body = StructuralQuery, tag = "EntityType", responses( - (status = 200, content_type = "application/json", body = [EntityTypeRootedSubgraph], description = "A list of subgraphs rooted at entity types that satisfy the given query, each resolved to the requested depth."), + (status = 200, content_type = "application/json", body = Subgraph, description = "A subgraph rooted at entity types that satisfy the given query, each resolved to the requested depth."), (status = 422, content_type = "text/plain", description = "Provided query is invalid"), (status = 500, description = "Store error occurred"), @@ -158,7 +158,7 @@ async fn create_entity_type( async fn get_entity_types_by_query( pool: Extension>, Json(query): Json, -) -> Result>, StatusCode> { +) -> Result, StatusCode> { pool.acquire() .map_err(|error| { tracing::error!(?error, "Could not acquire access to the store"); diff --git a/packages/graph/hash_graph/lib/graph/src/ontology/mod.rs b/packages/graph/hash_graph/lib/graph/src/ontology/mod.rs index 2feaf4651cd..3a51e32a2a2 100644 --- a/packages/graph/hash_graph/lib/graph/src/ontology/mod.rs +++ b/packages/graph/hash_graph/lib/graph/src/ontology/mod.rs @@ -306,13 +306,3 @@ impl PersistedEntityType { &self.metadata } } - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] -#[serde(rename_all = "camelCase")] -pub struct EntityTypeRootedSubgraph { - pub entity_type: PersistedEntityType, - pub referenced_data_types: Vec, - pub referenced_property_types: Vec, - pub referenced_link_types: Vec, - pub referenced_entity_types: Vec, -} diff --git a/packages/graph/hash_graph/lib/graph/src/store/mod.rs b/packages/graph/hash_graph/lib/graph/src/store/mod.rs index 7075750e7f4..ebc06f8d000 100644 --- a/packages/graph/hash_graph/lib/graph/src/store/mod.rs +++ b/packages/graph/hash_graph/lib/graph/src/store/mod.rs @@ -22,8 +22,8 @@ use crate::{ PersistedEntityMetadata, PersistedLink, }, ontology::{ - AccountId, EntityTypeRootedSubgraph, LinkTypeRootedSubgraph, PersistedDataType, - PersistedEntityType, PersistedLinkType, PersistedOntologyMetadata, PersistedPropertyType, + AccountId, LinkTypeRootedSubgraph, PersistedDataType, PersistedEntityType, + PersistedLinkType, PersistedOntologyMetadata, PersistedPropertyType, }, store::{error::LinkRemovalError, query::Expression}, subgraph::{StructuralQuery, Subgraph}, @@ -293,15 +293,12 @@ pub trait EntityTypeStore: for<'q> crud::Read = E actor_id: AccountId, ) -> Result; - /// Get the [`EntityTypeRootedSubgraph`]s specified by the [`StructuralQuery`]. + /// Get the [`Subgraph`]s specified by the [`StructuralQuery`]. /// /// # Errors /// /// - if the requested [`EntityType`] doesn't exist. - async fn get_entity_type( - &self, - query: &StructuralQuery, - ) -> Result, QueryError>; + async fn get_entity_type(&self, query: &StructuralQuery) -> Result; /// Update the definition of an existing [`EntityType`]. /// diff --git a/packages/graph/hash_graph/lib/graph/src/store/postgres/ontology/entity_type/mod.rs b/packages/graph/hash_graph/lib/graph/src/store/postgres/ontology/entity_type/mod.rs index 703a61a2635..2d1b3606c6a 100644 --- a/packages/graph/hash_graph/lib/graph/src/store/postgres/ontology/entity_type/mod.rs +++ b/packages/graph/hash_graph/lib/graph/src/store/postgres/ontology/entity_type/mod.rs @@ -3,15 +3,13 @@ mod resolve; use std::{future::Future, pin::Pin}; use async_trait::async_trait; -use error_stack::{IntoReport, Result, ResultExt}; +use error_stack::{IntoReport, Report, Result, ResultExt}; use futures::{stream, FutureExt, StreamExt, TryStreamExt}; use tokio_postgres::GenericClient; use type_system::{uri::VersionedUri, EntityType}; use crate::{ - ontology::{ - AccountId, EntityTypeRootedSubgraph, PersistedEntityType, PersistedOntologyMetadata, - }, + ontology::{AccountId, PersistedEntityType, PersistedOntologyMetadata}, store::{ crud::Read, postgres::{ @@ -22,6 +20,7 @@ use crate::{ }, subgraph::{ EdgeKind, GraphElementIdentifier, GraphResolveDepths, OutwardEdge, StructuralQuery, + Subgraph, }, }; @@ -203,16 +202,13 @@ impl EntityTypeStore for PostgresStore { Ok(metadata) } - async fn get_entity_type( - &self, - query: &StructuralQuery, - ) -> Result, QueryError> { + async fn get_entity_type(&self, query: &StructuralQuery) -> Result { let StructuralQuery { ref expression, graph_resolve_depths, } = *query; - stream::iter(Read::::read(self, expression).await?) + let subgraphs = stream::iter(Read::::read(self, expression).await?) .then(|entity_type| async move { let mut dependency_context = DependencyContext::new(graph_resolve_depths); @@ -229,23 +225,17 @@ impl EntityTypeStore for PostgresStore { ) .await?; - let root = dependency_context - .referenced_entity_types - .remove(&entity_type_id) - .expect("root was not added to the subgraph"); + let root = GraphElementIdentifier::OntologyElementId(entity_type_id); - Ok(EntityTypeRootedSubgraph { - entity_type: root, - referenced_data_types: dependency_context.referenced_data_types.into_vec(), - referenced_property_types: dependency_context - .referenced_property_types - .into_vec(), - referenced_link_types: dependency_context.referenced_link_types.into_vec(), - referenced_entity_types: dependency_context.referenced_entity_types.into_vec(), - }) + Ok::<_, Report>(dependency_context.into_subgraph(vec![root])) }) - .try_collect() - .await + .try_collect::>() + .await?; + + let mut subgraph = Subgraph::new(graph_resolve_depths); + subgraph.extend(subgraphs); + + Ok(subgraph) } async fn update_entity_type( diff --git a/packages/graph/hash_graph/tests/integration/postgres/mod.rs b/packages/graph/hash_graph/tests/integration/postgres/mod.rs index d1da398b6d7..01da2309a76 100644 --- a/packages/graph/hash_graph/tests/integration/postgres/mod.rs +++ b/packages/graph/hash_graph/tests/integration/postgres/mod.rs @@ -207,7 +207,7 @@ impl DatabaseApi<'_> { .expect("no property type found"); match vertex { - Vertex::PropertyType(persisted_data_type) => Ok(persisted_data_type), + Vertex::PropertyType(persisted_property_type) => Ok(persisted_property_type), _ => unreachable!(), } } @@ -234,16 +234,21 @@ impl DatabaseApi<'_> { &mut self, uri: &VersionedUri, ) -> Result { - Ok(self + let vertex = self .store .get_entity_type(&StructuralQuery { expression: Expression::for_versioned_uri(uri), graph_resolve_depths: GraphResolveDepths::zeroed(), }) .await? - .pop() - .expect("no entity type found") - .entity_type) + .vertices + .remove(&GraphElementIdentifier::OntologyElementId(uri.clone())) + .expect("no entity type found"); + + match vertex { + Vertex::EntityType(persisted_entity_type) => Ok(persisted_entity_type), + _ => unreachable!(), + } } pub async fn update_entity_type( diff --git a/packages/hash/api/src/graphql/resolvers/ontology/data-type.ts b/packages/hash/api/src/graphql/resolvers/ontology/data-type.ts index b68e7d245a9..b7a28306307 100644 --- a/packages/hash/api/src/graphql/resolvers/ontology/data-type.ts +++ b/packages/hash/api/src/graphql/resolvers/ontology/data-type.ts @@ -1,7 +1,12 @@ import { ApolloError } from "apollo-server-express"; import { AxiosError } from "axios"; -import { Subgraph, QueryGetDataTypeArgs, ResolverFn } from "../../apiTypes.gen"; +import { + Subgraph, + QueryGetDataTypeArgs, + ResolverFn, + QueryGetAllLatestDataTypesArgs, +} from "../../apiTypes.gen"; import { GraphQLContext, LoggedInGraphQLContext } from "../../context"; import { mapSubgraphToGql } from "./model-mapping"; @@ -9,16 +14,15 @@ export const getAllLatestDataTypes: ResolverFn< Promise, {}, LoggedInGraphQLContext, - {} -> = async (_, __, { dataSources }) => { + QueryGetAllLatestDataTypesArgs +> = async (_, { dataTypeResolveDepth }, { dataSources }) => { const { graphApi } = dataSources; const { data: dataTypeSubgraph } = await graphApi .getDataTypesByQuery({ query: { eq: [{ path: ["version"] }, { literal: "latest" }] }, - /** @todo - make these configurable once non-primitive data types are a thing https://app.asana.com/0/1200211978612931/1202464168422955/f */ graphResolveDepths: { - dataTypeResolveDepth: 0, + dataTypeResolveDepth, propertyTypeResolveDepth: 0, linkTypeResolveDepth: 0, entityTypeResolveDepth: 0, @@ -41,7 +45,7 @@ export const getDataType: ResolverFn< {}, GraphQLContext, QueryGetDataTypeArgs -> = async (_, { dataTypeId }, { dataSources }) => { +> = async (_, { dataTypeId, dataTypeResolveDepth }, { dataSources }) => { const { graphApi } = dataSources; const { data: dataTypeSubgraph } = await graphApi @@ -51,7 +55,7 @@ export const getDataType: ResolverFn< }, /** @todo - make these configurable once non-primitive data types are a thing https://app.asana.com/0/1200211978612931/1202464168422955/f */ graphResolveDepths: { - dataTypeResolveDepth: 0, + dataTypeResolveDepth, propertyTypeResolveDepth: 0, linkTypeResolveDepth: 0, entityTypeResolveDepth: 0, diff --git a/packages/hash/api/src/graphql/resolvers/ontology/entity-type.ts b/packages/hash/api/src/graphql/resolvers/ontology/entity-type.ts index 3cbca3852a2..87c001d6889 100644 --- a/packages/hash/api/src/graphql/resolvers/ontology/entity-type.ts +++ b/packages/hash/api/src/graphql/resolvers/ontology/entity-type.ts @@ -6,21 +6,13 @@ import { MutationCreateEntityTypeArgs, MutationUpdateEntityTypeArgs, QueryGetEntityTypeArgs, + QueryGetAllLatestEntityTypesArgs, ResolverFn, - EntityTypeRootedSubgraph, + Subgraph, } from "../../apiTypes.gen"; import { LoggedInGraphQLContext } from "../../context"; import { EntityTypeModel } from "../../../model"; -import { - mapEntityTypeModelToGQL, - mapEntityTypeRootedSubgraphToGQL, -} from "./model-mapping"; -import { - dataTypeQueryDepth, - entityTypeQueryDepth, - linkTypeQueryDepth, - propertyTypeQueryDepth, -} from "../util"; +import { mapEntityTypeModelToGQL, mapSubgraphToGql } from "./model-mapping"; export const createEntityType: ResolverFn< Promise, @@ -43,53 +35,86 @@ export const createEntityType: ResolverFn< }; export const getAllLatestEntityTypes: ResolverFn< - Promise, + Promise, {}, LoggedInGraphQLContext, - {} -> = async (_, __, { dataSources }, info) => { + QueryGetAllLatestEntityTypesArgs +> = async ( + _, + { + dataTypeResolveDepth, + propertyTypeResolveDepth, + linkTypeResolveDepth, + entityTypeResolveDepth, + }, + { dataSources }, + __, +) => { const { graphApi } = dataSources; - const entityTypeRootedSubgraphs = await EntityTypeModel.getAllLatestResolved( - graphApi, - { - dataTypeQueryDepth: dataTypeQueryDepth(info), - propertyTypeQueryDepth: propertyTypeQueryDepth(info), - linkTypeQueryDepth: linkTypeQueryDepth(info), - entityTypeQueryDepth: entityTypeQueryDepth(info), - }, - ).catch((err: AxiosError) => { - throw new ApolloError( - `Unable to retrieve all latest entity types. ${err.response?.data}`, - "GET_ALL_ERROR", - ); - }); + const { data: entityTypeSubgraph } = await graphApi + .getEntityTypesByQuery({ + query: { eq: [{ path: ["version"] }, { literal: "latest" }] }, + graphResolveDepths: { + dataTypeResolveDepth, + propertyTypeResolveDepth, + linkTypeResolveDepth, + entityTypeResolveDepth, + linkTargetEntityResolveDepth: 0, + linkResolveDepth: 0, + }, + }) + .catch((err: AxiosError) => { + throw new ApolloError( + `Unable to retrieve all latest entity types. ${err.response?.data}`, + "GET_ALL_ERROR", + ); + }); - return entityTypeRootedSubgraphs.map(mapEntityTypeRootedSubgraphToGQL); + return mapSubgraphToGql(entityTypeSubgraph); }; export const getEntityType: ResolverFn< - Promise, + Promise, {}, LoggedInGraphQLContext, QueryGetEntityTypeArgs -> = async (_, { entityTypeId }, { dataSources }, info) => { +> = async ( + _, + { + entityTypeId, + dataTypeResolveDepth, + propertyTypeResolveDepth, + linkTypeResolveDepth, + entityTypeResolveDepth, + }, + { dataSources }, + __, +) => { const { graphApi } = dataSources; - const entityTypeRootedSubgraph = await EntityTypeModel.getResolved(graphApi, { - entityTypeId, - dataTypeQueryDepth: dataTypeQueryDepth(info), - propertyTypeQueryDepth: propertyTypeQueryDepth(info), - linkTypeQueryDepth: linkTypeQueryDepth(info), - entityTypeQueryDepth: entityTypeQueryDepth(info), - }).catch((err: AxiosError) => { - throw new ApolloError( - `Unable to retrieve entity type. ${err.response?.data}`, - "GET_ERROR", - ); - }); + const { data: entityTypeSubgraph } = await graphApi + .getEntityTypesByQuery({ + query: { + eq: [{ path: ["versionedUri"] }, { literal: entityTypeId }], + }, + graphResolveDepths: { + dataTypeResolveDepth, + propertyTypeResolveDepth, + linkTypeResolveDepth, + entityTypeResolveDepth, + linkTargetEntityResolveDepth: 0, + linkResolveDepth: 0, + }, + }) + .catch((err: AxiosError) => { + throw new ApolloError( + `Unable to retrieve entity type. ${err.response?.data}`, + "GET_ERROR", + ); + }); - return mapEntityTypeRootedSubgraphToGQL(entityTypeRootedSubgraph); + return mapSubgraphToGql(entityTypeSubgraph); }; export const updateEntityType: ResolverFn< diff --git a/packages/hash/api/src/graphql/resolvers/ontology/model-mapping.ts b/packages/hash/api/src/graphql/resolvers/ontology/model-mapping.ts index 48b6e7243f6..24defa298d3 100644 --- a/packages/hash/api/src/graphql/resolvers/ontology/model-mapping.ts +++ b/packages/hash/api/src/graphql/resolvers/ontology/model-mapping.ts @@ -5,29 +5,17 @@ import { } from "@hashintel/hash-shared/graphql/types"; import { EntityType, PropertyType } from "@blockprotocol/type-system-web"; import { - DataTypeModel, EntityTypeModel, LinkTypeModel, PropertyTypeModel, } from "../../../model"; import { - PersistedDataType as PersistedDataTypeGql, PersistedEntityType as PersistedEntityTypeGql, PersistedLinkType as PersistedLinkTypeGql, PersistedPropertyType as PersistedPropertyTypeGql, - EntityTypeRootedSubgraph as EntityTypeRootedSubgraphGql, Subgraph as SubgraphGql, } from "../../apiTypes.gen"; -export const mapDataTypeModelToGQL = ( - dataType: DataTypeModel, -): PersistedDataTypeGql => ({ - ownedById: dataType.ownedById, - accountId: dataType.ownedById, - dataTypeId: dataType.schema.$id, - dataType: dataType.schema, -}); - export const mapPropertyTypeModelToGQL = ( propertyType: PropertyTypeModel, ): PersistedPropertyTypeGql => ({ @@ -55,27 +43,6 @@ export const mapEntityTypeModelToGQL = ( entityType: entityType.schema, }); -export const mapEntityTypeRootedSubgraphToGQL = (params: { - entityType: EntityTypeModel; - referencedDataTypes: DataTypeModel[]; - referencedPropertyTypes: PropertyTypeModel[]; - referencedLinkTypes: LinkTypeModel[]; - referencedEntityTypes: EntityTypeModel[]; -}): EntityTypeRootedSubgraphGql => ({ - ownedById: params.entityType.ownedById, - accountId: params.entityType.ownedById, - entityTypeId: params.entityType.schema.$id, - entityType: params.entityType.schema, - referencedDataTypes: params.referencedDataTypes.map(mapDataTypeModelToGQL), - referencedPropertyTypes: params.referencedPropertyTypes.map( - mapPropertyTypeModelToGQL, - ), - referencedLinkTypes: params.referencedLinkTypes.map(mapLinkTypeModelToGQL), - referencedEntityTypes: params.referencedEntityTypes.map( - mapEntityTypeModelToGQL, - ), -}); - /** * @todo and a warning, this mapping function is here to compensate for * the differences between the Graph API package and the @@ -94,7 +61,10 @@ export const mapSubgraphToGql = (subgraph: Subgraph): SubgraphGql => { Object.entries(subgraph.vertices).map(([identifier, vertex]) => { switch (vertex.kind) { // These types are compatible with the Type System package's types - case "dataType" || "linkType" || "entity" || "link": { + case "dataType": + case "linkType": + case "entity": + case "link": { return [identifier, vertex]; } // The OpenAPI spec currently incorrectly expresses these @@ -118,14 +88,9 @@ export const mapSubgraphToGql = (subgraph: Subgraph): SubgraphGql => { }; return [identifier, entityTypeVertex]; } - // TypeScript is failing to recognize this is unreachable (due to the combined initial case) and therefore - // thinks the function can return undefined without it - default: { - throw new Error( - `this should be unreachable, unknown vertex kind: ${vertex.kind}`, - ); - } } + + throw new Error(`unknown vertex kind: ${JSON.stringify(vertex)}`); }), ), }; diff --git a/packages/hash/api/src/graphql/resolvers/ontology/property-type.ts b/packages/hash/api/src/graphql/resolvers/ontology/property-type.ts index 45db0af3317..9ed9052a759 100644 --- a/packages/hash/api/src/graphql/resolvers/ontology/property-type.ts +++ b/packages/hash/api/src/graphql/resolvers/ontology/property-type.ts @@ -6,13 +6,13 @@ import { MutationCreatePropertyTypeArgs, MutationUpdatePropertyTypeArgs, QueryGetPropertyTypeArgs, + QueryGetAllLatestPropertyTypesArgs, ResolverFn, Subgraph, } from "../../apiTypes.gen"; import { LoggedInGraphQLContext } from "../../context"; import { PropertyTypeModel } from "../../../model"; import { mapPropertyTypeModelToGQL, mapSubgraphToGql } from "./model-mapping"; -import { dataTypeQueryDepth, propertyTypeQueryDepth } from "../util"; export const createPropertyType: ResolverFn< Promise, @@ -38,8 +38,13 @@ export const getAllLatestPropertyTypes: ResolverFn< Promise, {}, LoggedInGraphQLContext, - {} -> = async (_, __, { dataSources }, info) => { + QueryGetAllLatestPropertyTypesArgs +> = async ( + _, + { dataTypeResolveDepth, propertyTypeResolveDepth }, + { dataSources }, + __, +) => { const { graphApi } = dataSources; /** @@ -52,8 +57,8 @@ export const getAllLatestPropertyTypes: ResolverFn< .getPropertyTypesByQuery({ query: { eq: [{ path: ["version"] }, { literal: "latest" }] }, graphResolveDepths: { - dataTypeResolveDepth: dataTypeQueryDepth(info), - propertyTypeResolveDepth: propertyTypeQueryDepth(info), + dataTypeResolveDepth, + propertyTypeResolveDepth, linkTypeResolveDepth: 0, entityTypeResolveDepth: 0, linkTargetEntityResolveDepth: 0, @@ -75,7 +80,12 @@ export const getPropertyType: ResolverFn< {}, LoggedInGraphQLContext, QueryGetPropertyTypeArgs -> = async (_, { propertyTypeId }, { dataSources }, info) => { +> = async ( + _, + { propertyTypeId, dataTypeResolveDepth, propertyTypeResolveDepth }, + { dataSources }, + __, +) => { const { graphApi } = dataSources; const { data: propertyTypeSubgraph } = await graphApi @@ -84,8 +94,8 @@ export const getPropertyType: ResolverFn< eq: [{ path: ["versionedUri"] }, { literal: propertyTypeId }], }, graphResolveDepths: { - dataTypeResolveDepth: dataTypeQueryDepth(info), - propertyTypeResolveDepth: propertyTypeQueryDepth(info), + dataTypeResolveDepth, + propertyTypeResolveDepth, linkTypeResolveDepth: 0, entityTypeResolveDepth: 0, linkTargetEntityResolveDepth: 0, diff --git a/packages/hash/api/src/graphql/resolvers/util.ts b/packages/hash/api/src/graphql/resolvers/util.ts index 9c42e95a1ff..e9bb710ee60 100644 --- a/packages/hash/api/src/graphql/resolvers/util.ts +++ b/packages/hash/api/src/graphql/resolvers/util.ts @@ -1,10 +1,3 @@ -import { - ArgumentNode, - FieldNode, - GraphQLResolveInfo, - IntValueNode, - SelectionNode, -} from "graphql"; import { AggregateOperationInput } from "../apiTypes.gen"; // Where a property needs to resolve to another object or objects of a type, @@ -25,78 +18,3 @@ export type LinkedDataDefinition = { entityId?: string; entityVersionId?: string; }; - -/** - * Returns a specified field node, which was requested in the GraphQL query. - * - * @param info the 'info' fourth argument to all resolvers - * @param field_name the field in question - * @returns the field identified by `fieldName` - */ -const fieldNodeByName = ( - info: GraphQLResolveInfo, - fieldName: string, -): FieldNode | undefined => { - const requestedFields = info.fieldNodes[0]?.selectionSet?.selections; - return requestedFields?.find( - (field: SelectionNode) => - field.kind === "Field" && field.name.value === fieldName, - ) as FieldNode; -}; - -const queryDepthByFieldName = (info: any, fieldName: string): number => { - const field = fieldNodeByName(info, fieldName); - if (field === undefined) { - return 0; - } - - const depth_argument = field.arguments?.find( - (argument: ArgumentNode) => - argument.name.value === "depth" && argument.value.kind === "IntValue", - )?.value as IntValueNode; - - if (depth_argument === undefined) { - return 255; - } - return Number(depth_argument.value); -}; - -/** - * Returns the requested query depth for referenced data types - * - * @param info the 'info' fourth argument to all resolvers - * @returns the depth requested - */ -export const dataTypeQueryDepth = (info: GraphQLResolveInfo): number => { - return queryDepthByFieldName(info, "referencedDataTypes"); -}; - -/** - * Returns the requested query depth for referenced property types - * - * @param info the 'info' fourth argument to all resolvers - * @returns the depth requested - */ -export const propertyTypeQueryDepth = (info: GraphQLResolveInfo): number => { - return queryDepthByFieldName(info, "referencedPropertyTypes"); -}; - -/** - * Returns the requested query depth for referenced link types - * - * @param info the 'info' fourth argument to all resolvers - * @returns the depth requested - */ -export const linkTypeQueryDepth = (info: GraphQLResolveInfo): number => { - return queryDepthByFieldName(info, "referencedLinkTypes"); -}; - -/** - * Returns the requested query depth for referenced entity types - * - * @param info the 'info' fourth argument to all resolvers - * @returns the depth requested - */ -export const entityTypeQueryDepth = (info: GraphQLResolveInfo): number => { - return queryDepthByFieldName(info, "referencedEntityTypes"); -}; diff --git a/packages/hash/api/src/graphql/typeDefs/ontology/data-type.typedef.ts b/packages/hash/api/src/graphql/typeDefs/ontology/data-type.typedef.ts index 808ad9cbf5f..3aff4bd61b8 100644 --- a/packages/hash/api/src/graphql/typeDefs/ontology/data-type.typedef.ts +++ b/packages/hash/api/src/graphql/typeDefs/ontology/data-type.typedef.ts @@ -27,14 +27,14 @@ export const dataTypeTypedef = gql` extend type Query { """ - Get all data types at their latest version. + Get a subgraph rooted at all data types at their latest version. """ - getAllLatestDataTypes: Subgraph! + getAllLatestDataTypes(dataTypeResolveDepth: Int!): Subgraph! """ - Get a data type by its versioned URI. + Get a subgraph rooted at an data type resolved by its versioned URI. """ - getDataType(dataTypeId: String!): Subgraph! + getDataType(dataTypeId: String!, dataTypeResolveDepth: Int!): Subgraph! } # The following mutations should not be exposed until user defined data types diff --git a/packages/hash/api/src/graphql/typeDefs/ontology/entity-type.typedef.ts b/packages/hash/api/src/graphql/typeDefs/ontology/entity-type.typedef.ts index 61b4e0124fd..8eca192c094 100644 --- a/packages/hash/api/src/graphql/typeDefs/ontology/entity-type.typedef.ts +++ b/packages/hash/api/src/graphql/typeDefs/ontology/entity-type.typedef.ts @@ -4,16 +4,7 @@ export const entityTypeTypedef = gql` scalar EntityType scalar EntityTypeWithoutId - interface PersistedEntityTypeInterface { - # These fields are repeated everywhere they're used because - # (a) GQL requires it - https://github.com/graphql/graphql-spec/issues/533 - # (b) string interpolation breaks the code generator's introspection - # - # Could maybe use a custom schema loader to parse it ourselves: - # https://www.graphql-code-generator.com/docs/getting-started/schema-field#custom-schema-loader - # - # For now, _COPY ANY CHANGES_ from here to any type that 'implements PersistedPropertyTypeInterface' - + type PersistedEntityType { """ The specific versioned URI of the entity type """ @@ -33,77 +24,27 @@ export const entityTypeTypedef = gql` entityType: EntityType! } - type PersistedEntityType implements PersistedEntityTypeInterface { - # INTERFACE FIELDS BEGIN # - """ - The specific versioned URI of the entity type - """ - entityTypeId: String! - """ - The id of the account that owns this entity type. - """ - ownedById: ID! - """ - Alias of ownedById - the id of the account that owns this entity type. - """ - accountId: ID! - @deprecated(reason: "accountId is deprecated. Use ownedById instead.") - """ - The entity type - """ - entityType: EntityType! - # INTERFACE FIELDS END # - } - - type EntityTypeRootedSubgraph implements PersistedEntityTypeInterface { - """ - Data types indirectly referenced by this entity type - """ - referencedDataTypes(depth: Int): [PersistedDataType!]! - """ - Property types directly or indirectly referenced by this entity type - """ - referencedPropertyTypes(depth: Int): [PersistedPropertyType!]! - """ - Link types directly or indirectly referenced by this entity type - """ - referencedLinkTypes(depth: Int): [PersistedLinkType!]! - """ - Entity types directly or indirectly referenced by this entity type - """ - referencedEntityTypes(depth: Int): [PersistedEntityType!]! - - # INTERFACE FIELDS BEGIN # - """ - The specific versioned URI of the entity type - """ - entityTypeId: String! - """ - The id of the account that owns this entity type. - """ - ownedById: ID! - """ - Alias of ownedById - the id of the account that owns this entity type. - """ - accountId: ID! - @deprecated(reason: "accountId is deprecated. Use ownedById instead.") - """ - The entity type - """ - entityType: EntityType! - # INTERFACE FIELDS END # - } - extend type Query { """ - Get all entity types at their latest version. + Get a subgraph rooted at all entity types at their latest version. """ - getAllLatestEntityTypes: [EntityTypeRootedSubgraph!]! + getAllLatestEntityTypes( + dataTypeResolveDepth: Int! + propertyTypeResolveDepth: Int! + linkTypeResolveDepth: Int! + entityTypeResolveDepth: Int! + ): Subgraph! """ - Get a entity type by its versioned URI. + Get a subgraph rooted at an entity type resolved by its versioned URI. """ - getEntityType(entityTypeId: String!): EntityTypeRootedSubgraph! + getEntityType( + entityTypeId: String! + dataTypeResolveDepth: Int! + propertyTypeResolveDepth: Int! + linkTypeResolveDepth: Int! + entityTypeResolveDepth: Int! + ): Subgraph! } extend type Mutation { diff --git a/packages/hash/api/src/graphql/typeDefs/ontology/property-type.typedef.ts b/packages/hash/api/src/graphql/typeDefs/ontology/property-type.typedef.ts index 2c9351688a3..fec8729db4d 100644 --- a/packages/hash/api/src/graphql/typeDefs/ontology/property-type.typedef.ts +++ b/packages/hash/api/src/graphql/typeDefs/ontology/property-type.typedef.ts @@ -26,14 +26,21 @@ export const propertyTypeTypedef = gql` extend type Query { """ - Get all property types at their latest version. + Get a subgraph rooted at all property types at their latest version. """ - getAllLatestPropertyTypes: Subgraph! + getAllLatestPropertyTypes( + dataTypeResolveDepth: Int! + propertyTypeResolveDepth: Int! + ): Subgraph! """ - Get a property type by its versioned URI. + Get a subgraph rooted at an property type resolved by its versioned URI. """ - getPropertyType(propertyTypeId: String!): Subgraph! + getPropertyType( + propertyTypeId: String! + dataTypeResolveDepth: Int! + propertyTypeResolveDepth: Int! + ): Subgraph! } extend type Mutation { diff --git a/packages/hash/api/src/graphql/typeDefs/subgraph.typedef.ts b/packages/hash/api/src/graphql/typeDefs/subgraph.typedef.ts index 90652eeb9a6..adef05f4517 100644 --- a/packages/hash/api/src/graphql/typeDefs/subgraph.typedef.ts +++ b/packages/hash/api/src/graphql/typeDefs/subgraph.typedef.ts @@ -8,12 +8,12 @@ export const subgraphTypedef = gql` # TODO: Maybe we want an exploration strategy instead of this? So you have parameters for a depth first search vs parameters for a breadth first, etc. type ResolveDepths { - dataTypeResolveDepth(depth: Int): Int! - propertyTypeResolveDepth(depth: Int): Int! - entityTypeResolveDepth(depth: Int): Int! - linkTypeResolveDepth(depth: Int): Int! - linkTargetEntityResolveDepth(depth: Int): Int! - linkResolveDepth(depth: Int): Int! + dataTypeResolveDepth: Int! + propertyTypeResolveDepth: Int! + entityTypeResolveDepth: Int! + linkTypeResolveDepth: Int! + linkTargetEntityResolveDepth: Int! + linkResolveDepth: Int! } type Subgraph { diff --git a/packages/hash/api/src/model/ontology/entity-type.model.ts b/packages/hash/api/src/model/ontology/entity-type.model.ts index 958243eaa50..88b96894313 100644 --- a/packages/hash/api/src/model/ontology/entity-type.model.ts +++ b/packages/hash/api/src/model/ontology/entity-type.model.ts @@ -7,14 +7,7 @@ import { UpdateEntityTypeRequest, } from "@hashintel/hash-graph-client"; import { generateTypeId, types } from "@hashintel/hash-shared/types"; -import { - EntityTypeModel, - PropertyTypeModel, - LinkTypeModel, - DataTypeModel, -} from "../index"; -import dataTypeModel from "./data-type.model"; -import linkTypeModel from "./link-type.model"; +import { EntityTypeModel, PropertyTypeModel, LinkTypeModel } from "../index"; import { getNamespaceOfAccountOwner } from "./util"; import { WORKSPACE_TYPES } from "../../graph/workspace-types"; @@ -142,72 +135,6 @@ export default class { return persistedEntityTypes.map(EntityTypeModel.fromPersistedEntityType); } - /** - * Get all entity types at their latest version with their references resolved as a list. - * - * @param params.dataTypeQueryDepth recursion depth to use to resolve data types - * @param params.propertyTypeQueryDepth recursion depth to use to resolve property types - * @param params.linkTypeQueryDepth recursion depth to use to resolve link types - * @param params.entityTypeQueryDepth recursion depth to use to resolve entity types - */ - static async getAllLatestResolved( - graphApi: GraphApi, - params: { - dataTypeQueryDepth: number; - propertyTypeQueryDepth: number; - linkTypeQueryDepth: number; - entityTypeQueryDepth: number; - }, - ): Promise< - { - entityType: EntityTypeModel; - referencedDataTypes: dataTypeModel[]; - referencedPropertyTypes: PropertyTypeModel[]; - referencedLinkTypes: LinkTypeModel[]; - referencedEntityTypes: EntityTypeModel[]; - }[] - > { - /** - * @todo: get all latest entity types in specified account. - * This may mean implicitly filtering results by what an account is - * authorized to see. - * https://app.asana.com/0/1202805690238892/1202890446280569/f - */ - const { data: entityTypeRootedSubgraphs } = - await graphApi.getEntityTypesByQuery({ - query: { - eq: [{ path: ["version"] }, { literal: "latest" }], - }, - graphResolveDepths: { - dataTypeResolveDepth: params.dataTypeQueryDepth, - propertyTypeResolveDepth: params.propertyTypeQueryDepth, - linkTypeResolveDepth: params.linkTypeQueryDepth, - entityTypeResolveDepth: params.entityTypeQueryDepth, - linkResolveDepth: 0, - linkTargetEntityResolveDepth: 0, - }, - }); - - return entityTypeRootedSubgraphs.map((entityTypeRootedSubgraph) => ({ - entityType: EntityTypeModel.fromPersistedEntityType( - entityTypeRootedSubgraph.entityType, - ), - referencedDataTypes: entityTypeRootedSubgraph.referencedDataTypes.map( - DataTypeModel.fromPersistedDataType, - ), - referencedPropertyTypes: - entityTypeRootedSubgraph.referencedPropertyTypes.map( - PropertyTypeModel.fromPersistedPropertyType, - ), - referencedLinkTypes: entityTypeRootedSubgraph.referencedLinkTypes.map( - linkTypeModel.fromPersistedLinkType, - ), - referencedEntityTypes: entityTypeRootedSubgraph.referencedEntityTypes.map( - EntityTypeModel.fromPersistedEntityType, - ), - })); - } - /** * Get an entity type by its versioned URI. * @@ -227,71 +154,6 @@ export default class { return EntityTypeModel.fromPersistedEntityType(persistedEntityType); } - /** - * Get an entity type by its versioned URI. - * - * @param params.dataTypeQueryDepth recursion depth to use to resolve data types - * @param params.propertyTypeQueryDepth recursion depth to use to resolve property types - * @param params.linkTypeQueryDepth recursion depth to use to resolve link types - * @param params.entityTypeQueryDepth recursion depth to use to resolve entity types - */ - static async getResolved( - graphApi: GraphApi, - params: { - entityTypeId: string; - dataTypeQueryDepth: number; - propertyTypeQueryDepth: number; - linkTypeQueryDepth: number; - entityTypeQueryDepth: number; - }, - ): Promise<{ - entityType: EntityTypeModel; - referencedDataTypes: dataTypeModel[]; - referencedPropertyTypes: PropertyTypeModel[]; - referencedLinkTypes: LinkTypeModel[]; - referencedEntityTypes: EntityTypeModel[]; - }> { - const { data: propertyTypeRootedSubgraphs } = - await graphApi.getEntityTypesByQuery({ - query: { - eq: [{ path: ["versionedUri"] }, { literal: params.entityTypeId }], - }, - graphResolveDepths: { - dataTypeResolveDepth: params.dataTypeQueryDepth, - propertyTypeResolveDepth: params.propertyTypeQueryDepth, - linkTypeResolveDepth: params.linkTypeQueryDepth, - entityTypeResolveDepth: params.entityTypeQueryDepth, - linkResolveDepth: 0, - linkTargetEntityResolveDepth: 0, - }, - }); - const entityTypeRootedSubgraph = propertyTypeRootedSubgraphs.pop(); - if (entityTypeRootedSubgraph === undefined) { - throw new Error( - `Unable to retrieve property type for URI: ${params.entityTypeId}`, - ); - } - - return { - entityType: EntityTypeModel.fromPersistedEntityType( - entityTypeRootedSubgraph.entityType, - ), - referencedDataTypes: entityTypeRootedSubgraph.referencedDataTypes.map( - DataTypeModel.fromPersistedDataType, - ), - referencedPropertyTypes: - entityTypeRootedSubgraph.referencedPropertyTypes.map( - PropertyTypeModel.fromPersistedPropertyType, - ), - referencedLinkTypes: entityTypeRootedSubgraph.referencedLinkTypes.map( - LinkTypeModel.fromPersistedLinkType, - ), - referencedEntityTypes: entityTypeRootedSubgraph.referencedEntityTypes.map( - EntityTypeModel.fromPersistedEntityType, - ), - }; - } - /** * Update an entity type. * diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/knowledge-shim.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/knowledge-shim.ts index 880dc250a1f..f1c85801609 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/knowledge-shim.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/knowledge-shim.ts @@ -13,8 +13,8 @@ import { } from "@blockprotocol/graph"; import { PersistedLink, + Subgraph, UnknownPersistedEntity, - EntityTypeRootedSubgraph, } from "../../../../graphql/apiTypes.gen"; export type KnowledgeCallbacks = { @@ -41,7 +41,7 @@ type BaseEntity = Omit< type Entity = BaseEntity & { links: Link[]; - entityTypeRootedSubgraph: EntityTypeRootedSubgraph; + entityTypeRootedSubgraph: Subgraph; }; type Link = Omit & { diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolCreateEntity.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolCreateEntity.ts index e754b360558..e76c2305854 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolCreateEntity.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolCreateEntity.ts @@ -96,6 +96,10 @@ export const useBlockProtocolCreateEntity = ( getEntityTypeRootedSubgraphFn({ variables: { entityTypeId: createdEntity.entityTypeId, + dataTypeResolveDepth: 255, + propertyTypeResolveDepth: 255, + linkTypeResolveDepth: 255, + entityTypeResolveDepth: 1, }, }), getOutgoingLinksFn({ diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolGetEntity.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolGetEntity.ts index 27a87a2d000..7a4efc5f259 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolGetEntity.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolGetEntity.ts @@ -95,6 +95,10 @@ export const useBlockProtocolGetEntity = (): { query: getEntityTypeRootedSubgraphQuery, variables: { entityTypeId: persistedEntity.entityTypeId, + dataTypeResolveDepth: 255, + propertyTypeResolveDepth: 255, + linkTypeResolveDepth: 255, + entityTypeResolveDepth: 1, }, }); diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolUpdateEntity.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolUpdateEntity.ts index 8729f3a0cfa..645cb28b92f 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolUpdateEntity.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/knowledge/useBlockProtocolUpdateEntity.ts @@ -111,6 +111,10 @@ export const useBlockProtocolUpdateEntity = ( query: getEntityTypeRootedSubgraphQuery, variables: { entityTypeId: updatedEntity.entityTypeId, + dataTypeResolveDepth: 255, + propertyTypeResolveDepth: 255, + linkTypeResolveDepth: 255, + entityTypeResolveDepth: 1, }, }); diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/ontology-types-shim.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/ontology-types-shim.ts index c962f6f0b3f..4573907ad93 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/ontology-types-shim.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/ontology-types-shim.ts @@ -130,7 +130,7 @@ export type AggregateEntityTypesRequest = {}; export type AggregateEntityTypesMessageCallback = MessageCallback< AggregateEntityTypesRequest, null, - AggregateResult, + Subgraph, ReadOrModifyResourceError >; @@ -138,7 +138,7 @@ export type GetEntityTypeRequest = Pick; export type GetEntityTypeMessageCallback = MessageCallback< GetEntityTypeRequest, null, - EntityTypeResponse, + Subgraph, ReadOrModifyResourceError >; diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateDataTypes.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateDataTypes.ts index 827bbbb0f0e..c36e61652f7 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateDataTypes.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateDataTypes.ts @@ -37,7 +37,11 @@ export const useBlockProtocolAggregateDataTypes = (): { * or doing it from here. * https://app.asana.com/0/1202805690238892/1202890614880643/f */ - const response = await aggregateFn({}); + const response = await aggregateFn({ + variables: { + dataTypeResolveDepth: 255, + }, + }); if (!response.data) { return { diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateEntityTypes.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateEntityTypes.ts index e0b14c7dac1..2828119c21b 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateEntityTypes.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateEntityTypes.ts @@ -39,7 +39,12 @@ export const useBlockProtocolAggregateEntityTypes = (): { * https://app.asana.com/0/1202805690238892/1202890614880643/f */ const response = await aggregateFn({ - query: getAllLatestEntityTypesQuery, + variables: { + dataTypeResolveDepth: 255, + propertyTypeResolveDepth: 255, + linkTypeResolveDepth: 255, + entityTypeResolveDepth: 0, + }, }); if (!response.data) { @@ -54,9 +59,7 @@ export const useBlockProtocolAggregateEntityTypes = (): { } return { - data: { - results: response.data.getAllLatestEntityTypes, - }, + data: response.data.getAllLatestEntityTypes, }; }, [aggregateFn], diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregatePropertyTypes.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregatePropertyTypes.ts index 4e65fee66e5..44ad7de2047 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregatePropertyTypes.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregatePropertyTypes.ts @@ -39,7 +39,12 @@ export const useBlockProtocolAggregatePropertyTypes = (): { * or doing it from here. * https://app.asana.com/0/1202805690238892/1202890614880643/f */ - const response = await aggregateFn({}); + const response = await aggregateFn({ + variables: { + dataTypeResolveDepth: 255, + propertyTypeResolveDepth: 255, + }, + }); if (!response.data) { return { diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetDataType.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetDataType.ts index 4db9e746acb..38219e108ac 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetDataType.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetDataType.ts @@ -35,7 +35,10 @@ export const useBlockProtocolGetDataType = (): { const { dataTypeId } = data; const response = await getFn({ - variables: { dataTypeId }, + variables: { + dataTypeId, + dataTypeResolveDepth: 255, + }, }); if (!response.data) { diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetEntityType.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetEntityType.ts index dcaa93391f9..fcc65b56664 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetEntityType.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetEntityType.ts @@ -36,7 +36,13 @@ export const useBlockProtocolGetEntityType = (): { const response = await getFn({ query: getEntityTypeQuery, - variables: { entityTypeId }, + variables: { + entityTypeId, + dataTypeResolveDepth: 255, + propertyTypeResolveDepth: 255, + linkTypeResolveDepth: 255, + entityTypeResolveDepth: 1, + }, }); if (!response.data) { diff --git a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetPropertyType.ts b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetPropertyType.ts index df7283d29fe..5a7c95b4f76 100644 --- a/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetPropertyType.ts +++ b/packages/hash/frontend/src/components/hooks/blockProtocolFunctions/ontology/useBlockProtocolGetPropertyType.ts @@ -35,7 +35,11 @@ export const useBlockProtocolGetPropertyType = (): { const { propertyTypeId } = data; const response = await getFn({ - variables: { propertyTypeId }, + variables: { + propertyTypeId, + dataTypeResolveDepth: 255, + propertyTypeResolveDepth: 255, + }, }); if (!response.data) { diff --git a/packages/hash/frontend/src/graphql/queries/ontology/data-type.queries.ts b/packages/hash/frontend/src/graphql/queries/ontology/data-type.queries.ts index 372197bcd58..f67d20354cd 100644 --- a/packages/hash/frontend/src/graphql/queries/ontology/data-type.queries.ts +++ b/packages/hash/frontend/src/graphql/queries/ontology/data-type.queries.ts @@ -1,36 +1,39 @@ import { gql } from "@apollo/client"; export const getDataTypeQuery = gql` - query getDataType($dataTypeId: String!) { - getDataType(dataTypeId: $dataTypeId) { + query getDataType($dataTypeId: String!, $dataTypeResolveDepth: Int!) { + getDataType( + dataTypeId: $dataTypeId + dataTypeResolveDepth: $dataTypeResolveDepth + ) { roots vertices edges depths { - dataTypeResolveDepth(depth: 0) - propertyTypeResolveDepth(depth: 0) - linkTypeResolveDepth(depth: 0) - entityTypeResolveDepth(depth: 0) - linkTargetEntityResolveDepth(depth: 0) - linkResolveDepth(depth: 0) + dataTypeResolveDepth + propertyTypeResolveDepth + linkTypeResolveDepth + entityTypeResolveDepth + linkTargetEntityResolveDepth + linkResolveDepth } } } `; export const getAllLatestDataTypesQuery = gql` - query getAllLatestDataTypes { - getAllLatestDataTypes { + query getAllLatestDataTypes($dataTypeResolveDepth: Int!) { + getAllLatestDataTypes(dataTypeResolveDepth: $dataTypeResolveDepth) { roots vertices edges depths { - dataTypeResolveDepth(depth: 0) - propertyTypeResolveDepth(depth: 0) - linkTypeResolveDepth(depth: 0) - entityTypeResolveDepth(depth: 0) - linkTargetEntityResolveDepth(depth: 0) - linkResolveDepth(depth: 0) + dataTypeResolveDepth + propertyTypeResolveDepth + linkTypeResolveDepth + entityTypeResolveDepth + linkTargetEntityResolveDepth + linkResolveDepth } } } diff --git a/packages/hash/frontend/src/graphql/queries/ontology/entity-type.queries.ts b/packages/hash/frontend/src/graphql/queries/ontology/entity-type.queries.ts index eda6b06a536..b1ce0df2d06 100644 --- a/packages/hash/frontend/src/graphql/queries/ontology/entity-type.queries.ts +++ b/packages/hash/frontend/src/graphql/queries/ontology/entity-type.queries.ts @@ -1,21 +1,59 @@ import { gql } from "@apollo/client"; export const getEntityTypeQuery = gql` - query getEntityType($entityTypeId: String!) { - getEntityType(entityTypeId: $entityTypeId) { - entityTypeId - ownedById - entityType + query getEntityType( + $entityTypeId: String! + $dataTypeResolveDepth: Int! + $propertyTypeResolveDepth: Int! + $linkTypeResolveDepth: Int! + $entityTypeResolveDepth: Int! + ) { + getEntityType( + entityTypeId: $entityTypeId + dataTypeResolveDepth: $dataTypeResolveDepth + propertyTypeResolveDepth: $propertyTypeResolveDepth + linkTypeResolveDepth: $linkTypeResolveDepth + entityTypeResolveDepth: $entityTypeResolveDepth + ) { + roots + vertices + edges + depths { + dataTypeResolveDepth + propertyTypeResolveDepth + linkTypeResolveDepth + entityTypeResolveDepth + linkTargetEntityResolveDepth + linkResolveDepth + } } } `; export const getAllLatestEntityTypesQuery = gql` - query getAllLatestEntityTypes { - getAllLatestEntityTypes { - entityTypeId - ownedById - entityType + query getAllLatestEntityTypes( + $dataTypeResolveDepth: Int! + $propertyTypeResolveDepth: Int! + $linkTypeResolveDepth: Int! + $entityTypeResolveDepth: Int! + ) { + getAllLatestEntityTypes( + dataTypeResolveDepth: $dataTypeResolveDepth + propertyTypeResolveDepth: $propertyTypeResolveDepth + linkTypeResolveDepth: $linkTypeResolveDepth + entityTypeResolveDepth: $entityTypeResolveDepth + ) { + roots + vertices + edges + depths { + dataTypeResolveDepth + propertyTypeResolveDepth + linkTypeResolveDepth + entityTypeResolveDepth + linkTargetEntityResolveDepth + linkResolveDepth + } } } `; @@ -23,39 +61,28 @@ export const getAllLatestEntityTypesQuery = gql` export const getEntityTypeRootedSubgraphQuery = gql` query getEntityTypeRootedSubgraph( $entityTypeId: String! - $referencedDataTypesDepth: Int - $referencedPropertyTypesDepth: Int - $referencedLinkTypesDepth: Int - $referencedEntityTypesDepth: Int + $dataTypeResolveDepth: Int! + $propertyTypeResolveDepth: Int! + $linkTypeResolveDepth: Int! + $entityTypeResolveDepth: Int! ) { - getEntityType(entityTypeId: $entityTypeId) { - entityTypeId - ownedById - accountId - entityType - referencedDataTypes(depth: $referencedDataTypesDepth) { - dataTypeId - ownedById - accountId - dataType - } - referencedPropertyTypes(depth: $referencedPropertyTypesDepth) { - propertyTypeId - ownedById - accountId - propertyType - } - referencedLinkTypes(depth: $referencedLinkTypesDepth) { - linkTypeId - ownedById - accountId - linkType - } - referencedEntityTypes(depth: $referencedEntityTypesDepth) { - entityTypeId - ownedById - accountId - entityType + getEntityType( + entityTypeId: $entityTypeId + dataTypeResolveDepth: $dataTypeResolveDepth + propertyTypeResolveDepth: $propertyTypeResolveDepth + linkTypeResolveDepth: $linkTypeResolveDepth + entityTypeResolveDepth: $entityTypeResolveDepth + ) { + roots + vertices + edges + depths { + dataTypeResolveDepth + propertyTypeResolveDepth + linkTypeResolveDepth + entityTypeResolveDepth + linkTargetEntityResolveDepth + linkResolveDepth } } } diff --git a/packages/hash/frontend/src/graphql/queries/ontology/property-type.queries.ts b/packages/hash/frontend/src/graphql/queries/ontology/property-type.queries.ts index 693e014f841..e2ce6abcc73 100644 --- a/packages/hash/frontend/src/graphql/queries/ontology/property-type.queries.ts +++ b/packages/hash/frontend/src/graphql/queries/ontology/property-type.queries.ts @@ -1,36 +1,50 @@ import { gql } from "@apollo/client"; export const getPropertyTypeQuery = gql` - query getPropertyType($propertyTypeId: String!) { - getPropertyType(propertyTypeId: $propertyTypeId) { + query getPropertyType( + $propertyTypeId: String! + $dataTypeResolveDepth: Int! + $propertyTypeResolveDepth: Int! + ) { + getPropertyType( + propertyTypeId: $propertyTypeId + dataTypeResolveDepth: $dataTypeResolveDepth + propertyTypeResolveDepth: $propertyTypeResolveDepth + ) { roots vertices edges depths { - dataTypeResolveDepth(depth: 0) - propertyTypeResolveDepth(depth: 0) - linkTypeResolveDepth(depth: 0) - entityTypeResolveDepth(depth: 0) - linkTargetEntityResolveDepth(depth: 0) - linkResolveDepth(depth: 0) + dataTypeResolveDepth + propertyTypeResolveDepth + linkTypeResolveDepth + entityTypeResolveDepth + linkTargetEntityResolveDepth + linkResolveDepth } } } `; export const getAllLatestPropertyTypesQuery = gql` - query getAllLatestPropertyTypes { - getAllLatestPropertyTypes { + query getAllLatestPropertyTypes( + $dataTypeResolveDepth: Int! + $propertyTypeResolveDepth: Int! + ) { + getAllLatestPropertyTypes( + dataTypeResolveDepth: $dataTypeResolveDepth + propertyTypeResolveDepth: $propertyTypeResolveDepth + ) { roots vertices edges depths { - dataTypeResolveDepth(depth: 0) - propertyTypeResolveDepth(depth: 0) - linkTypeResolveDepth(depth: 0) - entityTypeResolveDepth(depth: 0) - linkTargetEntityResolveDepth(depth: 0) - linkResolveDepth(depth: 0) + dataTypeResolveDepth + propertyTypeResolveDepth + linkTypeResolveDepth + entityTypeResolveDepth + linkTargetEntityResolveDepth + linkResolveDepth } } } diff --git a/packages/hash/frontend/src/lib/entities.ts b/packages/hash/frontend/src/lib/entities.ts index 31a662273a9..b88cecf8b01 100644 --- a/packages/hash/frontend/src/lib/entities.ts +++ b/packages/hash/frontend/src/lib/entities.ts @@ -16,6 +16,7 @@ import { LinkGroup as ApiLinkGroup, LinkedAggregation as ApiLinkedAggregation, } from "../graphql/apiTypes.gen"; +import { getPropertyTypesByBaseUri } from "./subgraph"; const isObject = (thing: unknown): thing is {} => typeof thing === "object" && thing !== null; @@ -467,22 +468,30 @@ export const generateEntityLabel = ( "shortname", ]; - /** @todo refactor the following section to make it more readable */ - const propertyTypes: { title?: string; propertyTypeId: string }[] = - Object.keys(entity.properties).map((propertyTypeId) => ({ - propertyTypeId, - title: ( - entity as EntityResponse - ).entityTypeRootedSubgraph?.referencedPropertyTypes - .find((item) => item.propertyTypeId.startsWith(propertyTypeId)) - ?.propertyType.title.toLowerCase(), - })); + const propertyTypes: { title?: string; propertyTypeBaseUri: string }[] = + Object.keys(entity.properties).map((propertyTypeBaseUri) => { + /** @todo - pick the latest version rather than first element? */ + const [propertyType] = getPropertyTypesByBaseUri( + (entity as EntityResponse).entityTypeRootedSubgraph, + propertyTypeBaseUri, + ); + + return propertyType + ? { + title: propertyType.inner.title.toLowerCase(), + propertyTypeBaseUri, + } + : { + title: undefined, + propertyTypeBaseUri, + }; + }); for (const option of options) { const found = propertyTypes.find(({ title }) => title === option); if (found) { - return entity.properties[found.propertyTypeId]; + return entity.properties[found.propertyTypeBaseUri]; } } diff --git a/packages/hash/frontend/src/lib/subgraph.ts b/packages/hash/frontend/src/lib/subgraph.ts new file mode 100644 index 00000000000..b2a2c49d816 --- /dev/null +++ b/packages/hash/frontend/src/lib/subgraph.ts @@ -0,0 +1,340 @@ +import { + Vertex, + DataTypeVertex, + PropertyTypeVertex, + LinkTypeVertex, + EntityTypeVertex, + EntityVertex, + LinkVertex, + PersistedDataType, + PersistedPropertyType, + PersistedLinkType, + PersistedEntityType, +} from "@hashintel/hash-shared/graphql/types"; +import { BaseUri } from "@blockprotocol/type-system-web"; + +import { Subgraph } from "../graphql/apiTypes.gen"; + +// ------------------- Type Guards to use inside .filters ------------------- + +export const isDataTypeVertex = (vertex: Vertex): vertex is DataTypeVertex => { + return vertex.kind === "dataType"; +}; + +export const isPropertyTypeVertex = ( + vertex: Vertex, +): vertex is PropertyTypeVertex => { + return vertex.kind === "propertyType"; +}; + +export const isLinkTypeVertex = (vertex: Vertex): vertex is LinkTypeVertex => { + return vertex.kind === "linkType"; +}; + +export const isEntityTypeVertex = ( + vertex: Vertex, +): vertex is EntityTypeVertex => { + return vertex.kind === "entityType"; +}; + +export const isEntityVertex = (vertex: Vertex): vertex is EntityVertex => { + return vertex.kind === "entity"; +}; + +export const isLinkVertex = (vertex: Vertex): vertex is LinkVertex => { + return vertex.kind === "link"; +}; + +/** + * @todo - use `VersionedUri` for the params in here once the type-system package is unified and we no-longer need to + * gate on init: + * https://app.asana.com/0/1201095311341924/1202923896339225/f + */ + +// ------------------- Get methods to encapsulate lookups and error checking ------------------- + +/** + * Gets a `PersistedDataType` by its `VersionedUri` from within the vertices of the subgraph. Returns `undefined` if + * the data type couldn't be found. + * + * @param subgraph + * @param dataTypeId + * @throws if the vertex isn't a `DataTypeVertex` + */ +export const getPersistedDataType = ( + subgraph: Subgraph, + dataTypeId: string, +): PersistedDataType | undefined => { + const vertex = subgraph.vertices[dataTypeId]; + + if (!vertex) { + return undefined; + } + + if (!isDataTypeVertex(vertex)) { + throw new Error(`expected data type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; +}; + +/** + * Gets a `PersistedPropertyType` by its `VersionedUri` from within the vertices of the subgraph. Returns `undefined` if + * the property type couldn't be found. + * + * @param subgraph + * @param propertyTypeId + * @throws if the vertex isn't a `PropertyTypeVertex` + */ +export const getPersistedPropertyType = ( + subgraph: Subgraph, + propertyTypeId: string, +): PersistedPropertyType | undefined => { + const vertex = subgraph.vertices[propertyTypeId]; + + if (!vertex) { + return undefined; + } + + if (!isPropertyTypeVertex(vertex)) { + throw new Error(`expected property type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; +}; + +/** + * Gets a `PersistedLinkType` by its `VersionedUri` from within the vertices of the subgraph. Returns `undefined` if + * the data type couldn't be found. + * + * @param subgraph + * @param linkTypeId + * @throws if the vertex isn't a `LinkTypeVertex` + */ +export const getPersistedLinkType = ( + subgraph: Subgraph, + linkTypeId: string, +): PersistedLinkType | undefined => { + const vertex = subgraph.vertices[linkTypeId]; + + if (!vertex) { + return undefined; + } + + if (!isLinkTypeVertex(vertex)) { + throw new Error(`expected link type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; +}; + +/** + * Gets a `PersistedEntityType` by its `VersionedUri` from within the vertices of the subgraph. Returns `undefined` if + * the entity type couldn't be found. + * + * @param subgraph + * @param entityTypeId + * @throws if the vertex isn't a `EntityTypeVertex` + */ +export const getPersistedEntityType = ( + subgraph: Subgraph, + entityTypeId: string, +): PersistedEntityType | undefined => { + const vertex = subgraph.vertices[entityTypeId]; + + if (!vertex) { + return undefined; + } + + if (!isEntityTypeVertex(vertex)) { + throw new Error(`expected entity type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; +}; + +/** @todo - getPersistedEntity and getPersistedLink - https://app.asana.com/0/0/1203157172269853/f */ + +/** + * Returns all root vertices of the subgraph + * + * @param subgraph + */ +export const roots = (subgraph: Subgraph): Vertex[] => { + return subgraph.roots.map((root) => { + const rootVertex = subgraph.vertices[root]; + if (!rootVertex) { + throw new Error(`looked in vertex set but failed to find root: ${root}`); + } + + return rootVertex; + }); +}; + +/** + * Returns all `PersistedDataType`s within the vertices of the subgraph + * + * @param subgraph + */ +export const persistedDataTypes = (subgraph: Subgraph): PersistedDataType[] => { + return Object.values(subgraph.vertices) + .filter(isDataTypeVertex) + .map((vertex) => vertex.inner); +}; + +/** + * Returns all `PersistedPropertyType`s within the vertices of the subgraph + * + * @param subgraph + */ +export const persistedPropertyTypes = ( + subgraph: Subgraph, +): PersistedPropertyType[] => { + return Object.values(subgraph.vertices) + .filter(isPropertyTypeVertex) + .map((vertex) => vertex.inner); +}; + +/** + * Returns all `PersistedLinkType`s within the vertices of the subgraph + * + * @param subgraph + */ +export const persistedLinkTypes = (subgraph: Subgraph): PersistedLinkType[] => { + return Object.values(subgraph.vertices) + .filter(isLinkTypeVertex) + .map((vertex) => vertex.inner); +}; + +/** + * Returns all `PersistedEntityType`s within the vertices of the subgraph + * + * @param subgraph + */ +export const persistedEntityTypes = ( + subgraph: Subgraph, +): PersistedEntityType[] => { + return Object.values(subgraph.vertices) + .filter(isEntityTypeVertex) + .map((vertex) => vertex.inner); +}; + +/** @todo - improve the typing of these */ + +/** + * Returns all `PersistedLink`s within the vertices of the subgraph + * + * @param subgraph + */ +export const persistedLinks = (subgraph: Subgraph) => { + return Object.values(subgraph.vertices) + .filter(isLinkVertex) + .map((vertex) => vertex.inner); +}; + +/** + * Returns all `PersistedEntity`s within the vertices of the subgraph + * + * @param subgraph + */ +export const persistedEntities = (subgraph: Subgraph) => { + return Object.values(subgraph.vertices) + .filter(isEntityVertex) + .map((vertex) => vertex.inner); +}; + +/** + * Returns all `PersistedDataType`s within the vertices of the subgraph that match a given `BaseUri` + * + * @param subgraph + * @param baseUri + */ +export const getDataTypesByBaseUri = ( + subgraph: Subgraph, + baseUri: BaseUri, +): PersistedDataType[] => { + const dataTypeIds = Object.keys(subgraph.vertices).filter( + (graphElementIdentifier) => graphElementIdentifier.startsWith(baseUri), + ); + + return dataTypeIds.map((dataTypeId) => { + const vertex = subgraph.vertices[dataTypeId]!; + if (!isDataTypeVertex(vertex)) { + throw new Error(`expected data type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; + }); +}; + +/** + * Returns all `PersistedPropertyType`s within the vertices of the subgraph that match a given `BaseUri` + * + * @param subgraph + * @param baseUri + */ +export const getPropertyTypesByBaseUri = ( + subgraph: Subgraph, + baseUri: BaseUri, +): PersistedPropertyType[] => { + const propertyTypeIds = Object.keys(subgraph.vertices).filter( + (graphElementIdentifier) => graphElementIdentifier.startsWith(baseUri), + ); + + return propertyTypeIds.map((propertyTypeId) => { + const vertex = subgraph.vertices[propertyTypeId]!; + if (!isPropertyTypeVertex(vertex)) { + throw new Error(`expected property type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; + }); +}; + +/** + * Returns all `PersistedLinkType`s within the vertices of the subgraph that match a given `BaseUri` + * + * @param subgraph + * @param baseUri + */ +export const getLinkTypesByBaseUri = ( + subgraph: Subgraph, + baseUri: BaseUri, +): PersistedLinkType[] => { + const linkTypeIds = Object.keys(subgraph.vertices).filter( + (graphElementIdentifier) => graphElementIdentifier.startsWith(baseUri), + ); + + return linkTypeIds.map((linkTypeId) => { + const vertex = subgraph.vertices[linkTypeId]!; + if (!isLinkTypeVertex(vertex)) { + throw new Error(`expected link type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; + }); +}; + +/** + * Returns all `PersistedEntityType`s within the vertices of the subgraph that match a given `BaseUri` + * + * @param subgraph + * @param baseUri + */ +export const getEntityTypesByBaseUri = ( + subgraph: Subgraph, + baseUri: BaseUri, +): PersistedEntityType[] => { + const entityTypeIds = Object.keys(subgraph.vertices).filter( + (graphElementIdentifier) => graphElementIdentifier.startsWith(baseUri), + ); + + return entityTypeIds.map((entityTypeId) => { + const vertex = subgraph.vertices[entityTypeId]!; + if (!isEntityTypeVertex(vertex)) { + throw new Error(`expected entity type vertex but got: ${vertex.kind}`); + } + + return vertex.inner; + }); +}; diff --git a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/link-table/use-row-data.ts b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/link-table/use-row-data.ts index 1b733a6e4cd..a0cff6ac72c 100644 --- a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/link-table/use-row-data.ts +++ b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/link-table/use-row-data.ts @@ -3,6 +3,10 @@ import { LinkRow } from "./types"; import { useEntityEditor } from "../entity-editor-context"; import { generateEntityLabel } from "../../../../../lib/entities"; import { sortRowData } from "../../../../../components/GlideGlid/utils"; +import { + getPersistedEntityType, + getPersistedLinkType, +} from "../../../../../lib/subgraph"; export const useRowData = () => { const { entity, linkSort } = useEntityEditor(); @@ -14,18 +18,18 @@ export const useRowData = () => { return ( entity?.links.map((link) => { - const linkType = - entity.entityTypeRootedSubgraph.referencedLinkTypes.find( - (val) => val.linkTypeId === link.linkTypeId, - )?.linkType; + const linkType = getPersistedLinkType( + entity.entityTypeRootedSubgraph, + link.linkTypeId, + )?.inner; - const referencedEntityType = - entity.entityTypeRootedSubgraph.referencedEntityTypes.find( - (val) => val.entityTypeId === link.targetEntity.entityTypeId, - )?.entityType.title; + const referencedEntityType = getPersistedEntityType( + entity.entityTypeRootedSubgraph, + link.targetEntity.entityTypeId, + )?.inner; return { - expectedEntityType: referencedEntityType ?? "", + expectedEntityType: referencedEntityType?.title ?? "", linkedWith: generateEntityLabel(link.targetEntity), linkId: link.linkTypeId, relationShip: "Outbound", diff --git a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/extract-enriched-property-types-from-entity.ts b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/extract-enriched-property-types-from-entity.ts index 9639e4be1d2..83d5d301432 100644 --- a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/extract-enriched-property-types-from-entity.ts +++ b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/extract-enriched-property-types-from-entity.ts @@ -2,6 +2,10 @@ import { PropertyType } from "@blockprotocol/type-system-web"; import { capitalize } from "@mui/material"; import { EntityResponse } from "../../../../../components/hooks/blockProtocolFunctions/knowledge/knowledge-shim"; import { EnrichedPropertyType } from "./types"; +import { + getPersistedDataType, + getPropertyTypesByBaseUri, +} from "../../../../../lib/subgraph"; const getDataTypesOfPropertyType = ( propertyType: PropertyType, @@ -9,12 +13,13 @@ const getDataTypesOfPropertyType = ( ) => { return propertyType.oneOf.map((propertyValue) => { if ("$ref" in propertyValue) { - const dataTypeId = propertyValue.$ref; - return ( - entity.entityTypeRootedSubgraph.referencedDataTypes.find( - (val) => val.dataTypeId === dataTypeId, - )?.dataType.title ?? "undefined" + const dataTypeId = propertyValue?.$ref; + const persistedDataType = getPersistedDataType( + entity.entityTypeRootedSubgraph, + dataTypeId, ); + + return persistedDataType ? persistedDataType.inner.title : "undefined"; } return capitalize(propertyValue.type); @@ -24,22 +29,26 @@ const getDataTypesOfPropertyType = ( export const extractEnrichedPropertyTypesFromEntity = ( entity: EntityResponse, ): EnrichedPropertyType[] => { - return Object.keys(entity.properties).map((propertyTypeId) => { - const { propertyType } = - entity.entityTypeRootedSubgraph.referencedPropertyTypes.find((val) => - val.propertyTypeId.startsWith(propertyTypeId), - ) ?? {}; - - if (!propertyType) { - throw new Error("propertyType not found"); + return Object.keys(entity.properties).map((propertyTypeBaseUri) => { + const propertyTypeVersions = getPropertyTypesByBaseUri( + entity.entityTypeRootedSubgraph, + propertyTypeBaseUri, + ); + + if (!propertyTypeVersions) { + throw new Error( + `propertyType not found for base URI: ${propertyTypeBaseUri}`, + ); } + const propertyType = propertyTypeVersions[0]!.inner; + const dataTypes = getDataTypesOfPropertyType(propertyType, entity); return { ...propertyType, - value: entity.properties[propertyTypeId], - propertyTypeId, + value: entity.properties[propertyTypeBaseUri], + propertyTypeId: propertyTypeBaseUri, dataTypes, }; }); diff --git a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/types.ts b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/types.ts index db19fdddc0f..4c3179eb649 100644 --- a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/types.ts +++ b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/property-table/types.ts @@ -10,6 +10,7 @@ export type PropertyRow = { export type EnrichedPropertyType = PropertyType & { value: any; + /** @todo - Correct this, it is a property type BaseUri not an ID (it's unversioned) */ propertyTypeId: string; dataTypes: string[]; }; diff --git a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/types-section.tsx b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/types-section.tsx index 32a85da0c04..b7e73839d5b 100644 --- a/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/types-section.tsx +++ b/packages/hash/frontend/src/pages/[account-slug]/entities/[entity-id].page/types-section.tsx @@ -4,6 +4,7 @@ import { Box, Typography } from "@mui/material"; import { WhiteCard } from "../../types/entity-type/white-card"; import { useEntityEditor } from "./entity-editor-context"; import { EntitySection } from "./shared/entity-section"; +import { getPersistedEntityType } from "../../../../lib/subgraph"; interface TypeCardProps { url: string; @@ -39,7 +40,10 @@ export const TypesSection = () => { return null; } - const entityTypeTitle = entity.entityTypeRootedSubgraph.entityType.title; + const entityTypeTitle = getPersistedEntityType( + entity.entityTypeRootedSubgraph, + entity.entityTypeId, + )!.inner.title; return ( diff --git a/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-entity-type.tsx b/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-entity-type.tsx index dd01d7f2f09..1ba67ba3d13 100644 --- a/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-entity-type.tsx +++ b/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-entity-type.tsx @@ -1,4 +1,4 @@ -import { EntityType, extractBaseUri } from "@blockprotocol/type-system-web"; +import { EntityType } from "@blockprotocol/type-system-web"; import { useCallback, useEffect, @@ -9,7 +9,7 @@ import { import { useBlockProtocolAggregateEntityTypes } from "../../../../components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregateEntityTypes"; import { useBlockProtocolUpdateEntityType } from "../../../../components/hooks/blockProtocolFunctions/ontology/useBlockProtocolUpdateEntityType"; import { useAdvancedInitTypeSystem } from "../../../../lib/use-init-type-system"; -import { mustBeVersionedUri } from "./util"; +import { getEntityTypesByBaseUri } from "../../../../lib/subgraph"; export const useEntityType = ( entityTypeBaseUri: string, @@ -35,19 +35,23 @@ export const useEntityType = ( entityTypeRef.current = null; void aggregateEntityTypes({ data: {} }).then(async (res) => { - const relevantEntity = - res.data?.results.find((item) => { - const baseUri = extractBaseUri(mustBeVersionedUri(item.entityTypeId)); - return baseUri === entityTypeBaseUri; - })?.entityType ?? null; + const subgraph = res.data; + const relevantEntityTypes = subgraph + ? getEntityTypesByBaseUri(subgraph, entityTypeBaseUri) + : []; + + /** @todo - pick the latest version? */ + const relevantEntityType = relevantEntityTypes + ? relevantEntityTypes[0]!.inner + : null; await loadTypeSystem(); if (!cancelled) { - setEntityType(relevantEntity); - entityTypeRef.current = relevantEntity; - if (relevantEntity) { - onCompletedRef.current?.(relevantEntity); + setEntityType(relevantEntityType); + entityTypeRef.current = relevantEntityType; + if (relevantEntityType) { + onCompletedRef.current?.(relevantEntityType); } } }); diff --git a/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-property-types.tsx b/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-property-types.tsx index 4862dc972f0..6149a2655c4 100644 --- a/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-property-types.tsx +++ b/packages/hash/frontend/src/pages/[account-slug]/types/entity-type/use-property-types.tsx @@ -2,44 +2,46 @@ import { PropertyType, VersionedUri } from "@blockprotocol/type-system-web"; import { createContext, useContext, useEffect, useState } from "react"; import { useBlockProtocolAggregatePropertyTypes } from "../../../../components/hooks/blockProtocolFunctions/ontology/useBlockProtocolAggregatePropertyTypes"; import { mustBeVersionedUri } from "./util"; +import { getPersistedPropertyType } from "../../../../lib/subgraph"; +import { useAdvancedInitTypeSystem } from "../../../../lib/use-init-type-system"; type PropertyTypesContextValues = Record; export const useRemotePropertyTypes = () => { + const [typeSystemLoading, _] = useAdvancedInitTypeSystem(); + const [propertyTypes, setPropertyTypes] = useState(null); const { aggregatePropertyTypes } = useBlockProtocolAggregatePropertyTypes(); useEffect(() => { - void aggregatePropertyTypes({ data: {} }).then(({ data }) => { + if (typeSystemLoading) { + return; + } + void aggregatePropertyTypes({ data: {} }).then(({ data: subgraph }) => { // @todo error handling - if (data) { + if (subgraph) { setPropertyTypes( Object.fromEntries( - data.roots.map((propertyTypeId) => { - const propertyTypeVertex = data.vertices[propertyTypeId]; + subgraph.roots.map((propertyTypeId) => { + const propertyType = getPersistedPropertyType( + subgraph, + propertyTypeId, + ); - if (!propertyTypeVertex) { + if (!propertyType) { throw new Error( "property type was missing from the subgraph vertices list", ); } - if (propertyTypeVertex.kind !== "propertyType") { - throw new Error( - `expected property type but got ${propertyTypeVertex.kind}`, - ); - } - return [ - mustBeVersionedUri(propertyTypeId), - propertyTypeVertex.inner.inner, - ] as const; + return [mustBeVersionedUri(propertyTypeId), propertyType.inner]; }), ), ); } }); - }, [aggregatePropertyTypes]); + }, [aggregatePropertyTypes, typeSystemLoading]); return propertyTypes; }; diff --git a/packages/hash/frontend/src/pages/entity-editor.page.tsx b/packages/hash/frontend/src/pages/entity-editor.page.tsx index a932d30fb7a..e7d6218369a 100644 --- a/packages/hash/frontend/src/pages/entity-editor.page.tsx +++ b/packages/hash/frontend/src/pages/entity-editor.page.tsx @@ -8,6 +8,10 @@ import { useUser } from "../components/hooks/useUser"; import { NextPageWithLayout } from "../shared/layout"; import { useBlockProtocolFunctionsWithOntology } from "./type-editor/blockprotocol-ontology-functions-hook"; import { EntityResponse } from "../components/hooks/blockProtocolFunctions/knowledge/knowledge-shim"; +import { + getPersistedEntityType, + getPersistedPropertyType, +} from "../lib/subgraph"; /** * Helper type-guard for determining if a `ValueOrArray` definition is an array or a value. @@ -40,7 +44,12 @@ const ExampleUsage = ({ ownedById }: { ownedById: string }) => { const { entityTypeRootedSubgraph, ...entityWithoutEntityType } = entity ?? {}; - const { entityType } = entityTypeRootedSubgraph ?? {}; + const entityType = entityTypeRootedSubgraph + ? getPersistedEntityType( + entityTypeRootedSubgraph, + entityTypeRootedSubgraph.roots[0]!, + )?.inner + : undefined; // The (top-level) property type IDs defined in the entity type const propertyTypeIds = useMemo( @@ -57,8 +66,10 @@ const ExampleUsage = ({ ownedById }: { ownedById: string }) => { const propertyTypeDefinitions = useMemo( () => entityTypeRootedSubgraph && propertyTypeIds - ? entityTypeRootedSubgraph.referencedPropertyTypes.filter( - ({ propertyTypeId }) => propertyTypeIds.includes(propertyTypeId), + ? propertyTypeIds.map( + (propertyTypeId) => + getPersistedPropertyType(entityTypeRootedSubgraph, propertyTypeId) + ?.inner, ) : undefined, [entityTypeRootedSubgraph, propertyTypeIds],