diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt index d876dfc9d..15a76be1e 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/scope/ScopeService.kt @@ -102,9 +102,9 @@ class ScopeService( when (temporalQuery.timerel) { TemporalQuery.Timerel.BEFORE -> sqlQueryBuilder.append(" AND time < '${temporalQuery.timeAt}'") - TemporalQuery.Timerel.AFTER -> sqlQueryBuilder.append(" AND time > '${temporalQuery.timeAt}'") + TemporalQuery.Timerel.AFTER -> sqlQueryBuilder.append(" AND time >= '${temporalQuery.timeAt}'") TemporalQuery.Timerel.BETWEEN -> sqlQueryBuilder.append( - " AND time > '${temporalQuery.timeAt}' AND time < '${temporalQuery.endTimeAt}'" + " AND time >= '${temporalQuery.timeAt}' AND time < '${temporalQuery.endTimeAt}'" ) null -> Unit } diff --git a/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt b/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt index e887e0f3b..2997bbe79 100644 --- a/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt +++ b/search-service/src/main/kotlin/com/egm/stellio/search/service/AttributeInstanceService.kt @@ -150,9 +150,9 @@ class AttributeInstanceService( when (temporalQuery.timerel) { Timerel.BEFORE -> sqlQueryBuilder.append(" AND time < '${temporalQuery.timeAt}'") - Timerel.AFTER -> sqlQueryBuilder.append(" AND time > '${temporalQuery.timeAt}'") + Timerel.AFTER -> sqlQueryBuilder.append(" AND time >= '${temporalQuery.timeAt}'") Timerel.BETWEEN -> sqlQueryBuilder.append( - " AND time > '${temporalQuery.timeAt}' AND time < '${temporalQuery.endTimeAt}'" + " AND time >= '${temporalQuery.timeAt}' AND time < '${temporalQuery.endTimeAt}'" ) null -> Unit } 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 11cfd976b..f652bbb1c 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 @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.r2dbc.core.R2dbcEntityTemplate import org.springframework.test.context.ActiveProfiles +import java.time.ZonedDateTime import java.util.stream.Stream @SpringBootTest @@ -320,6 +321,98 @@ class ScopeServiceTests : WithTimescaleContainer, WithKafkaContainer { } } + @Test + fun `it should include lower bound of interval with after timerel`() = runTest { + loadSampleData("beehive_with_scope.jsonld") + .sampleDataToNgsiLdEntity() + .map { entityPayloadService.createEntityPayload(it.second, it.first, ngsiLdDateTime()) } + scopeService.addHistoryEntry( + beehiveTestCId, + listOf("/A", "/B/C"), + TemporalProperty.MODIFIED_AT, + ZonedDateTime.parse("2024-08-13T00:00:00Z") + ).shouldSucceed() + scopeService.addHistoryEntry( + beehiveTestCId, + listOf("/B/C"), + TemporalProperty.MODIFIED_AT, + ZonedDateTime.parse("2024-08-14T00:00:00Z") + ).shouldSucceed() + + scopeService.retrieveHistory( + listOf(beehiveTestCId), + TemporalEntitiesQuery( + EntitiesQuery( + paginationQuery = PaginationQuery(limit = 100, offset = 0), + contexts = APIC_COMPOUND_CONTEXTS + ), + buildDefaultTestTemporalQuery( + timeproperty = TemporalProperty.MODIFIED_AT, + timerel = TemporalQuery.Timerel.AFTER, + timeAt = ZonedDateTime.parse("2024-08-13T00:00:00Z"), + instanceLimit = 5 + ), + withTemporalValues = false, + withAudit = false, + withAggregatedValues = false + ), + ngsiLdDateTime().minusHours(1) + ).shouldSucceedWith { + assertEquals(2, it.size) + } + } + + @Test + fun `it should exclude upper bound of interval with between timerel`() = runTest { + loadSampleData("beehive_with_scope.jsonld") + .sampleDataToNgsiLdEntity() + .map { entityPayloadService.createEntityPayload(it.second, it.first, ngsiLdDateTime()) } + scopeService.addHistoryEntry( + beehiveTestCId, + listOf("/A", "/B/C"), + TemporalProperty.MODIFIED_AT, + ZonedDateTime.parse("2024-08-13T00:00:00Z") + ).shouldSucceed() + scopeService.addHistoryEntry( + beehiveTestCId, + listOf("/B/C"), + TemporalProperty.MODIFIED_AT, + ZonedDateTime.parse("2024-08-14T00:00:00Z") + ).shouldSucceed() + scopeService.addHistoryEntry( + beehiveTestCId, + listOf("/C/D"), + TemporalProperty.MODIFIED_AT, + ZonedDateTime.parse("2024-08-15T00:00:00Z") + ).shouldSucceed() + + scopeService.retrieveHistory( + listOf(beehiveTestCId), + TemporalEntitiesQuery( + EntitiesQuery( + paginationQuery = PaginationQuery(limit = 100, offset = 0), + contexts = APIC_COMPOUND_CONTEXTS + ), + buildDefaultTestTemporalQuery( + timeproperty = TemporalProperty.MODIFIED_AT, + timerel = TemporalQuery.Timerel.BETWEEN, + timeAt = ZonedDateTime.parse("2024-08-13T00:00:00Z"), + endTimeAt = ZonedDateTime.parse("2024-08-15T00:00:00Z"), + instanceLimit = 5 + ), + withTemporalValues = false, + withAudit = false, + withAggregatedValues = false + ), + ngsiLdDateTime().minusHours(1) + ).shouldSucceedWith { + assertEquals(2, it.size) + (it as List).forEach { result -> + assertNotEquals(ZonedDateTime.parse("2024-08-15T00:00:00Z"), result.time) + } + } + } + @Test fun `it should delete scope and its history`() = runTest { loadSampleData("beehive_with_scope.jsonld") diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt index f9469ffae..8f6170bdb 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/service/AttributeInstanceServiceTests.kt @@ -40,7 +40,7 @@ import org.springframework.test.context.ActiveProfiles import java.time.Instant import java.time.ZoneOffset import java.time.ZonedDateTime -import java.util.* +import java.util.UUID @SpringBootTest @ActiveProfiles("test") @@ -346,6 +346,60 @@ class AttributeInstanceServiceTests : WithTimescaleContainer, WithKafkaContainer assertEquals(ZonedDateTime.parse("2022-07-01T00:00:00Z"), origin) } + @Test + fun `it should include lower bound of interval with after timerel`() = runTest { + (1..5).forEachIndexed { index, _ -> + val attributeInstance = + gimmeNumericPropertyAttributeInstance(incomingTemporalEntityAttribute.id) + .copy( + measuredValue = index.toDouble(), + time = ZonedDateTime.parse("2022-07-0${index + 1}T00:00:00Z") + ) + attributeInstanceService.create(attributeInstance) + } + val temporalEntitiesQuery = gimmeTemporalEntitiesQuery( + buildDefaultTestTemporalQuery( + timerel = Timerel.AFTER, + timeAt = ZonedDateTime.parse("2022-07-01T00:00:00Z"), + instanceLimit = 5 + ) + ) + + attributeInstanceService.search(temporalEntitiesQuery, incomingTemporalEntityAttribute) + .shouldSucceedWith { + assertEquals(5, it.size) + } + } + + @Test + fun `it should exclude upper bound of interval with between timerel`() = runTest { + (1..5).forEachIndexed { index, _ -> + val attributeInstance = + gimmeNumericPropertyAttributeInstance(incomingTemporalEntityAttribute.id) + .copy( + measuredValue = index.toDouble(), + time = ZonedDateTime.parse("2022-07-0${index + 1}T00:00:00Z") + ) + attributeInstanceService.create(attributeInstance) + } + val temporalEntitiesQuery = gimmeTemporalEntitiesQuery( + buildDefaultTestTemporalQuery( + timerel = Timerel.BETWEEN, + timeAt = ZonedDateTime.parse("2022-07-01T00:00:00Z"), + endTimeAt = ZonedDateTime.parse("2022-07-05T00:00:00Z"), + instanceLimit = 5 + ) + ) + + attributeInstanceService.search(temporalEntitiesQuery, incomingTemporalEntityAttribute) + .shouldSucceedWith { + assertEquals(4, it.size) + (it as List).forEach { result -> + assertNotEquals(ZonedDateTime.parse("2022-07-05T00:00:00Z"), result.time) + } + } + } + @Test fun `it should only return the limited instances asked in the temporal query`() = runTest { (1..10).forEach { _ ->