1
0
Fork 0

merge with SVN

This commit is contained in:
Jan Steemann 2012-03-28 14:01:41 +02:00
parent 46243e8288
commit 6f35cfaecc
31 changed files with 1743 additions and 2205 deletions

View File

@ -143,7 +143,7 @@ void ActionDispatcherThread::tick (bool idle) {
_gc += (idle ? 10 : 1);
if (_gc > _gcInterval) {
LOG_DEBUG("collecting garbage...");
LOG_TRACE("collecting garbage...");
while (!v8::V8::IdleNotification()) {
}

View File

@ -62,7 +62,7 @@
/// The basic operations (create, read, update, delete) for documents are mapped
/// to the standard HTTP methods (POST, GET, PUT, DELETE).
///
/// @section HttpCollectionResource Address of an Collection
/// @section HttpCollectionResource Address of a Collection
////////////////////////////////////////////////////////////
///
/// All collections in AvocadoDB have an unique identifier. This collection

View File

@ -0,0 +1,4 @@
source :rubygems
gem "httparty", "~> 0.8.1"
gem "rspec", "~> 2.8.0"

View File

@ -0,0 +1,132 @@
require 'httparty'
class AvocadoDB
include HTTParty
base_uri 'http://localhost:8529'
format :json
################################################################################
## create a collection
################################################################################
def self.create_collection (name, wait_for_sync = true)
body = "{ \"name\" : \"#{name}\", \"waitForSync\" : #{wait_for_sync} }"
doc = self.post("/_api/database/collection", :body => body)
if doc.code == 409
return doc.parsed_response['id']
end
if doc.code != 200
return nil
end
return doc.parsed_response['id']
end
################################################################################
## drop a collection
################################################################################
def self.drop_collection (name)
# TODO
end
################################################################################
## size of a collection
################################################################################
def self.size_collection (name)
doc = self.get("/document?collection=#{name}") # TODO use api call
return doc.parsed_response['documents'].length
end
################################################################################
## generate log file
################################################################################
def self.log (args)
if args.key?(:output)
logfile = File.new("logs/#{args[:output]}", "a")
else
logfile = File.new("output.log", "a")
end
method = args[:method] || :get
url = args[:url]
body = args[:body]
headers = args[:headers]
result = args[:result]
response = result.parsed_response
logfile.puts '-' * 80
h_option = ""
h_sep = ""
if headers
for k in [ "if-match", "if-none-match" ] do
if headers.key?(k)
h_option = h_option + h_sep + "'-H #{k}: #{headers[k]}'"
h_sep = " "
end
end
h_option = h_option + h_sep
end
if method == :get
logfile.puts "> curl -X GET #{h_option}--dump - http://localhost:8529#{url}"
logfile.puts
elsif method == :head
logfile.puts "> curl -X HEAD #{h_option}--dump - http://localhost:8529#{url}"
logfile.puts
elsif method == :delete
logfile.puts "> curl -X DELETE #{h_option}--dump - http://localhost:8529#{url}"
logfile.puts
elsif method == :post
if body == nil
logfile.puts "> curl -X POST #{h_option}--dump - http://localhost:8529#{url}"
logfile.puts
else
logfile.puts "> curl --data @- -X POST #{h_option}--dump - http://localhost:8529#{url}"
logfile.puts body
logfile.puts
end
elsif method == :put
if body == nil
logfile.puts "> curl -X PUT #{h_option}--dump - http://localhost:8529#{url}"
logfile.puts
else
logfile.puts "> curl --data @- -X PUT #{h_option}--dump - http://localhost:8529#{url}"
logfile.puts body
logfile.puts
end
else
logfile.puts "MISSING"
end
logfile.puts "HTTP/1.1 #{result.code} #{result.message}"
if result.headers.key?('content-type')
logfile.puts "content-type: #{result.headers['content-type']}"
end
if result.headers.key?('location')
logfile.puts "location: #{result.headers['location']}"
end
if result.headers.key?('etag')
logfile.puts "etag: #{result.headers['etag']}"
end
if response != nil
logfile.puts
logfile.puts JSON.pretty_generate(response)
end
logfile.close
end
end

View File

@ -0,0 +1,305 @@
require 'rspec'
require './avocadodb.rb'
describe AvocadoDB do
prefix = "rest_create-document"
context "creating a document:" do
################################################################################
## error handling
################################################################################
context "error handling:" do
it "returns an error if url contains a suffix" do
cmd = "/document/123456"
body = "{}"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(601)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-superfluous-suffix")
end
it "returns an error if collection idenifier is missing" do
cmd = "/document"
body = "{}"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1204)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-missing-cid")
end
it "returns an error if the collection identifier is unknown" do
cmd = "/document?collection=123456"
body = "{}"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1203)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-unknown-cid")
end
it "returns an error if the collection name is unknown" do
cmd = "/document?collection=unknown_collection"
body = "{}"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1203)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-unknown-name")
end
it "returns an error if the JSON body is corrupted" do
cn = "UnitTestsCollectionBasics"
id = AvocadoDB.create_collection(cn)
id.should be_kind_of(Integer)
id.should_not be_zero
cmd = "/document?collection=#{id}"
body = "{ 1 : 2 }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(600)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-bad-json")
AvocadoDB.size_collection(cn).should eq(0)
AvocadoDB.drop_collection(cn)
end
end
################################################################################
## known collection identifier, waitForSync = true
################################################################################
context "known collection identifier, waitForSync = true:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "creating a new document" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
etag = doc.headers['etag']
etag.should be_kind_of(String)
location = doc.headers['location']
location.should be_kind_of(String)
rev = doc.parsed_response['_rev']
rev.should be_kind_of(Integer)
did = doc.parsed_response['_id']
did.should be_kind_of(String)
match = /([0-9]*)\/([0-9]*)/.match(did)
match[1].should eq("#{@cid}")
etag.should eq("\"#{rev}\"")
location.should eq("/document/#{did}")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## known collection identifier, waitForSync = false
################################################################################
context "known collection identifier, waitForSync = false:" do
before do
@cn = "UnitTestsCollectionUnsynced"
@cid = AvocadoDB.create_collection(@cn, false)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "creating a new document" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(202)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
etag = doc.headers['etag']
etag.should be_kind_of(String)
location = doc.headers['location']
location.should be_kind_of(String)
rev = doc.parsed_response['_rev']
rev.should be_kind_of(Integer)
did = doc.parsed_response['_id']
did.should be_kind_of(String)
match = /([0-9]*)\/([0-9]*)/.match(did)
match[1].should eq("#{@cid}")
etag.should eq("\"#{rev}\"")
location.should eq("/document/#{did}")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-accept")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## known collection name
################################################################################
context "known collection name:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "creating a new document" do
cmd = "/document?collection=#{@cn}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
etag = doc.headers['etag']
etag.should be_kind_of(String)
location = doc.headers['location']
location.should be_kind_of(String)
rev = doc.parsed_response['_rev']
rev.should be_kind_of(Integer)
did = doc.parsed_response['_id']
did.should be_kind_of(String)
match = /([0-9]*)\/([0-9]*)/.match(did)
match[1].should eq("#{@cid}")
etag.should eq("\"#{rev}\"")
location.should eq("/document/#{did}")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-named-collection")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## unknown collection name
################################################################################
context "unknown collection name:" do
before do
@cn = "UnitTestsCollectionNamed#{Time.now.to_i}"
end
after do
AvocadoDB.drop_collection(@cn)
end
it "returns an error if collection is unknown" do
cmd = "/document?collection=#{@cn}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1203)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-unknown-collection-name")
end
it "create the collection and the document" do
cmd = "/document?collection=#{@cn}&createCollection=true"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(202)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
etag = doc.headers['etag']
etag.should be_kind_of(String)
location = doc.headers['location']
location.should be_kind_of(String)
rev = doc.parsed_response['_rev']
rev.should be_kind_of(Integer)
did = doc.parsed_response['_id']
did.should be_kind_of(String)
etag.should eq("\"#{rev}\"")
location.should eq("/document/#{did}")
AvocadoDB.log(:method => :post, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-create-collection")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cn).should eq(0)
end
end
end
end

View File

@ -0,0 +1,346 @@
require 'rspec'
require './avocadodb.rb'
describe AvocadoDB do
prefix = "rest_delete-document"
context "delete a document:" do
################################################################################
## error handling
################################################################################
context "error handling:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "returns an error if document handle is missing" do
cmd = "/document"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(400)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}-missing-handle")
end
it "returns an error if document handle is corrupted" do
cmd = "/document/123456"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(400)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}-bad-handle")
end
it "returns an error if document handle is corrupted" do
cmd = "/document//123456"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(600)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}-bad-handle2")
end
it "returns an error if collection identifier is unknown" do
cmd = "/document/123456/234567"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1203)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}-unknown-cid")
end
it "returns an error if document handle is unknown" do
cmd = "/document/#{@cid}/234567"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1202)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}-unknown-handle")
end
it "returns an error if the policy parameter is bad" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# delete document, different revision
cmd = "/document/#{did}?policy=last-write"
hdr = { "if-match" => "\"#{rev-1}\"" }
doc = AvocadoDB.delete(cmd, :headers => hdr)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :delete, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-policy-bad")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## deleting documents
################################################################################
context "deleting documents:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "create a document and delete it" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# delete document
cmd = "/document/#{did}"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(200)
doc.parsed_response['error'].should eq(false)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and delete it, using if-match" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# delete document, different revision
cmd = "/document/#{did}"
hdr = { "if-match" => "\"#{rev-1}\"" }
doc = AvocadoDB.delete(cmd, :headers => hdr)
doc.code.should eq(412)
doc.parsed_response['error'].should eq(true)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :delete, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-if-match-other")
# delete document, same revision
cmd = "/document/#{did}"
hdr = { "if-match" => "\"#{rev}\"" }
doc = AvocadoDB.delete(cmd, :headers => hdr)
doc.code.should eq(200)
doc.parsed_response['error'].should eq(false)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :delete, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-if-match")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and delete it, using if-match and last-write wins" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# delete document, different revision
cmd = "/document/#{did}?policy=last"
hdr = { "if-match" => "\"#{rev-1}\"" }
doc = AvocadoDB.delete(cmd, :headers => hdr)
doc.code.should eq(200)
doc.parsed_response['error'].should eq(false)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :delete, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-if-match-other-last-write")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and delete it, using rev" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# delete document, different revision
cmd = "/document/#{did}?rev=#{rev-1}"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(412)
doc.parsed_response['error'].should eq(true)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}-rev-other")
# delete document, same revision
cmd = "/document/#{did}?rev=#{rev}"
doc = AvocadoDB.delete(cmd)
doc.code.should eq(200)
doc.parsed_response['error'].should eq(false)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :delete, :url => cmd, :result => doc, :output => "#{prefix}-rev")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and delete it, using rev and last-write wins" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# delete document, different revision
cmd = "/document/#{did}?policy=last"
hdr = { "rev" => "\"#{rev-1}\"" }
doc = AvocadoDB.delete(cmd, :headers => hdr)
doc.code.should eq(200)
doc.parsed_response['error'].should eq(false)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :delete, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-rev-other-last-write")
AvocadoDB.size_collection(@cid).should eq(0)
end
end
end
end

View File

