Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

H-2205, H-2354: Implement multi-type entities in the graph #4140

Merged
merged 12 commits into from
Mar 12, 2024
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.

8 changes: 5 additions & 3 deletions apps/hash-ai-worker-ts/src/activities/infer-entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
zeroedGraphResolveDepths,
} from "@local/hash-isomorphic-utils/graph-queries";
import { systemLinkEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids";
import type { AccountId, Subgraph, Timestamp } from "@local/hash-subgraph";
import type { AccountId, Timestamp } from "@local/hash-subgraph";
import { mapGraphApiSubgraphToSubgraph } from "@local/hash-subgraph/stdlib";
import { StatusCode } from "@local/status";
import { CancelledFailure, Context } from "@temporalio/activity";
import dedent from "dedent";
Expand Down Expand Up @@ -269,7 +270,7 @@ const inferEntities = async ({
for (const entityTypeId of entityTypeIds) {
entityTypes[entityTypeId] = dereferenceEntityType(
entityTypeId,
entityTypesSubgraph as Subgraph,
mapGraphApiSubgraphToSubgraph(entityTypesSubgraph),
);
}
} catch (err) {
Expand Down Expand Up @@ -555,10 +556,11 @@ export const inferEntitiesActivity = async ({
draft: false,
properties: {},
ownedById: userAuthenticationInfo.actorId,
entityTypeId:
entityTypeIds: [
entityResult.operation === "create"
? systemLinkEntityTypes.created.linkEntityTypeId
: systemLinkEntityTypes.updated.linkEntityTypeId,
],
linkData: {
leftEntityId: usageRecordMetadata.recordId.entityId,
rightEntityId: entityResult.entity.metadata.recordId.entityId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Subgraph as ApiClientSubgraph } from "@local/hash-graph-client";
import type { Subgraph } from "@local/hash-subgraph";
import { mapGraphApiVerticesToVertices } from "@local/hash-subgraph/stdlib";

import { dereferenceEntityType } from "./dereference-entity-type";

Expand Down Expand Up @@ -981,7 +982,10 @@ describe("The dereferenceEntityType function", () => {
it("correctly dereferences an entity type", () => {
const result = dereferenceEntityType(
"https://hash.ai/@test/types/entity-type/property-values-demo/v/4",
testSubgraph as Subgraph,
{
...testSubgraph,
vertices: mapGraphApiVerticesToVertices(testSubgraph.vertices),
} as Subgraph,
);

expect(result).toEqual(expectedResult);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { VersionedUrl } from "@blockprotocol/type-system/slim";
import type { Entity } from "@local/hash-graph-client";
import type {
InferenceTokenUsage,
InferredEntityChangeResult,
ProposedEntity,
} from "@local/hash-isomorphic-utils/ai-inference-types";
import type { Entity } from "@local/hash-subgraph";
import type OpenAI from "openai";

import type { DereferencedEntityType } from "./dereference-entity-type";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { typedEntries } from "@local/advanced-types/typed-entries";
import type {
AllFilter,
CosineDistanceFilter,
Entity,
GraphApi,
} from "@local/hash-graph-client";
import type {
Expand All @@ -15,8 +14,7 @@ import { generateVersionedUrlMatchingFilter } from "@local/hash-isomorphic-utils
import type {
AccountId,
BaseUrl,
Entity as BrandedEntity,
EntityId,
Entity,
LinkData,
OwnedById,
} from "@local/hash-subgraph";
Expand Down Expand Up @@ -301,7 +299,7 @@ export const createEntities = async ({
internalEntityStatusMap.unchangedEntities[
proposedEntity.entityId
] = {
entity: existingEntity as BrandedEntity,
entity: existingEntity,
entityTypeId,
operation: "already-exists-as-proposed",
proposedEntity,
Expand All @@ -313,15 +311,15 @@ export const createEntities = async ({

try {
await graphApiClient.validateEntity(actorId, {
entityType: entityTypeId,
entityTypes: [entityTypeId],
profile: createAsDraft ? "draft" : "full",
properties,
});

const { data: createdEntityMetadata } =
await graphApiClient.createEntity(actorId, {
draft: createAsDraft,
entityTypeId,
entityTypeIds: [entityTypeId],
ownedById,
properties,
relationships: [
Expand Down Expand Up @@ -495,13 +493,13 @@ export const createEntities = async ({
}

const linkData: LinkData = {
leftEntityId: sourceEntity.metadata.recordId.entityId as EntityId,
rightEntityId: targetEntity.metadata.recordId.entityId as EntityId,
leftEntityId: sourceEntity.metadata.recordId.entityId,
rightEntityId: targetEntity.metadata.recordId.entityId,
};

try {
await graphApiClient.validateEntity(actorId, {
entityType: entityTypeId,
entityTypes: [entityTypeId],
profile: createAsDraft ? "draft" : "full",
properties,
linkData,
Expand Down Expand Up @@ -589,7 +587,7 @@ export const createEntities = async ({
const { data: createdEntityMetadata } =
await graphApiClient.createEntity(actorId, {
draft: createAsDraft,
entityTypeId,
entityTypeIds: [entityTypeId],
linkData,
ownedById,
properties,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export const updateEntities = async ({
);

await graphApiClient.validateEntity(actorId, {
entityType: entityTypeId,
entityTypes: [entityTypeId],
profile: draft ? "draft" : "full",
properties,
linkData: existingEntity.linkData,
Expand All @@ -127,7 +127,7 @@ export const updateEntities = async ({
await graphApiClient.updateEntity(actorId, {
archived: existingEntity.metadata.archived,
draft,
entityTypeId,
entityTypeIds: [entityTypeId],
entityId: updateEntityId,
properties: newProperties,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const parseTextFromFile = async (

await graphApiClient.updateEntity(webMachineActorId, {
entityId: fileEntity.metadata.recordId.entityId,
entityTypeId: fileEntity.metadata.entityTypeId,
entityTypeIds: [fileEntity.metadata.entityTypeId],
properties: updatedProperties,
archived: fileEntity.metadata.archived,
draft:
Expand Down
58 changes: 23 additions & 35 deletions apps/hash-api/src/graph/knowledge/primitive/entity.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { VersionedUrl } from "@blockprotocol/type-system";
import { typedEntries, typedKeys } from "@local/advanced-types/typed-entries";
import {
EntityMetadata,
EntityPermission,
EntityStructuralQuery,
EntityType,
Filter,
GraphResolveDepths,
ModifyRelationshipOperation,
Expand All @@ -27,7 +28,6 @@ import {
Entity,
EntityAuthorizationRelationship,
EntityId,
EntityMetadata,
EntityPropertiesObject,
EntityRelationAndSubject,
EntityRootType,
Expand All @@ -42,6 +42,7 @@ import {
} from "@local/hash-subgraph";
import {
getRoots,
mapGraphApiEntityMetadataToMetadata,
mapGraphApiSubgraphToSubgraph,
} from "@local/hash-subgraph/stdlib";
import { LinkEntity } from "@local/hash-subgraph/type-system-patch";
Expand Down Expand Up @@ -119,14 +120,17 @@ export const createEntity: ImpureGraphFunction<

const { data: metadata } = await graphApi.createEntity(actorId, {
ownedById,
entityTypeId,
entityTypeIds: [entityTypeId],
properties,
entityUuid: overrideEntityUuid,
draft,
relationships: params.relationships,
});

const entity = { properties, metadata: metadata as EntityMetadata };
const entity = {
properties,
metadata: mapGraphApiEntityMetadataToMetadata(metadata),
};

for (const createOutgoingLinkParams of outgoingLinks ?? []) {
await createLinkEntity(context, authentication, {
Expand Down Expand Up @@ -199,29 +203,25 @@ export const getEntities: ImpureGraphFunction<
return await graphApi
.getEntitiesByQuery(actorId, { query })
.then(({ data }) => {
const subgraph = mapGraphApiSubgraphToSubgraph<EntityRootType>(
data.subgraph,
);
// filter archived entities from the vertices until we implement archival by timestamp, not flag: remove after H-349
for (const [entityId, editionMap] of Object.entries(
data.subgraph.vertices,
)) {
const latestEditionTimestamp = Object.keys(editionMap).sort().pop();
for (const [entityId, editionMap] of typedEntries(subgraph.vertices)) {
const latestEditionTimestamp = typedKeys(editionMap).sort().pop()!;

if (
(
editionMap[latestEditionTimestamp!]!.inner
.metadata as EntityMetadata
).archived &&
// @ts-expect-error - The subgraph vertices are entity vertices so `Timestamp` is the correct type to get
// the latest revision
(editionMap[latestEditionTimestamp]!.inner.metadata as EntityMetadata)
.archived &&
// if the vertex is in the roots of the query, then it is intentionally included
!data.subgraph.roots.find((root) => root.baseId === entityId)
!subgraph.roots.find((root) => root.baseId === entityId)
) {
// eslint-disable-next-line no-param-reassign -- temporary hack
delete data.subgraph.vertices[entityId];
delete subgraph.vertices[entityId];
}
}

const subgraph = mapGraphApiSubgraphToSubgraph<EntityRootType>(
data.subgraph,
);

return subgraph;
});
};
Expand Down Expand Up @@ -487,7 +487,7 @@ export const updateEntity: ImpureGraphFunction<
*
* @see https://app.asana.com/0/1201095311341924/1203285029221330/f
* */
entityTypeId: entityTypeId ?? entity.metadata.entityTypeId,
entityTypeIds: [entityTypeId ?? entity.metadata.entityTypeId],
archived: entity.metadata.archived,
draft:
params.draft ??
Expand All @@ -508,7 +508,7 @@ export const updateEntity: ImpureGraphFunction<

return {
...entity,
metadata: metadata as EntityMetadata,
metadata: mapGraphApiEntityMetadataToMetadata(metadata),
properties,
};
};
Expand All @@ -529,7 +529,7 @@ export const archiveEntity: ImpureGraphFunction<
* @see https://app.asana.com/0/1201095311341924/1203285029221330/f
* */
draft: !!extractDraftIdFromEntityId(entity.metadata.recordId.entityId),
entityTypeId: entity.metadata.entityTypeId,
entityTypeIds: [entity.metadata.entityTypeId],
properties: entity.properties,
});
};
Expand All @@ -550,7 +550,7 @@ export const unarchiveEntity: ImpureGraphFunction<
* */
archived: false,
draft: !!extractDraftIdFromEntityId(entity.metadata.recordId.entityId),
entityTypeId: entity.metadata.entityTypeId,
entityTypeIds: [entity.metadata.entityTypeId],
properties: entity.properties,
});
};
Expand Down Expand Up @@ -1008,15 +1008,3 @@ export const getEntityAuthorizationRelationships: ImpureGraphFunction<
}) as EntityAuthorizationRelationship,
),
);

export const validateEntity: ImpureGraphFunction<
{
entityType: VersionedUrl | EntityType;
properties: Entity["properties"];
linkData?: Entity["linkData"];
profile: "draft" | "full";
},
Promise<void>
> = async ({ graphApi }, { actorId }, params) => {
await graphApi.validateEntity(actorId, params);
};
10 changes: 5 additions & 5 deletions apps/hash-api/src/graph/knowledge/primitive/link-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import {
AccountId,
Entity,
EntityId,
EntityMetadata,
EntityPropertiesObject,
EntityRelationAndSubject,
extractDraftIdFromEntityId,
LinkData,
OwnedById,
} from "@local/hash-subgraph";
import { mapGraphApiEntityMetadataToMetadata } from "@local/hash-subgraph/stdlib";
import { LinkEntity } from "@local/hash-subgraph/type-system-patch";

import { ImpureGraphFunction } from "../../context-types";
Expand Down Expand Up @@ -95,15 +95,15 @@ export const createLinkEntity: ImpureGraphFunction<
{
ownedById,
linkData,
entityTypeId: linkEntityType.schema.$id,
entityTypeIds: [linkEntityType.schema.$id],
properties,
draft,
relationships: params.relationships,
},
);

const linkEntity = {
metadata: metadata as EntityMetadata,
metadata: mapGraphApiEntityMetadataToMetadata(metadata),
properties,
linkData,
};
Expand Down Expand Up @@ -146,7 +146,7 @@ export const updateLinkEntity: ImpureGraphFunction<

const { data: metadata } = await graphApi.updateEntity(actorId, {
entityId: linkEntity.metadata.recordId.entityId,
entityTypeId: linkEntity.metadata.entityTypeId,
entityTypeIds: [linkEntity.metadata.entityTypeId],
properties,
archived: linkEntity.metadata.archived,
draft:
Expand All @@ -157,7 +157,7 @@ export const updateLinkEntity: ImpureGraphFunction<
});

return {
metadata: metadata as EntityMetadata,
metadata: mapGraphApiEntityMetadataToMetadata(metadata),
properties,
linkData: {
...linkEntity.linkData,
Expand Down
6 changes: 3 additions & 3 deletions apps/hash-graph/libs/api/src/rest/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ where
struct UpdateEntityRequest {
properties: EntityProperties,
entity_id: EntityId,
entity_type_id: VersionedUrl,
entity_type_ids: Vec<VersionedUrl>,
#[serde(flatten)]
order: EntityLinkOrder,
archived: bool,
Expand Down Expand Up @@ -507,7 +507,7 @@ where
let Json(UpdateEntityRequest {
properties,
entity_id,
entity_type_id,
entity_type_ids,
order: link_order,
archived,
draft,
Expand All @@ -528,7 +528,7 @@ where
UpdateEntityParams {
entity_id,
decision_time,
entity_type_id,
entity_type_ids,
properties,
link_order,
archived,
Expand Down
Loading
Loading