1
0
Fork 0

allow using `returnOld` and `returnNew` attributes in HTTP REST APIs … (#4479)

This commit is contained in:
Jan 2018-02-09 14:50:56 +01:00 committed by GitHub
parent 8da61a9875
commit 42dd337152
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 367 additions and 41 deletions

View File

@ -1,6 +1,15 @@
devel devel
----- -----
* support `returnOld` and `returnNew` attributes for in the following HTTP REST
APIs:
* /_api/gharial/<graph>/vertex/<collection>
* /_api/gharial/<graph>/edge/<collection>
The exception from this is that the HTTP DELETE verb for these APIs does not
support `returnOld` because that would make the existing API incompatible
* fixed issue #4160: Run arangod with "--database.auto-upgrade" option always crash silently without error log * fixed issue #4160: Run arangod with "--database.auto-upgrade" option always crash silently without error log
* fix issue #4457: create /var/tmp/arangod with correct user in supervisor mode * fix issue #4457: create /var/tmp/arangod with correct user in supervisor mode

View File

@ -110,9 +110,12 @@ describe ArangoDB do
return doc return doc
end end
def create_vertex (waitForSync, graph_name, collection, body) def create_vertex (waitForSync, graph_name, collection, body, options = {})
cmd = vertex_endpoint(graph_name, collection) cmd = vertex_endpoint(graph_name, collection)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.post(cmd, :body => JSON.dump(body)) doc = ArangoDB.post(cmd, :body => JSON.dump(body))
return doc return doc
end end
@ -123,36 +126,48 @@ describe ArangoDB do
return doc return doc
end end
def update_vertex (waitForSync, graph_name, collection, key, body, keepNull = '') def update_vertex (waitForSync, graph_name, collection, key, body, keepNull = '', options = {})
cmd = vertex_endpoint(graph_name, collection, key) cmd = vertex_endpoint(graph_name, collection, key)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
if keepNull != '' then if keepNull != '' then
cmd = cmd + "&keepNull=#{keepNull}" cmd = cmd + "&keepNull=#{keepNull}"
end end
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.patch(cmd, :body => JSON.dump(body)) doc = ArangoDB.patch(cmd, :body => JSON.dump(body))
return doc return doc
end end
def replace_vertex (waitForSync, graph_name, collection, key, body) def replace_vertex (waitForSync, graph_name, collection, key, body, options = {})
cmd = vertex_endpoint(graph_name, collection, key) cmd = vertex_endpoint(graph_name, collection, key)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.put(cmd, :body => JSON.dump(body)) doc = ArangoDB.put(cmd, :body => JSON.dump(body))
return doc return doc
end end
def delete_vertex (waitForSync, graph_name, collection, key) def delete_vertex (waitForSync, graph_name, collection, key, options = {})
cmd = vertex_endpoint(graph_name, collection, key) cmd = vertex_endpoint(graph_name, collection, key)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.delete(cmd) doc = ArangoDB.delete(cmd)
return doc return doc
end end
def create_edge (waitForSync, graph_name, collection, from, to, body) def create_edge (waitForSync, graph_name, collection, from, to, body, options = {})
cmd = edge_endpoint(graph_name, collection) cmd = edge_endpoint(graph_name, collection)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
body["_from"] = from body["_from"] = from
body["_to"] = to body["_to"] = to
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.post(cmd, :body => JSON.dump(body)) doc = ArangoDB.post(cmd, :body => JSON.dump(body))
return doc return doc
end end
@ -163,26 +178,35 @@ describe ArangoDB do
return doc return doc
end end
def update_edge (waitForSync, graph_name, collection, key, body, keepNull = '') def update_edge (waitForSync, graph_name, collection, key, body, keepNull = '', options = {})
cmd = edge_endpoint(graph_name, collection, key) cmd = edge_endpoint(graph_name, collection, key)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
if keepNull != '' then if keepNull != '' then
cmd = cmd + "&keepNull=#{keepNull}" cmd = cmd + "&keepNull=#{keepNull}"
end end
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.patch(cmd, :body => JSON.dump(body)) doc = ArangoDB.patch(cmd, :body => JSON.dump(body))
return doc return doc
end end
def replace_edge (waitForSync, graph_name, collection, key, body) def replace_edge (waitForSync, graph_name, collection, key, body, options = {})
cmd = edge_endpoint(graph_name, collection, key) cmd = edge_endpoint(graph_name, collection, key)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.put(cmd, :body => JSON.dump(body)) doc = ArangoDB.put(cmd, :body => JSON.dump(body))
return doc return doc
end end
def delete_edge (waitForSync, graph_name, collection, key) def delete_edge (waitForSync, graph_name, collection, key, options = {})
cmd = edge_endpoint(graph_name, collection, key) cmd = edge_endpoint(graph_name, collection, key)
cmd = cmd + "?waitForSync=#{waitForSync}" cmd = cmd + "?waitForSync=#{waitForSync}"
options.each do |key,value|
cmd = cmd + "&" + key + "=" + value.to_s
end
doc = ArangoDB.delete(cmd) doc = ArangoDB.delete(cmd)
return doc return doc
end end
@ -417,6 +441,22 @@ describe ArangoDB do
doc.parsed_response['error'].should eq(false) doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 201 : 202) doc.parsed_response['code'].should eq(sync ? 201 : 202)
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag']) doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
end
it "can create a vertex, returnNew" do
name = "Alice"
doc = create_vertex( sync, graph_name, user_collection, {"name" => name}, { "returnNew" => "true" })
doc.code.should eq(sync ? 201 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 201 : 202)
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new']['_key'].should_not eq(nil)
doc.parsed_response['new']['name'].should eq(name)
end end
it "can get a vertex" do it "can get a vertex" do
@ -458,6 +498,39 @@ describe ArangoDB do
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag']) doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['vertex']['_key'].should eq(key) doc.parsed_response['vertex']['_key'].should eq(key)
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
doc = get_vertex(graph_name, user_collection, key)
doc.parsed_response['vertex']['name'].should eq(nil)
doc.parsed_response['vertex']['name2'].should eq(name)
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
oldTag.should_not eq(doc.headers['etag'])
doc.parsed_response['vertex']['_key'].should eq(key)
end
it "can replace a vertex, returnOld" do
name = "Alice"
doc = create_vertex( sync, graph_name, user_collection, {"name" => name})
key = doc.parsed_response['vertex']['_key']
oldTag = doc.parsed_response['vertex']['_rev']
oldTag.should eq(doc.headers['etag'])
name = "Bob"
doc = replace_vertex( sync, graph_name, user_collection, key, {"name2" => name}, { "returnOld" => "true", "returnNew" => true })
doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['vertex']['_key'].should eq(key)
doc.parsed_response['old']['_key'].should eq(key)
doc.parsed_response['old']['name'].should eq("Alice")
doc.parsed_response['old']['name2'].should eq(nil)
doc.parsed_response['new']['_key'].should eq(key)
doc.parsed_response['new']['name'].should eq(nil)
doc.parsed_response['new']['name2'].should eq("Bob")
doc = get_vertex(graph_name, user_collection, key) doc = get_vertex(graph_name, user_collection, key)
doc.parsed_response['vertex']['name'].should eq(nil) doc.parsed_response['vertex']['name'].should eq(nil)
doc.parsed_response['vertex']['name2'].should eq(name) doc.parsed_response['vertex']['name2'].should eq(name)
@ -489,6 +562,36 @@ describe ArangoDB do
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag']) doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['vertex']['_key'].should eq(key) doc.parsed_response['vertex']['_key'].should eq(key)
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
doc = get_vertex(graph_name, user_collection, key)
doc.parsed_response['vertex']['name'].should eq(name)
doc.parsed_response['vertex']['name2'].should eq(name2)
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['vertex']['_key'].should eq(key)
end
it "can update a vertex, returnOld" do
name = "Alice"
doc = create_vertex( sync, graph_name, user_collection, {"name" => name})
key = doc.parsed_response['vertex']['_key']
name2 = "Bob"
doc = update_vertex( sync, graph_name, user_collection, key, {"name2" => name2}, "", { "returnOld" => "true", "returnNew" => "true" })
doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['vertex']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['vertex']['_key'].should eq(key)
doc.parsed_response['old']['_key'].should eq(key)
doc.parsed_response['old']['name'].should eq(name)
doc.parsed_response['old']['name2'].should eq(nil)
doc.parsed_response['new']['_key'].should eq(key)
doc.parsed_response['new']['name'].should eq(name)
doc.parsed_response['new']['name2'].should eq(name2)
doc = get_vertex(graph_name, user_collection, key) doc = get_vertex(graph_name, user_collection, key)
doc.parsed_response['vertex']['name'].should eq(name) doc.parsed_response['vertex']['name'].should eq(name)
doc.parsed_response['vertex']['name2'].should eq(name2) doc.parsed_response['vertex']['name2'].should eq(name2)
@ -545,6 +648,29 @@ describe ArangoDB do
doc.code.should eq(sync ? 200 : 202) doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false) doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202) doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
doc = get_vertex(graph_name, user_collection, key)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorMessage'].should include("document not found")
doc.parsed_response['code'].should eq(404)
end
it "can delete a vertex, returnOld" do
name = "Alice"
doc = create_vertex( sync, graph_name, user_collection, {"name" => name})
key = doc.parsed_response['vertex']['_key']
doc = delete_vertex( sync, graph_name, user_collection, key, { "returnOld" => "true" })
doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['removed'].should eq(true)
doc.parsed_response['old']['_key'].should eq(key)
doc.parsed_response['old']['name'].should eq(name)
doc.parsed_response['new'].should eq(nil)
doc = get_vertex(graph_name, user_collection, key) doc = get_vertex(graph_name, user_collection, key)
doc.code.should eq(404) doc.code.should eq(404)
@ -587,10 +713,30 @@ describe ArangoDB do
v2.code.should eq(sync ? 201 : 202) v2.code.should eq(sync ? 201 : 202)
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
doc.parsed_response['error'].should eq(false) doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(202) doc.parsed_response['code'].should eq(sync ? 201 : 202)
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag']) doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
end
it "can create an edge, returnNew" do
v1 = create_vertex( sync, graph_name, user_collection, {})
v1.code.should eq(sync ? 201 : 202)
v1 = v1.parsed_response['vertex']['_id']
v2 = create_vertex( sync, graph_name, user_collection, {})
v2.code.should eq(sync ? 201 : 202)
v2 = v2.parsed_response['vertex']['_id']
doc = create_edge( sync, graph_name, friend_collection, v1, v2, { "value" => "foo" }, { "returnNew" => "true" })
doc.code.should eq(sync ? 201 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 201 : 202)
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new']['value'].should eq("foo")
end end
it "can get an edge" do it "can get an edge" do
@ -602,7 +748,7 @@ describe ArangoDB do
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
type = "married" type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key'] key = doc.parsed_response['edge']['_key']
doc = get_edge(graph_name, friend_collection, key) doc = get_edge(graph_name, friend_collection, key)
@ -633,7 +779,7 @@ describe ArangoDB do
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
type = "married" type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key'] key = doc.parsed_response['edge']['_key']
oldTag = doc.parsed_response['edge']['_rev'] oldTag = doc.parsed_response['edge']['_rev']
oldTag.should eq(doc.headers['etag']) oldTag.should eq(doc.headers['etag'])
@ -646,6 +792,51 @@ describe ArangoDB do
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag']) doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['edge']['_key'].should eq(key) doc.parsed_response['edge']['_key'].should eq(key)
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
doc = get_edge(graph_name, friend_collection, key)
doc.parsed_response['edge']['type2'].should eq(type)
doc.parsed_response['edge']['type'].should eq(nil)
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
oldTag.should_not eq(doc.headers['etag'])
doc.parsed_response['edge']['_key'].should eq(key)
end
it "can replace an edge, returnOld" do
v1 = create_vertex( sync, graph_name, user_collection, {})
v1.code.should eq(sync ? 201 : 202)
v1 = v1.parsed_response['vertex']['_id']
v2 = create_vertex( sync, graph_name, user_collection, {})
v2.code.should eq(sync ? 201 : 202)
v2 = v2.parsed_response['vertex']['_id']
type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key']
oldTag = doc.parsed_response['edge']['_rev']
oldTag.should eq(doc.headers['etag'])
type = "divorced"
doc = replace_edge( sync, graph_name, friend_collection, key, {"type2" => type, "_from" => v1, "_to" => v2}, { "returnOld" => "true", "returnNew" => "true" })
doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['edge']['_key'].should eq(key)
doc.parsed_response['old']['_key'].should eq(key)
doc.parsed_response['old']['type'].should eq("married")
doc.parsed_response['old']['type2'].should eq(nil)
doc.parsed_response['old']['_from'].should eq(v1)
doc.parsed_response['old']['_to'].should eq(v2)
doc.parsed_response['new']['_key'].should eq(key)
doc.parsed_response['new']['type'].should eq(nil)
doc.parsed_response['new']['type2'].should eq("divorced")
doc.parsed_response['new']['_from'].should eq(v1)
doc.parsed_response['new']['_to'].should eq(v2)
doc = get_edge(graph_name, friend_collection, key) doc = get_edge(graph_name, friend_collection, key)
doc.parsed_response['edge']['type2'].should eq(type) doc.parsed_response['edge']['type2'].should eq(type)
doc.parsed_response['edge']['type'].should eq(nil) doc.parsed_response['edge']['type'].should eq(nil)
@ -673,7 +864,7 @@ describe ArangoDB do
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
type = "married" type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key'] key = doc.parsed_response['edge']['_key']
type2 = "divorced" type2 = "divorced"
@ -684,6 +875,46 @@ describe ArangoDB do
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag']) doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['edge']['_key'].should eq(key) doc.parsed_response['edge']['_key'].should eq(key)
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
doc = get_edge(graph_name, friend_collection, key)
doc.parsed_response['edge']['type'].should eq(type)
doc.parsed_response['edge']['type2'].should eq(type2)
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['edge']['_key'].should eq(key)
end
it "can update an edge, returnOld" do
v1 = create_vertex( sync, graph_name, user_collection, {})
v1.code.should eq(sync ? 201 : 202)
v1 = v1.parsed_response['vertex']['_id']
v2 = create_vertex( sync, graph_name, user_collection, {})
v2.code.should eq(sync ? 201 : 202)
v2 = v2.parsed_response['vertex']['_id']
type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key']
type2 = "divorced"
doc = update_edge( sync, graph_name, friend_collection, key, {"type2" => type2}, "", { "returnOld" => "true", "returnNew" => "true" })
doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['edge']['_rev'].should eq(doc.headers['etag'])
doc.parsed_response['edge']['_key'].should eq(key)
doc.parsed_response['old']['_key'].should eq(key)
doc.parsed_response['old']['type'].should eq("married")
doc.parsed_response['old']['type2'].should eq(nil)
doc.parsed_response['old']['_from'].should eq(v1)
doc.parsed_response['old']['_to'].should eq(v2)
doc.parsed_response['new']['_key'].should eq(key)
doc.parsed_response['new']['type'].should eq("married")
doc.parsed_response['new']['type2'].should eq("divorced")
doc.parsed_response['new']['_from'].should eq(v1)
doc.parsed_response['new']['_to'].should eq(v2)
doc = get_edge(graph_name, friend_collection, key) doc = get_edge(graph_name, friend_collection, key)
doc.parsed_response['edge']['type'].should eq(type) doc.parsed_response['edge']['type'].should eq(type)
doc.parsed_response['edge']['type2'].should eq(type2) doc.parsed_response['edge']['type2'].should eq(type2)
@ -700,7 +931,7 @@ describe ArangoDB do
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
type = "married" type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key'] key = doc.parsed_response['edge']['_key']
doc = update_edge( sync, graph_name, friend_collection, key, {"type" => nil}, "") doc = update_edge( sync, graph_name, friend_collection, key, {"type" => nil}, "")
@ -720,7 +951,7 @@ describe ArangoDB do
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
type = "married" type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key'] key = doc.parsed_response['edge']['_key']
doc = update_edge( sync, graph_name, friend_collection, key, {"type" => nil}, true) doc = update_edge( sync, graph_name, friend_collection, key, {"type" => nil}, true)
@ -740,7 +971,7 @@ describe ArangoDB do
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
type = "married" type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key'] key = doc.parsed_response['edge']['_key']
doc = update_edge( sync, graph_name, friend_collection, key, {"type" => nil}, false) doc = update_edge( sync, graph_name, friend_collection, key, {"type" => nil}, false)
@ -769,13 +1000,43 @@ describe ArangoDB do
v2 = v2.parsed_response['vertex']['_id'] v2 = v2.parsed_response['vertex']['_id']
type = "married" type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type}) doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(202) doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key'] key = doc.parsed_response['edge']['_key']
doc = delete_edge( sync, graph_name, friend_collection, key) doc = delete_edge( sync, graph_name, friend_collection, key)
doc.code.should eq(sync ? 200 : 202) doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false) doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202) doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['old'].should eq(nil)
doc.parsed_response['new'].should eq(nil)
doc = get_edge(graph_name, friend_collection, key)
doc.code.should eq(404)
doc.parsed_response['error'].should eq(true)
doc.parsed_response['errorMessage'].should include("document not found")
doc.parsed_response['code'].should eq(404)
end
it "can delete an edge, returnOld" do
v1 = create_vertex( sync, graph_name, user_collection, {})
v1.code.should eq(sync ? 201 : 202)
v1 = v1.parsed_response['vertex']['_id']
v2 = create_vertex( sync, graph_name, user_collection, {})
v2.code.should eq(sync ? 201 : 202)
v2 = v2.parsed_response['vertex']['_id']
type = "married"
doc = create_edge( sync, graph_name, friend_collection, v1, v2, {"type" => type})
doc.code.should eq(sync ? 201 : 202)
key = doc.parsed_response['edge']['_key']
doc = delete_edge( sync, graph_name, friend_collection, key, { "returnOld" => "true" })
doc.code.should eq(sync ? 200 : 202)
doc.parsed_response['error'].should eq(false)
doc.parsed_response['code'].should eq(sync ? 200 : 202)
doc.parsed_response['old']['_from'].should eq(v1)
doc.parsed_response['old']['_to'].should eq(v2)
doc.parsed_response['old']['type'].should eq(type)
doc.parsed_response['new'].should eq(nil)
doc = get_edge(graph_name, friend_collection, key) doc = get_edge(graph_name, friend_collection, key)
doc.code.should eq(404) doc.code.should eq(404)

