Skip to content

Commit

Permalink
Implemented expansion of RHS in 'q' for values of LHS VocabularyPrope…
Browse files Browse the repository at this point in the history
…rty (hinted by URL param 'expandValues')
  • Loading branch information
kzangeli committed Jan 20, 2024
1 parent 90e14a8 commit d79b1dc
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CHANGES_NEXT_RELEASE
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ Fixed Issue:
* #1535 No matching with 'q' when matching subscriptions for deletion of an entity

New Features:
* Support for VocabularyProperty (highly untested and 'q' expansions for vocab-properties is not yet implemented)
* Support for VocabularyProperty
* Support for the new URL parameter "format" for output formats (normalized, concise, simplified)
4 changes: 4 additions & 0 deletions src/lib/orionld/common/orionldState.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ extern "C"
#include "orionld/types/Verb.h" // Verb
#include "orionld/types/OrionldRenderFormat.h" // OrionldRenderFormat
#include "orionld/types/OrionldMimeType.h" // MimeType
#include "orionld/types/QNode.h" // QNode
#include "orionld/types/ApiVersion.h" // ApiVersion
#include "orionld/common/performance.h" // REQUEST_PERFORMANCE
#include "orionld/kjTree/kjTreeLog.h" // Because it is so often used but then removed again ...
Expand Down Expand Up @@ -129,6 +130,7 @@ typedef struct OrionldUriParams
int limit;
bool count;
char* q;
char* expandValues;
char* qCopy;
char* mq;
char* geometry;
Expand Down Expand Up @@ -263,6 +265,7 @@ typedef struct OrionldStateIn
StringArray idList;
StringArray typeList;
StringArray attrList;
StringArray expandValuesList;

// Entity Map
EntityMap* entityMap;
Expand Down Expand Up @@ -343,6 +346,7 @@ typedef struct OrionldConnectionState
OrionldContext* contextP;
ApiVersion apiVersion;
int requestNo;
QNode* qVariable; // Aux for qLex - to know whether a string should be expanded (VocabularyProperty)

