diff --git a/CHANGELOG.md b/CHANGELOG.md index a6f4c689..1cc022a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ Expected: October 2024 ### Features -* List pagination: added sort-by parameter +* List pagination: Added where, sort-by and direction parameter for configured data ### C/CLI-API changes on existing features diff --git a/apps/backend/backend_get.c b/apps/backend/backend_get.c index 636deac0..cdbc07cf 100644 --- a/apps/backend/backend_get.c +++ b/apps/backend/backend_get.c @@ -435,7 +435,8 @@ get_nacm_and_reply(clixon_handle h, /*! Help function for parsing restconf query parameter and setting netconf attribute * - * If not "unbounded", parse and set a numeric value + * Parse and set a uint32 numeric value, + * Accept also a default string (such as none/unbounded) which sets value to 0 * @param[in] h Clixon handle * @param[in] name Name of attribute * @param[in] defaultstr Default string which is accepted and sets value to 0 @@ -514,7 +515,14 @@ list_pagination_hdr(clixon_handle h, * @retval -1 Error * @note pagination uses appending xpath with predicate, eg [position(). - */ - if ((cbpath = cbuf_new()) == NULL){ - clixon_err(OE_UNIX, errno, "cbuf_new"); - goto done; - } - /* This uses xpath. Maybe limit should use parameters */ - if (xpath) - cprintf(cbpath, "%s", xpath); - else - cprintf(cbpath, "/"); -#ifdef NOTYET - if (where) - cprintf(cbpath, "[%s]", where); -#endif - if (offset){ - cprintf(cbpath, "[%u <= position()", offset); - if (limit) - cprintf(cbpath, " and position() < %u", limit+offset); - cprintf(cbpath, "]"); - } - else if (limit) - cprintf(cbpath, "[position() < %u]", limit); - - /* Append predicate to original xpath and replace it */ - xpath2 = cbuf_get(cbpath); - /* specific xpath */ - if ((ret = xmldb_get0(h, db, YB_MODULE, nsc, xpath2?xpath2:"/", 1, wdef, &xret, NULL, &xerr)) < 0) { + /* Build a "predicate" cbuf */ + if ((ret = xmldb_get0(h, db, YB_MODULE, nsc, xpath?xpath:"/", 1, wdef, &xret, NULL, &xerr)) < 0) { if ((cbmsg = cbuf_new()) == NULL){ clixon_err(OE_UNIX, errno, "cbuf_new"); goto done; @@ -672,14 +659,12 @@ get_list_pagination(clixon_handle h, goto done; break; }/* switch content */ - - /* Read state */ - switch (content){ + switch (content){ /* Read state */ case CONTENT_CONFIG: /* config data only */ break; case CONTENT_ALL: /* both config and state */ case CONTENT_NONCONFIG: /* state data only */ - if (list_config == 0) + if (list_config == 0) /* Special handling */ break; if ((ret = get_statedata(h, xpath?xpath:"/", nsc, &xret)) < 0) goto done; @@ -697,6 +682,75 @@ get_list_pagination(clixon_handle h, goto done; } if (list_config){ + /* first processes the "where" parameter (see Section 3.1.1) */ + if (where){ + if (xpath_vec(xret, nsc, "%s[%s]", &xvec, &xlen, xpath?xpath:"/", where) < 0) + goto done; + for (i=0; ii; j--){ + xj = xvec[j]; + if (xml_type(xj) == CX_ELMNT){ + xvec[j] = x; + xvec[i] = xj; + } + break; + } + } + } + /* the "offset" parameter (see Section 3.1.5) + lastly "the "limit" parameter (see Section 3.1.7) */ + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + goto done; + if (limit == 0) + upper = xlen; + else{ + if ((upper = offset+limit) > xlen) + upper = xlen; + } + for (i=offset; i $fexample key "member-id"; description "List of members."; - + ordered-by user; leaf member-id { type string { length "1..80"; diff --git a/test/test_pagination_extra.sh b/test/test_pagination_extra.sh index 731d7178..41aea0d7 100755 --- a/test/test_pagination_extra.sh +++ b/test/test_pagination_extra.sh @@ -218,20 +218,42 @@ fi new "wait backend" wait_backend -# new "A.3.5 The sort-by parameter" +new "A.3.4.1. direction=forwards" +# 17, 13, 11, 7, 5, 3] +# Confusing: forwards means dont change order +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "forwards" "alice171311753" -new "A.3.5.1.1. type is a leaf-list" +new "A.3.4.2. direction=backwards" +# 3, 5, 7, 11, 13, 17] +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "backwards" "alice357111317" + +new "A.3.5.1.1. sort-by type is a leaf-list" # 3,5,7,11,13,17 expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "." "alice357111317" -new "A.3.5.1.2. type is a list and sort-by node is a direct descendent" +new "A.3.5.1.2. sort-by type is a list and sort-by node is a direct descendent" # alice, bob, eric, joe, lin expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "member-id" "alice.*bob.*eric.*joe.*lin" -new "A.3.5.1.3. type is a list and sort-by node is an indirect descendent" +new "A.3.5.1.3. sort-by type is a list and sort-by node is an indirect descendent" # alice, lin, bob, eric, joe expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "stats/joined" "alice.*lin.*bob.*eric.*joe" +new "A.3.6.2. where, match on descendent string containing a substring" +# bob, eric, alice, lin, joe +# Confusing: all match +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" ".[contains (email-address,'@example.com')]" "bob.*eric.*alice.*lin.*joe" + +new "A.3.6.3. where, match on decendent timestamp starting with a substring" +# bob, eric, alice, joe, +# starts-with NYI, replaced with contains +# posts//post[starts-with(timestamp,'2020')] +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "posts/post[contains(timestamp,'2020')]" "bob.*eric.*alice.*joe" + +new "A.3.9.1. All six parameters at once" +# eric, bob +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "//post[contains(timestamp,'2020')]member-idbackwards22" "eric.*bob" + if [ $BE -ne 0 ]; then new "Kill backend" # Check if premature kill