1
0
Fork 0

doc and minor fixes

This commit is contained in:
Frank Celler 2012-05-02 13:53:30 +02:00
parent b07ea9445e
commit 1fe03b0642
23 changed files with 816 additions and 252 deletions

View File

@ -0,0 +1,25 @@
> curl --data @- -X POST --dump - http://localhost:8529/_api/cursor
{ "query" : "FOR u IN users LIMIT 5 RETURN u", "count" : true, "batchSize" : 2 }
HTTP/1.1 201 Created
content-type: application/json
{
"hasMore": true,
"error": false,
"id": 26011191,
"result": [
{
"n": 0,
"_rev": 25880119,
"_id": "23914039/25880119"
},
{
"n": 1,
"_rev": 25880119,
"_id": "23914039/25880119"
}
],
"code": 201,
"count": 5
}

View File

@ -0,0 +1,24 @@
> curl -X PUT --dump - http://localhost:8529/_api/cursor/26011191
HTTP/1.1 200 OK
content-type: application/json
{
"hasMore": true,
"error": false,
"id": 26011191,
"result": [
{
"n": 2,
"_rev": 25880119,
"_id": "23914039/25880119"
},
{
"n": 3,
"_rev": 25880119,
"_id": "23914039/25880119"
}
],
"code": 200,
"count": 5
}

View File

@ -0,0 +1,18 @@
> curl -X PUT --dump - http://localhost:8529/_api/cursor/26011191
HTTP/1.1 200 OK
content-type: application/json
{
"hasMore": false,
"error": false,
"result": [
{
"n": 4,
"_rev": 25880119,
"_id": "23914039/25880119"
}
],
"code": 200,
"count": 5
}

View File

@ -0,0 +1,11 @@
> curl -X PUT --dump - http://localhost:8529/_api/cursor/26011191
HTTP/1.1 400 Bad Request
content-type: application/json
{
"errorNum": 1600,
"errorMessage": "cursor not found: disposed or unknown cursor",
"error": true,
"code": 400
}

View File

@ -0,0 +1,24 @@
> curl --data @- -X POST --dump - http://localhost:8529/_api/cursor
{ "query" : "FOR u IN users LIMIT 2 RETURN u", "count" : true, "batchSize" : 2 }
HTTP/1.1 201 Created
content-type: application/json
{
"hasMore": false,
"error": false,
"result": [
{
"n": 0,
"_rev": 21030455,
"_id": "19588663/21030455"
},
{
"n": 1,
"_rev": 21030455,
"_id": "19588663/21030455"
}
],
"code": 201,
"count": 2
}

View File

@ -0,0 +1,10 @@
> curl -X DELETE --dump - http://localhost:8529/_api/cursor/8679702
HTTP/1.1 202 Accepted
content-type: application/json
{
"code": 202,
"id": "8679702",
"error": false
}

View File

@ -0,0 +1,11 @@
> curl -X PUT --dump - http://localhost:8529/_api/cursor/123456
HTTP/1.1 400 Bad Request
content-type: application/json
{
"code": 400,
"errorNum": 1600,
"error": true,
"errorMessage": "cursor not found: disposed or unknown cursor"
}

View File

@ -0,0 +1,11 @@
> curl -X POST --dump - http://localhost:8529/_api/cursor
HTTP/1.1 400 Bad Request
content-type: application/json
{
"errorNum": 1503,
"code": 400,
"error": true,
"errorMessage": "query specification invalid"
}

View File

@ -0,0 +1,11 @@
> curl -X PUT --dump - http://localhost:8529/_api/cursor
HTTP/1.1 400 Bad Request
content-type: application/json
{
"code": 400,
"errorMessage": "bad parameter",
"errorNum": 400,
"error": true
}

View File

@ -0,0 +1,12 @@
> curl --data @- -X POST --dump - http://localhost:8529/_api/cursor
{ "query" : "FOR u IN unknowncollection LIMIT 2 RETURN u.n", "count" : true, "bindVars" : {}, "batchSize" : 2 }
HTTP/1.1 400 Bad Request
content-type: application/json
{
"code": 400,
"error": true,
"errorMessage": "unable to open collection '%s': unable to open collection 'unknowncollection'",
"errorNum": 1510
}

View File

@ -0,0 +1,12 @@
> curl --data @- -X POST --dump - http://localhost:8529/_api/query
{ "query" : "FOR u IN users FILTER u.name = @name LIMIT 2 RETURN u.n" }
HTTP/1.1 400 Bad Request
content-type: application/json
{
"errorNum": 1501,
"errorMessage": "parse error: %s: parse error: 1:29 syntax error, unexpected assignment near ' = @name LIMIT 2 RETURN u.n'",
"error": true,
"code": 400
}

View File

@ -0,0 +1,13 @@
> curl --data @- -X POST --dump - http://localhost:8529/_api/query
{ "query" : "FOR u IN users FILTER u.name == @name LIMIT 2 RETURN u.n" }
HTTP/1.1 200 OK
content-type: application/json
{
"error": false,
"bindVars": [
"name"
],
"code": 200
}

View File

@ -56,7 +56,6 @@ doxygen: Doxygen/avocado.doxy $(DOXYGEN)
wiki: doxygen $(addsuffix .md,$(addprefix Doxygen/xml/,$(WIKI)))
@test -d Doxygen/wiki || mkdir Doxygen/wiki
@for w in $(WIKI); do @top_srcdir@/Doxygen/Scripts/pandoc.sh Doxygen/xml/$$w.md; done
@for w in $(WIKI); do @top_srcdir@/Doxygen/Scripts/md2html.sh Doxygen/wiki/$$w.md; done
################################################################################
## CLEANUP

View File

@ -374,6 +374,7 @@ WIKI = \
Graphs \
Home \
HttpCollection \
HttpCursor \
HttpIndex \
HttpInterface \
HttpSystem \

View File

@ -962,6 +962,7 @@ WIKI = \
Graphs \
Home \
HttpCollection \
HttpCursor \
HttpIndex \
HttpInterface \
HttpSystem \
@ -2939,7 +2940,6 @@ doxygen: Doxygen/avocado.doxy $(DOXYGEN)
wiki: doxygen $(addsuffix .md,$(addprefix Doxygen/xml/,$(WIKI)))
@test -d Doxygen/wiki || mkdir Doxygen/wiki
@for w in $(WIKI); do @top_srcdir@/Doxygen/Scripts/pandoc.sh Doxygen/xml/$$w.md; done
@for w in $(WIKI); do @top_srcdir@/Doxygen/Scripts/md2html.sh Doxygen/wiki/$$w.md; done
.setup-directories:
@test -d js || mkdir js

