Permalink
Browse files

Support for create unique entities and search by array

Unique Entities - neo4jrb/neo4j#143
Search by Array - neo4jrb/neo4j#118
  • Loading branch information...
1 parent 5d6d14b commit d3e6c5f588f6f5bec1944628ad03fb827ece754e @andreasronge committed Apr 24, 2012
@@ -41,7 +41,7 @@ def inherited(klass)
# class FolderNode
# include Ne4j::NodeMixin
# has_n(:files).to(File)
- # Same as has_n(:files).to("File")
+ # # Same as has_n(:files).to("File")
# end
#
# FolderNode.files #=> 'File#files' the name of the relationship
@@ -48,6 +48,38 @@ def new(*args)
alias_method :create, :new
+
+ # Get the indexed entity, creating it (exactly once) if no indexed entity exist.
+ #
+ # @example Creating a Unique node
+ #
+ # class MyNode
+ # include Neo4j::NodeMixin
+ # property :email, :index => :exact, :unique => true
+ # end
+ #
+ # node = MyNode.get_or_create(:email =>'jimmy@gmail.com', :name => 'jimmy')
+ #
+ # @see #put_if_absent
+ def get_or_create(*args)
+ props = args.first
+ raise "Can't get or create entity since #{props.inspect} does not included unique key #{props[unique_factory_key]}'" unless props[unique_factory_key]
+ index = index_for_type(_decl_props[unique_factory_key][:index])
+ Neo4j::Core::Index::UniqueFactory.new(unique_factory_key, index) { |*| new(*args) }.get_or_create(unique_factory_key, props[unique_factory_key])
+ end
+
+ # @throws Exception if there are more then one property having unique index
+ # @return [Symbol,nil] the property which has an unique index or nil
+ def unique_factory_key
+ @unique_factory_key ||= begin
+ unique = []
+ _decl_props.each_pair { |k, v| unique << k if v[:unique] }
+ return nil if unique.empty?
+ raise "Only one property can be unique, got #{unique.join(', ')}" if unique.size > 1
+ unique.first
+ end
+ end
+
# Loads a wrapped node from the database given a neo id.
# @param [#to_i, nil] neo_id
# @return [Object, nil] If the node does not exist it will return nil otherwise the loaded node or wrapped node.
@@ -115,12 +115,12 @@ def convert?(class_or_symbol)
def to_java(value)
return nil if value.nil?
- value.to_s
+ Array === value ? value.map(&:to_s) : value.to_s
end
def to_ruby(value)
return nil if value.nil?
- value.to_s
+ value
end
def index_as
@@ -141,12 +141,12 @@ def convert?(class_or_symbol)
def to_java(value)
return nil if value.nil?
- value.to_i
+ Array === value ? value.map(&:to_i) : value.to_i
end
def to_ruby(value)
return nil if value.nil?
- value.to_i
+ value#.to_i
end
def index_as
@@ -165,12 +165,12 @@ def convert?(clazz_or_symbol)
def to_java(value)
return nil if value.nil?
- value.to_f
+ Array === value ? value.map(&:to_f) : value.to_f
end
def to_ruby(value)
return nil if value.nil?
- value.to_f
+ value
end
def index_as
@@ -27,5 +27,5 @@ It comes included with the Apache Lucene document database.
s.extra_rdoc_files = %w( README.rdoc )
s.rdoc_options = ["--quiet", "--title", "Neo4j.rb", "--line-numbers", "--main", "README.rdoc", "--inline-source"]
- s.add_dependency("neo4j-core", "0.0.13")
+ s.add_dependency("neo4j-core", "0.0.14")
end
@@ -2,14 +2,24 @@
describe Neo4j::Wrapper::NodeMixin::ClassMethods do
- subject do
- klass = Class.new do
- extend Neo4j::Wrapper::NodeMixin::ClassMethods
- end
- klass
- end
describe "#new" do
+ subject do
+ #class MyTest1
+ # class << self
+ # alias_method :_orig_new, :new
+ # end
+ # extend Neo4j::Wrapper::NodeMixin::ClassMethods
+ #end
+ klass = Class.new do
+ class << self
+ alias_method :_orig_new, :new
+ end
+ extend Neo4j::Wrapper::NodeMixin::ClassMethods
+ end
+ #klass
+ end
+
it "creates a new node" do
node = mock("Node")
Neo4j::Node.stub(:create).and_return(node)
@@ -19,4 +29,63 @@
end
end
+
+ describe "#get_or_create" do
+ subject do
+ klass = Class.new do
+ extend Neo4j::Wrapper::NodeMixin::ClassMethods
+ extend Neo4j::Wrapper::Property::ClassMethods
+ extend Neo4j::Core::Index::ClassMethods
+ include Neo4j::Wrapper::NodeMixin::Initialize
+
+ def []=(key, value)
+ @hash ||= {}
+ @hash[key] = value
+ end
+
+ def [](key)
+ @hash && @hash[key]
+ end
+
+ node_indexer do
+ index_names :exact => 'unique_node_index_exact'
+ end
+ end
+ TempModel.setup(klass)
+ klass
+ end
+
+ it "creates a new node if it does not already exist" do
+ subject.property :email, :index => :exact, :unique => true
+ other = subject.get_or_create(:email => 'kalle2@gmail.com')
+ node = subject.get_or_create(:email => 'kalle@gmail.com')
+ node.should be_kind_of(subject)
+ node._java_node.should_not == other._java_node
+ end
+
+ it "returns old node if it does already exist" do
+ subject.property :email, :index => :exact, :unique => true
+ old_node = subject.get_or_create(:email => 'kalle@gmail.com')
+ node = subject.get_or_create(:email => 'kalle@gmail.com')
+ node._java_node.should == old_node._java_node
+ end
+
+ it "raise an exception if trying to get an entity with no unique key" do
+ lambda do
+ subject.property :email, :index => :exact, :unique => true
+ subject.get_or_create(:phone => '123')
+ end.should raise_error
+ end
+
+ it "raise an exception there are more then one unique index" do
+ lambda do
+ subject.property :email, :index => :exact, :unique => true
+ subject.property :phone, :index => :exact, :unique => true
+ subject.get_or_create(:phone => '123')
+ end.should raise_error
+ end
+
+ end
+
+
end
@@ -14,6 +14,8 @@
its(:to_java, 123) { should == 123 }
its(:to_java, 123) { should == 123 }
its(:to_java, -123) { should == -123 }
+ its(:to_java, [1, 2, 3]) { should == [1,2,3] }
+
# TODO: Where does Bignum fits?
its(:to_java, 999999999999999) { should == 999999999999999 }
@@ -13,8 +13,9 @@
its(:to_java, nil) { should be_nil }
its(:to_java, 123.12) { should === 123.12 }
its(:to_java, '12.3') { should === 12.3 }
+ its(:to_java, [1.2, 2.3, 3.4]) { should === [1.2, 2.3, 3.4] }
its(:to_ruby, nil) { should be_nil }
its(:to_ruby, 12.34) { should === 12.34 }
- its(:to_ruby, '12.34') { should === 12.34 }
+ its(:to_ruby, '12.34') { should === "12.34" }
end
@@ -11,8 +11,9 @@
its(:to_java, nil) { should be_nil }
its(:to_java, 'aa') { should === 'aa' }
its(:to_java, 123) { should === '123' }
+ its(:to_java, %w[1 2 3]) { should === %w[1 2 3] }
its(:to_ruby, nil) { should be_nil }
its(:to_ruby, 'aa') { should === 'aa' }
- its(:to_ruby, 123) { should === '123' }
+ its(:to_ruby, 123) { should === 123 }
end

0 comments on commit d3e6c5f

Please sign in to comment.