1
0
Fork 0

Feature/cpp aql reverse (#4911)

This commit is contained in:
Wilfried Goesgens 2018-03-23 09:54:37 +01:00 committed by Jan
parent 7e53d3ed75
commit a16d4b0109
13 changed files with 652 additions and 181 deletions

View File

@ -574,6 +574,10 @@ Alternatively, *search* and *replace* can be specified in a combined value.
- **value** (string): a string
- **mapping** (object): a lookup map with search strings as keys and replacement
strings as values. Empty strings and *null* as values remove matches.
Please note that no sequence of search strings can be warrantied by this;
Means, if you have overlapping search results, one time the first may win,
another time the second. If you need to ensure the precedence of the sequence
choose the array based invocation method.
- **limit** (number, *optional*): cap the number of replacements to this value
- returns **substitutedString** (string): a new string with matches replaced
(or removed)

View File

@ -707,7 +707,7 @@ Building will fail if resources aren't cleaned.
However, if you intend a set of OUTPUT and RUN to demonstrate interactively and share generated *ids*, you have to use an alphabetical
sortable naming scheme so they're executed in sequence. Using `<modulename>_<sequencenumber>[a|b|c|d]_thisDoesThat` seems to be a good scheme.
- OUTPUT is intended to create samples that the users can cut'n'paste into their arangosh. Its used for javascript api documentation.
- EXAMPLE_ARANGOSH_OUTPUT is intended to create samples that the users can cut'n'paste into their arangosh. Its used for javascript api documentation.
* wrapped lines:
Lines starting with a pipe (`/// |`) are joined together with the next following line.
You have to use this if you want to execute loops, functions or commands which shouldn't be torn apart by the framework.
@ -727,7 +727,7 @@ sortable naming scheme so they're executed in sequence. Using `<modulename>_<seq
/// | someLongStatement()
/// ~ // xpError(ERROR_ARANGO_DOCUMENT_KEY_UNEXPECTED)
- RUN is intended to be pasted into a unix shell with *cURL* to demonstrate how the REST-HTTP-APIs work.
- EXAMPLE_ARANGOSH_RUN is intended to be pasted into a unix shell with *cURL* to demonstrate how the REST-HTTP-APIs work.
The whole chunk of code is executed at once, and is expected **not to throw**.
You should use **assert(condition)** to ensure the result is what you've expected.
The *body* can be a string, or a javascript object which is then represented in JSON format.
@ -739,14 +739,14 @@ sortable naming scheme so they're executed in sequence. Using `<modulename>_<seq
* output the plain text to dump to the user: `logRawResponse(response);`
* dump the reply to the errorlog for testing (will mark run as failed): `logErrorResponse(response);`
- AQL is intended to contain AQL queries that can be pasted into arangosh or the webinterfaces query editor.
- EXAMPLE_AQL is intended to contain AQL queries that can be pasted into arangosh or the webinterfaces query editor.
Usually this query references an example dataset generator in `js/common/modules/@arangodb/examples/examples.js`
which the users can also invoke to generate the data in their installation.
This sort of example consists of three parts:
- @DATASET{datasetName} - the name of the dataset in the above mentioned `examples.js` to be instanciated before executing this query.
- @EXPLAIN{TRUE|FALSE} - print execution plan of the AQL query. The default is `FALSE`.
- A following AQL query which may either end at the end of the comment block, or at the optional next section:
- @BV - verbatim object containing the bind parameters to be passed into the query. Will also be put into the generated snippet.
- @DATASET{datasetName} - (optional) the name of the dataset in the above mentioned `examples.js` to be instanciated before executing this query.
- @EXPLAIN{TRUE|FALSE} - (optional) print execution plan of the AQL query. The default is `FALSE`.
- A following AQL query which may either end at the end of the comment block, or at the next section:
- @BV - (optional) verbatim object containing the bind parameters to be passed into the query. Will also be put into the generated snippet.
Swagger integration
===================

View File

@ -259,7 +259,7 @@ void AqlFunctionFeature::addStringFunctions() {
add({"FIND_FIRST", ".,.|.,.", true, false, true, true, &Functions::FindFirst});
add({"FIND_LAST", ".,.|.,.", true, false, true, true, &Functions::FindLast});
add({"SPLIT", ".|.,.", true, false, true, true, &Functions::Split});
add({"SUBSTITUTE", ".,.|.,.", true, false, true, true});
add({"SUBSTITUTE", ".,.|.,.", true, false, true, true, &Functions::Substitute});
add({"MD5", ".", true, false, true, true, &Functions::Md5});
add({"SHA1", ".", true, false, true, true, &Functions::Sha1});
add({"SHA512", ".", true, false, true, true, &Functions::Sha512});
@ -356,7 +356,7 @@ void AqlFunctionFeature::addListFunctions() {
add({"SLICE", ".,.|.", true, false, true, true,
&Functions::Slice});
add({"REVERSE", ".", true, false, true,
true}); // note: REVERSE() can be applied on strings, too
true, &Functions::Reverse});
add({"FIRST", ".", true, false, true, true,
&Functions::First});
add({"LAST", ".", true, false, true, true,

File diff suppressed because it is too large Load Diff

View File

@ -144,6 +144,8 @@ struct Functions {
VPackFunctionParameters const&);
static AqlValue FindLast(arangodb::aql::Query*, transaction::Methods*,
VPackFunctionParameters const&);
static AqlValue Reverse(arangodb::aql::Query*, transaction::Methods*,
VPackFunctionParameters const&);
static AqlValue First(arangodb::aql::Query*, transaction::Methods*,
VPackFunctionParameters const&);
static AqlValue Last(arangodb::aql::Query*, transaction::Methods*,
@ -169,6 +171,9 @@ struct Functions {
static AqlValue Substring(arangodb::aql::Query*,
transaction::Methods*,
VPackFunctionParameters const&);
static AqlValue Substitute(arangodb::aql::Query*,
transaction::Methods*,
VPackFunctionParameters const&);
static AqlValue Left(arangodb::aql::Query*,
transaction::Methods*,
VPackFunctionParameters const&);

View File

@ -38,6 +38,7 @@
"ERROR_SHUTTING_DOWN" : { "code" : 30, "message" : "shutdown in progress" },
"ERROR_ONLY_ENTERPRISE" : { "code" : 31, "message" : "only enterprise version" },
"ERROR_RESOURCE_LIMIT" : { "code" : 32, "message" : "resource limit exceeded" },
"ERROR_ARANGO_ICU_ERROR" : { "code" : 33, "message" : "icu error: %s" },
"ERROR_HTTP_BAD_PARAMETER" : { "code" : 400, "message" : "bad parameter" },
"ERROR_HTTP_UNAUTHORIZED" : { "code" : 401, "message" : "unauthorized" },
"ERROR_HTTP_FORBIDDEN" : { "code" : 403, "message" : "forbidden" },

View File

@ -624,7 +624,7 @@ function ahuacatlCollectionCountTestSuite () {
setUp : function () {
db._drop(cn);
c = db._create(cn, { numberOfShards: 4 });
let docs = []
let docs = [];
for (var i = 1; i <= 1000; ++i) {
docs.push({ _key: "test" + i });

View File

@ -978,7 +978,12 @@ function ahuacatlStringFunctionsTestSuite () {
[ 'the quick brown foxx jumped over the lazy dog', 'the quick brown foxx jumped over the lazy dog', 'the', 'a', 0 ],
[ 'a quick brown foxx jumped over a lazy dog', 'the quick brown foxx jumped over the lazy dog', [ 'the' ], [ 'a' ] ],
[ 'a quick brown foxx jumped over the lazy dog', 'the quick brown foxx jumped over the lazy dog', [ 'the' ], [ 'a' ], 1 ],
[ 'the quick brown foxx jumped over the lazy dog', 'the quick brown foxx jumped over the lazy dog', 'thisIsNotThere', 'a'],
[ 'the quick brown foxx jumped over the lazy dog', 'the quick brown foxx jumped over the lazy dog', {'thisIsNotThere': 'a'}],
[ 'the quick brown foxx jumped over the lazy dog', 'the quick brown foxx jumped over the lazy dog', ['thisIsNotThere', 'thisIsAlsoNotThere'], ['a', 'b'], 0 ],
[ 'mötör quick brown mötör jumped over the lazy dog', 'the quick brown foxx jumped over the lazy dog', [ 'over', 'the', 'foxx' ], 'mötör', 2 ],
[ 'apfela', 'rabarbara', ['barbara', 'rabarbar'], ['petra', 'apfel']],
[ 'rapetra', 'rabarbara', ['barbara', 'bar'], ['petra', 'foo']],
[ 'AbCdEF', 'aBcDef', { a: 'A', B: 'b', c: 'C', D: 'd', e: 'E', f: 'F' } ],
[ 'AbcDef', 'aBcDef', { a: 'A', B: 'b', c: 'C', D: 'd', e: 'E', f: 'F' }, 2 ],
[ 'aBcDef', 'aBcDef', { a: 'A', B: 'b', c: 'C', D: 'd', e: 'E', f: 'F' }, 0 ],
@ -999,7 +1004,10 @@ function ahuacatlStringFunctionsTestSuite () {
for (i = 1; i < n; ++i) {
args.push(JSON.stringify(value[i]));
}
assertEqual([ expected ], getQueryResults('RETURN SUBSTITUTE(' + args.join(', ') + ')'), value);
var nuResults = getQueryResults('RETURN SUBSTITUTE(' + args.join(', ') + ')');
var jsResults = getQueryResults('RETURN NOOPT(V8(SUBSTITUTE(' + args.join(', ') + ')))');
assertEqual([ expected ], nuResults, value);
assertEqual(jsResults, nuResults, value);
});
},
@ -1010,6 +1018,8 @@ function ahuacatlStringFunctionsTestSuite () {
testSubstituteInvalid: function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, 'RETURN SUBSTITUTE()');
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, `RETURN SUBSTITUTE('foo', 'bar', 'baz', 2, 2)`);
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, 'RETURN NOOPT(V8(SUBSTITUTE()))');
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, `RETURN NOOPT(V8(SUBSTITUTE('foo', 'bar', 'baz', 2, 2)))`);
},
// //////////////////////////////////////////////////////////////////////////////

View File

@ -615,6 +615,22 @@ function ahuacatlFunctionsTestSuite () {
assertEqual([ expected[0].reverse() ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test reverse function
////////////////////////////////////////////////////////////////////////////////
testReverse5 : function () {
let val = [
['eÜrCyeltÖM', 'MÖtleyCrÜe'],
['狗懶了過跳狸狐色棕的捷敏', '敏捷的棕色狐狸跳過了懶狗']
];
for (let i = 0; i < 2; i++) {
let v = val[i];
assertEqual([v[0]], getQueryResults('RETURN REVERSE(@v)', {v: v[1]}));
assertEqual([v[0]], getQueryResults('RETURN NOOPT(V8(REVERSE(@v)))', {v: v[1]}));
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test reverse function
////////////////////////////////////////////////////////////////////////////////
@ -628,6 +644,64 @@ function ahuacatlFunctionsTestSuite () {
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN REVERSE({ })");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test reverse V8 function
////////////////////////////////////////////////////////////////////////////////
testReverseV8_1 : function () {
var expected = [ [ ] ];
var actual = getQueryResults("RETURN NOOPT(V8(REVERSE([ ])))");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test reverse V8 function
////////////////////////////////////////////////////////////////////////////////
testReverseV8_2 : function () {
var expected = [ [ "fox" ] ];
var actual = getQueryResults("RETURN NOOPT(V8(REVERSE([ \"fox\" ])))");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test reverse V8 function
////////////////////////////////////////////////////////////////////////////////
testReverseV8_3 : function () {
var expected = [ [ false, [ "fox", "jumped" ], { "quick" : "brown" }, "the" ] ];
var actual = getQueryResults("RETURN NOOPT(V8(REVERSE([ \"the\", { \"quick\" : \"brown\" }, [ \"fox\", \"jumped\" ], false ])))");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test reverse V8 function
////////////////////////////////////////////////////////////////////////////////
testReverseV8_4 : function () {
var expected = [ [ 1, 2, 3 ] ];
var actual = getQueryResults("LET a = (FOR i IN [ 1, 2, 3 ] RETURN i) LET b = NOOPT(V8(REVERSE(a))) RETURN a");
// make sure reverse does not modify the original value
assertEqual(expected, actual);
actual = getQueryResults("LET a = (FOR i IN [ 1, 2, 3] RETURN i) LET b = NOOPT(V8(REVERSE(a))) RETURN b");
assertEqual([ expected[0].reverse() ], actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test reverse V8 function
////////////////////////////////////////////////////////////////////////////////
testReverseV8_Invalid : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(V8(REVERSE()))");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(V8(REVERSE([ ], [ ])))");
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(REVERSE(null)))");
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(REVERSE(true)))");
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(REVERSE(4)))");
assertQueryWarningAndNull(errors.ERROR_QUERY_ARRAY_EXPECTED.code, "RETURN NOOPT(V8(REVERSE({ })))");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unique function
////////////////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertTrue */
/*global assertEqual, assertTrue, assertFalse */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, subqueries in cluster
@ -109,10 +109,10 @@ function clusterSubqueriesTestSuite () {
RETURN sub[*].foo
`;
let c = db._query(q).toArray();
assertEqual(c.length, 10) // we have 10 values for X
assertEqual(c.length, 10); // we have 10 values for X
let seen = new Set();
for (let d of c) {
assertEqual(d.length, 5) // we have 5 values for each x
assertEqual(d.length, 5); // we have 5 values for each x
let first = d[0];
seen.add(first);
for (let q of d) {

View File

@ -32,6 +32,7 @@ ERROR_DEADLOCK,29,"deadlock detected","Will be raised when a deadlock is detecte
ERROR_SHUTTING_DOWN,30,"shutdown in progress","Will be raised when a call cannot succeed because a server shutdown is already in progress."
ERROR_ONLY_ENTERPRISE,31,"only enterprise version","Will be raised when an enterprise-feature is requested from the community edition."
ERROR_RESOURCE_LIMIT,32,"resource limit exceeded","Will be raised when the resources used by an operation exceed the configured maximum value."
ERROR_ARANGO_ICU_ERROR,33,"icu error: %s","will be raised if icu operations failed"
################################################################################
## HTTP error status codes

View File

@ -37,6 +37,7 @@ void TRI_InitializeErrorMessages() {
REG_ERROR(ERROR_SHUTTING_DOWN, "shutdown in progress");
REG_ERROR(ERROR_ONLY_ENTERPRISE, "only enterprise version");
REG_ERROR(ERROR_RESOURCE_LIMIT, "resource limit exceeded");
REG_ERROR(ERROR_ARANGO_ICU_ERROR, "icu error: %s");
REG_ERROR(ERROR_HTTP_BAD_PARAMETER, "bad parameter");
REG_ERROR(ERROR_HTTP_UNAUTHORIZED, "unauthorized");
REG_ERROR(ERROR_HTTP_FORBIDDEN, "forbidden");

View File

@ -158,6 +158,11 @@ constexpr int TRI_ERROR_ONLY_ENTERPRISE
/// configured maximum value.
constexpr int TRI_ERROR_RESOURCE_LIMIT = 32;
/// 33: ERROR_ARANGO_ICU_ERROR
/// "icu error: %s"
/// will be raised if icu operations failed
constexpr int TRI_ERROR_ARANGO_ICU_ERROR = 33;
/// 400: ERROR_HTTP_BAD_PARAMETER
/// "bad parameter"
/// Will be raised when the HTTP request does not fulfill the requirements.