KjNode* geoAttr[10]; // Preallocated array of GeoProperties
KjNode** geoAttrV; // Array of GeoProperty attributes
Expand Down
5 changes: 5 additions & 0 deletions src/lib/orionld/mhd/mhdConnectionInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,11 @@ MHD_Result orionldUriArgumentGet(void* cbDataP, MHD_ValueKind kind, const char*
orionldState.uriParams.options = (char*) value;
orionldState.uriParams.mask |= ORIONLD_URIPARAM_OPTIONS;
}
else if (strcmp(key, "expandValues") == 0)
{
orionldState.uriParams.expandValues = (char*) value;
orionldState.uriParams.mask |= ORIONLD_URIPARAM_EXPAND_VALUES;
}
else if (strcmp(key, "format") == 0)
{
orionldState.uriParams.format = (char*) value;
Expand Down
37 changes: 37 additions & 0 deletions src/lib/orionld/mhd/mhdConnectionTreat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,42 @@ static bool pCheckUrlPathAttributeName(void)



// -----------------------------------------------------------------------------
//
// pCheckExpandValuesParam -
//
static bool pCheckExpandValuesParam(void)
{
if (orionldState.uriParams.expandValues == NULL)
return true;

int items = commaCount(orionldState.uriParams.expandValues) + 1;
char* arraysDup = kaStrdup(&orionldState.kalloc, orionldState.uriParams.expandValues); // To not destroy the original value

orionldState.in.expandValuesList.items = items;
orionldState.in.expandValuesList.array = (char**) kaAlloc(&orionldState.kalloc, sizeof(char*) * items);

if (orionldState.in.expandValuesList.array == NULL)
{
LM_E(("Out of memory (allocating an /expandValues/ array of %d char pointers)", items));
orionldError(OrionldInternalError, "Out of memory", "allocating the array for /expandValues/ URI param", 500);
return false;
}

int splitItems = kStringSplit(arraysDup, ',', orionldState.in.expandValuesList.array, items);

if (splitItems != items)
{
LM_E(("kStringSplit didn't find exactly %d items (it found %d)", items, splitItems));
orionldError(OrionldInternalError, "Internal Error", "kStringSplit does not agree with commaCount", 500);
return false;
}

return true;
}



// -----------------------------------------------------------------------------
//
// uriParamExpansion -
Expand All @@ -845,6 +881,7 @@ static bool uriParamExpansion(void)
if (pCheckUriParamGeometryProperty() == false) return false;
if (pCheckPayloadEntityType() == false) return false;
if (pCheckUrlPathAttributeName() == false) return false;
if (pCheckExpandValuesParam() == false) return false; // This one isn't expanded, it's just a StringArray of attribute names for VocabularyProperty

// Can't do anything about 'q' - needs to be parsed first - expansion done in 'orionld/q/qParse.cpp'

Expand Down
26 changes: 25 additions & 1 deletion src/lib/orionld/q/qLex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "orionld/types/QNode.h" // QNode
#include "orionld/common/orionldState.h" // orionldState
#include "orionld/common/dateTime.h" // dateTimeFromString
#include "orionld/context/orionldContextItemExpand.h" // orionldContextItemExpand
#include "orionld/q/qNode.h" // qNode
#include "orionld/q/qNodeType.h" // qNodeType
#include "orionld/q/qLexCheck.h" // qLexCheck
Expand All @@ -44,7 +45,24 @@ static QNode* qStringPush(QNode* prev, char* stringValue)
{
QNode* qNodeP = qNode(QNodeStringValue);

LM_T(LmtQ, ("Pushing a String: '%s'", stringValue));
LM_T(LmtQ, ("Pushing a String: '%s'", stringValue));
if (orionldState.qVariable != NULL)
{
LM_T(LmtQ, ("For Variable: '%s'", orionldState.qVariable->value.s));
if (orionldState.uriParams.expandValues != NULL)
{
LM_T(LmtQ, ("And, expandValues is: '%s'", orionldState.uriParams.expandValues));
for (int ix = 0; ix < orionldState.in.expandValuesList.items; ix++)
{
LM_T(LmtQ, ("expandValuesList[%d]: '%s'", ix, orionldState.in.expandValuesList.array[ix]));
if (strcmp(orionldState.qVariable->value.s, orionldState.in.expandValuesList.array[ix]) == 0)
{
LM_T(LmtQ, ("The string '%s' needs to be expanded", stringValue));
stringValue = orionldContextItemExpand(orionldState.contextP, stringValue, true, NULL);
}
}
}
}

if (orionldState.useMalloc == false)
qNodeP->value.s = stringValue;
Expand Down Expand Up @@ -179,6 +197,12 @@ static QNode* qTermPush(QNode* prev, char* term, bool* lastTermIsTimestampP, cha

QNode* qNodeP = qNode(type);

if (type == QNodeVariable)
{
orionldState.qVariable = qNodeP;
LM_T(LmtQ, ("'%s' IS a VARIABLE", term));
}

if (dateTime == true)
{
LM_T(LmtQ, ("'%s' might be a DateTime", term));
Expand Down
3 changes: 2 additions & 1 deletion src/lib/orionld/q/qParse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ extern "C"
#include "orionld/common/orionldState.h" // orionldState
#include "orionld/context/orionldAttributeExpand.h" // orionldAttributeExpand
#include "orionld/context/orionldSubAttributeExpand.h" // orionldSubAttributeExpand
#include "orionld/context/orionldContextItemExpand.h" // orionldContextItemExpand
#include "orionld/q/qVariableFix.h" // qVariableFix
#include "orionld/q/qClone.h" // qClone
#include "orionld/q/qNodeType.h" // qNodeType
Expand Down Expand Up @@ -188,7 +189,7 @@ QNode* qParse(QNode* qLexList, QNode* endNodeP, bool forDb, bool qToDbModel, cha
case QNodeTrueValue:
case QNodeFalseValue:
case QNodeRegexpValue:
if (compOpP == NULL) // Still no operatore - this is on the Left-Hand side - saved for later
if (compOpP == NULL) // Still no operator - this is on the Left-Hand side - saved for later
{
leftP = qLexP;
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/orionld/service/orionldServiceInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ static void restServicePrepare(OrionLdRestService* serviceP, OrionLdRestServiceS
serviceP->uriParams |= ORIONLD_URIPARAM_IDPATTERN;
serviceP->uriParams |= ORIONLD_URIPARAM_ATTRS;
serviceP->uriParams |= ORIONLD_URIPARAM_Q;
serviceP->uriParams |= ORIONLD_URIPARAM_EXPAND_VALUES;
serviceP->uriParams |= ORIONLD_URIPARAM_CSF;
serviceP->uriParams |= ORIONLD_URIPARAM_GEOREL;
serviceP->uriParams |= ORIONLD_URIPARAM_GEOMETRY;
Expand Down
1 change: 1 addition & 0 deletions src/lib/orionld/types/OrionLdRestService.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ typedef struct OrionLdRestServiceSimplifiedVector
#define ORIONLD_URIPARAM_ONLYIDS (UINT64_C(1) << 38)
#define ORIONLD_URIPARAM_ENTITYMAP (UINT64_C(1) << 39)
#define ORIONLD_URIPARAM_FORMAT (UINT64_C(1) << 40)
#define ORIONLD_URIPARAM_EXPAND_VALUES (UINT64_C(1) << 41)



Expand Down
77 changes: 77 additions & 0 deletions test/functionalTest/cases/0000_ngsild/ngsild_vocab-property.test
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ accumulatorStart --pretty-print
# 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'
Expand Down Expand Up @@ -134,6 +137,27 @@ echo
echo


echo "08. Query entities with q=V1==abc => see nothing"
echo "================================================"
orionCurl --url /ngsi-ld/v1/entities?q=V1==%22abc%22
echo
echo


echo "09. Query entities with q=V1==abc&expandValues=V1,V2 => see urn:E1"
echo "=================================================================="
orionCurl --url '/ngsi-ld/v1/entities?q=V1==%22abc%22&expandValues=V1,V2'
echo
echo


echo "10. Query entities with q=V2==id&expandValues=V1,V2 => see urn:E2"
echo "================================================================="
orionCurl --url '/ngsi-ld/v1/entities?q=V2==%22id%22&expandValues=V1,V2'
echo
echo


--REGEXPECT--
01. Create a subscription on entity type T
==========================================
Expand Down Expand Up @@ -343,6 +367,59 @@ Link: <https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-contextREGEX(.*)
}


08. Query entities with q=V1==abc => see nothing
================================================
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json
Date: REGEX(.*)

[]


09. Query entities with q=V1==abc&expandValues=V1,V2 => see urn:E1
==================================================================
HTTP/1.1 200 OK
Content-Length: 77
Content-Type: application/json
Date: REGEX(.*)
Link: <https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-contextREGEX(.*)

[
{
"V1": {
"type": "VocabularyProperty",
"vocab": "abc"
},
"id": "urn:E1",
"type": "T"
}
]


10. Query entities with q=V2==id&expandValues=V1,V2 => see urn:E2
=================================================================
HTTP/1.1 200 OK
Content-Length: 86
Content-Type: application/json
Date: REGEX(.*)
Link: <https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-contextREGEX(.*)

[
{
"V2": {
"type": "VocabularyProperty",
"vocab": [
"vocab",
"id"
]
},
"id": "urn:E2",
"type": "T"
}
]


--TEARDOWN--
brokerStop CB
accumulatorStop
Expand Down

0 comments on commit d79b1dc

Please sign in to comment.