Skip to content

Commit

Permalink
Impl. better support for BatchInserter and more RSpecs [#111]
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas committed Feb 18, 2010
1 parent d599df5 commit 170436b
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 43 deletions.
54 changes: 31 additions & 23 deletions lib/neo4j/batch_inserter.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
module Neo4j

class BatchItem # :nodoc:
attr_accessor :neo_id, :_wrapper
class BatchItem < Struct.new(:neo_id, :inserter) # :nodoc:
attr_accessor :_wrapper

def initialize(id, inserter)
@neo_id = id
@inserter = inserter
end

def []=(k, v)
props = {}
props[k.to_s] = v
@inserter.setNodeProperties(self.neo_id, props)
def []=(key, value)
# not sure why I have to do it like this, Strange why I can't use the Java Hash ?
# gets java.lang.UnsupportedOperationException: null, in java/util/AbstractMap.java:186:in `put'
java_props = inserter.getNodeProperties(neo_id)
ruby_props = {}
java_props.keySet().each{|k| ruby_props[k] = java_props[k]}
ruby_props[key.to_s] = value
inserter.setNodeProperties(neo_id, ruby_props)
end
end

Expand All @@ -27,10 +26,13 @@ def []=(k, v)
# a = Neo4j::Node.new :name => 'a'
# b = Neo4j::Node.new :name => 'b'
# c = Foo.new :key1 => 'val1', :key2 => 'val2'
# c[:name] = "c"
# Neo4j::Relationship.new(:friend, a, b, :since => '2001-01-01')
# Neo4j::Relationship.new(:friend, Neo4j.ref_node, c, :since => '2001-01-01')
# end
#
# After the code block the normal creation for nodes and relationship will be used.
# Traversals inside the batch inserter block is not possible.
# The BatchInserter can be used together with Neo4j Migrations (see Neo4j#migration)
#
class BatchInserter
Expand All @@ -39,40 +41,46 @@ class BatchInserter
# See class description
#
def initialize(storage_path = Neo4j::Config[:storage_path]) # :yields: batch_inserter
inserter = org.neo4j.kernel.impl.batchinsert.BatchInserterImpl.new(storage_path)
# Neo4j must not be running while using batch inserter, stop it just in case ...
Neo4j::Transaction.finish
Neo4j.stop

# create the batch inserter
inserter = org.neo4j.kernel.impl.batchinsert.BatchInserterImpl.new(storage_path)

# save original methods
create_node_meth = Neo4j.method(:create_node)
create_rel_meth = Neo4j.method(:create_rel)

neo4j_meta = (
class << Neo4j;
self;
end)
create_rel_meth = Neo4j.method(:create_rel)
ref_node_meth = Neo4j.method(:ref_node)

# replace methods
neo4j_meta = (class << Neo4j; self; end)
neo4j_meta.instance_eval do
define_method(:create_node) do |props|
props ||= {}
id = inserter.createNode(props.keys.inject({}) {|hash, key| hash[key.to_s] = props[key]; hash})
BatchItem.new(id, inserter)
end
end

neo4j_meta.instance_eval do
define_method(:create_rel) do |type, from_node, to_node, props|
props.each_pair{|k, v| props.delete(k); props[k.to_s] = v} if props
java_type = org.neo4j.graphdb.DynamicRelationshipType.withName(type.to_s)
id = inserter.createRelationship(from_node.neo_id, to_node.neo_id, java_type, props)
BatchItem.new(id, inserter)
end
define_method(:ref_node) do
BatchItem.new(inserter.getReferenceNode, inserter)
end
end

begin
yield inserter
begin
yield inserter
ensure
inserter.shutdown
# restore old methods
neo4j_meta.instance_eval do
define_method(:create_node, create_node_meth)
define_method(:create_rel, create_rel_meth)
define_method(:ref_node, ref_node_meth)
end
end
end
Expand Down
12 changes: 8 additions & 4 deletions lib/neo4j/mixins/migration_mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ def init_with_node(java_node) # :nodoc:
#
def migrate!(to_version=nil, verbose = false)
return if self.class.migrations.nil? || self.class.migrations.empty?


# which version should we go to if to_version was not provided ?
to_version ||= self.class.migrations.keys.sort.reverse[0]
puts "Migration: Curr ver #{db_version} need upgrade to version #{to_version}" if verbose

# going up or down ?
if (db_version == to_version)
puts "Already at version #{to_version}" if verbose
elsif (db_version < to_version)
# do we need to migrate ?
return if db_version == to_version

# ok, so we are running some migrations
if (db_version < to_version)
Migrator.upgrade( (db_version+1).upto(to_version).collect { |ver| self.class.migrations[ver] }, self, verbose )
else
Migrator.downgrade( db_version.downto(to_version+1).collect { |ver| self.class.migrations[ver] }, self, verbose )
Expand Down
6 changes: 1 addition & 5 deletions lib/neo4j/mixins/node_mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ def init_with_node(java_node) # :nodoc:
java_node._wrapper=self
end

def init_with_hash(hash)
hash.each_pair{|k, v| self[k] = v}
end

# Returns the org.neo4j.graphdb.Node wrapped object
def _java_node
@_java_node
Expand All @@ -100,9 +96,9 @@ def _java_node
# Creates a new node and initialize with given properties.
#
def init_without_node(props) # :nodoc:
props[:_classname] = self.class.to_s
@_java_node = Neo4j.create_node props
@_java_node._wrapper = self
@_java_node[:_classname] = self.class.to_s
Neo4j.event_handler.node_created(self)
end

Expand Down
9 changes: 6 additions & 3 deletions lib/neo4j/neo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,22 @@ class << self
# neo4j will be started automatically when needed.
# Registers an at_exit handler that stops neo4j (see Neo4j::stop)
#
# === Parameters
# neo_instance:: optional, an instance of org.neo4j.graphdb.GraphDatabaseService
#
# === Examples
# Neo4j::Config[:storage_path] = '/var/neo4j-db'
# Neo4j.start
#
# === Returns
# Nil
# nil
#
def start(neo_instance=nil)
return if running?
at_exit do
Neo4j.stop
end
@neo = org.neo4j.kernel.EmbeddedGraphDatabase.new(Neo4j::Config[:storage_path])
@neo = neo_instance || org.neo4j.kernel.EmbeddedGraphDatabase.new(Neo4j::Config[:storage_path])
@ref_node = Neo4j::Transaction.run do
ReferenceNode.new(@neo.getReferenceNode())
end
Expand Down Expand Up @@ -141,7 +144,7 @@ def load_node(node_id, raw = false)
neo_node = @neo.getNodeById(node_id.to_i)
if (raw)
neo_node
else
else
neo_node.wrapper
end
rescue org.neo4j.graphdb.NotFoundException
Expand Down
53 changes: 45 additions & 8 deletions test/neo4j/batch_inserter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

describe Neo4j::BatchInserter do

it "should accept Neo4j::Node.new and Neo4j::Relationship.new" do
Neo4j.stop # must not have a running neo4j while using batch inserter
before(:all) { stop }
after(:each) { stop }

it "should accept Neo4j::Node.new and Neo4j::Relationship.new" do
class Foo
include Neo4j::NodeMixin
end
Expand All @@ -22,28 +23,64 @@ class Foo
Neo4j::Transaction.new
node_a = Neo4j.load_node(a.neo_id)
node_a[:name].should == 'a'
node_a.rel?(:friend).should be_true
Neo4j::Transaction.finish
end

it "should accept Neo4j::NodeMixin classes" do
pending "Not working yet - properties are not set using batch inserter"
Neo4j.stop # must not have a running neo4j while using batch inserter

it "should allow creating Neo4j::NodeMixin instances" do
class Foo
include Neo4j::NodeMixin
end


c = nil
Neo4j::BatchInserter.new do |b|
c = Foo.new :key1 => 'val1', :key2 => 'val2'
c[:key] = 'val1'
c[:key3] = 'val3'
end

Neo4j::Transaction.new
node_c = Neo4j.load_node(c.neo_id)
node_c[:key1].should == 'val1'
node_c[:key2].should == 'val2'
node_c[:key3].should == 'val3'
node_c.should be_kind_of(Foo)
Neo4j::Transaction.finish
end

it "should expose the ReferenceNode object" do
Neo4j::BatchInserter.new do |b|
ref_node = Neo4j.ref_node
ref_node[:some_prop] = "some value"
Neo4j::Relationship.new(:friend, ref_node, Neo4j::Node.new, :since => '2001-01-01')
end

Neo4j::Transaction.run do
puts "running tx #{Neo4j::Transaction.running?}"
Neo4j.ref_node.rel?(:friend).should be_true
end
end

it "should be possible to use together with Migrations" do
pending "Endless recursion since it will trigger running the migration again"
Neo4j.migration 1, :first do
up do
puts "Create batch inserter" + caller.inspect
Neo4j::BatchInserter.new do
Neo4j.ref_node[:first] = true
end
Neo4j.start
end
down do
Neo4j.ref_node[:first] = nil
end
end

Neo4j.migrate!

Neo4j::Transaction.run do
Neo4j.ref_node[:first].should be_true
Neo4j.db_version.should == 1
end
end

end

0 comments on commit 170436b

Please sign in to comment.