@ -0,0 +1,404 @@
require 'rspec'
require './avocadodb.rb'
describe AvocadoDB do
prefix = "rest_read-document"
context "reading a document:" do
################################################################################
## error handling
################################################################################
context "error handling:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "returns an error if document handle is corrupted" do
cmd = "/document/123456"
doc = AvocadoDB.get(cmd)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(601)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}-bad-handle")
end
it "returns an error if document handle is corrupted" do
cmd = "/document//123456"
doc = AvocadoDB.get(cmd)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(600)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}-bad-handle2")
end
it "returns an error if collection identifier is unknown" do
cmd = "/document/123456/234567"
doc = AvocadoDB.get(cmd)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1203)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}-unknown-cid")
end
it "returns an error if document handle is unknown" do
cmd = "/document/#{@cid}/234567"
doc = AvocadoDB.get(cmd)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1202)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}-unknown-handle")
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## reading documents
################################################################################
context "reading a document:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "create a document and read it" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# get document
cmd = "/document/#{did}"
doc = AvocadoDB.get(cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
etag = doc.headers['etag']
etag.should be_kind_of(String)
etag.should eq("\"#{rev}\"")
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and read it, use if-none-match" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# get document, if-none-match with same rev
cmd = "/document/#{did}"
hdr = { "if-none-match" => "\"#{rev}\"" }
doc = AvocadoDB.get(cmd, :headers => hdr)
doc.code.should eq(304)
etag = doc.headers['etag']
etag.should be_kind_of(String)
etag.should eq("\"#{rev}\"")
AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-if-none-match")
# get document, if-none-match with different rev
cmd = "/document/#{did}"
hdr = { "if-none-match" => "\"#{rev-1}\"" }
doc = AvocadoDB.get(cmd, :headers => hdr)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
etag = doc.headers['etag']
etag.should be_kind_of(String)
etag.should eq("\"#{rev}\"")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
etag = doc.headers['etag']
etag.should be_kind_of(String)
etag.should eq("\"#{rev}\"")
AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-if-none-match-other")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and read it, use if-match" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# get document, if-match with same rev
cmd = "/document/#{did}"
hdr = { "if-match" => "\"#{rev}\"" }
doc = AvocadoDB.get(cmd, :headers => hdr)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
etag = doc.headers['etag']
etag.should be_kind_of(String)
etag.should eq("\"#{rev}\"")
AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-if-match")
# get document, if-match with different rev
cmd = "/document/#{did}"
hdr = { "if-match" => "\"#{rev-1}\"" }
doc = AvocadoDB.get(cmd, :headers => hdr)
doc.code.should eq(412)
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :get, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-if-match-other")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## reading all documents
################################################################################
context "reading all documents:" do
before do
@cn = "UnitTestsCollectionAll"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "get all documents of an empty collection" do
cmd = "/document?collection=#{@cid}"
# get documents
cmd = "/document?collection=#{@cid}"
doc = AvocadoDB.get(cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
documents = doc.parsed_response['documents']
documents.should be_kind_of(Array)
documents.length.should eq(0)
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}-all-0")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create three documents and read them using the collection identifier" do
cmd = "/document?collection=#{@cid}"
location = []
for i in [ 1, 2, 3 ]
body = "{ \"Hallo\" : \"World-#{i}\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location.push(doc.headers['location'])
end
# get document
cmd = "/document?collection=#{@cid}"
doc = AvocadoDB.get(cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
documents = doc.parsed_response['documents']
documents.should be_kind_of(Array)
documents.length.should eq(3)
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}-all")
for l in location
AvocadoDB.delete(l)
end
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create three documents and read them using the collection name" do
cmd = "/document?collection=#{@cn}"
location = []
for i in [ 1, 2, 3 ]
body = "{ \"Hallo\" : \"World-#{i}\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location.push(doc.headers['location'])
end
# get document
cmd = "/document?collection=#{@cn}"
doc = AvocadoDB.get(cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
documents = doc.parsed_response['documents']
documents.should be_kind_of(Array)
documents.length.should eq(3)
AvocadoDB.log(:method => :get, :url => cmd, :result => doc, :output => "#{prefix}-all-name")
for l in location
AvocadoDB.delete(l)
end
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## checking document
################################################################################
context "checking a document:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "create a document and read it" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
# get document
cmd = location
doc = AvocadoDB.get(cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
content_length = doc.headers['content-length']
# get the document head
doc = AvocadoDB.head(cmd)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.headers['content-length'].should eq(content_length)
doc.body.should eq(nil)
AvocadoDB.log(:method => :head, :url => cmd, :result => doc, :output => "#{prefix}-head")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
end
end

View File

@ -0,0 +1,375 @@
require 'rspec'
require './avocadodb.rb'
describe AvocadoDB do
prefix = "rest_update-document"
context "update a document:" do
################################################################################
## error handling
################################################################################
context "error handling:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "returns an error if document handle is missing" do
cmd = "/document"
body = "{}"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(400)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-missing-handle")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "returns an error if document handle is corrupted" do
cmd = "/document/123456"
body = "{}"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(400)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-bad-handle")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "returns an error if document handle is corrupted" do
cmd = "/document//123456"
body = "{}"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(600)
doc.parsed_response['code'].should eq(400)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-bad-handle2")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "returns an error if collection identifier is unknown" do
cmd = "/document/123456/234567"
body = "{}"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1203)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-unknown-cid")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "returns an error if document handle is unknown" do
cmd = "/document/#{@cid}/234567"
body = "{}"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorNum'].should eq(1202)
doc.parsed_response['code'].should eq(404)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-unknown-handle")
AvocadoDB.size_collection(@cid).should eq(0)
end
it "returns an error if the policy parameter is bad" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# update document, different revision
cmd = "/document/#{did}?policy=last-write"
hdr = { "if-match" => "\"#{rev-1}\"" }
doc = AvocadoDB.put(cmd, :headers => hdr)
doc.code.should eq(400)
doc.parsed_response['error'].should eq(true)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
AvocadoDB.log(:method => :put, :url => cmd, :headers => hdr, :result => doc, :output => "#{prefix}-policy-bad")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
################################################################################
## updating documents
################################################################################
context "updating document:" do
before do
@cn = "UnitTestsCollectionBasics"
@cid = AvocadoDB.create_collection(@cn)
end
after do
AvocadoDB.drop_collection(@cn)
end
it "create a document and update it" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# update document
cmd = "/document/#{did}"
body = "{ \"World\" : \"Hallo\" }"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(200)
doc.parsed_response['error'].should eq(false)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should_not eq(rev)
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and update it, using if-match" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# update document, different revision
cmd = "/document/#{did}"
hdr = { "if-match" => "\"#{rev-1}\"" }
body = "{ \"World\" : \"Hallo\" }"
doc = AvocadoDB.put(cmd, :headers => hdr, :body => body)
doc.code.should eq(412)
doc.parsed_response['error'].should eq(true)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :headers => hdr, :result => doc, :output => "#{prefix}-if-match-other")
# update document, same revision
cmd = "/document/#{did}"
hdr = { "if-match" => "\"#{rev}\"" }
body = "{ \"World\" : \"Hallo\" }"
doc = AvocadoDB.put(cmd, :headers => hdr, :body => body)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should_not eq(rev)
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :headers => hdr, :result => doc, :output => "#{prefix}-if-match")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and update it, using if-match and last-write wins" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# update document, different revision
cmd = "/document/#{did}?policy=last"
hdr = { "if-match" => "\"#{rev-1}\"" }
body = "{ \"World\" : \"Hallo\" }"
doc = AvocadoDB.put(cmd, :headers => hdr, :body => body)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should_not eq(rev)
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :headers => hdr, :result => doc, :output => "#{prefix}-if-match-other-last-write")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and update it, using rev" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# update document, different revision
cmd = "/document/#{did}?rev=#{rev-1}"
body = "{ \"World\" : \"Hallo\" }"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(412)
doc.parsed_response['error'].should eq(true)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should eq(rev)
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-rev-other")
# update document, same revision
cmd = "/document/#{did}?rev=#{rev}"
body = "{ \"World\" : \"Hallo\" }"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should_not eq(rev)
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-rev")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
it "create a document and update it, using rev and last-write wins" do
cmd = "/document?collection=#{@cid}"
body = "{ \"Hallo\" : \"World\" }"
doc = AvocadoDB.post(cmd, :body => body)
doc.code.should eq(201)
location = doc.headers['location']
location.should be_kind_of(String)
did = doc.parsed_response['_id']
rev = doc.parsed_response['_rev']
# update document, different revision
cmd = "/document/#{did}?policy=last&rev=#{rev-1}"
body = "{ \"World\" : \"Hallo\" }"
doc = AvocadoDB.put(cmd, :body => body)
doc.code.should eq(200)
doc.headers['content-type'].should eq("application/json; charset=utf-8")
doc.parsed_response['error'].should eq(false)
did2 = doc.parsed_response['_id']
did2.should be_kind_of(String)
did2.should eq(did)
rev2 = doc.parsed_response['_rev']
rev2.should be_kind_of(Integer)
rev2.should_not eq(rev)
AvocadoDB.log(:method => :put, :url => cmd, :body => body, :result => doc, :output => "#{prefix}-rev-other-last-write")
AvocadoDB.delete(location)
AvocadoDB.size_collection(@cid).should eq(0)
end
end
end
end

View File

@ -0,0 +1,7 @@
#!/bin/sh
test -d logs || mkdir logs
rspec rest_create-document_spec.rb --format d
rspec rest_read-document_spec.rb --format d
rspec rest_update-document_spec.rb --format d
rspec rest_delete-document_spec.rb --format d

View File

