diff --git a/lib/neography/connection.rb b/lib/neography/connection.rb index e7d0760..b3c0eff 100644 --- a/lib/neography/connection.rb +++ b/lib/neography/connection.rb @@ -44,6 +44,15 @@ def post(path, options={}) evaluate_response(@client.post(configuration + path, merge_options(options)[:body], merge_options(options)[:headers])) end + def post_chunked(path, options={}) + authenticate(configuration + path) + result = "" + response = @client.post(configuration + path, merge_options(options)[:body], merge_options(options)[:headers]) do |chunk| + result << chunk + end + evaluate_chunk_response(response, result) + end + def put(path, options={}) authenticate(configuration + path) evaluate_response(@client.put(configuration + path, merge_options(options)[:body], merge_options(options)[:headers])) @@ -97,9 +106,18 @@ def save_local_configuration(config) end end + def evaluate_chunk_response(response, result) + code = response.code + return_result(code, result) + end + def evaluate_response(response) code = response.code body = response.body + return_result(code, body) + end + + def return_result(code, body) case code when 200 @logger.debug "OK" if @log_enabled @@ -115,7 +133,7 @@ def evaluate_response(response) when 400..500 handle_4xx_500_response(code, body) nil - end + end end def handle_4xx_500_response(code, body) diff --git a/lib/neography/rest/batch.rb b/lib/neography/rest/batch.rb index f798dad..56ee83b 100644 --- a/lib/neography/rest/batch.rb +++ b/lib/neography/rest/batch.rb @@ -29,8 +29,11 @@ def batch(accept_header, *args) :body => batch.to_json, :headers => json_content_type.merge(accept_header) } - - @connection.post(batch_path, options) + if accept_header.empty? + @connection.post(batch_path, options) + else + @connection.post_chunked(batch_path, options) + end end def get_batch(args) diff --git a/spec/integration/performance_spec.rb b/spec/integration/performance_spec.rb new file mode 100644 index 0000000..f357352 --- /dev/null +++ b/spec/integration/performance_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Neography::Rest, :slow => true do + before(:each) do + @neo = Neography::Rest.new + end + + describe "can perform" do + it "is fast" do + Benchmark.bm do |x| + x.report(" 100 Times") { 100.times { @neo.create_node } } + x.report(" 500 Times") { 500.times { @neo.create_node } } + x.report("1000 Times") { 1000.times { @neo.create_node } } + end + end + end +end diff --git a/spec/integration/rest_batch_spec.rb b/spec/integration/rest_batch_spec.rb index fe96127..418d479 100644 --- a/spec/integration/rest_batch_spec.rb +++ b/spec/integration/rest_batch_spec.rb @@ -452,5 +452,5 @@ end end - + end diff --git a/spec/integration/rest_batch_streaming_spec.rb b/spec/integration/rest_batch_streaming_spec.rb new file mode 100644 index 0000000..b571f15 --- /dev/null +++ b/spec/integration/rest_batch_streaming_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe Neography::Rest do + before(:each) do + @neo = Neography::Rest.new + end + + describe "streaming" do + + it "can send a 1000 item batch" do + commands = [] + 1000.times do |x| + commands << [:create_node, {"name" => "Max " + x.to_s}] + end + batch_result = @neo.batch *commands + batch_result.first["body"]["data"]["name"].should == "Max 0" + batch_result.last["body"]["data"]["name"].should == "Max 999" + end + + it "can send a 10000 item batch" do + commands = [] + 10000.times do |x| + commands << [:get_node, 0] + end + batch_result = @neo.batch *commands + batch_result.first["body"]["self"].split('/').last.should == "0" + batch_result.last["body"]["self"].split('/').last.should == "0" + end + + end + +end diff --git a/spec/unit/rest/batch_spec.rb b/spec/unit/rest/batch_spec.rb index d937465..cfd69d5 100644 --- a/spec/unit/rest/batch_spec.rb +++ b/spec/unit/rest/batch_spec.rb @@ -13,7 +13,7 @@ class Rest { "id" => 1, "method" => "GET", "to" => "/node/bar" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:get_node, "foo"], [:get_node, "bar"] end @@ -23,7 +23,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "/node", "body" => { "baz" => "qux" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:create_node, { "foo" => "bar" }], [:create_node, { "baz" => "qux" }] end @@ -33,7 +33,7 @@ class Rest { "id" => 1, "method" => "DELETE", "to" => "/node/bar" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:delete_node, "foo"], [:delete_node, "bar"] end @@ -43,7 +43,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "/index/node/quux?unique", "body" => { "key" => "corge", "value" => "grault", "properties" => "garply" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:create_unique_node, "foo", "bar", "baz", "qux" ], [:create_unique_node, "quux", "corge", "grault", "garply"] end @@ -54,7 +54,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "/index/node/quux", "body" => { "uri" => "{0}", "key" => "corge", "value" => "grault" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:add_node_to_index, "foo", "bar", "baz", "qux" ], [:add_node_to_index, "quux", "corge", "grault", "{0}"] end @@ -65,7 +65,7 @@ class Rest { "id" => 1, "method" => "GET", "to" => "/index/node/qux/quux/corge" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:get_node_index, "foo", "bar", "baz" ], [:get_node_index, "qux", "quux", "corge" ] end @@ -77,7 +77,7 @@ class Rest { "id" => 2, "method" => "DELETE", "to" => "/index/node/index3/key3/value3/id3" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:remove_node_from_index, "index1", "id1", ], [:remove_node_from_index, "index2", "key2", "id2" ], [:remove_node_from_index, "index3", "key3", "value3", "id3" ] @@ -89,7 +89,7 @@ class Rest { "id" => 1, "method" => "PUT", "to" => "/node/index2/properties/key2", "body" => "value2" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:set_node_property, "index1", { "key1" => "value1" } ], [:set_node_property, "index2", { "key2" => "value2" } ] end @@ -100,7 +100,7 @@ class Rest { "id" => 1, "method" => "PUT", "to" => "/node/index2/properties", "body" => { "key2" => "value2" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:reset_node_properties, "index1", { "key1" => "value1" } ], [:reset_node_properties, "index2", { "key2" => "value2" } ] end @@ -111,7 +111,7 @@ class Rest { "id" => 1, "method" => "GET", "to" => "/node/id2/relationships/all" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:get_node_relationships, "id1", "direction1" ], [:get_node_relationships, "id2" ] end @@ -122,7 +122,7 @@ class Rest { "id" => 1, "method" => "GET", "to" => "/relationship/bar" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:get_relationship, "foo"], [:get_relationship, "bar"] end @@ -132,7 +132,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "{0}/relationships", "body" => { "to" => "{1}", "type" => "type2", "data" => "data2" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:create_relationship, "type1", "from1", "to1", "data1" ], [:create_relationship, "type2", "{0}", "{1}", "data2" ] end @@ -143,7 +143,7 @@ class Rest { "id" => 1, "method" => "DELETE", "to" => "/relationship/bar" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:delete_relationship, "foo"], [:delete_relationship, "bar"] end @@ -153,7 +153,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "/index/relationship/index2?unique", "body" => { "key" => "key2", "value" => "value2", "type" => "type2", "start" => "{0}", "end" => "{1}" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:create_unique_relationship, "index1", "key1", "value1", "type1", "node1", "node2" ], [:create_unique_relationship, "index2", "key2", "value2", "type2", "{0}", "{1}" ] end @@ -164,7 +164,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "/index/relationship/index2", "body" => { "uri" => "{0}", "key" => "key2", "value" => "value2" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:add_relationship_to_index, "index1", "key1", "value1", "rel1" ], [:add_relationship_to_index, "index2", "key2", "value2", "{0}"] end @@ -175,7 +175,7 @@ class Rest { "id" => 1, "method" => "GET", "to" => "/index/relationship/qux/quux/corge" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:get_relationship_index, "foo", "bar", "baz" ], [:get_relationship_index, "qux", "quux", "corge" ] end @@ -187,7 +187,7 @@ class Rest { "id" => 2, "method" => "DELETE", "to" => "/index/relationship/index3/key3/value3/id3" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:remove_relationship_from_index, "index1", "id1", ], [:remove_relationship_from_index, "index2", "key2", "id2" ], [:remove_relationship_from_index, "index3", "key3", "value3", "id3" ] @@ -199,7 +199,7 @@ class Rest { "id" => 1, "method" => "PUT", "to" => "/relationship/index2/properties/key2", "body" => "value2" } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:set_relationship_property, "index1", { "key1" => "value1" } ], [:set_relationship_property, "index2", { "key2" => "value2" } ] end @@ -210,7 +210,7 @@ class Rest { "id" => 1, "method" => "PUT", "to" => "{0}/properties", "body" => { "key2" => "value2" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:reset_relationship_properties, "index1", { "key1" => "value1" } ], [:reset_relationship_properties, "{0}", { "key2" => "value2" } ] end @@ -221,7 +221,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "/gremlin", "body" => { "script" => "script2", "params" => "params2" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:execute_script, "script1", "params1"], [:execute_script, "script2", "params2"] end @@ -232,7 +232,7 @@ class Rest { "id" => 1, "method" => "POST", "to" => "/cypher", "body" => { "query" => "query2" } } ] - connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + connection.should_receive(:post_chunked).with("/batch", json_match(:body, expected_body)) subject.execute [:execute_query, "query1", "params1"], [:execute_query, "query2" ] end