View File

@ -129,16 +129,29 @@ function checkCollection (g, collection) {
} }
} }
function setResponse (res, name, body, code) { function setResponse (res, name, body, code, returnOld, returnNew) {
res.status(code); res.status(code);
if (body._rev) { if (body._rev) {
res.set('etag', body._rev); res.set('etag', body._rev);
} }
res.json({ let result = { error: false, code };
error: false, if (returnOld) {
[name]: body, result.old = body.old;
code delete body.old;
}); }
if (returnNew) {
result.new = body.new;
delete body.new;
}
if (name === undefined) {
// special hack currently used for HTTP DELETE only
for (let att in body) {
result[att] = body[att];
}
} else {
result[name] = body;
}
res.json(result);
} }
function matchVertexRevision (req, rev) { function matchVertexRevision (req, rev) {
@ -205,6 +218,12 @@ const definitionEdgeCollectionName = joi.string()
const waitForSyncFlag = phpCompatFlag const waitForSyncFlag = phpCompatFlag
.description('define if the request should wait until synced to disk.'); .description('define if the request should wait until synced to disk.');
const returnOldFlag = phpCompatFlag
.description('define if the request should wait return the old version of the updated document.');
const returnNewFlag = phpCompatFlag
.description('define if the request should wait return the new version of the updated document.');
const vertexKey = joi.string() const vertexKey = joi.string()
.description('_key attribute of one specific vertex'); .description('_key attribute of one specific vertex');
@ -549,13 +568,14 @@ router.delete('/:graph/edge/:definition', function (req, res) {
router.post('/:graph/vertex/:collection', function (req, res) { router.post('/:graph/vertex/:collection', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync); const waitForSync = Boolean(req.queryParams.waitForSync);
const returnNew = Boolean(req.queryParams.returnNew);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
const g = loadGraph(name); const g = loadGraph(name);
checkCollection(g, collection); checkCollection(g, collection);
let meta; let meta;
try { try {
meta = g[collection].save(req.body, {waitForSync}); meta = g[collection].save(req.body, {waitForSync, returnNew});
} catch (e) { } catch (e) {
if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_INVALID_EDGE.code) { if (e.isArangoError && e.errorNum === errors.ERROR_GRAPH_INVALID_EDGE.code) {
throw Object.assign( throw Object.assign(
@ -565,11 +585,12 @@ router.post('/:graph/vertex/:collection', function (req, res) {
} }
throw e; throw e;
} }
setResponse(res, 'vertex', meta, waitForSync ? CREATED : ACCEPTED); setResponse(res, 'vertex', meta, waitForSync ? CREATED : ACCEPTED, false, returnNew);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', vertexCollectionName) .pathParam('collection', vertexCollectionName)
.queryParam('waitForSync', waitForSyncFlag) .queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnNew', returnNewFlag)
.body(joi.any().required(), 'The document to be stored') .body(joi.any().required(), 'The document to be stored')
.error('bad request', 'The edge definition is invalid.') .error('bad request', 'The edge definition is invalid.')
.error('not found', 'Graph or collection not found.') .error('not found', 'Graph or collection not found.')
@ -607,6 +628,8 @@ router.get('/:graph/vertex/:collection/:key', function (req, res) {
router.put('/:graph/vertex/:collection/:key', function (req, res) { router.put('/:graph/vertex/:collection/:key', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync); const waitForSync = Boolean(req.queryParams.waitForSync);
const returnOld = Boolean(req.queryParams.returnOld);
const returnNew = Boolean(req.queryParams.returnNew);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
const key = req.pathParams.key; const key = req.pathParams.key;
@ -626,13 +649,15 @@ router.put('/:graph/vertex/:collection/:key', function (req, res) {
throw e; throw e;
} }
matchVertexRevision(req, doc._rev); matchVertexRevision(req, doc._rev);
const meta = g[collection].replace(id, req.body, {waitForSync}); const meta = g[collection].replace(id, req.body, {waitForSync, returnOld, returnNew});
setResponse(res, 'vertex', meta, waitForSync ? OK : ACCEPTED); setResponse(res, 'vertex', meta, waitForSync ? OK : ACCEPTED, returnOld, returnNew);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', vertexCollectionName) .pathParam('collection', vertexCollectionName)
.pathParam('key', vertexKey) .pathParam('key', vertexKey)
.queryParam('waitForSync', waitForSyncFlag) .queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnOld', returnOldFlag)
.queryParam('returnNew', returnNewFlag)
.body(joi.any().required(), 'The document to be stored') .body(joi.any().required(), 'The document to be stored')
.error('bad request', 'The vertex is invalid.') .error('bad request', 'The vertex is invalid.')
.error('not found', 'The vertex does not exist.') .error('not found', 'The vertex does not exist.')
@ -645,6 +670,8 @@ router.put('/:graph/vertex/:collection/:key', function (req, res) {
router.patch('/:graph/vertex/:collection/:key', function (req, res) { router.patch('/:graph/vertex/:collection/:key', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync); const waitForSync = Boolean(req.queryParams.waitForSync);
const keepNull = Boolean(req.queryParams.keepNull); const keepNull = Boolean(req.queryParams.keepNull);
const returnOld = Boolean(req.queryParams.returnOld);
const returnNew = Boolean(req.queryParams.returnNew);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
const key = req.pathParams.key; const key = req.pathParams.key;
@ -664,13 +691,15 @@ router.patch('/:graph/vertex/:collection/:key', function (req, res) {
throw e; throw e;
} }
matchVertexRevision(req, doc._rev); matchVertexRevision(req, doc._rev);
const meta = g[collection].update(id, req.body, {waitForSync, keepNull}); const meta = g[collection].update(id, req.body, {waitForSync, keepNull, returnOld, returnNew});
setResponse(res, 'vertex', meta, waitForSync ? OK : ACCEPTED); setResponse(res, 'vertex', meta, waitForSync ? OK : ACCEPTED, returnOld, returnNew);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', vertexCollectionName) .pathParam('collection', vertexCollectionName)
.pathParam('key', vertexKey) .pathParam('key', vertexKey)
.queryParam('waitForSync', waitForSyncFlag) .queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnOld', returnOldFlag)
.queryParam('returnNew', returnNewFlag)
.queryParam('keepNull', keepNullFlag) .queryParam('keepNull', keepNullFlag)
.body(joi.any().required(), 'The values that should be modified') .body(joi.any().required(), 'The values that should be modified')
.error('bad request', 'The vertex is invalid.') .error('bad request', 'The vertex is invalid.')
@ -683,6 +712,7 @@ router.patch('/:graph/vertex/:collection/:key', function (req, res) {
router.delete('/:graph/vertex/:collection/:key', function (req, res) { router.delete('/:graph/vertex/:collection/:key', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync); const waitForSync = Boolean(req.queryParams.waitForSync);
const returnOld = Boolean(req.queryParams.returnOld);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
const key = req.pathParams.key; const key = req.pathParams.key;
@ -714,12 +744,17 @@ router.delete('/:graph/vertex/:collection/:key', function (req, res) {
} }
throw e; throw e;
} }
setResponse(res, 'removed', didRemove, waitForSync ? OK : ACCEPTED); let meta = { removed: didRemove };
if (returnOld) {
meta.old = doc;
}
setResponse(res, undefined, meta, waitForSync ? OK : ACCEPTED, returnOld, false);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', vertexCollectionName) .pathParam('collection', vertexCollectionName)
.pathParam('key', vertexKey) .pathParam('key', vertexKey)
.queryParam('waitForSync', waitForSyncFlag) .queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnOld', returnOldFlag)
.error('not found', 'The vertex does not exist.') .error('not found', 'The vertex does not exist.')
.summary('Delete a vertex.') .summary('Delete a vertex.')
.description(dd` .description(dd`
@ -730,6 +765,8 @@ router.delete('/:graph/vertex/:collection/:key', function (req, res) {
// Edge Operations // Edge Operations
router.post('/:graph/edge/:collection', function (req, res) { router.post('/:graph/edge/:collection', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync);
const returnNew = Boolean(req.queryParams.returnNew);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
if (!req.body._from || !req.body._to) { if (!req.body._from || !req.body._to) {
@ -742,7 +779,7 @@ router.post('/:graph/edge/:collection', function (req, res) {
checkCollection(g, collection); checkCollection(g, collection);
let meta; let meta;
try { try {
meta = g[collection].save(req.body); meta = g[collection].save(req.body, {waitForSync, returnNew});
} catch (e) { } catch (e) {
if (e.errorNum !== errors.ERROR_GRAPH_INVALID_EDGE.code) { if (e.errorNum !== errors.ERROR_GRAPH_INVALID_EDGE.code) {
throw Object.assign( throw Object.assign(
@ -752,10 +789,12 @@ router.post('/:graph/edge/:collection', function (req, res) {
} }
throw e; throw e;
} }
setResponse(res, 'edge', meta, ACCEPTED); setResponse(res, 'edge', meta, waitForSync ? CREATED : ACCEPTED, false, returnNew);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', edgeCollectionName) .pathParam('collection', edgeCollectionName)
.queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnNew', returnNewFlag)
.body(joi.object().required(), 'The edge to be stored. Has to contain _from and _to attributes.') .body(joi.object().required(), 'The edge to be stored. Has to contain _from and _to attributes.')
.error('bad request', 'The edge is invalid.') .error('bad request', 'The edge is invalid.')
.error('not found', 'Graph or collection not found.') .error('not found', 'Graph or collection not found.')
@ -793,6 +832,8 @@ router.get('/:graph/edge/:collection/:key', function (req, res) {
router.put('/:graph/edge/:collection/:key', function (req, res) { router.put('/:graph/edge/:collection/:key', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync); const waitForSync = Boolean(req.queryParams.waitForSync);
const returnOld = Boolean(req.queryParams.returnOld);
const returnNew = Boolean(req.queryParams.returnNew);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
const key = req.pathParams.key; const key = req.pathParams.key;
@ -812,13 +853,15 @@ router.put('/:graph/edge/:collection/:key', function (req, res) {
throw e; throw e;
} }
matchVertexRevision(req, doc._rev); matchVertexRevision(req, doc._rev);
const meta = g[collection].replace(id, req.body, {waitForSync}); const meta = g[collection].replace(id, req.body, {waitForSync, returnOld, returnNew});
setResponse(res, 'edge', meta, waitForSync ? OK : ACCEPTED); setResponse(res, 'edge', meta, waitForSync ? OK : ACCEPTED, returnOld, returnNew);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', edgeCollectionName) .pathParam('collection', edgeCollectionName)
.pathParam('key', edgeKey) .pathParam('key', edgeKey)
.queryParam('waitForSync', waitForSyncFlag) .queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnOld', returnOldFlag)
.queryParam('returnNew', returnNewFlag)
.body(joi.any().required(), 'The document to be stored. _from and _to attributes are ignored') .body(joi.any().required(), 'The document to be stored. _from and _to attributes are ignored')
.error('bad request', 'The edge is invalid.') .error('bad request', 'The edge is invalid.')
.error('not found', 'The edge does not exist.') .error('not found', 'The edge does not exist.')
@ -830,6 +873,8 @@ router.put('/:graph/edge/:collection/:key', function (req, res) {
router.patch('/:graph/edge/:collection/:key', function (req, res) { router.patch('/:graph/edge/:collection/:key', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync); const waitForSync = Boolean(req.queryParams.waitForSync);
const returnOld = Boolean(req.queryParams.returnOld);
const returnNew = Boolean(req.queryParams.returnNew);
const keepNull = Boolean(req.queryParams.keepNull); const keepNull = Boolean(req.queryParams.keepNull);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
@ -850,13 +895,15 @@ router.patch('/:graph/edge/:collection/:key', function (req, res) {
throw e; throw e;
} }
matchVertexRevision(req, doc._rev); matchVertexRevision(req, doc._rev);
const meta = g[collection].update(id, req.body, {waitForSync, keepNull}); const meta = g[collection].update(id, req.body, {waitForSync, keepNull, returnOld, returnNew});
setResponse(res, 'edge', meta, waitForSync ? OK : ACCEPTED); setResponse(res, 'edge', meta, waitForSync ? OK : ACCEPTED, returnOld, returnNew);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', edgeCollectionName) .pathParam('collection', edgeCollectionName)
.pathParam('key', edgeKey) .pathParam('key', edgeKey)
.queryParam('waitForSync', waitForSyncFlag) .queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnOld', returnOldFlag)
.queryParam('returnNew', returnNewFlag)
.queryParam('keepNull', keepNullFlag) .queryParam('keepNull', keepNullFlag)
.body(joi.any().required(), 'The values that should be modified. _from and _to attributes are ignored') .body(joi.any().required(), 'The values that should be modified. _from and _to attributes are ignored')
.error('bad request', 'The edge is invalid.') .error('bad request', 'The edge is invalid.')
@ -869,6 +916,7 @@ router.patch('/:graph/edge/:collection/:key', function (req, res) {
router.delete('/:graph/edge/:collection/:key', function (req, res) { router.delete('/:graph/edge/:collection/:key', function (req, res) {
const waitForSync = Boolean(req.queryParams.waitForSync); const waitForSync = Boolean(req.queryParams.waitForSync);
const returnOld = Boolean(req.queryParams.returnOld);
const name = req.pathParams.graph; const name = req.pathParams.graph;
const collection = req.pathParams.collection; const collection = req.pathParams.collection;
const key = req.pathParams.key; const key = req.pathParams.key;
@ -900,12 +948,17 @@ router.delete('/:graph/edge/:collection/:key', function (req, res) {
} }
throw e; throw e;
} }
setResponse(res, 'removed', didRemove, waitForSync ? OK : ACCEPTED); let meta = { removed: didRemove };
if (returnOld) {
meta.old = doc;
}
setResponse(res, undefined, meta, waitForSync ? OK : ACCEPTED, returnOld, false);
}) })
.pathParam('graph', graphName) .pathParam('graph', graphName)
.pathParam('collection', edgeCollectionName) .pathParam('collection', edgeCollectionName)
.pathParam('key', edgeKey) .pathParam('key', edgeKey)
.queryParam('waitForSync', waitForSyncFlag) .queryParam('waitForSync', waitForSyncFlag)
.queryParam('returnOld', returnOldFlag)
.error('not found', 'The edge does not exist.') .error('not found', 'The edge does not exist.')
.summary('Delete an edge.') .summary('Delete an edge.')
.description('Deletes an edge with the given id, if it is contained within the graph.'); .description('Deletes an edge with the given id, if it is contained within the graph.');

View File

@ -382,10 +382,16 @@ var bindEdgeCollections = function (self, edgeCollections) {
// save // save
var oldSave = wrap.insert; var oldSave = wrap.insert;
wrap.save = wrap.insert = function (from, to, data) { wrap.save = wrap.insert = function (from, to, data) {
var options = {};
if (typeof from === 'object' && to === undefined) { if (typeof from === 'object' && to === undefined) {
data = from; data = from;
from = data._from; from = data._from;
to = data._to; to = data._to;
} else if (typeof from === 'object' && typeof to === 'object' && data === undefined) {
data = from;
options = to;
from = data._from;
to = data._to;
} else if (typeof from === 'string' && typeof to === 'string' && typeof data === 'object') { } else if (typeof from === 'string' && typeof to === 'string' && typeof data === 'object') {
data._from = from; data._from = from;
data._to = to; data._to = to;
@ -420,7 +426,7 @@ var bindEdgeCollections = function (self, edgeCollections) {
} }
} }
); );
return oldSave(data); return oldSave(data, options);
}; };
// remove // remove
@ -580,9 +586,7 @@ var checkRWPermission = function (c) {
let user = users.currentUser(); let user = users.currentUser();
if (user) { if (user) {
let p = users.permission(user, db._name(), c); let p = users.permission(user, db._name(), c);
//print(`${user}: ${db._name()}/${c} = ${p}`);
if (p !== 'rw') { if (p !== 'rw') {
//print(`Denied ${user} access to ${db._name()}/${c}`);
var err = new ArangoError(); var err = new ArangoError();
err.errorNum = arangodb.errors.ERROR_FORBIDDEN.code; err.errorNum = arangodb.errors.ERROR_FORBIDDEN.code;
err.errorMessage = arangodb.errors.ERROR_FORBIDDEN.message; err.errorMessage = arangodb.errors.ERROR_FORBIDDEN.message;
@ -601,7 +605,6 @@ var checkROPermission = function(c) {
let p = users.permission(user, db._name(), c); let p = users.permission(user, db._name(), c);
var err = new ArangoError(); var err = new ArangoError();
if (p === 'none') { if (p === 'none') {
//print(`Denied ${user} access to ${db._name()}/${c}`);
err.errorNum = arangodb.errors.ERROR_FORBIDDEN.code; err.errorNum = arangodb.errors.ERROR_FORBIDDEN.code;
err.errorMessage = arangodb.errors.ERROR_FORBIDDEN.message; err.errorMessage = arangodb.errors.ERROR_FORBIDDEN.message;
throw err; throw err;