@ -1121,9 +1121,6 @@ static void FreeJoinsQueryInstance (TRI_query_instance_t* const instance) {
static bool AddBindParameterValues (TRI_query_instance_t* const instance,
const TRI_json_t* parameters) {
TRI_bind_parameter_t* parameter;
void* nameParameter;
void* valueParameter;
size_t i;
assert(parameters);
@ -1136,6 +1133,10 @@ static bool AddBindParameterValues (TRI_query_instance_t* const instance,
}
for (i = 0; i < parameters->_value._objects._length; i += 2) {
void* nameParameter;
void* valueParameter;
TRI_bind_parameter_t* parameter;
nameParameter = TRI_AtVector(&parameters->_value._objects, i);
valueParameter = TRI_AtVector(&parameters->_value._objects, i + 1);
@ -1181,7 +1182,6 @@ static bool AddBindParameterValues (TRI_query_instance_t* const instance,
static bool ValidateBindParameters (TRI_query_instance_t* const instance) {
TRI_associative_pointer_t* templateParameters;
TRI_associative_pointer_t* instanceParameters;
TRI_bind_parameter_t* parameter;
size_t i;
templateParameters = &instance->_template->_bindParameters;
@ -1189,6 +1189,8 @@ static bool ValidateBindParameters (TRI_query_instance_t* const instance) {
// enumerate all template bind parameters....
for (i = 0; i < templateParameters->_nrAlloc; i++) {
TRI_bind_parameter_t* parameter;
parameter = (TRI_bind_parameter_t*) templateParameters->_table[i];
if (!parameter) {
continue;

View File

@ -29,7 +29,6 @@
#include "VocBase/query-cursor.h"
#include "VocBase/query-context.h"
#include "VocBase/query-locks.h"
// -----------------------------------------------------------------------------
// --SECTION-- private functions
@ -143,14 +142,12 @@ static uint32_t GetBatchSizeQueryCursor (const TRI_query_cursor_t* const cursor)
void TRI_FreeQueryCursor (TRI_query_cursor_t* cursor) {
FreeData(cursor);
if (cursor->_locks) {
TRI_FreeLocksQueryInstance(cursor->_vocbase, cursor->_locks);
}
TRI_DestroyMutex(&cursor->_lock);
TRI_DestroyVectorPointer(&cursor->_containers);
TRI_Free(cursor);
LOG_DEBUG("destroyed query cursor");
}
@ -201,6 +198,8 @@ TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const instance,
TRI_InitMutex(&cursor->_lock);
TRI_InitVectorPointer(&cursor->_containers);
LOG_DEBUG("created query cursor");
return cursor;
}

View File

@ -170,12 +170,6 @@ TRI_query_cursor_t* TRI_ExecuteQueryInstance (TRI_query_instance_t* const instan
cursor->_length = selectResult->_numRows;
cursor->_currentRow = 0;
if (cursor->_length > 0 && !instance->_query._select._isConstant) {
// we have a result set. the cursor now becomes responsible
// for freeing any locks we still have on the underlying collections
TRI_HandoverLocksQueryInstance(instance, cursor);
}
return cursor;
}

View File

@ -256,18 +256,6 @@ bool TRI_AddCollectionsBarrierQueryInstance (TRI_query_instance_t* const instanc
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hand over locks from query instance to result cursor
////////////////////////////////////////////////////////////////////////////////
void TRI_HandoverLocksQueryInstance (TRI_query_instance_t* const instance,
TRI_query_cursor_t* const cursor) {
cursor->_locks = instance->_locks;
instance->_locks = NULL;
// cursor is now responsible for freeing the locks
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a vector for holding collection locks
////////////////////////////////////////////////////////////////////////////////

View File

@ -109,19 +109,6 @@ void TRI_ReadUnlockCollectionsQueryInstance (TRI_query_instance_t* const);
bool TRI_AddCollectionsBarrierQueryInstance (TRI_query_instance_t* const,
TRI_query_cursor_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief hand over locks from query instance to result cursor
///
/// This function is called when there is a select result with at least one row.
/// The query instance will be freed immediately after executing the select,
/// but the result set cursor might still be in use. The underlying collections
/// are still needed and are still read-locked. When the cursor usage is over,
/// the cursor is responsible for freeing the locks held.
////////////////////////////////////////////////////////////////////////////////
void TRI_HandoverLocksQueryInstance (TRI_query_instance_t* const,
TRI_query_cursor_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief create a vector for holding collection locks
////////////////////////////////////////////////////////////////////////////////

View File

@ -77,6 +77,68 @@ static TRI_shadow_t* CreateShadow (const void* const data) {
return shadow;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief decrease the refcount for a shadow
////////////////////////////////////////////////////////////////////////////////
static void DecreaseRefCount (TRI_shadow_store_t* const store, TRI_shadow_t* const shadow) {
LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
if (--shadow->_rc <= 0 && shadow->_type == SHADOW_TRANSIENT) {
LOG_TRACE("deleting shadow %p", shadow);
TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
store->destroyShadow(shadow->_data);
TRI_Free(shadow);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief increase the refcount for a shadow
////////////////////////////////////////////////////////////////////////////////
static void IncreaseRefCount (TRI_shadow_store_t* const store, TRI_shadow_t* const shadow) {
LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
++shadow->_rc;
UpdateTimestampShadow(shadow);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the persistence flag for a shadow
////////////////////////////////////////////////////////////////////////////////
static void PersistShadow (TRI_shadow_t* const shadow) {
LOG_TRACE("persisting shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
shadow->_type = SHADOW_PERSISTENT;
UpdateTimestampShadow(shadow);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the deleted flag for a shadow
////////////////////////////////////////////////////////////////////////////////
static void DeleteShadow (TRI_shadow_store_t* const store, TRI_shadow_t* const shadow) {
LOG_TRACE("setting deleted flag for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
shadow->_deleted = true;
DecreaseRefCount(store, shadow);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an element in the ids index
////////////////////////////////////////////////////////////////////////////////
@ -260,13 +322,7 @@ void* TRI_BeginUsageDataShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && !shadow->_deleted) {
LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
++shadow->_rc;
UpdateTimestampShadow(shadow);
IncreaseRefCount(store, shadow);
TRI_UnlockMutex(&store->_lock);
return shadow->_data;
}
@ -292,13 +348,7 @@ void* TRI_BeginUsageIdShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, (void const*) &id);
if (shadow && !shadow->_deleted) {
LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
++shadow->_rc;
UpdateTimestampShadow(shadow);
IncreaseRefCount(store, shadow);
TRI_UnlockMutex(&store->_lock);
return shadow->_data;
}
@ -325,19 +375,7 @@ void TRI_EndUsageDataShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && !shadow->_deleted) {
LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
if (--shadow->_rc <= 0 && shadow->_type == SHADOW_TRANSIENT) {
LOG_TRACE("deleting shadow %p", shadow);
TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
TRI_RemoveKeyAssociativePointer(&store->_pointers, data);
store->destroyShadow(shadow->_data);
TRI_Free(shadow);
}
DecreaseRefCount(store, shadow); // this might delete the shadow
}
TRI_UnlockMutex(&store->_lock);
@ -361,19 +399,7 @@ void TRI_EndUsageIdShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
if (shadow && !shadow->_deleted) {
LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
if (--shadow->_rc <= 0 && shadow->_type == SHADOW_TRANSIENT) {
LOG_TRACE("deleting shadow %p", shadow);
TRI_RemoveKeyAssociativePointer(&store->_ids, &id);
TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
store->destroyShadow(shadow->_data);
TRI_Free(shadow);
}
DecreaseRefCount(store, shadow); // this might delete the shadow
}
TRI_UnlockMutex(&store->_lock);
@ -394,13 +420,7 @@ bool TRI_PersistDataShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && !shadow->_deleted) {
LOG_TRACE("persisting shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
shadow->_type = SHADOW_PERSISTENT;
UpdateTimestampShadow(shadow);
PersistShadow(shadow);
result = true;
}
@ -424,13 +444,7 @@ bool TRI_PersistIdShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
if (shadow && !shadow->_deleted) {
LOG_TRACE("persisting shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
shadow->_type = SHADOW_PERSISTENT;
UpdateTimestampShadow(shadow);
PersistShadow(shadow);
result = true;
}
@ -455,12 +469,7 @@ bool TRI_DeleteDataShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && !shadow->_deleted) {
LOG_TRACE("setting deleted flag for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
shadow->_deleted = true;
DeleteShadow(store, shadow);
found = true;
}
@ -485,12 +494,7 @@ bool TRI_DeleteIdShadowData (TRI_shadow_store_t* const store,
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
if (shadow && !shadow->_deleted) {
LOG_TRACE("setting deleted flag for shadow %p with data ptr %p and id %lu",
shadow,
shadow->_data,
(unsigned long) shadow->_id);
shadow->_deleted = true;
DeleteShadow(store, shadow);
found = true;
}

View File

@ -84,7 +84,7 @@ function getCursorResult(cursor) {
function postCursor(req, res) {
if (req.suffix.length != 0) {
actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
actions.resultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
return;
}
@ -92,7 +92,7 @@ function postCursor(req, res) {
var json = JSON.parse(req.requestBody);
if (!json || !(json instanceof Object)) {
actions.actionResultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid");
actions.resultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid");
return;
}
@ -104,23 +104,23 @@ function postCursor(req, res) {
(json.batchSize != undefined ? json.batchSize : 1000));
}
else {
actions.actionResultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid");
actions.resultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid");
return;
}
if (cursor instanceof AvocadoQueryError) {
// error occurred
actions.actionResultError (req, res, 404, cursor.code, cursor.message);
actions.resultError (req, res, 404, cursor.code, cursor.message);
return;
}
// this might dispose or persist the cursor
var result = getCursorResult(cursor);
actions.actionResultOK(req, res, 201, result);
actions.resultOk(req, res, 201, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.errorJavascriptException, "Javascript exception");
actions.resultError (req, res, 404, actions.errorJavascriptException, "Javascript exception");
}
}
@ -130,7 +130,7 @@ function postCursor(req, res) {
function putCursor(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
actions.resultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
return;
}
@ -142,10 +142,10 @@ function putCursor(req, res) {
}
// note: this might dispose or persist the cursor
actions.actionResultOK(req, res, 200, getCursorResult(cursor));
actions.resultOk(req, res, 200, getCursorResult(cursor));
}
catch (e) {
actions.actionResultError (req, res, 404, actions.errorCursorNotFound, "Cursor not found");
actions.resultError (req, res, 404, actions.errorCursorNotFound, "Cursor not found");
}
}
@ -155,7 +155,7 @@ function putCursor(req, res) {
function deleteCursor(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
actions.resultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
return;
}
@ -167,10 +167,10 @@ function deleteCursor(req, res) {
}
cursor.dispose();
actions.actionResultOK(req, res, 202, { "_id" : cursorId });
actions.resultOk(req, res, 202, { "_id" : cursorId });
}
catch (e) {
actions.actionResultError (req, res, 404, actions.errorCursorNotFound, "Cursor not found");
actions.resultError (req, res, 404, actions.errorCursorNotFound, "Cursor not found");
}
}
@ -201,7 +201,7 @@ actions.defineHttp({
break;
default:
actions.actionResultUnsupported(req, res);
actions.resultUnsupported(req, res);
}
}
});

View File

@ -74,7 +74,7 @@ actions.defineHttp({
for (var i = 0; i < collections.length; ++i) {
collection = collections[i];
result.push({ id : collection._id, name : collection._name });
result.push({ id : collection._id, name : collection.name() });
}
actions.result(req, res, actions.HTTP_OK, result);
@ -129,7 +129,7 @@ function GET_api_database_collection (req, res) {
var result = {};
result.id = collection._id;
result.name = collection._name;
result.name = collection.name();
actions.resultOk(req, res, actions.HTTP_OK, result);
}
@ -199,7 +199,7 @@ function POST_api_database_collection (req, res) {
actions.VERR_COLLECTION_EXISTS,
"collection already exists",
undefined,
{ name : collection._name, id : collection._id });
{ name : collection.name(), id : collection._id });
}
else {
collection = db[name];
@ -219,7 +219,7 @@ function POST_api_database_collection (req, res) {
var result = {};
result.id = collection._id;
result.name = collection._name;
result.name = collection.name();
collection.parameter({ waitForSync : waitForSync });

View File

@ -1,101 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief JavaScript actions modules
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Achim Brandt
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var actions = require("actions");
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
var API = "_api/";
var ApiRequests = {};
ApiRequests.cursor = {};
ApiRequests.cursor["POST /" + API + "cursor"] = "create and execute query. (creates a cursor)";
ApiRequests.cursor["PUT /" + API + "cursor/<cursor-id>"] = "get next results";
ApiRequests.cursor["DELETE /" + API + "cursor/<cursor-id>"] = "delete cursor";
ApiRequests.collection = {};
ApiRequests.collection["GET /" + API + "collections"] = "get list of collections";
ApiRequests.collection["GET /" + API + "collection/<collection-id>"] = "get all elements of collection";
ApiRequests.document = {};
ApiRequests.document["POST /" + API + "document/<collection-id>"] = "create new document";
ApiRequests.document["PUT /" + API + "document/<collection-id>/<document-id>"] = "update document";
ApiRequests.document["GET /" + API + "document/<collection-id>/<document-id>"] = "get a document";
ApiRequests.document["DELETE /" + API + "document/<collection-id>/<document-id>"] = "delete a document";
ApiRequests.query = {};
ApiRequests.query["POST /" + API + "query"] = "create a query";
ApiRequests.query["GET /" + API + "query/<query-id>"] = "get query";
ApiRequests.query["PUT /" + API + "query/<query-id>"] = "change query";
ApiRequests.query["DELETE /" + API + "query/<query-id>"] = "delete query";
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a help
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "help",
context : "api",
callback : function (req, res) {
var result = {
requests : ApiRequests
}
actions.actionResultOK(req, res, 200, result);
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -42,7 +42,7 @@ var actions = require("actions");
function postQuery(req, res) {
if (req.suffix.length != 0) {
actions.actionResultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
actions.resultError (req, res, 404, actions.errorInvalidRequest, "Invalid request");
return;
}
@ -50,22 +50,22 @@ function postQuery(req, res) {
var json = JSON.parse(req.requestBody);
if (!json || !(json instanceof Object) || json.query == undefined) {
actions.actionResultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid");
actions.resultError (req, res, 400, actions.errorQuerySpecificationInvalid, "Query specification invalid");
return;
}
var result = AQL_PARSE(json.query);
if (result instanceof AvocadoQueryError) {
actions.actionResultError (req, res, 404, result.code, result.message);
actions.resultError (req, res, 404, result.code, result.message);
return;
}
result = { "bindVars" : result };
actions.actionResultOK(req, res, 200, result);
actions.resultOk (req, res, 200, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.errorJavascriptException, "Javascript exception");
actions.resultError (req, res, 404, actions.errorJavascriptException, "Javascript exception");
}
}
@ -88,7 +88,7 @@ actions.defineHttp({
break;
default:
actions.actionResultUnsupported(req, res);
actions.resultUnsupported(req, res);
}
}
});

View File

@ -1,388 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief querying and managing collections
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Achim Brandt
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var actions = require("actions");
var API = "_api/";
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a collection
///
/// @REST{POST /_api/collection}
///
/// Creates an new collection with a given name. The request must contain an
/// object with the following attributes.
///
/// @LIT{name}: The name of the collection.
///
/// @LIT{waitForSync} (optional, default: false): If @LIT{true} then the data
/// is synchronised to disk before returning from a create or update of an
/// document.
///
/// @EXAMPLES
///
/// @verbinclude api-collection-create-collection
////////////////////////////////////////////////////////////////////////////////
function POST_api_collection (req, res) {
var body;
try {
body = JSON.parse(req.requestBody || "{}") || {};
}
catch (err) {
actions.resultBad(req, res, actions.ERROR_HTTP_CORRUPTED_JSON, err);
return;
}
var waitForSync = false;
if (! body.hasOwnProperty("name")) {
actions.resultBad(req, res, actions.ERROR_AVOCADO_ILLEGAL_NAME,
"name must be non-empty");
return;
}
var name = body.name;
if (body.hasOwnProperty("waitForSync")) {
waitForSync = body.waitForSync;
}
try {
var collection = db._create(name, waitForSync);
var result = {};
var headers = {};
collection.parameter({ waitForSync : waitForSync });
result.id = collection._id;
result.name = collection.name();
result.waitForSync = collection.parameter().waitForSync;
result.status = collection.status();
headers.location = "/" + API + "collection/" + collection._id;
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
catch (err) {
actions.resultException(req, res, err);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a collection
///
/// @REST{GET /_api/collection/@FA{collection-identifier}}
///
/// The result is an objects describing the collection with the following
/// attributes:
///
/// @LIT{id}: The identifier of the collection.
///
/// @LIT{name}: The name of the collection.
///
/// @LIT{waitForSync}: If @LIT{true} then creating or changing a document will
/// wait until the data has been synchronised to disk.
///
/// @LIT{status}: The status of the collection as number.
///
/// - 1: new born collection
/// - 2: unloaded
/// - 3: loaded
/// - 4: in the process of being unloaded
/// - 5: deleted
///
/// Every other status indicates a corrupted collection.
///
/// If the @FA{collection-identifier} is missing, then a @LIT{HTTP 400} is
/// returned. If the @FA{collection-identifier} is unknown, then a @LIT{HTTP
/// 404} is returned.
///
/// It is possible to specify a name instead of an identifier. In this case the
/// response will contain a field "Location" which contains the correct
/// location.
///
/// @REST{GET /_api/collection/@FA{collection-identifier}/count}
///
/// In addition to the above, the result also contains the number of documents.
/// Note that this will always load the collection into memory.
///
/// @LIT{count}: The number of documents inside the collection.
///
/// @REST{GET /_api/collection/@FA{collection-identifier}/figures}
///
/// In addition to the above, the result also contains the number of documents
/// and additional statistical information about the collection. Note that this
/// will always load the collection into memory.
///
/// @LIT{count}: The number of documents inside the collection.
///
/// @LIT{figures.alive.count}: The number of living documents.
///
/// @LIT{figures.alive.size}: The total size in bytes used by all living
/// documents.
///
/// @LIT{figures.dead.count}: The number of dead documents.
///
/// @LIT{figures.dead.size}: The total size in bytes used by all dead
/// documents.
///
/// @LIT{figures.datafile.count}: The number of active datafiles.
///
/// @LIT{journalSize}: The maximal size of the journal in bytes.
///
/// @EXAMPLES
///
/// Using an identifier:
///
/// @verbinclude api-collection-get-collection-identifier
///
/// Using a name:
///
/// @verbinclude api-collection-get-collection-name
///
/// Using an identifier and requesting the number of documents:
///
/// @verbinclude api-collection-get-collection-count
///
/// Using an identifier and requesting the figures of the collection:
///
/// @verbinclude api-collection-get-collection-figures
////////////////////////////////////////////////////////////////////////////////
function GET_api_collection (req, res) {
if (req.suffix.length == 0) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
"expected GET /" + API + "collection/<collection-identifer>")
}
else {
var name = decodeURIComponent(req.suffix[0]);
var id = parseInt(name) || name;
var collection = db._collection(id);
if (collection == null) {
actions.collectionNotFound(req, res, name);
}
else {
// .............................................................................
// /_api/collection/<identifier>
// .............................................................................
if (req.suffix.length == 1) {
var result = {};
var headers = {};
var parameter = collection.parameter();
result.id = collection._id;
result.name = collection.name();
result.waitForSync = parameter.waitForSync;
result.status = collection.status();
headers.location = "/" + API + "collection/" + collection._id;
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
else if (req.suffix.length == 2) {
var sub = decodeURIComponent(req.suffix[1]);
// .............................................................................
// /_api/collection/<identifier>/figures
// .............................................................................
if (sub == "figures") {
var result = {};
var headers = {};
var parameter = collection.parameter();
result.id = collection._id;
result.name = collection.name();
result.count = collection.count();
result.journalSize = parameter.journalSize;
result.waitForSync = parameter.waitForSync;
var figures = collection.figures();
if (figures) {
result.figures = {
alive : {
count : figures.numberAlive,
size : figures.sizeAlive
},
dead : {
count : figures.numberDead,
size : figures.sizeDead
},
datafiles : {
count : figures.numberDatafiles
}
};
}
result.status = collection.status();
headers.location = "/" + API + "collection/" + collection._id + "/figures";
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
// .............................................................................
// /_api/collection/<identifier>/count
// .............................................................................
else if (sub == "count") {
var result = {};
var headers = {};
var parameter = collection.parameter();
result.id = collection._id;
result.name = collection.name();
result.count = collection.count();
result.waitForSync = parameter.waitForSync;
result.status = collection.status();
headers.location = "/" + API + "collection/" + collection._id + "/count";
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
else {
actions.resultNotFound(req, res, "expecting one of the sub-method 'count', 'figures'");
}
}
else {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
"expect GET /" + API + "collection/<collection-identifer>/<method>")
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief deletes a collection
///
/// @REST{DELETE /_api/collection/@FA{collection-identifier}}
///
/// Deletes a collection identified by @FA{collection-identified}.
///
/// If the collection was successfully deleted then, an object is returned with
/// the following attributes:
///
/// @LIT{error}: @LIT{false}
///
/// @LIT{id}: The identifier of the deleted collection.
///
/// If the @FA{collection-identifier} is missing, then a @LIT{HTTP 400} is
/// returned. If the @FA{collection-identifier} is unknown, then a @LIT{HTTP
/// 404} is returned.
///
/// It is possible to specify a name instead of an identifier.
///
/// @EXAMPLES
///
/// Using an identifier:
///
/// @verbinclude api-collection-delete-collection-identifier
///
/// Using a name:
///
/// @verbinclude api-collection-delete-collection-name
////////////////////////////////////////////////////////////////////////////////
function DELETE_api_collection (req, res) {
if (req.suffix.length != 1) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
"expected DELETE /" + API + "collection/<collection-identifer>")
}
else {
var name = decodeURIComponent(req.suffix[0]);
var id = parseInt(name) || name;
var collection = db._collection(id);
if (collection == null) {
actions.collectionNotFound(req, res, name);
}
else {
try {
var result = {
id : collection._id
};
collection.drop();
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief reads or creates a collection
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "collection",
context : "api",
callback : function (req, res) {
if (req.requestType == actions.GET) {
GET_api_collection(req, res);
}
else if (req.requestType == actions.DELETE) {
DELETE_api_collection(req, res);
}
else if (req.requestType == actions.POST) {
POST_api_collection(req, res);
}
else {
actions.resultUnsupported(req, res);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -1,261 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief querying and managing collections
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Achim Brandt
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var actions = require("actions");
var API = "_api/database/";
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @fn JSA_GET_api_datebase_collections
/// @brief returns all collections
///
/// @REST{GET /_api/database/collections}
///
/// Returns all collections. The result is a list of objects with the following
/// attributes:
///
/// @FA{id}
///
/// The identifier of the collection.
///
/// @FA{name}
///
/// The name of the collection.
///
/// @EXAMPLES
///
/// @verbinclude api_database1
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "collections",
context : "api",
callback : function (req, res) {
if (req.requestType != actions.GET) {
actions.resultUnsupported(req, res);
}
else {
var collections = db._collections();
var result = [];
for (var i = 0; i < collections.length; ++i) {
collection = collections[i];
result.push({ id : collection._id, name : collection._name });
}
actions.result(req, res, actions.HTTP_OK, result);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief returns information about a collection
///
/// @REST{GET /_api/database/collection/@FA{collection-identifier}}
///
/// The result is an objects with the following attributes:
///
/// @FA{id}
///
/// The identifier of the collection.
///
/// @FA{name}
///
/// The name of the collection.
///
/// @EXAMPLES
///
/// Using a name:
///
/// @verbinclude api_database2
///
/// Using an identifier:
///
/// @verbinclude api_database3
////////////////////////////////////////////////////////////////////////////////
function GET_api_database_collection (req, res) {
if (req.suffix.length != 1) {
actions.collectionUnknown(req, res);
}
else {
var name = req.suffix[0];
var id = parseInt(name);
if (id != NaN) {
name = id;
}
var collection = db._collection(name);
if (collection == null) {
actions.collectionUnknown(req, res, name);
}
else {
var result = {};
result.id = collection._id;
result.name = collection._name;
actions.resultOk(req, res, actions.HTTP_OK, result);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new collection
///
/// @REST{POST /_api/database/collection}
///
/// Creates a new collection. If the collection could be create, a @LIT{HTTP 200}
/// is returned. If the collection already exists, a @LIT{HTTP 409} is
/// returned.
///
/// The call expects a JSON hash array as body with the following
/// attributes:
///
/// @FA{name}
///
/// The name of the collection.
///
/// @FA{waitForSync} (optional, default true)
///
/// If @FA{waitForSync} is false, then creation of documents will not wait
/// for the synchronization to file.
///
/// In case of success, returns information about the created collection:
///
/// @FA{id}
///
/// The identifier of the collection.
///
/// @FA{name}
///
/// The name of the collection.
///
/// @EXAMPLES
///
/// Create a collection named test:
///
/// @verbinclude api_database4
///
/// Try it again:
///
/// @verbinclude api_database5
////////////////////////////////////////////////////////////////////////////////
function POST_api_database_collection (req, res) {
var body = JSON.parse(req.requestBody || "{}");
var name = body.name;
var waitForSync = true;
if (body.hasOwnProperty("waitForSync")) {
waitForSync = body.waitForSync;
}
if (name == null) {
badParameter(req, res, "name");
}
else {
var collection = db._collection(name);
if (collection != null) {
actions.error(req, res,
actions.HTTP_CONFLICT,
actions.VERR_COLLECTION_EXISTS,
"collection already exists",
undefined,
{ name : collection._name, id : collection._id });
}
else {
collection = db[name];
if (collection == null) {
actions.badParameter(req, res, "cannot create collection named '" + name + "'");
}
else {
if (collection._id == 0) {
collection.load();
}
if (collection._id == 0) {
actions.badParameter(req, res, "cannot create collection named '" + name + "'");
}
else {
var result = {};
result.id = collection._id;
result.name = collection._name;
collection.parameter({ waitForSync : waitForSync });
actions.resultOk(req, res, actions.HTTP_OK, result);
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief reads or creates a collection
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "collection",
context : "api",
callback : function (req, res) {
if (req.requestType == actions.GET) {
GET_api_database_collection(req, res);
}
else if (req.requestType == actions.POST) {
POST_api_database_collection(req, res);
}
else {
actions.resultUnsupported(req, res);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -1,423 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief simple queries
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Achim Brandt
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var actions = require("actions");
var simple = require("simple-query");
var API = "_api/simple/";
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup AvocadoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @fn JSA_PUT_api_simple_all
/// @brief returns all documents of a collection
///
/// @REST{PUT /_api/simple/all}
///
/// Returns all documents of a collections. The call expects a JSON hash array
/// as body with the following attributes:
///
/// @FA{collection}
///
/// The identifier or name of the collection to query.
///
/// @FA{skip} (optional)
///
/// The documents to skip in the query.
///
/// @FA{limit} (optional)
///
/// The maximal amount of documents to return.
///
/// @EXAMPLES
///
/// To get all documents (NEVER DO THAT!)
///
/// @verbinclude api_simple1
///
/// Limit the amount of documents using
///
/// @verbinclude api_simple2
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "all",
context : "api",
callback : function (req, res) {
var body = JSON.parse(req.requestBody || "{}");
var limit = body.limit;
var skip = body.skip;
var name = body.collection;
if (req.requestType != actions.PUT) {
actions.unsupported(req, res);
}
else {
collection = db._collection(name);
if (collection == null) {
actions.collectionUnknown(req, res, name);
}
else {
var result = collection.all();
if (skip != null) {
result = result.skip(skip);
}
if (limit != null) {
result = result.limit(limit);
}
actions.result(req, res, actions.HTTP_OK, result.toArray());
}
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSA_PUT_api_simple_near
/// @brief returns all documents of a collection near a given location
///
/// @REST{PUT /_api/simple/near}
///
/// The default will find at most 100 documents near a given coordinate. The
/// returned list is sorted according to the distance, with the nearest document
/// coming first. If there are near documents of equal distance, documents are
/// chosen randomly from this set until the limit is reached. It is possible to
/// change the limit using the @FA{limit} operator.
///
/// In order to use the @FN{near} operator, a geo index must be defined for the
/// collection. This index also defines which attribute holds the coordinates
/// for the document. If you have more then one geo-spatial index, you can use
/// the @FN{geo} operator to select a particular index.
///
/// The call expects a JSON hash array as body with the following attributes:
///
/// @FA{collection}
///
/// The identifier or name of the collection to query.
///
/// @FA{latitude}
///
/// The latitude of the coordinate.
///
/// @FA{longitude}
///
/// The longitude of the coordinate.
///
/// @FA{distance} (optional)
///
/// If given, the attribute key used to store the distance.
///
/// @FA{skip} (optional)
///
/// The documents to skip in the query.
///
/// @FA{limit} (optional)
///
/// The maximal amount of documents to return.
///
/// @FA{geo} (optional)
///
/// If given, the identifier of the geo-index to use.
///
/// @EXAMPLES
///
/// Without distance:
///
/// @verbinclude api_simple3
///
/// With distance:
///
/// @verbinclude api_simple4
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "near",
context : "api",
callback : function (req, res) {
var body = JSON.parse(req.requestBody || "{}");
var limit = body.limit;
var skip = body.skip;
var latitude = body.latitude;
var longitude = body.longitude;
var distance = body.distance;
var name = body.collection;
var geo = body.geo;
if (req.requestType != actions.PUT) {
actions.unsupported(req, res);
}
else {
collection = db._collection(name);
if (collection == null) {
actions.collectionUnknown(req, res, name);
}
else if (latitude == null) {
actions.badParameter(req, res, "latitude");
}
else if (longitude == null) {
actions.badParameter(req, res, "longitude");
}
else {
var result;
if (geo == null) {
result = collection.near(latitude, longitude);
}
else {
result = collection.geo(geo).near(latitude, longitude);
}
if (skip != null) {
result = result.skip(skip);
}
if (limit != null) {
result = result.limit(limit);
}
if (distance != null) {
result = result.distance(distance);
}
actions.result(req, res, actions.HTTP_OK, result.toArray());
}
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSA_PUT_api_simple_within
/// @brief returns all documents of a collection within a given radius
///
/// @REST{PUT /_api/simple/within}
///
/// This will find all documents with in a given radius around the coordinate
/// (@FA{latitude}, @FA{longitude}). The returned list is sorted by distance.
///
/// In order to use the @FN{within} operator, a geo index must be defined for the
/// collection. This index also defines which attribute holds the coordinates
/// for the document. If you have more then one geo-spatial index, you can use
/// the @FN{geo} operator to select a particular index.
///
/// The call expects a JSON hash array as body with the following attributes:
///
/// @FA{collection}
///
/// The identifier or name of the collection to query.
///
/// @FA{latitude}
///
/// The latitude of the coordinate.
///
/// @FA{longitude}
///
/// The longitude of the coordinate.
///
/// @FA{radius}
///
/// The maximal radius.
///
/// @FA{distance} (optional)
///
/// If given, the attribute key used to store the distance.
///
/// @FA{skip} (optional)
///
/// The documents to skip in the query.
///
/// @FA{limit} (optional)
///
/// The maximal amount of documents to return.
///
/// @FA{geo} (optional)
///
/// If given, the identifier of the geo-index to use.
///
/// @EXAMPLES
///
/// Without distance:
///
/// @verbinclude api_simple5
///
/// With distance:
///
/// @verbinclude api_simple6
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "within",
context : "api",
callback : function (req, res) {
var body = JSON.parse(req.requestBody || "{}");
var limit = body.limit;
var skip = body.skip;
var latitude = body.latitude;
var longitude = body.longitude;
var distance = body.distance;
var radius = body.radius;
var name = body.collection;
var geo = body.geo;
if (req.requestType != actions.PUT) {
actions.unsupported(req, res);
}
else {
collection = db._collection(name);
if (collection == null) {
actions.collectionUnknown(req, res, name);
}
else if (latitude == null) {
actions.badParameter(req, res, "latitude");
}
else if (longitude == null) {
actions.badParameter(req, res, "longitude");
}
else {
var result;
if (geo == null) {
result = collection.within(latitude, longitude, radius);
}
else {
result = collection.geo(geo).within(latitude, longitude, radius);
}
if (skip != null) {
result = result.skip(skip);
}
if (limit != null) {
result = result.limit(limit);
}
if (distance != null) {
result = result.distance(distance);
}
actions.result(req, res, actions.HTTP_OK, result.toArray());
}
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSA_PUT_api_simple_by_example
/// @brief returns all documents of a collection matching a given example
///
/// @REST{PUT /_api/simple/by-example}
///
/// This will find all documents matching a given example.
///
/// The call expects a JSON hash array as body with the following attributes:
///
/// @FA{collection}
///
/// The identifier or name of the collection to query.
///
/// @FA{example}
///
/// The example.
///
/// @FA{skip} (optional)
///
/// The documents to skip in the query.
///
/// @FA{limit} (optional)
///
/// The maximal amount of documents to return.
///
/// @EXAMPLES
///
/// @verbinclude api_simple7
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : API + "by-example",
context : "api",
callback : function (req, res) {
var body = JSON.parse(req.requestBody || "{}");
var limit = body.limit;
var skip = body.skip;
var name = body.collection;
var example = body.example;
if (req.requestType != actions.PUT) {
actions.unsupported(req, res);
}
else {
collection = db._collection(name);
if (collection == null) {
actions.collectionUnknown(req, res, name);
}
else if (typeof example !== "object") {
actions.badParameter(req, res, "example");
}
else {
var result = collection.byExample(example);
if (skip != null) {
result = result.skip(skip);
}
if (limit != null) {
result = result.limit(limit);
}
actions.result(req, res, actions.HTTP_OK, result.toArray());
}
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -44,15 +44,16 @@ function getCollections(req, res) {
for (var i = skip; i < end; ++i) {
coll = colls[i];
result.collections[coll._name] = {
var name = coll.name();
result.collections[name] = {
_id : coll._id,
name : coll._name,
name : name,
status : coll.status(),
figures : coll.figures()
};
}
actions.actionResultOK(req, res, 200, result);
actions.resultOk(req, res, 200, result);
}
actions.defineHttp({
@ -66,7 +67,7 @@ actions.defineHttp({
break;
default:
actions.actionResultUnsupported(req, res);
actions.resultUnsupported(req, res);
}
}
});

View File

@ -1,127 +0,0 @@
var actions = require("actions");
function getDocument(req, res) {
if (req.suffix.length != 2) {
actions.actionResultError (req, res, 404, actions.documentNotFound, "Document not found");
return;
}
try {
var collection = decodeURIComponent(req.suffix[0]);
var documentId = decodeURIComponent(req.suffix[1]);
var result = {
"document" : {}
};
result.document = db[collection].document(documentId);
actions.actionResultOK(req, res, 200, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.documentNotFound, "Document not found: " + e);
}
}
function deleteDocument(req, res) {
if (req.suffix.length != 2) {
actions.actionResultError (req, res, 404, actions.documentNotFound, "Document not found");
return;
}
try {
var collection = decodeURIComponent(req.suffix[0]);
var documentId = decodeURIComponent(req.suffix[1]);
var result = {};
if (db[collection].delete(documentId)) {
result = {
"deleted" : true,
"_id" : documentId
};
actions.actionResultOK(req, res, 200, result);
}
else {
actions.actionResultError (req, res, 304, actions.documentNotModified, "Document not deleted");
}
}
catch (e) {
actions.actionResultError(req, res, 304, actions.documentNotModified, "Document not deleted: " + e);
}
}
function postDocument(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.collectionNotFound, "Collection not found");
return;
}
try {
var collection = decodeURIComponent(req.suffix[0]);
var json = JSON.parse(req.requestBody);
var id = db[collection].save(json);
var result = {
"created" : true,
"_id" : id
};
actions.actionResultOK(req, res, 201, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.documentNotModified, "Document not saved: " + e);
}
}
function putDocument(req, res) {
if (req.suffix.length != 2) {
actions.actionResultError (req, res, 404, actions.documentNotFound, "Document not found");
return;
}
try {
var collection = decodeURIComponent(req.suffix[0]);
var documentId = decodeURIComponent(req.suffix[1]);
var json = JSON.parse(req.requestBody);
var id = db[collection].replace(documentId, json);
var result = {
"updated" : true,
"_id" : id
};
actions.actionResultOK(req, res, 202, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.documentNotModified, "Document not changed: " + e);
}
}
actions.defineHttp({
url : "_api/document",
context : "api",
callback : function (req, res) {
switch (req.requestType) {
case ("GET") :
getDocument(req, res);
break;
case ("POST") :
postDocument(req, res);
break;
case ("PUT") :
putDocument(req, res);
break;
case ("DELETE") :
deleteDocument(req, res);
break;
default:
actions.actionResultUnsupported(req, res);
}
}
});

View File

@ -2,7 +2,7 @@ var actions = require("actions");
function getDocuments(req, res) {
if (req.suffix.length != 1) {
actions.actionResultError (req, res, 404, actions.collectionNotFound, "Collection not found");
actions.resultError (req, res, 404, actions.collectionNotFound, "Collection not found");
return;
}
@ -26,10 +26,10 @@ function getDocuments(req, res) {
try {
var result = db[collection].ALL(skip, limit);
actions.actionResultOK(req, res, 200, result);
actions.resultOk(req, res, 200, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.collectionNotFound, "Collection not found")
actions.resultError (req, res, 404, actions.collectionNotFound, "Collection not found")
}
}
@ -44,7 +44,7 @@ actions.defineHttp({
break;
default:
actions.actionResultUnsupported(req, res);
actions.resultUnsupported(req, res);
}
},

View File

@ -36,57 +36,6 @@ var actions = require("actions");
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief returns information about all collections
///
/// @REST{GET /_system/collections}
///
/// Returns information about all collections of the database. The returned
/// array contains the following entries.
///
/// - path: The server directory containing the database.
/// - collections : An associative array of all collections.
///
/// An entry of collections is again an associative array containing the
/// following entries.
///
/// - name: The name of the collection.
/// - status: The status of the collection. 1 = new born, 2 = unloaded,
/// 3 = loaded, 4 = corrupted.
///
/// @verbinclude rest15
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_system/collections",
context : "admin",
callback : function (req, res) {
var colls;
var coll;
var result;
colls = db._collections();
result = {
path : db._path,
collections : {}
};
for (var i = 0; i < colls.length; ++i) {
coll = colls[i];
result.collections[coll._name] = {
id : coll._id,
name : coll._name,
status : coll.status(),
figures : coll.figures()
};
}
actions.actionResult(req, res, 200, result);
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief loads a collection
///
@ -98,17 +47,17 @@ actions.defineHttp({
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_system/collection/load",
url : "_system/collection/load", // TODO -> api_collection.js
context : "admin",
callback : function (req, res) {
try {
req.collection.load();
actions.actionResult(req, res, 204);
actions.resultOk(req, res, 204);
}
catch (err) {
actions.actionError(req, res, err);
actions.resultError(req, res, err);
}
},
@ -117,61 +66,6 @@ actions.defineHttp({
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief information about a collection
///
/// @REST{GET /_system/collection/info?collection=@FA{identifier}}
///
/// Returns information about a collection
///
/// @verbinclude rest16
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_system/collection/info",
context : "admin",
callback : function (req, res) {
try {
result = {};
result.id = req.collection._id;
result.name = req.collection._name;
result.status = req.collection.status();
result.figures = req.collection.figures();
actions.actionResult(req, res, 200, result);
}
catch (err) {
actions.actionError(req, res, err);
}
},
parameters : {
collection : "collection-identifier"
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief returns information about all documents
///
/// @REST{GET /_system/documents}
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_system/documents",
context : "admin",
callback : function (req, res) {
queryReferences(req, res, req.collection.all());
},
parameters : {
collection : "collection-identifier",
blocksize : "number",
page : "number"
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief returns information about all indexes of a collection
///
@ -181,20 +75,20 @@ actions.defineHttp({
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_system/collection/indexes",
url : "_system/collection/indexes", // TODO api_indexes.js
context : "admin",
callback : function (req, res) {
try {
result = {};
result.name = req.collection._name;
result.name = req.collection.name();
result.id = req.collection._id;
result.indexes = req.collection.getIndexes();
actions.actionResult(req, res, 200, result);
actions.resultOk(req, res, 200, result);
}
catch (err) {
actions.actionError(req, res, err);
actions.resultError(req, res, err);
}
},
@ -210,7 +104,7 @@ actions.defineHttp({
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_system/status",
url : "_system/status", // TODO -> _api/system
context : "admin",
callback : function (req, res) {
@ -218,10 +112,10 @@ actions.defineHttp({
result = {};
result.system = SYS_PROCESS_STAT();
actions.actionResult(req, res, 200, result);
actions.resultOk(req, res, 200, result);
}
catch (err) {
actions.actionError(req, res, err);
actions.resultError(req, res, err);
}
}
});

View File

@ -113,7 +113,7 @@ function buildDocumentFromReq(req) {
function postKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not created. Missing key.");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not created. Missing key.");
return;
}
@ -121,7 +121,7 @@ function postKeyValue(req, res) {
var collection = req.suffix[0];
if (db._collection(collection) == null) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
return;
}
@ -131,7 +131,7 @@ function postKeyValue(req, res) {
s.execute();
if (s._countTotal != 0) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Use PUT to change value");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Use PUT to change value");
}
else {
var id = db[collection].save(doc);
@ -139,11 +139,11 @@ function postKeyValue(req, res) {
"saved" : true,
"_id" : id
}
actions.actionResultOK(req, res, 201, result);
actions.resultOk(req, res, 201, result);
}
}
catch (e) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not created. " + e.message);
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not created. " + e.message);
}
}
@ -153,7 +153,7 @@ function postKeyValue(req, res) {
function putKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
return;
}
@ -161,7 +161,7 @@ function putKeyValue(req, res) {
var collection = req.suffix[0];
if (db._collection(collection) == null) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
return;
}
@ -177,13 +177,13 @@ function putKeyValue(req, res) {
"saved" : true,
"_id" : id
}
actions.actionResultOK(req, res, 201, result);
actions.resultOk(req, res, 201, result);
return;
}
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
}
else if (s._countTotal > 1) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. Wrong key?");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. Wrong key?");
}
else {
// get _id
@ -197,15 +197,15 @@ function putKeyValue(req, res) {
// replace the document
if (db[collection].replace(id, doc)) {
actions.actionResultOK(req, res, 202, {"changed" : true});
actions.resultOk(req, res, 202, {"changed" : true});
}
else {
actions.actionResultError(req, res, 404, actions.keyValueNotModified, "Value not changed");
actions.resultError(req, res, 404, actions.keyValueNotModified, "Value not changed");
}
}
}
catch (e) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. " + e.message);
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. " + e.message);
}
}
@ -215,7 +215,7 @@ function putKeyValue(req, res) {
function deleteKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
return;
}
@ -223,7 +223,7 @@ function deleteKeyValue(req, res) {
var collection = req.suffix[0];
if (db._collection(collection) == null) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
return;
}
@ -237,23 +237,23 @@ function deleteKeyValue(req, res) {
s.execute();
if (s._countTotal < 1) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
}
else if (s._countTotal > 1) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. Wrong key?");
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. Wrong key?");
}
else {
var id = s._execution._documents[0]._id;
if (db[collection].delete(id)) {
actions.actionResultOK(req, res, 202, {"removed" : true});
actions.resultOk(req, res, 202, {"removed" : true});
}
else {
actions.actionResultError(req, res, 404, actions.keyValueNotModified, "Value not removed");
actions.resultError(req, res, 404, actions.keyValueNotModified, "Value not removed");
}
}
}
catch (e) {
actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. " + e.message);
actions.resultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. " + e.message);
}
}
@ -263,7 +263,7 @@ function deleteKeyValue(req, res) {
function getKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
actions.resultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
return;
}
@ -271,7 +271,7 @@ function getKeyValue(req, res) {
var collection = req.suffix[0];
if (db._collection(collection) == null) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Collection not found.");
actions.resultError (req, res, 404, actions.keyValueNotFound, "Collection not found.");
return;
}
@ -285,10 +285,10 @@ function getKeyValue(req, res) {
s.execute();
if (s._countTotal < 1) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
actions.resultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
}
else if (s._countTotal > 1) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found. Wrong key?");
actions.resultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found. Wrong key?");
}
else {
var headers = {};
@ -306,11 +306,11 @@ function getKeyValue(req, res) {
headers["x-voc-created"] = formatTimeStamp(s._execution._documents[0]["x-voc-created"]);
}
actions.actionResultOK(req, res, 200, s._execution._documents[0].value, headers);
actions.resultOk(req, res, 200, s._execution._documents[0].value, headers);
}
}
catch (e) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found. " + e.message);
actions.resultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found. " + e.message);
}
}
@ -345,7 +345,7 @@ actions.defineHttp({
break;
default:
actions.actionResultUnsupported(req, res);
actions.resultUnsupported(req, res);
}
}
});
@ -370,7 +370,7 @@ actions.defineHttp({
function searchKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pairs not found.");
actions.resultError (req, res, 404, actions.keyValueNotFound, "Key value pairs not found.");
return;
}
@ -378,7 +378,7 @@ function searchKeyValue(req, res) {
var collection = req.suffix[0];
if (db._collection(collection) == null) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Collection not found.");
actions.resultError (req, res, 404, actions.keyValueNotFound, "Collection not found.");
return;
}
@ -407,10 +407,10 @@ function searchKeyValue(req, res) {
}
}
actions.actionResult (req, res, 200, result);
actions.result (req, res, 200, result);
}
catch (e) {
actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pairs not found. " + e.message);
actions.resultError (req, res, 404, actions.keyValueNotFound, "Key value pairs not found. " + e.message);
}
}
@ -433,7 +433,7 @@ actions.defineHttp({
break;
default:
actions.actionResultUnsupported(req, res);
actions.resultUnsupported(req, res);
}
}
});

View File

@ -585,16 +585,8 @@ AvocadoDatabase.prototype._create = function (name) {
"name" : name
};
var str = this._connection.post("/_api/database/collection", JSON.stringify(body));
var requestResult = this._connection.post("/_api/collection", JSON.stringify(body));
print(str);
var requestResult = undefined;
if (str != undefined) {
requestResult = JSON.parse(str);
}
if (isErrorResult(requestResult)) {
return undefined;
}
@ -617,278 +609,7 @@ AvocadoDatabase.prototype._help = function () {
AvocadoDatabase.prototype.toString = function () {
return "[object AvocadoDatabase]";
}
/*
// -----------------------------------------------------------------------------
// --SECTION-- AvocadoStoredStatement
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////
function AvocadoStoredStatement (database, data) {
this._database = database;
this._doCount = false;
this._batchSize = null;
this._bindVars = {};
this._id = null;
this.document = {
"queryCollection" : DEFAULT_QUERY_COLLECTION
};
if (!(data instanceof Object)) {
throw "AvocadoStoredStatement needs a data attribute";
}
if (data["name"] != undefined) {
this.document.name = data["name"];
}
if (data["query"] != undefined) {
this.document.query = data["query"];
}
if (data["queryCollection"] != undefined) {
this.document.queryCollection = data["queryCollection"];
}
this._isNew = (data["query"] != undefined);
this.validate();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief update a stored statement
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.update = function (data) {
// update query string
if (data["query"] != undefined) {
this.document.query = data["query"];
}
this.validate();
var queryCollection = new AvocadoCollection(this._database, this.document.queryCollection);
if (!queryCollection) {
throw "Could not determine collection for AvocadoStoredStatement";
}
if (this._isNew) {
var requestResult = queryCollection.save(this.document);
if (requestResult == undefined) {
throw "Could not save AvocadoStoredStatement";
}
// document saved
this._id = requestResult;
this._isNew = false;
return true;
}
if (!queryCollection.update(this.document._id, this.document)) {
throw "Could not update AvocadoStoredStatement";
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief save a stored statement
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.save = function () {
return this.update(this.document);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate the data of an AvocadoStoredStatement
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.validate = function () {
if (this._isNew) {
if (this.document.query == undefined || this.document.query == "") {
throw "AvocadoStoredStatement needs a valid query";
}
}
if (this.document.name == undefined || this.document.name == "") {
throw "AvocadoStoredStatement needs a name attribute";
}
if (this.document.queryCollection == undefined || this.document.queryCollection == "") {
throw "AvocadoStoredStatement needs a queryCollection";
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief lookup the data of an AvocadoStoredStatement
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.lookup = function () {
if (this.isNew) {
throw "Cannot lookup a new AvocadoStoredStatement";
}
var data = {
"query" : "SELECT c FROM `" + this.document.queryCollection +
"` c WHERE c.name == '" + QuoteJSONString(this.document.name) + "'"
}
var statement = new AvocadoStatement(this._database, data);
var result = statement.execute();
if (result instanceof AvocadoQueryError) {
throw result.message;
}
if (!result.hasNext()) {
throw "Could not find stored statement for the given parameters";
}
var row = result.next();
this._id = row["id"];
this._query = row["query"];
this._isNew = false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief delete a stored statement
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.delete = function () {
if (this._isNew) {
throw "Cannot delete a new AvocadoStoredStatement";
}
if (this._id == undefined || this._id == null) {
this.lookup();
}
var queryCollection = new AvocadoCollection(this._database, this.document.collection);
if (!queryCollection) {
throw "Could not determine collection for AvocadoStoredStatement";
}
if (!queryCollection.delete(this.document._id)) {
this.document = {};
this._isNew = true;
this._bindVars = {};
this._id = null;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief bind a parameter to the statement
///
/// This function can be called multiple times, once for each bind parameter.
/// All bind parameters will be transferred to the server in one go when
/// execute() is called.
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.bind = function (key, value) {
if (typeof(key) != "string") {
throw "bind parameter name must be a string";
}
if (this._bindVars[key] != undefined) {
throw "redeclaration of bind parameter";
}
this._bindVars[key] = value;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the count flag for the statement
///
/// Setting the count flag will make the query instance's cursor return the
/// total number of result documents. The count flag is not set by default.
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.setCount = function (bool) {
this._doCount = bool ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the maximum number of results documents the cursor will return
/// in a single server roundtrip.
/// The higher this number is, the less server roundtrips will be made when
/// iterating over the result documents of a cursor.
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.setBatchSize = function (value) {
if (parseInt(value) > 0) {
this._batchSize = parseInt(value);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute the query
///
/// Invoking execute() will transfer the query and all bind parameters to the
/// server. It will return a cursor with the query results in case of success.
/// In case of an error, the error will be printed
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.execute = function () {
if (this._isNew) {
this.save();
}
var body = {
"name" : this.document.name,
"count" : this._doCount,
"bindVars" : this._bindVars,
"_id" : this._id
}
if (this._batchSize) {
body["batchSize"] = this._batchSize;
}
var requestResult = this._database._connection.post("/_api/cursor", JSON.stringify(body));
if (isErrorResult(requestResult)) {
return undefined;
}
return new AvocadoQueryCursor(this._database, requestResult);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief print the help for AvocadoStoredStatement
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype._help = function () {
print(helpAvocadoStoredStatement);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return a string representation of the stored statement
////////////////////////////////////////////////////////////////////////////////
AvocadoStoredStatement.prototype.toString = function () {
return getIdString(this, "AvocadoStoredStatement");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief factory method to create a new stored statement
////////////////////////////////////////////////////////////////////////////////
AvocadoDatabase.prototype._createStoredStatement = function (data) {
return new AvocadoStoredStatement(this, data);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief factory method to retrieve an existing stored statement
////////////////////////////////////////////////////////////////////////////////
AvocadoDatabase.prototype._getStoredStatement = function (data) {
return new AvocadoStoredStatement(this, data);
}
*/
// -----------------------------------------------------------------------------
// --SECTION-- AvocadoStatement
// -----------------------------------------------------------------------------
@ -977,7 +698,7 @@ AvocadoStatement.prototype.getCount = function () {
/// in a single server roundtrip.
////////////////////////////////////////////////////////////////////////////////
AvocadoStatement.prototype.getMax = function () {
AvocadoStatement.prototype.getBatchSize = function () {
return this._batchSize;
}
@ -1126,7 +847,7 @@ getHeadline("Select query help") +
' > st.setCount(<value>); set count flag (return number of ' + "\n" +
' results in "count" attribute) ' + "\n" +
'Get query options: ' + "\n" +
' > st.getMax(); return the max. number of results ' + "\n" +
' > st.setBatchSize(); return the max. number of results ' + "\n" +
' to be transferred per roundtrip ' + "\n" +
' > st.getCount(); return count flag (return number of' + "\n" +
' results in "count" attribute) ' + "\n" +
@ -1205,7 +926,7 @@ getHeadline("AvocadoStatement help") +
' to be transferred per roundtrip ' + "\n" +
' setCount(<value>); set count flag (return number of ' + "\n" +
' results in "count" attribute) ' + "\n" +
' getMax(); return max. number of results ' + "\n" +
' getBatchSize(); return max. number of results ' + "\n" +
' to be transferred per roundtrip ' + "\n" +
' getCount(); return count flag (return number of' + "\n" +
' results in "count" attribute) ' + "\n" +
@ -1221,32 +942,7 @@ getHeadline("AvocadoStatement help") +
' > st.bind("b", "world"); ' + "\n" +
' > c = st.execute(); ' + "\n" +
' > print(c.elements()); ';
/*
helpAvocadoStoredStatement =
getHeadline("AvocadoQueryTemplate help") +
'AvocadoQueryTemplate constructor: ' + "\n" +
' > qt1 = db._createQueryTemplate("select ..."); simple query ' + "\n" +
' > qt2 = db._createQueryTemplate( complex query ' + "\n" +
' {query:"select...", ' + "\n" +
' name:"qname", ' + "\n" +
' collection:"q" ' + "\n" +
' ... } ' + "\n" +
'Functions: ' + "\n" +
' update(<new data>); update query template ' + "\n" +
' delete(<id>); delete query template by id ' + "\n" +
' getInstance(); get a query instance ' + "\n" +
' returns: AvocadoQueryInstance' + "\n" +
' _help(); this help ' + "\n" +
'Attributes: ' + "\n" +
' _database database object ' + "\n" +
' _id template id ' + "\n" +
' name collection name ' + "\n" +
'Example: ' + "\n" +
' > qt1 = db._getQueryTemplate("4334:2334"); ' + "\n" +
' > qt1.update("select a from collA a"); ' + "\n" +
' > qi1 = qt1.getInstance(); ' + "\n" +
' > qt1.delete("4334:2334"); ';
*/
helpExtended =
getHeadline("More help") +
'Pager: ' + "\n" +

View File

@ -586,16 +586,8 @@ static string JS_client_client =
" \"name\" : name\n"
" };\n"
"\n"
" var str = this._connection.post(\"/_api/database/collection\", JSON.stringify(body));\n"
" var requestResult = this._connection.post(\"/_api/collection\", JSON.stringify(body));\n"
"\n"
" print(str);\n"
" \n"
" var requestResult = undefined;\n"
"\n"
" if (str != undefined) {\n"
" requestResult = JSON.parse(str);\n"
" }\n"
" \n"
" if (isErrorResult(requestResult)) {\n"
" return undefined;\n"
" }\n"
@ -618,278 +610,7 @@ static string JS_client_client =
"AvocadoDatabase.prototype.toString = function () { \n"
" return \"[object AvocadoDatabase]\";\n"
"}\n"
"/*\n"
"// -----------------------------------------------------------------------------\n"
"// --SECTION-- AvocadoStoredStatement\n"
"// -----------------------------------------------------------------------------\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief constructor\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AvocadoStoredStatement (database, data) {\n"
" this._database = database;\n"
" this._doCount = false;\n"
" this._batchSize = null;\n"
" this._bindVars = {};\n"
" this._id = null;\n"
" this.document = {\n"
" \"queryCollection\" : DEFAULT_QUERY_COLLECTION\n"
" };\n"
"\n"
" if (!(data instanceof Object)) {\n"
" throw \"AvocadoStoredStatement needs a data attribute\";\n"
" }\n"
" \n"
" if (data[\"name\"] != undefined) {\n"
" this.document.name = data[\"name\"];\n"
" }\n"
" \n"
" if (data[\"query\"] != undefined) {\n"
" this.document.query = data[\"query\"];\n"
" }\n"
"\n"
" if (data[\"queryCollection\"] != undefined) {\n"
" this.document.queryCollection = data[\"queryCollection\"];\n"
" } \n"
" \n"
" this._isNew = (data[\"query\"] != undefined); \n"
"\n"
" this.validate();\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief update a stored statement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.update = function (data) {\n"
" // update query string\n"
" if (data[\"query\"] != undefined) {\n"
" this.document.query = data[\"query\"];\n"
" }\n"
"\n"
" this.validate();\n"
"\n"
" var queryCollection = new AvocadoCollection(this._database, this.document.queryCollection);\n"
" if (!queryCollection) {\n"
" throw \"Could not determine collection for AvocadoStoredStatement\";\n"
" }\n"
"\n"
" if (this._isNew) {\n"
" var requestResult = queryCollection.save(this.document);\n"
" if (requestResult == undefined) {\n"
" throw \"Could not save AvocadoStoredStatement\";\n"
" }\n"
"\n"
" // document saved\n"
" this._id = requestResult;\n"
" this._isNew = false;\n"
" return true;\n"
" }\n"
"\n"
" if (!queryCollection.update(this.document._id, this.document)) {\n"
" throw \"Could not update AvocadoStoredStatement\";\n"
" }\n"
" \n"
" return true;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief save a stored statement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.save = function () {\n"
" return this.update(this.document);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief validate the data of an AvocadoStoredStatement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.validate = function () {\n"
" if (this._isNew) {\n"
" if (this.document.query == undefined || this.document.query == \"\") {\n"
" throw \"AvocadoStoredStatement needs a valid query\";\n"
" }\n"
" }\n"
"\n"
" if (this.document.name == undefined || this.document.name == \"\") {\n"
" throw \"AvocadoStoredStatement needs a name attribute\";\n"
" }\n"
" \n"
" if (this.document.queryCollection == undefined || this.document.queryCollection == \"\") {\n"
" throw \"AvocadoStoredStatement needs a queryCollection\";\n"
" }\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief lookup the data of an AvocadoStoredStatement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.lookup = function () {\n"
" if (this.isNew) {\n"
" throw \"Cannot lookup a new AvocadoStoredStatement\";\n"
" }\n"
"\n"
" var data = {\n"
" \"query\" : \"SELECT c FROM `\" + this.document.queryCollection + \n"
" \"` c WHERE c.name == '\" + QuoteJSONString(this.document.name) + \"'\"\n"
" } \n"
" var statement = new AvocadoStatement(this._database, data);\n"
" var result = statement.execute();\n"
" if (result instanceof AvocadoQueryError) {\n"
" throw result.message;\n"
" }\n"
"\n"
" if (!result.hasNext()) {\n"
" throw \"Could not find stored statement for the given parameters\";\n"
" }\n"
"\n"
" var row = result.next();\n"
" this._id = row[\"id\"];\n"
" this._query = row[\"query\"];\n"
" this._isNew = false;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief delete a stored statement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.delete = function () {\n"
" if (this._isNew) {\n"
" throw \"Cannot delete a new AvocadoStoredStatement\";\n"
" }\n"
" \n"
" if (this._id == undefined || this._id == null) {\n"
" this.lookup();\n"
" }\n"
"\n"
" var queryCollection = new AvocadoCollection(this._database, this.document.collection);\n"
" if (!queryCollection) {\n"
" throw \"Could not determine collection for AvocadoStoredStatement\";\n"
" }\n"
"\n"
" if (!queryCollection.delete(this.document._id)) {\n"
" this.document = {};\n"
" this._isNew = true;\n"
" this._bindVars = {};\n"
" this._id = null;\n"
" return true;\n"
" }\n"
" \n"
" return false;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief bind a parameter to the statement\n"
"///\n"
"/// This function can be called multiple times, once for each bind parameter.\n"
"/// All bind parameters will be transferred to the server in one go when \n"
"/// execute() is called.\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.bind = function (key, value) {\n"
" if (typeof(key) != \"string\") {\n"
" throw \"bind parameter name must be a string\";\n"
" }\n"
"\n"
" if (this._bindVars[key] != undefined) {\n"
" throw \"redeclaration of bind parameter\";\n"
" }\n"
"\n"
" this._bindVars[key] = value;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief set the count flag for the statement\n"
"///\n"
"/// Setting the count flag will make the query instance's cursor return the\n"
"/// total number of result documents. The count flag is not set by default.\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.setCount = function (bool) {\n"
" this._doCount = bool ? true : false;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief set the maximum number of results documents the cursor will return\n"
"/// in a single server roundtrip.\n"
"/// The higher this number is, the less server roundtrips will be made when\n"
"/// iterating over the result documents of a cursor.\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.setBatchSize = function (value) {\n"
" if (parseInt(value) > 0) {\n"
" this._batchSize = parseInt(value);\n"
" }\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief execute the query\n"
"///\n"
"/// Invoking execute() will transfer the query and all bind parameters to the\n"
"/// server. It will return a cursor with the query results in case of success.\n"
"/// In case of an error, the error will be printed\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.execute = function () {\n"
" if (this._isNew) {\n"
" this.save();\n"
" }\n"
" \n"
" var body = {\n"
" \"name\" : this.document.name,\n"
" \"count\" : this._doCount,\n"
" \"bindVars\" : this._bindVars,\n"
" \"_id\" : this._id\n"
" }\n"
"\n"
" if (this._batchSize) {\n"
" body[\"batchSize\"] = this._batchSize;\n"
" }\n"
" \n"
" var requestResult = this._database._connection.post(\"/_api/cursor\", JSON.stringify(body));\n"
" \n"
" if (isErrorResult(requestResult)) {\n"
" return undefined;\n"
" }\n"
"\n"
" return new AvocadoQueryCursor(this._database, requestResult);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief print the help for AvocadoStoredStatement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype._help = function () {\n"
" print(helpAvocadoStoredStatement);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief return a string representation of the stored statement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStoredStatement.prototype.toString = function () { \n"
" return getIdString(this, \"AvocadoStoredStatement\");\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief factory method to create a new stored statement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoDatabase.prototype._createStoredStatement = function (data) { \n"
" return new AvocadoStoredStatement(this, data);\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief factory method to retrieve an existing stored statement\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoDatabase.prototype._getStoredStatement = function (data) { \n"
" return new AvocadoStoredStatement(this, data);\n"
"}\n"
"\n"
"*/\n"
"// -----------------------------------------------------------------------------\n"
"// --SECTION-- AvocadoStatement\n"
"// -----------------------------------------------------------------------------\n"
@ -978,7 +699,7 @@ static string JS_client_client =
"/// in a single server roundtrip.\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"AvocadoStatement.prototype.getMax = function () {\n"
"AvocadoStatement.prototype.getBatchSize = function () {\n"
" return this._batchSize;\n"
"}\n"
"\n"
@ -1127,7 +848,7 @@ static string JS_client_client =
"' > st.setCount(<value>); set count flag (return number of ' + \"\\n\" +\n"
"' results in \"count\" attribute) ' + \"\\n\" +\n"
"'Get query options: ' + \"\\n\" +\n"
"' > st.getMax(); return the max. number of results ' + \"\\n\" +\n"
"' > st.setBatchSize(); return the max. number of results ' + \"\\n\" +\n"
"' to be transferred per roundtrip ' + \"\\n\" +\n"
"' > st.getCount(); return count flag (return number of' + \"\\n\" +\n"
"' results in \"count\" attribute) ' + \"\\n\" +\n"
@ -1206,7 +927,7 @@ static string JS_client_client =
"' to be transferred per roundtrip ' + \"\\n\" +\n"
"' setCount(<value>); set count flag (return number of ' + \"\\n\" +\n"
"' results in \"count\" attribute) ' + \"\\n\" +\n"
"' getMax(); return max. number of results ' + \"\\n\" +\n"
"' getBatchSize(); return max. number of results ' + \"\\n\" +\n"
"' to be transferred per roundtrip ' + \"\\n\" +\n"
"' getCount(); return count flag (return number of' + \"\\n\" +\n"
"' results in \"count\" attribute) ' + \"\\n\" +\n"
@ -1222,32 +943,7 @@ static string JS_client_client =
"' > st.bind(\"b\", \"world\"); ' + \"\\n\" +\n"
"' > c = st.execute(); ' + \"\\n\" +\n"
"' > print(c.elements()); ';\n"
"/*\n"
"helpAvocadoStoredStatement = \n"
"getHeadline(\"AvocadoQueryTemplate help\") +\n"
"'AvocadoQueryTemplate constructor: ' + \"\\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"
"'Functions: ' + \"\\n\" +\n"
"' update(<new data>); update query template ' + \"\\n\" +\n"
"' delete(<id>); delete query template by id ' + \"\\n\" +\n"
"' getInstance(); get a query instance ' + \"\\n\" +\n"
"' returns: AvocadoQueryInstance' + \"\\n\" +\n"
"' _help(); this help ' + \"\\n\" +\n"
"'Attributes: ' + \"\\n\" +\n"
"' _database database object ' + \"\\n\" +\n"
"' _id template id ' + \"\\n\" +\n"
"' name collection name ' + \"\\n\" +\n"
"'Example: ' + \"\\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"
"*/\n"
"\n"
"helpExtended = \n"
"getHeadline(\"More help\") +\n"
"'Pager: ' + \"\\n\" +\n"

View File

@ -16,7 +16,9 @@ ModuleCache["/internal"].exports.errors = {
"ERROR_DEAD_PID" : { "code" : 8, "message" : "dead process identifier" },
"ERROR_NOT_IMPLEMENTED" : { "code" : 9, "message" : "not implemented" },
"ERROR_HTTP_BAD_PARAMETER" : { "code" : 400, "message" : "bad parameter" },
"ERROR_HTTP_NOT_FOUND" : { "code" : 404, "message" : "not found" },
"ERROR_HTTP_METHOD_NOT_ALLOWED" : { "code" : 405, "message" : "method not supported" },
"ERROR_HTTP_SERVER_ERROR" : { "code" : 500, "message" : "internal server error" },
"ERROR_HTTP_CORRUPTED_JSON" : { "code" : 600, "message" : "invalid JSON object" },
"ERROR_HTTP_SUPERFLUOUS_SUFFICES" : { "code" : 601, "message" : "superfluous URL suffices" },
"ERROR_AVOCADO_ILLEGAL_STATE" : { "code" : 1000, "message" : "illegal state" },

View File

@ -17,7 +17,9 @@ static string JS_common_bootstrap_errors =
" \"ERROR_DEAD_PID\" : { \"code\" : 8, \"message\" : \"dead process identifier\" }, \n"
" \"ERROR_NOT_IMPLEMENTED\" : { \"code\" : 9, \"message\" : \"not implemented\" }, \n"
" \"ERROR_HTTP_BAD_PARAMETER\" : { \"code\" : 400, \"message\" : \"bad parameter\" }, \n"
" \"ERROR_HTTP_NOT_FOUND\" : { \"code\" : 404, \"message\" : \"not found\" }, \n"
" \"ERROR_HTTP_METHOD_NOT_ALLOWED\" : { \"code\" : 405, \"message\" : \"method not supported\" }, \n"
" \"ERROR_HTTP_SERVER_ERROR\" : { \"code\" : 500, \"message\" : \"internal server error\" }, \n"
" \"ERROR_HTTP_CORRUPTED_JSON\" : { \"code\" : 600, \"message\" : \"invalid JSON object\" }, \n"
" \"ERROR_HTTP_SUPERFLUOUS_SUFFICES\" : { \"code\" : 601, \"message\" : \"superfluous URL suffices\" }, \n"
" \"ERROR_AVOCADO_ILLEGAL_STATE\" : { \"code\" : 1000, \"message\" : \"illegal state\" }, \n"