Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: add support for user defined geo properties #1319

Merged
merged 1 commit into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer() {

@Test
fun `it should retrieve a list of entity payloads`() = runTest {
val expandedPayload = loadSampleData("beehive_expanded.jsonld")
expandedPayload.sampleDataToNgsiLdEntity().map {
val entityPayload = loadSampleData("beehive.jsonld")
entityPayload.sampleDataToNgsiLdEntity().map {
entityService.createEntityPayload(
it.second,
it.first,
Expand All @@ -184,7 +184,7 @@ class EntityQueryServiceTests : WithTimescaleContainer, WithKafkaContainer() {
val entityPayloads = entityQueryService.retrieve(listOf(beehiveTestCId))
assertEquals(1, entityPayloads.size)
assertEquals(beehiveTestCId, entityPayloads[0].entityId)
assertJsonPayloadsAreEqual(expandedPayload, entityPayloads[0].payload.asString())
assertJsonPayloadsAreEqual(loadSampleData("beehive_expanded.jsonld"), entityPayloads[0].payload.asString())
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,8 @@ class EntityServiceTests : WithTimescaleContainer, WithKafkaContainer() {

@Test
fun `it should add a type to an entity`() = runTest {
val expandedPayload = loadSampleData("beehive_expanded.jsonld")
expandedPayload.sampleDataToNgsiLdEntity().map {
val entityPayload = loadSampleData("beehive.jsonld")
entityPayload.sampleDataToNgsiLdEntity().map {
entityService.createEntityPayload(
it.second,
it.first,
Expand Down
46 changes: 26 additions & 20 deletions shared/src/main/kotlin/com/egm/stellio/shared/util/JsonLdUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -296,22 +296,25 @@ object JsonLdUtils {
}

private fun transformGeoPropertyToWKT(): (Map.Entry<String, Any>) -> Any = {
if (NGSILD_GEO_PROPERTIES_TERMS.contains(it.key)) {
when (it.value) {
is Map<*, *> -> {
when {
it.key in JSONLD_COMPACTED_ENTITY_CORE_MEMBERS -> it.value
it.value is Map<*, *> -> {
if ((it.value as Map<*, *>)[JSONLD_TYPE_TERM] == NGSILD_GEOPROPERTY_TERM) {
val geoProperty = it.value as Map<String, Any>
val wktGeometry = geoPropertyToWKTOrNull(geoProperty[JSONLD_VALUE_TERM]!!)
geoProperty.plus(JSONLD_VALUE_TERM to wktGeometry)
}
is List<*> -> {
(it.value as List<Map<String, Any>>).map { geoProperty ->
} else it.value
}
it.value is List<*> -> {
(it.value as List<Map<String, Any>>).map { geoProperty ->
if (geoProperty[JSONLD_TYPE_TERM] == NGSILD_GEOPROPERTY_TERM) {
val wktGeometry = geoPropertyToWKTOrNull(geoProperty[JSONLD_VALUE_TERM]!!)
geoProperty.plus(JSONLD_VALUE_TERM to wktGeometry)
}
} else geoProperty
}
else -> it.value
}
} else it.value
else -> it.value
}
}

private fun geoPropertyToWKTOrNull(geoPropertyValue: Any): String =
Expand All @@ -321,29 +324,32 @@ object JsonLdUtils {
throwingGeoJsonToWkt(geoPropertyValue as Map<String, Any>)

private fun restoreGeoPropertyFromWKT(): (Map.Entry<String, Any>) -> Any = {
if (NGSILD_GEO_PROPERTIES_TERMS.contains(it.key)) {
when (it.value) {
is Map<*, *> -> {
when {
it.key in JSONLD_COMPACTED_ENTITY_CORE_MEMBERS -> it.value
it.value is Map<*, *> -> {
if ((it.value as Map<*, *>)[JSONLD_TYPE_TERM] == NGSILD_GEOPROPERTY_TERM) {
val geoValues = it.value as MutableMap<String, Any>
// in case of an aggregated or temporalValues query, there is no "value" member
if (geoValues.isNotEmpty() && geoValues.containsKey(JSONLD_VALUE_TERM)) {
geoValues[JSONLD_VALUE_TERM] = wktToGeoJson(geoValues[JSONLD_VALUE_TERM] as String)
geoValues
} else geoValues
}
// case of a multi-instance geoproperty or when retrieving the history of a geoproperty
is List<*> ->
(it.value as List<Map<String, Any>>).map { geoInstance ->
} else it.value
}
// case of a multi-instance geoproperty or when retrieving the history of a geoproperty
it.value is List<*> ->
(it.value as List<Map<String, Any>>).map { geoInstance ->
if (geoInstance[JSONLD_TYPE_TERM] == NGSILD_GEOPROPERTY_TERM) {
val geoValues = geoInstance.toMutableMap()
// in case of an aggregated or temporalValues query, there is no "value" member
if (geoValues.containsKey(JSONLD_VALUE_TERM)) {
geoValues[JSONLD_VALUE_TERM] = wktToGeoJson(geoValues[JSONLD_VALUE_TERM] as String)
geoValues
} else geoValues
}
else -> it.value
}
} else it.value
} else geoInstance
}
else -> it.value
}
}

fun compactEntity(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class JsonLdUtilsTests {
}

@Test
fun `it should correctly transform geoproperties`() = runTest {
fun `it should correctly transform core geoproperties`() = runTest {
val payload =
"""
{
Expand Down Expand Up @@ -242,7 +242,7 @@ class JsonLdUtilsTests {
}

@Test
fun `it should correctly transform and restore geoproperties`() = runTest {
fun `it should correctly transform and restore core geoproperties`() = runTest {
val payload =
"""
{
Expand Down Expand Up @@ -281,6 +281,42 @@ class JsonLdUtilsTests {
)
}

@Test
fun `it should correctly transform and restore a user defined geoproperty`() = runTest {
val payload =
"""
{
"id": "urn:ngsi-ld:Device:01234",
"type": "Device",
"userDefinedGeoProperty": {
"type": "GeoProperty",
"value": {
"type": "Point",
"coordinates": [ 100.12, 0.23 ]
}
}
}
""".trimIndent()

val deserializedPayload = payload.deserializeAsMap()
val expandedEntity = expandJsonLdEntityF(deserializedPayload, NGSILD_TEST_CORE_CONTEXTS)
.shouldSucceedAndResult()

val userDefinedGeoProperty = expandedEntity.getAttributes()
.getAttributeFromExpandedAttributes(NGSILD_DEFAULT_VOCAB + "userDefinedGeoProperty", null)
assertNotNull(userDefinedGeoProperty)
assertEquals(
"POINT (100.12 0.23)",
userDefinedGeoProperty!!.getMemberValueAsString(NGSILD_PROPERTY_VALUE)
)

val compactedEntity = compactEntity(expandedEntity, NGSILD_TEST_CORE_CONTEXTS)
assertJsonPayloadsAreEqual(
serializeObject(deserializedPayload.plus(JSONLD_CONTEXT to NGSILD_TEST_CORE_CONTEXT)),
serializeObject(compactedEntity)
)
}

@Test
fun `it should correctly compact a term if it is in the provided contexts`() = runTest {
assertEquals(
Expand Down
Loading