View File

@ -89,21 +89,39 @@
/// attribute of the result set. If it is set to false, then the client has
/// fetched the complete result set from the server.
///
/// @EXAMPLES
///
/// @verbinclude api-cursor-create-for-limit-return-single
///
/// @subsection HttpCursorResultsCursor Using a Cursor
//////////////////////////////////////////////////////
///
/// If the result set contains more documents than should be transferred in a
/// single roundtrip (i.e. as set via the @LIT{batchSize} attribute), the server
/// will return the first few documents and create a temporary cursor. The
/// cursor id will also be returned to the client. The server will put the
/// cursor id in the @LIT{id} attribute of the response object. Furthermore,
/// the @LIT{hasMore} attribute of the response object will be set to
/// @LIT{true}. This is an indication for the client that there are additional
/// results to fetch from the server.
/// cursor identifier will also be returned to the client. The server will put
/// the cursor identifier in the @LIT{id} attribute of the response
/// object. Furthermore, the @LIT{hasMore} attribute of the response object will
/// be set to @LIT{true}. This is an indication for the client that there are
/// additional results to fetch from the server.
///
/// @EXAMPLES
///
/// @verbinclude cursorput1
/// Create and extract first batch:
///
/// @verbinclude api-cursor-create-for-limit-return
///
/// Extract next batch, still have more:
///
/// @verbinclude api-cursor-create-for-limit-return-cont
///
/// Extract next batch, done:
///
/// @verbinclude api-cursor-create-for-limit-return-cont2
///
/// Do not do this:
///
/// @verbinclude api-cursor-create-for-limit-return-cont3
///
/// @section HttpCursorHttp Accessing Cursors via Http
//////////////////////////////////////////////////////

View File

