From 05822fb2bb0233ae2ef77fbdab39d4ebd4a6acb0 Mon Sep 17 00:00:00 2001 From: Benoit Orihuela Date: Sun, 7 Apr 2024 16:58:26 +0200 Subject: [PATCH] feat: handle @none for default values --- .../stellio/shared/model/CompactedEntity.kt | 5 +++- .../egm/stellio/shared/model/NgsiLdEntity.kt | 28 +++++++++++-------- .../shared/model/LanguageFilterTests.kt | 11 ++++---- .../stellio/shared/model/NgsiLdEntityTests.kt | 25 +++++++++++------ 4 files changed, 43 insertions(+), 26 deletions(-) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt index aa71d6df8d..fc38b4fdf5 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/CompactedEntity.kt @@ -76,7 +76,10 @@ private fun filterLanguageProperty(value: Map, transformationParame val localeRanges = Locale.LanguageRange.parse(transformationParameters?.get(QUERY_PARAM_LANG)!!) val propertyLocales = (value[JSONLD_LANGUAGEMAP_TERM] as Map).keys.sorted() val bestLocaleMatch = Locale.filterTags(localeRanges, propertyLocales) - .getOrElse(0) { _ -> propertyLocales.first() } + .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)[bestLocaleMatch], diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt index c5a4a21cac..7931e49a88 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/NgsiLdEntity.kt @@ -325,11 +325,11 @@ class NgsiLdJsonPropertyInstance private constructor( ): Either = either { val json = values.getMemberValue(NGSILD_JSONPROPERTY_VALUE) ensureNotNull(json) { - BadRequestDataException("Property $name has an instance without a json member") + BadRequestDataException("JsonProperty $name has an instance without a json member") } ensure(json is Map<*, *> || (json is List<*> && json.all { it is Map<*, *> })) { BadRequestDataException( - "Property $name has a json member that is not a JSON object, nor an array of JSON objects" + "JsonProperty $name has a json member that is not a JSON object, nor an array of JSON objects" ) } @@ -366,10 +366,10 @@ class NgsiLdLanguagePropertyInstance private constructor( ): Either = either { val languageMap = values[NGSILD_LANGUAGEPROPERTY_VALUE] ensureNotNull(languageMap) { - BadRequestDataException("Property $name has an instance without a languageMap member") + BadRequestDataException("LanguageProperty $name has an instance without a languageMap member") } ensure(isValidLanguageMap(languageMap)) { - BadRequestDataException("Property $name has an invalid languageMap member") + BadRequestDataException("LanguageProperty $name has an invalid languageMap member") } val observedAt = values.getMemberValueAsDateTime(NGSILD_OBSERVED_AT_PROPERTY) @@ -391,16 +391,20 @@ class NgsiLdLanguagePropertyInstance private constructor( private fun isValidLanguageMap(languageMap: List): Boolean = languageMap.all { it is Map<*, *> && - it.size == 2 && - (it.containsKey(JSONLD_VALUE) || it.containsKey(JSONLD_LANGUAGE)) && - it.values.all { value -> value is String } && - isValidLanguageTag(it[JSONLD_LANGUAGE] as String) + isValidStructure(it) && + isValidLangValue(it.values) && + isValidLanguageTag(it[JSONLD_LANGUAGE] as? String) } - private fun isValidLanguageTag(tag: String): Boolean { - val locale = Locale.forLanguageTag(tag) - return tag == locale.toLanguageTag() - } + private fun isValidStructure(langEntry: Map<*, *>): Boolean = + (langEntry.size == 2 && langEntry.containsKey(JSONLD_VALUE) && langEntry.containsKey(JSONLD_LANGUAGE)) || + (langEntry.size == 1 && langEntry.containsKey(JSONLD_VALUE)) + + private fun isValidLangValue(values: Collection): Boolean = + values.all { value -> value is String || value is List<*> } + + private fun isValidLanguageTag(tag: String?): Boolean = + tag == null || "und" != Locale.forLanguageTag(tag).toLanguageTag() } override fun toString(): String = "NgsiLdLanguagePropertyInstance(languageMap=$languageMap)" diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/LanguageFilterTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/LanguageFilterTests.kt index 6c328ba1de..f54f06000a 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/LanguageFilterTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/LanguageFilterTests.kt @@ -30,8 +30,8 @@ class LanguageFilterTests { """ "languageProperty": { "type": "Property", - "value": "Grand Place", - "lang": "fr" + "value": "Big Place", + "lang": "@none" } """.trimIndent() ), @@ -40,8 +40,8 @@ class LanguageFilterTests { """ "languageProperty": { "type": "Property", - "value": "Grand Place", - "lang": "fr" + "value": "Big Place", + "lang": "@none" } """.trimIndent() ), @@ -103,7 +103,8 @@ class LanguageFilterTests { "type": "LanguageProperty", "languageMap": { "fr": "Grand Place", - "nl": "Grote Markt" + "nl": "Grote Markt", + "@none": "Big Place" } } } diff --git a/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt b/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt index 04038cb09e..a9bfaf7483 100644 --- a/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt +++ b/shared/src/test/kotlin/com/egm/stellio/shared/model/NgsiLdEntityTests.kt @@ -829,7 +829,7 @@ class NgsiLdEntityTests { .shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Property ${NGSILD_DEFAULT_VOCAB}jsonProperty has an instance without a json member", + "JsonProperty ${NGSILD_DEFAULT_VOCAB}jsonProperty has an instance without a json member", it.message ) } @@ -853,7 +853,7 @@ class NgsiLdEntityTests { .shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Property ${NGSILD_DEFAULT_VOCAB}jsonProperty has a json member that is not a JSON object, " + + "JsonProperty ${NGSILD_DEFAULT_VOCAB}jsonProperty has a json member that is not a JSON object, " + "nor an array of JSON objects", it.message ) @@ -870,8 +870,9 @@ class NgsiLdEntityTests { "languageProperty": { "type": "LanguageProperty", "languageMap": { - "fr": "Grand Place", - "nl": "Grote Markt" + "fr": ["Grand Place", "Grande Place"], + "nl": "Grote Markt", + "@none": "Big Place" } } } @@ -891,10 +892,17 @@ class NgsiLdEntityTests { "@language" to "fr", "@value" to "Grand Place" ), + mapOf( + "@language" to "fr", + "@value" to "Grande Place" + ), mapOf( "@language" to "nl", "@value" to "Grote Markt" ), + mapOf( + "@value" to "Big Place" + ) ), languagePropertyInstance.languageMap ) @@ -920,7 +928,8 @@ class NgsiLdEntityTests { .shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Property ${NGSILD_DEFAULT_VOCAB}languageProperty has an instance without a languageMap member", + "LanguageProperty ${NGSILD_DEFAULT_VOCAB}languageProperty has an instance " + + "without a languageMap member", it.message ) } @@ -947,7 +956,7 @@ class NgsiLdEntityTests { .shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Property ${NGSILD_DEFAULT_VOCAB}languageProperty has an invalid languageMap member", + "LanguageProperty ${NGSILD_DEFAULT_VOCAB}languageProperty has an invalid languageMap member", it.message ) } @@ -963,7 +972,7 @@ class NgsiLdEntityTests { "languageProperty": { "type": "LanguageProperty", "languageMap": { - "invalid-lang-tag": "Grand Place" + "123": "Grand Place" } } } @@ -973,7 +982,7 @@ class NgsiLdEntityTests { .shouldFail { assertInstanceOf(BadRequestDataException::class.java, it) assertEquals( - "Property ${NGSILD_DEFAULT_VOCAB}languageProperty has an invalid languageMap member", + "LanguageProperty ${NGSILD_DEFAULT_VOCAB}languageProperty has an invalid languageMap member", it.message ) }