1
0
Fork 0

added waitForSync parameter, added JavaScript tests

This commit is contained in:
Frank Celler 2012-03-09 10:13:42 +01:00
parent b0f717ccb8
commit 41a622652b
37 changed files with 2156 additions and 848 deletions

View File

@ -46,14 +46,6 @@
#include "BasicsC/locks-win32.h"
#endif
// -----------------------------------------------------------------------------
// --SECTION-- POSIX SPINS
// -----------------------------------------------------------------------------
#ifdef TRI_HAVE_POSIX_THREADS
#include "BasicsC/locks-posix.h"
#endif
// -----------------------------------------------------------------------------
// --SECTION-- MAC OS X SPIN
// -----------------------------------------------------------------------------

View File

@ -915,9 +915,11 @@ void QLOptimizeFreeRangeVector (TRI_vector_pointer_t* vector) {
if (range->_valueType == RANGE_TYPE_STRING) {
if (range->_minValue._stringValue) {
TRI_FreeString(range->_minValue._stringValue);
range->_minValue._stringValue = 0;
}
if (range->_maxValue._stringValue) {
TRI_FreeString(range->_maxValue._stringValue);
range->_maxValue._stringValue = 0;
}
}
@ -1434,7 +1436,7 @@ static QL_optimize_range_t* QLOptimizeCreateRange (TRI_query_node_t* memberNode,
}
else if (range->_valueType == RANGE_TYPE_STRING) {
range->_minValue._stringValue = TRI_DuplicateString(valueNode->_value._stringValue);
range->_maxValue._stringValue = range->_minValue._stringValue;
range->_maxValue._stringValue = TRI_DuplicateString(valueNode->_value._stringValue);
}
else if (range->_valueType == RANGE_TYPE_JSON) {
documentJs = TRI_InitQueryJavascript();
@ -1446,7 +1448,7 @@ static QL_optimize_range_t* QLOptimizeCreateRange (TRI_query_node_t* memberNode,
}
TRI_ConvertQueryJavascript(documentJs, valueNode, bindParameters);
range->_minValue._stringValue = TRI_DuplicateString(documentJs->_buffer->_buffer);
range->_maxValue._stringValue = range->_minValue._stringValue;
range->_maxValue._stringValue = TRI_DuplicateString(documentJs->_buffer->_buffer);
TRI_FreeQueryJavascript(documentJs);
if (!range->_minValue._stringValue) {
TRI_FreeStringBuffer(name);

File diff suppressed because it is too large Load Diff

View File

@ -561,6 +561,7 @@ named_attribute:
ABORT_IF_OOM($1);
ABORT_IF_OOM($3);
str->_value._stringValue = TRI_ParseQueryRegisterString(template_, TRI_UnescapeUtf8String($1, strlen($1), &outLength));
ABORT_IF_OOM(str->_value._stringValue);
$$ = TRI_ParseQueryCreateNode(template_, TRI_QueryNodeValueNamedValue);
ABORT_IF_OOM($$);
@ -574,6 +575,7 @@ named_attribute:
ABORT_IF_OOM($1);
ABORT_IF_OOM($3);
str->_value._stringValue = TRI_ParseQueryRegisterString(template_, TRI_UnescapeUtf8String($1 + 1, strlen($1) - 2, &outLength));
ABORT_IF_OOM(str->_value._stringValue);
$$ = TRI_ParseQueryCreateNode(template_, TRI_QueryNodeValueNamedValue);
ABORT_IF_OOM($$);
@ -613,7 +615,6 @@ collection_reference:
}
;
collection_name:
IDENTIFIER {
$$ = TRI_ParseQueryCreateNode(template_, TRI_QueryNodeValueIdentifier);
@ -627,6 +628,7 @@ collection_name:
ABORT_IF_OOM($$);
ABORT_IF_OOM($1);
$$->_value._stringValue = TRI_ParseQueryRegisterString(template_, TRI_UnescapeUtf8String($1 + 1, strlen($1) - 2, &outLength));
ABORT_IF_OOM($$->_value._stringValue);
}
;
@ -643,6 +645,7 @@ collection_alias:
ABORT_IF_OOM($$);
ABORT_IF_OOM($1);
$$->_value._stringValue = TRI_ParseQueryRegisterString(template_, TRI_UnescapeUtf8String($1 + 1, strlen($1) - 2, &outLength));
ABORT_IF_OOM($$->_value._stringValue);
}
;
@ -775,6 +778,15 @@ object_access:
name->_value._stringValue = $2;
TRI_ParseQueryContextAddElement(template_, name);
}
| '.' QUOTED_IDENTIFIER {
TRI_query_node_t* name = TRI_ParseQueryCreateNode(template_, TRI_QueryNodeValueIdentifier);
size_t outLength;
ABORT_IF_OOM(name);
ABORT_IF_OOM($2);
name->_value._stringValue = TRI_ParseQueryRegisterString(template_, TRI_UnescapeUtf8String($2 + 1, strlen($2) - 2, &outLength));
ABORT_IF_OOM(name->_value._stringValue);
TRI_ParseQueryContextAddElement(template_, name);
}
| '.' function_call {
ABORT_IF_OOM($2);
TRI_ParseQueryContextAddElement(template_, $2);
@ -786,6 +798,15 @@ object_access:
name->_value._stringValue = $3;
TRI_ParseQueryContextAddElement(template_, name);
}
| object_access '.' QUOTED_IDENTIFIER {
TRI_query_node_t* name = TRI_ParseQueryCreateNode(template_, TRI_QueryNodeValueIdentifier);
size_t outLength;
ABORT_IF_OOM(name);
ABORT_IF_OOM($3);
name->_value._stringValue = TRI_ParseQueryRegisterString(template_, TRI_UnescapeUtf8String($3 + 1, strlen($3) - 2, &outLength));
ABORT_IF_OOM(name->_value._stringValue);
TRI_ParseQueryContextAddElement(template_, name);
}
| object_access '.' function_call {
ABORT_IF_OOM($1);
ABORT_IF_OOM($3);
@ -1042,6 +1063,7 @@ atom:
ABORT_IF_OOM($$);
ABORT_IF_OOM($1);
$$->_value._stringValue = TRI_ParseQueryRegisterString(template_, TRI_UnescapeUtf8String($1 + 1, strlen($1) - 2, &outLength));
ABORT_IF_OOM($$->_value._stringValue);
}
| REAL {
double d = TRI_DoubleString($1);

View File

@ -171,6 +171,10 @@ HttpHandler::status_e RestCollectionHandler::execute () {
/// document. The "ETag" header field contains the revision of the newly created
/// document.
///
/// If the collection parameter @LIT{waitForSync} is @LIT{false}, then a
/// @LIT{HTTP 202} is returned in order to indicate that the document has been
/// accepted but not yet stored.
///
/// If the @FA{collection-identifier} is unknown, then a @LIT{HTTP 404} is
/// returned.
///
@ -227,6 +231,7 @@ bool RestCollectionHandler::createDocument () {
_documentCollection->beginWrite(_documentCollection);
bool waitForSync = _documentCollection->base._waitForSync;
TRI_doc_mptr_t const* mptr = _documentCollection->createJson(_documentCollection, TRI_DOC_MARKER_DOCUMENT, json, 0, true);
TRI_voc_did_t did = 0;
TRI_voc_rid_t rid = 0;
@ -241,7 +246,13 @@ bool RestCollectionHandler::createDocument () {
// .............................................................................
if (mptr != 0) {
generateCreated(_documentCollection->base._cid, did, rid);
if (waitForSync) {
generateCreated(_documentCollection->base._cid, did, rid);
}
else {
generateAccepted(_documentCollection->base._cid, did, rid);
}
return true;
}
else {

View File

@ -162,6 +162,17 @@ void RestVocbaseBaseHandler::generateCreated (TRI_voc_cid_t cid, TRI_voc_did_t d
response->setHeader("location", DOCUMENT_PATH + "/" + StringUtils::itoa(cid) + "/" + StringUtils::itoa(did));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates accepted message without content but a location header
////////////////////////////////////////////////////////////////////////////////
void RestVocbaseBaseHandler::generateAccepted (TRI_voc_cid_t cid, TRI_voc_did_t did, TRI_voc_rid_t rid) {
response = new HttpResponse(HttpResponse::ACCEPTED);
response->setHeader("ETag", "\"" + StringUtils::itoa(rid) + "\"");
response->setHeader("location", DOCUMENT_PATH + "/" + StringUtils::itoa(cid) + "/" + StringUtils::itoa(did));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates collection not found error message
////////////////////////////////////////////////////////////////////////////////

View File

@ -222,6 +222,12 @@ namespace triagens {
void generateCreated (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief generates accepted message without content but a location header
////////////////////////////////////////////////////////////////////////////////
void generateAccepted (TRI_voc_cid_t, TRI_voc_did_t, TRI_voc_rid_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief generates collection not found error message
////////////////////////////////////////////////////////////////////////////////

View File

@ -668,7 +668,7 @@ void AvocadoServer::executeShell () {
V8LineEditor* console = new V8LineEditor(context, ".avocado");
console->open();
console->open(true);
while (true) {
while(! v8::V8::IdleNotification()) {
@ -690,11 +690,16 @@ void AvocadoServer::executeShell () {
console->addHistory(input);
v8::HandleScope scope;
v8::TryCatch tryCatch;
TRI_ExecuteStringVocBase(context, v8::String::New(input), name, true, true);
TRI_ExecuteStringVocBase(context, v8::String::New(input), name, true);
TRI_FreeString(input);
if (tryCatch.HasCaught()) {
cout << TRI_StringifyV8Exception(&tryCatch);
}
}
console->close();
delete console;

View File

@ -137,6 +137,7 @@ string const& JSLoader::findScript (string const& name) {
bool JSLoader::loadScript (v8::Persistent<v8::Context> context, string const& name) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
findScript(name);
@ -146,11 +147,17 @@ bool JSLoader::loadScript (v8::Persistent<v8::Context> context, string const& na
return false;
}
return TRI_ExecuteStringVocBase(context,
v8::String::New(i->second.c_str()),
v8::String::New(name.c_str()),
false,
true);
TRI_ExecuteStringVocBase(context,
v8::String::New(i->second.c_str()),
v8::String::New(name.c_str()),
false);
if (tryCatch.HasCaught()) {
TRI_LogV8Exception(&tryCatch);
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
@ -158,6 +165,9 @@ bool JSLoader::loadScript (v8::Persistent<v8::Context> context, string const& na
////////////////////////////////////////////////////////////////////////////////
bool JSLoader::loadAllScripts (v8::Persistent<v8::Context> context) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (_directory.empty()) {
return true;
}
@ -171,6 +181,7 @@ bool JSLoader::loadAllScripts (v8::Persistent<v8::Context> context) {
bool JSLoader::executeScript (v8::Persistent<v8::Context> context, string const& name) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
findScript(name);
@ -182,11 +193,17 @@ bool JSLoader::executeScript (v8::Persistent<v8::Context> context, string const&
string content = "(function() { " + i->second + "/* end-of-file '" + name + "' */ })()";
return TRI_ExecuteStringVocBase(context,
v8::String::New(content.c_str()),
v8::String::New(name.c_str()),
false,
true);
TRI_ExecuteStringVocBase(context,
v8::String::New(content.c_str()),
v8::String::New(name.c_str()),
false);
if (! tryCatch.HasCaught()) {
TRI_LogV8Exception(&tryCatch);
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
@ -194,6 +211,9 @@ bool JSLoader::executeScript (v8::Persistent<v8::Context> context, string const&
////////////////////////////////////////////////////////////////////////////////
bool JSLoader::executeAllScripts (v8::Persistent<v8::Context> context) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (_directory.empty()) {
return true;
}

View File

@ -504,7 +504,7 @@ HttpResponse* TRI_ExecuteActionVocBase (TRI_vocbase_t* vocbase,
// convert the result
if (tryCatch.HasCaught()) {
string msg = TRI_ReportV8Exception(&tryCatch);
string msg = TRI_StringifyV8Exception(&tryCatch);
HttpResponse* response = new HttpResponse(HttpResponse::SERVER_ERROR);
response->body().appendText(msg);

View File

@ -83,7 +83,7 @@ static void RunShell (v8::Handle<v8::Context> context) {
V8LineEditor* console = new V8LineEditor(context, ".avoc");
console->open();
console->open(true);
while (true) {
while(! V8::IdleNotification()) {
@ -103,7 +103,7 @@ static void RunShell (v8::Handle<v8::Context> context) {
HandleScope scope;
TRI_ExecuteStringVocBase(context, String::New(input), name, true, true);
TRI_ExecuteStringVocBase(context, String::New(input), name, true);
TRI_FreeString(input);
}
@ -138,7 +138,7 @@ static int RunMain (v8::Handle<v8::Context> context, int argc, char* argv[]) {
v8::Handle<v8::String> source = v8::String::New(content);
TRI_FreeString(content);
bool ok = TRI_ExecuteStringVocBase(context, source, filename, false, true);
bool ok = TRI_ExecuteStringVocBase(context, source, filename, false);
if (! ok) {
return 1;

View File

@ -94,9 +94,7 @@ typedef struct TRI_v8_global_s {
JournalSizeKey(),
ParametersKey(),
ResponseCodeKey(),
SyncAfterBytesKey(),
SyncAfterObjectsKey(),
SyncAfterTimeKey(),
WaitForSyncKey(),
DocumentIdRegex() {
}
@ -417,22 +415,10 @@ typedef struct TRI_v8_global_s {
v8::Persistent<v8::String> SuffixKey;
////////////////////////////////////////////////////////////////////////////////
/// @brief "syncAfterBytes" key name
/// @brief "waitForSync" key name
////////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::String> SyncAfterBytesKey;
////////////////////////////////////////////////////////////////////////////////
/// @brief "syncAfterObjects" key name
////////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::String> SyncAfterObjectsKey;
////////////////////////////////////////////////////////////////////////////////
/// @brief "syncAfterTime" key name
////////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::String> SyncAfterTimeKey;
v8::Persistent<v8::String> WaitForSyncKey;
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -380,12 +380,14 @@ V8LineEditor::V8LineEditor (v8::Handle<v8::Context> context, string const& histo
/// @brief line editor open
////////////////////////////////////////////////////////////////////////////////
bool V8LineEditor::open () {
bool V8LineEditor::open (const bool autoComplete) {
rl_initialize();
rl_attempted_completion_function = AttemptedCompletion;
rl_completer_word_break_characters = WordBreakCharacters;
if (autoComplete) {
rl_attempted_completion_function = AttemptedCompletion;
rl_completer_word_break_characters = WordBreakCharacters;
rl_bind_key('\t', rl_complete);
rl_bind_key('\t', rl_complete);
}
using_history();
stifle_history(MAX_HISTORY_ENTRIES);

View File

@ -72,7 +72,7 @@ class V8LineEditor {
/// @brief line editor open
////////////////////////////////////////////////////////////////////////////////
bool open ();
bool open (const bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief line editor shutdown

View File

@ -686,9 +686,10 @@ bool TRI_ExecuteOrderExecutionContext (TRI_js_exec_context_t context, int* r) {
/// @brief reads/execute a file into/in the current context
////////////////////////////////////////////////////////////////////////////////
static bool LoadJavaScriptFile (v8::Handle<v8::Context> context, char const* filename, bool execute) {
static bool LoadJavaScriptFile (v8::Handle<v8::Context> context,
char const* filename,
bool execute) {
v8::HandleScope handleScope;
v8::TryCatch tryCatch;
char* content = TRI_SlurpFile(filename);
@ -718,8 +719,6 @@ static bool LoadJavaScriptFile (v8::Handle<v8::Context> context, char const* fil
// compilation failed, print errors that happened during compilation
if (script.IsEmpty()) {
LOG_ERROR("cannot compile java script file '%s'", filename);
TRI_ReportV8Exception(&tryCatch);
return false;
}
@ -727,17 +726,10 @@ static bool LoadJavaScriptFile (v8::Handle<v8::Context> context, char const* fil
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
assert(tryCatch.HasCaught());
// print errors that happened during execution
LOG_ERROR("cannot execute java script file '%s'", filename);
TRI_ReportV8Exception(&tryCatch);
return false;
}
LOG_TRACE("loaded java script file: '%s'", filename);
return true;
}
@ -746,6 +738,7 @@ static bool LoadJavaScriptFile (v8::Handle<v8::Context> context, char const* fil
////////////////////////////////////////////////////////////////////////////////
static bool LoadJavaScriptDirectory (v8::Handle<v8::Context> context, char const* path, bool execute) {
v8::HandleScope scope;
TRI_vector_string_t files;
bool result;
regex_t re;
@ -760,6 +753,7 @@ static bool LoadJavaScriptDirectory (v8::Handle<v8::Context> context, char const
result = true;
for (i = 0; i < files._length; ++i) {
v8::TryCatch tryCatch;
bool ok;
char const* filename;
char* full;
@ -771,12 +765,14 @@ static bool LoadJavaScriptDirectory (v8::Handle<v8::Context> context, char const
}
full = TRI_Concatenate2File(path, filename);
ok = LoadJavaScriptFile(context, full, execute);
TRI_FreeString(full);
result = result && ok;
if (! ok) {
TRI_LogV8Exception(&tryCatch);
}
}
TRI_DestroyVectorString(&files);
@ -813,7 +809,6 @@ static bool LoadJavaScriptDirectory (v8::Handle<v8::Context> context, char const
static v8::Handle<v8::Value> JS_Execute (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
size_t i;
// extract arguments
@ -868,32 +863,24 @@ static v8::Handle<v8::Value> JS_Execute (v8::Arguments const& argv) {
// compilation failed, print errors that happened during compilation
if (script.IsEmpty()) {
assert(tryCatch.HasCaught());
TRI_PrintV8Exception(&tryCatch);
if (useSandbox) {
context->DetachGlobal();
context->Exit();
}
return scope.Close(tryCatch.ReThrow());
return scope.Close(v8::Undefined());
}
// compilation succeeded, run the script
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
assert(tryCatch.HasCaught());
TRI_PrintV8Exception(&tryCatch);
if (useSandbox) {
context->DetachGlobal();
context->Exit();
}
return scope.Close(tryCatch.ReThrow());
return scope.Close(v8::Undefined());
}
// copy result back into the sandbox
@ -941,7 +928,6 @@ static v8::Handle<v8::Value> JS_Execute (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_Load (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
// extract arguments
if (argv.Length() != 1) {
@ -960,11 +946,10 @@ static v8::Handle<v8::Value> JS_Load (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(v8::String::New(TRI_last_error())));
}
bool ok = TRI_ExecuteStringVocBase(v8::Context::GetCurrent(), v8::String::New(content), argv[0], false, true);
TRI_ExecuteStringVocBase(v8::Context::GetCurrent(), v8::String::New(content), argv[0], false);
TRI_FreeString(content);
return scope.Close(ok ? v8::True() : v8::False());
return scope.Close(v8::Undefined());
}
////////////////////////////////////////////////////////////////////////////////
@ -1400,7 +1385,7 @@ void TRI_AugmentObject (v8::Handle<v8::Value> value, TRI_json_t const* json) {
/// @brief reports an exception
////////////////////////////////////////////////////////////////////////////////
string TRI_ReportV8Exception (v8::TryCatch* tryCatch) {
string TRI_StringifyV8Exception (v8::TryCatch* tryCatch) {
v8::HandleScope handle_scope;
v8::String::Utf8Value exception(tryCatch->Exception());
@ -1411,12 +1396,10 @@ string TRI_ReportV8Exception (v8::TryCatch* tryCatch) {
// V8 didn't provide any extra information about this error; just print the exception.
if (message.IsEmpty()) {
if (exceptionString == 0) {
LOG_ERROR("JavaScript exception");
result = "JavaScript exception";
result = "JavaScript exception\n";
}
else {
LOG_ERROR("JavaScript exception: %s", exceptionString);
result = "JavaScript exception: " + string(exceptionString);
result = "JavaScript exception: " + string(exceptionString) + "\n";
}
}
else {
@ -1424,35 +1407,51 @@ string TRI_ReportV8Exception (v8::TryCatch* tryCatch) {
const char* filenameString = *filename;
int linenum = message->GetLineNumber();
int start = message->GetStartColumn() + 1;
int end = message->GetEndColumn();
if (filenameString == 0) {
if (exceptionString == 0) {
LOG_ERROR("JavaScript exception");
result = "JavaScript exception";
result = "JavaScript exception\n";
}
else {
LOG_ERROR("JavaScript exception: %s", exceptionString);
result = "JavaScript exception: " + string(exceptionString);
result = "JavaScript exception: " + string(exceptionString) + "\n";
}
}
else {
if (exceptionString == 0) {
LOG_ERROR("JavaScript exception in file '%s' at %d,%d", filenameString, linenum, start);
result = "JavaScript exception in file '" + string(filenameString) + "' at "
+ StringUtils::itoa(linenum) + "," + StringUtils::itoa(start);
+ StringUtils::itoa(linenum) + "," + StringUtils::itoa(start) + "\n";
}
else {
LOG_ERROR("JavaScript exception in file '%s' at %d,%d: %s", filenameString, linenum, start, exceptionString);
result = "JavaScript exception in file '" + string(filenameString) + "' at "
+ StringUtils::itoa(linenum) + "," + StringUtils::itoa(start)
+ ": " + exceptionString;
+ ": " + exceptionString + "\n";
}
}
v8::String::Utf8Value sourceline(message->GetSourceLine());
if (*sourceline) {
string l = *sourceline;
result += "!" + l + "\n";
if (1 < start) {
l = string(start - 1, ' ');
}
else {
l = "";
}
l += string((size_t)(end - start + 1), '^');
result += "!" + l + "\n";
}
v8::String::Utf8Value stacktrace(tryCatch->StackTrace());
if (*stacktrace && stacktrace.length() > 0) {
LOG_DEBUG("stacktrace: %s", *stacktrace);
result += "stacktrace: " + string(*stacktrace) + "\n";
}
}
@ -1463,7 +1462,7 @@ string TRI_ReportV8Exception (v8::TryCatch* tryCatch) {
/// @brief prints an exception and stacktrace
////////////////////////////////////////////////////////////////////////////////
void TRI_PrintV8Exception (v8::TryCatch* tryCatch) {
void TRI_LogV8Exception (v8::TryCatch* tryCatch) {
v8::HandleScope handle_scope;
v8::String::Utf8Value exception(tryCatch->Exception());
@ -1488,18 +1487,18 @@ void TRI_PrintV8Exception (v8::TryCatch* tryCatch) {
if (filenameString == 0) {
if (exceptionString == 0) {
LOG_ERROR("exception");
LOG_ERROR("JavaScript exception");
}
else {
LOG_ERROR("exception: %s", exceptionString);
LOG_ERROR("JavaScript exception: %s", exceptionString);
}
}
else {
if (exceptionString == 0) {
LOG_ERROR("exception in file '%s' at %d,%d", filenameString, linenum, start);
LOG_ERROR("JavaScript exception in file '%s' at %d,%d", filenameString, linenum, start);
}
else {
LOG_ERROR("exception in file '%s' at %d,%d: %s", filenameString, linenum, start, exceptionString);
LOG_ERROR("JavaScript exception in file '%s' at %d,%d: %s", filenameString, linenum, start, exceptionString);
}
}
@ -1508,18 +1507,18 @@ void TRI_PrintV8Exception (v8::TryCatch* tryCatch) {
if (*sourceline) {
string l = *sourceline;
LOG_ERROR("[%s]", l.c_str());
LOG_ERROR("!%s", l.c_str());
if (1 < start) {
l = string(start - 1, '_');
l = string(start - 1, ' ');
}
else {
l = "";
l = "";
}
l += string((size_t)(end - start + 1), '^');
LOG_ERROR("_%s", l.c_str());
LOG_ERROR("!%s", l.c_str());
}
v8::String::Utf8Value stacktrace(tryCatch->StackTrace());
@ -1569,19 +1568,13 @@ bool TRI_ExecuteJavaScriptDirectory (v8::Handle<v8::Context> context, char const
bool TRI_ExecuteStringVocBase (v8::Handle<v8::Context> context,
v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool printResult,
bool reportExceptions) {
v8::HandleScope handleScope;
v8::TryCatch tryCatch;
bool printResult) {
v8::HandleScope scope;
v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
// compilation failed, print errors that happened during compilation
if (script.IsEmpty()) {
if (reportExceptions) {
TRI_PrintV8Exception(&tryCatch);
}
return false;
}
@ -1590,25 +1583,23 @@ bool TRI_ExecuteStringVocBase (v8::Handle<v8::Context> context,
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
assert(tryCatch.HasCaught());
// print errors that happened during execution
if (reportExceptions) {
TRI_PrintV8Exception(&tryCatch);
}
return false;
}
else {
assert(! tryCatch.HasCaught());
// if all went well and the result wasn't undefined then print the returned value
if (printResult && ! result->IsUndefined()) {
v8::TryCatch tryCatch;
v8::Handle<v8::String> printFuncName = v8::String::New("print");
v8::Handle<v8::Function> print = v8::Handle<v8::Function>::Cast(context->Global()->Get(printFuncName));
v8::Handle<v8::Value> args[] = { result };
print->Call(print, 1, args);
if (tryCatch.HasCaught()) {
TRI_LogV8Exception(&tryCatch);
}
}
return true;

View File

@ -56,13 +56,13 @@ void TRI_AugmentObject (v8::Handle<v8::Value> value, TRI_json_t const* json);
/// @brief reports an exception
////////////////////////////////////////////////////////////////////////////////
std::string TRI_ReportV8Exception (v8::TryCatch* tryCatch);
std::string TRI_StringifyV8Exception (v8::TryCatch* tryCatch);
////////////////////////////////////////////////////////////////////////////////
/// @brief prints an exception and stacktrace
////////////////////////////////////////////////////////////////////////////////
void TRI_PrintV8Exception (v8::TryCatch* tryCatch);
void TRI_LogV8Exception (v8::TryCatch* tryCatch);
////////////////////////////////////////////////////////////////////////////////
/// @brief reads a file into the current context
@ -95,8 +95,7 @@ bool TRI_ExecuteJavaScriptDirectory (v8::Handle<v8::Context> context, char const
bool TRI_ExecuteStringVocBase (v8::Handle<v8::Context> context,
v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool printResult,
bool reportExceptions);
bool printResult);
////////////////////////////////////////////////////////////////////////////////
/// @brief stores the V8 utils function inside the global variable

View File

@ -731,6 +731,8 @@ static TRI_rc_cursor_t* ExecuteQuery (v8::Handle<v8::Object> queryObject,
////////////////////////////////////////////////////////////////////////////////
static TRI_query_cursor_t* ExecuteQueryInstance (v8::Handle<v8::Object> queryObject,
bool doCount,
uint32_t max,
v8::Handle<v8::Value>* err) {
v8::TryCatch tryCatch;
@ -743,7 +745,7 @@ static TRI_query_cursor_t* ExecuteQueryInstance (v8::Handle<v8::Object> queryObj
LOG_TRACE("executing query");
TRI_query_cursor_t* cursor = TRI_ExecuteQueryInstance(instance);
TRI_query_cursor_t* cursor = TRI_ExecuteQueryInstance(instance, doCount, max);
if (!cursor) {
if (tryCatch.HasCaught()) {
*err = tryCatch.Exception();
@ -2037,14 +2039,29 @@ static v8::Handle<v8::Value> JS_ExecuteAql (v8::Arguments const& argv) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes a query instance
/// @brief executes a query, returns a cursor
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_ExecuteQueryInstance (v8::Arguments const& argv) {
v8::HandleScope scope;
// return number of total records in cursor?
bool doCount = false;
if (argv.Length() > 0) {
doCount = TRI_ObjectToBoolean(argv[0]);
}
// maximum number of results to return at once
uint32_t max = 1000;
if (argv.Length() > 1) {
double maxValue = TRI_ObjectToDouble(argv[1]);
if (maxValue >= 1.0) {
max = (uint32_t) maxValue;
}
}
v8::Handle<v8::Value> err;
TRI_query_cursor_t* cursor = ExecuteQueryInstance(argv.Holder(), &err);
TRI_query_cursor_t* cursor = ExecuteQueryInstance(argv.Holder(), doCount, max, &err);
if (!cursor) {
return v8::ThrowException(err);
@ -2065,10 +2082,6 @@ static v8::Handle<v8::Value> JS_ExecuteQueryInstance (v8::Arguments const& argv)
// --SECTION-- AQL CURSOR
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- javascript functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
@ -2092,6 +2105,7 @@ static v8::Handle<v8::Value> JS_DisposeQueryCursor (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
// set the deleted flag so the gc can catch this instance
TRI_LockQueryCursor(cursor);
cursor->_deleted = true;
TRI_UnlockQueryCursor(cursor);
@ -2179,32 +2193,39 @@ static v8::Handle<v8::Value> JS_NextQueryCursor (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
v8::Handle<v8::Value> value;
TRI_LockQueryCursor(cursor);
if (cursor->_deleted) {
TRI_UnlockQueryCursor(cursor);
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
v8::Handle<v8::Value> value;
bool ok = true;
TRI_js_exec_context_t context = NULL;
// exceptions must be caught in the following part because we hold an exclusive
// lock that might otherwise not be freed
try {
TRI_rc_result_t* next = cursor->next(cursor);
if (!next) {
value = v8::Undefined();
}
else {
TRI_js_exec_context_t context = TRI_CreateExecutionContext(cursor->_functionCode);
context = TRI_CreateExecutionContext(cursor->_functionCode);
if (context) {
TRI_DefineSelectExecutionContext(context, next);
ok = TRI_ExecuteExecutionContext(context, (void*) &value);
TRI_FreeExecutionContext(context);
}
}
}
catch (...) {
}
if (context) {
TRI_FreeExecutionContext(context);
}
// always free lock
TRI_UnlockQueryCursor(cursor);
if (!ok) {
@ -2219,6 +2240,142 @@ static v8::Handle<v8::Value> JS_NextQueryCursor (v8::Arguments const& argv) {
return scope.Close(value);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the next x rows from the cursor in one go
///
/// This function constructs multiple rows at once and should be preferred over
/// hasNext()...next() when iterating over bigger result sets
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_GetRowsQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: getRows()")));
}
v8::Handle<v8::Object> self = argv.Holder();
TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
if (!cursor) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
v8::Handle<v8::Array> result = v8::Array::New();
TRI_LockQueryCursor(cursor);
if (cursor->_deleted) {
TRI_UnlockQueryCursor(cursor);
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
TRI_js_exec_context_t context = NULL;
bool ok = true;
// exceptions must be caught in the following part because we hold an exclusive
// lock that might otherwise not be freed
try {
uint32_t max = cursor->getMax(cursor);
context = TRI_CreateExecutionContext(cursor->_functionCode);
if (context) {
for (uint32_t i = 0; i < max; i++) {
TRI_rc_result_t* next = cursor->next(cursor);
if (!next) {
break;
}
TRI_DefineSelectExecutionContext(context, next);
v8::Handle<v8::Value> value;
ok = TRI_ExecuteExecutionContext(context, (void*) &value);
if (ok) {
result->Set(i, value);
}
}
}
}
catch (...) {
}
if (context) {
TRI_FreeExecutionContext(context);
}
// always free lock
TRI_UnlockQueryCursor(cursor);
if (!ok) {
if (tryCatch.HasCaught()) {
return scope.Close(v8::ThrowException(tryCatch.Exception()));
}
else {
return scope.Close(v8::ThrowException(v8::String::New("cannot convert to JavaScript")));
}
}
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return max number of results per transfer for cursor
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_GetMaxQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: getMax()")));
}
v8::Handle<v8::Object> self = argv.Holder();
TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
if (!cursor) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
TRI_LockQueryCursor(cursor);
if (cursor->_deleted) {
TRI_UnlockQueryCursor(cursor);
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
uint32_t max = cursor->getMax(cursor);
TRI_UnlockQueryCursor(cursor);
return scope.Close(v8::Number::New(max));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return if count flag was set for cursor
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_HasCountQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: hasCount()")));
}
v8::Handle<v8::Object> self = argv.Holder();
TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
if (!cursor) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
TRI_LockQueryCursor(cursor);
if (cursor->_deleted) {
TRI_UnlockQueryCursor(cursor);
return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
}
bool hasCount = cursor->hasCount(cursor);
TRI_UnlockQueryCursor(cursor);
return scope.Close(hasCount ? v8::True() : v8::False());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if the cursor is exhausted
////////////////////////////////////////////////////////////////////////////////
@ -3468,49 +3625,18 @@ static v8::Handle<v8::Value> JS_ParameterVocbaseCol (v8::Arguments const& argv)
v8::Handle<v8::Object> po = par->ToObject();
TRI_LockCondition(&sim->_journalsCondition);
TRI_voc_size_t syncAfterObjects = sim->base.base._syncAfterObjects;
TRI_voc_size_t syncAfterBytes = sim->base.base._syncAfterBytes;
double syncAfterTime = sim->base.base._syncAfterTime;
bool waitForSync = sim->base.base._waitForSync;
TRI_UnlockCondition(&sim->_journalsCondition);
bool error;
// extract sync after objects
if (po->Has(v8g->SyncAfterObjectsKey)) {
syncAfterObjects = TRI_ObjectToDouble(po->Get(v8g->SyncAfterObjectsKey), error);
if (error || syncAfterObjects < 0.0) {
return scope.Close(v8::ThrowException(v8::String::New("<parameter>.syncAfterObjects must be a number")));
}
}
// extract sync after bytes
if (po->Has(v8g->SyncAfterBytesKey)) {
syncAfterBytes = TRI_ObjectToDouble(po->Get(v8g->SyncAfterBytesKey), error);
if (error || syncAfterBytes < 0.0) {
return scope.Close(v8::ThrowException(v8::String::New("<parameter>.syncAfterBytes must be a number")));
}
}
// extract sync after times
if (po->Has(v8g->SyncAfterTimeKey)) {
syncAfterTime = TRI_ObjectToDouble(po->Get(v8g->SyncAfterTimeKey), error);
if (error || syncAfterTime < 0.0) {
return scope.Close(v8::ThrowException(v8::String::New("<parameter>.syncAfterTime must be a non-negative number")));
}
if (po->Has(v8g->WaitForSyncKey)) {
waitForSync = TRI_ObjectToBoolean(po->Get(v8g->WaitForSyncKey));
}
// try to write new parameter to file
TRI_LockCondition(&sim->_journalsCondition);
sim->base.base._syncAfterObjects = syncAfterObjects;
sim->base.base._syncAfterBytes = syncAfterBytes;
sim->base.base._syncAfterTime = syncAfterTime;
sim->base.base._waitForSync = waitForSync;
bool ok = TRI_UpdateParameterInfoCollection(&sim->base.base);
TRI_UnlockCondition(&sim->_journalsCondition);
@ -3528,15 +3654,11 @@ static v8::Handle<v8::Value> JS_ParameterVocbaseCol (v8::Arguments const& argv)
TRI_LockCondition(&sim->_journalsCondition);
TRI_voc_size_t maximalSize = sim->base.base._maximalSize;
TRI_voc_size_t syncAfterObjects = sim->base.base._syncAfterObjects;
TRI_voc_size_t syncAfterBytes = sim->base.base._syncAfterBytes;
double syncAfterTime = sim->base.base._syncAfterTime;
bool waitForSync = sim->base.base._waitForSync;
TRI_UnlockCondition(&sim->_journalsCondition);
result->Set(v8g->SyncAfterObjectsKey, v8::Number::New(syncAfterObjects));
result->Set(v8g->SyncAfterBytesKey, v8::Number::New(syncAfterBytes));
result->Set(v8g->SyncAfterTimeKey, v8::Number::New(syncAfterTime));
result->Set(v8g->WaitForSyncKey, waitForSync ? v8::True() : v8::False());
result->Set(v8g->JournalSizeKey, v8::Number::New(maximalSize));
}
@ -4537,6 +4659,9 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocbase_t* vocbas
v8::Handle<v8::String> ExecuteFuncName = v8::Persistent<v8::String>::New(v8::String::New("execute"));
v8::Handle<v8::String> FiguresFuncName = v8::Persistent<v8::String>::New(v8::String::New("figures"));
v8::Handle<v8::String> GetIndexesFuncName = v8::Persistent<v8::String>::New(v8::String::New("getIndexes"));
v8::Handle<v8::String> GetMaxFuncName = v8::Persistent<v8::String>::New(v8::String::New("getMax"));
v8::Handle<v8::String> GetRowsFuncName = v8::Persistent<v8::String>::New(v8::String::New("getRows"));
v8::Handle<v8::String> HasCountFuncName = v8::Persistent<v8::String>::New(v8::String::New("hasCount"));
v8::Handle<v8::String> HasNextFuncName = v8::Persistent<v8::String>::New(v8::String::New("hasNext"));
v8::Handle<v8::String> IdFuncName = v8::Persistent<v8::String>::New(v8::String::New("id"));
v8::Handle<v8::String> InEdgesFuncName = v8::Persistent<v8::String>::New(v8::String::New("inEdges"));
@ -4561,9 +4686,7 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocbase_t* vocbas
// .............................................................................
v8g->JournalSizeKey = v8::Persistent<v8::String>::New(v8::String::New("journalSize"));
v8g->SyncAfterBytesKey = v8::Persistent<v8::String>::New(v8::String::New("syncAfterBytes"));
v8g->SyncAfterObjectsKey = v8::Persistent<v8::String>::New(v8::String::New("syncAfterObjects"));
v8g->SyncAfterTimeKey = v8::Persistent<v8::String>::New(v8::String::New("syncAfterTime"));
v8g->WaitForSyncKey = v8::Persistent<v8::String>::New(v8::String::New("waitForSync"));
if (v8g->DidKey.IsEmpty()) {
v8g->DidKey = v8::Persistent<v8::String>::New(v8::String::New("_id"));
@ -4803,11 +4926,14 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context, TRI_vocbase_t* vocbas
rt = ft->InstanceTemplate();
rt->SetInternalFieldCount(2);
rt->Set(HasNextFuncName, v8::FunctionTemplate::New(JS_HasNextQueryCursor));
rt->Set(NextFuncName, v8::FunctionTemplate::New(JS_NextQueryCursor));
rt->Set(CountFuncName, v8::FunctionTemplate::New(JS_CountQueryCursor));
rt->Set(IdFuncName, v8::FunctionTemplate::New(JS_IdQueryCursor));
rt->Set(DisposeFuncName, v8::FunctionTemplate::New(JS_DisposeQueryCursor));
rt->Set(GetMaxFuncName, v8::FunctionTemplate::New(JS_GetMaxQueryCursor));
rt->Set(GetRowsFuncName, v8::FunctionTemplate::New(JS_GetRowsQueryCursor));
rt->Set(HasCountFuncName, v8::FunctionTemplate::New(JS_HasCountQueryCursor));
rt->Set(HasNextFuncName, v8::FunctionTemplate::New(JS_HasNextQueryCursor));
rt->Set(IdFuncName, v8::FunctionTemplate::New(JS_IdQueryCursor));
rt->Set(NextFuncName, v8::FunctionTemplate::New(JS_NextQueryCursor));
v8g->QueryCursorTempl = v8::Persistent<v8::ObjectTemplate>::New(rt);

View File

@ -94,10 +94,12 @@ namespace triagens {
_version = vs->getValue();
}
}
delete json;
}
}
}
delete result;
}
V8ClientConnection::~V8ClientConnection () {

View File

@ -48,8 +48,6 @@
#include "V8/v8-utils.h"
#include "V8Client/V8ClientConnection.h"
using namespace v8;
using namespace std;
using namespace triagens::basics;
using namespace triagens::httpclient;
@ -145,6 +143,12 @@ static bool noColors = false;
static bool prettyPrint = false;
////////////////////////////////////////////////////////////////////////////////
/// @brief disable auto completion
////////////////////////////////////////////////////////////////////////////////
static bool noAutoComplete = false;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -159,7 +163,7 @@ static bool prettyPrint = false;
/// @verbinclude fluent39
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> Tri_Output (v8::Arguments const& argv) {
static v8::Handle<v8::Value> Js_Pager_Output (v8::Arguments const& argv) {
for (int i = 0; i < argv.Length(); i++) {
v8::HandleScope scope;
@ -264,7 +268,8 @@ static void ParseProgramOptions (int argc, char* argv[]) {
("startup", &StartupPath, "startup path containing the JavaScript files")
("use_pager", &usePager, "use pager")
("pager", &OutputPager, "output pager (default: 'more')")
("no_colors", &noColors, "deaktivate color support")
("no_colors", &noColors, "deactivate color support")
("no_autocomplete", &noAutoComplete, "disable auto completion")
("pretty_print", &prettyPrint, "pretty print values")
;
@ -358,7 +363,7 @@ static T* UnwrapClass (v8::Handle<v8::Object> obj, int32_t type) {
/// @brief ClientConnection constructor
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_ConstructorCallback(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_ConstructorCallback(v8::Arguments const& argv) {
v8::HandleScope scope;
string server = DEFAULT_SERVER_NAME;
@ -398,7 +403,7 @@ static Handle<Value> ClientConnection_ConstructorCallback(v8::Arguments const& a
/// @brief ClientConnection method "httpGet"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_httpGet(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_httpGet(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -428,7 +433,7 @@ static Handle<Value> ClientConnection_httpGet(v8::Arguments const& argv) {
/// @brief ClientConnection method "httpDelete"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_httpDelete(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_httpDelete(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -458,7 +463,7 @@ static Handle<Value> ClientConnection_httpDelete(v8::Arguments const& argv) {
/// @brief ClientConnection method "httpPost"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_httpPost(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_httpPost(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -489,7 +494,7 @@ static Handle<Value> ClientConnection_httpPost(v8::Arguments const& argv) {
/// @brief ClientConnection method "httpPut"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_httpPut(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_httpPut(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -520,7 +525,7 @@ static Handle<Value> ClientConnection_httpPut(v8::Arguments const& argv) {
/// @brief ClientConnection method "lastError"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_lastHttpReturnCode(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_lastHttpReturnCode(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -542,7 +547,7 @@ static Handle<Value> ClientConnection_lastHttpReturnCode(v8::Arguments const& ar
/// @brief ClientConnection method "lastErrorMessage"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_lastErrorMessage(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_lastErrorMessage(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -564,7 +569,7 @@ static Handle<Value> ClientConnection_lastErrorMessage(v8::Arguments const& argv
/// @brief ClientConnection method "isConnected"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_isConnected(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_isConnected(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -585,7 +590,7 @@ static Handle<Value> ClientConnection_isConnected(v8::Arguments const& argv) {
/// @brief ClientConnection method "isConnected"
////////////////////////////////////////////////////////////////////////////////
static Handle<Value> ClientConnection_toString(v8::Arguments const& argv) {
static v8::Handle<v8::Value> ClientConnection_toString(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
@ -599,13 +604,15 @@ static Handle<Value> ClientConnection_toString(v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(v8::String::New("usage: toString()")));
}
string result = "[object AvocadoConnection/"
string result = "[object AvocadoConnection:"
+ connection->getHostname()
+ ":"
+ triagens::basics::StringUtils::itoa(connection->getPort());
+ triagens::basics::StringUtils::itoa(connection->getPort())
+ ","
+ connection->getVersion();
if (connection->isConnected()) {
result += "/connected]";
result += ",connected]";
}
else {
result += "]";
@ -614,7 +621,26 @@ static Handle<Value> ClientConnection_toString(v8::Arguments const& argv) {
return scope.Close(v8::String::New(result.c_str()));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief ClientConnection method "isConnected"
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> ClientConnection_getVersion(v8::Arguments const& argv) {
v8::HandleScope scope;
// get the connection
V8ClientConnection* connection = UnwrapClass<V8ClientConnection>(argv.Holder(), WRAP_TYPE_CONNECTION);
if (connection == 0) {
return scope.Close(v8::ThrowException(v8::String::New("connection class corrupted")));
}
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: getVersion()")));
}
return scope.Close(v8::String::New(connection->getVersion().c_str()));
}
@ -635,10 +661,10 @@ static void RunShell (v8::Handle<v8::Context> context) {
V8LineEditor* console = new V8LineEditor(context, ".avocsh");
console->open();
console->open(!noAutoComplete);
while (true) {
while (!V8::IdleNotification()) {
while (! v8::V8::IdleNotification()) {
}
char* input = console->prompt("avocsh> ");
@ -663,12 +689,19 @@ static void RunShell (v8::Handle<v8::Context> context) {
console->addHistory(input);
HandleScope scope;
v8::HandleScope scope;
v8::TryCatch tryCatch;
init_pager();
TRI_ExecuteStringVocBase(context, String::New(input), name, true, true);
end_pager();
TRI_ExecuteStringVocBase(context, v8::String::New(input), name, true);
TRI_FreeString(input);
if (tryCatch.HasCaught()) {
cout << TRI_StringifyV8Exception(&tryCatch);
}
end_pager();
}
console->close();
@ -696,21 +729,37 @@ static char DEF_BRIGHT[5] = "\x1b[1m";
static char DEF_RESET[5] = "\x1b[0m";
static void addColors (v8::Handle<v8::Context> context) {
context->Global()->Set(v8::String::New("COLOR_RED"), v8::String::New(DEF_RED, 5));
context->Global()->Set(v8::String::New("COLOR_BOLD_RED"), v8::String::New(DEF_BOLD_RED, 8));
context->Global()->Set(v8::String::New("COLOR_GREEN"), v8::String::New(DEF_GREEN, 5));
context->Global()->Set(v8::String::New("COLOR_BOLD_GREEN"), v8::String::New(DEF_BOLD_GREEN, 8));
context->Global()->Set(v8::String::New("COLOR_BLUE"), v8::String::New(DEF_BLUE, 5));
context->Global()->Set(v8::String::New("COLOR_BOLD_BLUE"), v8::String::New(DEF_BOLD_BLUE, 8));
context->Global()->Set(v8::String::New("COLOR_WHITE"), v8::String::New(DEF_WHITE, 5));
context->Global()->Set(v8::String::New("COLOR_YELLOW"), v8::String::New(DEF_YELLOW, 5));
context->Global()->Set(v8::String::New("COLOR_BOLD_WHITE"), v8::String::New(DEF_BOLD_WHITE, 7));
context->Global()->Set(v8::String::New("COLOR_BLACK"), v8::String::New(DEF_BLACK, 5));
context->Global()->Set(v8::String::New("COLOR_BOLD_BLACK"), v8::String::New(DEF_BOLD_BLACK, 8));
context->Global()->Set(v8::String::New("COLOR_BLINK"), v8::String::New(DEF_BLINK, 4));
context->Global()->Set(v8::String::New("COLOR_BRIGHT"), v8::String::New(DEF_BRIGHT, 4));
context->Global()->Set(v8::String::New("COLOR_OUTPUT"), v8::String::New(DEF_BRIGHT, 4));
context->Global()->Set(v8::String::New("COLOR_OUTPUT_RESET"), v8::String::New(DEF_RESET, 4));
context->Global()->Set(v8::String::New("COLOR_RED"), v8::String::New(DEF_RED, 5),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BOLD_RED"), v8::String::New(DEF_BOLD_RED, 8),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_GREEN"), v8::String::New(DEF_GREEN, 5),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BOLD_GREEN"), v8::String::New(DEF_BOLD_GREEN, 8),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BLUE"), v8::String::New(DEF_BLUE, 5),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BOLD_BLUE"), v8::String::New(DEF_BOLD_BLUE, 8),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_WHITE"), v8::String::New(DEF_WHITE, 5),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_YELLOW"), v8::String::New(DEF_YELLOW, 5),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BOLD_WHITE"), v8::String::New(DEF_BOLD_WHITE, 7),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BLACK"), v8::String::New(DEF_BLACK, 5),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BOLD_BLACK"), v8::String::New(DEF_BOLD_BLACK, 8),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BLINK"), v8::String::New(DEF_BLINK, 4),
v8::ReadOnly);
context->Global()->Set(v8::String::New("COLOR_BRIGHT"), v8::String::New(DEF_BRIGHT, 4),
v8::ReadOnly);
if (!noColors) {
context->Global()->Set(v8::String::New("COLOR_OUTPUT"), v8::String::New(DEF_BRIGHT, 4));
}
context->Global()->Set(v8::String::New("COLOR_OUTPUT_RESET"), v8::String::New(DEF_RESET, 4),
v8::ReadOnly);
}
////////////////////////////////////////////////////////////////////////////////
@ -755,8 +804,8 @@ int main (int argc, char* argv[]) {
context->Enter();
// add function SYS_OUTPUT to use pager
context->Global()->Set(v8::String::New("SYS_OUTPUT"),
v8::FunctionTemplate::New(Tri_Output)->GetFunction(),
context->Global()->Set(v8::String::New("TRI_SYS_OUTPUT"),
v8::FunctionTemplate::New(Js_Pager_Output)->GetFunction(),
v8::ReadOnly);
@ -782,19 +831,20 @@ int main (int argc, char* argv[]) {
// .............................................................................
// define AvocadoConnection class
// .............................................................................
v8::Handle<v8::FunctionTemplate> connection_templ = FunctionTemplate::New();
connection_templ->SetClassName(String::New("AvocadoConnection"));
v8::Handle<v8::FunctionTemplate> connection_templ = v8::FunctionTemplate::New();
connection_templ->SetClassName(v8::String::New("AvocadoConnection"));
v8::Handle<v8::ObjectTemplate> connection_proto = connection_templ->PrototypeTemplate();
connection_proto->Set("get", FunctionTemplate::New(ClientConnection_httpGet));
connection_proto->Set("post", FunctionTemplate::New(ClientConnection_httpPost));
connection_proto->Set("delete", FunctionTemplate::New(ClientConnection_httpDelete));
connection_proto->Set("put", FunctionTemplate::New(ClientConnection_httpPut));
connection_proto->Set("lastHttpReturnCode", FunctionTemplate::New(ClientConnection_lastHttpReturnCode));
connection_proto->Set("lastErrorMessage", FunctionTemplate::New(ClientConnection_lastErrorMessage));
connection_proto->Set("isConnected", FunctionTemplate::New(ClientConnection_isConnected));
connection_proto->Set("toString", FunctionTemplate::New(ClientConnection_toString));
connection_proto->Set("get", v8::FunctionTemplate::New(ClientConnection_httpGet));
connection_proto->Set("post", v8::FunctionTemplate::New(ClientConnection_httpPost));
connection_proto->Set("delete", v8::FunctionTemplate::New(ClientConnection_httpDelete));
connection_proto->Set("put", v8::FunctionTemplate::New(ClientConnection_httpPut));
connection_proto->Set("lastHttpReturnCode", v8::FunctionTemplate::New(ClientConnection_lastHttpReturnCode));
connection_proto->Set("lastErrorMessage", v8::FunctionTemplate::New(ClientConnection_lastErrorMessage));
connection_proto->Set("isConnected", v8::FunctionTemplate::New(ClientConnection_isConnected));
connection_proto->Set("toString", v8::FunctionTemplate::New(ClientConnection_toString));
connection_proto->Set("getVersion", v8::FunctionTemplate::New(ClientConnection_getVersion));
connection_proto->SetCallAsFunctionHandler(ClientConnection_ConstructorCallback);
Handle<ObjectTemplate> connection_inst = connection_templ->InstanceTemplate();
v8::Handle<v8::ObjectTemplate> connection_inst = connection_templ->InstanceTemplate();
connection_inst->SetInternalFieldCount(2);
context->Global()->Set(v8::String::New("AvocadoConnection"), connection_proto->NewInstance());
ConnectionTempl = v8::Persistent<v8::ObjectTemplate>::New(connection_inst);
@ -810,18 +860,18 @@ int main (int argc, char* argv[]) {
// http://www.network-science.de/ascii/ Font: ogre
if (noColors) {
printf(" " " _ \n");
printf(" __ ___ _____ ___ " "___| |__ \n");
printf(" / _` \\ \\ / / _ \\ / __" "/ __| '_ \\ \n");
printf("| (_| |\\ V / (_) | (__" "\\__ \\ | | | \n");
printf(" \\__,_| \\_/ \\___/ \\___" "|___/_| |_| \n\n");
printf(" " " _ \n");
printf(" __ ___ _____ ___ " "___| |__ \n");
printf(" / _` \\ \\ / / _ \\ / __" "/ __| '_ \\ \n");
printf(" | (_| |\\ V / (_) | (__" "\\__ \\ | | | \n");
printf(" \\__,_| \\_/ \\___/ \\___" "|___/_| |_| \n\n");
}
else {
printf( " " "\x1b[31m _ \x1b[0m\n");
printf("\x1b[32m __ ___ _____ ___ " "\x1b[31m___| |__ \x1b[0m\n");
printf("\x1b[32m / _` \\ \\ / / _ \\ / __" "\x1b[31m/ __| '_ \\ \x1b[0m\n");
printf("\x1b[32m| (_| |\\ V / (_) | (__" "\x1b[31m\\__ \\ | | | \x1b[0m\n");
printf("\x1b[32m \\__,_| \\_/ \\___/ \\___" "\x1b[31m|___/_| |_| \x1b[0m\n\n");
printf( " " "\x1b[31m _ \x1b[0m\n");
printf("\x1b[32m __ ___ _____ ___ " "\x1b[31m___| |__ \x1b[0m\n");
printf("\x1b[32m / _` \\ \\ / / _ \\ / __" "\x1b[31m/ __| '_ \\ \x1b[0m\n");
printf("\x1b[32m | (_| |\\ V / (_) | (__" "\x1b[31m\\__ \\ | | | \x1b[0m\n");
printf("\x1b[32m \\__,_| \\_/ \\___/ \\___" "\x1b[31m|___/_| |_| \x1b[0m\n\n");
}
printf("Welcome to avocsh %s. Copyright (c) 2012 triAGENS GmbH.\n", TRIAGENS_VERSION);
@ -846,7 +896,9 @@ int main (int argc, char* argv[]) {
}
// add the client connection to the context:
context->Global()->Set(v8::String::New("avocado"), wrapV8ClientConnection(clientConnection));
context->Global()->Set(v8::String::New("avocado"),
wrapV8ClientConnection(clientConnection),
v8::ReadOnly);
if (prettyPrint) {
printf("Pretty print values.\n");
@ -856,10 +908,7 @@ int main (int argc, char* argv[]) {
context->Global()->Set(v8::String::New("PRETTY_PRINT"), v8::Boolean::New(prettyPrint));
// add colors for print.js
if (!noColors) {
addColors(context);
}
addColors(context);
// load java script from js/bootstrap/*.h files
if (StartupPath.empty()) {

View File

@ -62,9 +62,7 @@ static void InitCollection (TRI_collection_t* collection,
collection->_cid = info->_cid;
TRI_CopyString(collection->_name, info->_name, sizeof(collection->_name));
collection->_maximalSize = info->_maximalSize;
collection->_syncAfterObjects = info->_syncAfterObjects;
collection->_syncAfterBytes = info->_syncAfterBytes;
collection->_syncAfterTime = info->_syncAfterTime;
collection->_waitForSync = info->_waitForSync;
collection->_directory = directory;
@ -318,9 +316,7 @@ void TRI_InitParameterCollection (TRI_col_parameter_t* parameter,
parameter->_type = TRI_COL_TYPE_SIMPLE_DOCUMENT;
parameter->_syncAfterObjects = 1;
parameter->_syncAfterBytes = 0;
parameter->_syncAfterTime = 0.0;
parameter->_waitForSync = true;
parameter->_maximalSize = (maximalSize / PageSize) * PageSize;
@ -511,14 +507,8 @@ bool TRI_LoadParameterInfo (char const* path,
else if (TRI_EqualString(key->_value._string.data, "maximalSize")) {
parameter->_maximalSize = value->_value._number;
}
else if (TRI_EqualString(key->_value._string.data, "syncAfterObjects")) {
parameter->_syncAfterObjects = value->_value._number;
}
else if (TRI_EqualString(key->_value._string.data, "syncAfterBytes")) {
parameter->_syncAfterBytes = value->_value._number;
}
else if (TRI_EqualString(key->_value._string.data, "syncAfterTime")) {
parameter->_syncAfterTime = value->_value._number;
else if (TRI_EqualString(key->_value._string.data, "waitForSync")) {
parameter->_waitForSync = value->_value._boolean;
}
}
else if (key->_type == TRI_JSON_STRING && value->_type == TRI_JSON_STRING) {
@ -551,9 +541,7 @@ bool TRI_SaveParameterInfo (char const* path,
TRI_Insert2ArrayJson(json, "cid", TRI_CreateNumberJson(info->_cid));
TRI_Insert2ArrayJson(json, "name", TRI_CreateStringCopyJson(info->_name));
TRI_Insert2ArrayJson(json, "maximalSize", TRI_CreateNumberJson(info->_maximalSize));
TRI_Insert2ArrayJson(json, "syncAfterObjects", TRI_CreateNumberJson(info->_syncAfterObjects));
TRI_Insert2ArrayJson(json, "syncAfterBytes", TRI_CreateNumberJson(info->_syncAfterBytes));
TRI_Insert2ArrayJson(json, "syncAfterTime", TRI_CreateNumberJson(info->_syncAfterTime));
TRI_Insert2ArrayJson(json, "waitForSync", TRI_CreateBooleanJson(info->_waitForSync));
// save json info to file
filename = TRI_Concatenate2File(path, TRI_COL_PARAMETER_FILE);
@ -583,9 +571,7 @@ bool TRI_UpdateParameterInfoCollection (TRI_collection_t* collection) {
parameter._cid = collection->_cid;
TRI_CopyString(parameter._name, collection->_name, sizeof(parameter._name));
parameter._maximalSize = collection->_maximalSize;
parameter._syncAfterObjects = collection->_syncAfterObjects;
parameter._syncAfterBytes = collection->_syncAfterBytes;
parameter._syncAfterTime = collection->_syncAfterTime;
parameter._waitForSync = collection->_waitForSync;
parameter._size = sizeof(TRI_col_info_t);
return TRI_SaveParameterInfo(collection->_directory, &parameter);

View File

@ -161,9 +161,7 @@ typedef struct TRI_col_parameter_s {
char _name[TRI_COL_PATH_LENGTH]; // name of the collection
TRI_voc_size_t _maximalSize; // maximal size of memory mapped file
TRI_voc_size_t _syncAfterObjects; // 0 = ignore, 1 = always, n = at most n non-synced
TRI_voc_size_t _syncAfterBytes; // 0 = ignore, n = at most n bytes
TRI_voc_ms_t _syncAfterTime; // 0 = ignore, n = at most n milli-seconds
bool _waitForSync; // if true, wait for msync
}
TRI_col_parameter_t;
@ -178,9 +176,7 @@ typedef struct TRI_col_info_s {
char _name[TRI_COL_PATH_LENGTH]; // name of the collection
TRI_voc_size_t _maximalSize; // maximal size of memory mapped file
TRI_voc_size_t _syncAfterObjects; // 0 = ignore, 1 = always, n = at most n non-synced
TRI_voc_size_t _syncAfterBytes; // 0 = ignore, n = at most n bytes
double _syncAfterTime; // 0 = ignore, n = at most n seconds
TRI_voc_size_t _waitForSync; // if true, wait for msync
TRI_voc_size_t _size; // total size of the parameter info block
}
@ -201,9 +197,7 @@ typedef struct TRI_collection_s {
char _name[TRI_COL_PATH_LENGTH]; // name of the collection
TRI_voc_size_t _maximalSize; // maximal size of memory mapped file
TRI_voc_size_t _syncAfterObjects; // 0 = ignore, 1 = always, n = at most n non-synced
TRI_voc_size_t _syncAfterBytes; // 0 = ignore, n = at most n bytes
double _syncAfterTime; // 0 = ignore, n = at most n seconds
TRI_voc_size_t _waitForSync; // if true, wait for msync
char* _directory; // directory of the collection

View File

@ -66,9 +66,8 @@ static int const COMPACTOR_INTERVAL = 5 * 1000 * 1000;
////////////////////////////////////////////////////////////////////////////////
/// @brief selects a journal, possibly waits until a journal appears
///
/// Note that the function is garbs a lock. We have to release this
/// lock, in order to allow the gc to start when waiting for a journal
/// to appear.
/// Note that the function grabs a lock. We have to release this lock, in order
/// to allow the gc to start when waiting for a journal to appear.
////////////////////////////////////////////////////////////////////////////////
static TRI_datafile_t* SelectCompactor (TRI_sim_collection_t* collection,

View File

@ -73,6 +73,22 @@ static bool HasNextQueryCursor (const TRI_query_cursor_t* const cursor) {
return cursor->_currentRow < cursor->_length;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns if the count flag is set for the cursor
////////////////////////////////////////////////////////////////////////////////
static bool HasCountQueryCursor (const TRI_query_cursor_t* const cursor) {
return cursor->_hasCount;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the maximum number of results per transfer
////////////////////////////////////////////////////////////////////////////////
static uint32_t GetMaxQueryCursor (const TRI_query_cursor_t* const cursor) {
return cursor->_maxResults;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief frees a cursor
////////////////////////////////////////////////////////////////////////////////
@ -99,7 +115,9 @@ static void FreeQueryCursor (TRI_query_cursor_t* cursor) {
////////////////////////////////////////////////////////////////////////////////
TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const instance,
const TRI_select_result_t* const selectResult) {
const TRI_select_result_t* const selectResult,
const bool doCount,
const uint32_t maxResults) {
TRI_query_cursor_t* cursor;
cursor = TRI_Allocate(sizeof(TRI_query_cursor_t));
@ -116,6 +134,8 @@ TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const instance,
return NULL;
}
cursor->_hasCount = doCount;
cursor->_maxResults = maxResults;
cursor->_deleted = false;
cursor->_vocbase = instance->_template->_vocbase;
@ -133,6 +153,8 @@ TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const instance,
}
cursor->next = NextQueryCursor;
cursor->hasNext = HasNextQueryCursor;
cursor->hasCount = HasCountQueryCursor;
cursor->getMax = GetMaxQueryCursor;
cursor->free = FreeQueryCursor;
TRI_InitMutex(&cursor->_lock);

View File

@ -50,6 +50,8 @@ typedef struct TRI_query_cursor_s {
TRI_vocbase_t* _vocbase;
TRI_shadow_t* _shadow;
char* _functionCode;
bool _hasCount;
uint32_t _maxResults;
TRI_vector_pointer_t _containers;
TRI_mutex_t _lock;
bool _deleted;
@ -61,6 +63,8 @@ typedef struct TRI_query_cursor_s {
void (*free) (struct TRI_query_cursor_s*);
TRI_rc_result_t* (*next)(struct TRI_query_cursor_s* const);
bool (*hasNext)(const struct TRI_query_cursor_s* const);
bool (*hasCount)(const struct TRI_query_cursor_s* const);
uint32_t (*getMax)(const struct TRI_query_cursor_s* const);
}
TRI_query_cursor_t;
@ -70,7 +74,9 @@ TRI_query_cursor_t;
////////////////////////////////////////////////////////////////////////////////
TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const,
const TRI_select_result_t* const);
const TRI_select_result_t* const,
const bool,
const uint32_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief Free a cursor based on its shadow

View File

@ -149,7 +149,9 @@ static bool AddCollectionsBarrierQueryInstance (TRI_query_instance_t* const inst
/// @brief executes a query
////////////////////////////////////////////////////////////////////////////////
TRI_query_cursor_t* TRI_ExecuteQueryInstance (TRI_query_instance_t* const instance) {
TRI_query_cursor_t* TRI_ExecuteQueryInstance (TRI_query_instance_t* const instance,
const bool doCount,
const uint32_t max) {
TRI_select_result_t* selectResult;
TRI_query_cursor_t* cursor;
TRI_voc_ssize_t noLimit = (TRI_voc_ssize_t) INT32_MAX;
@ -161,7 +163,7 @@ TRI_query_cursor_t* TRI_ExecuteQueryInstance (TRI_query_instance_t* const instan
return NULL;
}
cursor = TRI_CreateQueryCursor(instance, selectResult);
cursor = TRI_CreateQueryCursor(instance, selectResult, doCount, max);
if (!cursor) {
selectResult->free(selectResult);
return NULL;

View File

@ -556,7 +556,9 @@ extern "C" {
/// @brief executes a query
////////////////////////////////////////////////////////////////////////////////
TRI_query_cursor_t* TRI_ExecuteQueryInstance (TRI_query_instance_t* const);
TRI_query_cursor_t* TRI_ExecuteQueryInstance (TRI_query_instance_t* const,
const bool,
const uint32_t);
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -140,12 +140,11 @@ static void WaitSync (TRI_sim_collection_t* collection,
TRI_datafile_t* journal,
char const* position) {
TRI_collection_t* base;
bool done;
base = &collection->base.base;
// no condition at all
if (0 == base->_syncAfterObjects && 0 == base->_syncAfterBytes && 0 == base->_syncAfterTime) {
if (! base->_waitForSync) {
return;
}
@ -153,7 +152,6 @@ static void WaitSync (TRI_sim_collection_t* collection,
// wait until the sync condition is fullfilled
while (true) {
done = true;
// check for error
if (journal->_state == TRI_DF_STATE_WRITE_ERROR) {
@ -161,37 +159,7 @@ static void WaitSync (TRI_sim_collection_t* collection,
}
// always sync
if (1 == base->_syncAfterObjects) {
if (journal->_synced < position) {
done = false;
}
}
// at most that many outstanding objects
else if (1 < base->_syncAfterObjects) {
if (journal->_nWritten - journal->_nSynced < base->_syncAfterObjects) {
done = false;
}
}
// at most that many outstanding bytes
if (0 < base->_syncAfterBytes) {
if (journal->_written - journal->_synced < base->_syncAfterBytes) {
done = false;
}
}
// at most that many seconds
if (0 < base->_syncAfterTime && journal->_synced < journal->_written) {
double t = TRI_microtime();
if (journal->_lastSynced < t - base->_syncAfterTime) {
done = false;
}
}
// stop waiting of we reached our limits
if (done) {
if (position <= journal->_synced) {
break;
}

View File

@ -796,7 +796,7 @@ bool TRI_ManifestCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t co
TRI_InitParameterCollection(&parameter, vc->_name, DEFAULT_MAXIMAL_SIZE);
parameter._type = type;
parameter._syncAfterTime = 1;
parameter._waitForSync = false;
sim = TRI_CreateSimCollection(vocbase->_path, &parameter);

View File

@ -34,8 +34,22 @@
// --SECTION-- global variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief change internal.output to shell output
////////////////////////////////////////////////////////////////////////////////
ModuleCache["/internal"].exports.output = TRI_SYS_OUTPUT;
////////////////////////////////////////////////////////////////////////////////
/// @brief default collection for saving queries
////////////////////////////////////////////////////////////////////////////////
var DEFAULT_QUERY_COLLECTION = "query";
////////////////////////////////////////////////////////////////////////////////
/// @brief help texts
////////////////////////////////////////////////////////////////////////////////
var HELP = "";
var helpQueries = "";
var helpAvocadoDatabase = "";
@ -191,18 +205,14 @@ function start_color_print (color) {
////////////////////////////////////////////////////////////////////////////////
function getHeadline (text) {
var x = parseInt((78 - text.length) / 2);
var x = parseInt(Math.abs(78 - text.length) / 2);
var p = "";
for (var i = 0; i < x; ++i) {
p += "-";
}
if ( typeof(COLOR_BRIGHT) != "undefined" ) {
return COLOR_BRIGHT + p + " " + text + " " + p + COLOR_OUTPUT_RESET + "\n";
}
return p + " " + text + " " + p + "\n";
return "\n" + p + " " + text + " " + p + "\n";
}
////////////////////////////////////////////////////////////////////////////////
@ -229,7 +239,7 @@ function help () {
////////////////////////////////////////////////////////////////////////////////
ModuleCache["/internal"].exports.log = function(level, msg) {
internal.output(msg, "\n");
internal.output(level, ": ", msg, "\n");
}
// -----------------------------------------------------------------------------
@ -892,7 +902,7 @@ AvocadoDatabase.prototype._collection = function (id) {
/// @brief factory method to create a new query template
////////////////////////////////////////////////////////////////////////////////
AvocadoDatabase.prototype.createQueryTemplate = function (queryData) {
AvocadoDatabase.prototype._createQueryTemplate = function (queryData) {
var qt = new AvocadoQueryTemplate(this, queryData);
if (qt.save()) {
return qt;
@ -901,7 +911,7 @@ AvocadoDatabase.prototype.createQueryTemplate = function (queryData) {
return undefined;
}
AvocadoDatabase.prototype.getQueryTemplate = function (id) {
AvocadoDatabase.prototype._getQueryTemplate = function (id) {
var qt = new AvocadoQueryTemplate(this, {"_id" : id});
if (qt.load()) {
return qt;
@ -914,7 +924,7 @@ AvocadoDatabase.prototype.getQueryTemplate = function (id) {
/// @brief factory method to create a new query instance
////////////////////////////////////////////////////////////////////////////////
AvocadoDatabase.prototype.createQueryInstance = function (queryData) {
AvocadoDatabase.prototype._createQueryInstance = function (queryData) {
return new AvocadoQueryInstance(this, queryData);
}
@ -960,13 +970,13 @@ getHeadline("Help") +
helpQueries =
getHeadline("Simple queries help") +
'Create query template: ' + "\n" +
' > qt1 = db.createQueryTemplate("select ..."); simple query ' + "\n" +
' > qt2 = db.createQueryTemplate( complex query ' + "\n" +
' > qt1 = db._createQueryTemplate("select ..."); simple query ' + "\n" +
' > qt2 = db._createQueryTemplate( complex query ' + "\n" +
' {query:"select...", ' + "\n" +
' name:"qname", ' + "\n" +
' collection:"q" ' + "\n" +
' ... } ' + "\n" +
' > qt3 = db.getQueryTemplate("4334:2334"); query by id ' + "\n" +
' > qt3 = db._getQueryTemplate("4334:2334"); query by id ' + "\n" +
' > qt1.update("select ..."); update ' + "\n" +
' > qt1.delete("4334:2334"); delete ' + "\n" +
'Create query instance: ' + "\n" +
@ -1039,7 +1049,7 @@ helpAvocadoQueryInstance =
getHeadline("AvocadoQueryInstance help") +
'AvocadoQueryInstance constructor: ' + "\n" +
' > qi1 = qt1.getInstance(); ' + "\n" +
' > qi2 = db.createQueryInstance("select ...."); ' + "\n" +
' > qi2 = db._createQueryInstance("select ...."); ' + "\n" +
'Functions: ' + "\n" +
' bind(<key>, <value>); bind vars ' + "\n" +
' setCount(true); ' + "\n" +
@ -1054,7 +1064,7 @@ getHeadline("AvocadoQueryInstance help") +
' maxResults maximum number of results ' + "\n" +
' query the query string ' + "\n" +
'Example: ' + "\n" +
' > qi2 = db.createQueryInstance("select a from colA a ' + "\n" +
' > qi2 = db._createQueryInstance("select a from colA a ' + "\n" +
' where a.x = @a@ and a.y = @b@"); ' + "\n" +
' > qi2.bind("a", "hello"); ' + "\n" +
' > qi2.bind("b", "world"); ' + "\n" +
@ -1063,8 +1073,8 @@ getHeadline("AvocadoQueryInstance help") +
helpAvocadoQueryTemplate =
getHeadline("AvocadoQueryTemplate help") +
'AvocadoQueryTemplate constructor: ' + "\n" +
' > qt1 = db.createQueryTemplate("select ..."); simple query ' + "\n" +
' > qt2 = db.createQueryTemplate( complex query ' + "\n" +
' > qt1 = db._createQueryTemplate("select ..."); simple query ' + "\n" +
' > qt2 = db._createQueryTemplate( complex query ' + "\n" +
' {query:"select...", ' + "\n" +
' name:"qname", ' + "\n" +
' collection:"q" ' + "\n" +
@ -1080,7 +1090,7 @@ getHeadline("AvocadoQueryTemplate help") +
' _id template id ' + "\n" +
' name collection name ' + "\n" +
'Example: ' + "\n" +
' > qt1 = db.getQueryTemplate("4334:2334"); ' + "\n" +
' > qt1 = db._getQueryTemplate("4334:2334"); ' + "\n" +
' > qt1.update("select a from collA a"); ' + "\n" +
' > qi1 = qt1.getInstance(); ' + "\n" +
' > qt1.delete("4334:2334"); ';

View File

@ -35,8 +35,22 @@ static string JS_client_client =
"// --SECTION-- global variables\n"
"// -----------------------------------------------------------------------------\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief change internal.output to shell output\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"ModuleCache[\"/internal\"].exports.output = TRI_SYS_OUTPUT;\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief default collection for saving queries\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"var DEFAULT_QUERY_COLLECTION = \"query\";\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief help texts\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"var HELP = \"\";\n"
"var helpQueries = \"\";\n"
"var helpAvocadoDatabase = \"\";\n"
@ -192,18 +206,14 @@ static string JS_client_client =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function getHeadline (text) {\n"
" var x = parseInt((78 - text.length) / 2);\n"
" var x = parseInt(Math.abs(78 - text.length) / 2);\n"
" \n"
" var p = \"\";\n"
" for (var i = 0; i < x; ++i) {\n"
" p += \"-\";\n"
" }\n"
" \n"
" if ( typeof(COLOR_BRIGHT) != \"undefined\" ) {\n"
" return COLOR_BRIGHT + p + \" \" + text + \" \" + p + COLOR_OUTPUT_RESET + \"\\n\";\n"
" }\n"
"\n"
" return p + \" \" + text + \" \" + p + \"\\n\";\n"
" return \"\\n\" + p + \" \" + text + \" \" + p + \"\\n\";\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
@ -230,7 +240,7 @@ static string JS_client_client =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"ModuleCache[\"/internal\"].exports.log = function(level, msg) {\n"
" internal.output(msg, \"\\n\");\n"
" internal.output(level, \": \", msg, \"\\n\");\n"
"}\n"
"\n"
"// -----------------------------------------------------------------------------\n"
@ -893,7 +903,7 @@ static string JS_client_client =
"/// @brief factory method to create a new query template\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoDatabase.prototype.createQueryTemplate = function (queryData) { \n"
"AvocadoDatabase.prototype._createQueryTemplate = function (queryData) { \n"
" var qt = new AvocadoQueryTemplate(this, queryData);\n"
" if (qt.save()) {\n"
" return qt;\n"
@ -902,7 +912,7 @@ static string JS_client_client =
" return undefined;\n"
"}\n"
"\n"
"AvocadoDatabase.prototype.getQueryTemplate = function (id) { \n"
"AvocadoDatabase.prototype._getQueryTemplate = function (id) { \n"
" var qt = new AvocadoQueryTemplate(this, {\"_id\" : id});\n"
" if (qt.load()) {\n"
" return qt;\n"
@ -915,7 +925,7 @@ static string JS_client_client =
"/// @brief factory method to create a new query instance\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoDatabase.prototype.createQueryInstance = function (queryData) { \n"
"AvocadoDatabase.prototype._createQueryInstance = function (queryData) { \n"
" return new AvocadoQueryInstance(this, queryData);\n"
"}\n"
"\n"
@ -961,13 +971,13 @@ static string JS_client_client =
"helpQueries = \n"
"getHeadline(\"Simple queries help\") +\n"
"'Create query template: ' + \"\\n\" +\n"
"' > qt1 = db.createQueryTemplate(\"select ...\"); simple query ' + \"\\n\" +\n"
"' > qt2 = db.createQueryTemplate( complex query ' + \"\\n\" +\n"
"' > qt1 = db._createQueryTemplate(\"select ...\"); simple query ' + \"\\n\" +\n"
"' > qt2 = db._createQueryTemplate( complex query ' + \"\\n\" +\n"
"' {query:\"select...\", ' + \"\\n\" +\n"
"' name:\"qname\", ' + \"\\n\" +\n"
"' collection:\"q\" ' + \"\\n\" +\n"
"' ... } ' + \"\\n\" +\n"
"' > qt3 = db.getQueryTemplate(\"4334:2334\"); query by id ' + \"\\n\" +\n"
"' > qt3 = db._getQueryTemplate(\"4334:2334\"); query by id ' + \"\\n\" +\n"
"' > qt1.update(\"select ...\"); update ' + \"\\n\" +\n"
"' > qt1.delete(\"4334:2334\"); delete ' + \"\\n\" +\n"
"'Create query instance: ' + \"\\n\" +\n"
@ -1040,7 +1050,7 @@ static string JS_client_client =
"getHeadline(\"AvocadoQueryInstance help\") +\n"
"'AvocadoQueryInstance constructor: ' + \"\\n\" +\n"
"' > qi1 = qt1.getInstance(); ' + \"\\n\" +\n"
"' > qi2 = db.createQueryInstance(\"select ....\"); ' + \"\\n\" +\n"
"' > qi2 = db._createQueryInstance(\"select ....\"); ' + \"\\n\" +\n"
"'Functions: ' + \"\\n\" +\n"
"' bind(<key>, <value>); bind vars ' + \"\\n\" +\n"
"' setCount(true); ' + \"\\n\" +\n"
@ -1055,7 +1065,7 @@ static string JS_client_client =
"' maxResults maximum number of results ' + \"\\n\" +\n"
"' query the query string ' + \"\\n\" +\n"
"'Example: ' + \"\\n\" +\n"
"' > qi2 = db.createQueryInstance(\"select a from colA a ' + \"\\n\" +\n"
"' > qi2 = db._createQueryInstance(\"select a from colA a ' + \"\\n\" +\n"
"' where a.x = @a@ and a.y = @b@\"); ' + \"\\n\" +\n"
"' > qi2.bind(\"a\", \"hello\"); ' + \"\\n\" +\n"
"' > qi2.bind(\"b\", \"world\"); ' + \"\\n\" +\n"
@ -1064,8 +1074,8 @@ static string JS_client_client =
"helpAvocadoQueryTemplate = \n"
"getHeadline(\"AvocadoQueryTemplate help\") +\n"
"'AvocadoQueryTemplate constructor: ' + \"\\n\" +\n"
"' > qt1 = db.createQueryTemplate(\"select ...\"); simple query ' + \"\\n\" +\n"
"' > qt2 = db.createQueryTemplate( complex query ' + \"\\n\" +\n"
"' > qt1 = db._createQueryTemplate(\"select ...\"); simple query ' + \"\\n\" +\n"
"' > qt2 = db._createQueryTemplate( complex query ' + \"\\n\" +\n"
"' {query:\"select...\", ' + \"\\n\" +\n"
"' name:\"qname\", ' + \"\\n\" +\n"
"' collection:\"q\" ' + \"\\n\" +\n"
@ -1081,7 +1091,7 @@ static string JS_client_client =
"' _id template id ' + \"\\n\" +\n"
"' name collection name ' + \"\\n\" +\n"
"'Example: ' + \"\\n\" +\n"
"' > qt1 = db.getQueryTemplate(\"4334:2334\"); ' + \"\\n\" +\n"
"' > qt1 = db._getQueryTemplate(\"4334:2334\"); ' + \"\\n\" +\n"
"' > qt1.update(\"select a from collA a\"); ' + \"\\n\" +\n"
"' > qi1 = qt1.getInstance(); ' + \"\\n\" +\n"
"' > qt1.delete(\"4334:2334\"); ';\n"

View File

@ -37,6 +37,7 @@ var AvocadoEdgesCollection = internal.AvocadoEdgesCollection;
/// <ol>
/// <li>@ref SimpleQueryDocument "db.@FA{collection}.document(@FA{document-reference})"</li>
/// <li>@ref SimpleQueryAll "db.@FA{collection}.all()"</li>
/// <li>@ref SimpleQuerySelect "db.@FA{collection}.select()"</li>
/// <li>@ref SimpleQueryCount "@FA{query}.count()"</li>
/// </ol>
/// </li>
@ -93,6 +94,10 @@ var AvocadoEdgesCollection = internal.AvocadoEdgesCollection;
/// @copydetails JSF_AvocadoCollection_prototype_all
/// <hr>
///
/// @anchor SimpleQuerySelect
/// @copydetails JSF_AvocadoCollection_prototype_select
/// <hr>
///
/// @anchor SimpleQueryCount
/// @copydetails JSF_SimpleQuery_prototype_count
///
@ -807,6 +812,184 @@ SimpleQueryAll.prototype._PRINT = function () {
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- SELECT QUERY
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup SimpleQuery
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief select query
////////////////////////////////////////////////////////////////////////////////
function SimpleQuerySelect (collection, example) {
this._collection = collection;
this._example = example;
}
SimpleQuerySelect.prototype = new SimpleQuery();
SimpleQuerySelect.prototype.constructor = SimpleQuerySelect;
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a select query for a collection
///
/// @FUN{select()}
///
/// Selects all documents of a collection that match the specified example.
/// The example must be specified as an object, with the object attributes being
/// the search values. Allowed attribute types for searching are numbers,
/// strings, and boolean values.
///
/// You can use @FN{toArray}, @FN{next},
/// @FN{nextRef}, or @FN{hasNext} to access the result. The result can be
/// limited using the @FN{skip} and @FN{limit} operator.
///
/// @EXAMPLES
///
/// Use @FN{toArray} to get all documents at once:
///
/// @verbinclude simple18
///
/// Use @FN{next} to loop over all documents:
///
/// @verbinclude simple19
////////////////////////////////////////////////////////////////////////////////
AvocadoCollection.prototype.select = function (example) {
return new SimpleQuerySelect(this, example);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup SimpleQuery
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief clones a select query
////////////////////////////////////////////////////////////////////////////////
SimpleQuerySelect.prototype.clone = function () {
var query;
query = new SimpleQuerySelect(this._collection, this._example);
query._skip = this._skip;
query._limit = this._limit;
return query;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes a select query
////////////////////////////////////////////////////////////////////////////////
SimpleQuerySelect.prototype.execute = function () {
var documents;
if (this._execution == null) {
if (this._skip == null || this._skip <= 0) {
this._skip = 0;
}
var queryString = "SELECT c FROM `" + this._collection._name + "` c";
if (!(this._example instanceof Object)) {
throw "invalid example specification";
}
var found = false;
for (var i in this._example) {
if (!this._example.hasOwnProperty(i)) {
continue;
}
var typeString = typeof(this._example[i]);
if (typeString !== "number" && typeString !== "string" && typeString !== "boolean") {
throw "invalid example specification for key " + i;
}
if (found) {
queryString += "&& ";
}
else {
queryString += " WHERE ";
found = true;
}
queryString += "c.`" + i + "` == ";
if (typeString == "number") {
queryString += this._example[i];
}
else if (typeString == "string") {
queryString += QuoteJSONString(this._example[i]);
}
else if (typeString == "boolean") {
queryString += this._example[i];
}
}
var result = AQL_PREPARE(db, queryString);
if (result instanceof AvocadoQueryError) {
throw result.message;
}
var cursor = result.execute();
if (cursor instanceof AvocadoQueryError) {
throw cursor.message;
}
var documents = { "count" : cursor.count(), "total" : cursor.count(), "documents": [] };
while (cursor.hasNext()) {
documents.documents.push(cursor.next());
}
cursor.dispose();
this._execution = new SimpleQueryArray(documents.documents);
this._execution._skip = this._skip;
this._execution._limit = this._limit;
this._countQuery = documents.count;
this._countTotal = documents.total;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief print a select query
////////////////////////////////////////////////////////////////////////////////
SimpleQuerySelect.prototype._PRINT = function () {
var text;
text = "SimpleQuerySelect(" + this._collection._name + ")";
if (this._skip != null && this._skip != 0) {
text += ".skip(" + this._skip + ")";
}
if (this._limit != null) {
text += ".limit(" + this._limit + ")";
}
internal.output(text);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- SIMPLE QUERY ARRAY
// -----------------------------------------------------------------------------
@ -1142,7 +1325,7 @@ function SimpleQueryNear (collection, latitiude, longitude, iid) {
}
if (this._index == null) {
throw "an geo-index must be known";
throw "a geo-index must be known";
}
}
@ -1325,7 +1508,7 @@ function SimpleQueryWithin (collection, latitiude, longitude, radius, iid) {
}
if (this._index == null) {
throw "an geo-index must be known";
throw "a geo-index must be known";
}
}
@ -1468,6 +1651,7 @@ exports.AvocadoCollection = AvocadoCollection;
exports.AvocadoEdgesCollection = AvocadoEdgesCollection;
exports.SimpleQuery = SimpleQuery;
exports.SimpleQueryAll = SimpleQueryAll;
exports.SimpleQuerySelect = SimpleQuerySelect;
exports.SimpleQueryArray = SimpleQueryArray;
exports.SimpleQueryGeo = SimpleQueryGeo;
exports.SimpleQueryNear = SimpleQueryNear;

206
js/system/aql-cursor.js Normal file
View File

@ -0,0 +1,206 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief query results cursor actions
///
/// @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 Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- global variables
// -----------------------------------------------------------------------------
var actions = require("actions");
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a result set from a cursor
////////////////////////////////////////////////////////////////////////////////
function getCursorResult(cursor) {
var hasCount = cursor.hasCount();
var lines = cursor.getRows();
var result = {
"result" : lines,
"_id" : cursor.id(),
"hasMore" : cursor.hasNext()
};
if (hasCount) {
result["count"] = cursor.count();
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a cursor and return the first results
////////////////////////////////////////////////////////////////////////////////
function postCursor(req, res) {
if (req.suffix.length != 0) {
actions.actionResultError (req, res, 404, actions.cursorNotModified, "Cursor not created");
return;
}
try {
var json = JSON.parse(req.requestBody);
var queryString;
if (json.qid != undefined) {
var q = db.query.document_wrapped(json.qid);
queryString = q.query;
}
else if (json.query != undefined) {
queryString = json.query;
}
if (queryString == undefined) {
actions.actionResultError (req, res, 404, actions.cursorNotModified, "Missing query identifier");
return;
}
var result;
if (json.bindVars) {
result = AQL_PREPARE(db, queryString, json.bindVars);
}
else {
result = AQL_PREPARE(db, queryString);
}
if (result instanceof AvocadoQueryError) {
actions.actionResultError (req, res, 404, result.code, result.message);
return;
}
var cursor = result.execute((json.count != undefined ? json.count : false), (json.maxResults != undefined ? json.maxResults : 1000));
if (cursor instanceof AvocadoQueryError) {
actionResultError (req, res, 404, result.code, result.message);
return;
}
actions.actionResultOK(req, res, 201, getCursorResult(cursor));
}
catch (e) {
actions.actionResultError (req, res, 404, actions.cursorNotModified, "Cursor not created");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the next results from an existing cursor
////////////////////////////////////////////////////////////////////////////////
function putCursor(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
return;
}
try {
var cursorId = decodeURIComponent(req.suffix[0]);
var cursor = AQL_CURSOR(db, cursorId);
if (!(cursor instanceof AvocadoQueryCursor)) {
throw "cursor not found";
}
actions.actionResultOK(req, res, 200, getCursorResult(cursor));
}
catch (e) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dispose an existing cursor
////////////////////////////////////////////////////////////////////////////////
function deleteCursor(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
return;
}
try {
var cursorId = decodeURIComponent(req.suffix[0]);
var cursor = AQL_CURSOR(db, cursorId);
if (!(cursor instanceof AvocadoQueryCursor)) {
throw "cursor not found";
}
cursor.dispose();
actions.actionResultOK(req, res, 202, { "_id" : cursorId });
}
catch (e) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
}
}
// -----------------------------------------------------------------------------
// --SECTION-- initialiser
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief cursor actions gateway
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_api/cursor",
context : "api",
callback : function (req, res) {
switch (req.requestType) {
case ("POST") :
postCursor(req, res);
break;
case ("PUT") :
putCursor(req, res);
break;
case ("DELETE") :
deleteCursor(req, res);
break;
default:
actions.actionResultUnsupported(req, res);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

46
js/system/aql-query.js Normal file
View File

@ -0,0 +1,46 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief query actions
///
/// @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 Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- global variables
// -----------------------------------------------------------------------------
var actions = require("actions");
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -1,145 +0,0 @@
var actions = require("actions");
function postCursor(req, res) {
if (req.suffix.length != 0) {
actions.actionResultError (req, res, 404, actions.cursorNotModified, "Cursor not created");
return;
}
try {
var json = JSON.parse(req.requestBody);
var queryString;
if (json.qid != undefined) {
var q = db.query.document_wrapped(json.qid);
queryString = q.query;
}
else if (json.query != undefined) {
queryString = json.query;
}
if (queryString == undefined) {
actions.actionResultError (req, res, 404, actions.cursorNotModified, "Missing query identifier");
return;
}
var result;
if (json.bindVars) {
result = AQL_PREPARE(db, queryString, json.bindVars);
}
else {
result = AQL_PREPARE(db, queryString);
}
if (result instanceof AvocadoQueryError) {
actions.actionResultError (req, res, 404, result.code, result.message);
return;
}
var cursor = result.execute();
if (cursor instanceof AvocadoQueryError) {
actionResultError (req, res, 404, result.code, result.message);
return;
}
var maxResults = 1000;
if (json.maxResults && parseInt(json.maxResults) > 0) {
maxResults = parseInt(json.maxResults);
}
var lines = [];
var i = 0;
while (i < maxResults && cursor.hasNext()) {
lines[i++] = cursor.next();
}
var cursorId;
var count = cursor.count();
var hasMore = i < count;
var result = {
"result" : lines,
"_id" : cursorId,
"hasMore" : hasMore
};
if (json.count) {
result["count"] = count;
}
actions.actionResultOK(req, res, 201, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.cursorNotModified, "Cursor not created");
}
}
function putCursor(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
return;
}
try {
var cursorId = decodeURIComponent(req.suffix[0]);
// TODO
var result = {
"result" : [{"test":"protest"}, {"hello":"world"}],
"count" : 2,
"_id" : cursorId,
"hasMore" : false
};
actions.actionResultOK(req, res, 200, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
}
}
function deleteCursor(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
return;
}
try {
var cid = decodeURIComponent(req.suffix[0]);
if(db.cursor.delete(qid)) {
actions.actionResultOK(req, res, 202, {"cid" : cid});
}
else {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
}
}
catch (e) {
actions.actionResultError (req, res, 404, actions.cursorNotFound, "Cursor not found");
}
}
actions.defineHttp({
url : "_api/cursor",
context : "api",
callback : function (req, res) {
switch (req.requestType) {
case ("POST") :
postCursor(req, res);
break;
case ("PUT") :
putCursor(req, res);
break;
case ("DELETE") :
deleteCursor(req, res);
break;
default:
actions.actionResultUnsupported(req, res);
}
}
});

254
js/tests/aql-joins.js Normal file
View File

@ -0,0 +1,254 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, joins
///
/// @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
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function aqlJoinsTestSuite () {
var collection = null;
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
function setUp () {
this.persons = db.UnitTestsPersons;
this.friends = db.UnitTestsFriends;
this.locations = db.UnitTestsLocations;
if (this.persons.count() == 0) {
this.persons.save( { "id" : 1, "name" : "fox" } );
this.persons.save( { "id" : 2, "name" : "brown" } );
this.persons.save( { "id" : 5, "name" : "peter" } );
this.persons.save( { "id" : 6, "name" : "hulk" } );
this.persons.save( { "id" : 9, "name" : "fred" } );
}
if (this.friends.count() == 0) {
this.friends.save( { "person1" : 1, "person2" : 2 } );
this.friends.save( { "person1" : 9, "person2" : 1 } );
this.friends.save( { "person1" : 1, "person2" : 9 } );
this.friends.save( { "person1" : 5, "person2" : 6 } );
this.friends.save( { "person1" : 6, "person2" : 9 } );
}
if (this.locations.count() == 0) {
this.locations.save( { "person" : 1, "x" : 1, "y": 5 } );
this.locations.save( { "person" : 1, "x" : 3, "y": 4 } );
this.locations.save( { "person" : 1, "x" : -2, "y": 3 } );
this.locations.save( { "person" : 2, "x" : 3, "y": -2 } );
this.locations.save( { "person" : 2, "x" : 2, "y": 1 } );
this.locations.save( { "person" : 5, "x" : 4, "y": -1 } );
this.locations.save( { "person" : 5, "x" : 3, "y": -2 } );
this.locations.save( { "person" : 5, "x" : 2, "y": -2 } );
this.locations.save( { "person" : 5, "x" : 5, "y": -5 } );
this.locations.save( { "person" : 5, "x" : 6, "y": -5 } );
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
function tearDown () {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief sanitize a result row, recursively
////////////////////////////////////////////////////////////////////////////////
function sanitizeRow (row) {
var copy;
if (row instanceof Array) {
copy = [ ];
}
else {
copy = { };
}
for (var i in row) {
if (i === "_id" || !row.hasOwnProperty(i)) {
continue;
}
if (row[i] instanceof Array || row[i] instanceof Object) {
copy[i] = this.sanitizeRow(row[i]);
}
else {
copy[i] = row[i];
}
}
return copy;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute a given query
////////////////////////////////////////////////////////////////////////////////
function executeQuery (query) {
var aQuery = AQL_PREPARE(db, query);
assertFalse(aQuery instanceof AvocadoQueryError);
return aQuery.execute();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute a given query and return the results as an array
////////////////////////////////////////////////////////////////////////////////
function getQueryResults (query) {
var aCursor = this.executeQuery(query);
if (aCursor) {
var results = [ ];
while (aCursor.hasNext()) {
results.push(this.sanitizeRow(aCursor.next()));
}
return results;
}
return aCursor;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test inner join results
////////////////////////////////////////////////////////////////////////////////
function testInnerJoin1 () {
var expected = [{ "id" : 1, "name" : "fox"}, { "id" : 1, "name" : "fox"}, { "id" : 1, "name" : "fox"}, { "id" : 2, "name" : "brown"}, { "id" : 2, "name" : "brown"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}];
var result = this.getQueryResults("SELECT p FROM " + this.persons._name + " p INNER JOIN " + this.locations._name + " l ON (p.id == l.person) ORDER BY p.id, l.x, l.y");
assertEqual(10, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test inner join results
////////////////////////////////////////////////////////////////////////////////
function testInnerJoin2 () {
var expected = [{ "p" : { "id" : 1, "name" : "fox"}, "l" : { "person" : 1, "x" : -2, "y" : 3}}, { "p" : { "id" : 1, "name" : "fox"}, "l" : { "person" : 1, "x" : 1, "y" : 5}}, { "p" : { "id" : 1, "name" : "fox"}, "l" : { "person" : 1, "x" : 3, "y" : 4}}, { "p" : { "id" : 2, "name" : "brown"}, "l" : { "person" : 2, "x" : 2, "y" : 1}}, { "p" : { "id" : 2, "name" : "brown"}, "l" : { "person" : 2, "x" : 3, "y" : -2}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 2, "y" : -2}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 3, "y" : -2}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 4, "y" : -1}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 5, "y" : -5}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 6, "y" : -5}}];
var result = this.getQueryResults("SELECT { p : p, l : l } FROM " + this.persons._name + " p INNER JOIN " + this.locations._name + " l ON (p.id == l.person) ORDER BY p.id, l.x, l.y");
assertEqual(10, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test inner join results with limit
////////////////////////////////////////////////////////////////////////////////
function testInnerJoinLimit1 () {
var expected = [{ "id" : 1, "name" : "fox"}, { "id" : 1, "name" : "fox"}, { "id" : 2, "name" : "brown"}];
var result = this.getQueryResults("SELECT p FROM " + this.persons._name + " p INNER JOIN " + this.locations._name + " l ON (p.id == l.person) ORDER BY p.id, l.x, l.y LIMIT 1, 3");
assertEqual(3, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test left join results
////////////////////////////////////////////////////////////////////////////////
function testLeftJoin1 () {
var expected = [{ "id" : 1, "name" : "fox"}, { "id" : 1, "name" : "fox"}, { "id" : 1, "name" : "fox"}, { "id" : 2, "name" : "brown"}, { "id" : 2, "name" : "brown"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}, { "id" : 5, "name" : "peter"}, { "id" : 6, "name" : "hulk"}, { "id" : 9, "name" : "fred"}];
var result = this.getQueryResults("SELECT p FROM " + this.persons._name + " p LEFT JOIN " + this.locations._name + " l ON (p.id == l.person) ORDER BY p.id, l.x, l.y");
assertEqual(12, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test left join results
////////////////////////////////////////////////////////////////////////////////
function testLeftJoin2 () {
var expected = [{ "p" : { "id" : 1, "name" : "fox"}, "l" : { "person" : 1, "x" : -2, "y" : 3}}, { "p" : { "id" : 1, "name" : "fox"}, "l" : { "person" : 1, "x" : 1, "y" : 5}}, { "p" : { "id" : 1, "name" : "fox"}, "l" : { "person" : 1, "x" : 3, "y" : 4}}, { "p" : { "id" : 2, "name" : "brown"}, "l" : { "person" : 2, "x" : 2, "y" : 1}}, { "p" : { "id" : 2, "name" : "brown"}, "l" : { "person" : 2, "x" : 3, "y" : -2}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 2, "y" : -2}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 3, "y" : -2}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 4, "y" : -1}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 5, "y" : -5}}, { "p" : { "id" : 5, "name" : "peter"}, "l" : { "person" : 5, "x" : 6, "y" : -5}}, { "p" : { "id" : 6, "name" : "hulk"}, "l" : null}, { "p" : { "id" : 9, "name" : "fred"}, "l" : null}];
var result = this.getQueryResults("SELECT { p : p, l : l } FROM " + this.persons._name + " p LEFT JOIN " + this.locations._name + " l ON (p.id == l.person) ORDER BY p.id, l.x, l.y");
assertEqual(12, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test list join results
////////////////////////////////////////////////////////////////////////////////
function testListJoin1 () {
var expected = [{ "p" : { "id" : 1, "name" : "fox"}, "l" : [{ "person" : 1, "x" : 1, "y" : 5}, { "person" : 1, "x" : 3, "y" : 4}, { "person" : 1, "x" : -2, "y" : 3}]}, { "p" : { "id" : 2, "name" : "brown"}, "l" : [{ "person" : 2, "x" : 2, "y" : 1}, { "person" : 2, "x" : 3, "y" : -2}]}, { "p" : { "id" : 5, "name" : "peter"}, "l" : [{ "person" : 5, "x" : 5, "y" : -5}, { "person" : 5, "x" : 3, "y" : -2}, { "person" : 5, "x" : 2, "y" : -2}, { "person" : 5, "x" : 6, "y" : -5}, { "person" : 5, "x" : 4, "y" : -1}]}, { "p" : { "id" : 6, "name" : "hulk"}, "l" : [ ]}, { "p" : { "id" : 9, "name" : "fred"}, "l" : [ ]}];
var result = this.getQueryResults("SELECT { p : p, l : l } FROM " + this.persons._name + " p LIST JOIN " + this.locations._name + " l ON (p.id == l.person) ORDER BY p.id, l.x, l.y");
assertEqual(5, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test list join results
////////////////////////////////////////////////////////////////////////////////
function testListJoin2 () {
var expected = [{ "p" : { "id" : 1, "name" : "fox"}, "f" : [{ "person1" : 1, "person2" : 9}, { "person1" : 1, "person2" : 2}]}, { "p" : { "id" : 2, "name" : "brown"}, "f" : [ ]}, { "p" : { "id" : 5, "name" : "peter"}, "f" : [{ "person1" : 5, "person2" : 6}]}, { "p" : { "id" : 6, "name" : "hulk"}, "f" : [{ "person1" : 6, "person2" : 9}]}, { "p" : { "id" : 9, "name" : "fred"}, "f" : [{ "person1" : 9, "person2" : 1}]}];
var result = this.getQueryResults("SELECT { p : p, f : f } FROM " + this.persons._name + " p LIST JOIN " + this.friends._name + " f ON (p.id == f.person1) ORDER BY p.id");
assertEqual(5, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test list join results
////////////////////////////////////////////////////////////////////////////////
function testListJoin3 () {
var expected = [{ "p" : { "id" : 1, "name" : "fox"}, "f" : [{ "person1" : 9, "person2" : 1}, { "person1" : 1, "person2" : 9}, { "person1" : 1, "person2" : 2}]}, { "p" : { "id" : 2, "name" : "brown"}, "f" : [{ "person1" : 1, "person2" : 2}]}, { "p" : { "id" : 5, "name" : "peter"}, "f" : [{ "person1" : 5, "person2" : 6}]}, { "p" : { "id" : 6, "name" : "hulk"}, "f" : [{ "person1" : 6, "person2" : 9}, { "person1" : 5, "person2" : 6}]}, { "p" : { "id" : 9, "name" : "fred"}, "f" : [{ "person1" : 9, "person2" : 1}, { "person1" : 1, "person2" : 9}, { "person1" : 6, "person2" : 9}]}];
var result = this.getQueryResults("SELECT { p : p, f : f } FROM " + this.persons._name + " p LIST JOIN " + this.friends._name + " f ON (p.id == f.person1 || p.id == f.person2) ORDER BY p.id");
assertEqual(5, result.length);
assertEqual(expected, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test self join results
////////////////////////////////////////////////////////////////////////////////
function testSelfJoin () {
var expected = [{ "id" : 1, "name" : "fox"}, { "id" : 2, "name" : "brown"}, { "id" : 5, "name" : "peter"}, { "id" : 6, "name" : "hulk"}, { "id" : 9, "name" : "fred"}];
var result = this.getQueryResults("SELECT p FROM " + this.persons._name + " p INNER JOIN " + this.persons._name + " p2 ON (p.id == p2.id) ORDER BY p.id");
assertEqual(5, result.length);
assertEqual(expected, result);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsUnity.run(aqlJoinsTestSuite);
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

250
js/tests/aql-keywords.js Normal file
View File

@ -0,0 +1,250 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, keywords
///
/// @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
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function aqlKeywordsTestSuite () {
var collection = null;
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
function setUp () {
this.keywords = [ "select", "from", "where", "join", "inner", "left", "right", "on", "limit", "order", "by", "near", "within" ];
this.keywordHash = { };
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
this.keywordHash[this.keywords[i]] = this.keywords[i];
}
this.collection = db.UnitTestsKeywords;
if (this.collection.count() == 0) {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
var k = this.keywords[i];
var row = { };
row[k] = k;
this.collection.save(row);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
function tearDown () {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute a given query
////////////////////////////////////////////////////////////////////////////////
function executeQuery (query, expectError) {
var aQuery = AQL_PREPARE(db, query);
if (expectError) {
assertTrue(aQuery instanceof AvocadoQueryError);
return null;
}
assertFalse(aQuery instanceof AvocadoQueryError);
return aQuery.execute();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute a given query and return the results as an array
////////////////////////////////////////////////////////////////////////////////
function getQueryResults (query, expectError) {
var aCursor = this.executeQuery(query, expectError);
if (aCursor) {
var results = [ ];
while (aCursor.hasNext()) {
results.push(aCursor.next());
}
return results;
}
return aCursor;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in select
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesSelectInvalid () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to fail
this.getQueryResults("SELECT { " + this.keywords[i] + " : null } FROM " + this.collection._name + " c", true);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in select
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesSelectValid1 () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to work
this.getQueryResults("SELECT { \"" + this.keywords[i] + "\" : null } FROM " + this.collection._name + " c", false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in select
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesSelectValid2 () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to work
this.getQueryResults("SELECT { value : \"" + this.keywords[i] + "\" } FROM " + this.collection._name + " c", false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in select
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesSelectValid3 () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to work
var result = this.getQueryResults("SELECT { value : c.`" + this.keywords[i] + "` } FROM " + this.collection._name + " c WHERE c.`" + this.keywords[i] + "` == '" + this.keywords[i] + "'", false);
for (var j in result) {
if (!result.hasOwnProperty(j)) {
continue;
}
assertEqual(this.keywords[i], result[j]["value"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in from alias
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesFromInvalid () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to work
this.getQueryResults("SELECT { } FROM " + this.collection._name + " " + this.keywords[i], true);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in from alias
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesFromValid () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to work
var result = this.getQueryResults("SELECT `" + this.keywords[i] + "` FROM " + this.collection._name + " `" + this.keywords[i] + "`", false);
assertEqual(result.length, this.keywords.length);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in where
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesWhereInvalid () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to work
this.getQueryResults("SELECT { } FROM " + this.collection._name + " c WHERE c." + this.keywords[i] + " == '" + this.keywords[i] + "'", true);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check keyword names in where
////////////////////////////////////////////////////////////////////////////////
function testKeywordNamesWhereValid () {
for (var i in this.keywords) {
if (!this.keywords.hasOwnProperty(i)) {
continue;
}
// this is expected to work
var result = this.getQueryResults("SELECT { \"" + this.keywords[i] + "\" : c.`" + this.keywords[i] + "` } FROM " + this.collection._name + " c WHERE '" + this.keywords[i] + "' == c.`" + this.keywords[i] + "`", false);
for (var j in result) {
if (!result.hasOwnProperty(j)) {
continue;
}
assertEqual(this.keywords[i], result[j][this.keywords[i]]);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsUnity.run(aqlKeywordsTestSuite);
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -61,6 +61,10 @@ function aqlSimpleTestSuite () {
function executeQuery (query) {
var aQuery = AQL_PREPARE(db, query);
if (aQuery instanceof AvocadoQueryError) {
print(query, aQuery.message);
}
assertFalse(aQuery instanceof AvocadoQueryError);
if (aQuery) {
return aQuery.execute();
}
@ -83,29 +87,54 @@ function aqlSimpleTestSuite () {
return aCursor;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief assemble a query string from the parameters given and run the query
////////////////////////////////////////////////////////////////////////////////
function runQuery (select, wheres, limit, order) {
var query = this.assembleQuery(select, wheres, limit, order);
var result = this.getQueryResults(query);
assertFalse(result instanceof AvocadoQueryError);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief assemble a query string from the parameters given
////////////////////////////////////////////////////////////////////////////////
function assembleQuery (value1, value2, limit) {
var query = 'SELECT { } FROM ' + this.collection._name + ' c WHERE ';
var cond = '';
if (value1 !== undefined) {
cond += value1;
}
if (value2 !== undefined) {
if (cond != '') {
cond += ' && ';
function assembleQuery (select, wheres, limit, order) {
var selectClause = select;
var whereClause = "";
if (wheres instanceof Array) {
whereClause = "WHERE ";
var found = false;
for (var i in wheres) {
if (wheres[i] == "" || wheres[i] === undefined || wheres[i] === null || !wheres.hasOwnProperty(i)) {
continue;
}
if (found) {
whereClause += "&& ";
}
found = true;
whereClause += wheres[i] + " ";
}
cond += value2;
}
query += cond;
if (limit !== undefined) {
query += ' LIMIT ' + limit;
var orderClause = "";
if (order != "" && order !== undefined && order !== null) {
orderClause = "ORDER BY " + order + " ";
}
var limitClause = "";
if (limit !== undefined && limit !== null) {
limitClause = "LIMIT " + limit;
}
var query = "SELECT " + selectClause + " FROM " + this.collection._name + " c " +
whereClause + orderClause + limitClause;
return query;
}
@ -114,8 +143,7 @@ function aqlSimpleTestSuite () {
////////////////////////////////////////////////////////////////////////////////
function checkLength (expected, value1, value2, limit) {
var query = this.assembleQuery(value1, value2, limit);
var result = this.getQueryResults(query);
var result = this.runQuery("{ }", new Array(value1, value2), limit);
assertTrue(result instanceof Array);
var actual = result.length;
assertEqual(expected, actual);
@ -505,6 +533,233 @@ function aqlSimpleTestSuite () {
this.checkLength(2,'c.value1 <= 9', 'c.value2 == 8');
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check query result values
////////////////////////////////////////////////////////////////////////////////
function testIdemValues1 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value: c.value1 }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(i, results[j]["value"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check query result values
////////////////////////////////////////////////////////////////////////////////
function testIdemValues2 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value: c.value2 }", new Array("c.value2 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(i, results[j]["value"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check query result values
////////////////////////////////////////////////////////////////////////////////
function testIdemValues3 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: c.value1, value2: c.value2 }", new Array("c.value1 == " + i, "c.value2 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(i, results[j]["value1"]);
assertEqual(i, results[j]["value2"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check query result values
////////////////////////////////////////////////////////////////////////////////
function testIdemValues3 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: c.value1, value2: c.value2 }", new Array("c.value1 == " + i, "c.value2 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(i, results[j]["value1"]);
assertEqual(i, results[j]["value2"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check computed query result values
////////////////////////////////////////////////////////////////////////////////
function testValueTypes1 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: c.value1, value2: c.value1 - 1, value3: c.value1 + 1, value4: null, value5: 'der fux' + 'xx' }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(i, results[j]["value1"]);
assertEqual(i - 1, results[j]["value2"]);
assertEqual(i + 1, results[j]["value3"]);
assertEqual(null, results[j]["value4"]);
assertEqual("der fuxxx", results[j]["value5"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check computed const result values
////////////////////////////////////////////////////////////////////////////////
function testValueTypes2 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: null, value2: null + null, value3: undefined, value4: [], value5: { }, value6: 0, value7: 0.0 }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(null, results[j]["value1"]);
assertEqual(0, results[j]["value2"]);
assertEqual(undefined, results[j]["value3"]);
assertEqual([], results[j]["value4"]);
assertEqual({}, results[j]["value5"]);
assertEqual(0, results[j]["value6"]);
assertEqual(0.0, results[j]["value7"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check numeric result values
////////////////////////////////////////////////////////////////////////////////
function testNumericValues1 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: 0, value2: -0, value3: +0, value4: 0 + 0, value5: 0 - 0, value6: 0 * 0 }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(0, results[j]["value1"]);
assertEqual(0, results[j]["value2"]);
assertEqual(0, results[j]["value3"]);
assertEqual(0, results[j]["value4"]);
assertEqual(0, results[j]["value5"]);
assertEqual(0, results[j]["value6"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check numeric result values
////////////////////////////////////////////////////////////////////////////////
function testNumericValues2 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: 1, value2: -1, value3: +1, value4: -1 + 2, value5: 2 - 1, value6: 1 * 1 }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(1, results[j]["value1"]);
assertEqual(-1, results[j]["value2"]);
assertEqual(1, results[j]["value3"]);
assertEqual(1, results[j]["value4"]);
assertEqual(1, results[j]["value5"]);
assertEqual(1, results[j]["value6"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check numeric result values
////////////////////////////////////////////////////////////////////////////////
function testNumericValues3 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: 1.0, value2: -1.0, value3: +1.0, value4: -1.0 + 2.0, value5: 2.0 - 1.0, value6: 1.0 * 1.0 }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(1, results[j]["value1"]);
assertEqual(-1, results[j]["value2"]);
assertEqual(1, results[j]["value3"]);
assertEqual(1, results[j]["value4"]);
assertEqual(1, results[j]["value5"]);
assertEqual(1, results[j]["value6"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check numeric result values
////////////////////////////////////////////////////////////////////////////////
function testNumericValues4 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: 42.0 - 10, value2: -15 + 37.5, value3: +11.4 - 18.3, value4: -15.3 - 16.5, value5: 14.0 - 18.5, value6: 14.2 * -13.5, value7: -14.05 * -14.15 }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(32, results[j]["value1"]);
assertEqual(22.5, results[j]["value2"]);
assertEqual(-6.9, results[j]["value3"]);
assertEqual(-31.8, results[j]["value4"]);
assertEqual(-4.5, results[j]["value5"]);
assertEqual(-191.7, results[j]["value6"]);
assertEqual(198.8075, results[j]["value7"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check string result values
////////////////////////////////////////////////////////////////////////////////
function testStringValues1 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery("{ value1: '', value2: ' ', value3: ' ', value4: '\\'', value5: '\n', value6: '\\\\ \n\\'\\n\\\\\\'' }", new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual("", results[j]["value1"]);
assertEqual(" ", results[j]["value2"]);
assertEqual(" ", results[j]["value3"]);
assertEqual("\'", results[j]["value4"]);
assertEqual("\n", results[j]["value5"]);
assertEqual("\\ \n\'\n\\\'", results[j]["value6"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check string result values
////////////////////////////////////////////////////////////////////////////////
function testStringValues2 () {
for (var i = 0; i <= 20; i++) {
var results = this.runQuery('{ value1: "", value2: " ", value3: " ", value4: "\\"", value5: "\n", value6: "\\\\ \n\\"\\n\\\\\\"" }', new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual("", results[j]["value1"]);
assertEqual(" ", results[j]["value2"]);
assertEqual(" ", results[j]["value3"]);
assertEqual("\"", results[j]["value4"]);
assertEqual("\n", results[j]["value5"]);
assertEqual("\\ \n\"\n\\\"", results[j]["value6"]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check document result values
////////////////////////////////////////////////////////////////////////////////
function testDocumentValues () {
var expected = { "value1" : { "value11" : { "value111" : "", "value112" : 4 }, "value12" : "bang" }, "value2" : -5, "value3": { } };
for (var i = 0; i <= 20; i++) {
var results = this.runQuery(JSON.stringify(expected), new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(expected, results[j]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check array result values
////////////////////////////////////////////////////////////////////////////////
function testArrayValues () {
var expected = { "v" : [ 1, 2, 5, 99, { }, [ "value1", "value99", [ { "value5" : 5, "null" : null }, [ 1, -99, 0 ], "peng" ], { "x": 9 } ], { "aha" : 55 }, [ 0 ], [ ] ] };
for (var i = 0; i <= 20; i++) {
var results = this.runQuery(JSON.stringify(expected), new Array("c.value1 == " + i));
for (var j = 0; j < results.length; j++) {
assertEqual(expected, results[j]);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////