@ -0,0 +1,226 @@
# coding: utf-8
require 'rspec'
require './avocadodb.rb'
describe AvocadoDB do
api = "/_api/cursor"
prefix = "api-cursor"
context "dealing with cursors:" do
################################################################################
## error handling
################################################################################
context "error handling:" do
it "returns an errror if body is missing" do
cmd = api
doc = AvocadoDB.log_post("#{prefix}-missing-body", cmd)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(1503)
end
it "returns an errror if collection is unknown" do
cmd = api
body = "{ \"query\" : \"FOR u IN unknowncollection LIMIT 2 RETURN u.n\", \"count\" : true, \"bindVars\" : {}, \"batchSize\" : 2 }"
doc = AvocadoDB.log_post("#{prefix}-unknown-collection", cmd, :body => body)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(1510)
end
it "returns an errror if cursor identifier is missing" do
cmd = api
doc = AvocadoDB.log_put("#{prefix}-missing-cursor-identifier", cmd)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(400)
end
it "returns an errror if cursor identifier is invalid" do
cmd = api + "/123456"
doc = AvocadoDB.log_put("#{prefix}-invalid-cursor-identifier", cmd)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(1600)
end
end
################################################################################
## create and using cursors
################################################################################
context "handling a cursor:" do
before do
@cn = "users"
AvocadoDB.drop_collection(@cn)
@cid = AvocadoDB.create_collection(@cn, false)
(0...10).each{|i|
AvocadoDB.post("/document?collection=#{@cid}", :body => "{ \"n\" : #{i} }")
}
end
after do
AvocadoDB.drop_collection(@cn)
end
it "creates a cursor single run" do
cmd = api
body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 2 RETURN u.n\", \"count\" : true, \"bindVars\" : {}, \"batchSize\" : 2 }"
doc = AvocadoDB.log_post("#{prefix}-create-for-limit-return-single", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(201)
doc.parsed_response['hasMore'].should eq(false)
doc.parsed_response['count'].should eq(2)
doc.parsed_response['result'].length.should eq(2)
end
it "creates a cursor single run, large batch size" do
cmd = api
body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 2 RETURN u.n\", \"count\" : true, \"batchSize\" : 5 }"
doc = AvocadoDB.log_post("#{prefix}-create-for-limit-return-single-larger", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(201)
doc.parsed_response['hasMore'].should eq(false)
doc.parsed_response['count'].should eq(2)
doc.parsed_response['result'].length.should eq(2)
end
it "creates a cursor" do
cmd = api
body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 5 RETURN u.n\", \"count\" : true, \"batchSize\" : 2 }"
doc = AvocadoDB.log_post("#{prefix}-create-for-limit-return", cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(201)
doc.parsed_response['id'].should be_kind_of(Integer)
doc.parsed_response['hasMore'].should eq(true)
doc.parsed_response['count'].should eq(5)
doc.parsed_response['result'].length.should eq(2)
id = doc.parsed_response['id']
cmd = api + "/#{id}"
doc = AvocadoDB.log_put("#{prefix}-create-for-limit-return-cont", cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(200)
doc.parsed_response['hasMore'].should eq(true)
doc.parsed_response['count'].should eq(5)
doc.parsed_response['result'].length.should eq(2)
cmd = api + "/#{id}"
doc = AvocadoDB.log_put("#{prefix}-create-for-limit-return-cont2", cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(200)
doc.parsed_response['hasMore'].should eq(false)
doc.parsed_response['count'].should eq(5)
doc.parsed_response['result'].length.should eq(1)
cmd = api + "/#{id}"
doc = AvocadoDB.log_put("#{prefix}-create-for-limit-return-cont3", cmd)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1600)
doc.parsed_response['code'].should eq(400)
end
it "deleting a cursor" do
cmd = api
body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 5 RETURN u.n\", \"count\" : true, \"batchSize\" : 2 }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(201)
doc.parsed_response['id'].should be_kind_of(Integer)
doc.parsed_response['hasMore'].should eq(true)
doc.parsed_response['count'].should eq(5)
doc.parsed_response['result'].length.should eq(2)
id = doc.parsed_response['id']
cmd = api + "/#{id}"
doc = AvocadoDB.log_delete("#{prefix}-delete", cmd)
doc.code.should eq(202)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(202)
end
end
################################################################################
## checking a query
################################################################################
context "checking a query:" do
before do
@cn = "users"
AvocadoDB.drop_collection(@cn)
@cid = AvocadoDB.create_collection(@cn, false)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "valid query" do
cmd = "/_api/query"
body = "{ \"query\" : \"FOR u IN #{@cn} FILTER u.name == @name LIMIT 2 RETURN u.n\" }"
doc = AvocadoDB.log_post("api-query-valid", cmd, :body => body)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(200)
doc.parsed_response['bindVars'].should eq(["name"])
end
it "invalid query" do
cmd = "/_api/query"
body = "{ \"query\" : \"FOR u IN #{@cn} FILTER u.name = @name LIMIT 2 RETURN u.n\" }"
doc = AvocadoDB.log_post("api-query-invalid", cmd, :body => body)
doc.code.should eq(400)
doc.headers['content-type'].should eq("application/json")
doc.parsed_response['error'].should eq(true)
doc.parsed_response['code'].should eq(400)
doc.parsed_response['errorNum'].should eq(1501)
end
end
end
end

View File

@ -60,7 +60,7 @@ describe AvocadoDB do
after do
AvocadoDB.drop_collection(@cn)
end
end
it "returns either 201 for new or 200 for old indexes" do
cmd = api + "?collection=#{@cid}"

View File

@ -8,4 +8,5 @@ rspec --format d \
rest-read-document-spec.rb \
rest-update-document-spec.rb \
rest-delete-document-spec.rb \
rest-edge-spec.rb
rest-edge-spec.rb \
api-cursor-spec.rb

View File

@ -1081,7 +1081,7 @@ static v8::Handle<v8::Value> CreateVocBase (v8::Arguments const& argv, bool edge
TRI_vocbase_col_t const* collection = TRI_CreateCollectionVocBase(vocbase, &parameter);
if (collection == NULL) {
if (collection == 0) {
return scope.Close(v8::ThrowException(CreateErrorObject(TRI_errno(), "cannot create collection")));
}
@ -2141,82 +2141,6 @@ static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generates a general cursor from a list
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
if (argv.Length() < 1) {
return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: GENERAL_CURSOR(<list>, <do-count>, <batch-size>)")));
}
if (! argv[0]->IsArray()) {
return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"<list> must be a list")));
}
// extract objects
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(argv[0]);
TRI_json_t* json = TRI_JsonObject(array);
if (json == 0) {
return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"cannot convert <list> to JSON")));
}
// return number of total records in cursor?
bool doCount = false;
if (argv.Length() >= 2) {
doCount = TRI_ObjectToBoolean(argv[1]);
}
// maximum number of results to return at once
uint32_t batchSize = 1000;
if (argv.Length() >= 3) {
double maxValue = TRI_ObjectToDouble(argv[2]);
if (maxValue >= 1.0) {
batchSize = (uint32_t) maxValue;
}
}
// create a cursor
TRI_general_cursor_t* cursor = 0;
TRI_general_cursor_result_t* cursorResult = TRI_CreateResultAql(json);
if (cursorResult != 0) {
cursor = TRI_CreateGeneralCursor(cursorResult, doCount, batchSize);
if (cursor == 0) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
}
}
else {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
}
if (cursor == 0) {
return scope.Close(v8::ThrowException(v8::String::New("cannot create cursor")));
}
TRI_StoreShadowData(vocbase->_cursors, (const void* const) cursor);
return scope.Close(WrapGeneralCursor(cursor));
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -2225,6 +2149,10 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
// --SECTION-- GENERAL CURSORS
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
@ -2300,30 +2228,129 @@ static void* UnwrapGeneralCursor (v8::Handle<v8::Object> cursorObject) {
return TRI_UnwrapClass<void>(cursorObject, WRP_GENERAL_CURSOR_TYPE);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- javascript functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief generates a general cursor from a list
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
if (argv.Length() < 1) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: GENERAL_CURSOR(<list>, <do-count>, <batch-size>)")));
}
if (! argv[0]->IsArray()) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"<list> must be a list")));
}
// extract objects
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(argv[0]);
TRI_json_t* json = TRI_JsonObject(array);
if (json == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"cannot convert <list> to JSON")));
}
// return number of total records in cursor?
bool doCount = false;
if (argv.Length() >= 2) {
doCount = TRI_ObjectToBoolean(argv[1]);
}
// maximum number of results to return at once
uint32_t batchSize = 1000;
if (argv.Length() >= 3) {
double maxValue = TRI_ObjectToDouble(argv[2]);
if (maxValue >= 1.0) {
batchSize = (uint32_t) maxValue;
}
}
// create a cursor
TRI_general_cursor_t* cursor = 0;
TRI_general_cursor_result_t* cursorResult = TRI_CreateResultAql(json);
if (cursorResult != 0) {
cursor = TRI_CreateGeneralCursor(cursorResult, doCount, batchSize);
if (cursor == 0) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
}
}
else {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
}
if (cursor == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"cannot create cursor")));
}
TRI_StoreShadowData(vocbase->_cursors, (const void* const) cursor);
return scope.Close(WrapGeneralCursor(cursor));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a general cursor
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_DisposeGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: dispose()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: dispose()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
if (TRI_DeleteDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()))) {
if (!tryCatch.HasCaught()) {
return scope.Close(v8::True());
}
bool found = TRI_DeleteDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (found) {
return scope.Close(v8::True());
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already disposed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2332,23 +2359,30 @@ static v8::Handle<v8::Value> JS_DisposeGeneralCursor (v8::Arguments const& argv)
static v8::Handle<v8::Value> JS_IdGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: id()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: id()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
TRI_shadow_id id = TRI_GetIdDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (id && !tryCatch.HasCaught()) {
if (id != 0) {
return scope.Close(v8::Number::New((double) id));
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already disposed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2357,15 +2391,19 @@ static v8::Handle<v8::Value> JS_IdGeneralCursor (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_CountGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: count()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: count()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
TRI_general_cursor_t* cursor;
@ -2378,7 +2416,9 @@ static v8::Handle<v8::Value> JS_CountGeneralCursor (v8::Arguments const& argv) {
return scope.Close(v8::Number::New(length));
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2387,15 +2427,19 @@ static v8::Handle<v8::Value> JS_CountGeneralCursor (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_NextGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: next()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: count()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
bool result = false;
@ -2416,9 +2460,12 @@ static v8::Handle<v8::Value> JS_NextGeneralCursor (v8::Arguments const& argv) {
// exceptions must be caught in the following part because we hold an exclusive
// lock that might otherwise not be freed
v8::TryCatch tryCatch;
try {
TRI_general_cursor_row_t row = cursor->next(cursor);
if (!row) {
if (row == 0) {
value = v8::Undefined();
}
else {
@ -2433,12 +2480,18 @@ static v8::Handle<v8::Value> JS_NextGeneralCursor (v8::Arguments const& argv) {
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
if (result && !tryCatch.HasCaught()) {
if (result && ! tryCatch.HasCaught()) {
return scope.Close(value);
}
if (tryCatch.HasCaught()) {
return scope.Close(v8::ThrowException(tryCatch.Exception()));
}
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2447,23 +2500,30 @@ static v8::Handle<v8::Value> JS_NextGeneralCursor (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_PersistGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: persist()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: persist()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
bool result = TRI_PersistDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (result && !tryCatch.HasCaught()) {
if (result) {
return scope.Close(v8::True());
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2475,15 +2535,19 @@ static v8::Handle<v8::Value> JS_PersistGeneralCursor (v8::Arguments const& argv)
static v8::Handle<v8::Value> JS_GetRowsGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: getRows()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: getRows()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
bool result = false;
@ -2497,6 +2561,8 @@ static v8::Handle<v8::Value> JS_GetRowsGeneralCursor (v8::Arguments const& argv)
// exceptions must be caught in the following part because we hold an exclusive
// lock that might otherwise not be freed
v8::TryCatch tryCatch;
try {
uint32_t max = (uint32_t) cursor->getBatchSize(cursor);
@ -2517,12 +2583,18 @@ static v8::Handle<v8::Value> JS_GetRowsGeneralCursor (v8::Arguments const& argv)
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
if (result && !tryCatch.HasCaught()) {
if (result && ! tryCatch.HasCaught()) {
return scope.Close(rows);
}
if (tryCatch.HasCaught()) {
return scope.Close(v8::ThrowException(tryCatch.Exception()));
}
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2531,15 +2603,19 @@ static v8::Handle<v8::Value> JS_GetRowsGeneralCursor (v8::Arguments const& argv)
static v8::Handle<v8::Value> JS_GetBatchSizeGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: getBatchSize()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: getBatchSize()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
TRI_general_cursor_t* cursor;
@ -2553,7 +2629,9 @@ static v8::Handle<v8::Value> JS_GetBatchSizeGeneralCursor (v8::Arguments const&
return scope.Close(v8::Number::New(max));
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2562,17 +2640,21 @@ static v8::Handle<v8::Value> JS_GetBatchSizeGeneralCursor (v8::Arguments const&
static v8::Handle<v8::Value> JS_HasCountGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: hasCount()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: hasCount()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
@ -2584,7 +2666,9 @@ static v8::Handle<v8::Value> JS_HasCountGeneralCursor (v8::Arguments const& argv
return scope.Close(hasCount ? v8::True() : v8::False());
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2596,12 +2680,17 @@ static v8::Handle<v8::Value> JS_HasNextGeneralCursor (v8::Arguments const& argv)
v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: hasNext()")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: hasNext()")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
TRI_general_cursor_t* cursor;
@ -2617,7 +2706,9 @@ static v8::Handle<v8::Value> JS_HasNextGeneralCursor (v8::Arguments const& argv)
return scope.Close(hasNext ? v8::True() : v8::False());
}
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@ -2628,27 +2719,39 @@ static v8::Handle<v8::Value> JS_Cursor (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 1) {
return scope.Close(v8::ThrowException(v8::String::New("usage: CURSOR(<cursor-id>)")));
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"usage: CURSOR(<cursor-identifier>)")));
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
if (vocbase == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_INTERNAL,
"corrupted vocbase")));
}
// get the id
v8::Handle<v8::Value> idArg = argv[0]->ToString();
if (!idArg->IsString()) {
return scope.Close(v8::ThrowException(v8::String::New("expecting string for <id>")));
if (! idArg->IsString()) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION,
"expecting a string for <cursor-identifier>)")));
}
string idString = TRI_ObjectToString(idArg);
uint64_t id = TRI_UInt64String(idString.c_str());
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageIdShadowData(vocbase->_cursors, id);
if (!cursor) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
if (cursor == 0) {
return scope.Close(v8::ThrowException(
CreateErrorObject(TRI_ERROR_CURSOR_NOT_FOUND,
"disposed or unknown cursor")));
}
return scope.Close(WrapGeneralCursor(cursor));
@ -2727,7 +2830,7 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
}
// bind parameters
TRI_json_t* parameters = NULL;
TRI_json_t* parameters = 0;
if (argv.Length() > 1) {
parameters = TRI_JsonObject(argv[1]);
}
@ -2976,7 +3079,7 @@ static v8::Handle<v8::Value> JS_WhereHashConstAql (const v8::Arguments& argv) {
for (int j = 1; j < argv.Length(); ++j) {
v8::Handle<v8::Value> parameter = argv[j];
TRI_json_t* jsonParameter = TRI_JsonObject(parameter);
if (jsonParameter == NULL) { // NOT the null json value!
if (jsonParameter == 0) { // NOT the null json value!
return scope.Close(v8::ThrowException(v8::String::New("type value not currently supported for hash index")));
}
TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, parameterList, jsonParameter);
@ -3052,7 +3155,7 @@ static v8::Handle<v8::Value> JS_WherePQConstAql (const v8::Arguments& argv) {
if (argv.Length() == 1) {
TRI_json_t* jsonParameter = TRI_CreateNumberJson(TRI_UNKNOWN_MEM_ZONE, 1);
if (jsonParameter == NULL) { // failure of some sort
if (jsonParameter == 0) { // failure of some sort
return scope.Close(v8::ThrowException(v8::String::New("internal error in JS_WherePQConstAql")));
}
TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, parameterList, jsonParameter);
@ -3062,7 +3165,7 @@ static v8::Handle<v8::Value> JS_WherePQConstAql (const v8::Arguments& argv) {
for (int j = 1; j < argv.Length(); ++j) {
v8::Handle<v8::Value> parameter = argv[j];
TRI_json_t* jsonParameter = TRI_JsonObject(parameter);
if (jsonParameter == NULL) { // NOT the null json value!
if (jsonParameter == 0) { // NOT the null json value!
return scope.Close(v8::ThrowException(v8::String::New("type value not currently supported for priority queue index")));
}
TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, parameterList, jsonParameter);
@ -3131,7 +3234,7 @@ static v8::Handle<v8::Value> JS_WhereSkiplistConstAql (const v8::Arguments& argv
// ..........................................................................
if (haveOperators) {
if (argv.Length() > 2) {
TRI_sl_operator_t* leftOp = NULL;
TRI_sl_operator_t* leftOp = 0;
v8::Handle<v8::Value> leftParameter = argv[1];
v8::Handle<v8::Object> leftObject = leftParameter->ToObject();
leftOp = TRI_UnwrapClass<TRI_sl_operator_t>(leftObject, WRP_SL_OPERATOR_TYPE);
@ -3147,7 +3250,7 @@ static v8::Handle<v8::Value> JS_WhereSkiplistConstAql (const v8::Arguments& argv
TRI_FreeSLOperator(leftOp);
return scope.Close(v8::ThrowException(v8::String::New("either logical/relational operators or constants allowed, but not both")));
}
TRI_sl_operator_t* tempAndOperator = CreateSLOperator(TRI_SL_AND_OPERATOR,leftOp, rightOp, NULL, NULL, NULL, 2, NULL);
TRI_sl_operator_t* tempAndOperator = CreateSLOperator(TRI_SL_AND_OPERATOR,leftOp, rightOp, 0, 0, 0, 2, 0);
leftOp = tempAndOperator;
}
where = TRI_CreateQueryWhereSkiplistConstant(iid, leftOp);
@ -3176,17 +3279,17 @@ static v8::Handle<v8::Value> JS_WhereSkiplistConstAql (const v8::Arguments& argv
for (int j = 1; j < argv.Length(); ++j) {
v8::Handle<v8::Value> parameter = argv[j];
TRI_json_t* jsonParameter = TRI_JsonObject(parameter);
if (jsonParameter == NULL) { // NOT the null json value!
if (jsonParameter == 0) { // NOT the null json value!
return scope.Close(v8::ThrowException(v8::String::New("type value not currently supported for skiplist index")));
}
TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, parameterList, jsonParameter);
}
TRI_sl_operator_t* eqOperator = CreateSLOperator(TRI_SL_EQ_OPERATOR,NULL, NULL, parameterList, NULL, NULL,
parameterList->_value._objects._length, NULL);
TRI_sl_operator_t* eqOperator = CreateSLOperator(TRI_SL_EQ_OPERATOR,0, 0, parameterList, 0, 0,
parameterList->_value._objects._length, 0);
where = TRI_CreateQueryWhereSkiplistConstant(iid, eqOperator);
}
if (where == NULL) {
if (where == 0) {
return scope.Close(v8::ThrowException(v8::String::New("Error detected in where statement")));
}
@ -3352,7 +3455,7 @@ static v8::Handle<v8::Value> JS_PQSelectAql (v8::Arguments const& argv) {
// ...........................................................................
TRI_qry_where_priorityqueue_const_t* pqWhere = (TRI_qry_where_priorityqueue_const_t*)(where);
TRI_priorityqueue_index_t* idx = (TRI_priorityqueue_index_t*)(TRI_LookupIndex(collection->_collection, pqWhere->_iid));
if (idx == NULL) {
if (idx == 0) {
ReleaseCollection(collection);
return scope.Close(v8::ThrowException(v8::String::New("invalid index in where statement")));
}
@ -3460,7 +3563,7 @@ static v8::Handle<v8::Value> JS_SkiplistSelectAql (v8::Arguments const& argv) {
// ...........................................................................
TRI_qry_where_skiplist_const_t* slWhere = (TRI_qry_where_skiplist_const_t*)(where);
TRI_skiplist_index_t* idx = (TRI_skiplist_index_t*)(TRI_LookupIndex(collection->_collection, slWhere->_iid));
if (idx == NULL) {
if (idx == 0) {
ReleaseCollection(collection);
return scope.Close(v8::ThrowException(v8::String::New("invalid index in where statement")));
}
@ -3539,17 +3642,17 @@ static v8::Handle<v8::Object> WrapSLOperator (TRI_sl_operator_t* slOperator) {
static TRI_json_t* parametersToJson(v8::Arguments const& argv, int startPos, int endPos) {
TRI_json_t* result = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE);
if (result == NULL) {
if (result == 0) {
v8::ThrowException(v8::String::New("out of memory"));
return NULL;
return 0;
}
for (int j = startPos; j < endPos; ++j) {
v8::Handle<v8::Value> parameter = argv[j];
TRI_json_t* jsonParameter = TRI_JsonObject(parameter);
if (jsonParameter == NULL) { // NOT the null json value!
if (jsonParameter == 0) { // NOT the null json value!
v8::ThrowException(v8::String::New("type value not currently supported for skiplist index"));
return NULL;
return 0;
}
TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, jsonParameter);
}
@ -3567,7 +3670,7 @@ static v8::Handle<v8::Value> JS_Operator_AND (v8::Arguments const& argv) {
// ...........................................................................
// We expect a list of constant values in the order in which the skip list
// index has been defined. An unknown value can have a NULL
// index has been defined. An unknown value can have a 0
// ...........................................................................
if (argv.Length() != 2) {
return scope.Close(v8::ThrowException(v8::String::New("usage: AND(<value 1>, <value 2>)")));
@ -3603,7 +3706,7 @@ static v8::Handle<v8::Value> JS_Operator_AND (v8::Arguments const& argv) {
// ...........................................................................
logicalOperator = (TRI_sl_logical_operator_t*)(CreateSLOperator(TRI_SL_AND_OPERATOR,
CopySLOperator(leftOperator),
CopySLOperator(rightOperator),NULL, NULL, NULL, 2, NULL));
CopySLOperator(rightOperator),0, 0, 0, 2, 0));
// ...........................................................................
// Wrap it up for later use and return.
// ...........................................................................
@ -3617,7 +3720,7 @@ static v8::Handle<v8::Value> JS_Operator_OR (v8::Arguments const& argv) {
// ...........................................................................
// We expect a list of constant values in the order in which the skip list
// index has been defined. An unknown value can have a NULL
// index has been defined. An unknown value can have a 0
// ...........................................................................
if (argv.Length() != 2) {
return scope.Close(v8::ThrowException(v8::String::New("usage: OR(<value 1>, <value 2>)")));
@ -3654,7 +3757,7 @@ static v8::Handle<v8::Value> JS_Operator_OR (v8::Arguments const& argv) {
// ...........................................................................
logicalOperator = (TRI_sl_logical_operator_t*)(CreateSLOperator(TRI_SL_OR_OPERATOR,
CopySLOperator(leftOperator),
CopySLOperator(rightOperator),NULL, NULL, NULL, 2, NULL));
CopySLOperator(rightOperator),0, 0, 0, 2, 0));
return scope.Close(WrapSLOperator(&(logicalOperator->_base)));
}
@ -3667,7 +3770,7 @@ static v8::Handle<v8::Value> JS_Operator_EQ (v8::Arguments const& argv) {
// ...........................................................................
// We expect a list of constant values in the order in which the skip list
// index has been defined. An unknown value can have a NULL
// index has been defined. An unknown value can have a 0
// ...........................................................................
if (argv.Length() < 1) {
return scope.Close(v8::ThrowException(v8::String::New("usage: EQ(<value 1>, <value 2>,..., <value n>)")));
@ -3681,15 +3784,15 @@ static v8::Handle<v8::Value> JS_Operator_EQ (v8::Arguments const& argv) {
// ...........................................................................
parameters = parametersToJson(argv,0,argv.Length());
if (parameters == NULL) {
if (parameters == 0) {
return scope.Close(v8::ThrowException(v8::String::New("unsupported type in EQ(...) parameter list")));
}
// ...........................................................................
// Allocate the storage for a relation (EQ) operator and assign it that type
// ...........................................................................
relationOperator = (TRI_sl_relation_operator_t*)(CreateSLOperator(TRI_SL_EQ_OPERATOR, NULL, NULL, parameters, NULL, NULL,
parameters->_value._objects._length, NULL));
relationOperator = (TRI_sl_relation_operator_t*)(CreateSLOperator(TRI_SL_EQ_OPERATOR, 0, 0, parameters, 0, 0,
parameters->_value._objects._length, 0));
return scope.Close(WrapSLOperator(&(relationOperator->_base)));
}
@ -3701,7 +3804,7 @@ static v8::Handle<v8::Value> JS_Operator_GE (v8::Arguments const& argv) {
// ...........................................................................
// We expect a list of constant values in the order in which the skip list
// index has been defined. An unknown value can have a NULL
// index has been defined. An unknown value can have a 0
// ...........................................................................
if (argv.Length() < 1) {
return scope.Close(v8::ThrowException(v8::String::New("usage: GE(<value 1>, <value 2>,..., <value n>)")));
@ -3715,15 +3818,15 @@ static v8::Handle<v8::Value> JS_Operator_GE (v8::Arguments const& argv) {
// ...........................................................................
parameters = parametersToJson(argv,0,argv.Length());
if (parameters == NULL) {
if (parameters == 0) {
return scope.Close(v8::ThrowException(v8::String::New("unsupported type in GE(...) parameter list")));
}
// ...........................................................................
// Allocate the storage for a relation (GE) operator and assign it that type
// ...........................................................................
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_GE_OPERATOR, NULL, NULL, parameters, NULL, NULL,
parameters->_value._objects._length, NULL) );
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_GE_OPERATOR, 0, 0, parameters, 0, 0,
parameters->_value._objects._length, 0) );
return scope.Close(WrapSLOperator(&(relationOperator->_base)));
}
@ -3736,7 +3839,7 @@ static v8::Handle<v8::Value> JS_Operator_GT (v8::Arguments const& argv) {
// ...........................................................................
// We expect a list of constant values in the order in which the skip list
// index has been defined. An unknown value can have a NULL
// index has been defined. An unknown value can have a 0
// ...........................................................................
if (argv.Length() < 1) {
return scope.Close(v8::ThrowException(v8::String::New("usage: GT(<value 1>, <value 2>,..., <value n>)")));
@ -3750,15 +3853,15 @@ static v8::Handle<v8::Value> JS_Operator_GT (v8::Arguments const& argv) {
// ...........................................................................
parameters = parametersToJson(argv,0,argv.Length());
if (parameters == NULL) {
if (parameters == 0) {
return scope.Close(v8::ThrowException(v8::String::New("unsupported type in GT(...) parameter list")));
}
// ...........................................................................
// Allocate the storage for a relation (GT) operator and assign it that type
// ...........................................................................
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_GT_OPERATOR, NULL, NULL, parameters, NULL, NULL,
parameters->_value._objects._length, NULL) );
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_GT_OPERATOR, 0, 0, parameters, 0, 0,
parameters->_value._objects._length, 0) );
return scope.Close(WrapSLOperator(&(relationOperator->_base)));
}
@ -3771,7 +3874,7 @@ static v8::Handle<v8::Value> JS_Operator_LE (v8::Arguments const& argv) {
// ...........................................................................
// We expect a list of constant values in the order in which the skip list
// index has been defined. An unknown value can have a NULL
// index has been defined. An unknown value can have a 0
// ...........................................................................
if (argv.Length() < 1) {
return scope.Close(v8::ThrowException(v8::String::New("usage: LE(<value 1>, <value 2>,..., <value n>)")));
@ -3785,15 +3888,15 @@ static v8::Handle<v8::Value> JS_Operator_LE (v8::Arguments const& argv) {
// ...........................................................................
parameters = parametersToJson(argv,0,argv.Length());
if (parameters == NULL) {
if (parameters == 0) {
return scope.Close(v8::ThrowException(v8::String::New("unsupported type in LE(...) parameter list")));
}
// ...........................................................................
// Allocate the storage for a relation (LE) operator and assign it that type
// ...........................................................................
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_LE_OPERATOR, NULL, NULL,parameters, NULL, NULL,
parameters->_value._objects._length, NULL) );
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_LE_OPERATOR, 0, 0,parameters, 0, 0,
parameters->_value._objects._length, 0) );
return scope.Close(WrapSLOperator(&(relationOperator->_base)));
}
@ -3806,7 +3909,7 @@ static v8::Handle<v8::Value> JS_Operator_LT (v8::Arguments const& argv) {
// ...........................................................................
// We expect a list of constant values in the order in which the skip list
// index has been defined. An unknown value can have a NULL
// index has been defined. An unknown value can have a 0
// ...........................................................................
if (argv.Length() < 1) {
return scope.Close(v8::ThrowException(v8::String::New("usage: LT(<value 1>, <value 2>,..., <value n>)")));
@ -3820,15 +3923,15 @@ static v8::Handle<v8::Value> JS_Operator_LT (v8::Arguments const& argv) {
// ...........................................................................
parameters = parametersToJson(argv,0,argv.Length());
if (parameters == NULL) {
if (parameters == 0) {
return scope.Close(v8::ThrowException(v8::String::New("unsupported type in LT(...) parameter list")));
}
// ...........................................................................
// Allocate the storage for a relation (LT) operator and assign it that type
// ...........................................................................
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_LT_OPERATOR, NULL,NULL,parameters, NULL, NULL,
parameters->_value._objects._length, NULL) );
relationOperator = (TRI_sl_relation_operator_t*)( CreateSLOperator(TRI_SL_LT_OPERATOR, 0,0,parameters, 0, 0,
parameters->_value._objects._length, 0) );
return scope.Close(WrapSLOperator(&(relationOperator->_base)));
}
@ -3904,15 +4007,15 @@ static v8::Handle<v8::Value> JS_SelectAql (v8::Arguments const& argv) {
TRI_AddPartSelectJoinX(join,
JOIN_TYPE_PRIMARY,
NULL,
0,
(char*) name.c_str(),
(char*) "alias",
NULL);
0);
// create the query
TRI_query_t* query = TRI_CreateQuery(vocbase,
select,
NULL,
0,
join,
skip,
limit);
@ -4383,7 +4486,7 @@ static v8::Handle<v8::Value> JS_EnsurePriorityQueueIndexVocbaseCol (v8::Argument
v8::String::Utf8Value argumentString(argument);
char* cArgument = (char*) (TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, argumentString.length() + 1, false));
if (cArgument == NULL) {
if (cArgument == 0) {
errorString = "insuffient memory to complete ensurePQIndex(...) command";
ok = false;
break;
@ -4445,7 +4548,7 @@ static v8::Handle<v8::Value> JS_EnsurePriorityQueueIndexVocbaseCol (v8::Argument
TRI_DestroyVector(&attributes);
if (idx == NULL) {
if (idx == 0) {
ReleaseCollection(collection);
return scope.Close(v8::String::New("Priority Queue index could not be created"));
}
@ -5722,8 +5825,8 @@ static v8::Handle<v8::Value> MapGetShapedJson (v8::Local<v8::String> name,
TRI_shape_access_t* acc = TRI_ShapeAccessor(shaper, sid, pid);
if (acc == NULL || acc->_shape == NULL) {
if (acc != NULL) {
if (acc == 0 || acc->_shape == 0) {
if (acc != 0) {
TRI_FreeShapeAccessor(acc);
}
@ -5869,8 +5972,8 @@ static v8::Handle<v8::Integer> PropertyQueryShapedJson (v8::Local<v8::String> na
TRI_shape_access_t* acc = TRI_ShapeAccessor(shaper, sid, pid);
// key not found
if (acc == NULL || acc->_shape == NULL) {
if (acc != NULL) {
if (acc == 0 || acc->_shape == 0) {
if (acc != 0) {
TRI_FreeShapeAccessor(acc);
}

View File

@ -121,7 +121,7 @@ function getCursorResult (cursor) {
/// - @LIT{count}: the total number of result documents available (only
/// available if the query was executed with the @LIT{count} attribute set.
///
/// - @LIT{id}: id of temporary cursor created on the server (optional, see below)
/// - @LIT{id}: id of temporary cursor created on the server (optional, see above)
///
/// If the JSON representation is malformed or the query specification is
/// missing from the request, the server will respond with @LIT{HTTP 400}.
@ -145,19 +145,15 @@ function getCursorResult (cursor) {
///
/// @EXAMPLES
///
/// @verbinclude cursor
/// Executes a query and extract the result in a single go:
///
/// @verbinclude api-cursor-create-for-limit-return-single
///
/// Bad queries:
///
/// @verbinclude cursor4001
/// @verbinclude api-cursor-missing-body
///
/// @verbinclude cursor4002
///
/// @verbinclude cursor404
///
/// Valid query:
///
/// @verbinclude cursor201
/// @verbinclude api-cursor-unknown-collection
////////////////////////////////////////////////////////////////////////////////
function POST_api_cursor(req, res) {
@ -166,15 +162,24 @@ function POST_api_cursor(req, res) {
return;
}
try {
var json = JSON.parse(req.requestBody);
if (!json || !(json instanceof Object)) {
actions.resultBad(req, res, actions.ERROR_QUERY_SPECIFICATION_INVALID, actions.getErrorMessage(actions.ERROR_QUERY_SPECIFICATION_INVALID));
return;
}
var json;
try {
json = JSON.parse(req.requestBody || "{}") || {};
}
catch (err) {
actions.resultBad(req, res, actions.ERROR_HTTP_CORRUPTED_JSON, err);
return;
}
if (! json || ! (json instanceof Object)) {
actions.resultBad(req, res, actions.ERROR_QUERY_SPECIFICATION_INVALID);
return;
}
try {
var cursor;
if (json.query != undefined) {
cursor = AHUACATL_RUN(json.query,
json.bindVars,
@ -182,12 +187,12 @@ function POST_api_cursor(req, res) {
(json.batchSize != undefined ? json.batchSize : 1000));
}
else {
actions.resultBad(req, res, actions.ERROR_QUERY_SPECIFICATION_INVALID, actions.getErrorMessage(actions.ERROR_QUERY_SPECIFICATION_INVALID));
actions.resultBad(req, res, actions.ERROR_QUERY_SPECIFICATION_INVALID);
return;
}
// error occurred
if (cursor instanceof AvocadoError) {
// error occurred
actions.resultBad(req, res, cursor.errorNum, cursor.errorMessage);
return;
}
@ -195,6 +200,7 @@ function POST_api_cursor(req, res) {
// this might dispose or persist the cursor
var result = getCursorResult(cursor);
// return result to the client for first batch
actions.resultOk(req, res, actions.HTTP_CREATED, result);
}
catch (err) {
@ -221,19 +227,27 @@ function POST_api_cursor(req, res) {
/// @LIT{false}, the client can stop.
///
/// The server will respond with @LIT{HTTP 200} in case of success. If the
/// cursor id is ommitted or somehow invalid, the server will respond with
/// @LIT{HTTP 404}.
/// cursor identifier is ommitted or somehow invalid, the server will respond
/// with @LIT{HTTP 404}.
///
/// @EXAMPLES
///
/// @verbinclude cursorputfail
/// Valid request for next batch:
///
/// @verbinclude cursorput3
/// @verbinclude api-cursor-create-for-limit-return-cont
///
/// Missing identifier
///
/// @verbinclude api-cursor-missing-cursor-identifier
///
/// Unknown identifier
///
/// @verbinclude api-cursor-invalid-cursor-identifier
////////////////////////////////////////////////////////////////////////////////
function PUT_api_cursor(req, res) {
if (req.suffix.length != 1) {
actions.resultNotFound(req, res, actions.ERROR_HTTP_NOT_FOUND);
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER);
return;
}
@ -242,7 +256,7 @@ function PUT_api_cursor(req, res) {
var cursor = CURSOR(cursorId);
if (!(cursor instanceof AvocadoCursor)) {
actions.resultBad(req, res, actions.ERROR_CURSOR_NOT_FOUND, actions.getErrorMessage(actions.ERROR_CURSOR_NOT_FOUND));
actions.resultBad(req, res, actions.ERROR_CURSOR_NOT_FOUND);
return;
}
@ -278,12 +292,12 @@ function PUT_api_cursor(req, res) {
///
/// @EXAMPLES
///
/// @verbinclude cursordeletefail
/// @verbinclude api-cursor-delete
////////////////////////////////////////////////////////////////////////////////
function DELETE_api_cursor(req, res) {
if (req.suffix.length != 1) {
actions.resultNotFound(req, res, actions.ERROR_HTTP_NOT_FOUND);
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER);
return;
}
@ -291,8 +305,8 @@ function DELETE_api_cursor(req, res) {
var cursorId = decodeURIComponent(req.suffix[0]);
var cursor = CURSOR(cursorId);
if (!(cursor instanceof AvocadoCursor)) {
actions.resultBad(req, res, actions.ERROR_CURSOR_NOT_FOUND, actions.getErrorMessage(actions.ERROR_CURSOR_NOT_FOUND));
if (! (cursor instanceof AvocadoCursor)) {
actions.resultNotFound(req, res, actions.ERROR_CURSOR_NOT_FOUND);
return;
}

View File

@ -41,27 +41,29 @@ var actions = require("actions");
///
/// @REST{POST /_api/query}
///
/// To validate a query string without executing it, the query string can be
/// To validate a query string without executing it, the query string can be
/// passed to the server via an HTTP POST request.
///
/// These query string needs to be passed in the attribute @LIT{query} of a
/// JSON object as the body of the POST request.
/// These query string needs to be passed in the attribute @LIT{query} of a JSON
/// object as the body of the POST request.
///
/// The server will respond with @LIT{HTTP 400} or @LIT{HTTP 500} in case of a
/// malformed request or a general error.
/// If the query contains a parse error, the server will respond with an
/// @LIT{HTTP 404} error.
/// If the query is valid, the server will respond with @LIT{HTTP 200} and
/// return the names of the bind parameters it found in the query (if any) in
/// the @LIT{"bindVars"} attribute of the response.
///
/// The body of the response will contain the error details embedded in a JSON
/// object.
/// The server will respond with @LIT{HTTP 400} in case of a malformed request,
/// or if the query contains a parse error. The body of the response will
/// contain the error details embedded in a JSON object.
///
/// @verbinclude querypostfail
/// @EXAMPLES
///
/// If the query is valid, the server will respond with @LIT{HTTP 200} and return
/// the names of the bind parameters it found in the query (if any) in the
/// @LIT{"bindVars"} attribute of the response.
/// Valid query:
///
/// @verbinclude querypost
/// @verbinclude api-query-valid
///
/// Invalid query:
///
/// @verbinclude api-query-invalid
////////////////////////////////////////////////////////////////////////////////
function POST_api_query (req, res) {
@ -70,15 +72,24 @@ function POST_api_query (req, res) {
return;
}
try {
var json = JSON.parse(req.requestBody);
if (!json || !(json instanceof Object) || json.query == undefined) {
actions.resultBad(req, res, actions.ERROR_QUERY_SPECIFICATION_INVALID, actions.getErrorMessage(actions.ERROR_QUERY_SPECIFICATION_INVALID));
return;
}
var json;
try {
json = JSON.parse(req.requestBody || "{}") || {};
}
catch (err) {
actions.resultBad(req, res, actions.ERROR_HTTP_CORRUPTED_JSON, err);
return;
}
if (! json || ! (json instanceof Object)) {
actions.resultBad(req, res, actions.ERROR_QUERY_SPECIFICATION_INVALID);
return;
}
try {
var result = AHUACATL_PARSE(json.query);
if (result instanceof AvocadoError) {
actions.resultBad(req, res, result.errorNum, result.errorMessage);
return;

View File

@ -185,13 +185,15 @@ function DefineHttp (options) {
////////////////////////////////////////////////////////////////////////////////
function GetErrorMessage (code) {
var error = internal.errors[code];
if (!error) {
return "";
for (var key in internal.errors) {
if (internal.errors.hasOwnProperty(key)) {
if (internal.errors[key].code == code) {
return internal.errors[key].message;
}
}
}
return error.message;
return "";
}
////////////////////////////////////////////////////////////////////////////////
@ -293,7 +295,14 @@ function ResultOk (req, res, httpReturnCode, result, headers) {
////////////////////////////////////////////////////////////////////////////////
function ResultBad (req, res, code, msg, headers) {
ResultError(req, res, exports.HTTP_BAD, code, "" + msg, headers);
if (msg == null) {
msg = GetErrorMessage(code);
}
else {
msg = "" + msg;
}
ResultError(req, res, exports.HTTP_BAD, code, msg, headers);
}
////////////////////////////////////////////////////////////////////////////////