Skip to content

Commit

Permalink
H-3285, H-3286: Optionally return set of distinct values for entity (…
Browse files Browse the repository at this point in the history
…type) queries (#5029)
  • Loading branch information
TimDiekmann authored Sep 9, 2024
1 parent fb7116d commit ed39631
Show file tree
Hide file tree
Showing 19 changed files with 553 additions and 64 deletions.
55 changes: 55 additions & 0 deletions apps/hash-graph/libs/api/src/rest/entity.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Web routes for CRU operations on entities.
use alloc::sync::Arc;
use std::collections::HashMap;

use authorization::{
backend::{ModifyRelationshipOperation, PermissionAssertion},
Expand Down Expand Up @@ -36,6 +37,7 @@ use graph::{
subgraph::{edges::GraphResolveDepths, temporal_axes::QueryTemporalAxesUnresolved},
};
use graph_types::{
account::{CreatedById, EditionCreatedById},
knowledge::{
entity::{
ActorType, Entity, EntityEditionId, EntityEditionProvenance, EntityEmbedding, EntityId,
Expand All @@ -58,6 +60,7 @@ use graph_types::{
};
use serde::{Deserialize, Serialize};
use temporal_client::TemporalClient;
use type_system::url::VersionedUrl;
use utoipa::{OpenApi, ToSchema};
use validation::ValidateEntityComponents;

Expand Down Expand Up @@ -483,6 +486,10 @@ fn generate_sorting_paths(

#[derive(Debug, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[expect(
clippy::struct_excessive_bools,
reason = "Parameter struct deserialized from JSON"
)]
struct GetEntitiesRequest<'q, 's, 'p> {
#[serde(borrow)]
filter: Filter<'q, Entity>,
Expand All @@ -495,6 +502,14 @@ struct GetEntitiesRequest<'q, 's, 'p> {
cursor: Option<EntityQueryCursor<'s>>,
#[serde(default)]
include_count: bool,
#[serde(default)]
include_web_ids: bool,
#[serde(default)]
include_created_by_ids: bool,
#[serde(default)]
include_edition_created_by_ids: bool,
#[serde(default)]
include_type_ids: bool,
}

#[utoipa::path(
Expand Down Expand Up @@ -564,6 +579,10 @@ where
include_drafts: request.include_drafts,
include_count: request.include_count,
temporal_axes: request.temporal_axes,
include_web_ids: request.include_web_ids,
include_created_by_ids: request.include_created_by_ids,
include_edition_created_by_ids: request.include_edition_created_by_ids,
include_type_ids: request.include_type_ids,
},
)
.await
Expand All @@ -572,13 +591,21 @@ where
entities: response.entities,
cursor: response.cursor.map(EntityQueryCursor::into_owned),
count: response.count,
web_ids: response.web_ids,
created_by_ids: response.created_by_ids,
edition_created_by_ids: response.edition_created_by_ids,
type_ids: response.type_ids,
})
})
.map_err(report_to_response)
}

#[derive(Debug, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[expect(
clippy::struct_excessive_bools,
reason = "Parameter struct deserialized from JSON"
)]
struct GetEntitySubgraphRequest<'q, 's, 'p> {
#[serde(borrow)]
filter: Filter<'q, Entity>,
Expand All @@ -592,6 +619,14 @@ struct GetEntitySubgraphRequest<'q, 's, 'p> {
cursor: Option<EntityQueryCursor<'s>>,
#[serde(default)]
include_count: bool,
#[serde(default)]
include_web_ids: bool,
#[serde(default)]
include_created_by_ids: bool,
#[serde(default)]
include_edition_created_by_ids: bool,
#[serde(default)]
include_type_ids: bool,
}

#[derive(Serialize, ToSchema)]
Expand All @@ -601,6 +636,18 @@ struct GetEntitySubgraphResponse<'r> {
#[serde(borrow)]
cursor: Option<EntityQueryCursor<'r>>,
count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(nullable = false)]
web_ids: Option<HashMap<OwnedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(nullable = false)]
created_by_ids: Option<HashMap<CreatedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(nullable = false)]
edition_created_by_ids: Option<HashMap<EditionCreatedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(nullable = false)]
type_ids: Option<HashMap<VersionedUrl, usize>>,
}

