diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/AuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/AuthorizationService.kt index 1aead2e427..c0dd9d0fe8 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/AuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/AuthorizationService.kt @@ -2,7 +2,7 @@ package com.egm.stellio.search.authorization.service import arrow.core.Either import arrow.core.Option -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.Sub @@ -22,7 +22,7 @@ interface AuthorizationService { suspend fun removeRightsOnEntity(entityId: URI): Either suspend fun getAuthorizedEntities( - entitiesQuery: EntitiesQuery, + entitiesQuery: EntitiesQueryFromGet, contexts: List, sub: Option ): Either>> diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/DisabledAuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/DisabledAuthorizationService.kt index 21da63b1e9..f27debb040 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/DisabledAuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/DisabledAuthorizationService.kt @@ -3,7 +3,7 @@ package com.egm.stellio.search.authorization.service import arrow.core.Either import arrow.core.Option import arrow.core.right -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.ExpandedEntity import com.egm.stellio.shared.util.Sub @@ -40,7 +40,7 @@ class DisabledAuthorizationService : AuthorizationService { override suspend fun removeRightsOnEntity(entityId: URI): Either = Unit.right() override suspend fun getAuthorizedEntities( - entitiesQuery: EntitiesQuery, + entitiesQuery: EntitiesQueryFromGet, contexts: List, sub: Option ): Either>> = Pair(-1, emptyList()).right() diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationService.kt index c1563b1195..53e3e31cf9 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationService.kt @@ -9,7 +9,7 @@ import arrow.core.left import arrow.core.raise.either import arrow.core.right import arrow.fx.coroutines.parMap -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.AccessDeniedException import com.egm.stellio.shared.model.ExpandedEntity @@ -107,7 +107,7 @@ class EnabledAuthorizationService( entityAccessRightsService.removeRolesOnEntity(entityId) override suspend fun getAuthorizedEntities( - entitiesQuery: EntitiesQuery, + entitiesQuery: EntitiesQueryFromGet, contexts: List, sub: Option ): Either>> = either { diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/web/EntityAccessControlHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/web/EntityAccessControlHandler.kt index 275f06c7bd..ca8b224b6e 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/authorization/web/EntityAccessControlHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/authorization/web/EntityAccessControlHandler.kt @@ -8,7 +8,7 @@ import com.egm.stellio.search.entity.model.NotUpdatedDetails import com.egm.stellio.search.entity.model.UpdateAttributeResult import com.egm.stellio.search.entity.model.UpdateOperationResult import com.egm.stellio.search.entity.model.updateResultFromDetailedResult -import com.egm.stellio.search.entity.util.composeEntitiesQuery +import com.egm.stellio.search.entity.util.composeEntitiesQueryFromGet import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.AccessDeniedException import com.egm.stellio.shared.model.BadRequestDataException @@ -74,7 +74,7 @@ class EntityAccessControlHandler( val contexts = getAuthzContextFromLinkHeaderOrDefault(httpHeaders, applicationProperties.contexts).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() - val entitiesQuery = composeEntitiesQuery( + val entitiesQuery = composeEntitiesQueryFromGet( applicationProperties.pagination, params, contexts @@ -121,7 +121,7 @@ class EntityAccessControlHandler( val contexts = getAuthzContextFromLinkHeaderOrDefault(httpHeaders, applicationProperties.contexts).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() - val entitiesQuery = composeEntitiesQuery( + val entitiesQuery = composeEntitiesQueryFromGet( applicationProperties.pagination, params, contexts @@ -167,7 +167,7 @@ class EntityAccessControlHandler( val contexts = getAuthzContextFromLinkHeaderOrDefault(httpHeaders, applicationProperties.contexts).bind() val mediaType = getApplicableMediaType(httpHeaders).bind() - val entitiesQuery = composeEntitiesQuery( + val entitiesQuery = composeEntitiesQueryFromGet( applicationProperties.pagination, params, contexts diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/entity/model/EntitiesQuery.kt b/search-service/src/main/kotlin/com/egm/stellio/search/entity/model/EntitiesQuery.kt index 9a1e80113f..927bf622a4 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/entity/model/EntitiesQuery.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/entity/model/EntitiesQuery.kt @@ -1,20 +1,42 @@ package com.egm.stellio.search.entity.model +import com.egm.stellio.shared.model.EntitySelector import com.egm.stellio.shared.model.EntityTypeSelection import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.model.PaginationQuery import java.net.URI -data class EntitiesQuery( +sealed class EntitiesQuery( + open val q: String? = null, + open val scopeQ: String? = null, + open val paginationQuery: PaginationQuery, + open val attrs: Set = emptySet(), + open val datasetId: Set = emptySet(), + open val geoQuery: GeoQuery? = null, + open val contexts: List +) + +data class EntitiesQueryFromGet( val ids: Set = emptySet(), val typeSelection: EntityTypeSelection? = null, val idPattern: String? = null, - val q: String? = null, - val scopeQ: String? = null, - val paginationQuery: PaginationQuery, - val attrs: Set = emptySet(), - val datasetId: Set = emptySet(), - val geoQuery: GeoQuery? = null, - val contexts: List -) + override val q: String? = null, + override val scopeQ: String? = null, + override val paginationQuery: PaginationQuery, + override val attrs: Set = emptySet(), + override val datasetId: Set = emptySet(), + override val geoQuery: GeoQuery? = null, + override val contexts: List +) : EntitiesQuery(q, scopeQ, paginationQuery, attrs, datasetId, geoQuery, contexts) + +data class EntitiesQueryFromPost( + val entitySelectors: List?, + override val q: String? = null, + override val scopeQ: String? = null, + override val paginationQuery: PaginationQuery, + override val attrs: Set = emptySet(), + override val datasetId: Set = emptySet(), + override val geoQuery: GeoQuery? = null, + override val contexts: List +) : EntitiesQuery(q, scopeQ, paginationQuery, attrs, datasetId, geoQuery, contexts) diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/entity/service/EntityQueryService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/entity/service/EntityQueryService.kt index c7c72285b4..23e2a7ec19 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/entity/service/EntityQueryService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/entity/service/EntityQueryService.kt @@ -13,6 +13,8 @@ import com.egm.stellio.search.common.util.oneToResult import com.egm.stellio.search.common.util.toUri import com.egm.stellio.search.common.util.wrapToAndClause import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import com.egm.stellio.search.entity.model.Entity import com.egm.stellio.search.entity.util.rowToEntity import com.egm.stellio.shared.model.APIException @@ -119,23 +121,32 @@ class EntityQueryService( buildEntitiesQueryFilter( entitiesQuery, accessRightFilter - ).let { - if (entitiesQuery.q != null) - it.wrapToAndClause(buildQQuery(entitiesQuery.q, entitiesQuery.contexts)) - else it - }.let { - if (entitiesQuery.scopeQ != null) - it.wrapToAndClause(buildScopeQQuery(entitiesQuery.scopeQ)) - else it - }.let { - if (entitiesQuery.geoQuery != null) - it.wrapToAndClause(buildGeoQuery(entitiesQuery.geoQuery)) - else it + ).let { sqlFilter -> + entitiesQuery.q?.let { q -> + sqlFilter.wrapToAndClause(buildQQuery(q, entitiesQuery.contexts)) + } ?: sqlFilter + }.let { sqlFilter -> + entitiesQuery.scopeQ?.let { scopeQ -> + sqlFilter.wrapToAndClause(buildScopeQQuery(scopeQ)) + } ?: sqlFilter + }.let { sqlFilter -> + entitiesQuery.geoQuery?.let { geoQuery -> + sqlFilter.wrapToAndClause(buildGeoQuery(geoQuery)) + } ?: sqlFilter } fun buildEntitiesQueryFilter( entitiesQuery: EntitiesQuery, accessRightFilter: () -> String? + ): String = + when (entitiesQuery) { + is EntitiesQueryFromGet -> buildEntitiesQueryFilterFromGet(entitiesQuery, accessRightFilter) + is EntitiesQueryFromPost -> buildEntitiesQueryFilterFromPost(entitiesQuery, accessRightFilter) + } + + fun buildEntitiesQueryFilterFromGet( + entitiesQuery: EntitiesQueryFromGet, + accessRightFilter: () -> String? ): String { val formattedIds = if (entitiesQuery.ids.isNotEmpty()) @@ -171,6 +182,37 @@ class EntityQueryService( return queryFilter.joinToString(separator = " AND ") } + fun buildEntitiesQueryFilterFromPost( + entitiesQuery: EntitiesQueryFromPost, + accessRightFilter: () -> String? + ): String { + val entitySelectorFilter = entitiesQuery.entitySelectors?.map { entitySelector -> + val formattedId = + entitySelector.id?.let { "entity_payload.entity_id = '${entitySelector.id}'" } + val formattedIdPattern = + entitySelector.idPattern?.let { "entity_payload.entity_id ~ '${entitySelector.idPattern}'" } + val formattedType = entitySelector.typeSelection.let { "(" + buildTypeQuery(it) + ")" } + val formattedAttrs = + if (entitiesQuery.attrs.isNotEmpty()) + entitiesQuery.attrs.joinToString( + separator = ",", + prefix = "attribute_name in (", + postfix = ")" + ) { "'$it'" } + else null + + listOfNotNull( + formattedId, + formattedIdPattern, + formattedType, + formattedAttrs, + accessRightFilter() + ).joinToString(separator = " AND ", prefix = "(", postfix = ")") + } + + return entitySelectorFilter?.joinToString(separator = " OR ") ?: " 1 = 1 " + } + suspend fun retrieve(entityId: URI): Either = databaseClient.sql( """ diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtils.kt b/search-service/src/main/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtils.kt index f19ffab2fe..01970fcf33 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtils.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtils.kt @@ -4,10 +4,12 @@ import arrow.core.Either import arrow.core.left import arrow.core.raise.either import com.egm.stellio.search.common.model.Query -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.BadRequestDataException +import com.egm.stellio.shared.model.EntitySelector import com.egm.stellio.shared.util.JsonLdUtils import com.egm.stellio.shared.util.QUERY_PARAM_ATTRS import com.egm.stellio.shared.util.QUERY_PARAM_DATASET_ID @@ -26,11 +28,11 @@ import com.egm.stellio.shared.util.toListOfUri import com.egm.stellio.shared.util.validateIdPattern import org.springframework.util.MultiValueMap -fun composeEntitiesQuery( +fun composeEntitiesQueryFromGet( defaultPagination: ApplicationProperties.Pagination, requestParams: MultiValueMap, contexts: List -): Either = either { +): Either = either { val ids = requestParams.getFirst(QUERY_PARAM_ID)?.split(",").orEmpty().toListOfUri().toSet() val typeSelection = expandTypeSelection(requestParams.getFirst(QUERY_PARAM_TYPE), contexts) val idPattern = validateIdPattern(requestParams.getFirst(QUERY_PARAM_ID_PATTERN)).bind() @@ -51,7 +53,7 @@ fun composeEntitiesQuery( val geoQuery = parseGeoQueryParameters(requestParams.toSingleValueMap(), contexts).bind() - EntitiesQuery( + EntitiesQueryFromGet( ids = ids, typeSelection = typeSelection, idPattern = idPattern, @@ -65,7 +67,7 @@ fun composeEntitiesQuery( ) } -fun EntitiesQuery.validateMinimalQueryEntitiesParameters(): Either = either { +fun EntitiesQueryFromGet.validateMinimalQueryEntitiesParameters(): Either = either { if ( geoQuery == null && q.isNullOrEmpty() && @@ -74,20 +76,25 @@ fun EntitiesQuery.validateMinimalQueryEntitiesParameters(): Either() + ).left().bind() this@validateMinimalQueryEntitiesParameters } -fun composeEntitiesQueryFromPostRequest( +fun composeEntitiesQueryFromPost( defaultPagination: ApplicationProperties.Pagination, query: Query, requestParams: MultiValueMap, contexts: List -): Either = either { - val entitySelector = query.entities?.get(0) - val typeSelection = expandTypeSelection(entitySelector?.typeSelection, contexts) - val idPattern = validateIdPattern(entitySelector?.idPattern).bind() +): Either = either { + val entitySelectors = query.entities?.map { entitySelector -> + validateIdPattern(entitySelector.idPattern).bind() + EntitySelector( + entitySelector.id, + entitySelector.idPattern, + expandTypeSelection(entitySelector.typeSelection, contexts)!! + ) + } val attrs = query.attrs.orEmpty().map { JsonLdUtils.expandJsonLdTerm(it.trim(), contexts) }.toSet() val datasetId = query.datasetId.orEmpty().toSet() val geoQuery = query.geoQ?.let { @@ -106,10 +113,8 @@ fun composeEntitiesQueryFromPostRequest( defaultPagination.limitMax ).bind() - EntitiesQuery( - ids = setOfNotNull(entitySelector?.id), - typeSelection = typeSelection, - idPattern = idPattern, + EntitiesQueryFromPost( + entitySelectors = entitySelectors, q = query.q?.decode(), scopeQ = query.scopeQ, paginationQuery = paginationQuery, diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt index cba6daca8b..cf6c3be7ff 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityHandler.kt @@ -6,7 +6,7 @@ import arrow.core.raise.either import arrow.core.right import com.egm.stellio.search.entity.service.EntityQueryService import com.egm.stellio.search.entity.service.EntityService -import com.egm.stellio.search.entity.util.composeEntitiesQuery +import com.egm.stellio.search.entity.util.composeEntitiesQueryFromGet import com.egm.stellio.search.entity.util.validateMinimalQueryEntitiesParameters import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.BadRequestDataException @@ -177,7 +177,7 @@ class EntityHandler( val sub = getSubFromSecurityContext() val contexts = getContextFromLinkHeaderOrDefault(httpHeaders, applicationProperties.contexts.core).bind() - val entitiesQuery = composeEntitiesQuery( + val entitiesQuery = composeEntitiesQueryFromGet( applicationProperties.pagination, params, contexts @@ -218,7 +218,7 @@ class EntityHandler( val sub = getSubFromSecurityContext() val contexts = getContextFromLinkHeaderOrDefault(httpHeaders, applicationProperties.contexts.core).bind() - val queryParams = composeEntitiesQuery( + val queryParams = composeEntitiesQueryFromGet( applicationProperties.pagination, params, contexts diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandler.kt index 8deb342d41..33d2d6e790 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandler.kt @@ -8,8 +8,7 @@ import arrow.core.right import com.egm.stellio.search.common.model.Query import com.egm.stellio.search.entity.service.EntityOperationService import com.egm.stellio.search.entity.service.EntityQueryService -import com.egm.stellio.search.entity.util.composeEntitiesQueryFromPostRequest -import com.egm.stellio.search.entity.util.validateMinimalQueryEntitiesParameters +import com.egm.stellio.search.entity.util.composeEntitiesQueryFromPost import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.BadRequestDataException @@ -243,13 +242,12 @@ class EntityOperationHandler( val mediaType = getApplicableMediaType(httpHeaders).bind() val query = Query(requestBody.awaitFirst()).bind() - val entitiesQuery = composeEntitiesQueryFromPostRequest( + val entitiesQuery = composeEntitiesQueryFromPost( applicationProperties.pagination, query, params, contexts ).bind() - .validateMinimalQueryEntitiesParameters().bind() val (entities, count) = entityQueryService.queryEntities(entitiesQuery, sub.getOrNull()).bind() diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/model/TemporalEntitiesQuery.kt b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/model/TemporalEntitiesQuery.kt index 432da96bc0..1fad824f4b 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/model/TemporalEntitiesQuery.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/model/TemporalEntitiesQuery.kt @@ -1,31 +1,55 @@ package com.egm.stellio.search.temporal.model import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import java.time.Duration import java.time.Period import java.time.temporal.TemporalAmount -data class TemporalEntitiesQuery( - val entitiesQuery: EntitiesQuery, - val temporalQuery: TemporalQuery, - val withTemporalValues: Boolean, - val withAudit: Boolean, - val withAggregatedValues: Boolean +sealed class TemporalEntitiesQuery( + open val temporalQuery: TemporalQuery, + open val withTemporalValues: Boolean, + open val withAudit: Boolean, + open val withAggregatedValues: Boolean ) { fun isAggregatedWithDefinedDuration(): Boolean = withAggregatedValues && temporalQuery.aggrPeriodDuration != null && temporalQuery.aggrPeriodDuration != "PT0S" - fun computeAggrPeriodDuration(): TemporalAmount { - val splitted = temporalQuery.aggrPeriodDuration!!.split("T") - return if (splitted.size == 1) // has only date-based fields - Period.parse(temporalQuery.aggrPeriodDuration) - else { - val duration = Duration.parse("PT" + splitted[1]) - if ("P" == splitted[0]) // has only time-based fields - duration - else Period.parse(splitted[0]).plus(duration) - } - } + fun computeAggrPeriodDuration(): TemporalAmount = + temporalQuery.aggrPeriodDuration?.let { aggrPeriodDuration -> + val splitted = aggrPeriodDuration.split("T") + if (splitted.size == 1) // has only date-based fields + Period.parse(aggrPeriodDuration) + else { + val duration = Duration.parse("PT" + splitted[1]) + if ("P" == splitted[0]) // has only time-based fields + duration + else Period.parse(splitted[0]).plus(duration) + } + } ?: Period.ZERO + + abstract fun getEntitiesQuery(): EntitiesQuery +} + +data class TemporalEntitiesQueryFromGet( + val entitiesQueryFromGet: EntitiesQueryFromGet, + override val temporalQuery: TemporalQuery, + override val withTemporalValues: Boolean, + override val withAudit: Boolean, + override val withAggregatedValues: Boolean +) : TemporalEntitiesQuery(temporalQuery, withTemporalValues, withAudit, withAggregatedValues) { + override fun getEntitiesQuery(): EntitiesQuery = entitiesQueryFromGet +} + +data class TemporalEntitiesQueryFromPost( + val entitiesQueryFromPost: EntitiesQueryFromPost, + override val temporalQuery: TemporalQuery, + override val withTemporalValues: Boolean, + override val withAudit: Boolean, + override val withAggregatedValues: Boolean +) : TemporalEntitiesQuery(temporalQuery, withTemporalValues, withAudit, withAggregatedValues) { + override fun getEntitiesQuery(): EntitiesQuery = entitiesQueryFromPost } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryService.kt index 2371180c12..7d4192d97c 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryService.kt @@ -46,12 +46,12 @@ class TemporalQueryService( entityQueryService.checkEntityExistence(entityId).bind() authorizationService.userCanReadEntity(entityId, sub.toOption()).bind() - val attrs = temporalEntitiesQuery.entitiesQuery.attrs - val datasetIds = temporalEntitiesQuery.entitiesQuery.datasetId + val attrs = temporalEntitiesQuery.getEntitiesQuery().attrs + val datasetIds = temporalEntitiesQuery.getEntitiesQuery().datasetId val attributes = entityAttributeService.getForEntity(entityId, attrs, datasetIds).let { if (it.isEmpty()) ResourceNotFoundException( - entityOrAttrsNotFoundMessage(entityId.toString(), temporalEntitiesQuery.entitiesQuery.attrs) + entityOrAttrsNotFoundMessage(entityId.toString(), temporalEntitiesQuery.getEntitiesQuery().attrs) ).left() else it.right() }.bind() @@ -102,7 +102,7 @@ class TemporalQueryService( val originForAttributes = attributeInstanceService.selectOldestDate(temporalQuery, attributes) - val attrs = temporalEntitiesQuery.entitiesQuery.attrs + val attrs = temporalEntitiesQuery.getEntitiesQuery().attrs val originForScope = if (attrs.isEmpty() || attrs.contains(NGSILD_SCOPE_PROPERTY)) scopeService.selectOldestDate(entityId, temporalEntitiesQuery.temporalQuery.timeproperty) @@ -121,9 +121,9 @@ class TemporalQueryService( sub: Sub? = null ): Either, 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) + val attrs = temporalEntitiesQuery.getEntitiesQuery().attrs + val entitiesIds = entityQueryService.queryEntities(temporalEntitiesQuery.getEntitiesQuery(), accessRightFilter) + val count = entityQueryService.queryEntitiesCount(temporalEntitiesQuery.getEntitiesQuery(), accessRightFilter) .getOrElse { 0 } // we can have an empty list of entities with a non-zero count (e.g., offset too high) @@ -132,7 +132,7 @@ class TemporalQueryService( val attributes = entityAttributeService.getForEntities( entitiesIds, - temporalEntitiesQuery.entitiesQuery + temporalEntitiesQuery.getEntitiesQuery() ) val scopesHistory = diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtils.kt b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtils.kt index 05ea26e520..46d1b10b43 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtils.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtils.kt @@ -7,11 +7,13 @@ import arrow.core.left import arrow.core.raise.either import arrow.core.right import com.egm.stellio.search.common.model.Query -import com.egm.stellio.search.entity.util.composeEntitiesQuery -import com.egm.stellio.search.entity.util.composeEntitiesQueryFromPostRequest +import com.egm.stellio.search.entity.util.composeEntitiesQueryFromGet +import com.egm.stellio.search.entity.util.composeEntitiesQueryFromPost import com.egm.stellio.search.entity.util.validateMinimalQueryEntitiesParameters import com.egm.stellio.search.temporal.model.AttributeInstance import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromPost import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.search.temporal.model.TemporalQuery.Aggregate import com.egm.stellio.search.temporal.model.TemporalQuery.Timerel @@ -25,22 +27,22 @@ import com.egm.stellio.shared.util.parseTimeParameter import org.springframework.util.MultiValueMap import org.springframework.util.MultiValueMapAdapter import java.time.ZonedDateTime -import java.util.* +import java.util.Optional -fun composeTemporalEntitiesQuery( +fun composeTemporalEntitiesQueryFromGet( defaultPagination: ApplicationProperties.Pagination, requestParams: MultiValueMap, contexts: List, inQueryEntities: Boolean = false -): Either = either { - val entitiesQuery = composeEntitiesQuery( +): Either = either { + val entitiesQueryFromGet = composeEntitiesQueryFromGet( defaultPagination, requestParams, contexts ).bind() if (inQueryEntities) - entitiesQuery.validateMinimalQueryEntitiesParameters().bind() + entitiesQueryFromGet.validateMinimalQueryEntitiesParameters().bind() val withTemporalValues = hasValueInOptionsParam( Optional.ofNullable(requestParams.getFirst(QUERY_PARAM_OPTIONS)), @@ -57,8 +59,8 @@ fun composeTemporalEntitiesQuery( val temporalQuery = buildTemporalQuery(requestParams, defaultPagination, inQueryEntities, withAggregatedValues).bind() - TemporalEntitiesQuery( - entitiesQuery = entitiesQuery, + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = entitiesQueryFromGet, temporalQuery = temporalQuery, withTemporalValues = withTemporalValues, withAudit = withAudit, @@ -66,19 +68,18 @@ fun composeTemporalEntitiesQuery( ) } -fun composeTemporalEntitiesQueryFromPostRequest( +fun composeTemporalEntitiesQueryFromPost( defaultPagination: ApplicationProperties.Pagination, query: Query, requestParams: MultiValueMap, contexts: List ): Either = either { - val entitiesQuery = composeEntitiesQueryFromPostRequest( + val entitiesQueryFromPost = composeEntitiesQueryFromPost( defaultPagination, query, requestParams, contexts ).bind() - .validateMinimalQueryEntitiesParameters().bind() val withTemporalValues = hasValueInOptionsParam( Optional.ofNullable(requestParams.getFirst(QUERY_PARAM_OPTIONS)), @@ -109,8 +110,8 @@ fun composeTemporalEntitiesQueryFromPostRequest( withAggregatedValues ).bind() - TemporalEntitiesQuery( - entitiesQuery = entitiesQuery, + TemporalEntitiesQueryFromPost( + entitiesQueryFromPost = entitiesQueryFromPost, temporalQuery = temporalQuery, withTemporalValues = withTemporalValues, withAudit = withAudit, diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalApiResponses.kt b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalApiResponses.kt index 4fc12e7493..6038852dda 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalApiResponses.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalApiResponses.kt @@ -39,7 +39,7 @@ object TemporalApiResponses { entities.toFinalRepresentation(representation), total, resourceUrl, - query.entitiesQuery.paginationQuery, + query.getEntitiesQuery().paginationQuery, requestParams, mediaType, contexts diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandler.kt index 747e57ff4b..a885853579 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandler.kt @@ -7,7 +7,7 @@ import arrow.core.right import com.egm.stellio.search.entity.service.EntityService import com.egm.stellio.search.temporal.service.TemporalQueryService import com.egm.stellio.search.temporal.service.TemporalService -import com.egm.stellio.search.temporal.util.composeTemporalEntitiesQuery +import com.egm.stellio.search.temporal.util.composeTemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.web.TemporalApiResponses.buildEntitiesTemporalResponse import com.egm.stellio.search.temporal.web.TemporalApiResponses.buildEntityTemporalResponse import com.egm.stellio.shared.config.ApplicationProperties @@ -141,7 +141,7 @@ class TemporalEntityHandler( val mediaType = getApplicableMediaType(httpHeaders).bind() val temporalEntitiesQuery = - composeTemporalEntitiesQuery(applicationProperties.pagination, params, contexts, true).bind() + composeTemporalEntitiesQueryFromGet(applicationProperties.pagination, params, contexts, true).bind() val (temporalEntities, total, range) = temporalQueryService.queryTemporalEntities( temporalEntitiesQuery, @@ -179,7 +179,7 @@ class TemporalEntityHandler( val mediaType = getApplicableMediaType(httpHeaders).bind() val temporalEntitiesQuery = - composeTemporalEntitiesQuery(applicationProperties.pagination, params, contexts).bind() + composeTemporalEntitiesQueryFromGet(applicationProperties.pagination, params, contexts).bind() val (temporalEntity, range) = temporalQueryService.queryTemporalEntity( entityId, diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandler.kt b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandler.kt index ea0cb51053..40a37bcc84 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandler.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandler.kt @@ -3,7 +3,7 @@ package com.egm.stellio.search.temporal.web import arrow.core.raise.either import com.egm.stellio.search.common.model.Query import com.egm.stellio.search.temporal.service.TemporalQueryService -import com.egm.stellio.search.temporal.util.composeTemporalEntitiesQueryFromPostRequest +import com.egm.stellio.search.temporal.util.composeTemporalEntitiesQueryFromPost import com.egm.stellio.search.temporal.web.TemporalApiResponses.buildEntitiesTemporalResponse import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.util.JSON_LD_CONTENT_TYPE @@ -47,7 +47,7 @@ class TemporalEntityOperationsHandler( val query = Query(requestBody.awaitFirst()).bind() val temporalEntitiesQuery = - composeTemporalEntitiesQueryFromPostRequest( + composeTemporalEntitiesQueryFromPost( applicationProperties.pagination, query, params, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/AuthorizationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/AuthorizationServiceTests.kt index febd20e8fd..f434cdf06e 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/AuthorizationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/AuthorizationServiceTests.kt @@ -1,7 +1,7 @@ package com.egm.stellio.search.authorization.service import arrow.core.None -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.AUTHZ_TEST_COMPOUND_CONTEXTS @@ -36,7 +36,7 @@ class AuthorizationServiceTests { @Test fun `get authorized entities should return a count of -1 if authentication is not enabled`() = runTest { authorizationService.getAuthorizedEntities( - EntitiesQuery( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 0, offset = 0), contexts = listOf(applicationProperties.contexts.core) ), diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationServiceTests.kt index 5a11530cad..859e649955 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/authorization/service/EnabledAuthorizationServiceTests.kt @@ -7,7 +7,7 @@ import com.egm.stellio.search.authorization.model.EntityAccessRights import com.egm.stellio.search.authorization.model.EntityAccessRights.SubjectRightInfo import com.egm.stellio.search.authorization.model.Group import com.egm.stellio.search.authorization.model.User -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.shared.model.AccessDeniedException import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXTS @@ -363,7 +363,7 @@ class EnabledAuthorizationServiceTests { } returns emptyMap>>().right() enabledAuthorizationService.getAuthorizedEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 10, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -419,7 +419,7 @@ class EnabledAuthorizationServiceTests { ).right() enabledAuthorizationService.getAuthorizedEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 10, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -471,7 +471,7 @@ class EnabledAuthorizationServiceTests { ).right() enabledAuthorizationService.getAuthorizedEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 10, offset = 0), contexts = APIC_COMPOUND_CONTEXTS diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/entity/service/EntityServiceQueriesTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/entity/service/EntityServiceQueriesTests.kt index 8d69552f64..062a717c7e 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/entity/service/EntityServiceQueriesTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/entity/service/EntityServiceQueriesTests.kt @@ -2,11 +2,13 @@ package com.egm.stellio.search.entity.service import arrow.core.right import com.egm.stellio.search.authorization.service.AuthorizationService -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import com.egm.stellio.search.entity.model.Entity import com.egm.stellio.search.support.WithKafkaContainer import com.egm.stellio.search.support.WithTimescaleContainer import com.egm.stellio.search.temporal.service.AttributeInstanceService +import com.egm.stellio.shared.model.EntitySelector import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.util.APIARY_TYPE @@ -123,7 +125,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { ) = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = types, paginationQuery = PaginationQuery(limit = 30, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -151,7 +153,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { ) = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, scopeQ = scopeQ, paginationQuery = PaginationQuery(limit = 30, offset = 0), @@ -168,7 +170,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should retrieve entities according to ids and a type`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( ids = setOf(entity02Uri), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 2, offset = 0), @@ -184,7 +186,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should retrieve entities according to ids and a selection of types`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( ids = setOf(entity02Uri, entity05Uri), typeSelection = "$APIARY_TYPE|$BEEHIVE_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 0), @@ -200,7 +202,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should retrieve entities according to attrs and types`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 2, offset = 0), attrs = setOf(NGSILD_NAME_PROPERTY), @@ -216,7 +218,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should retrieve entities by a list of ids`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( ids = setOf(entity02Uri), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 1, offset = 0), @@ -232,7 +234,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should retrieve entities with respect to limit and offset`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 1, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -246,7 +248,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should retrieve entities with respect to idPattern`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, idPattern = ".*urn:ngsi-ld:BeeHive:01.*", paginationQuery = PaginationQuery(limit = 1, offset = 0), @@ -310,7 +312,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { ) = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( q = q, paginationQuery = PaginationQuery(limit = 2, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -343,7 +345,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { ) = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 2, offset = 0), geoQuery = GeoQuery( georel = georel, @@ -361,11 +363,98 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { assertEquals(expectedCount, entitiesIds.size) } + @Test + fun `it should retrieve entities according to one entity selector`() = runTest { + val entitiesIds = + entityQueryService.queryEntities( + EntitiesQueryFromPost( + entitySelectors = listOf( + EntitySelector(id = null, idPattern = null, typeSelection = BEEHIVE_TYPE) + ), + paginationQuery = PaginationQuery(limit = 30, offset = 0), + contexts = APIC_COMPOUND_CONTEXTS + ) + ) { null } + + assertThat(entitiesIds) + .hasSize(2) + .contains(entity01Uri, entity02Uri) + } + + @Test + fun `it should retrieve entities according to two entity selectors with type and idPattern`() = runTest { + val entitiesIds = + entityQueryService.queryEntities( + EntitiesQueryFromPost( + entitySelectors = listOf( + EntitySelector(id = null, idPattern = null, typeSelection = BEEHIVE_TYPE), + EntitySelector( + id = null, + idPattern = "urn:ngsi-ld:Beekeeper:*", + typeSelection = BEEKEEPER_TYPE + ) + ), + paginationQuery = PaginationQuery(limit = 30, offset = 0), + contexts = APIC_COMPOUND_CONTEXTS + ) + ) { null } + + assertThat(entitiesIds) + .hasSize(3) + .contains(entity01Uri, entity02Uri, entity04Uri) + } + + @Test + fun `it should retrieve entities according to two entity selectors with type and id`() = runTest { + val entitiesIds = + entityQueryService.queryEntities( + EntitiesQueryFromPost( + entitySelectors = listOf( + EntitySelector(id = null, idPattern = null, typeSelection = BEEHIVE_TYPE), + EntitySelector( + id = entity05Uri, + idPattern = null, + typeSelection = APIARY_TYPE + ) + ), + paginationQuery = PaginationQuery(limit = 30, offset = 0), + contexts = APIC_COMPOUND_CONTEXTS + ) + ) { null } + + assertThat(entitiesIds) + .hasSize(3) + .contains(entity01Uri, entity02Uri, entity05Uri) + } + + @Test + fun `it should retrieve entities according to two entity selectors with one not matching any entities`() = runTest { + val entitiesIds = + entityQueryService.queryEntities( + EntitiesQueryFromPost( + entitySelectors = listOf( + EntitySelector(id = null, idPattern = null, typeSelection = BEEHIVE_TYPE), + EntitySelector( + id = entity05Uri, + idPattern = null, + typeSelection = BEEKEEPER_TYPE + ) + ), + paginationQuery = PaginationQuery(limit = 30, offset = 0), + contexts = APIC_COMPOUND_CONTEXTS + ) + ) { null } + + assertThat(entitiesIds) + .hasSize(2) + .contains(entity01Uri, entity02Uri) + } + @Test fun `it should retrieve entities according to access rights`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -390,7 +479,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -417,7 +506,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -441,7 +530,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should retrieve the count of entities`() = runTest { entityQueryService.queryEntitiesCount( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), contexts = APIC_COMPOUND_CONTEXTS @@ -452,7 +541,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { @Test fun `it should retrieve the count of entities according to access rights`() = runTest { entityQueryService.queryEntitiesCount( - EntitiesQuery( + EntitiesQueryFromGet( ids = setOf(entity02Uri, entity01Uri), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 30, offset = 0), @@ -466,7 +555,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should return an empty list if no entity matches the requested type`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( ids = setOf(entity02Uri, entity01Uri), typeSelection = "https://ontology.eglobalmark.com/apic#UnknownType", paginationQuery = PaginationQuery(limit = 2, offset = 10), @@ -481,7 +570,7 @@ class EntityServiceQueriesTests : WithTimescaleContainer, WithKafkaContainer { fun `it should return an empty list if no entity matches the requested attributes`() = runTest { val entitiesIds = entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(limit = 2, offset = 10), attrs = setOf("unknownAttribute"), diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtilsTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtilsTests.kt index b91abec068..6ecda63876 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtilsTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/entity/util/EntitiesQueryUtilsTests.kt @@ -3,15 +3,17 @@ package com.egm.stellio.search.entity.util import arrow.core.Either import arrow.core.raise.either import com.egm.stellio.search.common.model.Query -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import com.egm.stellio.search.support.buildDefaultPagination import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.APIException import com.egm.stellio.shared.model.BadRequestDataException +import com.egm.stellio.shared.model.EntitySelector import com.egm.stellio.shared.model.GeoQuery import com.egm.stellio.shared.util.APIARY_TYPE import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXTS import com.egm.stellio.shared.util.BEEHIVE_TYPE +import com.egm.stellio.shared.util.BEEKEEPER_TYPE import com.egm.stellio.shared.util.GEO_QUERY_GEOREL_EQUALS import com.egm.stellio.shared.util.INCOMING_PROPERTY import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DEFAULT_VOCAB @@ -23,7 +25,9 @@ import com.egm.stellio.shared.util.shouldSucceedAndResult import com.egm.stellio.shared.util.shouldSucceedWith import com.egm.stellio.shared.util.toUri import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test import org.springframework.test.context.ActiveProfiles import org.springframework.util.LinkedMultiValueMap @@ -36,7 +40,7 @@ class EntitiesQueryUtilsTests { @Test fun `it should parse query parameters`() = runTest { val requestParams = gimmeEntitiesQueryParams() - val entitiesQuery = composeEntitiesQuery( + val entitiesQuery = composeEntitiesQueryFromGet( buildDefaultPagination(1, 20), requestParams, APIC_COMPOUND_CONTEXTS @@ -60,7 +64,7 @@ class EntitiesQueryUtilsTests { fun `it should decode q in query parameters`() = runTest { val requestParams = LinkedMultiValueMap() requestParams.add("q", "speed%3E50%3BfoodName%3D%3Ddietary+fibres") - val entitiesQuery = composeEntitiesQuery( + val entitiesQuery = composeEntitiesQueryFromGet( buildDefaultPagination(30, 100), requestParams, NGSILD_TEST_CORE_CONTEXTS @@ -72,7 +76,7 @@ class EntitiesQueryUtilsTests { @Test fun `it should set default values in query parameters`() = runTest { val requestParams = LinkedMultiValueMap() - val entitiesQuery = composeEntitiesQuery( + val entitiesQuery = composeEntitiesQueryFromGet( buildDefaultPagination(30, 100), requestParams, NGSILD_TEST_CORE_CONTEXTS @@ -105,7 +109,7 @@ class EntitiesQueryUtilsTests { } @Test - fun `it should parse a valid complete query`() = runTest { + fun `it should parse a valid complete Query datatype`() = runTest { val query = """ { "type": "Query", @@ -140,9 +144,12 @@ class EntitiesQueryUtilsTests { LinkedMultiValueMap(), APIC_COMPOUND_CONTEXTS ).shouldSucceedWith { - assertEquals(setOf("urn:ngsi-ld:BeeHive:TESTC".toUri()), it.ids) - assertEquals("urn:ngsi-ld:BeeHive:*", it.idPattern) - assertEquals(BEEHIVE_TYPE, it.typeSelection) + assertNotNull(it.entitySelectors) + assertEquals(1, it.entitySelectors!!.size) + val entitySelector = it.entitySelectors!![0] + assertEquals("urn:ngsi-ld:BeeHive:TESTC".toUri(), entitySelector.id) + assertEquals("urn:ngsi-ld:BeeHive:*", entitySelector.idPattern) + assertEquals(BEEHIVE_TYPE, entitySelector.typeSelection) assertEquals(setOf("${NGSILD_DEFAULT_VOCAB}attr1", "${NGSILD_DEFAULT_VOCAB}attr2"), it.attrs) assertEquals("temperature>32", it.q) assertEquals(GeoQuery.GeometryType.POINT, it.geoQuery?.geometry) @@ -155,7 +162,7 @@ class EntitiesQueryUtilsTests { } @Test - fun `it should parse a valid simple query`() = runTest { + fun `it should parse a valid simple Query datatype`() = runTest { val query = """ { "type": "Query", @@ -173,14 +180,57 @@ class EntitiesQueryUtilsTests { LinkedMultiValueMap(), APIC_COMPOUND_CONTEXTS ).shouldSucceedWith { - assertEquals(BEEHIVE_TYPE, it.typeSelection) + assertEquals(BEEHIVE_TYPE, it.entitySelectors!![0].typeSelection) assertEquals(setOf("${NGSILD_DEFAULT_VOCAB}attr1"), it.attrs) assertEquals("temperature>32", it.q) } } @Test - fun `it should not validate a query if the type is not correct`() { + fun `it should parse a Query datatype with more than one entity selectors`() = runTest { + val query = """ + { + "type": "Query", + "entities": [ + { + "idPattern": "urn:ngsi-ld:BeeHive:*", + "type": "BeeHive" + }, + { + "type": "Apiary" + }, + { + "id": "urn:ngsi-ld:Beekeeper:Jules", + "type": "Beekeeper" + } + ] + } + """.trimIndent() + + composeEntitiesQueryFromPostRequest( + buildDefaultPagination(30, 100), + query, + LinkedMultiValueMap(), + APIC_COMPOUND_CONTEXTS + ).shouldSucceedWith { + assertThat(it.entitySelectors) + .hasSize(3) + .containsAll( + listOf( + EntitySelector(id = null, idPattern = "urn:ngsi-ld:BeeHive:*", typeSelection = BEEHIVE_TYPE), + EntitySelector(id = null, idPattern = null, typeSelection = APIARY_TYPE), + EntitySelector( + id = "urn:ngsi-ld:Beekeeper:Jules".toUri(), + idPattern = null, + typeSelection = BEEKEEPER_TYPE + ) + ) + ) + } + } + + @Test + fun `it should not validate a Query if the type is not correct`() { val query = """ { "type": "NotAQuery", @@ -200,7 +250,7 @@ class EntitiesQueryUtilsTests { } @Test - fun `it should not validate a query if the payload could not be parsed because the JSON is invalid`() { + fun `it should not validate a Query if the payload could not be parsed because the JSON is invalid`() { val query = """ { "type": "Query",, @@ -220,7 +270,7 @@ class EntitiesQueryUtilsTests { } @Test - fun `it should not validate a query if the payload contains unexpected parameters`() { + fun `it should not validate a Query if the payload contains unexpected parameters`() { val query = """ { "type": "Query", @@ -239,14 +289,38 @@ class EntitiesQueryUtilsTests { } } + @Test + fun `it should not validate a Query if an entity selector has no type member`() { + val query = """ + { + "type": "Query", + "entities": [ + { + "idPattern": "urn:ngsi-ld:BeeHive:*" + } + ] + } + """.trimIndent() + + composeEntitiesQueryFromPostRequest( + buildDefaultPagination(30, 100), + query, + LinkedMultiValueMap(), + APIC_COMPOUND_CONTEXTS + ).shouldFailWith { + it is BadRequestDataException && + it.message.startsWith("The supplied query could not be parsed") + } + } + private fun composeEntitiesQueryFromPostRequest( defaultPagination: ApplicationProperties.Pagination, requestBody: String, requestParams: MultiValueMap, contexts: List - ): Either = either { + ): Either = either { val query = Query(requestBody).bind() - composeEntitiesQueryFromPostRequest( + composeEntitiesQueryFromPost( defaultPagination, query, requestParams, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityHandlerTests.kt index 17ffcd499c..cf5648e6cd 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityHandlerTests.kt @@ -3,7 +3,7 @@ package com.egm.stellio.search.entity.web import arrow.core.left import arrow.core.right import com.egm.stellio.search.common.config.SearchProperties -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.search.entity.model.NotUpdatedDetails import com.egm.stellio.search.entity.model.UpdateOperationResult import com.egm.stellio.search.entity.model.UpdateResult @@ -877,7 +877,7 @@ class EntityHandlerTests { fun `get entities by type should include temporal properties if optional query param sysAttrs is present`() { coEvery { entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = "https://uri.etsi.org/ngsi-ld/default-context/Beehive", paginationQuery = PaginationQuery(offset = 0, limit = 30), contexts = listOf(applicationProperties.contexts.core) @@ -1011,7 +1011,7 @@ class EntityHandlerTests { fun `get entities with id and type should return 200`() { coEvery { entityQueryService.queryEntities( - EntitiesQuery( + EntitiesQueryFromGet( ids = setOf(beehiveId), typeSelection = BEEHIVE_TYPE, paginationQuery = PaginationQuery(offset = 0, limit = 30), diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandlerTests.kt index 12cfcbe129..efebbdfc00 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/entity/web/EntityOperationHandlerTests.kt @@ -3,6 +3,7 @@ package com.egm.stellio.search.entity.web import arrow.core.right import com.egm.stellio.search.common.config.SearchProperties import com.egm.stellio.search.entity.model.EMPTY_UPDATE_RESULT +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import com.egm.stellio.search.entity.model.UpdateResult import com.egm.stellio.search.entity.service.EntityOperationService import com.egm.stellio.search.entity.service.EntityQueryService @@ -487,7 +488,8 @@ class EntityOperationHandlerTests { match { it.paginationQuery.limit == 10 && it.paginationQuery.offset == 20 && - it.typeSelection == BEEHIVE_TYPE && + it is EntitiesQueryFromPost && + it.entitySelectors!![0].typeSelection == BEEHIVE_TYPE && it.attrs == setOf("${NGSILD_DEFAULT_VOCAB}attr1", "${NGSILD_DEFAULT_VOCAB}attr2") }, any() diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt index 7b92fc2fb2..5a0300487e 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/scope/ScopeServiceTests.kt @@ -1,6 +1,6 @@ package com.egm.stellio.search.scope -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.search.entity.model.Entity import com.egm.stellio.search.entity.model.OperationType import com.egm.stellio.search.entity.service.EntityQueryService @@ -10,7 +10,7 @@ import com.egm.stellio.search.support.WithKafkaContainer import com.egm.stellio.search.support.WithTimescaleContainer import com.egm.stellio.search.support.buildDefaultTestTemporalQuery import com.egm.stellio.search.temporal.model.AttributeInstance.TemporalProperty -import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.model.getScopes @@ -153,8 +153,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { val scopeHistoryEntries = scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -179,8 +179,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { val scopeHistoryEntries = scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -209,8 +209,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { val scopeHistoryEntries = scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -243,8 +243,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { val scopeHistoryEntries = scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -278,8 +278,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { val scopeHistoryEntries = scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -310,8 +310,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { val scopeHistoryEntries = scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -359,8 +359,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -406,8 +406,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -446,8 +446,8 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { } val scopeHistoryEntries = scopeService.retrieveHistory( listOf(beehiveTestCId), - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 100, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt index 97798d43b0..3f2f4ba6b9 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/scope/TemporalScopeBuilderTests.kt @@ -4,7 +4,7 @@ import com.egm.stellio.search.support.buildDefaultQueryParams import com.egm.stellio.search.support.buildDefaultTestTemporalQuery import com.egm.stellio.search.support.gimmeEntityPayload import com.egm.stellio.search.temporal.model.AttributeInstance.TemporalProperty -import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.shared.util.JsonUtils import com.egm.stellio.shared.util.assertJsonPayloadsAreEqual @@ -70,8 +70,8 @@ class TemporalScopeBuilderTests { val scopeHistory = TemporalScopeBuilder.buildScopeAttributeInstances( entityPayload, scopeInstances, - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = temporalQuery, withTemporalValues = false, withAudit = false, @@ -108,8 +108,8 @@ class TemporalScopeBuilderTests { val scopeHistory = TemporalScopeBuilder.buildScopeAttributeInstances( entityPayload, scopeInstances, - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = temporalQuery, withTemporalValues = true, withAudit = false, @@ -148,8 +148,8 @@ class TemporalScopeBuilderTests { val scopeHistory = TemporalScopeBuilder.buildScopeAttributeInstances( entityPayload, scopeInstances, - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = temporalQuery, withTemporalValues = false, withAudit = false, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt index e85720e75a..091a669472 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/support/BusinessObjectsFactory.kt @@ -2,10 +2,10 @@ package com.egm.stellio.search.support import com.egm.stellio.search.entity.model.Attribute import com.egm.stellio.search.entity.model.AttributeMetadata -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.search.entity.model.Entity import com.egm.stellio.search.temporal.model.AttributeInstance -import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.shared.model.ExpandedTerm import com.egm.stellio.shared.model.PaginationQuery @@ -149,9 +149,9 @@ fun gimmeTemporalEntitiesQuery( withTemporalValues: Boolean = false, withAudit: Boolean = false, withAggregatedValues: Boolean = false -): TemporalEntitiesQuery = - TemporalEntitiesQuery( - entitiesQuery = EntitiesQuery( +): TemporalEntitiesQueryFromGet = + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 50, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ), @@ -161,8 +161,8 @@ fun gimmeTemporalEntitiesQuery( withAggregatedValues = withAggregatedValues ) -fun buildDefaultQueryParams(): EntitiesQuery = - EntitiesQuery( +fun buildDefaultQueryParams(): EntitiesQueryFromGet = + EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 50, offset = 0), contexts = APIC_COMPOUND_CONTEXTS ) diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/AggregatedTemporalQueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/AggregatedTemporalQueryServiceTests.kt index 9dc258a4b6..2233517a3e 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/AggregatedTemporalQueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/AggregatedTemporalQueryServiceTests.kt @@ -12,7 +12,7 @@ import com.egm.stellio.search.support.gimmeTemporalEntitiesQuery import com.egm.stellio.search.temporal.model.AggregatedAttributeInstanceResult import com.egm.stellio.search.temporal.model.AttributeInstance import com.egm.stellio.search.temporal.model.AttributeInstanceResult -import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.shared.model.OperationNotSupportedException import com.egm.stellio.shared.util.INCOMING_PROPERTY @@ -501,7 +501,7 @@ class AggregatedTemporalQueryServiceTests : WithTimescaleContainer, WithKafkaCon private fun createTemporalEntitiesQuery( aggrMethod: String, aggrPeriodDuration: String = "P1D" - ): TemporalEntitiesQuery = + ): TemporalEntitiesQueryFromGet = gimmeTemporalEntitiesQuery( buildDefaultTestTemporalQuery( timerel = TemporalQuery.Timerel.AFTER, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalPaginationServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalPaginationServiceTests.kt index f10964f3bd..09980e6316 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalPaginationServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalPaginationServiceTests.kt @@ -2,13 +2,14 @@ package com.egm.stellio.search.temporal.service import com.egm.stellio.search.common.config.SearchProperties import com.egm.stellio.search.entity.model.Attribute -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.search.support.EMPTY_JSON_PAYLOAD import com.egm.stellio.search.support.buildDefaultTestTemporalQuery import com.egm.stellio.search.temporal.model.AggregatedAttributeInstanceResult import com.egm.stellio.search.temporal.model.AttributeInstanceResult import com.egm.stellio.search.temporal.model.SimplifiedAttributeInstanceResult import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.search.temporal.service.TemporalPaginationService.getPaginatedAttributeWithInstancesAndRange import com.egm.stellio.search.temporal.util.AttributesWithInstances @@ -130,9 +131,9 @@ class TemporalPaginationServiceTests { ) ) - private fun getQuery(temporalQuery: TemporalQuery): TemporalEntitiesQuery = TemporalEntitiesQuery( + private fun getQuery(temporalQuery: TemporalQuery): TemporalEntitiesQuery = TemporalEntitiesQueryFromGet( temporalQuery = temporalQuery, - entitiesQuery = EntitiesQuery( + entitiesQueryFromGet = EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 0, offset = 50), attrs = setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), contexts = APIC_COMPOUND_CONTEXTS @@ -268,7 +269,7 @@ class TemporalPaginationServiceTests { @Test fun `range calculation with aggregatedValues`() = runTest { - val query = TemporalEntitiesQuery( + val query = TemporalEntitiesQueryFromGet( temporalQuery = buildDefaultTestTemporalQuery( instanceLimit = 2, timerel = TemporalQuery.Timerel.AFTER, @@ -276,7 +277,7 @@ class TemporalPaginationServiceTests { aggrMethods = listOf(TemporalQuery.Aggregate.SUM, TemporalQuery.Aggregate.AVG), aggrPeriodDuration = "P1M" ), - entitiesQuery = EntitiesQuery( + entitiesQueryFromGet = EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 0, offset = 50), attrs = setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), contexts = APIC_COMPOUND_CONTEXTS diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryServiceTests.kt index 39d1ace9e8..83fa7b7bdb 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/service/TemporalQueryServiceTests.kt @@ -5,7 +5,7 @@ import arrow.core.left import arrow.core.right import com.egm.stellio.search.authorization.service.AuthorizationService import com.egm.stellio.search.entity.model.Attribute -import com.egm.stellio.search.entity.model.EntitiesQuery +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.search.entity.service.EntityAttributeService import com.egm.stellio.search.entity.service.EntityQueryService import com.egm.stellio.search.scope.ScopeInstanceResult @@ -18,7 +18,7 @@ import com.egm.stellio.search.support.gimmeEntityPayload import com.egm.stellio.search.temporal.model.AttributeInstanceResult import com.egm.stellio.search.temporal.model.FullAttributeInstanceResult import com.egm.stellio.search.temporal.model.SimplifiedAttributeInstanceResult -import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.shared.model.PaginationQuery import com.egm.stellio.shared.model.ResourceNotFoundException @@ -88,8 +88,8 @@ class TemporalQueryServiceTests { temporalQueryService.queryTemporalEntity( entityUri, - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = buildDefaultTestTemporalQuery(), withTemporalValues = true, withAudit = false, @@ -131,12 +131,12 @@ class TemporalQueryServiceTests { temporalQueryService.queryTemporalEntity( entityUri, - TemporalEntitiesQuery( + TemporalEntitiesQueryFromGet( temporalQuery = buildDefaultTestTemporalQuery( timerel = TemporalQuery.Timerel.AFTER, timeAt = ZonedDateTime.parse("2019-10-17T07:31:39Z") ), - entitiesQuery = EntitiesQuery( + entitiesQueryFromGet = EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 0, offset = 50), contexts = APIC_COMPOUND_CONTEXTS ), @@ -167,9 +167,9 @@ class TemporalQueryServiceTests { fun `it should not return an oldest timestamp if not in an aggregattion query`() = runTest { val origin = temporalQueryService.calculateOldestTimestamp( entityUri, - TemporalEntitiesQuery( + TemporalEntitiesQueryFromGet( temporalQuery = buildDefaultTestTemporalQuery(), - entitiesQuery = EntitiesQuery( + entitiesQueryFromGet = EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 0, offset = 50), contexts = APIC_COMPOUND_CONTEXTS ), @@ -187,12 +187,12 @@ class TemporalQueryServiceTests { fun `it should return timeAt as the oldest timestamp if it is provided in the temporal query`() = runTest { val origin = temporalQueryService.calculateOldestTimestamp( entityUri, - TemporalEntitiesQuery( + TemporalEntitiesQueryFromGet( temporalQuery = buildDefaultTestTemporalQuery( timerel = TemporalQuery.Timerel.AFTER, timeAt = now ), - entitiesQuery = EntitiesQuery( + entitiesQueryFromGet = EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 0, offset = 50), contexts = APIC_COMPOUND_CONTEXTS ), @@ -218,9 +218,9 @@ class TemporalQueryServiceTests { val origin = temporalQueryService.calculateOldestTimestamp( entityUri, - TemporalEntitiesQuery( + TemporalEntitiesQueryFromGet( temporalQuery = buildDefaultTestTemporalQuery(), - entitiesQuery = EntitiesQuery( + entitiesQueryFromGet = EntitiesQueryFromGet( paginationQuery = PaginationQuery(limit = 0, offset = 50), contexts = APIC_COMPOUND_CONTEXTS ), @@ -265,8 +265,8 @@ class TemporalQueryServiceTests { ).right() temporalQueryService.queryTemporalEntities( - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), contexts = APIC_COMPOUND_CONTEXTS @@ -284,7 +284,7 @@ class TemporalQueryServiceTests { coVerify { entityAttributeService.getForEntities( listOf(entityUri), - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), contexts = APIC_COMPOUND_CONTEXTS @@ -300,7 +300,7 @@ class TemporalQueryServiceTests { any>() ) entityQueryService.queryEntitiesCount( - EntitiesQuery( + EntitiesQueryFromGet( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), contexts = APIC_COMPOUND_CONTEXTS @@ -334,8 +334,8 @@ class TemporalQueryServiceTests { coEvery { entityQueryService.queryEntitiesCount(any(), any()) } returns 1.right() temporalQueryService.queryTemporalEntities( - TemporalEntitiesQuery( - EntitiesQuery( + TemporalEntitiesQueryFromGet( + EntitiesQueryFromGet( typeSelection = "$BEEHIVE_TYPE,$APIARY_TYPE", paginationQuery = PaginationQuery(limit = 2, offset = 2), contexts = APIC_COMPOUND_CONTEXTS diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalEntityBuilderTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalEntityBuilderTests.kt index 8058d97c0f..b536284b5d 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalEntityBuilderTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalEntityBuilderTests.kt @@ -10,7 +10,7 @@ import com.egm.stellio.search.temporal.model.AggregatedAttributeInstanceResult import com.egm.stellio.search.temporal.model.AggregatedAttributeInstanceResult.AggregateResult import com.egm.stellio.search.temporal.model.AttributeInstanceResult import com.egm.stellio.search.temporal.model.EntityTemporalResult -import com.egm.stellio.search.temporal.model.TemporalEntitiesQuery +import com.egm.stellio.search.temporal.model.TemporalEntitiesQueryFromGet import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.shared.util.BEEHIVE_TYPE import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_PROPERTY @@ -53,8 +53,8 @@ class TemporalEntityBuilderTests { ) val temporalEntity = TemporalEntityBuilder.buildTemporalEntity( EntityTemporalResult(entity, emptyList(), attributeAndResultsMap), - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = buildDefaultTestTemporalQuery(), withTemporalValues = false, withAudit = false, @@ -86,8 +86,8 @@ class TemporalEntityBuilderTests { val temporalEntity = TemporalEntityBuilder.buildTemporalEntity( EntityTemporalResult(entity, scopeHistory, attributeAndResultsMap), - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = buildDefaultTestTemporalQuery(), withTemporalValues, withAudit, @@ -111,8 +111,8 @@ class TemporalEntityBuilderTests { ) { val temporalEntity = TemporalEntityBuilder.buildTemporalEntities( entityTemporalResults, - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = buildDefaultTestTemporalQuery(), withTemporalValues, withAudit, @@ -190,8 +190,8 @@ class TemporalEntityBuilderTests { val temporalEntity = TemporalEntityBuilder.buildTemporalEntity( EntityTemporalResult(entity, emptyList(), attributeAndResultsMap), - TemporalEntitiesQuery( - entitiesQuery = buildDefaultQueryParams(), + TemporalEntitiesQueryFromGet( + entitiesQueryFromGet = buildDefaultQueryParams(), temporalQuery = temporalQuery, withTemporalValues = false, withAudit = false, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtilsTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtilsTests.kt index 76e68a8cf1..34ecaca63f 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtilsTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/util/TemporalQueryUtilsTests.kt @@ -1,11 +1,15 @@ package com.egm.stellio.search.temporal.util +import com.egm.stellio.search.common.model.Query +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import com.egm.stellio.search.support.buildDefaultPagination import com.egm.stellio.search.support.buildDefaultTestTemporalQuery import com.egm.stellio.search.temporal.model.AttributeInstance import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.shared.config.ApplicationProperties import com.egm.stellio.shared.model.BadRequestDataException +import com.egm.stellio.shared.model.EntitySelector import com.egm.stellio.shared.util.APIARY_TYPE import com.egm.stellio.shared.util.APIC_COMPOUND_CONTEXTS import com.egm.stellio.shared.util.BEEHIVE_TYPE @@ -13,10 +17,12 @@ import com.egm.stellio.shared.util.INCOMING_PROPERTY import com.egm.stellio.shared.util.OUTGOING_PROPERTY import com.egm.stellio.shared.util.shouldFail import com.egm.stellio.shared.util.shouldSucceedAndResult +import com.egm.stellio.shared.util.shouldSucceedWith import com.egm.stellio.shared.util.toUri import io.mockk.every import io.mockk.mockkClass import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertInstanceOf @@ -38,7 +44,7 @@ class TemporalQueryUtilsTests { every { pagination.limitDefault } returns 30 every { pagination.limitMax } returns 100 - composeTemporalEntitiesQuery( + composeTemporalEntitiesQueryFromGet( pagination, queryParams, APIC_COMPOUND_CONTEXTS, @@ -58,7 +64,7 @@ class TemporalQueryUtilsTests { every { pagination.limitDefault } returns 30 every { pagination.limitMax } returns 100 - composeTemporalEntitiesQuery( + composeTemporalEntitiesQueryFromGet( pagination, queryParams, APIC_COMPOUND_CONTEXTS @@ -77,7 +83,7 @@ class TemporalQueryUtilsTests { every { pagination.limitDefault } returns 30 every { pagination.limitMax } returns 100 - composeTemporalEntitiesQuery( + composeTemporalEntitiesQueryFromGet( pagination, queryParams, APIC_COMPOUND_CONTEXTS, @@ -98,14 +104,18 @@ class TemporalQueryUtilsTests { every { pagination.temporalLimit } returns 100 val temporalEntitiesQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() + composeTemporalEntitiesQueryFromGet(pagination, queryParams, APIC_COMPOUND_CONTEXTS) + .shouldSucceedAndResult() assertEquals( setOf("urn:ngsi-ld:BeeHive:TESTC".toUri(), "urn:ngsi-ld:BeeHive:TESTB".toUri()), - temporalEntitiesQuery.entitiesQuery.ids + (temporalEntitiesQuery.getEntitiesQuery() as EntitiesQueryFromGet).ids ) - assertEquals("$BEEHIVE_TYPE,$APIARY_TYPE", temporalEntitiesQuery.entitiesQuery.typeSelection) - assertEquals(setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), temporalEntitiesQuery.entitiesQuery.attrs) + assertEquals( + "$BEEHIVE_TYPE,$APIARY_TYPE", + (temporalEntitiesQuery.getEntitiesQuery() as EntitiesQueryFromGet).typeSelection + ) + assertEquals(setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), temporalEntitiesQuery.getEntitiesQuery().attrs) assertEquals( buildDefaultTestTemporalQuery( timerel = TemporalQuery.Timerel.BETWEEN, @@ -116,9 +126,9 @@ class TemporalQueryUtilsTests { ) assertTrue(temporalEntitiesQuery.withTemporalValues) assertFalse(temporalEntitiesQuery.withAudit) - assertEquals(10, temporalEntitiesQuery.entitiesQuery.paginationQuery.limit) - assertEquals(2, temporalEntitiesQuery.entitiesQuery.paginationQuery.offset) - assertEquals(true, temporalEntitiesQuery.entitiesQuery.paginationQuery.count) + assertEquals(10, temporalEntitiesQuery.getEntitiesQuery().paginationQuery.limit) + assertEquals(2, temporalEntitiesQuery.getEntitiesQuery().paginationQuery.offset) + assertEquals(true, temporalEntitiesQuery.getEntitiesQuery().paginationQuery.count) } @Test @@ -132,7 +142,8 @@ class TemporalQueryUtilsTests { every { pagination.temporalLimit } returns 1000 val temporalEntitiesQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() + composeTemporalEntitiesQueryFromGet(pagination, queryParams, APIC_COMPOUND_CONTEXTS) + .shouldSucceedAndResult() assertTrue(temporalEntitiesQuery.withAudit) } @@ -166,10 +177,11 @@ class TemporalQueryUtilsTests { queryParams.add("attrs", "outgoing") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() + composeTemporalEntitiesQueryFromGet(pagination, queryParams, APIC_COMPOUND_CONTEXTS) + .shouldSucceedAndResult() - assertEquals(1, temporalQuery.entitiesQuery.attrs.size) - assertTrue(temporalQuery.entitiesQuery.attrs.contains(OUTGOING_PROPERTY)) + assertEquals(1, temporalQuery.getEntitiesQuery().attrs.size) + assertTrue(temporalQuery.getEntitiesQuery().attrs.contains(OUTGOING_PROPERTY)) } @Test @@ -185,10 +197,11 @@ class TemporalQueryUtilsTests { queryParams.add("attrs", "incoming,outgoing") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() + composeTemporalEntitiesQueryFromGet(pagination, queryParams, APIC_COMPOUND_CONTEXTS) + .shouldSucceedAndResult() - assertEquals(2, temporalQuery.entitiesQuery.attrs.size) - assertIterableEquals(setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), temporalQuery.entitiesQuery.attrs) + assertEquals(2, temporalQuery.getEntitiesQuery().attrs.size) + assertIterableEquals(setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY), temporalQuery.getEntitiesQuery().attrs) } @Test @@ -203,8 +216,9 @@ class TemporalQueryUtilsTests { queryParams.add("timeAt", "2019-10-17T07:31:39Z") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() - assertTrue(temporalQuery.entitiesQuery.attrs.isEmpty()) + composeTemporalEntitiesQueryFromGet(pagination, queryParams, APIC_COMPOUND_CONTEXTS) + .shouldSucceedAndResult() + assertTrue(temporalQuery.getEntitiesQuery().attrs.isEmpty()) } @Test @@ -289,9 +303,10 @@ class TemporalQueryUtilsTests { queryParams.add("datasetId", "urn:ngsi-ld:Dataset:Test1") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() - assertEquals(1, temporalQuery.entitiesQuery.datasetId.size) - assertEquals("urn:ngsi-ld:Dataset:Test1", temporalQuery.entitiesQuery.datasetId.first()) + composeTemporalEntitiesQueryFromGet(pagination, queryParams, APIC_COMPOUND_CONTEXTS) + .shouldSucceedAndResult() + assertEquals(1, temporalQuery.getEntitiesQuery().datasetId.size) + assertEquals("urn:ngsi-ld:Dataset:Test1", temporalQuery.getEntitiesQuery().datasetId.first()) } @Test @@ -307,11 +322,52 @@ class TemporalQueryUtilsTests { queryParams.add("datasetId", "urn:ngsi-ld:Dataset:Test1,urn:ngsi-ld:Dataset:Test2") val temporalQuery = - composeTemporalEntitiesQuery(pagination, queryParams, APIC_COMPOUND_CONTEXTS).shouldSucceedAndResult() - assertEquals(2, temporalQuery.entitiesQuery.datasetId.size) + composeTemporalEntitiesQueryFromGet(pagination, queryParams, APIC_COMPOUND_CONTEXTS) + .shouldSucceedAndResult() + assertEquals(2, temporalQuery.getEntitiesQuery().datasetId.size) assertIterableEquals( setOf("urn:ngsi-ld:Dataset:Test1", "urn:ngsi-ld:Dataset:Test2"), - temporalQuery.entitiesQuery.datasetId + temporalQuery.getEntitiesQuery().datasetId ) } + + @Test + fun `it should parse a Query datatype with a TemporalQuery`() = runTest { + val query = """ + { + "type": "Query", + "entities": [{ + "type": "BeeHive" + }], + "attrs": ["attr1"], + "temporalQ": { + "timerel": "between", + "timeAt": "2024-11-07T07:31:39Z", + "endTimeAt": "2024-11-12T07:31:39Z", + "timeproperty": "modifiedAt" + } + } + """.trimIndent() + + composeTemporalEntitiesQueryFromPost( + buildDefaultPagination(30, 100), + Query(query).shouldSucceedAndResult(), + LinkedMultiValueMap(), + APIC_COMPOUND_CONTEXTS + ).shouldSucceedWith { + assertThat((it.getEntitiesQuery() as EntitiesQueryFromPost).entitySelectors) + .hasSize(1) + .contains(EntitySelector(id = null, idPattern = null, typeSelection = BEEHIVE_TYPE)) + assertThat(it.temporalQuery) + .isEqualTo( + TemporalQuery( + timerel = TemporalQuery.Timerel.BETWEEN, + timeAt = ZonedDateTime.parse("2024-11-07T07:31:39Z"), + endTimeAt = ZonedDateTime.parse("2024-11-12T07:31:39Z"), + timeproperty = AttributeInstance.TemporalProperty.MODIFIED_AT, + instanceLimit = 100 + ) + ) + } + } } diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandlerTests.kt index e4e578b3cf..ef177404e1 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityHandlerTests.kt @@ -4,6 +4,7 @@ import arrow.core.Either import arrow.core.left import arrow.core.right import com.egm.stellio.search.common.config.SearchProperties +import com.egm.stellio.search.entity.model.EntitiesQueryFromGet import com.egm.stellio.search.support.buildDefaultTestTemporalQuery import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.search.temporal.service.TemporalService.CreateOrUpdateResult @@ -596,10 +597,11 @@ class TemporalEntityHandlerTests : TemporalEntityHandlerTestCommon() { coVerify { temporalQueryService.queryTemporalEntities( match { temporalEntitiesQuery -> - temporalEntitiesQuery.entitiesQuery.paginationQuery.limit == 30 && - temporalEntitiesQuery.entitiesQuery.paginationQuery.offset == 0 && - temporalEntitiesQuery.entitiesQuery.ids.isEmpty() && - temporalEntitiesQuery.entitiesQuery.typeSelection == BEEHIVE_TYPE && + val entitiesQueryFromGet = temporalEntitiesQuery.getEntitiesQuery() as EntitiesQueryFromGet + temporalEntitiesQuery.getEntitiesQuery().paginationQuery.limit == 30 && + temporalEntitiesQuery.getEntitiesQuery().paginationQuery.offset == 0 && + entitiesQueryFromGet.ids.isEmpty() && + entitiesQueryFromGet.typeSelection == BEEHIVE_TYPE && temporalEntitiesQuery.temporalQuery == temporalQuery && !temporalEntitiesQuery.withTemporalValues }, diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandlerTests.kt index 861c8cf039..d0c1dbf9de 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/temporal/web/TemporalEntityOperationsHandlerTests.kt @@ -2,6 +2,7 @@ package com.egm.stellio.search.temporal.web import arrow.core.Either import com.egm.stellio.search.common.config.SearchProperties +import com.egm.stellio.search.entity.model.EntitiesQueryFromPost import com.egm.stellio.search.support.buildDefaultTestTemporalQuery import com.egm.stellio.search.temporal.model.TemporalQuery import com.egm.stellio.search.temporal.service.TemporalQueryService @@ -91,11 +92,13 @@ class TemporalEntityOperationsHandlerTests { coVerify { temporalQueryService.queryTemporalEntities( match { temporalEntitiesQuery -> - temporalEntitiesQuery.entitiesQuery.paginationQuery.limit == 30 && - temporalEntitiesQuery.entitiesQuery.paginationQuery.offset == 0 && - temporalEntitiesQuery.entitiesQuery.ids.isEmpty() && - temporalEntitiesQuery.entitiesQuery.typeSelection == "$BEEHIVE_TYPE,$APIARY_TYPE" && - temporalEntitiesQuery.entitiesQuery.attrs == setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY) && + val entitiesQueryFromPost = temporalEntitiesQuery.getEntitiesQuery() as EntitiesQueryFromPost + temporalEntitiesQuery.getEntitiesQuery().paginationQuery.limit == 30 && + temporalEntitiesQuery.getEntitiesQuery().paginationQuery.offset == 0 && + entitiesQueryFromPost.entitySelectors!!.size == 1 && + entitiesQueryFromPost.entitySelectors!![0].id == null && + entitiesQueryFromPost.entitySelectors!![0].typeSelection == "$BEEHIVE_TYPE,$APIARY_TYPE" && + temporalEntitiesQuery.getEntitiesQuery().attrs == setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY) && temporalEntitiesQuery.temporalQuery == temporalQuery && temporalEntitiesQuery.withTemporalValues }, @@ -142,12 +145,14 @@ class TemporalEntityOperationsHandlerTests { coVerify { temporalQueryService.queryTemporalEntities( match { temporalEntitiesQuery -> - temporalEntitiesQuery.entitiesQuery.paginationQuery.limit == 30 && - temporalEntitiesQuery.entitiesQuery.paginationQuery.offset == 0 && - temporalEntitiesQuery.entitiesQuery.ids.isEmpty() && - temporalEntitiesQuery.entitiesQuery.typeSelection == "$BEEHIVE_TYPE,$APIARY_TYPE" && - temporalEntitiesQuery.entitiesQuery.attrs == setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY) && - temporalEntitiesQuery.entitiesQuery.paginationQuery.count && + val entitiesQueryFromPost = temporalEntitiesQuery.getEntitiesQuery() as EntitiesQueryFromPost + temporalEntitiesQuery.getEntitiesQuery().paginationQuery.limit == 30 && + temporalEntitiesQuery.getEntitiesQuery().paginationQuery.offset == 0 && + entitiesQueryFromPost.entitySelectors!!.size == 1 && + entitiesQueryFromPost.entitySelectors!![0].id == null && + entitiesQueryFromPost.entitySelectors!![0].typeSelection == "$BEEHIVE_TYPE,$APIARY_TYPE" && + temporalEntitiesQuery.getEntitiesQuery().attrs == setOf(INCOMING_PROPERTY, OUTGOING_PROPERTY) && + temporalEntitiesQuery.getEntitiesQuery().paginationQuery.count && temporalEntitiesQuery.temporalQuery == temporalQuery && temporalEntitiesQuery.withTemporalValues },