diff --git a/lib/neography/rest.rb b/lib/neography/rest.rb index 1aedb64..d33235a 100644 --- a/lib/neography/rest.rb +++ b/lib/neography/rest.rb @@ -16,6 +16,7 @@ require 'neography/rest/node_auto_indexes' require 'neography/rest/node_traversal' require 'neography/rest/node_paths' +require 'neography/rest/node_labels' require 'neography/rest/relationships' require 'neography/rest/relationship_properties' require 'neography/rest/relationship_indexes' @@ -53,6 +54,7 @@ def initialize(options = ENV['NEO4J_URL'] || {}) @schema_indexes = SchemaIndexes.new(@connection) @node_traversal = NodeTraversal.new(@connection) @node_paths = NodePaths.new(@connection) + @node_labels = NodeLabels.new(@connection) @relationships = Relationships.new(@connection) @relationship_properties = RelationshipProperties.new(@connection) @@ -72,7 +74,39 @@ def initialize(options = ENV['NEO4J_URL'] || {}) def list_relationship_types @relationship_types.list end + + # labels + + def list_labels + @node_labels.list + end + + def add_label(id, label) + @node_labels.add(id, label) + end + + def set_label(id, label) + @node_labels.set(id, label) + end + + def delete_label(id, label) + @node_labels.delete(id, label) + end + + def get_node_labels(id) + @node_labels.get(id) + end + + def get_nodes_labeled(label) + @node_labels.get_nodes(label) + end + + def find_nodes_labeled(label, hash) + @node_labels.find_nodes(label, hash) + end + # schema indexes + def get_schema_index(label) @schema_indexes.list(label) end diff --git a/lib/neography/rest/node_labels.rb b/lib/neography/rest/node_labels.rb new file mode 100644 index 0000000..fe78a9c --- /dev/null +++ b/lib/neography/rest/node_labels.rb @@ -0,0 +1,60 @@ +module Neography + class Rest + class NodeLabels + extend Neography::Rest::Paths + include Neography::Rest::Helpers + + add_path :base, "/labels" + add_path :node, "/node/:id/labels" + add_path :nodes, "/label/:label/nodes" + add_path :find, "/label/:label/nodes?:property=\":value\"" + add_path :delete, "/node/:id/labels/:label" + + def initialize(connection) + @connection = connection + end + + def list + @connection.get(base_path) + end + + def get(id) + @connection.get(node_path(:id => id)) + end + + def get_nodes(label) + @connection.get(nodes_path(:label => label)) + end + + def find_nodes(label, hash) + @connection.get(find_path(:label => label, :property => hash.keys.first, :value => hash.values.first)) + end + + def add(id, label) + options = { + :body => ( + label + ).to_json, + :headers => json_content_type + } + @connection.post(node_path(:id => id), options) + end + + def set(id, label) + options = { + :body => ( + Array(label) + ).to_json, + :headers => json_content_type + } + @connection.put(node_path(:id => id), options) + end + + def delete(id, label) + @connection.delete(delete_path(:id => id, :label => label)) + end + + + end + end +end diff --git a/lib/neography/rest/transactions.rb b/lib/neography/rest/transactions.rb new file mode 100644 index 0000000..7c4a67d --- /dev/null +++ b/lib/neography/rest/transactions.rb @@ -0,0 +1,102 @@ +module Neography + class Rest + class Transactions + extend Neography::Rest::Paths + include Neography::Rest::Helpers + + add_path :index, "/node" + add_path :base, "/node/:id" + + def initialize(connection) + @connection = connection + end + + def get(id) + @connection.get(base_path(:id => get_id(id))) + end + + def get_each(*nodes) + gotten_nodes = [] + Array(nodes).flatten.each do |node| + gotten_nodes << get(node) + end + gotten_nodes + end + + def root + root_node = @connection.get('/')["reference_node"] + @connection.get(base_path(:id => get_id(root_node))) + end + + def create(*args) + if args[0].respond_to?(:each_pair) && args[0] + create_with_attributes(args[0]) + else + create_empty + end + end + + def create_with_attributes(attributes) + options = { + :body => attributes.delete_if { |k, v| v.nil? }.to_json, + :headers => json_content_type + } + @connection.post(index_path, options) + end + + def create_empty + @connection.post(index_path) + end + + def delete(id) + @connection.delete(base_path(:id => get_id(id))) + end + + def create_multiple(nodes) + nodes = Array.new(nodes) if nodes.kind_of? Fixnum + created_nodes = [] + nodes.each do |node| + created_nodes << create(node) + end + created_nodes + end + + def create_multiple_threaded(nodes) + nodes = Array.new(nodes) if nodes.kind_of? Fixnum + + node_queue = Queue.new + thread_pool = [] + responses = Queue.new + + nodes.each do |node| + node_queue.push node + end + + [nodes.size, @connection.max_threads].min.times do + thread_pool << Thread.new do + until node_queue.empty? do + node = node_queue.pop + if node.respond_to?(:each_pair) + responses.push( @connection.post(index_path, { + :body => node.to_json, + :headers => json_content_type + } ) ) + else + responses.push( @connection.post(index_path) ) + end + end + self.join + end + end + + created_nodes = [] + + while created_nodes.size < nodes.size + created_nodes << responses.pop + end + created_nodes + end + + end + end +end diff --git a/spec/integration/rest_labels_spec.rb b/spec/integration/rest_labels_spec.rb new file mode 100644 index 0000000..3d72e2a --- /dev/null +++ b/spec/integration/rest_labels_spec.rb @@ -0,0 +1,133 @@ +require 'spec_helper' + +describe Neography::Rest do + before(:each) do + @neo = Neography::Rest.new + end + + describe "list_labels" do + it "can get the labels of the database" do + @neo.set_label(0, "Person") + labels = @neo.list_labels + labels.should include("Person") + end + end + + describe "add_label" do + it "can add a label to a node" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.add_label(new_node_id, "Person") + labels = @neo.get_node_labels(new_node_id) + labels.should == ["Person"] + end + + it "can add another label to a node" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.add_label(new_node_id, "Actor") + @neo.add_label(new_node_id, "Director") + labels = @neo.get_node_labels(new_node_id) + labels.should == ["Actor", "Director"] + end + + it "can add multiple labels to a node" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.add_label(new_node_id, ["Actor", "Director"]) + labels = @neo.get_node_labels(new_node_id) + labels.should == ["Actor", "Director"] + end + end + + describe "set_label" do + it "can set a label to a node" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.set_label(new_node_id, "Person") + labels = @neo.get_node_labels(new_node_id) + labels.should == ["Person"] + end + + it "can set a label to a node that already had a label" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.add_label(new_node_id, "Actor") + @neo.set_label(new_node_id, "Director") + labels = @neo.get_node_labels(new_node_id) + labels.should == ["Director"] + end + + it "can set multiple labels to a node" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.set_label(new_node_id, ["Actor", "Director"]) + labels = @neo.get_node_labels(new_node_id) + labels.should == ["Actor", "Director"] + end + end + + describe "delete_label" do + it "can delete a label from a node" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.set_label(new_node_id, ["Actor", "Director"]) + @neo.delete_label(new_node_id, "Actor") + labels = @neo.get_node_labels(new_node_id) + labels.should == ["Director"] + end + + it "can delete a label from a node that doesn't have one" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.delete_label(new_node_id, "Actor") + labels = @neo.get_node_labels(new_node_id) + labels.should == [] + end + + it "cannot delete a label from a node that doesn't exist" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + expect { + @neo.delete_label(new_node_id.to_i + 1, "Actor") + }.to raise_error Neography::NodeNotFoundException + end + end + + describe "get_nodes_labeled" do + it "can get a node with a label" do + new_node = @neo.create_node + new_node_id = new_node["self"].split('/').last + @neo.set_label(new_node_id, ["Actor", "Director"]) + nodes = @neo.get_nodes_labeled("Actor") + nodes.last["self"].split('/').last.should == new_node_id + end + + it "returns an empty array on non-existing label" do + nodes = @neo.get_nodes_labeled("do_not_exist") + nodes.should == [] + end + end + + describe "find_nodes_labeled" do + it "can find a node with a label and a property" do + new_node = @neo.create_node(:name => "max") + new_node_id = new_node["self"].split('/').last + puts new_node_id + @neo.set_label(new_node_id, "clown") + nodes = @neo.find_nodes_labeled("clown", { :name => "max" }) + nodes.last["self"].split('/').last.should == new_node_id + end + + it "returns an empty array on non-existing label property" do + new_node = @neo.create_node(:name => "max") + new_node_id = new_node["self"].split('/').last + puts new_node_id + @neo.set_label(new_node_id, "clown") + nodes = @neo.find_nodes_labeled("clown", { :name => "does_not_exist" }) + nodes.should == [] + end + + end + +end \ No newline at end of file