#[utoipa::path(
Expand Down Expand Up @@ -672,6 +719,10 @@ where
include_drafts: request.include_drafts,
include_count: request.include_count,
temporal_axes: request.temporal_axes,
include_web_ids: request.include_web_ids,
include_created_by_ids: request.include_created_by_ids,
include_edition_created_by_ids: request.include_edition_created_by_ids,
include_type_ids: request.include_type_ids,
},
)
.await
Expand All @@ -680,6 +731,10 @@ where
subgraph: response.subgraph.into(),
cursor: response.cursor.map(EntityQueryCursor::into_owned),
count: response.count,
web_ids: response.web_ids,
created_by_ids: response.created_by_ids,
edition_created_by_ids: response.edition_created_by_ids,
type_ids: response.type_ids,
})
})
.map_err(report_to_response)
Expand Down
11 changes: 11 additions & 0 deletions apps/hash-graph/libs/api/src/rest/entity_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use graph::{
subgraph::identifier::EntityTypeVertexId,
};
use graph_types::{
account::EditionCreatedById,
ontology::{
EntityTypeEmbedding, EntityTypeId, EntityTypeMetadata, EntityTypeWithMetadata,
OntologyTemporalMetadata, OntologyTypeClassificationMetadata, OntologyTypeMetadata,
Expand Down Expand Up @@ -749,6 +750,13 @@ where
struct GetEntityTypeSubgraphResponse {
subgraph: Subgraph,
cursor: Option<EntityTypeVertexId>,
count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(nullable = false)]
web_ids: Option<HashMap<OwnedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(nullable = false)]
edition_created_by_ids: Option<HashMap<EditionCreatedById, usize>>,
}

#[utoipa::path(
Expand Down Expand Up @@ -809,6 +817,9 @@ where
Json(GetEntityTypeSubgraphResponse {
subgraph: Subgraph::from(response.subgraph),
cursor: response.cursor,
count: response.count,
web_ids: response.web_ids,
edition_created_by_ids: response.edition_created_by_ids,
})
})
}
Expand Down
2 changes: 2 additions & 0 deletions apps/hash-graph/libs/graph/src/store/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ where
limit: None,
include_drafts: true,
include_count: false,
include_web_ids: false,
include_edition_created_by_ids: false,
},
)
.await
Expand Down
44 changes: 30 additions & 14 deletions apps/hash-graph/libs/graph/src/store/knowledge.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use alloc::borrow::Cow;
use core::{error::Error, fmt};
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};

use authorization::{schema::EntityRelationAndSubject, zanzibar::Consistency};
use error_stack::Report;
use futures::TryFutureExt;
use graph_types::{
account::AccountId,
account::{AccountId, CreatedById, EditionCreatedById},
knowledge::{
entity::{Entity, EntityEmbedding, EntityId, EntityUuid, ProvidedEntityEditionProvenance},
link::LinkData,
Expand Down Expand Up @@ -216,19 +216,19 @@ pub struct ValidateEntityParams<'a> {
pub components: ValidateEntityComponents,
}

#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[derive(Debug)]
#[expect(clippy::struct_excessive_bools, reason = "Parameter struct")]
pub struct GetEntitiesParams<'a> {
#[serde(borrow)]
pub filter: Filter<'a, Entity>,
pub temporal_axes: QueryTemporalAxesUnresolved,
#[serde(borrow)]
pub sorting: EntityQuerySorting<'static>,
pub limit: Option<usize>,
pub include_drafts: bool,
#[serde(default)]
pub include_count: bool,
pub include_web_ids: bool,
pub include_created_by_ids: bool,
pub include_edition_created_by_ids: bool,
pub include_type_ids: bool,
}

#[derive(Debug, Serialize)]
Expand All @@ -238,29 +238,45 @@ pub struct GetEntitiesResponse<'r> {
pub entities: Vec<Entity>,
pub cursor: Option<EntityQueryCursor<'r>>,
pub count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(nullable = false))]
pub web_ids: Option<HashMap<OwnedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(nullable = false))]
pub created_by_ids: Option<HashMap<CreatedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(nullable = false))]
pub edition_created_by_ids: Option<HashMap<EditionCreatedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(nullable = false))]
pub type_ids: Option<HashMap<VersionedUrl, usize>>,
}

