Skip to content

Commit

Permalink
feat: add support for user defined geo properties
Browse files Browse the repository at this point in the history
  • Loading branch information
bobeal committed Jan 20, 2025
1 parent 0310352 commit fa1bbd2
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 27 deletions.
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

0 comments on commit fa1bbd2

Please sign in to comment.