Skip to content

Commit

Permalink
feat: add language filter to sub attributes (#1274)
Browse files Browse the repository at this point in the history
* feat: add language filter to sub attributes

* added a test that fails

* Update shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt

Co-authored-by: Thomas Bousselin <61795238+thomasBousselin@users.noreply.github.com>

* fix for failing test

* fix: nested block depth / more functional way

---------

Co-authored-by: Benoit Orihuela <benoit.orihuela@egm.io>
Co-authored-by: Thomas Bousselin <61795238+thomasBousselin@users.noreply.github.com>
  • Loading branch information
3 people authored Dec 3, 2024
1 parent f3d668b commit 9417306
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@ import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_OBJECT
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_TYPE_TERM
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VALUE_TERM
import com.egm.stellio.shared.util.JsonLdUtils.JSONLD_VOCAB_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_CREATED_AT_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_ID_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_DATASET_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_ENTITY_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_GEOPROPERTY_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_JSONPROPERTY_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LANGUAGEPROPERTY_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_LANG_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_MODIFIED_AT_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_NONE_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_OBSERVED_AT_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_PROPERTY_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_RELATIONSHIP_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_SYSATTRS_TERMS
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_UNIT_CODE_TERM
import com.egm.stellio.shared.util.JsonLdUtils.NGSILD_VOCABPROPERTY_TERM
import com.egm.stellio.shared.util.PROPERTIES_PROPERTY_TERM
import com.egm.stellio.shared.util.QUERY_PARAM_LANG
Expand All @@ -42,6 +46,21 @@ typealias CompactedEntity = Map<String, Any>
typealias CompactedAttributeInstance = Map<String, Any>
typealias CompactedAttributeInstances = List<CompactedAttributeInstance>

val JSONLD_COMPACTED_ATTRIBUTE_CORE_MEMBERS =
setOf(
JSONLD_TYPE_TERM,
JSONLD_VALUE_TERM,
JSONLD_OBJECT,
JSONLD_JSON_TERM,
JSONLD_VOCAB_TERM,
JSONLD_LANGUAGEMAP_TERM,
NGSILD_UNIT_CODE_TERM,
NGSILD_DATASET_ID_TERM,
NGSILD_CREATED_AT_TERM,
NGSILD_MODIFIED_AT_TERM,
NGSILD_OBSERVED_AT_TERM
)

fun CompactedEntity.getRelationshipsObjects(): Set<URI> =
this.mapValues { entry ->
applyAttributeTransformation(
Expand Down Expand Up @@ -140,27 +159,38 @@ private fun filterLanguageProperty(value: Map<String, Any>, transformationParame
val attributeCompactedType = value[JSONLD_TYPE_TERM]?.let {
AttributeCompactedType.forKey(value[JSONLD_TYPE_TERM] as String)
}
val languageFilteredValue =
if (attributeCompactedType == LANGUAGEPROPERTY) {
val localeRanges = Locale.LanguageRange.parse(languageFilter)
val propertyLocales = (value[JSONLD_LANGUAGEMAP_TERM] as Map<String, Any>).keys.sorted()
val bestLocaleMatch = Locale.filterTags(localeRanges, propertyLocales)
.getOrElse(0) { _ ->
// as the list is sorted, @none is the first in the list if it exists
propertyLocales.first()
}
mapOf(
JSONLD_TYPE_TERM to NGSILD_PROPERTY_TERM,
JSONLD_VALUE_TERM to (value[JSONLD_LANGUAGEMAP_TERM] as Map<String, Any>)[bestLocaleMatch],
NGSILD_LANG_TERM to bestLocaleMatch
)
} else value

return languageFilteredValue.mapValues { entry ->
if (entry.key == NGSILD_ENTITY_TERM)
(entry.value as CompactedEntity).toFilteredLanguageProperties(languageFilter)
else entry.value
}
return if (attributeCompactedType == LANGUAGEPROPERTY) {
val localeRanges = Locale.LanguageRange.parse(languageFilter)
val propertyLocales = (value[JSONLD_LANGUAGEMAP_TERM] as Map<String, Any>).keys.sorted()
val bestLocaleMatch = Locale.filterTags(localeRanges, propertyLocales)
.getOrElse(0) { _ ->
// as the list is sorted, @none is the first in the list if it exists
propertyLocales.first()
}

value.map { entry ->
when {
entry.key == JSONLD_TYPE_TERM ->
JSONLD_TYPE_TERM to NGSILD_PROPERTY_TERM
entry.key == JSONLD_LANGUAGEMAP_TERM ->
JSONLD_VALUE_TERM to (value[JSONLD_LANGUAGEMAP_TERM] as Map<String, Any>)[bestLocaleMatch]
JSONLD_COMPACTED_ATTRIBUTE_CORE_MEMBERS.contains(entry.key) ->
entry.key to entry.value
else ->
entry.key to filterLanguageProperty(entry.value as Map<String, Any>, transformationParameters)
}
}.toMap()
.plus(NGSILD_LANG_TERM to bestLocaleMatch)
} else value.map { entry ->
when {
entry.key == NGSILD_ENTITY_TERM ->
entry.key to (entry.value as CompactedEntity).toFilteredLanguageProperties(languageFilter)
!JSONLD_COMPACTED_ATTRIBUTE_CORE_MEMBERS.contains(entry.key) ->
entry.key to filterLanguageProperty(entry.value as Map<String, Any>, transformationParameters)
else -> entry.key to entry.value
}
}.toMap()
}

fun CompactedEntity.toGeoJson(geometryProperty: String): Map<String, Any?> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ object JsonLdUtils {
const val NGSILD_OBSERVED_AT_TERM = "observedAt"
const val NGSILD_OBSERVED_AT_PROPERTY = "https://uri.etsi.org/ngsi-ld/$NGSILD_OBSERVED_AT_TERM"
const val NGSILD_UNIT_CODE_PROPERTY = "https://uri.etsi.org/ngsi-ld/unitCode"
const val NGSILD_UNIT_CODE_TERM = "unitCode"
const val NGSILD_LOCATION_TERM = "location"
const val NGSILD_LOCATION_PROPERTY = "https://uri.etsi.org/ngsi-ld/location"
const val NGSILD_OBSERVATION_SPACE_TERM = "observationSpace"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.egm.stellio.shared.model
import com.egm.stellio.shared.util.JsonUtils.deserializeAsMap
import com.egm.stellio.shared.util.JsonUtils.serializeObject
import com.egm.stellio.shared.util.assertJsonPayloadsAreEqual
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
Expand Down Expand Up @@ -164,4 +166,128 @@ class LanguageFilterTests {

assertJsonPayloadsAreEqual(expectedFilteredRepresentation, serializeObject(filteredRepresentation))
}

@Test
fun `it should filter language properties for sub attributes`() = runTest {
val entity = """
{
"id": "urn:ngsi-ld:Beehive:01",
"type": "Beehive",
"managedBy": {
"type": "Relationship",
"object": "urn:ngsi-ld:Beekeeper:1",
"name": {
"type": "LanguageProperty",
"languageMap": {
"en": "beekeeper",
"fr": "apiculteur"
}
}
}
}
""".trimIndent().deserializeAsMap()

val filteredEntity = entity.toFilteredLanguageProperties("en")

assertJsonPayloadsAreEqual(
"""
{
"id": "urn:ngsi-ld:Beehive:01",
"type": "Beehive",
"managedBy": {
"type": "Relationship",
"object": "urn:ngsi-ld:Beekeeper:1",
"name": {
"type": "Property",
"value": "beekeeper",
"lang": "en"
}
}
}
""".trimIndent(),
serializeObject(filteredEntity)
)
}

@Test
fun `it should filter language properties for an attribute and its sub attributes`() = runTest {
val entity = """
{
"id": "urn:ngsi-ld:Beehive:01",
"type": "Beehive",
"name": {
"type": "LanguageProperty",
"languageMap": {
"en": "beekeeper",
"fr": "apiculteur"
},
"subAttribute": {
"type": "LanguageProperty",
"languageMap": {
"en": "English",
"fr": "Français"
}
}
}
}
""".trimIndent().deserializeAsMap()

val filteredEntity = entity.toFilteredLanguageProperties("en")

assertJsonPayloadsAreEqual(
"""
{
"id": "urn:ngsi-ld:Beehive:01",
"type": "Beehive",
"name": {
"type": "Property",
"value": "beekeeper",
"lang": "en",
"subAttribute": {
"type": "Property",
"value": "English",
"lang": "en"
}
}
}
""".trimIndent(),
serializeObject(filteredEntity)
)
}

@Test
fun `it should filter language properties having other core attribute members`() = runTest {
val entity = """
{
"id": "urn:ngsi-ld:Beehive:01",
"type": "Beehive",
"name": {
"type": "LanguageProperty",
"languageMap": {
"en": "beekeeper",
"fr": "apiculteur"
},
"observedAt": "2024-11-30T00:00:00Z"
}
}
""".trimIndent().deserializeAsMap()

val filteredEntity = entity.toFilteredLanguageProperties("en")

assertJsonPayloadsAreEqual(
"""
{
"id": "urn:ngsi-ld:Beehive:01",
"type": "Beehive",
"name": {
"type": "Property",
"value": "beekeeper",
"lang": "en",
"observedAt": "2024-11-30T00:00:00Z"
}
}
""".trimIndent(),
serializeObject(filteredEntity)
)
}
}

0 comments on commit 9417306

Please sign in to comment.