diff --git a/3rdParty/libev/ev.c b/3rdParty/libev/ev.c index fe1b6ac86c..0c5e870238 100644 --- a/3rdParty/libev/ev.c +++ b/3rdParty/libev/ev.c @@ -1251,7 +1251,11 @@ typedef struct #include "ev_wrap.h" static struct ev_loop default_loop_struct; +#ifdef EV_API_STATIC EV_API_DECL struct ev_loop *ev_default_loop_ptr = 0; /* needs to be initialised to make it a definition despite extern */ +#else + struct ev_loop *ev_default_loop_ptr = 0; /* needs to be initialised to make it a definition despite extern */ +#endif #else @@ -1378,23 +1382,23 @@ array_realloc (int elem, void *base, int *cur, int cnt) return ev_realloc (base, elem * *cur); } -#define array_init_zero(base,count) \ +#define array_init_zero(base,count) \ memset ((void *)(base), 0, sizeof (*(base)) * (count)) -#define array_needsize(type,base,cur,cnt,init) \ - if (expect_false ((cnt) > (cur))) \ - { \ - int ecb_unused ocur_ = (cur); \ - (base) = (type *)array_realloc \ - (sizeof (type), (base), &(cur), (cnt)); \ - init ((base) + (ocur_), (cur) - ocur_); \ +#define array_needsize(type,base,cur,cnt,init) \ + if (expect_false ((cnt) > (cur))) \ + { \ + int ecb_unused ocur_ = (cur); \ + (base) = (type *)array_realloc \ + (sizeof (type), (base), &(cur), (cnt)); \ + init ((base) + (ocur_), (cur) - ocur_); \ } #if 0 -#define array_slim(type,stem) \ - if (stem ## max < array_roundsize (stem ## cnt >> 2)) \ - { \ - stem ## max = array_roundsize (stem ## cnt >> 1); \ +#define array_slim(type,stem) \ + if (stem ## max < array_roundsize (stem ## cnt >> 2)) \ + { \ + stem ## max = array_roundsize (stem ## cnt >> 1); \ base = (type *)ev_realloc (base, sizeof (type) * (stem ## max));\ fprintf (stderr, "slimmed down " # stem " to %d\n", stem ## max);/*D*/\ } diff --git a/3rdParty/mruby/include/mruby.h b/3rdParty/mruby/include/mruby.h index 7a46992ee5..738add91c4 100644 --- a/3rdParty/mruby/include/mruby.h +++ b/3rdParty/mruby/include/mruby.h @@ -143,7 +143,7 @@ mrb_obj_value(void *p) } static inline mrb_value -mrb_false_value() +mrb_false_value(void) { mrb_value v; @@ -153,7 +153,7 @@ mrb_false_value() } static inline mrb_value -mrb_nil_value() +mrb_nil_value(void) { mrb_value v; @@ -163,7 +163,7 @@ mrb_nil_value() } static inline mrb_value -mrb_true_value() +mrb_true_value(void) { mrb_value v; @@ -173,7 +173,7 @@ mrb_true_value() } static inline mrb_value -mrb_undef_value() +mrb_undef_value(void) { mrb_value v; diff --git a/3rdParty/mruby/include/mruby/variable.h b/3rdParty/mruby/include/mruby/variable.h index eb21ceeba6..7d694b620a 100644 --- a/3rdParty/mruby/include/mruby/variable.h +++ b/3rdParty/mruby/include/mruby/variable.h @@ -10,8 +10,8 @@ typedef struct global_variable { int counter; mrb_value *data; - mrb_value (*getter)(); - void (*setter)(); + mrb_value (*getter)(void); + void (*setter)(void); //void (*marker)(); //int block_trace; //struct trace_var *trace; diff --git a/Ahuacatl/ahuacatl-functions.c b/Ahuacatl/ahuacatl-functions.c index ff379d3171..17fea906a3 100644 --- a/Ahuacatl/ahuacatl-functions.c +++ b/Ahuacatl/ahuacatl-functions.c @@ -342,6 +342,7 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { // . = argument of any type (except collection) // c = collection + // z = null // b = bool // n = number // s = string @@ -356,8 +357,8 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { REGISTER_FUNCTION("TONULL", "CAST_NULL", true, false, "."); // string functions - REGISTER_FUNCTION("CONCAT", "STRING_CONCAT", true, false, "s,s|+"); - REGISTER_FUNCTION("CONCATSEPARATOR", "STRING_CONCAT_SEPARATOR", true, false, "s,s,s|+"); + REGISTER_FUNCTION("CONCAT", "STRING_CONCAT", true, false, "sz,sz|+"); + REGISTER_FUNCTION("CONCATSEPARATOR", "STRING_CONCAT_SEPARATOR", true, false, "s,sz,sz|+"); REGISTER_FUNCTION("CHARLENGTH", "STRING_LENGTH", true, false, "s"); REGISTER_FUNCTION("LOWER", "STRING_LOWER", true, false, "s"); REGISTER_FUNCTION("UPPER", "STRING_UPPER", true, false, "s"); @@ -381,10 +382,15 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { // geo functions REGISTER_FUNCTION("NEAR", "GEO_NEAR", false, false, "c,n,n,n|s"); REGISTER_FUNCTION("WITHIN", "GEO_WITHIN", false, false, "c,n,n,n|s"); + + // graph functions + REGISTER_FUNCTION("PATHS", "GRAPH_PATHS", false, false, "c,s|n,n,b"); // misc functions REGISTER_FUNCTION("FAIL", "FAIL", false, false, "|s"); // FAIL is non-deterministic, otherwise query optimisation will fail! REGISTER_FUNCTION("PASSTHRU", "PASSTHRU", false, false, "."); // simple non-deterministic wrapper to avoid optimisations at parse time + REGISTER_FUNCTION("COLLECTIONS", "COLLECTIONS", false, false, ""); + REGISTER_FUNCTION("HAS", "HAS", true, false, "az,s"); REGISTER_FUNCTION("MERGE", "MERGE", true, false, "a,a|+"); @@ -394,6 +400,10 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) { REGISTER_FUNCTION("MIN", "MIN", true, true, "l"); REGISTER_FUNCTION("MAX", "MAX", true, true, "l"); REGISTER_FUNCTION("SUM", "SUM", true, true, "l"); + REGISTER_FUNCTION("UNIQUE", "UNIQUE", true, false, "l"); + REGISTER_FUNCTION("REVERSE", "REVERSE", true, false, "l"); + REGISTER_FUNCTION("FIRST", "FIRST", true, false, "l"); + REGISTER_FUNCTION("LAST", "LAST", true, false, "l"); if (!result) { TRI_FreeFunctionsAql(functions); @@ -532,9 +542,7 @@ bool TRI_ValidateArgsFunctionAql (TRI_aql_context_t* const context, const char* pattern; size_t i, n; bool eof = false; - bool parse = true; bool repeat = false; - bool foundArg = false; assert(function); assert(parameters); @@ -554,6 +562,8 @@ bool TRI_ValidateArgsFunctionAql (TRI_aql_context_t* const context, // validate argument types for (i = 0; i < n; ++i) { TRI_aql_node_t* parameter = (TRI_aql_node_t*) TRI_AQL_NODE_MEMBER(parameters, i); + bool parse = true; + bool foundArg = false; if (repeat) { // last argument is repeated @@ -565,11 +575,9 @@ bool TRI_ValidateArgsFunctionAql (TRI_aql_context_t* const context, foundArg = false; - while (parse) { + while (parse && !eof) { char c = *pattern++; - assert(!eof); - switch (c) { case '\0': parse = false; @@ -582,19 +590,21 @@ bool TRI_ValidateArgsFunctionAql (TRI_aql_context_t* const context, if (foundArg) { parse = false; ARG_CHECK - break; + if (*pattern == '+') { + repeat = true; + eof = true; + } } break; case ',': // next argument assert(foundArg); - foundArg = false; parse = false; ARG_CHECK break; case '+': // repeat last argument - assert(foundArg); repeat = true; parse = false; + eof = true; ARG_CHECK break; case '.': // any type except collections diff --git a/Ahuacatl/ahuacatl-optimiser.c b/Ahuacatl/ahuacatl-optimiser.c index 5b92de5c1a..fe7bc22eb6 100644 --- a/Ahuacatl/ahuacatl-optimiser.c +++ b/Ahuacatl/ahuacatl-optimiser.c @@ -811,8 +811,12 @@ static TRI_aql_node_t* OptimiseBinaryArithmeticOperation (TRI_aql_context_t* con } value = fmod(TRI_GetNumericNodeValueAql(lhs), TRI_GetNumericNodeValueAql(rhs)); } + else { + value = 0.0; + } node = TRI_CreateNodeValueDoubleAql(context, value); + if (!node) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); return NULL; diff --git a/JsonParserX/JsonScannerX.cpp b/JsonParserX/JsonScannerX.cpp index d751823fd0..9b8c35d560 100644 --- a/JsonParserX/JsonScannerX.cpp +++ b/JsonParserX/JsonScannerX.cpp @@ -838,7 +838,6 @@ static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); #endif -#define YY_NO_INPUT #ifndef YY_NO_INPUT /* %if-c-only Standard (non-C++) definition */ /* %not-for-header */ @@ -1683,7 +1682,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, (size_t) num_to_read ); + yyg->yy_n_chars, (int) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } diff --git a/MRuby/MRLineEditor.cpp b/MRuby/MRLineEditor.cpp index 8ecbba3d69..a6d0497e56 100644 --- a/MRuby/MRLineEditor.cpp +++ b/MRuby/MRLineEditor.cpp @@ -62,11 +62,13 @@ using namespace std; /// @brief word break characters //////////////////////////////////////////////////////////////////////////////// +#if 0 static char WordBreakCharacters[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '<', '>', '=', ';', '|', '&', '{', '}', '(', ')', '\0' }; +#endif //////////////////////////////////////////////////////////////////////////////// /// @} @@ -199,6 +201,7 @@ static char* CompletionGenerator (char const* text, int state) { /// @brief attempted completion //////////////////////////////////////////////////////////////////////////////// +#if 0 static char** AttemptedCompletion (char const* text, int start, int end) { char** result; @@ -219,6 +222,7 @@ static char** AttemptedCompletion (char const* text, int start, int end) { return result; } +#endif //////////////////////////////////////////////////////////////////////////////// /// @} @@ -281,7 +285,7 @@ bool MRLineEditor::open (const bool autoComplete) { bool MRLineEditor::isComplete (string const& source, size_t lineno, size_t column) { -#ifdef TRI_ENABLE_MRUBY +#ifdef TRI_ENABLE_MRUBY char const* msg = "syntax error, unexpected $end"; char* text = TRI_DuplicateString(source.c_str()); diff --git a/MRuby/mr-utils.h b/MRuby/mr-utils.h index 2d96c2fbf4..ee19b3265f 100644 --- a/MRuby/mr-utils.h +++ b/MRuby/mr-utils.h @@ -76,7 +76,7 @@ MR_state_t; /// @brief opens a new context //////////////////////////////////////////////////////////////////////////////// -MR_state_t* MR_OpenShell (); +MR_state_t* MR_OpenShell (void); //////////////////////////////////////////////////////////////////////////////// /// @brief creates a ArangoError diff --git a/Makefile.in b/Makefile.in index 097dc0000a..c9c4bbe6db 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1057,6 +1057,7 @@ SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-operators.js \ @srcdir@/js/server/tests/ahuacatl-relational.js \ @srcdir@/js/server/tests/ahuacatl-ternary.js \ @srcdir@/js/server/tests/ahuacatl-parse.js \ + @srcdir@/js/server/tests/ahuacatl-hash.js \ @srcdir@/js/server/tests/ahuacatl-skiplist.js \ @srcdir@/js/server/tests/ahuacatl-queries-simple.js \ @srcdir@/js/server/tests/ahuacatl-queries-variables.js \ diff --git a/Makefile.unittests b/Makefile.unittests index 7d02db45d2..73f7ab2f42 100644 --- a/Makefile.unittests +++ b/Makefile.unittests @@ -186,6 +186,7 @@ SHELL_SERVER_AHUACATL = @srcdir@/js/server/tests/ahuacatl-operators.js \ @srcdir@/js/server/tests/ahuacatl-relational.js \ @srcdir@/js/server/tests/ahuacatl-ternary.js \ @srcdir@/js/server/tests/ahuacatl-parse.js \ + @srcdir@/js/server/tests/ahuacatl-hash.js \ @srcdir@/js/server/tests/ahuacatl-skiplist.js \ @srcdir@/js/server/tests/ahuacatl-queries-simple.js \ @srcdir@/js/server/tests/ahuacatl-queries-variables.js \ diff --git a/README.md b/README.md index 7ce0619edc..562846f44c 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ The ArangoDB shell will be install as Start the server: > mkdir /tmp/vocbase - > ./arango /tmp/vocbase + > ./arangod /tmp/vocbase 2012-03-30T12:54:19Z [11794] INFO ArangoDB (version 0.x.y) is ready for business 2012-03-30T12:54:19Z [11794] INFO HTTP client port: 127.0.0.1:8529 2012-03-30T12:54:19Z [11794] INFO HTTP admin port: 127.0.0.1:8530 @@ -56,7 +56,7 @@ Start the server: Start the shell in another windows: - > ./avocsh + > ./arangosh _ __ _ _ __ __ _ _ __ __ _ ___ ___| |__ / _` | '__/ _` | '_ \ / _` |/ _ \/ __| '_ \ @@ -64,19 +64,19 @@ Start the shell in another windows: \__,_|_| \__,_|_| |_|\__, |\___/|___/_| |_| |___/ - Welcome to avocsh 0.3.5. Copyright (c) 2012 triAGENS GmbH. + Welcome to arangosh 0.3.5. Copyright (c) 2012 triAGENS GmbH. Using Google V8 3.9.4.0 JavaScript engine. Using READLINE 6.1. Connected to Arango DB 127.0.0.1:8529 Version 0.3.5 - avocsh> db._create("examples") + arangosh> db._create("examples") [ArangoCollection 106097, "examples] - avocsh> db.examples.save({ Hallo: "World" }); + arangosh> db.examples.save({ Hallo: "World" }); {"error":false,"_id":"106097/2333739","_rev":2333739} - avocsh> db.examples.all(); + arangosh> db.examples.all(); [{ _id : "82883/1524675", _rev : 1524675, Hallo : "World" }] ## Caveat diff --git a/RestServer/ArangoServer.cpp b/RestServer/ArangoServer.cpp index af83a13399..d4b2d55bdd 100644 --- a/RestServer/ArangoServer.cpp +++ b/RestServer/ArangoServer.cpp @@ -695,6 +695,8 @@ int ArangoServer::startupServer () { RestHandlerCreator::createData< pair< TRI_vocbase_t*, set* >* >, (void*) &handlerDataAdmin); + adminFactory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_IMPORT_PATH, RestHandlerCreator::createData, _vocbase); + _adminHttpServer = _applicationHttpServer->buildServer(new ArangoHttpServer(scheduler, dispatcher), adminFactory, adminPorts); } diff --git a/ShapedJson/shaped-json.c b/ShapedJson/shaped-json.c index ba1ed5466f..63c35219ed 100644 --- a/ShapedJson/shaped-json.c +++ b/ShapedJson/shaped-json.c @@ -863,7 +863,8 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_shape_value_t* dst, T a = (TRI_array_shape_t*) (ptr = TRI_Allocate(shaper->_memoryZone, i, true)); if (ptr == NULL) { - // TODO: FIXME my compiler complains about e being potentially undefined. what to do? + e = values + n; + for (p = values; p < e; ++p) { if (p->_value != NULL) { TRI_Free(shaper->_memoryZone, p->_value); diff --git a/SkipLists/skiplist.c b/SkipLists/skiplist.c index 3adaca96ef..1511365023 100644 --- a/SkipLists/skiplist.c +++ b/SkipLists/skiplist.c @@ -92,7 +92,7 @@ static void TRI_DestroySkipListNode (TRI_skiplist_base_t* skiplist, TRI_skiplist /// @brief Grow the node at the height specified. //////////////////////////////////////////////////////////////////////////////// -static bool GrowNodeHeight(TRI_skiplist_node_t* node, uint32_t newHeight) { +static bool GrowNodeHeight (TRI_skiplist_node_t* node, uint32_t newHeight) { TRI_skiplist_nb_t* oldColumn = node->_column; uint32_t j; diff --git a/UnitTests/Philadelphia/json-utilities-test.cpp b/UnitTests/Philadelphia/json-utilities-test.cpp index 64c418fba8..7748c16c55 100644 --- a/UnitTests/Philadelphia/json-utilities-test.cpp +++ b/UnitTests/Philadelphia/json-utilities-test.cpp @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE (tst_compare_values_unequal) { JSON_CHECK(-1, TRI_CompareValuesJson, "0", "[0]"); JSON_CHECK(-1, TRI_CompareValuesJson, "0", "[1]"); JSON_CHECK(-1, TRI_CompareValuesJson, "0", "[null]"); - JSON_CHECK(-1, TRI_CompareValuesJson, "0", "[false"); + JSON_CHECK(-1, TRI_CompareValuesJson, "0", "[false]"); JSON_CHECK(-1, TRI_CompareValuesJson, "0", "[true]"); JSON_CHECK(-1, TRI_CompareValuesJson, "0", "{}"); JSON_CHECK(-1, TRI_CompareValuesJson, "1", "[]"); @@ -176,7 +176,7 @@ BOOST_AUTO_TEST_CASE (tst_compare_values_unequal) { JSON_CHECK(-1, TRI_CompareValuesJson, "1", "[0]"); JSON_CHECK(-1, TRI_CompareValuesJson, "1", "[1]"); JSON_CHECK(-1, TRI_CompareValuesJson, "1", "[null]"); - JSON_CHECK(-1, TRI_CompareValuesJson, "1", "[false"); + JSON_CHECK(-1, TRI_CompareValuesJson, "1", "[false]"); JSON_CHECK(-1, TRI_CompareValuesJson, "1", "[true]"); JSON_CHECK(-1, TRI_CompareValuesJson, "1", "{}"); @@ -263,8 +263,8 @@ BOOST_AUTO_TEST_CASE (tst_check_in_list_empty) { JSON_CHECK(false, TRI_CheckInListJson, "0", "[]"); JSON_CHECK(false, TRI_CheckInListJson, "1", "[]"); JSON_CHECK(false, TRI_CheckInListJson, "\"fox\"", "[]"); - JSON_CHECK(false, TRI_CheckInListJson, "", "[]"); - JSON_CHECK(false, TRI_CheckInListJson, " ", "[]"); + JSON_CHECK(false, TRI_CheckInListJson, "\"\"", "[]"); + JSON_CHECK(false, TRI_CheckInListJson, "\" \"", "[]"); JSON_CHECK(false, TRI_CheckInListJson, "[]", "[]"); JSON_CHECK(false, TRI_CheckInListJson, "{}", "[]"); } diff --git a/Utilities/LineEditor.cpp b/Utilities/LineEditor.cpp index f826e11a1c..eb8567bc8c 100644 --- a/Utilities/LineEditor.cpp +++ b/Utilities/LineEditor.cpp @@ -56,6 +56,13 @@ LineEditor::LineEditor (string const& history) rl_initialize(); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief destructor +//////////////////////////////////////////////////////////////////////////////// + +LineEditor::~LineEditor () { +} + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/Utilities/LineEditor.h b/Utilities/LineEditor.h index a6e6c31655..55a9b93c48 100644 --- a/Utilities/LineEditor.h +++ b/Utilities/LineEditor.h @@ -89,6 +89,12 @@ class LineEditor { LineEditor (std::string const& history); +//////////////////////////////////////////////////////////////////////////////// +/// @brief destructor +//////////////////////////////////////////////////////////////////////////////// + + virtual ~LineEditor (); + //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// diff --git a/V8/v8-conv.cpp b/V8/v8-conv.cpp index 33d299aed0..e198b0f7a7 100644 --- a/V8/v8-conv.cpp +++ b/V8/v8-conv.cpp @@ -662,7 +662,8 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper, a = (TRI_array_shape_t*) (ptr = (char*) TRI_Allocate(shaper->_memoryZone, i, true)); if (ptr == NULL) { - // TODO FIXME: my compiler complains about e being potentially undefined. what to do? + e = values + n; + for (p = values; p < e; ++p) { if (p->_value != NULL) { TRI_Free(shaper->_memoryZone, p->_value); @@ -1340,7 +1341,7 @@ bool TRI_IdentifiersObjectReference (v8::Handle value, TRI_voc_cid_t& did = 0; if (value->IsNumber() || value->IsNumberObject()) { - did = TRI_ObjectToDouble(value, error); + did = (TRI_voc_did_t) TRI_ObjectToDouble(value, error); return ! error; } diff --git a/V8/v8-json.cpp b/V8/v8-json.cpp index 83ce22dfbc..4d3f53ee4b 100644 --- a/V8/v8-json.cpp +++ b/V8/v8-json.cpp @@ -1352,7 +1352,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, (size_t) num_to_read ); + yyg->yy_n_chars, (int) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } diff --git a/V8/v8-query.cpp b/V8/v8-query.cpp index b2a8e1f495..0c6816dd1a 100644 --- a/V8/v8-query.cpp +++ b/V8/v8-query.cpp @@ -977,7 +977,7 @@ static v8::Handle JS_AllQuery (v8::Arguments const& argv) { } // limit - for (; ptr < end && (TRI_voc_ssize_t) count < limit; ++ptr) { + for (; ptr < end && count < limit; ++ptr) { if (*ptr) { TRI_doc_mptr_t const* d = (TRI_doc_mptr_t const*) *ptr; @@ -1096,6 +1096,8 @@ static v8::Handle JS_ByExampleQuery (v8::Arguments const& argv) { } } + TRI_DestroyVector(&filtered); + collection->_collection->endRead(collection->_collection); // ............................................................................. diff --git a/VocBase/document-collection.c b/VocBase/document-collection.c index 7d78a89a9a..e86f6fe5ea 100644 --- a/VocBase/document-collection.c +++ b/VocBase/document-collection.c @@ -71,7 +71,7 @@ static TRI_doc_mptr_t CreateJson (TRI_doc_collection_t* collection, if (shaped == 0) { collection->base._lastError = TRI_set_errno(TRI_ERROR_ARANGO_SHAPER_FAILED); - result._did = 0; + memset(&result, 0, sizeof(result)); return result; } @@ -123,7 +123,7 @@ static TRI_doc_mptr_t UpdateJson (TRI_doc_collection_t* collection, if (shaped == 0) { collection->base._lastError = TRI_set_errno(TRI_ERROR_ARANGO_SHAPER_FAILED); - result._did = 0; + memset(&result, 0, sizeof(result)); return result; } diff --git a/VocBase/index.c b/VocBase/index.c index b44a1df62c..d77afab61e 100644 --- a/VocBase/index.c +++ b/VocBase/index.c @@ -434,6 +434,9 @@ TRI_index_t* TRI_CreateCapConstraint (struct TRI_doc_collection_s* collection, //////////////////////////////////////////////////////////////////////////////// void TRI_DestroyCapConstraint (TRI_index_t* idx) { + TRI_cap_constraint_t* cap = (TRI_cap_constraint_t*) idx; + + TRI_DestroyLinkedArray(&cap->_array); } //////////////////////////////////////////////////////////////////////////////// diff --git a/VocBase/simple-collection.c b/VocBase/simple-collection.c index 64c26fb1d8..38fe3892d7 100644 --- a/VocBase/simple-collection.c +++ b/VocBase/simple-collection.c @@ -331,7 +331,7 @@ static TRI_doc_mptr_t CreateDocument (TRI_sim_collection_t* sim, sim->base.endWrite(&sim->base); } - mptr._did = 0; + memset(&mptr, 0, sizeof(mptr)); return mptr; } @@ -562,7 +562,7 @@ static TRI_doc_mptr_t UpdateDocument (TRI_sim_collection_t* collection, } TRI_set_errno(TRI_ERROR_ARANGO_CONFLICT); - mptr._did = 0; + memset(&mptr, 0, sizeof(mptr)); return mptr; } } @@ -1012,7 +1012,7 @@ static TRI_doc_mptr_t ReadShapedJson (TRI_doc_collection_t* document, header = TRI_LookupByKeyAssociativePointer(&collection->_primaryIndex, &did); if (header == NULL || header->_deletion != 0) { - result._did = 0; + memset(&result, 0, sizeof(result)); return result; } else { @@ -1048,7 +1048,7 @@ static TRI_doc_mptr_t UpdateShapedJson (TRI_doc_collection_t* document, } TRI_set_errno(TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND); - mptr._did = 0; + memset(&mptr, 0, sizeof(mptr)); return mptr; } diff --git a/VocBase/voc-shaper.c b/VocBase/voc-shaper.c index b91ebb969e..fb152d42f2 100644 --- a/VocBase/voc-shaper.c +++ b/VocBase/voc-shaper.c @@ -617,6 +617,7 @@ TRI_shaper_t* TRI_CreateVocShaper (TRI_vocbase_t* vocbase, void TRI_DestroyVocShaper (TRI_shaper_t* s) { voc_shaper_t* shaper = (voc_shaper_t*) s; + size_t i; assert(shaper); assert(shaper->_collection); @@ -627,6 +628,13 @@ void TRI_DestroyVocShaper (TRI_shaper_t* s) { TRI_DestroyAssociativeSynced(&shaper->_attributeIds); TRI_DestroyAssociativeSynced(&shaper->_shapeDictionary); TRI_DestroyAssociativeSynced(&shaper->_shapeIds); + + for (i = 0; i < shaper->_accessors._nrAlloc; ++i) { + TRI_shape_access_t* accessor = (TRI_shape_access_t*) shaper->_accessors._table[i]; + if (accessor != NULL) { + TRI_FreeShapeAccessor(accessor); + } + } TRI_DestroyAssociativePointer(&shaper->_accessors); TRI_DestroyMutex(&shaper->_shapeLock); diff --git a/VocBase/vocbase.h b/VocBase/vocbase.h index 89702faa45..4f59f47d76 100644 --- a/VocBase/vocbase.h +++ b/VocBase/vocbase.h @@ -178,7 +178,7 @@ extern size_t PageSize; /// @brief no limit //////////////////////////////////////////////////////////////////////////////// -#define TRI_QRY_NO_LIMIT ((TRI_voc_size_t) UINT32_MAX) +#define TRI_QRY_NO_LIMIT ((TRI_voc_size_t) (4294967295U)) //////////////////////////////////////////////////////////////////////////////// /// @brief no skip diff --git a/build.sh b/build.sh index 7262013293..51ae563e46 100755 --- a/build.sh +++ b/build.sh @@ -9,7 +9,7 @@ echo OPTIONS="--disable-dependency-tracking --disable-relative" PREFIX="--prefix=/usr --sysconfdir=/etc" -RESULTS="arango avocsh avocirb" +RESULTS="arangod arangosh arangoimp" export CPPFLAGS="" export LDFLAGS="" @@ -26,20 +26,23 @@ case $TRI_OS_LONG in Linux-openSUSE-11.4*) echo "Using configuration for openSuSE 11.4" - OPTIONS="$OPTIONS --disable-all-in-one --with-boost-test" + OPTIONS="$OPTIONS --disable-all-in-one --with-boost-test --enable-mruby" LDD_INFO="yes" + RESULTS="$RESULTS arangoirb" ;; Linux-openSUSE-11*) echo "Using configuration for openSuSE 11" - OPTIONS="$OPTIONS --enable-all-in-one" + OPTIONS="$OPTIONS --enable-all-in-one --enable-mruby" LDD_INFO="yes" + RESULTS="$RESULTS arangoirb" ;; Linux-Debian-6*) echo "Using configuration for Debian" - OPTIONS="$OPTIONS --enable-all-in-one" + OPTIONS="$OPTIONS --enable-all-in-one --enable-mruby" LDD_INFO="yes" + RESULTS="$RESULTS arangoirb" ;; Linux-Debian*) @@ -56,21 +59,24 @@ case $TRI_OS_LONG in Linux-Ubuntu-11.10*) echo "Using configuration for Ubuntu" - OPTIONS="$OPTIONS --enable-all-in-one" + OPTIONS="$OPTIONS --enable-all-in-one --enable-mruby" LDD_INFO="yes" + RESULTS="$RESULTS arangoirb" ;; Linux-Ubuntu-*) echo "Using configuration for Ubuntu" - OPTIONS="$OPTIONS --enable-all-in-one" + OPTIONS="$OPTIONS --enable-all-in-one --enable-mruby" LDD_INFO="yes" + RESULTS="$RESULTS arangoirb" ;; Darwin*) echo "Using configuration for DARWIN" CPPFLAGS='-isystem /usr/include -isystem /opt/local/include -Wno-deprecated-declarations' LDFLAGS='-L/usr/lib -L/opt/local/lib' # need to use OpenSSL from system - OPTIONS="$OPTIONS --enable-all-in-one" + OPTIONS="$OPTIONS --enable-all-in-one --enable-mruby" + RESULTS="$RESULTS arangoirb" ;; *) diff --git a/config/flex-c++.sh b/config/flex-c++.sh index 4574a27b87..a31e658c83 100755 --- a/config/flex-c++.sh +++ b/config/flex-c++.sh @@ -26,7 +26,7 @@ test -f ${OUTPUT} || exit 1 ############################################################################# cat ${OUTPUT} \ - | sed -e 's:(yy_n_chars), (size_t) num_to_read );:(yy_n_chars), (int) num_to_read );:' \ + | sed -e 's:yy_n_chars, (size_t) num_to_read );:yy_n_chars, (int) num_to_read );:' \ > ${OUTPUT}.tmp # give some information diff --git a/coverage.sh b/coverage.sh index 1b29fb36bc..1bce6151c6 100644 --- a/coverage.sh +++ b/coverage.sh @@ -8,7 +8,7 @@ echo "########################################################" OPTIONS="--disable-dependency-tracking --disable-relative --enable-gcov" PREFIX="--prefix=/usr --sysconfdir=/etc" -RESULTS="arango avocsh" +RESULTS="arangod arangosh" export CPPFLAGS="" export LDFLAGS="" diff --git a/html/admin/css/layout.css b/html/admin/css/layout.css index e60d9346b8..86be9c3b45 100644 --- a/html/admin/css/layout.css +++ b/html/admin/css/layout.css @@ -1,3 +1,7 @@ +#delete { + padding-right: 15px; +} + button { padding: 0; } @@ -329,7 +333,7 @@ form { #queryOutput { height:40%; - yoverflow-y: auto; + overflow-y: auto; border: 1px solid black; background: white; font-family: "courier"; @@ -352,6 +356,7 @@ form { margin-top: 0px; background-color: white; height: 70%; + word-wrap: break-word; overflow-y: auto; width:100%; } diff --git a/html/admin/index.html b/html/admin/index.html index 7094b3771e..49bbf70a60 100644 --- a/html/admin/index.html +++ b/html/admin/index.html @@ -43,7 +43,7 @@ - + @@ -388,7 +388,7 @@
- ArangoDB Shell - click for more information + ArangoDB Shell - click for more informaytion

