From 35727b151cb0b1e8a6d9e0878d8d33231462c046 Mon Sep 17 00:00:00 2001 From: David Campo Date: Sat, 27 Jan 2024 19:42:03 +0000 Subject: [PATCH 1/3] Add new atrribute type JsonProperty --- CHANGES_NEXT_RELEASE | 1 + .../dbModel/dbModelFromApiAttribute.cpp | 4 +- .../orionld/dbModel/dbModelToApiAttribute.cpp | 14 + .../dbModel/dbModelToApiSubAttribute.cpp | 2 + .../orionld/payloadCheck/pCheckAttribute.cpp | 105 ++++++- .../orionld/types/OrionldAttributeType.cpp | 2 + src/lib/orionld/types/OrionldAttributeType.h | 3 +- .../0000_ngsild/ngsild_json-property.test | 281 ++++++++++++++++++ test/functionalTest/testHarness.sh | 20 +- 9 files changed, 416 insertions(+), 16 deletions(-) create mode 100644 test/functionalTest/cases/0000_ngsild/ngsild_json-property.test diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 283c45d0ae..b6c464ca61 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -4,3 +4,4 @@ Fixed Issue: New Features: * Support for VocabularyProperty * Support for the new URL parameter "format" for output formats (normalized, concise, simplified) + * Support for JsonProperty attribute type diff --git a/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp b/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp index b583cf29ce..59114d9457 100644 --- a/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp +++ b/src/lib/orionld/dbModel/dbModelFromApiAttribute.cpp @@ -149,13 +149,13 @@ bool dbModelFromApiAttribute(KjNode* attrP, KjNode* dbAttrsP, KjNode* attrAddedV // // Move special fields back to "attrP" - const char* specialV[] = { "type", "value", "object", "languageMap", "vocab", "datasetId" }; // observedAt+unitCode are mds (db-model) + const char* specialV[] = { "type", "value", "object", "languageMap", "vocab", "json", "datasetId" }; // observedAt+unitCode are mds (db-model) for (unsigned int ix = 0; ix < K_VEC_SIZE(specialV); ix++) { KjNode* nodeP = kjLookup(mdP, specialV[ix]); if (nodeP != NULL) { - if ((ix == 2) || (ix == 3) || (ix == 4)) // "object", "languageMap", "vocab": change name to "value" (Orion's DB model) + if ((ix >= 2) && (ix <= 5)) // "object", "languageMap", "vocab", "json": change name to "value" (Orion's DB model) nodeP->name = (char*) "value"; kjChildRemove(mdP, nodeP); diff --git a/src/lib/orionld/dbModel/dbModelToApiAttribute.cpp b/src/lib/orionld/dbModel/dbModelToApiAttribute.cpp index a316374629..0c88f392e3 100644 --- a/src/lib/orionld/dbModel/dbModelToApiAttribute.cpp +++ b/src/lib/orionld/dbModel/dbModelToApiAttribute.cpp @@ -113,6 +113,7 @@ void dbModelToApiAttribute(KjNode* dbAttrP, bool sysAttrs, bool eqsForDots) { if (strcmp(typeP->value.s, "Relationship") == 0) valueP->name = (char*) "object"; else if (strcmp(typeP->value.s, "LanguageProperty") == 0) valueP->name = (char*) "languageMap"; + else if (strcmp(typeP->value.s, "JsonProperty") == 0) valueP->name = (char*) "json"; else if (strcmp(typeP->value.s, "VocabularyProperty") == 0) { valueP->name = (char*) "vocab"; @@ -398,6 +399,17 @@ KjNode* dbModelToApiAttribute2(KjNode* dbAttrP, KjNode* datasetP, bool sysAttrs, valueP->name = (char*) "vocab"; attrP = dbAttrP; } + else if (strcmp(attrTypeNodeP->value.s, "JsonProperty") == 0) + { + KjNode* valueP = kjLookup(dbAttrP, "value"); + + // Remove everything except the value, and change its name to "vocab" + dbAttrP->value.firstChildP = valueP; + dbAttrP->lastChild = valueP; + valueP->next = NULL; + valueP->name = (char*) "json"; + attrP = dbAttrP; + } else { // "Steal" the value node and rename it to have the attribute's name instead - that's all that's needed for SIMPLIFIED FORMAT @@ -435,6 +447,8 @@ KjNode* dbModelToApiAttribute2(KjNode* dbAttrP, KjNode* datasetP, bool sysAttrs, { if (attrType == Relationship) nodeP->name = (char*) "object"; + else if (attrType == JsonProperty) + nodeP->name = (char*) "json"; else if (attrType == VocabularyProperty) { nodeP->name = (char*) "vocab"; diff --git a/src/lib/orionld/dbModel/dbModelToApiSubAttribute.cpp b/src/lib/orionld/dbModel/dbModelToApiSubAttribute.cpp index 034b9018a1..6a9042ee6e 100644 --- a/src/lib/orionld/dbModel/dbModelToApiSubAttribute.cpp +++ b/src/lib/orionld/dbModel/dbModelToApiSubAttribute.cpp @@ -85,6 +85,7 @@ void dbModelToApiSubAttribute(KjNode* dbSubAttrP) if (strcmp(typeP->value.s, "Relationship") == 0) valueP->name = (char*) "object"; else if (strcmp(typeP->value.s, "LanguageProperty") == 0) valueP->name = (char*) "languageMap"; else if (strcmp(typeP->value.s, "VocabularyProperty") == 0) valueP->name = (char*) "vocab"; + else if (strcmp(typeP->value.s, "JsonProperty") == 0) valueP->name = (char*) "json"; } } @@ -144,6 +145,7 @@ KjNode* dbModelToApiSubAttribute2(KjNode* dbSubAttributeP, bool sysAttrs, Orionl if (subAttrType == Relationship) nodeP->name = (char*) "object"; else if (subAttrType == LanguageProperty) nodeP->name = (char*) "languageMap"; else if (subAttrType == VocabularyProperty) nodeP->name = (char*) "vocab"; + else if (subAttrType == JsonProperty) nodeP->name = (char*) "json"; kjChildAdd(subAttrP, nodeP); } diff --git a/src/lib/orionld/payloadCheck/pCheckAttribute.cpp b/src/lib/orionld/payloadCheck/pCheckAttribute.cpp index 997bc0e2b4..a31b59b599 100644 --- a/src/lib/orionld/payloadCheck/pCheckAttribute.cpp +++ b/src/lib/orionld/payloadCheck/pCheckAttribute.cpp @@ -70,6 +70,7 @@ static const char* attrTypeChangeTitle(OrionldAttributeType oldType, OrionldAttr if (oldType == GeoProperty) return "Attempt to transform a GeoProperty into a Property"; if (oldType == LanguageProperty) return "Attempt to transform a LanguageProperty into a Property"; if (oldType == VocabularyProperty) return "Attempt to transform a VocabularyProperty into a Property"; + if (oldType == JsonProperty) return "Attempt to transform a JsonProperty into a Property"; } else if (newType == Relationship) { @@ -77,6 +78,7 @@ static const char* attrTypeChangeTitle(OrionldAttributeType oldType, OrionldAttr if (oldType == GeoProperty) return "Attempt to transform a GeoProperty into a Relationship"; if (oldType == LanguageProperty) return "Attempt to transform a LanguageProperty into a Relationship"; if (oldType == VocabularyProperty) return "Attempt to transform a VocabularyProperty into a Relationship"; + if (oldType == JsonProperty) return "Attempt to transform a JsonProperty into a Relationship"; } else if (newType == GeoProperty) { @@ -84,6 +86,7 @@ static const char* attrTypeChangeTitle(OrionldAttributeType oldType, OrionldAttr if (oldType == Relationship) return "Attempt to transform a Relationship into a GeoProperty"; if (oldType == LanguageProperty) return "Attempt to transform a LanguageProperty into a GeoProperty"; if (oldType == VocabularyProperty) return "Attempt to transform a VocabularyProperty into a GeoProperty"; + if (oldType == JsonProperty) return "Attempt to transform a JsonProperty into a GeoProperty"; } else if (newType == LanguageProperty) { @@ -91,13 +94,23 @@ static const char* attrTypeChangeTitle(OrionldAttributeType oldType, OrionldAttr if (oldType == Relationship) return "Attempt to transform a Relationship into a LanguageProperty"; if (oldType == GeoProperty) return "Attempt to transform a GeoProperty into a LanguageProperty"; if (oldType == VocabularyProperty) return "Attempt to transform a VocabularyProperty into a LanguageProperty"; + if (oldType == JsonProperty) return "Attempt to transform a JsonProperty into a LanguageProperty"; } else if (newType == VocabularyProperty) { if (oldType == Property) return "Attempt to transform a Property into a VocabularyProperty"; if (oldType == Relationship) return "Attempt to transform a Relationship into a VocabularyProperty"; if (oldType == GeoProperty) return "Attempt to transform a GeoProperty into a VocabularyProperty"; - if (oldType == LanguageProperty) return "Attempt to transform a LanguageProperty into a GeoProperty"; + if (oldType == LanguageProperty) return "Attempt to transform a LanguageProperty into a VocabularyProperty"; + if (oldType == JsonProperty) return "Attempt to transform a JsonProperty into a VocabularyProperty"; + } + else if (newType == JsonProperty) + { + if (oldType == Property) return "Attempt to transform a Property into a JsonProperty"; + if (oldType == Relationship) return "Attempt to transform a Relationship into a JsonProperty"; + if (oldType == GeoProperty) return "Attempt to transform a GeoProperty into a JsonProperty"; + if (oldType == LanguageProperty) return "Attempt to transform a LanguageProperty into a JsonProperty"; + if (oldType == VocabularyProperty) return "Attempt to transform a VocabularyProperty into a JsonProperty"; } return "Attribute type inconsistency"; @@ -372,6 +385,7 @@ bool valueAndTypeCheck(KjNode* attrP, OrionldAttributeType attributeType, bool a KjNode* objectP = kjLookup(attrP, "object"); KjNode* languageMapP = kjLookup(attrP, "languageMap"); KjNode* vocabP = kjLookup(attrP, "vocab"); + KjNode* jsonP = kjLookup(attrP, "json"); if (attributeType == Property) { @@ -390,6 +404,11 @@ bool valueAndTypeCheck(KjNode* attrP, OrionldAttributeType attributeType, bool a orionldError(OrionldBadRequestData, "Forbidden field for a Property: vocab", attrP->name, 400); return false; } + else if (jsonP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a Property: json", attrP->name, 400); + return false; + } else if ((valueP == NULL) && (attributeExisted == false)) // Attribute is new but the value is missing { orionldError(OrionldBadRequestData, "Missing /value/ field for Property at creation time", attrP->name, 400); @@ -413,6 +432,11 @@ bool valueAndTypeCheck(KjNode* attrP, OrionldAttributeType attributeType, bool a orionldError(OrionldBadRequestData, "Forbidden field for a GeoProperty: vocab", attrP->name, 400); return false; } + else if (jsonP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a GeoProperty: json", attrP->name, 400); + return false; + } else if ((valueP == NULL) && (attributeExisted == false)) // Attribute is new but the value is missing { orionldError(OrionldBadRequestData, "Missing /value/ field for GeoProperty at creation time", attrP->name, 400); @@ -436,6 +460,11 @@ bool valueAndTypeCheck(KjNode* attrP, OrionldAttributeType attributeType, bool a orionldError(OrionldBadRequestData, "Forbidden field for a Relationship: vocab", attrP->name, 400); return false; } + else if (jsonP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a Relationship: json", attrP->name, 400); + return false; + } else if ((objectP == NULL) && (attributeExisted == false)) // Attribute is new but the value is missing { orionldError(OrionldBadRequestData, "Missing /object/ field for Relationship at creation time", attrP->name, 400); @@ -459,6 +488,11 @@ bool valueAndTypeCheck(KjNode* attrP, OrionldAttributeType attributeType, bool a orionldError(OrionldBadRequestData, "Forbidden field for a LanguageProperty: vocab", attrP->name, 400); return false; } + else if (jsonP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a LanguageProperty: json", attrP->name, 400); + return false; + } else if ((languageMapP == NULL) && (attributeExisted == false)) // Attribute is new but the value is missing { orionldError(OrionldBadRequestData, "Missing /languageMap/ field for LanguageProperty at creation time", attrP->name, 400); @@ -482,12 +516,45 @@ bool valueAndTypeCheck(KjNode* attrP, OrionldAttributeType attributeType, bool a orionldError(OrionldBadRequestData, "Forbidden field for a VocabularyProperty: languageMap", attrP->name, 400); return false; } + else if (jsonP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a VocabularyProperty: json", attrP->name, 400); + return false; + } else if ((vocabP == NULL) && (attributeExisted == false)) // Attribute is new but the value is missing { orionldError(OrionldBadRequestData, "Missing /vocab/ field for VocabularyProperty at creation time", attrP->name, 400); return false; } } + else if (attributeType == JsonProperty) + { + if (valueP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a JsonProperty: value", attrP->name, 400); + return false; + } + else if (objectP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a JsonProperty: object", attrP->name, 400); + return false; + } + else if (languageMapP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a JsonProperty: languageMap", attrP->name, 400); + return false; + } + else if (vocabP != NULL) + { + orionldError(OrionldBadRequestData, "Forbidden field for a JsonProperty: vocab", attrP->name, 400); + return false; + } + else if ((jsonP == NULL) && (attributeExisted == false)) // Attribute is new but the value is missing + { + orionldError(OrionldBadRequestData, "Missing /json/ field for JsonProperty at creation time", attrP->name, 400); + return false; + } + } return true; } @@ -796,6 +863,15 @@ bool deletionWithTypePresent(KjNode* attrP, KjNode* typeP) } } } + else if (strcmp(typeP->value.s, "JsonProperty") == 0) + { + valueP = kjLookup(attrP, "json"); + if ((valueP != NULL) && (valueP->type == KjString) && (strcmp(valueP->value.s, "urn:ngsi-ld:null") == 0)) + { + attrP->type = KjNull; + return true; + } + } return false; } @@ -813,7 +889,8 @@ static bool deletionWithoutTypePresent KjNode* valueP, KjNode* objectP, KjNode* languageMapP, - KjNode* vocabP + KjNode* vocabP, + KjNode* jsonP ) { if ((attributeType == Property) || (attributeType == GeoProperty)) @@ -852,6 +929,14 @@ static bool deletionWithoutTypePresent } } } + else if (attributeType == JsonProperty) + { + if ((jsonP != NULL) && (jsonP->type == KjString) && (strcmp(jsonP->value.s, "urn:ngsi-ld:null") == 0)) + { + attrP->type = KjNull; + return true; + } + } return false; } @@ -1016,6 +1101,7 @@ static bool pCheckAttributeObject KjNode* objectP = kjLookup(attrP, "object"); KjNode* languageMapP = kjLookup(attrP, "languageMap"); KjNode* vocabP = kjLookup(attrP, "vocab"); + KjNode* jsonP = kjLookup(attrP, "json"); if (valueP != NULL) { @@ -1030,6 +1116,8 @@ static bool pCheckAttributeObject attributeType = LanguageProperty; else if (vocabP != NULL) attributeType = VocabularyProperty; + else if (jsonP != NULL) + attributeType = JsonProperty; else { // If new attribute and no value field at all - error @@ -1060,7 +1148,7 @@ static bool pCheckAttributeObject // if ((orionldState.serviceP->options & ORIONLD_SERVICE_OPTION_ACCEPT_JSONLD_NULL) != 0) { - if (deletionWithoutTypePresent(attrP, attributeType, valueP, objectP, languageMapP, vocabP) == true) + if (deletionWithoutTypePresent(attrP, attributeType, valueP, objectP, languageMapP, vocabP, jsonP) == true) return true; } } @@ -1107,7 +1195,7 @@ static bool pCheckAttributeObject fieldP->value = fieldP->value.firstChildP->value; } } - if ((attributeType == Relationship) || (attributeType == LanguageProperty) || (attributeType == VocabularyProperty)) + if ((attributeType == Relationship) || (attributeType == LanguageProperty) || (attributeType == VocabularyProperty) || (attributeType == JsonProperty)) { orionldError(OrionldBadRequestData, "Invalid member /value/", "valid for Property/GeoProperty attributes only", 400); return false; @@ -1143,6 +1231,9 @@ static bool pCheckAttributeObject if (pCheckVocabulary(fieldP, attrP->name) == false) return false; } + else if ((attributeType == JsonProperty) && (strcmp(fieldP->name, "json") == 0)) + { + } else if (strcmp(fieldP->name, "observedAt") == 0) { // @@ -1345,6 +1436,12 @@ static bool validAttrName(const char* attrName, bool isAttribute) // - observedAt // - datasetId (sub-attributes don't have datasetId) // +// - Attributes of type JsonProperty can have the following special attributes: +// - type +// - json +// - observedAt +// - datasetId (sub-attributes don't have datasetId) +// bool pCheckAttribute ( const char* entityId, diff --git a/src/lib/orionld/types/OrionldAttributeType.cpp b/src/lib/orionld/types/OrionldAttributeType.cpp index ae22d51e6e..cb6f9f2811 100644 --- a/src/lib/orionld/types/OrionldAttributeType.cpp +++ b/src/lib/orionld/types/OrionldAttributeType.cpp @@ -44,6 +44,7 @@ const char* orionldAttributeTypeName(OrionldAttributeType attributeType) case GeoProperty: return "GeoProperty"; case LanguageProperty: return "LanguageProperty"; case VocabularyProperty: return "VocabularyProperty"; + case JsonProperty: return "JsonProperty"; } return "InvalidAttributeType"; @@ -62,6 +63,7 @@ OrionldAttributeType orionldAttributeType(const char* typeString) else if (strcmp(typeString, "GeoProperty") == 0) return GeoProperty; else if (strcmp(typeString, "LanguageProperty") == 0) return LanguageProperty; else if (strcmp(typeString, "VocabularyProperty") == 0) return VocabularyProperty; + else if (strcmp(typeString, "JsonProperty") == 0) return JsonProperty; return NoAttributeType; } diff --git a/src/lib/orionld/types/OrionldAttributeType.h b/src/lib/orionld/types/OrionldAttributeType.h index 8141fc4e02..1a5419546b 100644 --- a/src/lib/orionld/types/OrionldAttributeType.h +++ b/src/lib/orionld/types/OrionldAttributeType.h @@ -39,7 +39,8 @@ typedef enum OrionldAttributeType Relationship, GeoProperty, LanguageProperty, - VocabularyProperty + VocabularyProperty, + JsonProperty } OrionldAttributeType; diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_json-property.test b/test/functionalTest/cases/0000_ngsild/ngsild_json-property.test new file mode 100644 index 0000000000..2ccc8ae98e --- /dev/null +++ b/test/functionalTest/cases/0000_ngsild/ngsild_json-property.test @@ -0,0 +1,281 @@ +# Copyright 2024 FIWARE Foundation e.V. +# +# This file is part of Orion-LD Context Broker. +# +# Orion-LD Context Broker is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Orion-LD Context Broker is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +# General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Orion-LD Context Broker. If not, see http://www.gnu.org/licenses/. +# +# For those usages not covered by this license please contact with +# orionld at fiware dot org + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh + +--NAME-- +VocabularyProperty + +--SHELL-INIT-- +dbInit CB + +orionldStart CB -experimental +accumulatorStart --pretty-print + +--SHELL-- + +# +# 01. Create a subscription on entity type T +# 02. Create an entity urn:E1, type T, with a JsonProperty V1: "abc" +# 03. Create an entity urn:E2, type T, with a JsonProperty V2: [ "vocab", "id" ] +# 04. GET urn:E1 to see V1 +# 04b. See urn:E1 in the DB - see "abc" expanded +# 05. GET urn:E2 to see V2 +# 05b. See urn:E2 in the DB - see [ "vocab", "id" ] expanded +# 06. Dump/Reset accumulator, see urn:E1+V1 and urn:E2+V2 +# +# 07. GET urn:E2 in simplified format +# 08. Query entities with q=V1==abc => see nothing +# 09. Query entities with q=V1==abc&expandValues=V1,V2 => see urn:E1 +# 10. Query entities with q=V2==id&expandValues=V1,V2 => see urn:E2 +# + +echo '01. Create a subscription on entity type T' +echo '==========================================' +payload='{ + "id": "urn:ngsi-ld:subs:S1", + "type": "Subscription", + "entities": [ + { + "type": "T" + } + ], + "notification": { + "endpoint": { + "uri": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + }, + "showChanges": true + } +}' +orionCurl --url /ngsi-ld/v1/subscriptions --payload "$payload" +echo +echo + + +echo '02. Create an entity urn:E1, type T, with a JsonProperty V1: "abc"' +echo '========================================================================' +payload='{ + "id": "urn:E1", + "type": "T", + "V1": { + "json": "abc", + "type": "JsonProperty" + } +}' +orionCurl --url /ngsi-ld/v1/entities --payload "$payload" +echo +echo + + +echo '03. Create an entity urn:E2, type T, with a JsonProperty V2: [ "json", "id" ]' +echo '====================================================================================' +payload='{ + "id": "urn:E2", + "type": "T", + "V2": { + "json": [ "json", "id" ], + "type": "JsonProperty" + } +}' +orionCurl --url /ngsi-ld/v1/entities --payload "$payload" +echo +echo + + +echo '04. GET urn:E1 to see V1' +echo '========================' +orionCurl --url /ngsi-ld/v1/entities/urn:E1 +echo +echo + + +echo '05. GET urn:E2 to see V2' +echo '========================' +orionCurl --url /ngsi-ld/v1/entities/urn:E2 +echo +echo + + +echo "06. Dump/Reset accumulator, see urn:E1+V1 and urn:E2+V2" +echo "=======================================================" +sleep .2 +accumulatorDump +accumulatorReset +echo +echo + + +echo "07. GET urn:E2 in simplified format" +echo "===================================" +orionCurl --url /ngsi-ld/v1/entities/urn:E2?options=simplified +echo +echo + + +--REGEXPECT-- +01. Create a subscription on entity type T +========================================== +HTTP/1.1 201 Created +Content-Length: 0 +Date: REGEX(.*) +Location: /ngsi-ld/v1/subscriptions/urn:ngsi-ld:subs:S1 + + + +02. Create an entity urn:E1, type T, with a JsonProperty V1: "abc" +======================================================================== +HTTP/1.1 201 Created +Content-Length: 0 +Date: REGEX(.*) +Location: /ngsi-ld/v1/entities/urn:E1 + + + +03. Create an entity urn:E2, type T, with a JsonProperty V2: [ "json", "id" ] +==================================================================================== +HTTP/1.1 201 Created +Content-Length: 0 +Date: REGEX(.*) +Location: /ngsi-ld/v1/entities/urn:E2 + + + +04. GET urn:E1 to see V1 +======================== +HTTP/1.1 200 OK +Content-Length: 68 +Content-Type: application/json +Date: REGEX(.*) +Link: Date: Sun, 28 Jan 2024 15:54:08 +0000 Subject: [PATCH 2/3] Array reduction for JsonProperty --- .../orionld/payloadCheck/pCheckAttribute.cpp | 3 +++ .../0000_ngsild/ngsild_json-property.test | 25 +++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/lib/orionld/payloadCheck/pCheckAttribute.cpp b/src/lib/orionld/payloadCheck/pCheckAttribute.cpp index fa2b0eb7f0..fd5dd92fcc 100644 --- a/src/lib/orionld/payloadCheck/pCheckAttribute.cpp +++ b/src/lib/orionld/payloadCheck/pCheckAttribute.cpp @@ -1167,7 +1167,10 @@ static bool pCheckAttributeObject arrayReduce(vocabP); } else if (jsonP != NULL) + { attributeType = JsonProperty; + arrayReduce(jsonP); + } else { // If new attribute and no value field at all - error diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_json-property.test b/test/functionalTest/cases/0000_ngsild/ngsild_json-property.test index 2ccc8ae98e..994c986563 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_json-property.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_json-property.test @@ -36,15 +36,10 @@ accumulatorStart --pretty-print # 02. Create an entity urn:E1, type T, with a JsonProperty V1: "abc" # 03. Create an entity urn:E2, type T, with a JsonProperty V2: [ "vocab", "id" ] # 04. GET urn:E1 to see V1 -# 04b. See urn:E1 in the DB - see "abc" expanded # 05. GET urn:E2 to see V2 -# 05b. See urn:E2 in the DB - see [ "vocab", "id" ] expanded # 06. Dump/Reset accumulator, see urn:E1+V1 and urn:E2+V2 # # 07. GET urn:E2 in simplified format -# 08. Query entities with q=V1==abc => see nothing -# 09. Query entities with q=V1==abc&expandValues=V1,V2 => see urn:E1 -# 10. Query entities with q=V2==id&expandValues=V1,V2 => see urn:E2 # echo '01. Create a subscription on entity type T' @@ -92,6 +87,9 @@ payload='{ "V2": { "json": [ "json", "id" ], "type": "JsonProperty" + }, + "V3": { + "json": [ "json" ] } }' orionCurl --url /ngsi-ld/v1/entities --payload "$payload" @@ -178,7 +176,7 @@ Link: Date: Fri, 2 Feb 2024 20:32:03 +0100 Subject: [PATCH 3/3] After merginf the PR about flattening arrays of one single item, a functest needed a modification --- .../functionalTest/cases/0000_troe/troe_all_attribute_types.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test/functionalTest/cases/0000_troe/troe_all_attribute_types.test b/test/functionalTest/cases/0000_troe/troe_all_attribute_types.test index a254763406..89c11ff1c6 100644 --- a/test/functionalTest/cases/0000_troe/troe_all_attribute_types.test +++ b/test/functionalTest/cases/0000_troe/troe_all_attribute_types.test @@ -92,6 +92,7 @@ opmode,id,valuetype,entityid,subproperties,unitcode,datasetid,text,number,boolea Create,https://uri.etsi.org/ngsi-ld/default-context/property,Number,urn:ngsi-ld:entities:E1,f,,None,,12,,,202REGEX(.*) Create,https://uri.etsi.org/ngsi-ld/default-context/geop,GeoPoint,urn:ngsi-ld:entities:E1,f,,None,,,,,202REGEX(.*) Create,https://uri.etsi.org/ngsi-ld/default-context/relationship,Relationship,urn:ngsi-ld:entities:E1,f,,None,urn:E1,,,,202REGEX(.*) +Create,https://uri.etsi.org/ngsi-ld/default-context/json1,String,urn:ngsi-ld:entities:E1,f,,None,abc,,,,202REGEX(.*) Create,https://uri.etsi.org/ngsi-ld/default-context/json2,Number,urn:ngsi-ld:entities:E1,f,,None,,134,,,202REGEX(.*)