1
0
Fork 0

added TYPENAME() and HASH() functions

This commit is contained in:
jsteemann 2016-05-11 23:54:00 +02:00
parent 9b6467dc60
commit d4cb93fb9c
15 changed files with 508 additions and 141 deletions

View File

@ -16,6 +16,19 @@ AQL offers the following functions to let the user control the flow of operation
Finally, AQL supports the following functions that do not belong to any of the other
function categories:
- *HASH(value)*: Calculates a hash value for *value*. *value* is not required to be a
string, but can have any data type. The calculated hash value will take the data type
of *value* into account, so for example the number *1* and the string *"1"* will have
different hash values. For arrays the hash values will be creared if the arrays contain
exactly the same values (including value types) in the same order. For objects the same
hash values will be created if the objects have exactly the same attribute names and
values (including value types). The order in which attributes appear inside objects
is not important for hashing.
The hash value returned by this function is a number. The hash algorithm is not guaranteed
to remain the same in future versions of ArangoDB. The hash values should therefore be
used only for temporary calculations, e.g. to compare if two documents are the same, or
for grouping values in queries.
- *COLLECTIONS()*: Returns an array of collections. Each collection is returned as a document
with attributes *name* and *_id*

View File

@ -50,7 +50,7 @@ not not 1 // true
converted to the number *0*.
- An object / document is converted to the number *0*.
An unary plus will also try to cast to a number, but `TO_NUMBER()` is the preferred way:
A unary plus will also cast to a number, but `TO_NUMBER()` is the preferred way:
```js
+'5' // 5
+[8] // 8
@ -122,3 +122,6 @@ The following type check functions are available:
in a date function. This includes partial dates such as *2015* or *2015-10* and
strings containing invalid dates such as *2015-02-31*. The function will return
false for all non-string values, even if some of them may be usable in date functions.
- *TYPENAME(value)*: Returns the data type name of *value*. The data type name can
be either *null*, *bool*, *number*, *string*, *array* or *object*.

View File

@ -130,6 +130,34 @@ struct AqlValue final {
setType(AqlValueType::VPACK_INLINE);
}
// construct from char* and length
AqlValue(char const* value, size_t length) {
if (length == 0) {
// empty string
_data.internal[0] = 0x40;
setType(AqlValueType::VPACK_INLINE);
return;
}
if (length < sizeof(_data.internal) - 1) {
// short string... can store it inline
_data.internal[0] = 0x40 + length;
memcpy(_data.internal + 1, value, length);
setType(AqlValueType::VPACK_INLINE);
} else if (length <= 126) {
// short string... cannot store inline, but we don't need to
// create a full-features Builder object here
_data.buffer = new arangodb::velocypack::Buffer<uint8_t>(length + 1);
_data.buffer->push_back(0x40 + length);
_data.buffer->append(value, length);
setType(AqlValueType::VPACK_MANAGED);
} else {
// long string
VPackBuilder builder;
builder.add(VPackValue(value));
initFromSlice(builder.slice());
}
}
// construct from std::string
explicit AqlValue(std::string const& value) {
if (value.empty()) {

View File

@ -120,6 +120,8 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
false, true, true, &Functions::IsObject)},
{"IS_DATESTRING", Function("IS_DATESTRING", "AQL_IS_DATESTRING", ".", true,
true, false, true, true)},
{"TYPENAME", Function("TYPENAME", "AQL_TYPENAME", ".", true,
true, false, true, true)},
// type cast functions
{"TO_NUMBER", Function("TO_NUMBER", "AQL_TO_NUMBER", ".", true, true, false,
@ -173,6 +175,8 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
&Functions::Md5)},
{"SHA1", Function("SHA1", "AQL_SHA1", "s", true, true, false, true, true,
&Functions::Sha1)},
{"HASH", Function("HASH", "AQL_HASH", ".", true, true, false, true, true,
&Functions::Hash)},
{"RANDOM_TOKEN", Function("RANDOM_TOKEN", "AQL_RANDOM_TOKEN", "n", false,
false, true, true, true)},
@ -482,9 +486,6 @@ std::unordered_map<std::string, Function const> const Executor::FunctionNames{
/// an array / object literal "big" and pulling it out of the expression
size_t const Executor::DefaultLiteralSizeThreshold = 32;
/// @brief maxmium number of array members created from range accesses
int64_t const Executor::MaxRangeAccessArraySize = 1024 * 1024 * 32;
/// @brief creates an executor
Executor::Executor(int64_t literalSizeThreshold)
: _buffer(nullptr),

View File

@ -175,8 +175,6 @@ class Executor {
/// an array / object literal "big" and pulling it out of the expression
static size_t const DefaultLiteralSizeThreshold;
/// @brief maxmium number of array members created from range accesses
static int64_t const MaxRangeAccessArraySize;
};
}
}

View File

@ -884,7 +884,7 @@ AqlValue Functions::IsNull(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue a = ExtractFunctionParameterValue(trx, parameters, 0);
return AqlValue(arangodb::basics::VelocyPackHelper::BooleanValue(a.isNull(true)));
return AqlValue(a.isNull(true));
}
/// @brief function IS_BOOL
@ -892,7 +892,7 @@ AqlValue Functions::IsBool(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue a = ExtractFunctionParameterValue(trx, parameters, 0);
return AqlValue(arangodb::basics::VelocyPackHelper::BooleanValue(a.isBoolean()));
return AqlValue(a.isBoolean());
}
/// @brief function IS_NUMBER
@ -900,7 +900,7 @@ AqlValue Functions::IsNumber(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue a = ExtractFunctionParameterValue(trx, parameters, 0);
return AqlValue(arangodb::basics::VelocyPackHelper::BooleanValue(a.isNumber()));
return AqlValue(a.isNumber());
}
/// @brief function IS_STRING
@ -908,7 +908,7 @@ AqlValue Functions::IsString(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue a = ExtractFunctionParameterValue(trx, parameters, 0);
return AqlValue(arangodb::basics::VelocyPackHelper::BooleanValue(a.isString()));
return AqlValue(a.isString());
}
/// @brief function IS_ARRAY
@ -916,7 +916,7 @@ AqlValue Functions::IsArray(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue a = ExtractFunctionParameterValue(trx, parameters, 0);
return AqlValue(arangodb::basics::VelocyPackHelper::BooleanValue(a.isArray()));
return AqlValue(a.isArray());
}
/// @brief function IS_OBJECT
@ -924,7 +924,31 @@ AqlValue Functions::IsObject(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue a = ExtractFunctionParameterValue(trx, parameters, 0);
return AqlValue(arangodb::basics::VelocyPackHelper::BooleanValue(a.isObject()));
return AqlValue(a.isObject());
}
/// @brief function TYPENAME
AqlValue Functions::Typename(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue value = ExtractFunctionParameterValue(trx, parameters, 0);
if (value.isObject()) {
return AqlValue(TRI_CHAR_LENGTH_PAIR("object"));
}
if (value.isArray()) {
return AqlValue(TRI_CHAR_LENGTH_PAIR("array"));
}
if (value.isString()) {
return AqlValue(TRI_CHAR_LENGTH_PAIR("string"));
}
if (value.isNumber()) {
return AqlValue(TRI_CHAR_LENGTH_PAIR("number"));
}
if (value.isBoolean()) {
return AqlValue(TRI_CHAR_LENGTH_PAIR("bool"));
}
return AqlValue(TRI_CHAR_LENGTH_PAIR("null"));
}
/// @brief function TO_NUMBER
@ -968,7 +992,7 @@ AqlValue Functions::ToBool(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue a = ExtractFunctionParameterValue(trx, parameters, 0);
return AqlValue(arangodb::basics::VelocyPackHelper::BooleanValue(a.toBoolean()));
return AqlValue(a.toBoolean());
}
/// @brief function TO_ARRAY
@ -1639,9 +1663,7 @@ AqlValue Functions::Md5(arangodb::aql::Query* query,
arangodb::rest::SslInterface::sslHEX(hash, 16, p, length);
TransactionBuilderLeaser builder(trx);
builder->add(VPackValue(std::string(hex, 32)));
return AqlValue(builder.get());
return AqlValue(std::string(hex, 32));
}
/// @brief function SHA1
@ -1669,8 +1691,21 @@ AqlValue Functions::Sha1(arangodb::aql::Query* query,
arangodb::rest::SslInterface::sslHEX(hash, 20, p, length);
return AqlValue(std::string(hex, 40));
}
/// @brief function HASH
AqlValue Functions::Hash(arangodb::aql::Query* query,
arangodb::AqlTransaction* trx,
VPackFunctionParameters const& parameters) {
AqlValue value = ExtractFunctionParameterValue(trx, parameters, 0);
// throw away the top bytes so the hash value can safely be used
// without precision loss when storing in JavaScript etc.
uint64_t hash = value.hash(trx) & 0x0007ffffffffffffULL;
TransactionBuilderLeaser builder(trx);
builder->add(VPackValue(std::string(hex, 40)));
builder->add(VPackValue(hash));
return AqlValue(builder.get());
}

View File

@ -53,168 +53,172 @@ struct Functions {
static AqlValue IsNull(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue IsBool(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue IsNumber(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue IsString(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue IsArray(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue IsObject(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Typename(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue ToNumber(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue ToString(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue ToBool(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue ToArray(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Length(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue First(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Last(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Nth(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Concat(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Like(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Passthru(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Unset(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue UnsetRecursive(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Keep(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Merge(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue MergeRecursive(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Has(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Attributes(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Values(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Min(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Max(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Sum(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Average(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Md5(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Sha1(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue Hash(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Unique(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
VPackFunctionParameters const&);
static AqlValue SortedUnique(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Union(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue UnionDistinct(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Intersection(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Neighbors(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Near(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Within(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Flatten(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Zip(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue ParseIdentifier(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Minus(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Document(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Edges(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Round(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Abs(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Ceil(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Floor(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Sqrt(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Pow(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Rand(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue FirstDocument(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue FirstList(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Push(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Pop(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Append(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Unshift(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Shift(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue RemoveValue(arangodb::aql::Query*, arangodb::AqlTransaction*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue RemoveValues(arangodb::aql::Query*,
static AqlValue Union(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue UnionDistinct(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue RemoveNth(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue NotNull(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue CurrentDatabase(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue CollectionCount(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue VarianceSample(arangodb::aql::Query*,
static AqlValue Intersection(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Neighbors(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Near(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Within(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Flatten(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Zip(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue ParseIdentifier(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue VariancePopulation(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue StdDevSample(arangodb::aql::Query*,
static AqlValue Minus(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Document(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Edges(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Round(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Abs(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Ceil(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Floor(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Sqrt(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Pow(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Rand(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue FirstDocument(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue StdDevPopulation(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Median(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Percentile(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Range(arangodb::aql::Query*, arangodb::AqlTransaction*,
static AqlValue FirstList(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Push(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Pop(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Append(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Position(arangodb::aql::Query*, arangodb::AqlTransaction*,
static AqlValue Unshift(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Shift(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue RemoveValue(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue RemoveValues(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue RemoveNth(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Fulltext(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue IsSameCollection(arangodb::aql::Query*,
static AqlValue NotNull(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue CurrentDatabase(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue CollectionCount(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue VarianceSample(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue VariancePopulation(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue StdDevSample(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue StdDevPopulation(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Median(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Percentile(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Range(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Position(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue Fulltext(arangodb::aql::Query*, arangodb::AqlTransaction*,
VPackFunctionParameters const&);
static AqlValue IsSameCollection(arangodb::aql::Query*,
arangodb::AqlTransaction*,
VPackFunctionParameters const&);
};
}
}

View File

@ -2447,6 +2447,34 @@ static void JS_QuerySleepAql(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes a V8 object
////////////////////////////////////////////////////////////////////////////////
static void JS_ObjectHash(v8::FunctionCallbackInfo<v8::Value> const& args) {
TRI_V8_TRY_CATCH_BEGIN(isolate);
v8::HandleScope scope(isolate);
// extract arguments
if (args.Length() != 1) {
TRI_V8_THROW_EXCEPTION_USAGE("hash(<object>)");
}
VPackBuilder builder;
int res = TRI_V8ToVPack(isolate, builder, args[0], false);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
// throw away the top bytes so the hash value can safely be used
// without precision loss when storing in JavaScript etc.
uint64_t hash = builder.slice().normalizedHash() & 0x0007ffffffffffffULL;
TRI_V8_RETURN(v8::Number::New(isolate, static_cast<double>(hash)));
TRI_V8_TRY_CATCH_END
}
////////////////////////////////////////////////////////////////////////////////
/// @brief wraps a TRI_vocbase_t
////////////////////////////////////////////////////////////////////////////////
@ -3556,6 +3584,10 @@ void TRI_InitV8VocBridge(v8::Isolate* isolate, v8::Handle<v8::Context> context,
TRI_AddGlobalFunctionVocbase(
isolate, context, TRI_V8_ASCII_STRING("AQL_QUERY_CACHE_INVALIDATE"),
JS_QueryCacheInvalidateAql, true);
TRI_AddGlobalFunctionVocbase(isolate, context,
TRI_V8_ASCII_STRING("OBJECT_HASH"),
JS_ObjectHash, true);
TRI_AddGlobalFunctionVocbase(
isolate, context, TRI_V8_ASCII_STRING("THROW_COLLECTION_NOT_LOADED"),

View File

@ -92,7 +92,7 @@ var AqlHighlightRules = function() {
);
var builtinFunctions = (
"(to_bool|to_number|to_string|to_list|is_null|is_bool|is_number|is_string|is_list|is_document|" +
"(to_bool|to_number|to_string|to_list|is_null|is_bool|is_number|is_string|is_list|is_document|typename|" +
"concat|concat_separator|char_length|lower|upper|substring|left|right|trim|reverse|contains|" +
"like|floor|ceil|round|abs|rand|sqrt|pow|length|min|max|average|sum|median|variance_population|" +
"variance_sample|first|last|unique|matches|merge|merge_recursive|has|attributes|values|unset|unset_recursive|keep|" +
@ -107,7 +107,7 @@ var AqlHighlightRules = function() {
"date_add|date_subtract|date_diff|date_compare|date_format|fail|passthru|sleep|not_null|" +
"first_list|first_document|parse_identifier|current_user|current_database|" +
"collections|document|union|union_distinct|intersection|flatten|is_same_collection|" +
"ltrim|rtrim|find_first|find_last|split|substitute|md5|sha1|random_token|AQL_LAST_ENTRY)"
"ltrim|rtrim|find_first|find_last|split|substitute|md5|sha1|hash|random_token|AQL_LAST_ENTRY)"
);
var keywordMapper = this.createKeywordMapper({

View File

@ -1,6 +1,6 @@
/*jshint strict: false, unused: false, bitwise: false, esnext: true */
/*global COMPARE_STRING, AQL_TO_BOOL, AQL_TO_NUMBER, AQL_TO_STRING, AQL_WARNING, AQL_QUERY_SLEEP */
/*global CPP_SHORTEST_PATH, CPP_NEIGHBORS, Set */
/*global CPP_SHORTEST_PATH, CPP_NEIGHBORS, Set, OBJECT_HASH */
////////////////////////////////////////////////////////////////////////////////
/// @brief Aql, internal query functions
@ -2519,6 +2519,39 @@ function AQL_SHA1 (value) {
return INTERNAL.sha1(AQL_TO_STRING(value));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates a hash value for an object
////////////////////////////////////////////////////////////////////////////////
function AQL_HASH (value) {
'use strict';
return OBJECT_HASH(value);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the typename for an object
////////////////////////////////////////////////////////////////////////////////
function AQL_TYPENAME (value) {
'use strict';
switch (TYPEWEIGHT(value)) {
case TYPEWEIGHT_BOOL:
return "bool";
case TYPEWEIGHT_NUMBER:
return "number";
case TYPEWEIGHT_STRING:
return "string";
case TYPEWEIGHT_ARRAY:
return "array";
case TYPEWEIGHT_OBJECT:
return "object";
}
return "null";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates a random token of the specified length
////////////////////////////////////////////////////////////////////////////////
@ -8133,6 +8166,8 @@ exports.AQL_SPLIT = AQL_SPLIT;
exports.AQL_SUBSTITUTE = AQL_SUBSTITUTE;
exports.AQL_MD5 = AQL_MD5;
exports.AQL_SHA1 = AQL_SHA1;
exports.AQL_HASH = AQL_HASH;
exports.AQL_TYPENAME = AQL_TYPENAME;
exports.AQL_RANDOM_TOKEN = AQL_RANDOM_TOKEN;
exports.AQL_FIND_FIRST = AQL_FIND_FIRST;
exports.AQL_FIND_LAST = AQL_FIND_LAST;

View File

@ -1,5 +1,5 @@
/*jshint globalstrict:false, strict:false, maxlen:5000 */
/*global assertEqual, assertTrue */
/*global assertEqual, assertNotEqual, assertTrue */
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, functions
@ -1323,6 +1323,101 @@ function ahuacatlStringFunctionsTestSuite () {
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test hash function
////////////////////////////////////////////////////////////////////////////////
testHash : function () {
var buildQuery = function (nr, input) {
switch (nr) {
case 0:
return `RETURN HASH(${input})`;
case 1:
return `RETURN NOOPT(HASH(${input}))`;
case 2:
return `RETURN NOOPT(V8(HASH(${input})))`;
default:
assertTrue(false, "Undefined state");
}
};
var i;
for (i = 0; i < 3; ++i) {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, buildQuery(i, ""));
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, buildQuery(i, "1, 2"));
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, buildQuery(i, "1, 2, 3"));
assertEqual([ 675717317264138 ], getQueryResults(buildQuery(i, "null")));
assertEqual([ 1217335385489389 ], getQueryResults(buildQuery(i, "false")));
assertEqual([ 57801618404459 ], getQueryResults(buildQuery(i, "true")));
assertEqual([ 2964198978643 ], getQueryResults(buildQuery(i, "1 / 0")));
assertEqual([ 2964198978643 ], getQueryResults(buildQuery(i, "0")));
assertEqual([ 2964198978643 ], getQueryResults(buildQuery(i, "0.0")));
assertEqual([ 464020872367562 ], getQueryResults(buildQuery(i, "0.00001")));
assertEqual([ 652971229830707 ], getQueryResults(buildQuery(i, "1")));
assertEqual([ 510129580600084 ], getQueryResults(buildQuery(i, "-1")));
assertEqual([ 24372339383975 ], getQueryResults(buildQuery(i, "-10.5")));
assertEqual([ 1041198105137773 ], getQueryResults(buildQuery(i, "123452532322453")));
assertEqual([ 876255539722551 ], getQueryResults(buildQuery(i, "123452532322454")));
assertEqual([ 1277486662998285 ], getQueryResults(buildQuery(i, "123452532322454.434")));
assertEqual([ 210539478145939 ], getQueryResults(buildQuery(i, "-123452532322454")));
assertEqual([ 261745517313272 ], getQueryResults(buildQuery(i, "-9999999999999.999")));
assertEqual([ 441814588996558 ], getQueryResults(buildQuery(i, "''")));
assertEqual([ 1112732548475941 ], getQueryResults(buildQuery(i, "' '")));
assertEqual([ 246233608921999 ], getQueryResults(buildQuery(i, "' '")));
assertEqual([ 1542381651001813 ], getQueryResults(buildQuery(i, "'a'")));
assertEqual([ 843602980995939 ], getQueryResults(buildQuery(i, "'A'")));
assertEqual([ 1618092585478118 ], getQueryResults(buildQuery(i, "' a'")));
assertEqual([ 725364078947946 ], getQueryResults(buildQuery(i, "' A'")));
assertEqual([ 736233736371291 ], getQueryResults(buildQuery(i, "' foobar'")));
assertEqual([ 360657200843601 ], getQueryResults(buildQuery(i, "'this is a string test. please ignore.'")));
assertEqual([ 828085160327326 ], getQueryResults(buildQuery(i, "'this is a string test. please Ignore.'")));
assertEqual([ 2072438876063292 ], getQueryResults(buildQuery(i, "'a string is a string is a string of course. even longer strings can be hashed. isn\\'t this fantastic? let\\'s see if we can cross the short-string bounds with it...'")));
assertEqual([ 181227890622943 ], getQueryResults(buildQuery(i, "[]")));
assertEqual([ 346113245898278 ], getQueryResults(buildQuery(i, "[0]")));
assertEqual([ 785599515440277 ], getQueryResults(buildQuery(i, "[1]")));
assertEqual([ 1295855700045140 ], getQueryResults(buildQuery(i, "[1,2]")));
assertEqual([ 1295855700045140 ], getQueryResults(buildQuery(i, "1..2")));
assertEqual([ 1255602544875390 ], getQueryResults(buildQuery(i, "[2,1]")));
assertEqual([ 1255602544875390 ], getQueryResults(buildQuery(i, "2..1")));
assertEqual([ 1625466870434085 ], getQueryResults(buildQuery(i, "[1,2,3]")));
assertEqual([ 1625466870434085 ], getQueryResults(buildQuery(i, "1..3")));
assertEqual([ 1657598895986170 ], getQueryResults(buildQuery(i, "[1,2,3,4]")));
assertEqual([ 1657598895986170 ], getQueryResults(buildQuery(i, "1..4")));
assertEqual([ 1580543009747638 ], getQueryResults(buildQuery(i, "[1,2,4,3]")));
assertEqual([ 157821093310761 ], getQueryResults(buildQuery(i, "[1,2,3,2]")));
assertEqual([ 1032992608692014 ], getQueryResults(buildQuery(i, "[1,2,3,2,1]")));
assertEqual([ 2051766968908771 ], getQueryResults(buildQuery(i, "1..1000")));
assertEqual([ 1954991255293719 ], getQueryResults(buildQuery(i, "{}")));
assertEqual([ 1270059518310386 ], getQueryResults(buildQuery(i, "{a:1}")));
assertEqual([ 1462532781001381 ], getQueryResults(buildQuery(i, "{a:2}")));
assertEqual([ 1872109801523384 ], getQueryResults(buildQuery(i, "{a:1,b:1}")));
assertEqual([ 599770551193312 ], getQueryResults(buildQuery(i, "{a:1,b:2}")));
assertEqual([ 1872109801523384 ], getQueryResults(buildQuery(i, "{b:1,a:1}")));
assertEqual([ 599770551193312 ], getQueryResults(buildQuery(i, "{b:2,a:1}")));
assertEqual([ 876136767628139 ], getQueryResults(buildQuery(i, "{b:1,a:2}")));
assertEqual([ 876136767628139 ], getQueryResults(buildQuery(i, "{a:2,b:1}")));
assertEqual([ 92631926086363 ], getQueryResults(buildQuery(i, "{a:2,b:'1'}")));
assertEqual([ 2054068497715740 ], getQueryResults(buildQuery(i, "{a:2,b:null}")));
assertEqual([ 550542031834779 ], getQueryResults(buildQuery(i, "{A:1,B:2}")));
assertEqual([ 2125993103279620 ], getQueryResults(buildQuery(i, "{a:'A',b:'B'}")));
assertEqual([ 878459260153284 ], getQueryResults(buildQuery(i, "{a:'a',b:'b'}")));
assertEqual([ 1454594333033579 ], getQueryResults(buildQuery(i, "{a:['a'],b:['b']}")));
assertEqual([ 296899533959594 ], getQueryResults(buildQuery(i, "{a:1,b:-1}")));
assertEqual([ 944398530367049 ], getQueryResults(buildQuery(i, "{_id:'foo',_key:'bar',_rev:'baz'}")));
}
for (i = 0; i < 3; ++i) {
// order does not matter
assertEqual(getQueryResults(buildQuery(i, "{a:1,b:2}")), getQueryResults(buildQuery(i, "{b:2,a:1}")));
assertNotEqual(getQueryResults(buildQuery(i, "{a:1,b:2}")), getQueryResults(buildQuery(i, "{a:2,b:1}")));
// order matters
assertNotEqual(getQueryResults(buildQuery(i, "[1,2,3]")), getQueryResults(buildQuery(i, "[3,2,1]")));
// arrays and ranges
assertEqual(getQueryResults(buildQuery(i, "[1,2,3]")), getQueryResults(buildQuery(i, "1..3")));
// arrays and subqueries
assertEqual(getQueryResults(buildQuery(i, "[1,2,3]")), getQueryResults(buildQuery(i, "FOR i IN [1,2,3] RETURN i")));
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test md5 function
////////////////////////////////////////////////////////////////////////////////

View File

@ -41,6 +41,47 @@ var assertQueryError = helper.assertQueryError;
function ahuacatlTypesFunctionsTestSuite () {
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief test typename function
////////////////////////////////////////////////////////////////////////////////
testTypename : function () {
assertEqual([ "null" ], getQueryResults("RETURN NOOPT(TYPENAME(null))"));
assertEqual([ "bool" ], getQueryResults("RETURN NOOPT(TYPENAME(false))"));
assertEqual([ "bool" ], getQueryResults("RETURN NOOPT(TYPENAME(true))"));
assertEqual([ "number" ], getQueryResults("RETURN NOOPT(TYPENAME(0))"));
assertEqual([ "number" ], getQueryResults("RETURN NOOPT(TYPENAME(1))"));
assertEqual([ "number" ], getQueryResults("RETURN NOOPT(TYPENAME(-99999))"));
assertEqual([ "number" ], getQueryResults("RETURN NOOPT(TYPENAME(0.005))"));
assertEqual([ "number" ], getQueryResults("RETURN NOOPT(TYPENAME(1334540.005))"));
assertEqual([ "number" ], getQueryResults("RETURN NOOPT(TYPENAME(3e32))"));
assertEqual([ "array" ], getQueryResults("RETURN NOOPT(TYPENAME(1..2))"));
assertEqual([ "array" ], getQueryResults("RETURN NOOPT(TYPENAME(99..0))"));
assertEqual([ "array" ], getQueryResults("RETURN NOOPT(TYPENAME(FOR i IN 1..10 RETURN i))"));
assertEqual([ "array" ], getQueryResults("RETURN NOOPT(TYPENAME([ ]))"));
assertEqual([ "array" ], getQueryResults("RETURN NOOPT(TYPENAME([ 'foo ' ]))"));
assertEqual([ "object" ], getQueryResults("RETURN NOOPT(TYPENAME({ }))"));
assertEqual([ "object" ], getQueryResults("RETURN NOOPT(TYPENAME({ 'foo': 'bar' }))"));
assertEqual([ "string" ], getQueryResults("RETURN NOOPT(TYPENAME('foo'))"));
assertEqual([ "string" ], getQueryResults("RETURN NOOPT(TYPENAME(''))"));
assertEqual([ "string" ], getQueryResults("RETURN NOOPT(TYPENAME(' '))"));
assertEqual([ "string" ], getQueryResults("RETURN NOOPT(TYPENAME('0'))"));
assertEqual([ "string" ], getQueryResults("RETURN NOOPT(TYPENAME('1'))"));
assertEqual([ "string" ], getQueryResults("RETURN NOOPT(TYPENAME('true'))"));
assertEqual([ "string" ], getQueryResults("RETURN NOOPT(TYPENAME('false'))"));
assertEqual([ "number", "number" ], getQueryResults("FOR i IN 1..2 RETURN NOOPT(TYPENAME(i))"));
assertEqual([ "string", "string", "string", "number" ], getQueryResults("FOR i IN [ 'foo', 'bar', 'baz', 42 ] RETURN NOOPT(TYPENAME(i))"));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test typename function, invalid arguments
////////////////////////////////////////////////////////////////////////////////
testTypenameInvalid : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(TYPENAME())");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN NOOPT(TYPENAME('a', 'b'))");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test is_string function
////////////////////////////////////////////////////////////////////////////////

View File

@ -65,6 +65,47 @@ function ahuacatlTypesFunctionsTestSuite () {
db._drop(vn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test typename function
////////////////////////////////////////////////////////////////////////////////
testTypename : function () {
assertEqual([ "null" ], getQueryResults("RETURN TYPENAME(null)"));
assertEqual([ "bool" ], getQueryResults("RETURN TYPENAME(false)"));
assertEqual([ "bool" ], getQueryResults("RETURN TYPENAME(true)"));
assertEqual([ "number" ], getQueryResults("RETURN TYPENAME(0)"));
assertEqual([ "number" ], getQueryResults("RETURN TYPENAME(1)"));
assertEqual([ "number" ], getQueryResults("RETURN TYPENAME(-99999)"));
assertEqual([ "number" ], getQueryResults("RETURN TYPENAME(0.005)"));
assertEqual([ "number" ], getQueryResults("RETURN TYPENAME(1334540.005)"));
assertEqual([ "number" ], getQueryResults("RETURN TYPENAME(3e32)"));
assertEqual([ "array" ], getQueryResults("RETURN TYPENAME(1..2)"));
assertEqual([ "array" ], getQueryResults("RETURN TYPENAME(99..0)"));
assertEqual([ "array" ], getQueryResults("RETURN TYPENAME(FOR i IN 1..10 RETURN i)"));
assertEqual([ "array" ], getQueryResults("RETURN TYPENAME([ ])"));
assertEqual([ "array" ], getQueryResults("RETURN TYPENAME([ 'foo ' ])"));
assertEqual([ "object" ], getQueryResults("RETURN TYPENAME({ })"));
assertEqual([ "object" ], getQueryResults("RETURN TYPENAME({ 'foo': 'bar' })"));
assertEqual([ "string" ], getQueryResults("RETURN TYPENAME('foo')"));
assertEqual([ "string" ], getQueryResults("RETURN TYPENAME('')"));
assertEqual([ "string" ], getQueryResults("RETURN TYPENAME(' ')"));
assertEqual([ "string" ], getQueryResults("RETURN TYPENAME('0')"));
assertEqual([ "string" ], getQueryResults("RETURN TYPENAME('1')"));
assertEqual([ "string" ], getQueryResults("RETURN TYPENAME('true')"));
assertEqual([ "string" ], getQueryResults("RETURN TYPENAME('false')"));
assertEqual([ "number", "number" ], getQueryResults("FOR i IN 1..2 RETURN TYPENAME(i)"));
assertEqual([ "string", "string", "string", "number" ], getQueryResults("FOR i IN [ 'foo', 'bar', 'baz', 42 ] RETURN TYPENAME(i)"));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test typename function, invalid arguments
////////////////////////////////////////////////////////////////////////////////
testTypenameInvalid : function () {
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN TYPENAME()");
assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN TYPENAME('a', 'b')");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test is_string function
////////////////////////////////////////////////////////////////////////////////

View File

@ -854,6 +854,47 @@ function ahuacatlQueryCollectionTestSuite () {
var expected = [ [ "riding", "skating", "swimming", null, "swimming" ] ];
var actual = getQueryResults("FOR u in " + users.name() + " FILTER HAS(u, 'hobbies') RETURN [ u.hobbies[0], u.hobbies[1], u.hobbies[2], u.hobbies[3], u.hobbies[-1] ]");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test hashing the documents
////////////////////////////////////////////////////////////////////////////////
testHashes : function () {
var expected = [
1089385960271542,
1549718497690202,
560358553578052,
1642812332573238,
435359225373270,
408295336378511,
1897938296916959,
713554280722917,
369118524423277,
1548261017980441,
541971611858512,
1804578553815548,
976161958841139,
259242346857309,
671328068995257,
2154779012539123,
1413254027041724,
854175714643442,
178243611496212,
791314881371364
];
var actual = getQueryResults("FOR u in " + users.name() + " SORT u.id RETURN HASH(UNSET(u, ['_key', '_rev', '_id']))");
assertEqual(expected, actual);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test hashing the documents
////////////////////////////////////////////////////////////////////////////////
testHashSubquery : function () {
var expected = [ 1866655274639415 ];
var actual = getQueryResults("RETURN HASH(FOR u in " + users.name() + " SORT u.id RETURN UNSET(u, ['_key', '_rev', '_id']))");
assertEqual(expected, actual);
}
};