From 12488e5134876ac8ba3a5bb16fa598e33ed61ff2 Mon Sep 17 00:00:00 2001 From: Roel van Dijk Date: Thu, 20 Sep 2012 17:56:18 +0200 Subject: [PATCH] Add batch unit tests and refactor Batch class. --- lib/neography/rest/batch.rb | 291 ++++++++++++++++++++++++++++------- spec/unit/rest/batch_spec.rb | 243 +++++++++++++++++++++++++++++ 2 files changed, 476 insertions(+), 58 deletions(-) create mode 100644 spec/unit/rest/batch_spec.rb diff --git a/lib/neography/rest/batch.rb b/lib/neography/rest/batch.rb index 56eb709..588fc7e 100644 --- a/lib/neography/rest/batch.rb +++ b/lib/neography/rest/batch.rb @@ -22,7 +22,7 @@ def not_streaming(*args) def batch(accept_header, *args) batch = [] - Array(args).each_with_index do |c,i| + Array(args).each_with_index do |c, i| batch << {:id => i }.merge(get_batch(c)) end options = { @@ -34,66 +34,241 @@ def batch(accept_header, *args) end def get_batch(args) - case args[0] - when :get_node - {:method => "GET", :to => "/node/#{get_id(args[1])}"} - when :create_node - {:method => "POST", :to => "/node/", :body => args[1]} - when :create_unique_node - {:method => "POST", :to => "/index/node/#{args[1]}?unique", :body => {:key => args[2], :value => args[3], :properties => args[4]}} - when :set_node_property - {:method => "PUT", :to => "/node/#{get_id(args[1])}/properties/#{args[2].keys.first}", :body => args[2].values.first} - when :reset_node_properties - {:method => "PUT", :to => "/node/#{get_id(args[1])}/properties", :body => args[2]} - when :get_relationship - {:method => "GET", :to => "/relationship/#{get_id(args[1])}"} - when :create_relationship - {:method => "POST", :to => (args[2].is_a?(String) && args[2].start_with?("{") ? "" : "/node/") + "#{get_id(args[2])}/relationships", :body => {:to => (args[3].is_a?(String) && args[3].start_with?("{") ? "" : "/node/") + "#{get_id(args[3])}", :type => args[1], :data => args[4] } } - when :create_unique_relationship - {:method => "POST", :to => "/index/relationship/#{args[1]}?unique", :body => {:key => args[2], :value => args[3], :type => args[4], :start => (args[5].is_a?(String) && args[5].start_with?("{") ? "" : "/node/") + "#{get_id(args[5])}", :end=> (args[6].is_a?(String) && args[6].start_with?("{") ? "" : "/node/") + "#{get_id(args[6])}"} } - when :delete_relationship - {:method => "DELETE", :to => "/relationship/#{get_id(args[1])}"} - when :set_relationship_property - {:method => "PUT", :to => "/relationship/#{get_id(args[1])}/properties/#{args[2].keys.first}", :body => args[2].values.first} - when :reset_relationship_properties - {:method => "PUT", :to => (args[1].is_a?(String) && args[1].start_with?("{") ? "" : "/relationship/") + "#{get_id(args[1])}/properties", :body => args[2]} - when :add_node_to_index - {:method => "POST", :to => "/index/node/#{args[1]}", :body => {:uri => (args[4].is_a?(String) && args[4].start_with?("{") ? "" : "/node/") + "#{get_id(args[4])}", :key => args[2], :value => args[3] } } - when :add_relationship_to_index - {:method => "POST", :to => "/index/relationship/#{args[1]}", :body => {:uri => (args[4].is_a?(String) && args[4].start_with?("{") ? "" : "/relationship/") + "#{get_id(args[4])}", :key => args[2], :value => args[3] } } - when :get_node_index - {:method => "GET", :to => "/index/node/#{args[1]}/#{args[2]}/#{args[3]}"} - when :get_relationship_index - {:method => "GET", :to => "/index/relationship/#{args[1]}/#{args[2]}/#{args[3]}"} - when :get_node_relationships - {:method => "GET", :to => "/node/#{get_id(args[1])}/relationships/#{args[2] || 'all'}"} - when :execute_script - {:method => "POST", :to => @connection.gremlin_path, :body => {:script => args[1], :params => args[2]}} - when :execute_query - if args[2] - {:method => "POST", :to => @connection.cypher_path, :body => {:query => args[1], :params => args[2]}} - else - {:method => "POST", :to => @connection.cypher_path, :body => {:query => args[1]}} - end - when :remove_node_from_index - case args.size - when 5 then {:method => "DELETE", :to => "/index/node/#{args[1]}/#{args[2]}/#{args[3]}/#{get_id(args[4])}" } - when 4 then {:method => "DELETE", :to => "/index/node/#{args[1]}/#{args[2]}/#{get_id(args[3])}" } - when 3 then {:method => "DELETE", :to => "/index/node/#{args[1]}/#{get_id(args[2])}" } - end - when :remove_relationship_from_index - case args.size - when 5 then {:method => "DELETE", :to => "/index/relationship/#{args[1]}/#{args[2]}/#{args[3]}/#{get_id(args[4])}" } - when 4 then {:method => "DELETE", :to => "/index/relationship/#{args[1]}/#{args[2]}/#{get_id(args[3])}" } - when 3 then {:method => "DELETE", :to => "/index/relationship/#{args[1]}/#{get_id(args[2])}" } - end - when :delete_node - {:method => "DELETE", :to => "/node/#{get_id(args[1])}"} - else - raise "Unknown option #{args[0]}" + if respond_to?(args[0].to_sym, true) + send(args[0].to_sym, args) + else + raise "Unknown option #{args[0]}" end end + def get_node(args) + { + :method => "GET", + :to => Nodes.base_path(:id => get_id(args[1])) + } + end + + def create_node(args) + { + :method => "POST", + :to => Nodes.index_path, + :body => args[1] + } + end + + def delete_node(args) + { + :method => "DELETE", + :to => Nodes.base_path(:id => get_id(args[1])) + } + end + + def create_unique_node(args) + { + :method => "POST", + :to => NodeIndexes.unique_path(:index => args[1]), + :body => { + :key => args[2], + :value => args[3], + :properties => args[4] + } + } + end + + def add_node_to_index(args) + { + :method => "POST", + :to => "/index/node/#{args[1]}", + :body => { + :uri => build_node_uri(args[4]), + :key => args[2], + :value => args[3] + } + } + end + + def get_node_index(args) + { + :method => "GET", + :to => "/index/node/#{args[1]}/#{args[2]}/#{args[3]}" + } + end + + def remove_node_from_index(args) + path = case args.size + when 5 + NodeIndexes.value_path(:index => args[1], :key => args[2], :value => args[3], :id => get_id(args[4])) + when 4 + NodeIndexes.key_path(:index => args[1], :key => args[2], :id => get_id(args[3])) + when 3 + NodeIndexes.id_path(:index => args[1], :id => get_id(args[2])) + end + + { + :method => "DELETE", + :to => path + } + end + + def set_node_property(args) + { + :method => "PUT", + :to => NodeProperties.single_path(:id => get_id(args[1]), :property => args[2].keys.first), + :body => args[2].values.first + } + end + + def reset_node_properties(args) + { + :method => "PUT", + :to => NodeProperties.all_path(:id => get_id(args[1])), + :body => args[2] + } + end + + def get_node_relationships(args) + { + :method => "GET", + :to => NodeRelationships.direction_path(:id => get_id(args[1]), :direction => args[2] || 'all'), + } + end + + def get_relationship(args) + { + :method => "GET", + :to => Relationships.base_path(:id => get_id(args[1])) + } + end + + def create_relationship(args) + { + :method => "POST", + :to => build_node_uri(args[2]) + "/relationships", + :body => { + :to => build_node_uri(args[3]), + :type => args[1], + :data => args[4] + } + } + end + + def delete_relationship(args) + { + :method => "DELETE", + :to => Relationships.base_path(:id =>get_id(args[1])) + } + end + + def create_unique_relationship(args) + { + :method => "POST", + :to => "/index/relationship/#{args[1]}?unique", + :body => { + :key => args[2], + :value => args[3], + :type => args[4], + :start => build_node_uri(args[5]), + :end => build_node_uri(args[6]) + } + } + end + + def add_relationship_to_index(args) + { + :method => "POST", + :to => "/index/relationship/#{args[1]}", + :body => { + :uri => build_relationship_uri(args[4]), + :key => args[2], + :value => args[3] + } + } + end + + def get_relationship_index(args) + { + :method => "GET", + :to => "/index/relationship/#{args[1]}/#{args[2]}/#{args[3]}" + } + end + + def set_relationship_property(args) + { + :method => "PUT", + :to => RelationshipProperties.single_path(:id => get_id(args[1]), :property => args[2].keys.first), + :body => args[2].values.first + } + end + + def reset_relationship_properties(args) + { + :method => "PUT", + :to => build_relationship_uri(args[1]) + "/properties", + :body => args[2] + } + end + + def execute_query(args) + request = { + :method => "POST", + :to => @connection.cypher_path, + :body => { + :query => args[1] + } + } + + request[:body].merge!({ :params => args[2] }) if args[2] + + request + end + + def remove_relationship_from_index(args) + path = case args.size + when 5 + RelationshipIndexes.value_path(:index => args[1], :key => args[2], :value => args[3], :id => get_id(args[4])) + when 4 + RelationshipIndexes.key_path(:index => args[1], :key => args[2], :id => get_id(args[3])) + when 3 + RelationshipIndexes.id_path(:index => args[1], :id => get_id(args[2])) + end + + { + :method => "DELETE", + :to => path + } + end + + def build_node_uri(value) + build_uri(value, "node") + end + + def build_relationship_uri(value) + build_uri(value, "relationship") + end + + def build_uri(value, type) + path_or_variable(value, type) + "#{get_id(value)}" + end + + def path_or_variable(value, type) + if value.is_a?(String) && value.start_with?("{") + "" + else + "/#{type}/" + end + end + + def execute_script(args) + { + :method => "POST", + :to => @connection.gremlin_path, + :body => { + :script => args[1], + :params => args[2] + } + } + end + end end end diff --git a/spec/unit/rest/batch_spec.rb b/spec/unit/rest/batch_spec.rb new file mode 100644 index 0000000..d937465 --- /dev/null +++ b/spec/unit/rest/batch_spec.rb @@ -0,0 +1,243 @@ +require 'spec_helper' + +module Neography + class Rest + describe Batch do + + let(:connection) { stub(:gremlin_path => "/gremlin", :cypher_path => "/cypher") } + subject { Batch.new(connection) } + + it "gets nodes" do + expected_body = [ + { "id" => 0, "method" => "GET", "to" => "/node/foo" }, + { "id" => 1, "method" => "GET", "to" => "/node/bar" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:get_node, "foo"], [:get_node, "bar"] + end + + it "creates nodes" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/node", "body" => { "foo" => "bar" } }, + { "id" => 1, "method" => "POST", "to" => "/node", "body" => { "baz" => "qux" } } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:create_node, { "foo" => "bar" }], [:create_node, { "baz" => "qux" }] + end + + it "deletes nodes" do + expected_body = [ + { "id" => 0, "method" => "DELETE", "to" => "/node/foo" }, + { "id" => 1, "method" => "DELETE", "to" => "/node/bar" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:delete_node, "foo"], [:delete_node, "bar"] + end + + it "creates unique nodes" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/index/node/foo?unique", "body" => { "key" => "bar", "value" => "baz", "properties" => "qux" } }, + { "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)) + subject.execute [:create_unique_node, "foo", "bar", "baz", "qux" ], + [:create_unique_node, "quux", "corge", "grault", "garply"] + end + + it "adds nodes to an index" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/index/node/foo", "body" => { "uri" => "/node/qux", "key" => "bar", "value" => "baz" } }, + { "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)) + subject.execute [:add_node_to_index, "foo", "bar", "baz", "qux" ], + [:add_node_to_index, "quux", "corge", "grault", "{0}"] + end + + it "gets nodes from an index" do + expected_body = [ + { "id" => 0, "method" => "GET", "to" => "/index/node/foo/bar/baz" }, + { "id" => 1, "method" => "GET", "to" => "/index/node/qux/quux/corge" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:get_node_index, "foo", "bar", "baz" ], + [:get_node_index, "qux", "quux", "corge" ] + end + + it "deletes nodes from an index" do + expected_body = [ + { "id" => 0, "method" => "DELETE", "to" => "/index/node/index1/id1" }, + { "id" => 1, "method" => "DELETE", "to" => "/index/node/index2/key2/id2" }, + { "id" => 2, "method" => "DELETE", "to" => "/index/node/index3/key3/value3/id3" } + ] + + connection.should_receive(:post).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" ] + end + + it "sets node properties" do + expected_body = [ + { "id" => 0, "method" => "PUT", "to" => "/node/index1/properties/key1", "body" => "value1" }, + { "id" => 1, "method" => "PUT", "to" => "/node/index2/properties/key2", "body" => "value2" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:set_node_property, "index1", { "key1" => "value1" } ], + [:set_node_property, "index2", { "key2" => "value2" } ] + end + + it "resets node properties" do + expected_body = [ + { "id" => 0, "method" => "PUT", "to" => "/node/index1/properties", "body" => { "key1" => "value1" } }, + { "id" => 1, "method" => "PUT", "to" => "/node/index2/properties", "body" => { "key2" => "value2" } } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:reset_node_properties, "index1", { "key1" => "value1" } ], + [:reset_node_properties, "index2", { "key2" => "value2" } ] + end + + it "gets node relationships" do + expected_body = [ + { "id" => 0, "method" => "GET", "to" => "/node/id1/relationships/direction1" }, + { "id" => 1, "method" => "GET", "to" => "/node/id2/relationships/all" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:get_node_relationships, "id1", "direction1" ], + [:get_node_relationships, "id2" ] + end + + it "gets relationships" do + expected_body = [ + { "id" => 0, "method" => "GET", "to" => "/relationship/foo" }, + { "id" => 1, "method" => "GET", "to" => "/relationship/bar" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:get_relationship, "foo"], [:get_relationship, "bar"] + end + + it "creates relationships" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/node/from1/relationships", "body" => { "to" => "/node/to1", "type" => "type1", "data" => "data1" } }, + { "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)) + subject.execute [:create_relationship, "type1", "from1", "to1", "data1" ], + [:create_relationship, "type2", "{0}", "{1}", "data2" ] + end + + it "deletes relationships" do + expected_body = [ + { "id" => 0, "method" => "DELETE", "to" => "/relationship/foo" }, + { "id" => 1, "method" => "DELETE", "to" => "/relationship/bar" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:delete_relationship, "foo"], [:delete_relationship, "bar"] + end + + it "creates unique nodes" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/index/relationship/index1?unique", "body" => { "key" => "key1", "value" => "value1", "type" => "type1", "start" => "/node/node1", "end" => "/node/node2" } }, + { "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)) + subject.execute [:create_unique_relationship, "index1", "key1", "value1", "type1", "node1", "node2" ], + [:create_unique_relationship, "index2", "key2", "value2", "type2", "{0}", "{1}" ] + end + + it "adds relationships to an index" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/index/relationship/index1", "body" => { "uri" => "/relationship/rel1", "key" => "key1", "value" => "value1" } }, + { "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)) + subject.execute [:add_relationship_to_index, "index1", "key1", "value1", "rel1" ], + [:add_relationship_to_index, "index2", "key2", "value2", "{0}"] + end + + it "gets relationships from an index" do + expected_body = [ + { "id" => 0, "method" => "GET", "to" => "/index/relationship/foo/bar/baz" }, + { "id" => 1, "method" => "GET", "to" => "/index/relationship/qux/quux/corge" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:get_relationship_index, "foo", "bar", "baz" ], + [:get_relationship_index, "qux", "quux", "corge" ] + end + + it "deletes relationships from an index" do + expected_body = [ + { "id" => 0, "method" => "DELETE", "to" => "/index/relationship/index1/id1" }, + { "id" => 1, "method" => "DELETE", "to" => "/index/relationship/index2/key2/id2" }, + { "id" => 2, "method" => "DELETE", "to" => "/index/relationship/index3/key3/value3/id3" } + ] + + connection.should_receive(:post).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" ] + end + + it "sets relationship properties" do + expected_body = [ + { "id" => 0, "method" => "PUT", "to" => "/relationship/index1/properties/key1", "body" => "value1" }, + { "id" => 1, "method" => "PUT", "to" => "/relationship/index2/properties/key2", "body" => "value2" } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:set_relationship_property, "index1", { "key1" => "value1" } ], + [:set_relationship_property, "index2", { "key2" => "value2" } ] + end + + it "resets relationship properties" do + expected_body = [ + { "id" => 0, "method" => "PUT", "to" => "/relationship/index1/properties", "body" => { "key1" => "value1" } }, + { "id" => 1, "method" => "PUT", "to" => "{0}/properties", "body" => { "key2" => "value2" } } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:reset_relationship_properties, "index1", { "key1" => "value1" } ], + [:reset_relationship_properties, "{0}", { "key2" => "value2" } ] + end + + it "executes scripts" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/gremlin", "body" => { "script" => "script1", "params" => "params1" } }, + { "id" => 1, "method" => "POST", "to" => "/gremlin", "body" => { "script" => "script2", "params" => "params2" } } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:execute_script, "script1", "params1"], + [:execute_script, "script2", "params2"] + end + + it "executes queries" do + expected_body = [ + { "id" => 0, "method" => "POST", "to" => "/cypher", "body" => { "query" => "query1", "params" => "params1" } }, + { "id" => 1, "method" => "POST", "to" => "/cypher", "body" => { "query" => "query2" } } + ] + + connection.should_receive(:post).with("/batch", json_match(:body, expected_body)) + subject.execute [:execute_query, "query1", "params1"], + [:execute_query, "query2" ] + end + + end + end +end +