#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[derive(Debug)]
#[expect(clippy::struct_excessive_bools, reason = "Parameter struct")]
pub struct GetEntitySubgraphParams<'a> {
#[serde(borrow)]
pub filter: Filter<'a, Entity>,
pub temporal_axes: QueryTemporalAxesUnresolved,
pub graph_resolve_depths: GraphResolveDepths,
#[serde(borrow)]
pub sorting: EntityQuerySorting<'static>,
pub limit: Option<usize>,
pub include_drafts: bool,
#[serde(default)]
pub include_count: bool,
pub include_web_ids: bool,
pub include_created_by_ids: bool,
pub include_edition_created_by_ids: bool,
pub include_type_ids: bool,
}

#[derive(Debug)]
pub struct GetEntitySubgraphResponse<'r> {
pub subgraph: Subgraph,
pub cursor: Option<EntityQueryCursor<'r>>,
pub count: Option<usize>,
pub web_ids: Option<HashMap<OwnedById, usize>>,
pub created_by_ids: Option<HashMap<CreatedById, usize>>,
pub edition_created_by_ids: Option<HashMap<EditionCreatedById, usize>>,
pub type_ids: Option<HashMap<VersionedUrl, usize>>,
}

#[derive(Debug, Deserialize)]
Expand Down
21 changes: 20 additions & 1 deletion apps/hash-graph/libs/graph/src/store/ontology.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use authorization::schema::{
};
use error_stack::Result;
use graph_types::{
account::AccountId,
account::{AccountId, EditionCreatedById},
ontology::{
DataTypeMetadata, DataTypeWithMetadata, EntityTypeMetadata, EntityTypeWithMetadata,
OntologyTemporalMetadata, OntologyTypeClassificationMetadata, PropertyTypeMetadata,
PropertyTypeWithMetadata, ProvidedOntologyEditionProvenance,
},
owned_by_id::OwnedById,
Embedding,
};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -534,6 +535,7 @@ pub struct CreateEntityTypeParams<R> {
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[expect(clippy::struct_excessive_bools, reason = "Parameter struct")]
pub struct GetEntityTypeSubgraphParams<'p> {
#[serde(borrow)]
pub filter: Filter<'p, EntityTypeWithMetadata>,
Expand All @@ -544,13 +546,19 @@ pub struct GetEntityTypeSubgraphParams<'p> {
pub include_drafts: bool,
#[serde(default)]
pub include_count: bool,
#[serde(default)]
pub include_web_ids: bool,
#[serde(default)]
pub include_edition_created_by_ids: bool,
}

#[derive(Debug)]
pub struct GetEntityTypeSubgraphResponse {
pub subgraph: Subgraph,
pub cursor: Option<EntityTypeVertexId>,
pub count: Option<usize>,
pub web_ids: Option<HashMap<OwnedById, usize>>,
pub edition_created_by_ids: Option<HashMap<EditionCreatedById, usize>>,
}

#[derive(Debug, Deserialize)]
Expand All @@ -566,6 +574,7 @@ pub struct CountEntityTypesParams<'p> {
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[expect(clippy::struct_excessive_bools, reason = "Parameter struct")]
pub struct GetEntityTypesParams<'p> {
#[serde(borrow)]
pub filter: Filter<'p, EntityTypeWithMetadata>,
Expand All @@ -577,6 +586,10 @@ pub struct GetEntityTypesParams<'p> {
pub limit: Option<usize>,
#[serde(default)]
pub include_count: bool,
#[serde(default)]
pub include_web_ids: bool,
#[serde(default)]
pub include_edition_created_by_ids: bool,
}

#[derive(Debug, Serialize)]
Expand All @@ -586,6 +599,12 @@ pub struct GetEntityTypesResponse {
pub entity_types: Vec<EntityTypeWithMetadata>,
pub cursor: Option<EntityTypeVertexId>,
pub count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(nullable = false))]
pub web_ids: Option<HashMap<OwnedById, usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "utoipa", schema(nullable = false))]
pub edition_created_by_ids: Option<HashMap<EditionCreatedById, usize>>,
}

#[derive(Debug, Deserialize)]
Expand Down
Loading

0 comments on commit ed39631

Please sign in to comment.