- - ArangoDB Query Language - click for more information + + ArangoDB Query Language - click for more information

diff --git a/html/admin/js/avocsh1.js b/html/admin/js/avocsh1.js index 225ca425f1..eb66a0e989 100644 --- a/html/admin/js/avocsh1.js +++ b/html/admin/js/avocsh1.js @@ -1,14 +1,20 @@ +var ModuleCache = { "/internal" : { "exports": { } } }; + +var SYS_START_PAGER = function() { }; +var SYS_STOP_PAGER = function() { }; +var TRI_SYS_OUTPUT = function() { }; + +var print = function (value) { + hansmann(value); +}; + function ArangoConnection () { } -function TRI_SYS_OUTPUT (a, b, c, d, e, f, g, h) { - return true; -} - var arango = new ArangoConnection(); -ArangoConnection.prototype.get = function (url, obj) { +ArangoConnection.prototype.get = function (url) { var msg; $.ajax({ async: false, @@ -24,10 +30,9 @@ var msg; } }); return msg; -} +}; - -ArangoConnection.prototype.delete = function (url, obj) { +ArangoConnection.prototype.delete = function (url) { var msg; $.ajax({ async: false, @@ -43,39 +48,40 @@ var msg; } }); return msg; -} +}; -ArangoConnection.prototype.post = function (url, body, obj) { -var msg; +ArangoConnection.prototype.post = function (url, body) { +var msg; $.ajax({ async: false, type: "POST", url: url, - data: obj, + data: body, contentType: "application/json", processData: false, success: function(data) { - msg = JSON.stringify(data); + msg = data; //JSON.stringify(data); }, error: function(data) { msg = JSON.stringify(data); } }); return msg; -} +}; -ArangoConnection.prototype.put = function (url, body, obj) { +ArangoConnection.prototype.put = function (url, body) { var msg; $.ajax({ async: false, type: "PUT", url: url, - data: obj, + data: body, contentType: "application/json", processData: false, success: function(data) { +return data; msg = JSON.stringify(data); }, error: function(data) { @@ -83,4 +89,9 @@ var msg; } }); return msg; -} +}; + +ArangoConnection.prototype.GET = ArangoConnection.prototype.get; +ArangoConnection.prototype.POST = ArangoConnection.prototype.post; +ArangoConnection.prototype.DELETE = ArangoConnection.prototype.delete; +ArangoConnection.prototype.PUT = ArangoConnection.prototype.put; diff --git a/html/admin/js/client.js b/html/admin/js/client.js deleted file mode 100644 index 75f2792bdc..0000000000 --- a/html/admin/js/client.js +++ /dev/null @@ -1,2151 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// @brief ArangoShell client API -/// -/// @file -/// -/// DISCLAIMER -/// -/// Copyright 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 Achim Brandt -/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- global variables -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief default collection for saving queries -//////////////////////////////////////////////////////////////////////////////// - -var DEFAULT_QUERY_COLLECTION = "query"; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief help texts -//////////////////////////////////////////////////////////////////////////////// - -var HELP = ""; -var helpQueries = ""; -var helpArangoDatabase = ""; -var helpArangoCollection = ""; -var helpArangoQueryCursor = ""; -var helpArangoStoredStatement = ""; -var helpArangoStatement = ""; -var helpExtended = ""; - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a formatted type string for object -/// -/// If the object has an id, it will be included in the string. -//////////////////////////////////////////////////////////////////////////////// - -function TRI_GetIdString (object, typeName) { - var result = "[object " + typeName; - - if (object._id) { - result += ":" + object._id; - } - else if (object.data && object.data._id) { - result += ":" + object.data._id; - } - - result += "]"; - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief handles error results -/// -/// throws an exception in case of an an error -//////////////////////////////////////////////////////////////////////////////// - -function TRI_CheckRequestResult (requestResult) { - if (requestResult == undefined) { - requestResult = { - "error" : true, - "code" : 0, - "errorNum" : 0, - "errorMessage" : "Unknown error. Request result is empty" - } - } - - if (requestResult["error"] != undefined && requestResult["error"]) { - throw new ArangoError(requestResult); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief create a formatted headline text -//////////////////////////////////////////////////////////////////////////////// - -function TRI_CreateHelpHeadline (text) { - var x = parseInt(Math.abs(78 - text.length) / 2); - - var p = ""; - for (var i = 0; i < x; ++i) { - p += "-"; - } - - return "\n" + p + " " + text + " " + p + "\n"; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- public functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief turn off pretty print2ing -//////////////////////////////////////////////////////////////////////////////// - -function print2_plain (data) { - var p = PRETTY_PRINT; - PRETTY_PRINT = false; - var c; - if (typeof(COLOR_OUTPUT) != undefined) { - c = COLOR_OUTPUT; - COLOR_OUTPUT = undefined; - } - - try { - print2(data); - PRETTY_PRINT = p; - if (typeof(c) != undefined) { - COLOR_OUTPUT = c; - } - } - catch (e) { - PRETTY_PRINT = p; - if (typeof(c) != undefined) { - COLOR_OUTPUT = c; - } - throw e.message; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief start pretty print2ing -//////////////////////////////////////////////////////////////////////////////// - -function start_pretty_print2 () { - print2("use pretty print2ing"); - PRETTY_PRINT=true; - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief stop pretty print2ing -//////////////////////////////////////////////////////////////////////////////// - -function stop_pretty_print2 () { - print2("stop pretty print2ing"); - PRETTY_PRINT=false; - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief start pretty print2ing with optional color -//////////////////////////////////////////////////////////////////////////////// - -function start_color_print2 (color) { - if (typeof(color) == "string") { - COLOR_OUTPUT = color; - } - else { - COLOR_OUTPUT = COLOR_BRIGHT; - } - print2("start " + COLOR_OUTPUT + "color" + COLOR_OUTPUT_RESET + " print2ing"); - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief stop pretty print2ing -//////////////////////////////////////////////////////////////////////////////// - -function stop_color_print2 () { - print2("stop color print2ing"); - COLOR_OUTPUT = undefined; - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2 the overall help -//////////////////////////////////////////////////////////////////////////////// - -function help () { - print2(HELP); - print2(helpQueries); - print2(helpArangoDatabase); - print2(helpArangoCollection); - print2(helpArangoStatement); - print2(helpArangoQueryCursor); - print2(helpExtended); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- Module "internal" -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief change internal.output to shell output -//////////////////////////////////////////////////////////////////////////////// -/* -ModuleCache["/internal"].exports.output = TRI_SYS_OUTPUT; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief log function -//////////////////////////////////////////////////////////////////////////////// - -ModuleCache["/internal"].exports.log = function(level, msg) { - internal.output(level, ": ", msg, "\n"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief starts the pager -//////////////////////////////////////////////////////////////////////////////// - -ModuleCache["/internal"].exports.start_pager = SYS_START_PAGER; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief stops the pager -//////////////////////////////////////////////////////////////////////////////// - -ModuleCache["/internal"].exports.stop_pager = SYS_STOP_PAGER; -*/ -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- ArangoError -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructor -//////////////////////////////////////////////////////////////////////////////// - -function ArangoError (error) { - this.error = error.error; - this.code = error.code; - this.errorNum = error.errorNum; - this.errorMessage = error.errorMessage; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2s an error -//////////////////////////////////////////////////////////////////////////////// - -ArangoError.prototype._PRINT = function() { - internal.output(this.toString()); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief toString function -//////////////////////////////////////////////////////////////////////////////// - -ArangoError.prototype.toString = function() { - var result = ""; - if (typeof(COLOR_BRIGHT) != "undefined") { - result = COLOR_BRIGHT + "Error: " + COLOR_OUTPUT_RESET; - } - else { - result = "Error: "; - } - - result += "[" + this.code + ":" + this.errorNum + "] " + this.errorMessage; - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2s an error -//////////////////////////////////////////////////////////////////////////////// - -ArangoError.prototype.toString = function() { - var errorNum = this.errorNum; - var errorMessage = this.errorMessage; - - return "[ArangoError " + errorNum + ": " + errorMessage + "]"; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- ArangoDatabase -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructor -//////////////////////////////////////////////////////////////////////////////// - -function ArangoDatabase (connection) { - this._connection = connection; - this._collectionConstructor = ArangoCollection; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief help for ArangoDatabase -//////////////////////////////////////////////////////////////////////////////// - -helpArangoDatabase = TRI_CreateHelpHeadline("ArangoDatabase help") + -'ArangoDatabase constructor: ' + "\n" + -' > db = new ArangoDatabase(connection); ' + "\n" + -' ' + "\n" + -'Administration Functions: ' + "\n" + -' _help(); this help ' + "\n" + -' ' + "\n" + -'Collection Functions: ' + "\n" + -' _collections() list all collections ' + "\n" + -' _collection() get collection by identifier/name ' + "\n" + -' _create(, ) creates a new collection ' + "\n" + -' _truncate() delete all documents ' + "\n" + -' _drop() delete a collection ' + "\n" + -' ' + "\n" + -'Document Functions: ' + "\n" + -' _document() get document by handle ' + "\n" + -' _replace(, ) over-writes document ' + "\n" + -' _delete() deletes document ' + "\n" + -' ' + "\n" + -'Query Functions: ' + "\n" + -' _createStatement(); create and return select query ' + "\n" + -' ' + "\n" + -'Attributes: ' + "\n" + -' collection with the given name '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2 the help for ArangoDatabase -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._help = function () { - print2(helpArangoDatabase); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a string representation of the database object -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype.toString = function () { - return "[object ArangoDatabase]"; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- collection functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return all collections from the database -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._collections = function () { - var requestResult = this._connection.get("/_api/collection"); - - TRI_CheckRequestResult(requestResult); - - if (requestResult["collections"] != undefined) { - var collections = requestResult["collections"]; - var result = [] - - // add all collentions to object - for (var i = 0; i < collections.length; ++i) { - var collection = new this._collectionConstructor(this, collections[i]); - - this[collection._name] = collection; - result.push(collection); - } - - return result; - } - - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a single collection, identified by its id or name -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._collection = function (id) { - var requestResult = this._connection.get("/_api/collection/" + encodeURIComponent(id)); - - // return null in case of not found - if (requestResult != null - && requestResult.error == true - && requestResult.errorNum == internal.errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code) { - return null; - } - - // check all other errors and throw them - TRI_CheckRequestResult(requestResult); - - var name = requestResult["name"]; - - if (name != undefined) { - return this[name] = new this._collectionConstructor(this, requestResult); - } - - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief creates a new collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._create = function (name, properties) { - var body = { - "name" : name - }; - - if (properties != null) { - if (properties.hasOwnProperty("waitForSync")) { - body.waitForSync = properties.waitForSync; - } - - if (properties.hasOwnProperty("journalSize")) { - body.journalSize = properties.journalSize; - } - } - - var requestResult = this._connection.post("/_api/collection", JSON.stringify(body)); - - TRI_CheckRequestResult(requestResult); - - var name = requestResult["name"]; - - if (name != undefined) { - return this[name] = new this._collectionConstructor(this, requestResult); - } - - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief truncates a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._truncate = function (id) { - for (var name in this) { - if (this.hasOwnProperty(name)) { - var collection = this[name]; - - if (collection instanceof this._collectionConstructor) { - if (collection._id == id || collection._name == id) { - return collection.truncate(); - } - } - } - } - - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief drops a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._drop = function (id) { - for (var name in this) { - if (this.hasOwnProperty(name)) { - var collection = this[name]; - - if (collection instanceof this._collectionConstructor) { - if (collection._id == id || collection._name == id) { - return collection.drop(); - } - } - } - } - - return undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- document functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a single document from the collection, identified by its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._document = function (id) { - var rev = null; - var requestResult; - - if (id.hasOwnProperty("_id")) { - if (id.hasOwnProperty("_rev")) { - rev = id._rev; - } - - id = id._id; - } - - if (rev == null) { - requestResult = this._connection.get("/_api/document/" + id); - } - else { - requestResult = this._connection.get("/_api/document/" + id, {'if-match' : '"' + rev + '"' }); - } - - if (requestResult != null - && requestResult.error == true - && requestResult.errorNum == internal.errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code) { - var s = id.split("/"); - - if (s.length != 2) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code; - } - - throw new ArangoError(requestResult); - } - - TRI_CheckRequestResult(requestResult); - - return requestResult; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief delete a document in the collection, identified by its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._delete = function (id, overwrite) { - var rev = null; - var requestResult; - - if (id.hasOwnProperty("_id")) { - if (id.hasOwnProperty("_rev")) { - rev = id._rev; - } - - id = id._id; - } - - var policy = ""; - - if (overwrite) { - policy = "?policy=last"; - } - - if (rev == null) { - requestResult = this._connection.delete("/_api/document/" + id + policy); - } - else { - requestResult = this._connection.delete("/_api/document/" + id + policy, {'if-match' : '"' + rev + '"' }); - } - - if (requestResult != null && requestResult.error == true) { - var s = id.split("/"); - - if (s.length != 2) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code; - } - - if (overwrite) { - if (requestResult.errorNum == internal.errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code) { - return false; - } - } - - throw new ArangoError(requestResult); - } - - TRI_CheckRequestResult(requestResult); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief update a document in the collection, identified by its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._replace = function (id, data, overwrite) { - var rev = null; - var requestResult; - - if (id.hasOwnProperty("_id")) { - if (id.hasOwnProperty("_rev")) { - rev = id._rev; - } - - id = id._id; - } - - var policy = ""; - - if (overwrite) { - policy = "?policy=last"; - } - - if (rev == null) { - requestResult = this._connection.put("/_api/document/" + id + policy, JSON.stringify(data)); - } - else { - requestResult = this._connection.put("/_api/document/" + id + policy, JSON.stringify(data), {'if-match' : '"' + rev + '"' }); - } - - if (requestResult != null && requestResult.error == true) { - var s = id.split("/"); - - if (s.length != 2) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code; - } - - throw new ArangoError(requestResult); - } - - TRI_CheckRequestResult(requestResult); - - return requestResult; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- query functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief factory method to create a new statement -//////////////////////////////////////////////////////////////////////////////// - -ArangoDatabase.prototype._createStatement = function (data) { - return new ArangoStatement(this, data); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- ArangoEdges -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructor -//////////////////////////////////////////////////////////////////////////////// - -function ArangoEdges (connection) { - this._connection = connection; - this._collectionConstructor = ArangoEdgesCollection; -} - -ArangoEdges.prototype = new ArangoDatabase(); - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief help for ArangoEdges -//////////////////////////////////////////////////////////////////////////////// - -helpArangoEdges = TRI_CreateHelpHeadline("ArangoEdges help") + -'ArangoEdges constructor: ' + "\n" + -' > edges = new ArangoEdges(connection); ' + "\n" + -' ' + "\n" + -'Administration Functions: ' + "\n" + -' _help(); this help ' + "\n" + -' ' + "\n" + -'Attributes: ' + "\n" + -' collection with the given name '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2 the help for ArangoEdges -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdges.prototype._help = function () { - print2(helpArangoEdges); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a string representation of the database object -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdges.prototype.toString = function () { - return "[object ArangoEdges]"; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- ArangoCollection -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructor -//////////////////////////////////////////////////////////////////////////////// - -function ArangoCollection (database, data) { - this._database = database; - - if (typeof data === "string") { - this._name = data; - } - else if (data != null) { - this._id = data.id; - this._name = data.name; - this._status = data.status; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- constants -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief collection is corrupted -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.STATUS_CORRUPTED = 0; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief collection is new born -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.STATUS_NEW_BORN = 1; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief collection is unloaded -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.STATUS_UNLOADED = 2; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief collection is loaded -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.STATUS_LOADED = 3; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief collection is unloading -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.STATUS_UNLOADING = 4; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief collection is deleted -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.STATUS_DELETED = 5; - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief help for ArangoCollection -//////////////////////////////////////////////////////////////////////////////// - -helpArangoCollection = TRI_CreateHelpHeadline("ArangoCollection help") + -'ArangoCollection constructor: ' + "\n" + -' > col = db.mycoll; ' + "\n" + -' > col = db._create("mycoll"); ' + "\n" + -' ' + "\n" + -'Administration Functions: ' + "\n" + -' name() collection name ' + "\n" + -' status() status of the collection ' + "\n" + -' truncate() delete all documents ' + "\n" + -' properties() show collection properties ' + "\n" + -' drop() delete a collection ' + "\n" + -' load() load a collection into memeory ' + "\n" + -' unload() unload a collection from memory ' + "\n" + -' rename(new-name) renames a collection ' + "\n" + -' refresh() refreshes the status and name ' + "\n" + -' _help(); this help ' + "\n" + -' ' + "\n" + -'Document Functions: ' + "\n" + -' count() number of documents ' + "\n" + -' save() create document and return handle ' + "\n" + -' document() get document by handle ' + "\n" + -' replace(, ) over-writes document ' + "\n" + -' delete() deletes document ' + "\n" + -' ' + "\n" + -'Attributes: ' + "\n" + -' _database database object ' + "\n" + -' _id collection identifier '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a string representation of the collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.toString = function () { - return TRI_GetIdString(this, "ArangoCollection"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2s the collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype._PRINT = function () { - var status = "unknown"; - - switch (this.status()) { - case ArangoCollection.STATUS_NEW_BORN: status = "new born"; break; - case ArangoCollection.STATUS_UNLOADED: status = "unloaded"; break; - case ArangoCollection.STATUS_UNLOADING: status = "unloading"; break; - case ArangoCollection.STATUS_LOADED: status = "loaded"; break; - case ArangoCollection.STATUS_CORRUPTED: status = "corrupted"; break; - case ArangoCollection.STATUS_DELETED: status = "deleted"; break; - } - - internal.output("[ArangoCollection ", this._id, ", \"", this.name(), "\" (status " + status + ")]"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2 the help for ArangoCollection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype._help = function () { - print2(helpArangoCollection); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- public functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the name of a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.name = function () { - if (this._name == null) { - this.refresh(); - } - - return this._name; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the status of a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.status = function () { - if (this._status == null) { - this.refresh(); - } - - return this._status; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief gets or sets the properties of a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.properties = function (properties) { - var requestResult; - - if (properties == null) { - requestResult = this._database._connection.get("/_api/collection/" + encodeURIComponent(this._id) + "/properties"); - - TRI_CheckRequestResult(requestResult); - } - else { - var body = {}; - - if (properties.hasOwnProperty("waitForSync")) { - body.waitForSync = properties.waitForSync; - } - - requestResult = this._database._connection.put("/_api/collection/" + encodeURIComponent(this._id) + "/properties", JSON.stringify(body)); - - TRI_CheckRequestResult(requestResult); - } - - return { - waitForSync : requestResult.waitForSync, - journalSize : requestResult.journalSize - }; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief gets the figures of a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.figures = function () { - var requestResult = this._database._connection.get("/_api/collection/" + encodeURIComponent(this._id) + "/figures"); - - TRI_CheckRequestResult(requestResult); - - return requestResult.figures; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief drops a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.drop = function () { - var requestResult = this._database._connection.delete("/_api/collection/" + encodeURIComponent(this._id)); - - TRI_CheckRequestResult(requestResult); - - this._status = ArangoCollection.STATUS_DELETED; - - var database = this._database; - - for (var name in database) { - if (database.hasOwnProperty(name)) { - var collection = database[name]; - - if (collection instanceof ArangoCollection) { - if (collection._id == this._id) { - delete database[name]; - } - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief truncates a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.truncate = function () { - var requestResult = this._database._connection.put("/_api/collection/" + encodeURIComponent(this._id) + "/truncate", ""); - - TRI_CheckRequestResult(requestResult); - - this._status = null; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief loads a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.load = function () { - var requestResult = this._database._connection.put("/_api/collection/" + encodeURIComponent(this._id) + "/load", ""); - - TRI_CheckRequestResult(requestResult); - - this._status = null; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief unloads a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.unload = function () { - var requestResult = this._database._connection.put("/_api/collection/" + encodeURIComponent(this._id) + "/unload", ""); - - TRI_CheckRequestResult(requestResult); - - this._status = null; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief renames a collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.rename = function (name) { - var body = { name : name }; - var requestResult = this._database._connection.put("/_api/collection/" + encodeURIComponent(this._id) + "/rename", JSON.stringify(body)); - - TRI_CheckRequestResult(requestResult); - - delete this._database[this._name]; - this._database[name] = this; - - this._status = null; - this._name = null; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief refreshes a collection status and name -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.refresh = function () { - var requestResult = this._database._connection.get("/_api/collection/" + encodeURIComponent(this._id)); - - TRI_CheckRequestResult(requestResult); - - this._name = requestResult['name']; - this._status = requestResult['status']; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- document functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the number of documents -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.count = function () { - var requestResult = this._database._connection.get("/_api/collection/" + encodeURIComponent(this._id) + "/count"); - - TRI_CheckRequestResult(requestResult); - - return requestResult["count"]; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return all documents from the collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.all = function () { - var data = { - collection : this._id - } - - var requestResult = this._database._connection.put("/_api/simple/all", JSON.stringify(data)); - - TRI_CheckRequestResult(requestResult); - - return requestResult; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a single document from the collection, identified by its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.document = function (id) { - var rev = null; - var requestResult; - - if (id.hasOwnProperty("_id")) { - if (id.hasOwnProperty("_rev")) { - rev = id._rev; - } - - id = id._id; - } - - if (rev == null) { - requestResult = this._database._connection.get("/_api/document/" + id); - } - else { - requestResult = this._database._connection.get("/_api/document/" + id, {'if-match' : '"' + rev + '"' }); - } - - if (requestResult != null - && requestResult.error == true - && requestResult.errorNum == internal.errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code) { - var s = id.split("/"); - - if (s.length != 2) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code; - } - else if (s[0] != this._id) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_CROSS_COLLECTION_REQUEST.code; - } - - throw new ArangoError(requestResult); - } - - TRI_CheckRequestResult(requestResult); - - return requestResult; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief save a document in the collection, return its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.save = function (data) { - var requestResult = this._database._connection.post("/_api/document?collection=" + encodeURIComponent(this._id), JSON.stringify(data)); - - TRI_CheckRequestResult(requestResult); - - return requestResult; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief delete a document in the collection, identified by its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.delete = function (id, overwrite) { - var rev = null; - var requestResult; - - if (id.hasOwnProperty("_id")) { - if (id.hasOwnProperty("_rev")) { - rev = id._rev; - } - - id = id._id; - } - - var policy = ""; - - if (overwrite) { - policy = "?policy=last"; - } - - if (rev == null) { - requestResult = this._database._connection.delete("/_api/document/" + id + policy); - } - else { - requestResult = this._database._connection.delete("/_api/document/" + id + policy, {'if-match' : '"' + rev + '"' }); - } - - if (requestResult != null && requestResult.error == true) { - var s = id.split("/"); - - if (s.length != 2) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code; - } - else if (s[0] != this._id) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_CROSS_COLLECTION_REQUEST.code; - } - - if (overwrite) { - if (requestResult.errorNum == internal.errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code) { - return false; - } - } - - throw new ArangoError(requestResult); - } - - TRI_CheckRequestResult(requestResult); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief update a document in the collection, identified by its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoCollection.prototype.replace = function (id, data, overwrite) { - var rev = null; - var requestResult; - - if (id.hasOwnProperty("_id")) { - if (id.hasOwnProperty("_rev")) { - rev = id._rev; - } - - id = id._id; - } - - var policy = ""; - - if (overwrite) { - policy = "?policy=last"; - } - - if (rev == null) { - requestResult = this._database._connection.put("/_api/document/" + id + policy, JSON.stringify(data)); - } - else { - requestResult = this._database._connection.put("/_api/document/" + id + policy, JSON.stringify(data), {'if-match' : '"' + rev + '"' }); - } - - if (requestResult != null && requestResult.error == true) { - var s = id.split("/"); - - if (s.length != 2) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_DOCUMENT_HANDLE_BAD.code; - } - else if (s[0] != this._id) { - requestResult.errorNum = internal.errors.ERROR_ARANGO_CROSS_COLLECTION_REQUEST.code; - } - - throw new ArangoError(requestResult); - } - - TRI_CheckRequestResult(requestResult); - - return requestResult; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- ArangoEdgesCollection -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructor -//////////////////////////////////////////////////////////////////////////////// - -function ArangoEdgesCollection (database, data) { - this._database = database; - - if (typeof data === "string") { - this._name = data; - } - else { - this._id = data.id; - this._name = data.name; - this._status = data.status; - } -} - -ArangoEdgesCollection.prototype = new ArangoCollection(); - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief help for ArangoCollection -//////////////////////////////////////////////////////////////////////////////// - -helpArangoEdgesCollection = TRI_CreateHelpHeadline("ArangoEdgesCollection help") + -'ArangoEdgesCollection constructor: ' + "\n" + -' > col = edges.mycoll; ' + "\n" + -' > col = db._create("mycoll"); ' + "\n" + -' ' + "\n" + -'Attributes: ' + "\n" + -' _database database object ' + "\n" + -' _id collection identifier '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a string representation of the collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdgesCollection.prototype.toString = function () { - return TRI_GetIdString(this, "ArangoEdgesCollection"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2s the collection -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdgesCollection.prototype._PRINT = function () { - var status = "unknown"; - - switch (this.status()) { - case ArangoCollection.STATUS_NEW_BORN: status = "new born"; break; - case ArangoCollection.STATUS_UNLOADED: status = "unloaded"; break; - case ArangoCollection.STATUS_UNLOADING: status = "unloading"; break; - case ArangoCollection.STATUS_LOADED: status = "loaded"; break; - case ArangoCollection.STATUS_CORRUPTED: status = "corrupted"; break; - case ArangoCollection.STATUS_DELETED: status = "deleted"; break; - } - - internal.output("[ArangoEdgesCollection ", this._id, ", \"", this.name(), "\" (status " + status + ")]"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2 the help for ArangoCollection -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdgesCollection.prototype._help = function () { - print2(helpArangoEdgesCollection); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- document functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief save a document in the collection, return its id -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdgesCollection.prototype.save = function (from, to, data) { - if (from.hasOwnProperty("_id")) { - from = from._id; - } - - if (to.hasOwnProperty("_id")) { - to = to._id; - } - - var url = "/edge?collection=" + encodeURIComponent(this._id) - + "&from=" + encodeURIComponent(from) - + "&to=" + encodeURIComponent(to); - - var requestResult = this._database._connection.post(url, JSON.stringify(data)); - - TRI_CheckRequestResult(requestResult); - - return requestResult; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the edges starting or ending in a vertex -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdgesCollection.prototype.edges = function (vertex) { - - // if vertex is a list, iterator and concat - if (vertex instanceof Array) { - var edges = []; - - for (var i = 0; i < vertex.length; ++i) { - var e = this.edges(vertex[i]); - - edges.push.apply(edges, e); - } - - return edges; - } - - if (vertex.hasOwnProperty("_id")) { - vertex = vertex._id; - } - - // get the edges - requestResult = this._database._connection.get("/edges/" + encodeURIComponent(this._id) + "?vertex=" + encodeURIComponent(vertex)); - - TRI_CheckRequestResult(requestResult); - - return requestResult['edges']; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the edges ending in a vertex -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdgesCollection.prototype.inEdges = function (vertex) { - - // if vertex is a list, iterator and concat - if (vertex instanceof Array) { - var edges = []; - - for (var i = 0; i < vertex.length; ++i) { - var e = this.inEdges(vertex[i]); - - edges.push.apply(edges, e); - } - - return edges; - } - - if (vertex.hasOwnProperty("_id")) { - vertex = vertex._id; - } - - // get the edges - requestResult = this._database._connection.get("/edges/" + encodeURIComponent(this._id) + "?direction=in&vertex=" + encodeURIComponent(vertex)); - - TRI_CheckRequestResult(requestResult); - - return requestResult['edges']; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief returns the edges starting in a vertex -//////////////////////////////////////////////////////////////////////////////// - -ArangoEdgesCollection.prototype.outEdges = function (vertex) { - - // if vertex is a list, iterator and concat - if (vertex instanceof Array) { - var edges = []; - - for (var i = 0; i < vertex.length; ++i) { - var e = this.outEdges(vertex[i]); - - edges.push.apply(edges, e); - } - - return edges; - } - - if (vertex.hasOwnProperty("_id")) { - vertex = vertex._id; - } - - // get the edges - requestResult = this._database._connection.get("/edges/" + encodeURIComponent(this._id) + "?direction=out&vertex=" + encodeURIComponent(vertex)); - - TRI_CheckRequestResult(requestResult); - - return requestResult['edges']; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- ArangoQueryCursor -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructor -//////////////////////////////////////////////////////////////////////////////// - -function ArangoQueryCursor (database, data) { - this._database = database; - this.data = data; - this._hasNext = false; - this._hasMore = false; - this._pos = 0; - this._count = 0; - this._total = 0; - - if (data.result != undefined) { - this._count = data.result.length; - - if (this._pos < this._count) { - this._hasNext = true; - } - - if (data.hasMore != undefined && data.hasMore) { - this._hasMore = true; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief help for ArangoQueryCursor -//////////////////////////////////////////////////////////////////////////////// - -helpArangoQueryCursor = TRI_CreateHelpHeadline("ArangoQueryCursor help") + -'ArangoQueryCursor constructor: ' + "\n" + -' > cu1 = qi1.execute(); ' + "\n" + -'Functions: ' + "\n" + -' hasMore(); returns true if there ' + "\n" + -' are more results ' + "\n" + -' next(); returns the next document ' + "\n" + -' elements(); returns all documents ' + "\n" + -' _help(); this help ' + "\n" + -'Attributes: ' + "\n" + -' _database database object ' + "\n" + -'Example: ' + "\n" + -' > st = db._createStatement({ "query" : "select a from colA a" }); ' + "\n" + -' > c = st.execute(); ' + "\n" + -' > documents = c.elements(); ' + "\n" + -' > c = st.execute(); ' + "\n" + -' > while (c.hasNext()) { print2( c.next() ); } '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2 the help for the cursor -//////////////////////////////////////////////////////////////////////////////// - -ArangoQueryCursor.prototype._help = function () { - print2(helpArangoQueryCursor); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a string representation of the cursor -//////////////////////////////////////////////////////////////////////////////// - -ArangoQueryCursor.prototype.toString = function () { - return TRI_GetIdString(this, "ArangoQueryCursor"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- public functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return whether there are more results available in the cursor -//////////////////////////////////////////////////////////////////////////////// - -ArangoQueryCursor.prototype.hasNext = function () { - return this._hasNext; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return the next result document from the cursor -/// -/// If no more results are available locally but more results are available on -/// the server, this function will make a roundtrip to the server -//////////////////////////////////////////////////////////////////////////////// - -ArangoQueryCursor.prototype.next = function () { - if (!this._hasNext) { - throw "No more results"; - } - - var result = this.data.result[this._pos]; - this._pos++; - - // reached last result - if (this._pos == this._count) { - this._hasNext = false; - this._pos = 0; - - if (this._hasMore && this.data._id) { - this._hasMore = false; - - // load more results - var requestResult = this._database._connection.put("/_api/cursor/"+ encodeURIComponent(this.data._id), ""); - - TRI_CheckRequestResult(requestResult); - - this.data = requestResult; - this._count = requestResult.result.length; - - if (this._pos < this._count) { - this._hasNext = true; - } - - if (requestResult.hasMore != undefined && requestResult.hasMore) { - this._hasMore = true; - } - } - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return all remaining result documents from the cursor -/// -/// If no more results are available locally but more results are available on -/// the server, this function will make one or multiple roundtrips to the -/// server. Calling this function will also fully exhaust the cursor. -//////////////////////////////////////////////////////////////////////////////// - -ArangoQueryCursor.prototype.elements = function () { - var result = []; - - while (this.hasNext()) { - result.push( this.next() ); - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief explicitly dispose the cursor -/// -/// Calling this function will mark the cursor as deleted on the server. It will -/// therefore make a roundtrip to the server. Using a cursor after it has been -/// disposed is considered a user error -//////////////////////////////////////////////////////////////////////////////// - -ArangoQueryCursor.prototype.dispose = function () { - if (!this.data._id) { - // client side only cursor - return; - } - - var requestResult = this._database._connection.delete("/_api/cursor/"+ encodeURIComponent(this.data._id), ""); - - TRI_CheckRequestResult(requestResult); - - this.data._id = undefined; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return the total number of documents in the cursor -/// -/// The number will remain the same regardless how much result documents have -/// already been fetched from the cursor. -/// -/// This function will return the number only if the cursor was constructed -/// with the "doCount" attribute. Otherwise it will return undefined. -//////////////////////////////////////////////////////////////////////////////// - -ArangoQueryCursor.prototype.count = function () { - if (!this.data._id) { - throw "cursor has been disposed"; - } - - return this.data.count; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- ArangoStatement -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// --SECTION-- constructors and destructors -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief constructor -//////////////////////////////////////////////////////////////////////////////// - -function ArangoStatement (database, data) { - this._database = database; - this._doCount = false; - this._batchSize = null; - this._bindVars = {}; - - if (!(data instanceof Object)) { - throw "ArangoStatement needs initial data"; - } - - if (data.query == undefined || data.query == "") { - throw "ArangoStatement needs a valid query attribute"; - } - this.setQuery(data.query); - - if (data.count != undefined) { - this.setCount(data.count); - } - if (data.batchSize != undefined) { - this.setBatchSize(data.batchSize); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- private functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief help for ArangoStatement -//////////////////////////////////////////////////////////////////////////////// - -helpArangoStatement = TRI_CreateHelpHeadline("ArangoStatement help") + -'ArangoStatement constructor: ' + "\n" + -' > st = new ArangoStatement({ "query" : "select..." }); ' + "\n" + -' > st = db._createStatement({ "query" : "select ...." }); ' + "\n" + -'Functions: ' + "\n" + -' bind(, ); bind single variable ' + "\n" + -' bind(); bind multiple variables ' + "\n" + -' setBatchSize(); set max. number of results ' + "\n" + -' to be transferred per roundtrip ' + "\n" + -' setCount(); set count flag (return number of ' + "\n" + -' results in "count" attribute) ' + "\n" + -' getBatchSize(); return max. number of results ' + "\n" + -' to be transferred per roundtrip ' + "\n" + -' getCount(); return count flag (return number of' + "\n" + -' results in "count" attribute) ' + "\n" + -' getQuery(); return query string ' + "\n" + -' execute(); execute query and return cursor ' + "\n" + -' _help(); this help ' + "\n" + -'Attributes: ' + "\n" + -' _database database object ' + "\n" + -'Example: ' + "\n" + -' > st = db._createStatement({ "query" : "select a from colA a ' + "\n" + -' where a.x = @a@ and a.y = @b@" }); ' + "\n" + -' > st.bind("a", "hello"); ' + "\n" + -' > st.bind("b", "world"); ' + "\n" + -' > c = st.execute(); ' + "\n" + -' > print2(c.elements()); '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief print2 the help for ArangoStatement -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype._help = function () { - print2(helpArangoStatement); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return a string representation of the statement -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.toString = function () { - return TRI_GetIdString(this, "ArangoStatement"); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- public functions -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup ArangoShell -/// @{ -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// @brief bind a parameter to the statement -/// -/// This function can be called multiple times, once for each bind parameter. -/// All bind parameters will be transferred to the server in one go when -/// execute() is called. -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.bind = function (key, value) { - if (key instanceof Object) { - if (value != undefined) { - throw "invalid bind parameter declaration"; - } - this._bindVars = key; - } - else if (typeof(key) == "string") { - if (this._bindVars[key] != undefined) { - throw "redeclaration of bind parameter"; - } - this._bindVars[key] = value; - } - else if (typeof(key) == "number") { - var strKey = String(parseInt(key)); - if (strKey != String(key)) { - throw "invalid bind parameter declaration"; - } - if (this._bindVars[strKey] != undefined) { - throw "redeclaration of bind parameter"; - } - this._bindVars[strKey] = value; - } - else { - throw "invalid bind parameter declaration"; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief return the bind variables already set -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.getBindVariables = function () { - return this._bindVars; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief get the count flag for the statement -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.getCount = function () { - return this._doCount; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief get the maximum number of results documents the cursor will return -/// in a single server roundtrip. -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.getBatchSize = function () { - return this._batchSize; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief get query string -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.getQuery = function () { - return this._query; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief set the count flag for the statement -/// -/// Setting the count flag will make the statement's result cursor return the -/// total number of result documents. The count flag is not set by default. -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.setCount = function (bool) { - this._doCount = bool ? true : false; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief set the maximum number of results documents the cursor will return -/// in a single server roundtrip. -/// The higher this number is, the less server roundtrips will be made when -/// iterating over the result documents of a cursor. -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.setBatchSize = function (value) { - if (parseInt(value) > 0) { - this._batchSize = parseInt(value); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief set the query string -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.setQuery = function (query) { - this._query = query; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief parse a query and return the results -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.parse = function () { - var body = { - "query" : this._query, - } - - var requestResult = this._database._connection.post("/_api/query", JSON.stringify(body)); - - TRI_CheckRequestResult(requestResult); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief execute the query -/// -/// Invoking execute() will transfer the query and all bind parameters to the -/// server. It will return a cursor with the query results in case of success. -/// In case of an error, the error will be print2ed -//////////////////////////////////////////////////////////////////////////////// - -ArangoStatement.prototype.execute = function () { - var body = { - "query" : this._query, - "count" : this._doCount, - "bindVars" : this._bindVars - } - - if (this._batchSize) { - body["batchSize"] = this._batchSize; - } - - var requestResult = this._database._connection.post("/_api/cursor", JSON.stringify(body)); - - TRI_CheckRequestResult(requestResult); - - return new ArangoQueryCursor(this._database, requestResult); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// ----------------------------------------------------------------------------- -// --SECTION-- initialisers -// ----------------------------------------------------------------------------- - -//////////////////////////////////////////////////////////////////////////////// -/// @brief general help -//////////////////////////////////////////////////////////////////////////////// - -HELP = TRI_CreateHelpHeadline("Help") + -'Predefined objects: ' + "\n" + -' arango: ArangoConnection ' + "\n" + -' db: ArangoDatabase ' + "\n" + -'Example: ' + "\n" + -' > db._collections(); list all collections ' + "\n" + -' > db..all(); list all documents ' + "\n" + -' > id = db..save({ ... }); save a document ' + "\n" + -' > db..delete(<_id>); delete a document ' + "\n" + -' > db..document(<_id>); get a document ' + "\n" + -' > help show help pages ' + "\n" + -' > helpQueries query help ' + "\n" + -' > exit '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief query help -//////////////////////////////////////////////////////////////////////////////// - -helpQueries = TRI_CreateHelpHeadline("Select query help") + -'Create a select query: ' + "\n" + -' > st = new ArangoStatement(db, { "query" : "select..." }); ' + "\n" + -' > st = db._createStatement({ "query" : "select..." }); ' + "\n" + -'Set query options: ' + "\n" + -' > st.setBatchSize(); set the max. number of results ' + "\n" + -' to be transferred per roundtrip ' + "\n" + -' > st.setCount(); set count flag (return number of ' + "\n" + -' results in "count" attribute) ' + "\n" + -'Get query options: ' + "\n" + -' > st.setBatchSize(); return the max. number of results ' + "\n" + -' to be transferred per roundtrip ' + "\n" + -' > st.getCount(); return count flag (return number of' + "\n" + -' results in "count" attribute) ' + "\n" + -' > st.getQuery(); return query string ' + "\n" + -' results in "count" attribute) ' + "\n" + -'Bind parameters to a query: ' + "\n" + -' > st.bind(, ); bind single variable ' + "\n" + -' > st.bind(); bind multiple variables ' + "\n" + -'Execute query: ' + "\n" + -' > c = st.execute(); returns a cursor ' + "\n" + -'Get all results in an array: ' + "\n" + -' > e = c.elements(); ' + "\n" + -'Or loop over the result set: ' + "\n" + -' > while (c.hasNext()) { print2( c.next() ); } '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief extended help -//////////////////////////////////////////////////////////////////////////////// - -helpExtended = TRI_CreateHelpHeadline("More help") + -'Pager: ' + "\n" + -' > internal.stop_pager() stop the pager output ' + "\n" + -' > internal.start_pager() start the pager ' + "\n" + -'Pretty print2ing: ' + "\n" + -' > stop_pretty_print2() stop pretty print2ing ' + "\n" + -' > start_pretty_print2() start pretty print2ing ' + "\n" + -'Color output: ' + "\n" + -' > stop_color_print2() stop color print2ing ' + "\n" + -' > start_color_print2() start color print2ing ' + "\n" + -' > start_color_print2(COLOR_BLUE) set color ' + "\n" + -'Print function: ' + "\n" + -' > print2(x) std. print2 function ' + "\n" + -' > print2_plain(x) print2 without pretty print2ing' + "\n" + -' and without colors '; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief create the global db object and load the collections -//////////////////////////////////////////////////////////////////////////////// - -try { - - // default databases - db = new ArangoDatabase(arango); - edges = new ArangoEdges(arango); - - // load collection data - db._collections(); - edges._collections(); - - // export to internal - ModuleCache["/internal"].exports.db = db; - ModuleCache["/internal"].exports.edges = db; - - print2(HELP); -} -catch (err) { - console.log(err); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - -// Local Variables: -// mode: outline-minor -// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)" -// End: diff --git a/html/admin/js/client.js b/html/admin/js/client.js new file mode 120000 index 0000000000..9bd5f8c240 --- /dev/null +++ b/html/admin/js/client.js @@ -0,0 +1 @@ +../../../js/client/client.js \ No newline at end of file diff --git a/html/admin/js/master.js b/html/admin/js/master.js index 666ac9a513..b02c1aae16 100644 --- a/html/admin/js/master.js +++ b/html/admin/js/master.js @@ -765,13 +765,15 @@ var logTable = $('#logTableID').dataTable({ else { var collectionID; var boxContent = $('#documentEditSourceBox').val(); - var jsonContent = JSON.parse(boxContent); collectionID = globalCollectionID; + boxContent = stateReplace(boxContent); + parsedContent = JSON.parse(boxContent); + $.ajax({ type: "PUT", url: "/_api/document/" + collectionID, - data: JSON.stringify(jsonContent), + data: JSON.stringify(parsedContent), contentType: "application/json", processData: false, success: function(data) { @@ -1009,9 +1011,9 @@ var logTable = $('#logTableID').dataTable({ /*animation*/ $('#movetologinButton').text("Login"); - $('#footerSlideContent').animate({ height: '25px' }); - $('#footerSlideButton').css('backgroundPosition', 'top left'); - open = false; + $('#footerSlideContent').animate({ height: '25px' }); + $('#footerSlideButton').css('backgroundPosition', 'top left'); + open = false; return false; }, @@ -1164,14 +1166,7 @@ var logTable = $('#logTableID').dataTable({ var client = "arangodb:" + data; $('#avocshWindow').append('' + client + ''); - - try { - var server = "" + eval(data); - $('#avocshWindow').append('

' + server + '

'); - } - catch(e) { - $('#avocshWindow').append('

Error:' + e + '

'); - } + hansmann(data); $("#avocshWindow").animate({scrollTop:$("#avocshWindow")[0].scrollHeight}, 1); $("#avocshContent").val(''); return false; @@ -1190,14 +1185,14 @@ var logTable = $('#logTableID').dataTable({ contentType: "application/json", processData: false, success: function(data) { - var temp = JSON.parse(data.responseText); $("#queryOutput").empty(); - $("#queryOutput").append('' + JSON.stringify(temp.errorMessage) + ''); + $("#queryOutput").append('' + JSON.stringify(data.result) + ''); }, error: function(data) { + console.log(data); var temp = JSON.parse(data.responseText); $("#queryOutput").empty(); - $("#queryOutput").append('' + JSON.stringify(temp.errorMessage) + ''); + $("#queryOutput").append('[' + temp.errorNum + '] ' + temp.errorMessage + ''); } }); }); @@ -1516,7 +1511,7 @@ function drawCollectionsTable () { error: function(data) { } }); - + items.push(['', val.id, val.name, tempStatus, bytesToSize(size*1024), alive]); } @@ -2273,3 +2268,35 @@ function hideLogPagination() { $('#logToolbarInfo').hide(); } +function hansmann (data) { + try { + var server = eval(data); + if (server !== undefined) { + var resultung = ""; + if (server === null) { + resultung = "null"; + } + else if (typeof(server) == "string") { + resultung = server; + } + else if (typeof(server) == "number" || typeof(server) == "boolean") { + resultung = "" + server; + } + else if (typeof(server) == "object") { + try { + resultung = JSON.stringify(server); + } + catch (err) { + resultung = server.toString(); + } + } + + $('#avocshWindow').append('

' + resultung + '

'); + } + } + catch(e) { + $('#avocshWindow').append('

Error:' + e + '

'); + } +} + + diff --git a/js/server/ahuacatl.js b/js/server/ahuacatl.js index 7210bfbfc3..1597e9ce38 100644 --- a/js/server/ahuacatl.js +++ b/js/server/ahuacatl.js @@ -85,6 +85,47 @@ function AHUACATL_INDEX (collection, indexTypes) { return null; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief normalize a value for comparison, sorting etc. +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_NORMALIZE (value) { + if (value === null || value === undefined) { + return null; + } + if (typeof(value) !== "object") { + return value; + } + + if (Array.isArray(value)) { + var result = [ ]; + var length = value.length; + for (var i = 0; i < length; ++i) { + result.push(AHUACATL_NORMALIZE(value[i])); + } + + return result; + } + else { + var attributes = [ ]; + for (var attribute in value) { + if (!value.hasOwnProperty(attribute)) { + continue; + } + attributes.push(attribute); + } + attributes.sort(); + + var result = { }; + var length = attributes.length; + for (var i = 0; i < length; ++i) { + result[attributes[i]] = AHUACATL_NORMALIZE(value[attributes[i]]); + } + + return result; + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief clone an object //////////////////////////////////////////////////////////////////////////////// @@ -122,7 +163,7 @@ function AHUACATL_CLONE (obj) { /// @brief validate function call argument //////////////////////////////////////////////////////////////////////////////// -function AHUACATL_ARG_CHECK (actualValue, expectedType, functionName, argument) { +function AHUACATL_ARG_CHECK (actualValue, expectedType, functionName) { if (AHUACATL_TYPEWEIGHT(actualValue) !== expectedType) { AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, functionName); } @@ -442,10 +483,23 @@ function AHUACATL_GET_DOCUMENTS_SKIPLIST_LIST (collection, idx, attribute, value } } - return result; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief get names of all collections +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_COLLECTIONS () { + var collections = internal.db._collections(); + var result = [ ]; + + for (var i = 0; i < collections.length; ++i) { + result.push({ "_id" : collections[i]._id, "name" : collections[i].name() }); + } + + return result; +} //////////////////////////////////////////////////////////////////////////////// /// @} @@ -1149,7 +1203,7 @@ function AHUACATL_STRING_CONCAT () { continue; } - AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, "CONCAT", i + 1); + AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, "CONCAT"); result += element; } @@ -1175,7 +1229,7 @@ function AHUACATL_STRING_CONCAT_SEPARATOR () { continue; } - AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, "CONCAT_SEPARATOR", i + 1); + AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, "CONCAT_SEPARATOR"); if (i == 0) { separator = element; @@ -1200,7 +1254,7 @@ function AHUACATL_STRING_CONCAT_SEPARATOR () { //////////////////////////////////////////////////////////////////////////////// function AHUACATL_STRING_LENGTH (value) { - AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "STRING_LENGTH", 1); + AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "STRING_LENGTH"); return value.length; } @@ -1212,7 +1266,7 @@ function AHUACATL_STRING_LENGTH (value) { //////////////////////////////////////////////////////////////////////////////// function AHUACATL_STRING_LOWER (value) { - AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "LOWER", 1); + AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "LOWER"); return value.toLowerCase(); } @@ -1224,7 +1278,7 @@ function AHUACATL_STRING_LOWER (value) { //////////////////////////////////////////////////////////////////////////////// function AHUACATL_STRING_UPPER (value) { - AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "UPPER", 1); + AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "UPPER"); return value.toUpperCase(); } @@ -1236,8 +1290,8 @@ function AHUACATL_STRING_UPPER (value) { //////////////////////////////////////////////////////////////////////////////// function AHUACATL_STRING_SUBSTRING (value, offset, count) { - AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "SUBSTRING", 1); - AHUACATL_ARG_CHECK(offset, AHUACATL_TYPEWEIGHT_NUMBER, "SUBSTRING", 2); + AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, "SUBSTRING"); + AHUACATL_ARG_CHECK(offset, AHUACATL_TYPEWEIGHT_NUMBER, "SUBSTRING"); return value.substr(offset, count); } @@ -1587,6 +1641,74 @@ function AHUACATL_LENGTH () { return value.length; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the first element of a list +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_FIRST () { + var value = arguments[0]; + + AHUACATL_LIST(value); + + if (value.length == 0) { + return null; + } + + return value[0]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the last element of a list +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_LAST () { + var value = arguments[0]; + + AHUACATL_LIST(value); + + if (value.length == 0) { + return null; + } + + return value[value.length - 1]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief reverse the elements in a list +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_REVERSE () { + var value = arguments[0]; + + AHUACATL_LIST(value); + + return value.reverse(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return a list of unique elements from the list +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_UNIQUE () { + var value = arguments[0]; + + AHUACATL_LIST(value); + + var length = value.length; + var keys = { }; + for (var i = 0; i < length; ++i) { + var normalized = AHUACATL_NORMALIZE(value[i]); + keys[JSON.stringify(normalized)] = normalized; + } + + var result = []; + for (var i in keys) { + result.push(keys[i]); + } + + return result; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief create the union (all) of all arguments //////////////////////////////////////////////////////////////////////////////// @@ -1776,6 +1898,177 @@ function AHUACATL_GEO_WITHIN () { /// @} //////////////////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// --SECTION-- graph functions +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup Ahuacatl +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief find all paths through a graph +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_GRAPH_PATHS () { + var collection = arguments[0]; + var edgeType = arguments[1]; + var minLength = arguments[2] != undefined ? arguments[2] : 1; + var maxLength = arguments[3] != undefined ? arguments[3] : 10; + var followCycles = arguments[4] ? arguments[4] : false; + var direction; + + // validate arguments + if (edgeType == "outbound") { + direction = 1; + } + else if (edgeType == "inbound") { + direction = 2; + } + else if (edgeType == "any") { + direction = 3; + } + else { + AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "PATHS"); + } + + if (minLength < 0 || maxLength < 0 || minLength > maxLength) { + AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "PATHS"); + } + + var edgeCollection = internal.edges[collection]; + var searchAttributes = { + "edgeCollection" : edgeCollection, + "minLength" : minLength, + "maxLength" : maxLength, + "direction" : direction, + "followCycles" : followCycles, + }; + + var allEdges = edgeCollection.all().toArray(); + // TODO: restrict allEdges to edges with certain _from values etc. + + var result = [ ]; + var n = allEdges.length; + for (var i = 0; i < n; ++i) { + + var edge = allEdges[i]; + var _from = edge._from; + var _to = edge._to; + var sources = [ ]; + + if (searchAttributes.direction & 1) { + sources.push(_from); + } + if (searchAttributes.direction & 2) { + sources.push(_to); + } + + for (var j = 0; j < sources.length; ++j) { + var visited = { }; + var vertices = [ ]; + var edges = [ ]; + + var source = sources[j]; + var next = internal.db._document(source); + vertices.push(next); + if (!searchAttributes.followCycles) { + visited[source] = true; + } + + if (searchAttributes.minLength == 0) { + var copy = AHUACATL_CLONE(vertices); + result.push({ "vertices" : copy, "edges" : [ ], "source" : copy[0], "destination" : copy[copy.length - 1] }); + } + + if (searchAttributes.maxLength > 0) { + var subResult = AHUACATL_GRAPH_SUBNODES(searchAttributes, AHUACATL_CLONE(visited), edges, vertices, edge, 0); + for (var k = 0; k < subResult.length; ++k) { + result.push(subResult[k]); + } + } + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief find all paths through a graph, internal part called recursively +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_GRAPH_SUBNODES (searchAttributes, visited, edges, vertices, edge, level) { + var result = [ ]; + + var _from = edge._from; + var _to = edge._to; + var targets = [ ]; + + if (searchAttributes.direction & 1) { + targets.push(_to); + } + if (searchAttributes.direction & 2) { + targets.push(_from); + } + + for (var i = 0; i < targets.length; ++i) { + var target = targets[i]; + + if (!searchAttributes.followCycles && visited[target]) { + continue; + } + + var clonedEdges = AHUACATL_CLONE(edges); + var clonedVertices = AHUACATL_CLONE(vertices); + + clonedEdges.push(edge); + var vertex = internal.db._document(target); + clonedVertices.push(vertex); + + if (level + 1 >= searchAttributes.minLength) { + result.push({ "vertices" : clonedVertices, "edges" : clonedEdges, "source" : clonedVertices[0], "destination" : clonedVertices[clonedVertices.length - 1] }); + } + + if (level + 1 < searchAttributes.maxLength) { + // recursion + + if (!searchAttributes.followCycles) { + visited[target] = true; + } + + var subEdges; + if (searchAttributes.direction == 1) { + subEdges = searchAttributes.edgeCollection.outEdges(vertex); + } + else if (searchAttributes.direction == 2) { + subEdges = searchAttributes.edgeCollection.inEdges(vertex); + } + else if (searchAttributes.direction == 3) { + subEdges = searchAttributes.edgeCollection.edges(vertex); + } + + for (var j = 0; j < subEdges.length; ++j) { + var subResult = AHUACATL_GRAPH_SUBNODES(searchAttributes, AHUACATL_CLONE(visited), clonedEdges, clonedVertices, subEdges[j], level + 1); + + for (var k = 0; k < subResult.length; ++k) { + result.push(subResult[k]); + } + } + + if (!searchAttributes.followCycles) { + delete visited[target]; + } + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + // ----------------------------------------------------------------------------- // --SECTION-- misc functions // ----------------------------------------------------------------------------- @@ -1785,6 +2078,25 @@ function AHUACATL_GEO_WITHIN () { /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief check whether a document has an attribute +//////////////////////////////////////////////////////////////////////////////// + +function AHUACATL_HAS () { + var element = arguments[0]; + var name = arguments[1]; + + if (AHUACATL_TYPEWEIGHT(element) === AHUACATL_TYPEWEIGHT_NULL) { + return false; + } + + if (AHUACATL_TYPEWEIGHT(element) !== AHUACATL_TYPEWEIGHT_DOCUMENT) { + AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "HAS"); + } + + return element.hasOwnProperty(name); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief merge all arguments //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/js-ahuacatl.h b/js/server/js-ahuacatl.h index c5d48e3730..4a4d9d4475 100644 --- a/js/server/js-ahuacatl.h +++ b/js/server/js-ahuacatl.h @@ -87,6 +87,47 @@ static string JS_server_ahuacatl = "}\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief normalize a value for comparison, sorting etc.\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_NORMALIZE (value) {\n" + " if (value === null || value === undefined) {\n" + " return null;\n" + " }\n" + " if (typeof(value) !== \"object\") {\n" + " return value;\n" + " }\n" + "\n" + " if (Array.isArray(value)) {\n" + " var result = [ ];\n" + " var length = value.length;\n" + " for (var i = 0; i < length; ++i) {\n" + " result.push(AHUACATL_NORMALIZE(value[i]));\n" + " }\n" + " \n" + " return result;\n" + " } \n" + " else {\n" + " var attributes = [ ];\n" + " for (var attribute in value) {\n" + " if (!value.hasOwnProperty(attribute)) {\n" + " continue;\n" + " }\n" + " attributes.push(attribute);\n" + " }\n" + " attributes.sort();\n" + "\n" + " var result = { };\n" + " var length = attributes.length;\n" + " for (var i = 0; i < length; ++i) {\n" + " result[attributes[i]] = AHUACATL_NORMALIZE(value[attributes[i]]);\n" + " }\n" + "\n" + " return result;\n" + " }\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" "/// @brief clone an object\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" @@ -123,7 +164,7 @@ static string JS_server_ahuacatl = "/// @brief validate function call argument\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" - "function AHUACATL_ARG_CHECK (actualValue, expectedType, functionName, argument) {\n" + "function AHUACATL_ARG_CHECK (actualValue, expectedType, functionName) {\n" " if (AHUACATL_TYPEWEIGHT(actualValue) !== expectedType) {\n" " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, functionName);\n" " }\n" @@ -443,10 +484,23 @@ static string JS_server_ahuacatl = " }\n" " }\n" "\n" - "\n" " return result;\n" "}\n" "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief get names of all collections\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_COLLECTIONS () {\n" + " var collections = internal.db._collections();\n" + " var result = [ ];\n" + "\n" + " for (var i = 0; i < collections.length; ++i) {\n" + " result.push({ \"_id\" : collections[i]._id, \"name\" : collections[i].name() });\n" + " }\n" + "\n" + " return result;\n" + "}\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" "/// @}\n" @@ -1150,7 +1204,7 @@ static string JS_server_ahuacatl = " continue;\n" " }\n" "\n" - " AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, \"CONCAT\", i + 1);\n" + " AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, \"CONCAT\");\n" "\n" " result += element;\n" " }\n" @@ -1176,7 +1230,7 @@ static string JS_server_ahuacatl = " continue;\n" " }\n" " \n" - " AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, \"CONCAT_SEPARATOR\", i + 1);\n" + " AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, \"CONCAT_SEPARATOR\");\n" "\n" " if (i == 0) {\n" " separator = element;\n" @@ -1201,7 +1255,7 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "function AHUACATL_STRING_LENGTH (value) {\n" - " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"STRING_LENGTH\", 1);\n" + " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"STRING_LENGTH\");\n" "\n" " return value.length;\n" "}\n" @@ -1213,7 +1267,7 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "function AHUACATL_STRING_LOWER (value) {\n" - " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"LOWER\", 1);\n" + " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"LOWER\");\n" "\n" " return value.toLowerCase();\n" "}\n" @@ -1225,7 +1279,7 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "function AHUACATL_STRING_UPPER (value) {\n" - " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"UPPER\", 1);\n" + " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"UPPER\");\n" "\n" " return value.toUpperCase();\n" "}\n" @@ -1237,8 +1291,8 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "function AHUACATL_STRING_SUBSTRING (value, offset, count) {\n" - " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"SUBSTRING\", 1);\n" - " AHUACATL_ARG_CHECK(offset, AHUACATL_TYPEWEIGHT_NUMBER, \"SUBSTRING\", 2);\n" + " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"SUBSTRING\");\n" + " AHUACATL_ARG_CHECK(offset, AHUACATL_TYPEWEIGHT_NUMBER, \"SUBSTRING\");\n" "\n" " return value.substr(offset, count);\n" "}\n" @@ -1589,6 +1643,74 @@ static string JS_server_ahuacatl = "}\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief get the first element of a list\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_FIRST () {\n" + " var value = arguments[0];\n" + "\n" + " AHUACATL_LIST(value);\n" + "\n" + " if (value.length == 0) {\n" + " return null;\n" + " }\n" + "\n" + " return value[0];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief get the last element of a list\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_LAST () {\n" + " var value = arguments[0];\n" + "\n" + " AHUACATL_LIST(value);\n" + "\n" + " if (value.length == 0) {\n" + " return null;\n" + " }\n" + "\n" + " return value[value.length - 1];\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief reverse the elements in a list\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_REVERSE () {\n" + " var value = arguments[0];\n" + "\n" + " AHUACATL_LIST(value);\n" + "\n" + " return value.reverse();\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief return a list of unique elements from the list\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_UNIQUE () {\n" + " var value = arguments[0];\n" + "\n" + " AHUACATL_LIST(value);\n" + "\n" + " var length = value.length;\n" + " var keys = { };\n" + " for (var i = 0; i < length; ++i) {\n" + " var normalized = AHUACATL_NORMALIZE(value[i]);\n" + " keys[JSON.stringify(normalized)] = normalized;\n" + " }\n" + "\n" + " var result = [];\n" + " for (var i in keys) {\n" + " result.push(keys[i]);\n" + " }\n" + "\n" + " return result;\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" "/// @brief create the union (all) of all arguments\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" @@ -1778,6 +1900,177 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "// -----------------------------------------------------------------------------\n" + "// --SECTION-- graph functions\n" + "// -----------------------------------------------------------------------------\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @addtogroup Ahuacatl\n" + "/// @{\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief find all paths through a graph\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_GRAPH_PATHS () {\n" + " var collection = arguments[0];\n" + " var edgeType = arguments[1];\n" + " var minLength = arguments[2] != undefined ? arguments[2] : 1;\n" + " var maxLength = arguments[3] != undefined ? arguments[3] : 10;\n" + " var followCycles = arguments[4] ? arguments[4] : false;\n" + " var direction;\n" + "\n" + " // validate arguments\n" + " if (edgeType == \"outbound\") {\n" + " direction = 1;\n" + " }\n" + " else if (edgeType == \"inbound\") {\n" + " direction = 2;\n" + " }\n" + " else if (edgeType == \"any\") {\n" + " direction = 3;\n" + " }\n" + " else {\n" + " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"PATHS\");\n" + " }\n" + "\n" + " if (minLength < 0 || maxLength < 0 || minLength > maxLength) {\n" + " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"PATHS\");\n" + " }\n" + "\n" + " var edgeCollection = internal.edges[collection];\n" + " var searchAttributes = { \n" + " \"edgeCollection\" : edgeCollection, \n" + " \"minLength\" : minLength, \n" + " \"maxLength\" : maxLength, \n" + " \"direction\" : direction,\n" + " \"followCycles\" : followCycles,\n" + " };\n" + "\n" + " var allEdges = edgeCollection.all().toArray();\n" + " // TODO: restrict allEdges to edges with certain _from values etc.\n" + "\n" + " var result = [ ];\n" + " var n = allEdges.length;\n" + " for (var i = 0; i < n; ++i) {\n" + "\n" + " var edge = allEdges[i];\n" + " var _from = edge._from; \n" + " var _to = edge._to; \n" + " var sources = [ ];\n" + "\n" + " if (searchAttributes.direction & 1) {\n" + " sources.push(_from);\n" + " }\n" + " if (searchAttributes.direction & 2) {\n" + " sources.push(_to);\n" + " }\n" + "\n" + " for (var j = 0; j < sources.length; ++j) {\n" + " var visited = { };\n" + " var vertices = [ ];\n" + " var edges = [ ];\n" + "\n" + " var source = sources[j];\n" + " var next = internal.db._document(source);\n" + " vertices.push(next);\n" + " if (!searchAttributes.followCycles) {\n" + " visited[source] = true;\n" + " }\n" + " \n" + " if (searchAttributes.minLength == 0) {\n" + " var copy = AHUACATL_CLONE(vertices);\n" + " result.push({ \"vertices\" : copy, \"edges\" : [ ], \"source\" : copy[0], \"destination\" : copy[copy.length - 1] });\n" + " }\n" + "\n" + " if (searchAttributes.maxLength > 0) {\n" + " var subResult = AHUACATL_GRAPH_SUBNODES(searchAttributes, AHUACATL_CLONE(visited), edges, vertices, edge, 0);\n" + " for (var k = 0; k < subResult.length; ++k) {\n" + " result.push(subResult[k]);\n" + " }\n" + " }\n" + " }\n" + " }\n" + "\n" + " return result;\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief find all paths through a graph, internal part called recursively\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_GRAPH_SUBNODES (searchAttributes, visited, edges, vertices, edge, level) {\n" + " var result = [ ];\n" + "\n" + " var _from = edge._from; \n" + " var _to = edge._to;\n" + " var targets = [ ];\n" + "\n" + " if (searchAttributes.direction & 1) {\n" + " targets.push(_to);\n" + " }\n" + " if (searchAttributes.direction & 2) {\n" + " targets.push(_from);\n" + " }\n" + "\n" + " for (var i = 0; i < targets.length; ++i) {\n" + " var target = targets[i];\n" + "\n" + " if (!searchAttributes.followCycles && visited[target]) {\n" + " continue;\n" + " }\n" + "\n" + " var clonedEdges = AHUACATL_CLONE(edges);\n" + " var clonedVertices = AHUACATL_CLONE(vertices);\n" + "\n" + " clonedEdges.push(edge);\n" + " var vertex = internal.db._document(target);\n" + " clonedVertices.push(vertex);\n" + " \n" + " if (level + 1 >= searchAttributes.minLength) {\n" + " result.push({ \"vertices\" : clonedVertices, \"edges\" : clonedEdges, \"source\" : clonedVertices[0], \"destination\" : clonedVertices[clonedVertices.length - 1] });\n" + " }\n" + "\n" + " if (level + 1 < searchAttributes.maxLength) {\n" + " // recursion\n" + "\n" + " if (!searchAttributes.followCycles) {\n" + " visited[target] = true;\n" + " }\n" + "\n" + " var subEdges;\n" + " if (searchAttributes.direction == 1) {\n" + " subEdges = searchAttributes.edgeCollection.outEdges(vertex);\n" + " }\n" + " else if (searchAttributes.direction == 2) {\n" + " subEdges = searchAttributes.edgeCollection.inEdges(vertex);\n" + " }\n" + " else if (searchAttributes.direction == 3) {\n" + " subEdges = searchAttributes.edgeCollection.edges(vertex);\n" + " }\n" + "\n" + " for (var j = 0; j < subEdges.length; ++j) {\n" + " var subResult = AHUACATL_GRAPH_SUBNODES(searchAttributes, AHUACATL_CLONE(visited), clonedEdges, clonedVertices, subEdges[j], level + 1);\n" + "\n" + " for (var k = 0; k < subResult.length; ++k) {\n" + " result.push(subResult[k]);\n" + " }\n" + " }\n" + "\n" + " if (!searchAttributes.followCycles) {\n" + " delete visited[target];\n" + " }\n" + " }\n" + " }\n" + "\n" + " return result;\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "/// @}\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "// -----------------------------------------------------------------------------\n" "// --SECTION-- misc functions\n" "// -----------------------------------------------------------------------------\n" "\n" @@ -1787,6 +2080,25 @@ static string JS_server_ahuacatl = "////////////////////////////////////////////////////////////////////////////////\n" "\n" "////////////////////////////////////////////////////////////////////////////////\n" + "/// @brief check whether a document has an attribute\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AHUACATL_HAS () {\n" + " var element = arguments[0];\n" + " var name = arguments[1];\n" + " \n" + " if (AHUACATL_TYPEWEIGHT(element) === AHUACATL_TYPEWEIGHT_NULL) {\n" + " return false;\n" + " }\n" + "\n" + " if (AHUACATL_TYPEWEIGHT(element) !== AHUACATL_TYPEWEIGHT_DOCUMENT) {\n" + " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"HAS\");\n" + " }\n" + "\n" + " return element.hasOwnProperty(name);\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" "/// @brief merge all arguments\n" "////////////////////////////////////////////////////////////////////////////////\n" "\n" diff --git a/js/server/tests/ahuacatl-functions.js b/js/server/tests/ahuacatl-functions.js index 1725c17ab0..3210d884a0 100644 --- a/js/server/tests/ahuacatl-functions.js +++ b/js/server/tests/ahuacatl-functions.js @@ -117,6 +117,223 @@ function ahuacatlFunctionsTestSuite () { tearDown : function () { }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test first function +//////////////////////////////////////////////////////////////////////////////// + + testFirst1 : function () { + var expected = [ { "the fox" : "jumped" } ]; + var actual = getQueryResults("RETURN FIRST([ { \"the fox\" : \"jumped\" }, \"over\", [ \"the dog\" ] ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test first function +//////////////////////////////////////////////////////////////////////////////// + + testFirst2 : function () { + var expected = [ "over" ]; + var actual = getQueryResults("RETURN FIRST([ \"over\", [ \"the dog\" ] ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test first function +//////////////////////////////////////////////////////////////////////////////// + + testFirst3 : function () { + var expected = [ [ "the dog" ] ]; + var actual = getQueryResults("RETURN FIRST([ [ \"the dog\" ] ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test first function +//////////////////////////////////////////////////////////////////////////////// + + testFirst4 : function () { + var expected = [ null ]; + var actual = getQueryResults("RETURN FIRST([ ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test first function +//////////////////////////////////////////////////////////////////////////////// + + testFirstInvalid : function () { + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN FIRST()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN FIRST([ ], [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN FIRST(null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN FIRST(true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN FIRST(4)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN FIRST(\"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN FIRST({ })"); } )); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test last function +//////////////////////////////////////////////////////////////////////////////// + + testlast1 : function () { + var expected = [ [ "the dog" ] ]; + var actual = getQueryResults("RETURN LAST([ { \"the fox\" : \"jumped\" }, \"over\", [ \"the dog\" ] ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test last function +//////////////////////////////////////////////////////////////////////////////// + + testlast2 : function () { + var expected = [ "over" ]; + var actual = getQueryResults("RETURN LAST([ { \"the fox\" : \"jumped\" }, \"over\" ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test last function +//////////////////////////////////////////////////////////////////////////////// + + testlast3 : function () { + var expected = [ { "the fox" : "jumped" } ]; + var actual = getQueryResults("RETURN LAST([ { \"the fox\" : \"jumped\" } ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test last function +//////////////////////////////////////////////////////////////////////////////// + + testlast4 : function () { + var expected = [ null ]; + var actual = getQueryResults("RETURN LAST([ ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test last function +//////////////////////////////////////////////////////////////////////////////// + + testlastInvalid : function () { + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LAST()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LAST([ ], [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LAST(null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LAST(true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LAST(4)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LAST(\"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LAST({ })"); } )); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test reverse function +//////////////////////////////////////////////////////////////////////////////// + + testReverse1 : function () { + var expected = [ [ ] ]; + var actual = getQueryResults("RETURN REVERSE([ ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test reverse function +//////////////////////////////////////////////////////////////////////////////// + + testReverse2 : function () { + var expected = [ [ "fox" ] ]; + var actual = getQueryResults("RETURN REVERSE([ \"fox\" ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test reverse function +//////////////////////////////////////////////////////////////////////////////// + + testReverse3 : function () { + var expected = [ [ false, [ "fox", "jumped" ], { "quick" : "brown" }, "the" ] ]; + var actual = getQueryResults("RETURN REVERSE([ \"the\", { \"quick\" : \"brown\" }, [ \"fox\", \"jumped\" ], false ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test reverse function +//////////////////////////////////////////////////////////////////////////////// + + testReverseInvalid : function () { + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN REVERSE()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN REVERSE([ ], [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN REVERSE(null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN REVERSE(true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN REVERSE(4)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN REVERSE(\"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN REVERSE({ })"); } )); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test unique function +//////////////////////////////////////////////////////////////////////////////// + + testUnique1 : function () { + var expected = [ [ ] ]; + var actual = getQueryResults("RETURN UNIQUE([ ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test unique function +//////////////////////////////////////////////////////////////////////////////// + + testUnique2 : function () { + var expected = [ [ 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, false, true, null, "fox", "FOX", "Fox", "FoX", [0], [1], { "the fox" : "jumped" } ] ]; + var actual = getQueryResults("RETURN UNIQUE([ 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, false, true, null, \"fox\", \"FOX\", \"Fox\", \"FoX\", [ 0 ], [ 1 ], { \"the fox\" : \"jumped\" } ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test unique function +//////////////////////////////////////////////////////////////////////////////// + + testUnique3 : function () { + var expected = [ [ 1, 2, 3, 4, 5, 7, 9, 42, -1, -33 ] ]; + var actual = getQueryResults("RETURN UNIQUE([ 1, -1, 1, 2, 3, -1, 2, 3, 4, 5, 1, 3, 9, 2, -1, 9, -33, 42, 7 ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test unique function +//////////////////////////////////////////////////////////////////////////////// + + testUnique4 : function () { + var expected = [ [ [1, 2, 3], [3, 2, 1], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2] ] ]; + var actual = getQueryResults("RETURN UNIQUE([ [ 1, 2, 3 ], [ 3, 2, 1 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 2 , 1, 3 ] ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test unique function +//////////////////////////////////////////////////////////////////////////////// + + testUnique5 : function () { + var expected = [ [ { "the fox" : "jumped" }, { "the fox" : "jumped over" }, { "over" : "the dog", "the fox" : "jumped" }]] + + var actual = getQueryResults("RETURN UNIQUE([ { \"the fox\" : \"jumped\" }, { \"the fox\" : \"jumped over\" }, { \"the fox\" : \"jumped\", \"over\" : \"the dog\" }, { \"over\" : \"the dog\", \"the fox\" : \"jumped\" } ])", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test unique function +//////////////////////////////////////////////////////////////////////////////// + + testUniqueInvalid : function () { + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNIQUE()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNIQUE([ ], [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNIQUE(null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNIQUE(true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNIQUE(4)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNIQUE(\"yes\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN UNIQUE({ })"); } )); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test length function //////////////////////////////////////////////////////////////////////////////// @@ -143,6 +360,7 @@ function ahuacatlFunctionsTestSuite () { testLengthInvalid : function () { assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LENGTH()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LENGTH([ ], [ ])"); } )); assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LENGTH(null)"); } )); assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LENGTH(true)"); } )); assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN LENGTH(4)"); } )); @@ -709,7 +927,7 @@ function ahuacatlFunctionsTestSuite () { }, //////////////////////////////////////////////////////////////////////////////// -/// @brief test min function +/// @brief test max function //////////////////////////////////////////////////////////////////////////////// testMax3 : function () { @@ -719,7 +937,7 @@ function ahuacatlFunctionsTestSuite () { }, //////////////////////////////////////////////////////////////////////////////// -/// @brief test min function +/// @brief test max function //////////////////////////////////////////////////////////////////////////////// testMaxInvalid : function () { @@ -732,6 +950,46 @@ function ahuacatlFunctionsTestSuite () { assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN MAX({ })"); } )); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test has function +//////////////////////////////////////////////////////////////////////////////// + + testHas1 : function () { + var expected = [ true, true, true, false, true ]; + var actual = getQueryResults("FOR u IN [ { \"the fox\" : true }, { \"the fox\" : false }, { \"the fox\" : null }, { \"the FOX\" : true }, { \"the FOX\" : true, \"the fox\" : false } ] return HAS(u, \"the fox\")", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test has function +//////////////////////////////////////////////////////////////////////////////// + + testHas2 : function () { + var expected = [ false, false, false ]; + var actual = getQueryResults("FOR u IN [ { \"the foxx\" : { \"the fox\" : false } }, { \" the fox\" : false }, null ] return HAS(u, \"the fox\")", true); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test has function +//////////////////////////////////////////////////////////////////////////////// + + testHasInvalid : function () { + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS()"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ })"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, \"fox\", true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS(false, \"fox\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS(3, \"fox\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS(\"yes\", \"fox\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS([ ], \"fox\")"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, null)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, false)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, true)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, 1)"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, [ ])"); } )); + assertEqual(errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH.code, getErrorCode(function() { AHUACATL_RUN("RETURN HAS({ }, { })"); } )); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test non-existing functions //////////////////////////////////////////////////////////////////////////////// diff --git a/js/server/tests/ahuacatl-hash.js b/js/server/tests/ahuacatl-hash.js new file mode 100644 index 0000000000..62f5db86fc --- /dev/null +++ b/js/server/tests/ahuacatl-hash.js @@ -0,0 +1,147 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief tests for Ahuacatl, hash index queries +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2010-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 Jan Steemann +/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +var internal = require("internal"); +var jsunity = require("jsunity"); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test suite +//////////////////////////////////////////////////////////////////////////////// + +function ahuacatlHashTestSuite () { + var errors = internal.errors; + var hash; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief execute a given query +//////////////////////////////////////////////////////////////////////////////// + + function executeQuery (query, bindVars) { + var cursor = AHUACATL_RUN(query, bindVars); + return cursor; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief execute a given query and return the results as an array +//////////////////////////////////////////////////////////////////////////////// + + function getQueryResults (query, bindVars) { + var result = executeQuery(query, bindVars).getRows(); + var results = [ ]; + + for (var i in result) { + if (!result.hasOwnProperty(i)) { + continue; + } + + results.push(result[i]); + } + + return results; + } + + + return { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set up +//////////////////////////////////////////////////////////////////////////////// + + setUp : function () { + hash = internal.db.UnitTestsAhuacatlHash; + + if (hash.count() == 0) { + for (var i = 1; i <= 5; ++i) { + for (var j = 1; j <= 5; ++j) { + hash.save({ "a" : i, "b": j, "c": i }); + } + } + + hash.ensureHashIndex("a", "b"); + hash.ensureHashIndex("c"); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tear down +//////////////////////////////////////////////////////////////////////////////// + + tearDown : function () { + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test the single field hash index with equality +//////////////////////////////////////////////////////////////////////////////// + + testEqSingle1 : function () { + var expected = [ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ] ]; + var actual = getQueryResults("FOR v IN " + hash.name() + " FILTER v.c == 1 SORT v.b RETURN [ v.b ]"); + + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test the first hash index field with equality +//////////////////////////////////////////////////////////////////////////////// + + testEqSingle2 : function () { + var expected = [ [ 1, 4 ], [ 2, 4 ], [ 3, 4 ], [ 4, 4 ], [ 5, 4 ] ]; + var actual = getQueryResults("FOR v IN " + hash.name() + " FILTER v.c == 4 SORT v.b RETURN [ v.b, v.c ]"); + + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test multiple hash fields with multiple operators +//////////////////////////////////////////////////////////////////////////////// + + testEqMultiAll : function () { + for (var i = 1; i <= 5; ++i) { + for (var j = 1; j <=5; ++j) { + var expected = [ [ i, j ] ]; + var actual = getQueryResults("FOR v IN " + hash.name() + " FILTER v.a == @a && v.b == @b RETURN [ v.a, v.b ]", { "a" : i, "b" : j }); + + assertEqual(expected, actual); + } + } + } + + }; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes the test suite +//////////////////////////////////////////////////////////////////////////////// + +jsunity.run(ahuacatlHashTestSuite); + +return jsunity.done(); + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)" +// End: