Skip to content

Commit

Permalink
fix(temporal): do not filter deleted attributes / entities in tempora…
Browse files Browse the repository at this point in the history
…l queries
  • Loading branch information
bobeal committed Dec 11, 2024
1 parent d5e7a9a commit 2b5f96f
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ class EntityQueryService(
suspend fun queryEntities(
entitiesQuery: EntitiesQuery,
accessRightFilter: () -> String?
): List<URI> =
queryEntities(entitiesQuery, true, accessRightFilter)

suspend fun queryEntities(
entitiesQuery: EntitiesQuery,
excludedDeleted: Boolean = true,
accessRightFilter: () -> String?
): List<URI> {
val filterQuery = buildFullEntitiesFilter(entitiesQuery, accessRightFilter)

Expand All @@ -81,9 +88,10 @@ class EntityQueryService(
SELECT DISTINCT(entity_payload.entity_id)
FROM entity_payload
LEFT JOIN temporal_entity_attribute tea
ON tea.entity_id = entity_payload.entity_id AND tea.deleted_at is null
ON tea.entity_id = entity_payload.entity_id
${if (excludedDeleted) " AND tea.deleted_at is null " else ""}
WHERE $filterQuery
AND entity_payload.deleted_at is null
${if (excludedDeleted) " AND entity_payload.deleted_at is null " else ""}
ORDER BY entity_id
LIMIT :limit
OFFSET :offset
Expand All @@ -99,6 +107,13 @@ class EntityQueryService(
suspend fun queryEntitiesCount(
entitiesQuery: EntitiesQuery,
accessRightFilter: () -> String?
): Either<APIException, Int> =
queryEntitiesCount(entitiesQuery, true, accessRightFilter)

suspend fun queryEntitiesCount(
entitiesQuery: EntitiesQuery,
excludedDeleted: Boolean = true,
accessRightFilter: () -> String?
): Either<APIException, Int> {
val filterQuery = buildFullEntitiesFilter(entitiesQuery, accessRightFilter)

Expand All @@ -107,9 +122,10 @@ class EntityQueryService(
SELECT count(distinct(entity_payload.entity_id)) as count_entity
FROM entity_payload
LEFT JOIN temporal_entity_attribute tea
ON tea.entity_id = entity_payload.entity_id AND tea.deleted_at is null
ON tea.entity_id = entity_payload.entity_id
${if (excludedDeleted) " AND tea.deleted_at is null " else ""}
WHERE $filterQuery
AND entity_payload.deleted_at is null
${if (excludedDeleted) " AND entity_payload.deleted_at is null " else ""}
""".trimIndent()

return databaseClient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class TemporalQueryService(

val attrs = temporalEntitiesQuery.entitiesQuery.attrs
val datasetIds = temporalEntitiesQuery.entitiesQuery.datasetId
val attributes = entityAttributeService.getForEntity(entityId, attrs, datasetIds).let {
val attributes = entityAttributeService.getForEntity(entityId, attrs, datasetIds, false).let {
if (it.isEmpty())
ResourceNotFoundException(
entityOrAttrsNotFoundMessage(entityId.toString(), temporalEntitiesQuery.entitiesQuery.attrs)
Expand Down Expand Up @@ -122,9 +122,11 @@ class TemporalQueryService(
): Either<APIException, Triple<List<ExpandedEntity>, Int, Range?>> = either {
val accessRightFilter = authorizationService.computeAccessRightFilter(sub.toOption())
val attrs = temporalEntitiesQuery.entitiesQuery.attrs
val entitiesIds = entityQueryService.queryEntities(temporalEntitiesQuery.entitiesQuery, accessRightFilter)
val count = entityQueryService.queryEntitiesCount(temporalEntitiesQuery.entitiesQuery, accessRightFilter)
.getOrElse { 0 }
val entitiesIds =
entityQueryService.queryEntities(temporalEntitiesQuery.entitiesQuery, false, accessRightFilter)
val count =
entityQueryService.queryEntitiesCount(temporalEntitiesQuery.entitiesQuery, false, accessRightFilter)
.getOrElse { 0 }

// we can have an empty list of entities with a non-zero count (e.g., offset too high)
if (entitiesIds.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class TemporalQueryServiceTests {

coEvery { entityQueryService.checkEntityExistence(any()) } returns Unit.right()
coEvery { authorizationService.userCanReadEntity(any(), any()) } returns Unit.right()
coEvery { entityAttributeService.getForEntity(any(), any(), any()) } returns attributes
coEvery { entityAttributeService.getForEntity(any(), any(), any(), any()) } returns attributes
coEvery { entityQueryService.retrieve(any<URI>()) } returns gimmeEntityPayload().right()
coEvery { scopeService.retrieveHistory(any(), any()) } returns emptyList<ScopeInstanceResult>().right()
coEvery {
Expand Down Expand Up @@ -149,7 +149,7 @@ class TemporalQueryServiceTests {
coVerify {
entityQueryService.checkEntityExistence(entityUri)
authorizationService.userCanReadEntity(entityUri, None)
entityAttributeService.getForEntity(entityUri, emptySet(), emptySet())
entityAttributeService.getForEntity(entityUri, emptySet(), emptySet(), false)
attributeInstanceService.search(
match { temporalEntitiesQuery ->
temporalEntitiesQuery.temporalQuery.timerel == TemporalQuery.Timerel.AFTER &&
Expand Down Expand Up @@ -246,11 +246,11 @@ class TemporalQueryServiceTests {
)

coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null }
coEvery { entityQueryService.queryEntities(any(), any<() -> String?>()) } returns listOf(entityUri)
coEvery { entityQueryService.queryEntities(any(), any(), any<() -> String?>()) } returns listOf(entityUri)
coEvery {
entityAttributeService.getForEntities(any(), any())
} returns listOf(attribute)
coEvery { entityQueryService.queryEntitiesCount(any(), any()) } returns 1.right()
coEvery { entityQueryService.queryEntitiesCount(any(), any(), any()) } returns 1.right()
coEvery { scopeService.retrieveHistory(any(), any()) } returns emptyList<ScopeInstanceResult>().right()
coEvery { entityQueryService.retrieve(any<URI>()) } returns gimmeEntityPayload().right()
coEvery {
Expand Down Expand Up @@ -305,6 +305,7 @@ class TemporalQueryServiceTests {
paginationQuery = PaginationQuery(limit = 2, offset = 2),
contexts = APIC_COMPOUND_CONTEXTS
),
false,
any()
)
scopeService.retrieveHistory(listOf(entityUri), any())
Expand All @@ -322,7 +323,7 @@ class TemporalQueryServiceTests {
)

coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null }
coEvery { entityQueryService.queryEntities(any(), any<() -> String?>()) } returns listOf(entityUri)
coEvery { entityQueryService.queryEntities(any(), any(), any<() -> String?>()) } returns listOf(entityUri)
coEvery {
entityAttributeService.getForEntities(any(), any())
} returns listOf(attribute)
Expand All @@ -331,7 +332,7 @@ class TemporalQueryServiceTests {
attributeInstanceService.search(any(), any<List<Attribute>>())
} returns emptyList<AttributeInstanceResult>().right()
coEvery { entityQueryService.retrieve(any<URI>()) } returns gimmeEntityPayload().right()
coEvery { entityQueryService.queryEntitiesCount(any(), any()) } returns 1.right()
coEvery { entityQueryService.queryEntitiesCount(any(), any(), any()) } returns 1.right()

temporalQueryService.queryTemporalEntities(
TemporalEntitiesQueryFromGet(
Expand Down

0 comments on commit 2b5f96f

Please sign in to comment.