diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 23beb19b70..132ccd3712 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,8 +1,10 @@ ## Fixed Issues: ## New Features: - * Distributed subscriptions: subordinate subscriptions are DELETED when their "father" is deleted + * Distributed subscriptions: subordinate subscriptions are deleted when their "father" is deleted * Support for the URL parameter 'csf' in GET /ngsi-ld/v1/csourceRegistrations * Support for the URL parameter 'orderBy' (must be an attribute) in GET //ngsi-ld/v1/entities, but only if 'local' is set. (This is not NGSI-LD standard. Yet ...) + - Also supporting sorting on entity id, type, and modifiedAt + - One more URL parameter '?reverse=true' to reverse the sorting order ## Notes diff --git a/src/lib/orionld/common/orionldState.h b/src/lib/orionld/common/orionldState.h index d7bb1744ab..2907ce17be 100644 --- a/src/lib/orionld/common/orionldState.h +++ b/src/lib/orionld/common/orionldState.h @@ -156,6 +156,7 @@ typedef struct OrionldUriParams char* notExists; char* metadata; char* orderBy; + bool reverse; bool collapse; bool reset; char* attributeFormat; diff --git a/src/lib/orionld/mhd/mhdConnectionInit.cpp b/src/lib/orionld/mhd/mhdConnectionInit.cpp index 2cdd370ce3..3386269b10 100644 --- a/src/lib/orionld/mhd/mhdConnectionInit.cpp +++ b/src/lib/orionld/mhd/mhdConnectionInit.cpp @@ -945,6 +945,16 @@ MHD_Result orionldUriArgumentGet(void* cbDataP, MHD_ValueKind kind, const char* { orionldState.uriParams.orderBy = (char*) value; } + else if (strcmp(key, "reverse") == 0) + { + if (strcmp(value, "true") == 0) + orionldState.uriParams.reverse = true; + else if (strcmp(key, "false") != 0) + { + orionldError(OrionldBadRequestData, "Invalid value for uri parameter /reverse/", value, 400); + return MHD_YES; + } + } else if (strcmp(key, "collapse") == 0) { if (strcmp(value, "true") == 0) diff --git a/src/lib/orionld/mongoc/mongocEntitiesQuery.cpp b/src/lib/orionld/mongoc/mongocEntitiesQuery.cpp index 5904264812..1dead2f00e 100644 --- a/src/lib/orionld/mongoc/mongocEntitiesQuery.cpp +++ b/src/lib/orionld/mongoc/mongocEntitiesQuery.cpp @@ -695,30 +695,46 @@ KjNode* mongocEntitiesQuery bson_t sortDoc; int limit = orionldState.uriParams.limit; int offset = orionldState.uriParams.offset; + int sortOrder = 1; + + if (orionldState.uriParams.reverse == true) + sortOrder = -1; bson_init(&sortDoc); - if (orderBy == NULL) - bson_append_int32(&sortDoc, "creDate", 7, 1); + if ((orderBy == NULL) || (strcmp(orderBy, "createdAt") == 0)) + bson_append_int32(&sortDoc, "creDate", 7, sortOrder); else { - char* longName = orionldAttributeExpand(orionldState.contextP, orderBy, true, NULL); - int len = strlen(longName) + 14; - char* path = kaAlloc(&orionldState.kalloc, len); + char pathV[32]; + char* path = pathV; + int len = sizeof(pathV); + + if ((strcmp(orderBy, "id") == 0) || (strcmp(orderBy, "type") == 0)) + len = snprintf(path, len, "_id.%s", orderBy); + else if (strcmp(orderBy, "modifiedAt") == 0) + len = snprintf(path, len, "%s", "modDate"); + else + { + char* longName = orionldAttributeExpand(orionldState.contextP, orderBy, true, NULL); - len = snprintf(path, len - 1, "attrs.%s.value", longName); + len = strlen(longName) + 14; + path = kaAlloc(&orionldState.kalloc, len); - // Replacing dots for '=' - including the last one (should not be replaced) - dotForEq(&path[6]); + len = snprintf(path, len - 1, "attrs.%s.value", longName); - // Reversing the '=' of ".value" to a dot - path[len - 6] = '.'; + // Replacing dots for '=' - including the last one (should not be replaced) + dotForEq(&path[6]); + + // Reversing the '=' of ".value" to a dot + path[len - 6] = '.'; + } LM_T(LmtMongoc, ("Ordering by '%s' (%d letters)", path, len)); - bson_append_int32(&sortDoc, path, len, 1); + bson_append_int32(&sortDoc, path, len, sortOrder); } - bson_append_int32(&sortDoc, "_id.id", 6, 1); + bson_append_int32(&sortDoc, "_id.id", 6, sortOrder); // Secondary sort on Entity ID bson_append_document(&options, "sort", 4, &sortDoc); bson_destroy(&sortDoc); diff --git a/src/lib/orionld/service/orionldServiceInit.cpp b/src/lib/orionld/service/orionldServiceInit.cpp index e2a3dc5527..ed970b25cc 100644 --- a/src/lib/orionld/service/orionldServiceInit.cpp +++ b/src/lib/orionld/service/orionldServiceInit.cpp @@ -245,6 +245,7 @@ static void restServicePrepare(OrionLdRestService* serviceP, OrionLdRestServiceS serviceP->uriParams |= ORIONLD_URIPARAM_ONLYIDS; serviceP->uriParams |= ORIONLD_URIPARAM_ENTITYMAP; serviceP->uriParams |= ORIONLD_URIPARAM_ORDERBY; + serviceP->uriParams |= ORIONLD_URIPARAM_REVERSE; } else if (serviceP->serviceRoutine == orionldGetEntity) { diff --git a/src/lib/orionld/types/OrionLdRestService.h b/src/lib/orionld/types/OrionLdRestService.h index 0c3f212157..0e8c725c8b 100644 --- a/src/lib/orionld/types/OrionLdRestService.h +++ b/src/lib/orionld/types/OrionLdRestService.h @@ -158,6 +158,7 @@ typedef struct OrionLdRestServiceSimplifiedVector #define ORIONLD_URIPARAM_EXPAND_VALUES (UINT64_C(1) << 41) #define ORIONLD_URIPARAM_KIND (UINT64_C(1) << 42) #define ORIONLD_URIPARAM_ORDERBY (UINT64_C(1) << 43) +#define ORIONLD_URIPARAM_REVERSE (UINT64_C(1) << 44) diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_orderBy.test b/test/functionalTest/cases/0000_ngsild/ngsild_orderBy.test index 16919ae788..feb98ddf9e 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_orderBy.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_orderBy.test @@ -49,6 +49,11 @@ done # 01. GET entities ordered by 'relevance' # 02. GET entities ordered by 'relevance', offset 5 # 03. GET entities without specific order (createdAt is default) +# 04. GET entities ordered by 'relevance' but in reverse +# 05. GET entities ordered by 'type' (and then 'id') +# 06. GET entities ordered by 'id' +# 07. GET entities ordered by 'id' but in reverse +# 08. GET entities ordered by 'idx' (attribute that does not exist) # echo "01. GET entities ordered by 'relevance'" @@ -72,6 +77,41 @@ echo echo +echo "04. GET entities ordered by 'relevance' but in reverse" +echo "======================================================" +orionCurl --url "/ngsi-ld/v1/entities?local=true&orderBy=relevance&limit=5&reverse=true" +echo +echo + + +echo "05. GET entities ordered by 'type' (and then 'id')" +echo "==================================================" +orionCurl --url "/ngsi-ld/v1/entities?local=true&orderBy=type&limit=5" +echo +echo + + +echo "06. GET entities ordered by 'id'" +echo "================================" +orionCurl --url "/ngsi-ld/v1/entities?local=true&orderBy=id&limit=5" +echo +echo + + +echo "07. GET entities ordered by 'id' but in reverse" +echo "===============================================" +orionCurl --url "/ngsi-ld/v1/entities?local=true&orderBy=id&limit=5&reverse=true" +echo +echo + + +echo "08. GET entities ordered by 'idx' (attribute that does not exist)" +echo "=================================================================" +orionCurl --url "/ngsi-ld/v1/entities?local=true&orderBy=idx&limit=5" +echo +echo + + --REGEXPECT-- 01. GET entities ordered by 'relevance' ======================================= @@ -229,6 +269,266 @@ Link: