mirror of https://gitee.com/bigwinds/arangodb
2552 lines
86 KiB
C++
Executable File
2552 lines
86 KiB
C++
Executable File
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief V8-vocbase queries
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2004-2012 triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// @author Dr. Frank Celler
|
|
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <string>
|
|
|
|
#include "v8-query.h"
|
|
|
|
#include "BasicsC/logging.h"
|
|
#include "HashIndex/hashindex.h"
|
|
#include "SkipLists/skiplistIndex.h"
|
|
#include "V8/v8-conv.h"
|
|
#include "V8/v8-utils.h"
|
|
#include "V8Server/v8-vocbase.h"
|
|
#include "VocBase/edge-collection.h"
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- HELPER FUNCTIONS
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private types
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup VocBase
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief geo coordinate container, also containing the distance
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct {
|
|
double _distance;
|
|
void const* _data;
|
|
}
|
|
geo_coordinate_distance_t;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief query types
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef enum {
|
|
QUERY_EXAMPLE,
|
|
QUERY_CONDITION
|
|
}
|
|
query_t;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup VocBase
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief extracts skip and limit
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void ExtractSkipAndLimit (v8::Arguments const& argv,
|
|
size_t pos,
|
|
TRI_voc_ssize_t& skip,
|
|
TRI_voc_size_t& limit) {
|
|
|
|
skip = TRI_QRY_NO_SKIP;
|
|
limit = TRI_QRY_NO_LIMIT;
|
|
|
|
if (pos < (size_t) argv.Length() && ! argv[pos]->IsNull()) {
|
|
skip = (TRI_voc_size_t) TRI_ObjectToDouble(argv[pos]);
|
|
}
|
|
|
|
if (pos + 1 < (size_t) argv.Length() && ! argv[pos + 1]->IsNull()) {
|
|
limit = (TRI_voc_ssize_t) TRI_ObjectToDouble(argv[pos + 1]);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief calculates slice
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void CalculateSkipLimitSlice (size_t length,
|
|
TRI_voc_ssize_t skip,
|
|
TRI_voc_size_t limit,
|
|
size_t& s,
|
|
size_t& e) {
|
|
s = 0;
|
|
e = length;
|
|
|
|
// skip from the beginning
|
|
if (0 < skip) {
|
|
s = skip;
|
|
|
|
if (e < s) {
|
|
s = e;
|
|
}
|
|
}
|
|
|
|
// skip from the end
|
|
else if (skip < 0) {
|
|
skip = -skip;
|
|
|
|
if ((size_t) skip < e) {
|
|
s = e - skip;
|
|
}
|
|
}
|
|
|
|
// apply limit
|
|
if (s + limit < e) {
|
|
e = s + limit;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief cleans up the example object
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void CleanupExampleObject (TRI_shaper_t* shaper,
|
|
size_t n,
|
|
TRI_shape_pid_t* pids,
|
|
TRI_shaped_json_t** values) {
|
|
|
|
// clean shaped json objects
|
|
for (size_t j = 0; j < n; ++j) {
|
|
TRI_FreeShapedJson(shaper, values[j]);
|
|
}
|
|
|
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, values);
|
|
|
|
if (pids != 0) {
|
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, pids);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets up the example object
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int SetupExampleObject (v8::Handle<v8::Object> example,
|
|
TRI_shaper_t* shaper,
|
|
size_t& n,
|
|
TRI_shape_pid_t*& pids,
|
|
TRI_shaped_json_t**& values,
|
|
v8::Handle<v8::Object>* err) {
|
|
|
|
// get own properties of example
|
|
v8::Handle<v8::Array> names = example->GetOwnPropertyNames();
|
|
n = names->Length();
|
|
|
|
// setup storage
|
|
pids = (TRI_shape_pid_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, n * sizeof(TRI_shape_pid_t), false);
|
|
// TODO: memory allocation might fail
|
|
values = (TRI_shaped_json_t**) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, n * sizeof(TRI_shaped_json_t*), false);
|
|
// TODO: memory allocation might fail
|
|
|
|
// convert
|
|
for (size_t i = 0; i < n; ++i) {
|
|
v8::Handle<v8::Value> key = names->Get(i);
|
|
v8::Handle<v8::Value> val = example->Get(key);
|
|
|
|
TRI_Utf8ValueNFC keyStr(TRI_UNKNOWN_MEM_ZONE, key);
|
|
|
|
if (*keyStr != 0) {
|
|
pids[i] = shaper->findAttributePathByName(shaper, *keyStr);
|
|
values[i] = TRI_ShapedJsonV8Object(val, shaper);
|
|
}
|
|
|
|
if (*keyStr == 0 || pids[i] == 0 || values[i] == 0) {
|
|
CleanupExampleObject(shaper, i, pids, values);
|
|
|
|
if (*keyStr == 0) {
|
|
*err = TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"cannot convert attribute path to UTF8");
|
|
return TRI_ERROR_BAD_PARAMETER;
|
|
}
|
|
else if (pids[i] == 0) {
|
|
*err = TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"cannot convert to attribute path");
|
|
return TRI_ERROR_BAD_PARAMETER;
|
|
}
|
|
else {
|
|
*err = TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"cannot convert value to JSON");
|
|
return TRI_ERROR_BAD_PARAMETER;
|
|
}
|
|
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
return TRI_ERROR_NO_ERROR;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets up the skiplist operator for a skiplist condition query
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_index_operator_t* SetupConditionsSkiplist (TRI_index_t* idx,
|
|
TRI_shaper_t* shaper,
|
|
v8::Handle<v8::Object> conditions) {
|
|
TRI_index_operator_t* lastOperator = 0;
|
|
TRI_json_t* parameters = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE);
|
|
size_t numEq = 0;
|
|
size_t lastNonEq = 0;
|
|
|
|
if (parameters == 0) {
|
|
return 0;
|
|
}
|
|
|
|
// iterate over all index fields
|
|
for (size_t i = 1; i <= idx->_fields._length; ++i) {
|
|
v8::Handle<v8::String> key = v8::String::New(idx->_fields._buffer[i - 1]);
|
|
|
|
if (!conditions->HasOwnProperty(key)) {
|
|
break;
|
|
}
|
|
v8::Handle<v8::Value> fieldConditions = conditions->Get(key);
|
|
|
|
if (!fieldConditions->IsArray()) {
|
|
// wrong data type for field conditions
|
|
break;
|
|
}
|
|
|
|
// iterator over all conditions
|
|
v8::Handle<v8::Array> values = v8::Handle<v8::Array>::Cast(fieldConditions);
|
|
for (uint32_t j = 0; j < values->Length(); ++j) {
|
|
v8::Handle<v8::Value> fieldCondition = values->Get(j);
|
|
|
|
if (!fieldCondition->IsArray()) {
|
|
// wrong data type for single condition
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
v8::Handle<v8::Array> condition = v8::Handle<v8::Array>::Cast(fieldCondition);
|
|
|
|
if (condition->Length() != 2) {
|
|
// wrong number of values in single condition
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
v8::Handle<v8::Value> op = condition->Get(0);
|
|
v8::Handle<v8::Value> value = condition->Get(1);
|
|
|
|
if (!op->IsString()) {
|
|
// wrong operator type
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
TRI_json_t* json = TRI_JsonObject(value);
|
|
|
|
if (!json) {
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
std::string opValue = TRI_ObjectToString(op);
|
|
if (opValue == "==") {
|
|
// equality comparison
|
|
|
|
if (lastNonEq > 0) {
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, parameters, json);
|
|
// creation of equality operator is deferred until it is finally needed
|
|
++numEq;
|
|
break;
|
|
}
|
|
else {
|
|
if (lastNonEq > 0 && lastNonEq != i) {
|
|
// if we already had a range condition and a previous field, we cannot continue
|
|
// because the skiplist interface does not support such queries
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
TRI_index_operator_type_e opType;
|
|
if (opValue == ">") {
|
|
opType = TRI_GT_INDEX_OPERATOR;
|
|
}
|
|
else if (opValue == ">=") {
|
|
opType = TRI_GE_INDEX_OPERATOR;
|
|
}
|
|
else if (opValue == "<") {
|
|
opType = TRI_LT_INDEX_OPERATOR;
|
|
}
|
|
else if (opValue == "<=") {
|
|
opType = TRI_LE_INDEX_OPERATOR;
|
|
}
|
|
else {
|
|
// wrong operator type
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
lastNonEq = i;
|
|
|
|
TRI_json_t* cloned = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
if (cloned == 0) {
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, cloned, json);
|
|
|
|
if (numEq) {
|
|
// create equality operator if one is in queue
|
|
TRI_json_t* clonedParams = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
if (clonedParams == 0) {
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, cloned);
|
|
goto MEM_ERROR;
|
|
}
|
|
lastOperator = TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR, NULL, NULL, clonedParams, shaper, NULL, clonedParams->_value._objects._length, NULL);
|
|
numEq = 0;
|
|
}
|
|
|
|
TRI_index_operator_t* current = 0;
|
|
|
|
// create the operator for the current condition
|
|
current = TRI_CreateIndexOperator(opType, NULL, NULL, cloned, shaper, NULL, cloned->_value._objects._length, NULL);
|
|
if (current == 0) {
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, cloned);
|
|
goto MEM_ERROR;
|
|
}
|
|
|
|
if (lastOperator == 0) {
|
|
lastOperator = current;
|
|
}
|
|
else {
|
|
// merge the current operator with previous operators using logical AND
|
|
TRI_index_operator_t* newOperator = TRI_CreateIndexOperator(TRI_AND_INDEX_OPERATOR, lastOperator, current, NULL, shaper, NULL, 2, NULL);
|
|
|
|
if (newOperator == 0) {
|
|
TRI_FreeIndexOperator(current);
|
|
goto MEM_ERROR;
|
|
}
|
|
else {
|
|
lastOperator = newOperator;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (numEq) {
|
|
// create equality operator if one is in queue
|
|
assert(lastOperator == 0);
|
|
assert(lastNonEq == 0);
|
|
|
|
TRI_json_t* clonedParams = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
if (clonedParams == 0) {
|
|
goto MEM_ERROR;
|
|
}
|
|
lastOperator = TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR, NULL, NULL, clonedParams, shaper, NULL, clonedParams->_value._objects._length, NULL);
|
|
}
|
|
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
|
|
return lastOperator;
|
|
|
|
MEM_ERROR:
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
|
|
if (lastOperator == 0) {
|
|
TRI_FreeIndexOperator(lastOperator);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets up the bitarray operator for a bitarray condition query
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
static TRI_json_t* SetupBitarrayAttributeValuesHelper (TRI_index_t* idx, v8::Handle<v8::Object> attributeValues) {
|
|
TRI_json_t* parameters = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE);
|
|
|
|
|
|
// ........................................................................
|
|
// No memory, no problem
|
|
// ........................................................................
|
|
|
|
if (parameters == 0) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ........................................................................
|
|
// Client mucked something up?
|
|
// ........................................................................
|
|
|
|
if (!attributeValues->IsObject()) {
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ........................................................................
|
|
// Observe that the client can have sent any number of parameters which
|
|
// do not match the list of attributes defined in the index.
|
|
// These parameters are IGNORED -- no error is reported.
|
|
// ........................................................................
|
|
|
|
for (size_t i = 0; i < idx->_fields._length; ++i) {
|
|
v8::Handle<v8::String> key = v8::String::New(idx->_fields._buffer[i]);
|
|
TRI_json_t* json;
|
|
|
|
// ......................................................................
|
|
// The client may have sent values for all of the Attributes or for
|
|
// a subset of them. If the value for an Attribute is missing, then we
|
|
// assume that the client wishes to IGNORE the value of that Attribute.
|
|
// In the later case, we add the json object 'TRI_JSON_UNUSED' to
|
|
// indicate that this attribute is to be ignored. Notice that it is
|
|
// possible to ignore all the attributes defined as part of the index.
|
|
// ......................................................................
|
|
|
|
|
|
if (attributeValues->HasOwnProperty(key)) {
|
|
|
|
// ....................................................................
|
|
// for this index attribute, there is such an attribute given as a
|
|
// as a parameter by the client -- determine the value (or values)
|
|
// of this attribute parameter and store it for later use in the
|
|
// lookup
|
|
// ....................................................................
|
|
|
|
v8::Handle<v8::Value> value = attributeValues->Get(key);
|
|
json = TRI_JsonObject(value);
|
|
|
|
|
|
// ....................................................................
|
|
// special case: if client sent {"x":[],...}, then we wrap this up
|
|
// as {"x":[ [] ],...}.
|
|
// ....................................................................
|
|
|
|
if (json->_type == TRI_JSON_LIST) {
|
|
if (json->_value._objects._length == 0) {
|
|
TRI_json_t emptyList;
|
|
emptyList._type = TRI_JSON_LIST;
|
|
TRI_InitVector(&(emptyList._value._objects), TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_json_t));
|
|
TRI_PushBack2ListJson(json, &emptyList);
|
|
}
|
|
}
|
|
}
|
|
|
|
else {
|
|
// ....................................................................
|
|
// for this index attribute we can not locate it in the list of parameters
|
|
// sent to us by the client. Assign it an 'unused' (perhaps should be
|
|
// renamed to 'unknown' or 'undefined').
|
|
// ....................................................................
|
|
json = (TRI_json_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_json_t), true);
|
|
json->_type = TRI_JSON_UNUSED;
|
|
}
|
|
|
|
|
|
// ......................................................................
|
|
// Check and ensure we have a json object defined before we store it.
|
|
// ......................................................................
|
|
|
|
if (json == 0) {
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ......................................................................
|
|
// store it in an list json object -- eventually wil be stored as part
|
|
// of the index operator.
|
|
// ......................................................................
|
|
|
|
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, parameters, json);
|
|
}
|
|
|
|
|
|
return parameters;
|
|
}
|
|
|
|
|
|
static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
|
|
TRI_shaper_t* shaper,
|
|
v8::Handle<v8::Object> condition) {
|
|
|
|
v8::Handle<v8::Value> value;
|
|
TRI_index_operator_type_e operatorType;
|
|
TRI_index_operator_t* indexOperator = 0;
|
|
|
|
|
|
// ........................................................................
|
|
// Check the various operator conditions
|
|
// ........................................................................
|
|
|
|
|
|
// ........................................................................
|
|
// Check for an 'AND' condition. The following are acceptable: '&', '&&' 'and'
|
|
// ........................................................................
|
|
if (condition->HasOwnProperty(v8::String::New("&"))) {
|
|
operatorType = TRI_AND_INDEX_OPERATOR;
|
|
value = condition->Get(v8::String::New("&"));
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("&&"))) {
|
|
operatorType = TRI_AND_INDEX_OPERATOR;
|
|
value = condition->Get(v8::String::New("&&"));
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("and"))) {
|
|
operatorType = TRI_AND_INDEX_OPERATOR;
|
|
value = condition->Get(v8::String::New("and"));
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'OR' condition. The following are acceptable: '|', '||' 'or'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New("|"))) {
|
|
value = condition->Get(v8::String::New("|"));
|
|
operatorType = TRI_OR_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("||"))) {
|
|
value = condition->Get(v8::String::New("||"));
|
|
operatorType = TRI_OR_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("or"))) {
|
|
value = condition->Get(v8::String::New("or"));
|
|
operatorType = TRI_OR_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'NOT' condition. The following are acceptable: '!', 'not'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New("!"))) {
|
|
value = condition->Get(v8::String::New("!"));
|
|
operatorType = TRI_NOT_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("not"))) {
|
|
value = condition->Get(v8::String::New("not"));
|
|
operatorType = TRI_NOT_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'EQUAL' condition. The following are acceptable: '=', '==', 'eq'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New("=="))) {
|
|
value = condition->Get(v8::String::New("=="));
|
|
operatorType = TRI_EQ_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("="))) {
|
|
value = condition->Get(v8::String::New("="));
|
|
operatorType = TRI_EQ_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("eq"))) {
|
|
value = condition->Get(v8::String::New("eq"));
|
|
operatorType = TRI_EQ_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'NOT EQUAL' condition. The following are acceptable: '!=', '<>, 'ne'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New("!="))) {
|
|
value = condition->Get(v8::String::New("!="));
|
|
operatorType = TRI_NE_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("<>"))) {
|
|
value = condition->Get(v8::String::New("<>"));
|
|
operatorType = TRI_NE_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("ne"))) {
|
|
value = condition->Get(v8::String::New("ne"));
|
|
operatorType = TRI_NE_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'LESS THAN OR EQUAL' condition. The following are acceptable: '<=', 'le'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New("<="))) {
|
|
value = condition->Get(v8::String::New("<="));
|
|
operatorType = TRI_LE_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("le"))) {
|
|
value = condition->Get(v8::String::New("le"));
|
|
operatorType = TRI_LE_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'LESS THAN ' condition. The following are acceptable: '<', 'lt'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New("<"))) {
|
|
value = condition->Get(v8::String::New("<"));
|
|
operatorType = TRI_LT_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("lt"))) {
|
|
value = condition->Get(v8::String::New("lt"));
|
|
operatorType = TRI_LT_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'GREATER THAN OR EQUAL' condition. The following are acceptable: '>=', 'ge'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New(">="))) {
|
|
value = condition->Get(v8::String::New(">="));
|
|
operatorType = TRI_GE_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("ge"))) {
|
|
value = condition->Get(v8::String::New("ge"));
|
|
operatorType = TRI_GE_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// Check for an 'GREATER THAN ' condition. The following are acceptable: '>', 'gt'
|
|
// ........................................................................
|
|
else if (condition->HasOwnProperty(v8::String::New(">"))) {
|
|
value = condition->Get(v8::String::New(">"));
|
|
operatorType = TRI_GT_INDEX_OPERATOR;
|
|
}
|
|
else if (condition->HasOwnProperty(v8::String::New("gt"))) {
|
|
value = condition->Get(v8::String::New("gt"));
|
|
operatorType = TRI_GT_INDEX_OPERATOR;
|
|
}
|
|
// ........................................................................
|
|
// We received an invalid condition. Most likely we are really expressing
|
|
// a condition {"x":1} which should be BY_EXAMPLE rather than BY_CONDITION
|
|
// ........................................................................
|
|
else { // invalid operator index condition
|
|
return 0;
|
|
}
|
|
|
|
// ........................................................................
|
|
// Since we have a valid condition, act upon it
|
|
// may require recursion
|
|
// ........................................................................
|
|
|
|
switch (operatorType) {
|
|
|
|
case TRI_AND_INDEX_OPERATOR:
|
|
case TRI_OR_INDEX_OPERATOR: {
|
|
|
|
// ....................................................................
|
|
// For both the 'AND' and 'OR' index operators, we require an array
|
|
// with 2 elements for the value of the condition object. E.g. we
|
|
// expect: {"&": [{"x":0},{"x":1}]} <-- this is a special "and" call
|
|
// see the ensureBitarray doc for
|
|
// more information.
|
|
// More common is
|
|
// expect: {"or": [{"x":0},{"x":1}]} <-- which means return all docs
|
|
// where attribute "x" has the
|
|
// value of 0 or 1.
|
|
// To have "x" = 0 or "x" = 1 or "x" = 2 we expect:
|
|
// {"or":[{"x":0},{"or":[{"x":1},{"x":2}]}]} or any valid iteration
|
|
// of this. TODO: shortcut this with the "list" index operator
|
|
// ....................................................................
|
|
|
|
// ....................................................................
|
|
// wrong data type for this condition -- we require [leftOperation,rightOperation]
|
|
// ....................................................................
|
|
|
|
if (!value->IsArray()) {
|
|
return 0;
|
|
}
|
|
|
|
v8::Handle<v8::Array> andValues = v8::Handle<v8::Array>::Cast(value);
|
|
|
|
|
|
// ....................................................................
|
|
// Check the length of the array to ensure that it is exactly 2
|
|
// ....................................................................
|
|
|
|
if (andValues->Length() != 2) {
|
|
return 0;
|
|
}
|
|
|
|
v8::Handle<v8::Value> leftValue = andValues->Get(0);
|
|
v8::Handle<v8::Value> rightValue = andValues->Get(1);
|
|
|
|
if (!leftValue->IsObject() || !rightValue->IsObject()) {
|
|
return 0;
|
|
}
|
|
|
|
v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(leftValue);
|
|
v8::Handle<v8::Object> rightObject = v8::Handle<v8::Object>::Cast(rightValue);
|
|
|
|
|
|
// ....................................................................
|
|
// recurse the left and right operators
|
|
// ....................................................................
|
|
|
|
TRI_index_operator_t* leftOp = SetupConditionsBitarrayHelper(idx, shaper, leftObject);
|
|
TRI_index_operator_t* rightOp = SetupConditionsBitarrayHelper(idx, shaper, rightObject);
|
|
|
|
if (leftOp == 0 || rightOp == 0) {
|
|
TRI_FreeIndexOperator(leftOp);
|
|
TRI_FreeIndexOperator(rightOp);
|
|
return 0;
|
|
}
|
|
|
|
indexOperator = TRI_CreateIndexOperator(operatorType, leftOp, rightOp, NULL, shaper, NULL, 0, NULL);
|
|
break;
|
|
}
|
|
|
|
case TRI_NOT_INDEX_OPERATOR: {
|
|
|
|
// ....................................................................
|
|
// wrong data type for this condition -- we require {...} which becomes
|
|
// the left object for not operator.
|
|
// ....................................................................
|
|
|
|
if (!value->IsObject()) {
|
|
return 0;
|
|
}
|
|
|
|
v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(value);
|
|
|
|
|
|
// ....................................................................
|
|
// recurse the left and only operator
|
|
// ....................................................................
|
|
TRI_index_operator_t* leftOp = SetupConditionsBitarrayHelper(idx, shaper, leftObject);
|
|
|
|
if (leftOp == 0) {
|
|
return 0;
|
|
}
|
|
|
|
indexOperator = TRI_CreateIndexOperator(operatorType, leftOp, NULL, NULL, shaper, NULL, 0, NULL);
|
|
break;
|
|
}
|
|
|
|
case TRI_EQ_INDEX_OPERATOR:
|
|
case TRI_NE_INDEX_OPERATOR:
|
|
case TRI_LE_INDEX_OPERATOR:
|
|
case TRI_LT_INDEX_OPERATOR:
|
|
case TRI_GE_INDEX_OPERATOR:
|
|
case TRI_GT_INDEX_OPERATOR: {
|
|
|
|
v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(value);
|
|
TRI_json_t* parameters = SetupBitarrayAttributeValuesHelper(idx, leftObject);
|
|
|
|
if (parameters == 0) {
|
|
return 0;
|
|
}
|
|
indexOperator = TRI_CreateIndexOperator(operatorType, NULL, NULL, parameters, shaper, NULL, parameters->_value._objects._length, NULL);
|
|
break;
|
|
}
|
|
|
|
|
|
default: {
|
|
return 0;
|
|
}
|
|
|
|
} // end of switch (operatorType)
|
|
|
|
return indexOperator;
|
|
}
|
|
|
|
|
|
static TRI_index_operator_t* SetupConditionsBitarray (TRI_index_t* idx,
|
|
TRI_shaper_t* shaper,
|
|
v8::Handle<v8::Object> condition) {
|
|
TRI_index_operator_t* indexOperator = SetupConditionsBitarrayHelper(idx, shaper, condition);
|
|
return indexOperator;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets up the skiplist operator for a skiplist example query
|
|
///
|
|
/// this will set up a JSON container with the example values as a list
|
|
/// at the end, one skiplist equality operator is created for the entire list
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_index_operator_t* SetupExampleSkiplist (TRI_index_t* idx,
|
|
TRI_shaper_t* shaper,
|
|
v8::Handle<v8::Object> example) {
|
|
TRI_json_t* parameters = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE);
|
|
|
|
if (parameters == 0) {
|
|
return 0;
|
|
}
|
|
|
|
for (size_t i = 0; i < idx->_fields._length; ++i) {
|
|
v8::Handle<v8::String> key = v8::String::New(idx->_fields._buffer[i]);
|
|
|
|
if (!example->HasOwnProperty(key)) {
|
|
break;
|
|
}
|
|
|
|
v8::Handle<v8::Value> value = example->Get(key);
|
|
|
|
TRI_json_t* json = TRI_JsonObject(value);
|
|
|
|
if (!json) {
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
|
|
return 0;
|
|
}
|
|
|
|
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, parameters, json);
|
|
}
|
|
|
|
if (parameters->_value._objects._length > 0) {
|
|
// example means equality comparisons only
|
|
return TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR, NULL, NULL, parameters, shaper, NULL, parameters->_value._objects._length, NULL);
|
|
}
|
|
|
|
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, parameters);
|
|
return 0;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates an index operator for a bitarray example query
|
|
///
|
|
/// this will set up a JSON container with the example values as a list
|
|
/// at the end, one skiplist equality operator is created for the entire list
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_index_operator_t* SetupExampleBitarray (TRI_index_t* idx, TRI_shaper_t* shaper, v8::Handle<v8::Object> example) {
|
|
TRI_json_t* parameters = SetupBitarrayAttributeValuesHelper(idx, example);
|
|
|
|
if (parameters == 0) {
|
|
return 0;
|
|
}
|
|
|
|
// for an example query, we can only assume equality operator is required.
|
|
return TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR, NULL, NULL, parameters, shaper, NULL, parameters->_value._objects._length, NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets up the example object for hash index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int SetupExampleObjectIndex (TRI_hash_index_t* hashIndex,
|
|
v8::Handle<v8::Object> example,
|
|
TRI_shaper_t* shaper,
|
|
size_t& n,
|
|
TRI_shaped_json_t**& values,
|
|
v8::Handle<v8::Object>* err) {
|
|
|
|
// extract attribute paths
|
|
n = hashIndex->_paths._length;
|
|
|
|
// setup storage
|
|
values = (TRI_shaped_json_t**) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, n * sizeof(TRI_shaped_json_t*), false);
|
|
// TODO: memory allocation might fail
|
|
|
|
// convert
|
|
for (size_t i = 0; i < n; ++i) {
|
|
TRI_shape_pid_t pid = * (TRI_shape_pid_t*) TRI_AtVector(&hashIndex->_paths, i);
|
|
char const* name = TRI_AttributeNameShapePid(shaper, pid);
|
|
|
|
if (name == NULL) {
|
|
CleanupExampleObject(shaper, i, 0, values);
|
|
*err = TRI_CreateErrorObject(TRI_ERROR_INTERNAL, "shaper failed");
|
|
return TRI_ERROR_BAD_PARAMETER;
|
|
}
|
|
|
|
v8::Handle<v8::String> key = v8::String::New(name);
|
|
|
|
if (example->HasOwnProperty(key)) {
|
|
v8::Handle<v8::Value> val = example->Get(key);
|
|
|
|
values[i] = TRI_ShapedJsonV8Object(val, shaper);
|
|
}
|
|
else {
|
|
values[i] = TRI_ShapedJsonV8Object(v8::Null(), shaper);
|
|
}
|
|
|
|
if (values[i] == 0) {
|
|
CleanupExampleObject(shaper, i, 0, values);
|
|
|
|
*err = TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"cannot convert value to JSON");
|
|
return TRI_ERROR_BAD_PARAMETER;
|
|
}
|
|
}
|
|
|
|
return TRI_ERROR_NO_ERROR;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief execute a skiplist query (by condition or by example)
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
|
|
std::string const& signature,
|
|
const query_t type,
|
|
const bool lock) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = 0;
|
|
|
|
if (lock) {
|
|
document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
}
|
|
else {
|
|
document = TRI_ExtractSimpleCollection(argv, collection, &err);
|
|
}
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
// expecting index, example, skip, and limit
|
|
if (argv.Length() < 2) {
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
|
|
std::string usage("Usage: ");
|
|
usage += signature;
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
usage)));
|
|
}
|
|
|
|
if (! argv[1]->IsObject()) {
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
std::string msg;
|
|
|
|
if (type == QUERY_EXAMPLE) {
|
|
msg = "<example> must be an object";
|
|
}
|
|
else {
|
|
msg = "<conditions> must be an object";
|
|
}
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, msg)));
|
|
}
|
|
|
|
TRI_shaper_t* shaper = document->base._shaper;
|
|
|
|
// extract skip and limit
|
|
TRI_voc_ssize_t skip;
|
|
TRI_voc_size_t limit;
|
|
|
|
ExtractSkipAndLimit(argv, 2, skip, limit);
|
|
|
|
// setup result
|
|
v8::Handle<v8::Object> result = v8::Object::New();
|
|
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
result->Set(v8::String::New("documents"), documents);
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
if (lock) {
|
|
primary->beginRead(primary);
|
|
}
|
|
|
|
// extract the index
|
|
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, &err);
|
|
|
|
if (idx == 0) {
|
|
primary->endRead(primary);
|
|
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
if (idx->_type != TRI_IDX_TYPE_SKIPLIST_INDEX) {
|
|
if (lock) {
|
|
primary->endRead(primary);
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
|
|
}
|
|
|
|
TRI_index_operator_t* skiplistOperator;
|
|
v8::Handle<v8::Object> values = argv[1]->ToObject();
|
|
if (type == QUERY_EXAMPLE) {
|
|
skiplistOperator = SetupExampleSkiplist(idx, shaper, values);
|
|
}
|
|
else {
|
|
skiplistOperator = SetupConditionsSkiplist(idx, shaper, values);
|
|
}
|
|
|
|
if (! skiplistOperator) {
|
|
if (lock) {
|
|
primary->endRead(primary);
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up skiplist operator failed")));
|
|
}
|
|
|
|
TRI_skiplist_iterator_t* skiplistIterator = TRI_LookupSkiplistIndex(idx, skiplistOperator);
|
|
|
|
TRI_barrier_t* barrier = 0;
|
|
TRI_voc_ssize_t total = 0;
|
|
TRI_voc_size_t count = 0;
|
|
bool error = false;
|
|
|
|
while (true) {
|
|
SkiplistIndexElement* indexElement = (SkiplistIndexElement*) skiplistIterator->_next(skiplistIterator);
|
|
|
|
if (indexElement == NULL) {
|
|
break;
|
|
}
|
|
|
|
++total;
|
|
|
|
if (total > skip && count < limit) {
|
|
if (barrier == 0) {
|
|
barrier = TRI_CreateBarrierElement(&document->base._barrierList);
|
|
}
|
|
// TODO: barrier might be 0
|
|
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) indexElement->data, barrier);
|
|
|
|
if (doc.IsEmpty()) {
|
|
// error
|
|
error = true;
|
|
break;
|
|
}
|
|
else {
|
|
documents->Set(count, doc);
|
|
++count;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (lock) {
|
|
primary->endRead(primary);
|
|
}
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
// free data allocated by skiplist index result
|
|
TRI_FreeSkiplistIterator(skiplistIterator);
|
|
|
|
result->Set(v8::String::New("total"), v8::Number::New((double) total));
|
|
result->Set(v8::String::New("count"), v8::Number::New(count));
|
|
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
|
|
if (error) {
|
|
scope.Close(result);
|
|
}
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief execute a bitarray index query (by condition or by example)
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Example of a filter associated with an interator
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool BitarrayFilterExample(TRI_index_iterator_t* indexIterator) {
|
|
BitarrayIndexElement* indexElement;
|
|
TRI_bitarray_index_t* baIndex;
|
|
|
|
indexElement = (BitarrayIndexElement*) indexIterator->_next(indexIterator);
|
|
|
|
if (indexElement == NULL) {
|
|
return false;
|
|
}
|
|
|
|
baIndex = (TRI_bitarray_index_t*) indexIterator->_index;
|
|
|
|
if (baIndex == NULL) {
|
|
return false;
|
|
}
|
|
|
|
/* doc = (TRI_doc_mptr_t*) indexElement->data; */
|
|
|
|
// ..........................................................................
|
|
// Now perform any additional filter operations you require on the doc
|
|
// using baIndex which you now have access to.
|
|
// ..........................................................................
|
|
|
|
return true;
|
|
}
|
|
|
|
static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
|
|
std::string const& signature,
|
|
const query_t type,
|
|
const bool lock) {
|
|
v8::HandleScope scope;
|
|
v8::Handle<v8::Object> err;
|
|
const TRI_vocbase_col_t* collection;
|
|
TRI_voc_ssize_t skip;
|
|
TRI_voc_size_t limit;
|
|
|
|
// ...........................................................................
|
|
// extract and use the simple collection
|
|
// ...........................................................................
|
|
|
|
TRI_document_collection_t* document = 0;
|
|
|
|
if (lock) {
|
|
document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
}
|
|
else {
|
|
document = TRI_ExtractSimpleCollection(argv, collection, &err);
|
|
}
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
|
|
// ...........................................................................
|
|
// Check the parameters, expecting index, example, skip, and limit
|
|
// e.g. ("110597/962565", {"x":1}, null, null)
|
|
// ...........................................................................
|
|
|
|
if (argv.Length() < 2) {
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
|
|
std::string usage("Usage: ");
|
|
usage += signature;
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,usage)));
|
|
}
|
|
|
|
|
|
// ...........................................................................
|
|
// Check that the second parameter is an associative array (json object)
|
|
// ...........................................................................
|
|
|
|
if (! argv[1]->IsObject()) {
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
std::string msg;
|
|
|
|
if (type == QUERY_EXAMPLE) {
|
|
msg = "<example> must be an object";
|
|
}
|
|
else {
|
|
msg = "<conditions> must be an object";
|
|
}
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, msg)));
|
|
}
|
|
|
|
|
|
TRI_shaper_t* shaper = document->base._shaper;
|
|
|
|
|
|
// .............................................................................
|
|
// extract skip and limit
|
|
// .............................................................................
|
|
|
|
ExtractSkipAndLimit(argv, 2, skip, limit);
|
|
|
|
|
|
// .............................................................................
|
|
// Create the json object result which stores documents located
|
|
// .............................................................................
|
|
|
|
v8::Handle<v8::Object> result = v8::Object::New();
|
|
|
|
|
|
// .............................................................................
|
|
// Create the array to store documents located
|
|
// .............................................................................
|
|
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
result->Set(v8::String::New("documents"), documents);
|
|
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
if (lock) {
|
|
primary->beginRead(primary);
|
|
}
|
|
|
|
// .............................................................................
|
|
// extract the index
|
|
// .............................................................................
|
|
|
|
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, &err);
|
|
|
|
if (idx == 0) {
|
|
primary->endRead(primary);
|
|
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
|
|
if (idx->_type != TRI_IDX_TYPE_BITARRAY_INDEX) {
|
|
if (lock) {
|
|
primary->endRead(primary);
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
|
|
}
|
|
|
|
|
|
TRI_index_operator_t* indexOperator;
|
|
v8::Handle<v8::Object> values = argv[1]->ToObject();
|
|
if (type == QUERY_EXAMPLE) {
|
|
indexOperator = SetupExampleBitarray(idx, shaper, values);
|
|
}
|
|
else {
|
|
indexOperator = SetupConditionsBitarray(idx, shaper, values);
|
|
}
|
|
|
|
|
|
if (indexOperator == 0) { // something wrong
|
|
if (lock) {
|
|
primary->endRead(primary);
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up bitarray index operator failed")));
|
|
}
|
|
|
|
|
|
// .............................................................................
|
|
// attempt to locate the documents
|
|
// .............................................................................
|
|
|
|
TRI_index_iterator_t* indexIterator = TRI_LookupBitarrayIndex(idx, indexOperator, BitarrayFilterExample);
|
|
|
|
|
|
// .............................................................................
|
|
// Take care of the case where the index iterator is returned as NULL -- may
|
|
// occur when some catastrophic error occurs.
|
|
// .............................................................................
|
|
|
|
TRI_barrier_t* barrier = 0;
|
|
TRI_voc_ssize_t total = 0;
|
|
TRI_voc_size_t count = 0;
|
|
bool error = false;
|
|
|
|
if (indexIterator != NULL) {
|
|
|
|
|
|
while (true) {
|
|
TRI_doc_mptr_t* data = (TRI_doc_mptr_t*) indexIterator->_next(indexIterator);
|
|
|
|
if (data == NULL) {
|
|
break;
|
|
}
|
|
|
|
|
|
++total;
|
|
|
|
if (total > skip && count < limit) {
|
|
if (barrier == 0) {
|
|
barrier = TRI_CreateBarrierElement(&document->base._barrierList);
|
|
}
|
|
// TODO: barrier might be 0
|
|
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, data, barrier);
|
|
|
|
if (doc.IsEmpty()) {
|
|
// error
|
|
error = true;
|
|
break;
|
|
}
|
|
else {
|
|
documents->Set(count, doc);
|
|
++count;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// free data allocated by index result
|
|
TRI_FreeIndexIterator(indexIterator);
|
|
|
|
}
|
|
|
|
else {
|
|
LOG_WARNING("index iterator returned with a NULL value in ExecuteBitarrayQuery");
|
|
// return an empty list
|
|
}
|
|
|
|
if (lock) {
|
|
primary->endRead(primary);
|
|
}
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
|
|
result->Set(v8::String::New("total"), v8::Number::New((double) total));
|
|
result->Set(v8::String::New("count"), v8::Number::New(count));
|
|
|
|
if (lock) {
|
|
TRI_ReleaseCollection(collection);
|
|
}
|
|
|
|
if (error) {
|
|
return scope.Close(v8::Null());
|
|
}
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sorts geo coordinates
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int CompareGeoCoordinateDistance (geo_coordinate_distance_t* left,
|
|
geo_coordinate_distance_t* right) {
|
|
if (left->_distance < right->_distance) {
|
|
return -1;
|
|
}
|
|
else if (left->_distance > right->_distance) {
|
|
return 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#define FSRT_NAME SortGeoCoordinates
|
|
#define FSRT_NAM2 SortGeoCoordinatesTmp
|
|
#define FSRT_TYPE geo_coordinate_distance_t
|
|
|
|
#define FSRT_COMP(l,r,s) CompareGeoCoordinateDistance(l,r)
|
|
|
|
uint32_t FSRT_Rand = 0;
|
|
|
|
static uint32_t RandomGeoCoordinateDistance (void) {
|
|
return (FSRT_Rand = FSRT_Rand * 31415 + 27818);
|
|
}
|
|
|
|
#define FSRT__RAND \
|
|
((fs_b) + FSRT__UNIT * (RandomGeoCoordinateDistance() % FSRT__DIST(fs_e,fs_b,FSRT__SIZE)))
|
|
|
|
#include "BasicsC/fsrt.inc"
|
|
#include "strings.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates a geo result
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void StoreGeoResult (TRI_vocbase_col_t const* collection,
|
|
GeoCoordinates* cors,
|
|
v8::Handle<v8::Array>& documents,
|
|
v8::Handle<v8::Array>& distances) {
|
|
GeoCoordinate* end;
|
|
GeoCoordinate* ptr;
|
|
double* dtr;
|
|
geo_coordinate_distance_t* gnd;
|
|
geo_coordinate_distance_t* gtr;
|
|
geo_coordinate_distance_t* tmp;
|
|
size_t n;
|
|
uint32_t i;
|
|
TRI_barrier_t* barrier;
|
|
|
|
// sort the result
|
|
n = cors->length;
|
|
|
|
if (n == 0) {
|
|
GeoIndex_CoordinatesFree(cors);
|
|
return;
|
|
}
|
|
|
|
gtr = (tmp = (geo_coordinate_distance_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(geo_coordinate_distance_t) * n, false));
|
|
gnd = tmp + n;
|
|
|
|
ptr = cors->coordinates;
|
|
end = cors->coordinates + n;
|
|
|
|
dtr = cors->distances;
|
|
|
|
for (; ptr < end; ++ptr, ++dtr, ++gtr) {
|
|
gtr->_distance = *dtr;
|
|
gtr->_data = ptr->data;
|
|
}
|
|
|
|
GeoIndex_CoordinatesFree(cors);
|
|
|
|
SortGeoCoordinates(tmp, gnd);
|
|
|
|
barrier = TRI_CreateBarrierElement(&((TRI_primary_collection_t*) collection->_collection)->_barrierList);
|
|
// TODO: barrier might be 0
|
|
|
|
// copy the documents
|
|
for (gtr = tmp, i = 0; gtr < gnd; ++gtr, ++i) {
|
|
documents->Set(i, TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) gtr->_data, barrier));
|
|
distances->Set(i, v8::Number::New(gtr->_distance));
|
|
}
|
|
|
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, tmp);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- QUERY FUNCTIONS
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- private functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup VocBase
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief looks up edges for given direction
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
if (collection->_type != TRI_COL_TYPE_EDGE) {
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_ARANGO_COLLECTION_TYPE_INVALID,
|
|
"invalid collection type for edge query")));
|
|
}
|
|
|
|
// first and only argument schould be a list of document idenfifier
|
|
if (argv.Length() != 1) {
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
switch (direction) {
|
|
case TRI_EDGE_IN:
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: inEdges(<vertices>)")));
|
|
|
|
case TRI_EDGE_OUT:
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: outEdges(<vertices>)")));
|
|
|
|
case TRI_EDGE_ANY:
|
|
default: {
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: edges(<vertices>)")));
|
|
}
|
|
}
|
|
}
|
|
|
|
// setup result
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
primary->beginRead(primary);
|
|
|
|
TRI_barrier_t* barrier = 0;
|
|
uint32_t count = 0;
|
|
bool error = false;
|
|
|
|
// argument is a list of vertices
|
|
if (argv[0]->IsArray()) {
|
|
v8::Handle<v8::Array> vertices = v8::Handle<v8::Array>::Cast(argv[0]);
|
|
uint32_t len = vertices->Length();
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
TRI_vector_pointer_t edges;
|
|
TRI_voc_cid_t cid;
|
|
TRI_voc_rid_t rid;
|
|
TRI_voc_key_t key = 0;
|
|
|
|
TRI_vocbase_col_t const* vertexCollection = 0;
|
|
v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, key, rid, true, vertices->Get(i));
|
|
|
|
if (! errMsg.IsEmpty()) {
|
|
if (vertexCollection != 0) {
|
|
TRI_ReleaseCollection(vertexCollection);
|
|
}
|
|
|
|
if (key) {
|
|
TRI_FreeString(TRI_CORE_MEM_ZONE, key);
|
|
key = 0;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
cid = vertexCollection->_cid;
|
|
TRI_ReleaseCollection(vertexCollection);
|
|
|
|
edges = TRI_LookupEdgesDocumentCollection(document, direction, cid, key);
|
|
|
|
if (key) TRI_FreeString(TRI_CORE_MEM_ZONE, key);
|
|
|
|
for (size_t j = 0; j < edges._length; ++j) {
|
|
if (barrier == 0) {
|
|
barrier = TRI_CreateBarrierElement(&document->base._barrierList);
|
|
}
|
|
// TODO: barrier might be 0
|
|
|
|
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) edges._buffer[j], barrier);
|
|
|
|
if (doc.IsEmpty()) {
|
|
// error
|
|
error = true;
|
|
break;
|
|
}
|
|
else {
|
|
documents->Set(count, doc);
|
|
++count;
|
|
}
|
|
|
|
}
|
|
|
|
TRI_DestroyVectorPointer(&edges);
|
|
}
|
|
}
|
|
|
|
// argument is a single vertex
|
|
else {
|
|
TRI_vector_pointer_t edges;
|
|
TRI_voc_cid_t cid;
|
|
TRI_voc_rid_t rid;
|
|
TRI_voc_key_t key = 0;
|
|
|
|
TRI_vocbase_col_t const* vertexCollection = 0;
|
|
v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, key, rid, true, argv[0]);
|
|
|
|
if (! errMsg.IsEmpty()) {
|
|
if (vertexCollection != 0) {
|
|
TRI_ReleaseCollection(vertexCollection);
|
|
}
|
|
|
|
primary->endRead(primary);
|
|
|
|
if (key) {
|
|
TRI_FreeString(TRI_CORE_MEM_ZONE, key);
|
|
}
|
|
TRI_ReleaseCollection(collection);
|
|
return scope.Close(v8::ThrowException(errMsg));
|
|
}
|
|
|
|
cid = vertexCollection->_cid;
|
|
TRI_ReleaseCollection(vertexCollection);
|
|
|
|
edges = TRI_LookupEdgesDocumentCollection(document, direction, cid, key);
|
|
|
|
if (key) TRI_FreeString(TRI_CORE_MEM_ZONE, key);
|
|
|
|
for (size_t j = 0; j < edges._length; ++j) {
|
|
if (barrier == 0) {
|
|
barrier = TRI_CreateBarrierElement(&document->base._barrierList);
|
|
}
|
|
// TODO: barrier might be 0
|
|
|
|
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) edges._buffer[j], barrier);
|
|
|
|
if (doc.IsEmpty()) {
|
|
// error
|
|
error = true;
|
|
break;
|
|
}
|
|
else {
|
|
documents->Set(count, doc);
|
|
++count;
|
|
}
|
|
}
|
|
|
|
TRI_DestroyVectorPointer(&edges);
|
|
}
|
|
|
|
primary->endRead(primary);
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
if (error) {
|
|
return scope.Close(v8::Null());
|
|
}
|
|
|
|
return scope.Close(documents);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- javascript functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup VocBase
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief executes an ALL query, without any locking
|
|
///
|
|
/// the caller must ensure all relevant locks are acquired and freed
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> AllQuery (TRI_document_collection_t* document,
|
|
TRI_vocbase_col_t const* collection,
|
|
v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// expecting two arguments
|
|
if (argv.Length() != 2) {
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: ALL(<skip>, <limit>)")));
|
|
}
|
|
|
|
// extract skip and limit
|
|
TRI_voc_ssize_t skip;
|
|
TRI_voc_size_t limit;
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
ExtractSkipAndLimit(argv, 0, skip, limit);
|
|
|
|
// setup result
|
|
v8::Handle<v8::Object> result = v8::Object::New();
|
|
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
result->Set(v8::String::New("documents"), documents);
|
|
|
|
size_t total = primary->_primaryIndex._nrUsed;
|
|
uint32_t count = 0;
|
|
bool error = false;
|
|
|
|
if (0 < total && 0 < limit) {
|
|
TRI_barrier_t* barrier = 0;
|
|
|
|
void** beg = primary->_primaryIndex._table;
|
|
void** end = beg + primary->_primaryIndex._nrAlloc;
|
|
void** ptr = beg;
|
|
|
|
// skip from the beginning
|
|
if (0 < skip) {
|
|
for (; ptr < end && 0 < skip; ++ptr) {
|
|
if (*ptr) {
|
|
TRI_doc_mptr_t const* d = (TRI_doc_mptr_t const*) *ptr;
|
|
|
|
if (d->_validTo == 0) {
|
|
--skip;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// skip from the end
|
|
else if (skip < 0) {
|
|
ptr = end - 1;
|
|
|
|
for (; beg <= ptr; --ptr) {
|
|
if (*ptr) {
|
|
TRI_doc_mptr_t const* d = (TRI_doc_mptr_t const*) *ptr;
|
|
|
|
if (d->_validTo == 0) {
|
|
++skip;
|
|
|
|
if (skip == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ptr < beg) {
|
|
ptr = beg;
|
|
}
|
|
}
|
|
|
|
// limit
|
|
for (; ptr < end && count < limit; ++ptr) {
|
|
if (*ptr) {
|
|
TRI_doc_mptr_t const* d = (TRI_doc_mptr_t const*) *ptr;
|
|
|
|
if (d->_validTo == 0) {
|
|
if (barrier == 0) {
|
|
barrier = TRI_CreateBarrierElement(&document->base._barrierList);
|
|
}
|
|
// TODO: barrier might be 0
|
|
|
|
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, d, barrier);
|
|
|
|
if (doc.IsEmpty()) {
|
|
// error
|
|
error = true;
|
|
break;
|
|
}
|
|
else {
|
|
documents->Set(count, doc);
|
|
++count;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
result->Set(v8::String::New("total"), v8::Number::New((double) total));
|
|
result->Set(v8::String::New("count"), v8::Number::New(count));
|
|
|
|
if (error) {
|
|
return scope.Close(v8::Null());
|
|
}
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects all elements, acquiring all required locks
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
primary->beginRead(primary);
|
|
v8::Handle<v8::Value> result = AllQuery(document, collection, argv);
|
|
primary->endRead(primary);
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects all elements, without acquiring any locks
|
|
///
|
|
/// It is the callers responsibility to acquire and free the required locks
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_AllNLQuery (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
v8::Handle<v8::Value> result = AllQuery(document, collection, argv);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by example (not using any index)
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
TRI_shaper_t* shaper = document->base._shaper;
|
|
|
|
// expecting example, skip, limit
|
|
if (argv.Length() < 1) {
|
|
TRI_ReleaseCollection(collection);
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: BY_EXAMPLE(<example>, <skip>, <limit>)")));
|
|
}
|
|
|
|
// extract the example
|
|
if (! argv[0]->IsObject()) {
|
|
TRI_ReleaseCollection(collection);
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"<example> must be an object")));
|
|
}
|
|
|
|
v8::Handle<v8::Object> example = argv[0]->ToObject();
|
|
|
|
// extract skip and limit
|
|
TRI_voc_ssize_t skip;
|
|
TRI_voc_size_t limit;
|
|
|
|
ExtractSkipAndLimit(argv, 1, skip, limit);
|
|
|
|
// extract sub-documents
|
|
TRI_shape_pid_t* pids;
|
|
TRI_shaped_json_t** values;
|
|
size_t n;
|
|
|
|
int res = SetupExampleObject(example, shaper, n, pids, values, &err);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
TRI_ReleaseCollection(collection);
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
// setup result
|
|
v8::Handle<v8::Object> result = v8::Object::New();
|
|
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
result->Set(v8::String::New("documents"), documents);
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
TRI_doc_operation_context_t context;
|
|
|
|
TRI_InitReadContextPrimaryCollection(&context, primary);
|
|
|
|
primary->beginRead(primary);
|
|
|
|
// find documents by example
|
|
TRI_vector_t filtered = TRI_SelectByExample(&context, n, pids, values);
|
|
|
|
// convert to list of shaped jsons
|
|
size_t total = filtered._length;
|
|
size_t count = 0;
|
|
bool error = false;
|
|
|
|
if (0 < total) {
|
|
size_t s;
|
|
size_t e;
|
|
|
|
CalculateSkipLimitSlice(filtered._length, skip, limit, s, e);
|
|
|
|
if (s < e) {
|
|
// only go in here if something has to be done, otherwise barrier memory might be lost
|
|
TRI_barrier_t* barrier = TRI_CreateBarrierElement(&primary->_barrierList);
|
|
// TODO: barrier might be 0
|
|
|
|
for (size_t j = s; j < e; ++j) {
|
|
TRI_doc_mptr_t* mptr = (TRI_doc_mptr_t*) TRI_AtVector(&filtered, j);
|
|
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, mptr, barrier);
|
|
|
|
if (doc.IsEmpty()) {
|
|
// error
|
|
error = true;
|
|
break;
|
|
}
|
|
else {
|
|
documents->Set(count, doc);
|
|
++count;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
TRI_DestroyVector(&filtered);
|
|
|
|
primary->endRead(primary);
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
result->Set(v8::String::New("total"), v8::Number::New((double) total));
|
|
result->Set(v8::String::New("count"), v8::Number::New(count));
|
|
|
|
CleanupExampleObject(shaper, n, pids, values);
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
if (error) {
|
|
return scope.Close(v8::Null());
|
|
}
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by example using a hash index
|
|
///
|
|
/// It is the callers responsibility to acquire and free the required locks
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> ByExampleHashIndexQuery (TRI_document_collection_t* document,
|
|
TRI_vocbase_col_t const* collection,
|
|
v8::Handle<v8::Object>* err,
|
|
v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// expecting index, example, skip, and limit
|
|
if (argv.Length() < 2) {
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: BY_EXAMPLE_HASH(<index>, <example>, <skip>, <limit>)")));
|
|
}
|
|
|
|
// extract the example
|
|
if (! argv[1]->IsObject()) {
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"<example> must be an object")));
|
|
}
|
|
|
|
v8::Handle<v8::Object> example = argv[1]->ToObject();
|
|
|
|
// extract skip and limit
|
|
TRI_voc_ssize_t skip;
|
|
TRI_voc_size_t limit;
|
|
|
|
ExtractSkipAndLimit(argv, 2, skip, limit);
|
|
|
|
// setup result
|
|
v8::Handle<v8::Object> result = v8::Object::New();
|
|
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
result->Set(v8::String::New("documents"), documents);
|
|
|
|
// extract the index
|
|
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, err);
|
|
|
|
if (idx == 0) {
|
|
return scope.Close(v8::ThrowException(*err));
|
|
}
|
|
|
|
if (idx->_type != TRI_IDX_TYPE_HASH_INDEX) {
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a hash index")));
|
|
}
|
|
|
|
TRI_hash_index_t* hashIndex = (TRI_hash_index_t*) idx;
|
|
|
|
// convert the example (index is locked by beginRead)
|
|
size_t n;
|
|
TRI_shaped_json_t** values;
|
|
|
|
TRI_shaper_t* shaper = document->base._shaper;
|
|
int res = SetupExampleObjectIndex(hashIndex, example, shaper, n, values, err);
|
|
|
|
if (res != TRI_ERROR_NO_ERROR) {
|
|
return scope.Close(v8::ThrowException(*err));
|
|
}
|
|
|
|
// find the matches
|
|
TRI_hash_index_elements_t* list = TRI_LookupShapedJsonHashIndex(idx, values);
|
|
|
|
// convert result
|
|
size_t total = list->_numElements;
|
|
size_t count = 0;
|
|
bool error = false;
|
|
|
|
if (0 < total) {
|
|
size_t s;
|
|
size_t e;
|
|
|
|
CalculateSkipLimitSlice(total, skip, limit, s, e);
|
|
|
|
if (s < e) {
|
|
TRI_barrier_t* barrier = TRI_CreateBarrierElement(&document->base._barrierList);
|
|
// TODO: barrier might be 0
|
|
|
|
for (size_t i = s; i < e; ++i) {
|
|
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) list->_elements[i].data, barrier);
|
|
|
|
if (doc.IsEmpty()) {
|
|
// error
|
|
error = true;
|
|
break;
|
|
}
|
|
else {
|
|
documents->Set(count, doc);
|
|
++count;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// free data allocated by hash index result
|
|
TRI_FreeResultHashIndex(idx, list);
|
|
|
|
result->Set(v8::String::New("total"), v8::Number::New((double) total));
|
|
result->Set(v8::String::New("count"), v8::Number::New(count));
|
|
|
|
CleanupExampleObject(shaper, n, 0, values);
|
|
|
|
if (error) {
|
|
return scope.Close(v8::Null());
|
|
}
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by example using a hash index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
primary->beginRead(primary);
|
|
v8::Handle<v8::Value> result = ByExampleHashIndexQuery(document, collection, &err, argv);
|
|
primary->endRead(primary);
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by example using a hash index
|
|
///
|
|
/// It is the callers responsibility to acquire and free the required locks
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByExampleNLHashIndex (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
v8::Handle<v8::Value> result = ByExampleHashIndexQuery(document, collection, &err, argv);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by condition using a skiplist index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByConditionSkiplist (v8::Arguments const& argv) {
|
|
std::string signature("BY_CONDITION_SKIPLIST(<index>, <conditions>, <skip>, <limit>)");
|
|
|
|
return ExecuteSkiplistQuery(argv, signature, QUERY_CONDITION, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by condition using a skiplist index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByConditionNLSkiplist (v8::Arguments const& argv) {
|
|
std::string signature("BY_CONDITION_SKIPLIST_NL(<index>, <conditions>, <skip>, <limit>)");
|
|
|
|
return ExecuteSkiplistQuery(argv, signature, QUERY_CONDITION, false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by example using a skiplist index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByExampleSkiplist (v8::Arguments const& argv) {
|
|
std::string signature("BY_EXAMPLE_SKIPLIST(<index>, <example>, <skip>, <limit>)");
|
|
|
|
return ExecuteSkiplistQuery(argv, signature, QUERY_EXAMPLE, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by example using a skiplist index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByExampleNLSkiplist (v8::Arguments const& argv) {
|
|
std::string signature("BY_EXAMPLE_SKIPLIST_NL(<index>, <example>, <skip>, <limit>)");
|
|
|
|
return ExecuteSkiplistQuery(argv, signature, QUERY_EXAMPLE, false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects elements by example using a bitarray index
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_ByExampleBitarray (v8::Arguments const& argv) {
|
|
std::string signature("BY_EXAMPLE_BITARRAY(<index>, <example>, <skip>, <limit>)");
|
|
|
|
return ExecuteBitarrayQuery(argv, signature, QUERY_EXAMPLE, true);
|
|
}
|
|
|
|
static v8::Handle<v8::Value> JS_ByExampleNLBitarray (v8::Arguments const& argv) {
|
|
std::string signature("BY_EXAMPLE_BITARRAYNL(<index>, <example>, <skip>, <limit>)");
|
|
|
|
return ExecuteBitarrayQuery(argv, signature, QUERY_EXAMPLE, false);
|
|
}
|
|
|
|
static v8::Handle<v8::Value> JS_ByConditionBitarray (v8::Arguments const& argv) {
|
|
std::string signature("BY_CONDITION_BITARRAY(<index>, <conditions>, <skip>, <limit>)");
|
|
|
|
return ExecuteBitarrayQuery(argv, signature, QUERY_CONDITION, true);
|
|
}
|
|
|
|
static v8::Handle<v8::Value> JS_ByConditionNLBitarray (v8::Arguments const& argv) {
|
|
std::string signature("BY_CONDITION_BITARRAY_NL(<index>, <conditions>, <skip>, <limit>)");
|
|
|
|
return ExecuteBitarrayQuery(argv, signature, QUERY_CONDITION, false);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects all edges for a set of vertices
|
|
///
|
|
/// @FUN{@FA{edge-collection}.edges(@FA{vertex})}
|
|
///
|
|
/// The @FN{edges} operator finds all edges starting from (outbound) or ending
|
|
/// in (inbound) @FA{vertex}.
|
|
///
|
|
/// @FUN{@FA{edge-collection}.edges(@FA{vertices})}
|
|
///
|
|
/// The @FN{edges} operator finds all edges starting from (outbound) or ending
|
|
/// in (inbound) a document from @FA{vertices}, which must a list of documents
|
|
/// or document handles.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// @verbinclude shell-edge-edges
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_EdgesQuery (v8::Arguments const& argv) {
|
|
return EdgesQuery(TRI_EDGE_ANY, argv);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects all inbound edges
|
|
///
|
|
/// @FUN{@FA{edge-collection}.inEdges(@FA{vertex})}
|
|
///
|
|
/// The @FN{edges} operator finds all edges ending in (inbound) @FA{vertex}.
|
|
///
|
|
/// @FUN{@FA{edge-collection}.inEdges(@FA{vertices})}
|
|
///
|
|
/// The @FN{edges} operator finds all edges ending in (inbound) a document from
|
|
/// @FA{vertices}, which must a list of documents or document handles.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// @verbinclude shell-edge-in-edges
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_InEdgesQuery (v8::Arguments const& argv) {
|
|
return EdgesQuery(TRI_EDGE_IN, argv);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects points near a given coordinate
|
|
///
|
|
/// the caller must ensure all relevant locks are acquired and freed
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> NearQuery (TRI_document_collection_t* document,
|
|
TRI_vocbase_col_t const* collection,
|
|
v8::Handle<v8::Object>* err,
|
|
v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// expect: NEAR(<index-id>, <latitude>, <longitude>, <limit>)
|
|
if (argv.Length() != 4) {
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: NEAR(<index-handle>, <latitude>, <longitude>, <limit>)")));
|
|
}
|
|
|
|
// extract the index
|
|
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, err);
|
|
|
|
if (idx == 0) {
|
|
return scope.Close(v8::ThrowException(*err));
|
|
}
|
|
|
|
if (idx->_type != TRI_IDX_TYPE_GEO1_INDEX && idx->_type != TRI_IDX_TYPE_GEO2_INDEX) {
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index")));
|
|
}
|
|
|
|
// extract latitude and longitude
|
|
double latitude = TRI_ObjectToDouble(argv[1]);
|
|
double longitude = TRI_ObjectToDouble(argv[2]);
|
|
|
|
// extract the limit
|
|
TRI_voc_ssize_t limit = (TRI_voc_ssize_t) TRI_ObjectToDouble(argv[3]);
|
|
|
|
// setup result
|
|
v8::Handle<v8::Object> result = v8::Object::New();
|
|
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
result->Set(v8::String::New("documents"), documents);
|
|
|
|
v8::Handle<v8::Array> distances = v8::Array::New();
|
|
result->Set(v8::String::New("distances"), distances);
|
|
|
|
GeoCoordinates* cors = TRI_NearestGeoIndex(idx, latitude, longitude, limit);
|
|
|
|
if (cors != 0) {
|
|
StoreGeoResult(collection, cors, documents, distances);
|
|
}
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects points near a given coordinate
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
primary->beginRead(primary);
|
|
v8::Handle<v8::Value> result = NearQuery(document, collection, &err, argv);
|
|
primary->endRead(primary);
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects points near a given coordinate
|
|
///
|
|
/// It is the callers responsibility to acquire and free the required locks
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_NearNLQuery (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
v8::Handle<v8::Value> result = NearQuery(document, collection, &err, argv);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects all outbound edges
|
|
///
|
|
/// @FUN{@FA{edge-collection}.outEdges(@FA{vertex})}
|
|
///
|
|
/// The @FN{edges} operator finds all edges starting from (outbound)
|
|
/// @FA{vertices}.
|
|
///
|
|
/// @FUN{@FA{edge-collection}.outEdges(@FA{vertices})}
|
|
///
|
|
/// The @FN{edges} operator finds all edges starting from (outbound) a document
|
|
/// from @FA{vertices}, which must a list of documents or document handles.
|
|
///
|
|
/// @EXAMPLES
|
|
///
|
|
/// @verbinclude shell-edge-out-edges
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_OutEdgesQuery (v8::Arguments const& argv) {
|
|
return EdgesQuery(TRI_EDGE_OUT, argv);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects points within a given radius
|
|
///
|
|
/// the caller must ensure all relevant locks are acquired and freed
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> WithinQuery (TRI_document_collection_t* document,
|
|
TRI_vocbase_col_t const* collection,
|
|
v8::Handle<v8::Object>* err,
|
|
v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// expect: WITHIN(<index-handle>, <latitude>, <longitude>, <limit>)
|
|
if (argv.Length() != 4) {
|
|
return scope.Close(v8::ThrowException(
|
|
TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER,
|
|
"usage: WITHIN(<index-handle>, <latitude>, <longitude>, <radius>)")));
|
|
}
|
|
|
|
// extract the index
|
|
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, err);
|
|
|
|
if (idx == 0) {
|
|
return scope.Close(v8::ThrowException(*err));
|
|
}
|
|
|
|
if (idx->_type != TRI_IDX_TYPE_GEO1_INDEX && idx->_type != TRI_IDX_TYPE_GEO2_INDEX) {
|
|
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a geo-index")));
|
|
}
|
|
|
|
// extract latitude and longitude
|
|
double latitude = TRI_ObjectToDouble(argv[1]);
|
|
double longitude = TRI_ObjectToDouble(argv[2]);
|
|
|
|
// extract the limit
|
|
double radius = TRI_ObjectToDouble(argv[3]);
|
|
|
|
// setup result
|
|
v8::Handle<v8::Object> result = v8::Object::New();
|
|
|
|
v8::Handle<v8::Array> documents = v8::Array::New();
|
|
result->Set(v8::String::New("documents"), documents);
|
|
|
|
v8::Handle<v8::Array> distances = v8::Array::New();
|
|
result->Set(v8::String::New("distances"), distances);
|
|
|
|
GeoCoordinates* cors = TRI_WithinGeoIndex(idx, latitude, longitude, radius);
|
|
|
|
if (cors != 0) {
|
|
StoreGeoResult(collection, cors, documents, distances);
|
|
}
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects points within a given radius
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract and use the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
// .............................................................................
|
|
// inside a read transaction
|
|
// .............................................................................
|
|
|
|
TRI_primary_collection_t* primary = &document->base;
|
|
|
|
primary->beginRead(primary);
|
|
v8::Handle<v8::Value> result = WithinQuery(document, collection, &err, argv);
|
|
primary->endRead(primary);
|
|
|
|
// .............................................................................
|
|
// outside a write transaction
|
|
// .............................................................................
|
|
|
|
TRI_ReleaseCollection(collection);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief selects points within a given radius
|
|
///
|
|
/// It is the callers responsibility to acquire and free the required locks
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static v8::Handle<v8::Value> JS_WithinNLQuery (v8::Arguments const& argv) {
|
|
v8::HandleScope scope;
|
|
|
|
// extract the simple collection
|
|
v8::Handle<v8::Object> err;
|
|
TRI_vocbase_col_t const* collection;
|
|
TRI_document_collection_t* document = TRI_ExtractSimpleCollection(argv, collection, &err);
|
|
|
|
if (document == 0) {
|
|
return scope.Close(v8::ThrowException(err));
|
|
}
|
|
|
|
v8::Handle<v8::Value> result = WithinQuery(document, collection, &err, argv);
|
|
|
|
return scope.Close(result);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- MODULE
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- public functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup VocBase
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates the query functions
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void TRI_InitV8Queries (v8::Handle<v8::Context> context) {
|
|
v8::HandleScope scope;
|
|
|
|
v8::Handle<v8::ObjectTemplate> rt;
|
|
|
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
TRI_v8_global_t* v8g = (TRI_v8_global_t*) isolate->GetData();
|
|
|
|
assert(v8g != 0);
|
|
|
|
|
|
// .............................................................................
|
|
// generate the TRI_vocbase_col_t template
|
|
// .............................................................................
|
|
|
|
rt = v8g->VocbaseColTempl;
|
|
|
|
// the _NL functions are the same as their unsuffixed counterparts, just without any locking
|
|
TRI_AddMethodVocbase(rt, "ALL", JS_AllQuery);
|
|
TRI_AddMethodVocbase(rt, "ALL_NL", JS_AllNLQuery, true);
|
|
TRI_AddMethodVocbase(rt, "BY_CONDITION_BITARRAY", JS_ByConditionBitarray);
|
|
TRI_AddMethodVocbase(rt, "BY_CONDITION_BITARRAY_NL", JS_ByConditionNLBitarray, true);
|
|
TRI_AddMethodVocbase(rt, "BY_CONDITION_SKIPLIST", JS_ByConditionSkiplist);
|
|
TRI_AddMethodVocbase(rt, "BY_CONDITION_SKIPLIST_NL", JS_ByConditionNLSkiplist, true);
|
|
TRI_AddMethodVocbase(rt, "BY_EXAMPLE", JS_ByExampleQuery);
|
|
TRI_AddMethodVocbase(rt, "BY_EXAMPLE_BITARRAY", JS_ByExampleBitarray);
|
|
TRI_AddMethodVocbase(rt, "BY_EXAMPLE_BITARRAY_NL", JS_ByExampleNLBitarray, true);
|
|
TRI_AddMethodVocbase(rt, "BY_EXAMPLE_HASH", JS_ByExampleHashIndex);
|
|
TRI_AddMethodVocbase(rt, "BY_EXAMPLE_HASH_NL", JS_ByExampleNLHashIndex, true);
|
|
TRI_AddMethodVocbase(rt, "BY_EXAMPLE_SKIPLIST", JS_ByExampleSkiplist);
|
|
TRI_AddMethodVocbase(rt, "BY_EXAMPLE_SKIPLIST_NL", JS_ByExampleNLSkiplist, true);
|
|
TRI_AddMethodVocbase(rt, "edges", JS_EdgesQuery);
|
|
TRI_AddMethodVocbase(rt, "inEdges", JS_InEdgesQuery);
|
|
TRI_AddMethodVocbase(rt, "NEAR", JS_NearQuery);
|
|
TRI_AddMethodVocbase(rt, "NEARL_NL", JS_NearNLQuery, true);
|
|
TRI_AddMethodVocbase(rt, "outEdges", JS_OutEdgesQuery);
|
|
TRI_AddMethodVocbase(rt, "WITHIN", JS_WithinQuery);
|
|
TRI_AddMethodVocbase(rt, "WITHIN_NL", JS_WithinNLQuery, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\)"
|
|
// End:
|