neo4j 2.0.0.alpha.5-java → 2.0.0.alpha.6-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +12 -0
- data/Gemfile +0 -4
- data/README.rdoc +106 -62
- data/lib/neo4j.rb +7 -33
- data/lib/neo4j/performance.rb +43 -0
- data/lib/neo4j/rails/accept_id.rb +19 -18
- data/lib/neo4j/rails/attributes.rb +366 -120
- data/lib/neo4j/rails/finders.rb +41 -15
- data/lib/neo4j/rails/has_n.rb +203 -0
- data/lib/neo4j/rails/identity.rb +25 -0
- data/lib/neo4j/rails/model.rb +65 -242
- data/lib/neo4j/rails/nested_attributes.rb +108 -0
- data/lib/neo4j/rails/node_persistance.rb +56 -0
- data/lib/neo4j/rails/observer.rb +0 -2
- data/lib/neo4j/rails/persistence.rb +32 -154
- data/lib/neo4j/rails/rack_middleware.rb +26 -2
- data/lib/neo4j/rails/rails.rb +9 -6
- data/lib/neo4j/rails/railtie.rb +1 -2
- data/lib/neo4j/rails/relationship.rb +18 -125
- data/lib/neo4j/rails/relationship_persistence.rb +107 -0
- data/lib/neo4j/rails/relationships/node_dsl.rb +72 -44
- data/lib/neo4j/rails/relationships/relationships.rb +187 -59
- data/lib/neo4j/rails/relationships/rels_dsl.rb +18 -17
- data/lib/neo4j/rails/relationships/storage.rb +19 -17
- data/lib/neo4j/rails/timestamps.rb +53 -51
- data/lib/neo4j/rails/transaction.rb +9 -1
- data/lib/neo4j/rails/validations/uniqueness.rb +1 -1
- data/lib/neo4j/rails/versioning/versioning.rb +2 -2
- data/lib/neo4j/version.rb +1 -1
- data/lib/orm_adapter/adapters/neo4j.rb +47 -46
- data/neo4j.gemspec +1 -1
- metadata +10 -69
- data/lib/neo4j/algo/algo.rb +0 -294
- data/lib/neo4j/batch/batch.rb +0 -4
- data/lib/neo4j/batch/indexer.rb +0 -109
- data/lib/neo4j/batch/inserter.rb +0 -179
- data/lib/neo4j/batch/rule_inserter.rb +0 -24
- data/lib/neo4j/batch/rule_node.rb +0 -72
- data/lib/neo4j/config.rb +0 -177
- data/lib/neo4j/core_ext/class/inheritable_attributes.rb +0 -12
- data/lib/neo4j/core_ext/class/rewrite_inheritable_attributes.rb +0 -170
- data/lib/neo4j/database.rb +0 -158
- data/lib/neo4j/equal.rb +0 -21
- data/lib/neo4j/event_handler.rb +0 -263
- data/lib/neo4j/has_list/class_methods.rb +0 -11
- data/lib/neo4j/has_list/has_list.rb +0 -3
- data/lib/neo4j/has_list/mapping.rb +0 -133
- data/lib/neo4j/has_n/class_methods.rb +0 -119
- data/lib/neo4j/has_n/decl_relationship_dsl.rb +0 -246
- data/lib/neo4j/has_n/has_n.rb +0 -3
- data/lib/neo4j/has_n/mapping.rb +0 -98
- data/lib/neo4j/identity_map.rb +0 -140
- data/lib/neo4j/index/class_methods.rb +0 -108
- data/lib/neo4j/index/index.rb +0 -39
- data/lib/neo4j/index/indexer.rb +0 -341
- data/lib/neo4j/index/indexer_registry.rb +0 -68
- data/lib/neo4j/index/lucene_query.rb +0 -256
- data/lib/neo4j/load.rb +0 -25
- data/lib/neo4j/migrations/class_methods.rb +0 -110
- data/lib/neo4j/migrations/extensions.rb +0 -58
- data/lib/neo4j/migrations/lazy_node_mixin.rb +0 -41
- data/lib/neo4j/migrations/migration.rb +0 -112
- data/lib/neo4j/migrations/migrations.rb +0 -6
- data/lib/neo4j/migrations/node_mixin.rb +0 -80
- data/lib/neo4j/migrations/ref_node_wrapper.rb +0 -32
- data/lib/neo4j/model.rb +0 -4
- data/lib/neo4j/neo4j.rb +0 -216
- data/lib/neo4j/node.rb +0 -270
- data/lib/neo4j/node_mixin/class_methods.rb +0 -51
- data/lib/neo4j/node_mixin/node_mixin.rb +0 -141
- data/lib/neo4j/paginated.rb +0 -23
- data/lib/neo4j/property/class_methods.rb +0 -79
- data/lib/neo4j/property/property.rb +0 -111
- data/lib/neo4j/rails/mapping/property.rb +0 -183
- data/lib/neo4j/rails/rel_persistence.rb +0 -237
- data/lib/neo4j/relationship.rb +0 -239
- data/lib/neo4j/relationship_mixin/class_methods.rb +0 -36
- data/lib/neo4j/relationship_mixin/relationship_mixin.rb +0 -142
- data/lib/neo4j/relationship_set.rb +0 -58
- data/lib/neo4j/rels/rels.rb +0 -110
- data/lib/neo4j/rels/traverser.rb +0 -102
- data/lib/neo4j/rule/class_methods.rb +0 -201
- data/lib/neo4j/rule/event_listener.rb +0 -66
- data/lib/neo4j/rule/functions/count.rb +0 -43
- data/lib/neo4j/rule/functions/function.rb +0 -74
- data/lib/neo4j/rule/functions/functions.rb +0 -3
- data/lib/neo4j/rule/functions/sum.rb +0 -29
- data/lib/neo4j/rule/rule.rb +0 -150
- data/lib/neo4j/rule/rule_node.rb +0 -217
- data/lib/neo4j/to_java.rb +0 -31
- data/lib/neo4j/transaction.rb +0 -73
- data/lib/neo4j/traversal/filter_predicate.rb +0 -25
- data/lib/neo4j/traversal/prune_evaluator.rb +0 -14
- data/lib/neo4j/traversal/rel_expander.rb +0 -31
- data/lib/neo4j/traversal/traversal.rb +0 -141
- data/lib/neo4j/traversal/traverser.rb +0 -284
- data/lib/neo4j/type_converters/type_converters.rb +0 -288
@@ -1,12 +0,0 @@
|
|
1
|
-
# This is copied from Rails Active Support since it has been depricated and I still need it
|
2
|
-
|
3
|
-
# Taken from: https://raw.github.com/lifo/docrails/dd6c3676af3fa6019c53a59f62c4fd14966be728/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
|
4
|
-
|
5
|
-
# Changes made:
|
6
|
-
# - Remove deprecation warnings
|
7
|
-
# - Ignore if already available from ActiveSupport
|
8
|
-
#
|
9
|
-
# Can't use class_attribute because we want to use the same value for all subclasses
|
10
|
-
|
11
|
-
|
12
|
-
require 'neo4j/core_ext/class/rewrite_inheritable_attributes.rb'
|
@@ -1,170 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/object/duplicable'
|
2
|
-
require 'active_support/core_ext/array/extract_options'
|
3
|
-
|
4
|
-
# Retained for backward compatibility. Methods are now included in Class.
|
5
|
-
module ClassInheritableAttributes # :nodoc:
|
6
|
-
end
|
7
|
-
|
8
|
-
# It is recommended to use <tt>class_attribute</tt> over methods defined in this file. Please
|
9
|
-
# refer to documentation for <tt>class_attribute</tt> for more information. Officially it is not
|
10
|
-
#
|
11
|
-
# Allows attributes to be shared within an inheritance hierarchy. Each descendant gets a copy of
|
12
|
-
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
|
13
|
-
# to, for example, an array without those additions being shared with either their parent, siblings, or
|
14
|
-
# children. This is unlike the regular class-level attributes that are shared across the entire hierarchy.
|
15
|
-
#
|
16
|
-
# The copies of inheritable parent attributes are added to subclasses when they are created, via the
|
17
|
-
# +inherited+ hook.
|
18
|
-
#
|
19
|
-
# class Person
|
20
|
-
# class_inheritable_accessor :hair_colors
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# Person.hair_colors = [:brown, :black, :blonde, :red]
|
24
|
-
# Person.hair_colors # => [:brown, :black, :blonde, :red]
|
25
|
-
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
26
|
-
#
|
27
|
-
# To opt out of the instance writer method, pass :instance_writer => false.
|
28
|
-
# To opt out of the instance reader method, pass :instance_reader => false.
|
29
|
-
#
|
30
|
-
# class Person
|
31
|
-
# class_inheritable_accessor :hair_colors :instance_writer => false, :instance_reader => false
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# Person.new.hair_colors = [:brown] # => NoMethodError
|
35
|
-
# Person.new.hair_colors # => NoMethodError
|
36
|
-
class Class # :nodoc:
|
37
|
-
def class_inheritable_reader(*syms)
|
38
|
-
options = syms.extract_options!
|
39
|
-
syms.each do |sym|
|
40
|
-
next if sym.is_a?(Hash)
|
41
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
42
|
-
def self.#{sym} # def self.after_add
|
43
|
-
read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:after_add)
|
44
|
-
end # end
|
45
|
-
#
|
46
|
-
#{" #
|
47
|
-
def #{sym} # def after_add
|
48
|
-
self.class.#{sym} # self.class.after_add
|
49
|
-
end # end
|
50
|
-
" unless options[:instance_reader] == false } # # the reader above is generated unless options[:instance_reader] == false
|
51
|
-
EOS
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def class_inheritable_writer(*syms)
|
56
|
-
options = syms.extract_options!
|
57
|
-
syms.each do |sym|
|
58
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
59
|
-
def self.#{sym}=(obj) # def self.color=(obj)
|
60
|
-
write_inheritable_attribute(:#{sym}, obj) # write_inheritable_attribute(:color, obj)
|
61
|
-
end # end
|
62
|
-
#
|
63
|
-
#{" #
|
64
|
-
def #{sym}=(obj) # def color=(obj)
|
65
|
-
self.class.#{sym} = obj # self.class.color = obj
|
66
|
-
end # end
|
67
|
-
" unless options[:instance_writer] == false } # # the writer above is generated unless options[:instance_writer] == false
|
68
|
-
EOS
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def class_inheritable_array_writer(*syms)
|
73
|
-
options = syms.extract_options!
|
74
|
-
syms.each do |sym|
|
75
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
76
|
-
def self.#{sym}=(obj) # def self.levels=(obj)
|
77
|
-
write_inheritable_array(:#{sym}, obj) # write_inheritable_array(:levels, obj)
|
78
|
-
end # end
|
79
|
-
#
|
80
|
-
#{" #
|
81
|
-
def #{sym}=(obj) # def levels=(obj)
|
82
|
-
self.class.#{sym} = obj # self.class.levels = obj
|
83
|
-
end # end
|
84
|
-
" unless options[:instance_writer] == false } # # the writer above is generated unless options[:instance_writer] == false
|
85
|
-
EOS
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def class_inheritable_hash_writer(*syms)
|
90
|
-
options = syms.extract_options!
|
91
|
-
syms.each do |sym|
|
92
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
93
|
-
def self.#{sym}=(obj) # def self.nicknames=(obj)
|
94
|
-
write_inheritable_hash(:#{sym}, obj) # write_inheritable_hash(:nicknames, obj)
|
95
|
-
end # end
|
96
|
-
#
|
97
|
-
#{" #
|
98
|
-
def #{sym}=(obj) # def nicknames=(obj)
|
99
|
-
self.class.#{sym} = obj # self.class.nicknames = obj
|
100
|
-
end # end
|
101
|
-
" unless options[:instance_writer] == false } # # the writer above is generated unless options[:instance_writer] == false
|
102
|
-
EOS
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def class_inheritable_accessor(*syms)
|
107
|
-
class_inheritable_reader(*syms)
|
108
|
-
class_inheritable_writer(*syms)
|
109
|
-
end
|
110
|
-
|
111
|
-
def class_inheritable_array(*syms)
|
112
|
-
class_inheritable_reader(*syms)
|
113
|
-
class_inheritable_array_writer(*syms)
|
114
|
-
end
|
115
|
-
|
116
|
-
def class_inheritable_hash(*syms)
|
117
|
-
class_inheritable_reader(*syms)
|
118
|
-
class_inheritable_hash_writer(*syms)
|
119
|
-
end
|
120
|
-
|
121
|
-
def inheritable_attributes
|
122
|
-
@inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
|
123
|
-
end
|
124
|
-
|
125
|
-
def write_inheritable_attribute(key, value)
|
126
|
-
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
127
|
-
@inheritable_attributes = {}
|
128
|
-
end
|
129
|
-
inheritable_attributes[key] = value
|
130
|
-
end
|
131
|
-
|
132
|
-
def write_inheritable_array(key, elements)
|
133
|
-
write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
|
134
|
-
write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
|
135
|
-
end
|
136
|
-
|
137
|
-
def write_inheritable_hash(key, hash)
|
138
|
-
write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
|
139
|
-
write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
|
140
|
-
end
|
141
|
-
|
142
|
-
def read_inheritable_attribute(key)
|
143
|
-
inheritable_attributes[key]
|
144
|
-
end
|
145
|
-
|
146
|
-
def reset_inheritable_attributes
|
147
|
-
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
148
|
-
end
|
149
|
-
|
150
|
-
private
|
151
|
-
# Prevent this constant from being created multiple times
|
152
|
-
EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze
|
153
|
-
|
154
|
-
def inherited_with_inheritable_attributes(child)
|
155
|
-
inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
|
156
|
-
|
157
|
-
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
158
|
-
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
159
|
-
else
|
160
|
-
new_inheritable_attributes = Hash[inheritable_attributes.map do |(key, value)|
|
161
|
-
[key, value.duplicable? ? value.dup : value]
|
162
|
-
end]
|
163
|
-
end
|
164
|
-
|
165
|
-
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
|
166
|
-
end
|
167
|
-
|
168
|
-
alias inherited_without_inheritable_attributes inherited
|
169
|
-
alias inherited inherited_with_inheritable_attributes
|
170
|
-
end
|
data/lib/neo4j/database.rb
DELETED
@@ -1,158 +0,0 @@
|
|
1
|
-
require 'neo4j/config'
|
2
|
-
require 'neo4j/event_handler'
|
3
|
-
require 'neo4j/transaction'
|
4
|
-
|
5
|
-
module Neo4j
|
6
|
-
# Wraps both Java Neo4j GraphDatabaseService and Lucene.
|
7
|
-
# You can access the raw java neo4j and lucene db's with the <tt>graph</tt> and <tt>lucene</tt>
|
8
|
-
# properties.
|
9
|
-
#
|
10
|
-
# This class is also responsible for checking if there is already a running neo4j database.
|
11
|
-
# If one tries to start an already started database then a read only instance to neo4j will be used.
|
12
|
-
#
|
13
|
-
class Database
|
14
|
-
attr_reader :graph, :lucene, :event_handler, :storage_path
|
15
|
-
|
16
|
-
alias_method :index, :lucene # needed by cypher
|
17
|
-
|
18
|
-
def initialize()
|
19
|
-
@event_handler = EventHandler.new
|
20
|
-
end
|
21
|
-
|
22
|
-
def start #:nodoc:
|
23
|
-
return if running?
|
24
|
-
@running = true
|
25
|
-
@storage_path = Config.storage_path
|
26
|
-
|
27
|
-
begin
|
28
|
-
if self.class.locked?
|
29
|
-
start_readonly_graph_db
|
30
|
-
elsif Neo4j::Config['ha.db']
|
31
|
-
start_ha_graph_db
|
32
|
-
Neo4j.migrate!
|
33
|
-
else
|
34
|
-
start_local_graph_db
|
35
|
-
Neo4j.migrate!
|
36
|
-
end
|
37
|
-
rescue
|
38
|
-
@running = false
|
39
|
-
raise
|
40
|
-
end
|
41
|
-
|
42
|
-
at_exit { shutdown }
|
43
|
-
end
|
44
|
-
|
45
|
-
def start_readonly_graph_db #:nodoc:
|
46
|
-
Neo4j.logger.info "Starting Neo4j in readonly mode since the #{@storage_path} is locked"
|
47
|
-
@graph = org.neo4j.kernel.EmbeddedReadOnlyGraphDatabase.new(@storage_path, Config.to_java_map)
|
48
|
-
@lucene = @graph.index
|
49
|
-
end
|
50
|
-
|
51
|
-
def start_local_graph_db #:nodoc:
|
52
|
-
Neo4j.logger.info "Starting local Neo4j using db #{@storage_path}"
|
53
|
-
@graph = org.neo4j.kernel.EmbeddedGraphDatabase.new(@storage_path, Config.to_java_map)
|
54
|
-
@graph.register_transaction_event_handler(@event_handler)
|
55
|
-
@lucene = @graph.index
|
56
|
-
@event_handler.neo4j_started(self)
|
57
|
-
end
|
58
|
-
|
59
|
-
# needed by cypher
|
60
|
-
def getNodeById(id) #:nodoc:
|
61
|
-
Neo4j::Node.load(id)
|
62
|
-
end
|
63
|
-
|
64
|
-
# needed by cypher
|
65
|
-
def getRelationshipById(id) #:nodoc:
|
66
|
-
Neo4j::Relationship.load(id)
|
67
|
-
end
|
68
|
-
|
69
|
-
def start_ha_graph_db
|
70
|
-
Neo4j.logger.info "starting Neo4j in HA mode, machine id: #{Neo4j.config['ha.server_id']} at #{Neo4j.config['ha.server']} db #{@storage_path}"
|
71
|
-
# Modify the public base classes for the HA Node and Relationships
|
72
|
-
# (instead of private org.neo4j.kernel.HighlyAvailableGraphDatabase::LookupNode)
|
73
|
-
@graph = org.neo4j.kernel.HighlyAvailableGraphDatabase.new(@storage_path, Neo4j.config.to_java_map)
|
74
|
-
@graph.register_transaction_event_handler(@event_handler)
|
75
|
-
@lucene = @graph.index
|
76
|
-
@event_handler.neo4j_started(self)
|
77
|
-
end
|
78
|
-
|
79
|
-
def start_external_db(external_graph_db)
|
80
|
-
begin
|
81
|
-
@running = true
|
82
|
-
@graph = external_graph_db
|
83
|
-
Neo4j.migrate!
|
84
|
-
@graph.register_transaction_event_handler(@event_handler)
|
85
|
-
@lucene = @graph.index #org.neo4j.index.impl.lucene.LuceneIndexProvider.new
|
86
|
-
@event_handler.neo4j_started(self)
|
87
|
-
Neo4j.logger.info("Started with external db")
|
88
|
-
rescue
|
89
|
-
@running = false
|
90
|
-
raise
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def running? #:nodoc:
|
95
|
-
@running
|
96
|
-
end
|
97
|
-
|
98
|
-
# Returns true if the neo4j db was started in read only mode.
|
99
|
-
# This can occur if the database was locked (it was already one instance running).
|
100
|
-
def read_only?
|
101
|
-
@graph.java_class == org.neo4j.kernel.EmbeddedGraphDatabase
|
102
|
-
end
|
103
|
-
|
104
|
-
# check if the database is locked. A neo4j database is locked when the database is running.
|
105
|
-
def self.locked?
|
106
|
-
lock_file = File.join(Neo4j.config.storage_path, 'neostore')
|
107
|
-
return false unless File.exist?(lock_file)
|
108
|
-
rfile = java.io.RandomAccessFile.new(lock_file, 'rw')
|
109
|
-
begin
|
110
|
-
lock = rfile.getChannel.tryLock
|
111
|
-
lock.release if lock
|
112
|
-
return lock == nil # we got the lock, so that means it is not locked.
|
113
|
-
rescue Exception => e
|
114
|
-
return false
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def shutdown #:nodoc:
|
119
|
-
if @running
|
120
|
-
@graph.unregister_transaction_event_handler(@event_handler) unless read_only?
|
121
|
-
@event_handler.neo4j_shutdown(self)
|
122
|
-
@graph.shutdown
|
123
|
-
@graph = nil
|
124
|
-
@lucene = nil
|
125
|
-
@running = false
|
126
|
-
@neo4j_manager = nil
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
130
|
-
|
131
|
-
|
132
|
-
def management(jmx_clazz) #:nodoc:
|
133
|
-
@neo4j_manager ||= org.neo4j.management.Neo4jManager.new(@graph.get_management_bean(org.neo4j.jmx.Kernel.java_class))
|
134
|
-
@neo4j_manager.getBean(jmx_clazz.java_class)
|
135
|
-
end
|
136
|
-
|
137
|
-
def begin_tx #:nodoc:
|
138
|
-
@graph.begin_tx
|
139
|
-
end
|
140
|
-
|
141
|
-
|
142
|
-
def each_node #:nodoc:
|
143
|
-
iter = @graph.all_nodes.iterator
|
144
|
-
while (iter.hasNext)
|
145
|
-
yield iter.next.wrapper
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def _each_node #:nodoc:
|
150
|
-
iter = @graph.all_nodes.iterator
|
151
|
-
while (iter.hasNext)
|
152
|
-
yield iter.next
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
end
|
157
|
-
|
158
|
-
end
|
data/lib/neo4j/equal.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
# == This mixin is used for both nodes and relationships to decide if two entities are equal or not.
|
4
|
-
#
|
5
|
-
module Equal
|
6
|
-
def equal?(o)
|
7
|
-
eql?(o)
|
8
|
-
end
|
9
|
-
|
10
|
-
def eql?(o)
|
11
|
-
return false unless o.respond_to?(:getId)
|
12
|
-
o.getId == getId
|
13
|
-
end
|
14
|
-
|
15
|
-
def ==(o)
|
16
|
-
eql?(o)
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
data/lib/neo4j/event_handler.rb
DELETED
@@ -1,263 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
# == Handles Transactional Events
|
4
|
-
#
|
5
|
-
# You can use this to receive event before the transaction commits.
|
6
|
-
# The following events are supported:
|
7
|
-
# * <tt>on_neo4j_started</tt>
|
8
|
-
# * <tt>on_neo4j_shutdown</tt>
|
9
|
-
# * <tt>on_node_created</tt>
|
10
|
-
# * <tt>on_node_deleted</tt>
|
11
|
-
# * <tt>on_relationship_created</tt>
|
12
|
-
# * <tt>on_relationship_deleted</tt>
|
13
|
-
# * <tt>on_property_changed</tt>
|
14
|
-
# * <tt>on_rel_property_changed</tt>
|
15
|
-
# * <tt>on_after_commit</tt>
|
16
|
-
#
|
17
|
-
# ==== on_neo4j_started(db)
|
18
|
-
#
|
19
|
-
# Called when the neo4j engine starts.
|
20
|
-
# Notice that the neo4j will be started automatically when the first neo4j operation is performed.
|
21
|
-
# You can also start Neo4j: <tt>Neo4j.start</tt>
|
22
|
-
#
|
23
|
-
# * <tt>db</tt> :: the Neo4j::Database instance
|
24
|
-
#
|
25
|
-
# ==== on_neo4j_shutdown(db)
|
26
|
-
#
|
27
|
-
# Called when the neo4j engine shutdown. You don't need to call <tt>Neo4j.shutdown</tt> since
|
28
|
-
# the it will automatically be shutdown when the application exits (using the at_exit ruby hook).
|
29
|
-
#
|
30
|
-
# * <tt>db</tt> :: the Neo4j::Database instance
|
31
|
-
#
|
32
|
-
# ==== on_after_commit(data, state)
|
33
|
-
#
|
34
|
-
# Called after the transaction has successfully committed.
|
35
|
-
# See http://api.neo4j.org/1.4/org/neo4j/graphdb/event/TransactionEventHandler.html for the data and state parameter.
|
36
|
-
#
|
37
|
-
# ==== on_node_created(node)
|
38
|
-
#
|
39
|
-
# * <tt>node</tt> :: the node that was created
|
40
|
-
#
|
41
|
-
# ==== on_node_deleted(node, old_props, deleted_relationship_set, deleted_node_identity_map)
|
42
|
-
#
|
43
|
-
# * <tt>node</tt> :: the node that was deleted
|
44
|
-
# * <tt>old_props</tt> :: a hash of the old properties this node had
|
45
|
-
# * <tt>deleted_relationship_set</tt> :: the set of deleted relationships. See Neo4j::RelationshipSet
|
46
|
-
# * <tt>deleted_node_identity_map</tt> :: the identity map of deleted nodes. The key is the node id, and the value is the node
|
47
|
-
#
|
48
|
-
# ==== on_relationship_created(rel, created_node_identity_map)
|
49
|
-
#
|
50
|
-
# * <tt>rel</tt> :: the relationship that was created
|
51
|
-
# * <tt>created_node_identity_map</tt> :: the identity map of created nodes. The key is the node id, and the value is the node
|
52
|
-
#
|
53
|
-
# ==== on_relationship_deleted(rel, old_props, deleted_relationship_set, deleted_node_identity_map)
|
54
|
-
#
|
55
|
-
# * <tt>rel</tt> :: the relationship that was created
|
56
|
-
# * <tt>old_props</tt> :: a hash of the old properties this relationship had
|
57
|
-
# * <tt>deleted_relationship_set</tt> :: the set of deleted relationships. See Neo4j::RelationshipSet
|
58
|
-
# * <tt>deleted_node_identity_map</tt> :: the identity map of deleted nodes. The key is the node id, and the value is the node
|
59
|
-
#
|
60
|
-
# ==== on_property_changed(node, key, old_value, new_value)
|
61
|
-
#
|
62
|
-
# * <tt>node</tt> :: the node
|
63
|
-
# * <tt>key</tt> :: the name of the property that was changed (String)
|
64
|
-
# * <tt>old_value</tt> :: old value of the property
|
65
|
-
# * <tt>new_value</tt> :: new value of the property
|
66
|
-
#
|
67
|
-
# ==== on_rel_property_changed(rel, key, old_value, new_value)
|
68
|
-
#
|
69
|
-
# * <tt>rel</tt> :: the node that was created
|
70
|
-
# * <tt>key</tt> :: the name of the property that was changed (String)
|
71
|
-
# * <tt>old_value</tt> :: old value of the property
|
72
|
-
# * <tt>new_value</tt> :: new value of the property
|
73
|
-
#
|
74
|
-
# ==== classes_changed(class_change_map)
|
75
|
-
# * <tt>class_change_map</tt> :: a hash with class names as keys, and class changes as values. See Neo4j::ClassChanges
|
76
|
-
#
|
77
|
-
# == Usage
|
78
|
-
#
|
79
|
-
# class MyListener
|
80
|
-
# def on_node_deleted(node, old_props, deleted_relationship_set, deleted_node_identity_map)
|
81
|
-
# end
|
82
|
-
# end
|
83
|
-
#
|
84
|
-
# # to add an listener without starting neo4j:
|
85
|
-
# Neo4j.unstarted_db.event_handler.add(MyListener.new)
|
86
|
-
#
|
87
|
-
# You only need to implement the methods that you need.
|
88
|
-
#
|
89
|
-
class EventHandler
|
90
|
-
include org.neo4j.graphdb.event.TransactionEventHandler
|
91
|
-
|
92
|
-
def initialize
|
93
|
-
@listeners = []
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
def after_commit(data, state)
|
98
|
-
@listeners.each {|li| li.on_after_commit(data, state) if li.respond_to?(:on_after_commit)}
|
99
|
-
end
|
100
|
-
|
101
|
-
def after_rollback(data, state)
|
102
|
-
end
|
103
|
-
|
104
|
-
def before_commit(data)
|
105
|
-
class_change_map = java.util.HashMap.new
|
106
|
-
created_node_identity_map = iterate_created_nodes(data.created_nodes, class_change_map)
|
107
|
-
deleted_node_identity_map = deleted_node_identity_map(data.deleted_nodes)
|
108
|
-
deleted_relationship_set = relationship_set(data.deleted_relationships)
|
109
|
-
removed_node_properties_map = property_map(data.removed_node_properties)
|
110
|
-
removed_relationship_properties_map = property_map(data.removed_relationship_properties)
|
111
|
-
add_deleted_nodes(data, class_change_map, removed_node_properties_map)
|
112
|
-
empty_map = java.util.HashMap.new
|
113
|
-
data.assigned_node_properties.each { |tx_data| property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, tx_data.value) unless tx_data.key == '_classname'}
|
114
|
-
data.removed_node_properties.each { |tx_data| property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, nil) unless deleted_node_identity_map.containsKey(tx_data.entity.getId) }
|
115
|
-
data.deleted_nodes.each { |node| node_deleted(node, removed_node_properties_map.get(node.getId)||empty_map, deleted_relationship_set, deleted_node_identity_map)}
|
116
|
-
data.created_relationships.each {|rel| relationship_created(rel, created_node_identity_map)}
|
117
|
-
data.deleted_relationships.each {|rel| relationship_deleted(rel, removed_relationship_properties_map.get(rel.getId)||empty_map, deleted_relationship_set, deleted_node_identity_map)}
|
118
|
-
data.assigned_relationship_properties.each { |tx_data| rel_property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, tx_data.value) }
|
119
|
-
data.removed_relationship_properties.each {|tx_data| rel_property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, nil) unless deleted_relationship_set.contains_rel?(tx_data.entity) }
|
120
|
-
classes_changed(class_change_map)
|
121
|
-
rescue Exception => e
|
122
|
-
# since these exceptions gets swallowed
|
123
|
-
puts "ERROR in before commit hook #{e}"
|
124
|
-
puts e.backtrace.join("\n")
|
125
|
-
end
|
126
|
-
|
127
|
-
|
128
|
-
def iterate_created_nodes(nodes, class_change_map)
|
129
|
-
identity_map = java.util.HashMap.new
|
130
|
-
nodes.each do |node|
|
131
|
-
identity_map.put(node.neo_id,node) #using put due to a performance regression in JRuby 1.6.4
|
132
|
-
instance_created(node, class_change_map)
|
133
|
-
node_created(node)
|
134
|
-
end
|
135
|
-
identity_map
|
136
|
-
end
|
137
|
-
|
138
|
-
def deleted_node_identity_map(nodes)
|
139
|
-
identity_map = java.util.HashMap.new
|
140
|
-
nodes.each{|node| identity_map.put(node.neo_id,node)} #using put due to a performance regression in JRuby 1.6.4
|
141
|
-
identity_map
|
142
|
-
end
|
143
|
-
|
144
|
-
def relationship_set(relationships)
|
145
|
-
relationship_set = Neo4j::RelationshipSet.new#(relationships.size)
|
146
|
-
relationships.each{|rel| relationship_set.add(rel)}
|
147
|
-
relationship_set
|
148
|
-
end
|
149
|
-
|
150
|
-
def property_map(properties)
|
151
|
-
map = java.util.HashMap.new
|
152
|
-
properties.each do |property|
|
153
|
-
map(property.entity.getId, map).put(property.key, property.previously_commited_value)
|
154
|
-
end
|
155
|
-
map
|
156
|
-
end
|
157
|
-
|
158
|
-
def map(key,map)
|
159
|
-
map.get(key) || add_map(key,map)
|
160
|
-
end
|
161
|
-
|
162
|
-
def add_map(key,map)
|
163
|
-
map.put(key, java.util.HashMap.new)
|
164
|
-
map.get(key)
|
165
|
-
end
|
166
|
-
|
167
|
-
def add(listener)
|
168
|
-
@listeners << listener unless @listeners.include?(listener)
|
169
|
-
end
|
170
|
-
|
171
|
-
def remove(listener)
|
172
|
-
@listeners.delete(listener)
|
173
|
-
end
|
174
|
-
|
175
|
-
def remove_all
|
176
|
-
@listeners = []
|
177
|
-
end
|
178
|
-
|
179
|
-
def print
|
180
|
-
puts "Listeners #{@listeners.size}"
|
181
|
-
@listeners.each {|li| puts " Listener '#{li}'"}
|
182
|
-
end
|
183
|
-
|
184
|
-
def neo4j_started(db)
|
185
|
-
@listeners.each { |li| li.on_neo4j_started(db) if li.respond_to?(:on_neo4j_started) }
|
186
|
-
end
|
187
|
-
|
188
|
-
def neo4j_shutdown(db)
|
189
|
-
@listeners.each { |li| li.on_neo4j_shutdown(db) if li.respond_to?(:on_neo4j_shutdown) }
|
190
|
-
end
|
191
|
-
|
192
|
-
def node_created(node)
|
193
|
-
@listeners.each {|li| li.on_node_created(node) if li.respond_to?(:on_node_created)}
|
194
|
-
end
|
195
|
-
|
196
|
-
def node_deleted(node,old_properties, deleted_relationship_set, deleted_node_identity_map)
|
197
|
-
@listeners.each {|li| li.on_node_deleted(node,old_properties, deleted_relationship_set, deleted_node_identity_map) if li.respond_to?(:on_node_deleted)}
|
198
|
-
end
|
199
|
-
|
200
|
-
def relationship_created(relationship, created_node_identity_map)
|
201
|
-
@listeners.each {|li| li.on_relationship_created(relationship, created_node_identity_map) if li.respond_to?(:on_relationship_created)}
|
202
|
-
end
|
203
|
-
|
204
|
-
def relationship_deleted(relationship, old_props, deleted_relationship_set, deleted_node_identity_map)
|
205
|
-
@listeners.each {|li| li.on_relationship_deleted(relationship, old_props, deleted_relationship_set, deleted_node_identity_map) if li.respond_to?(:on_relationship_deleted)}
|
206
|
-
end
|
207
|
-
|
208
|
-
def property_changed(node, key, old_value, new_value)
|
209
|
-
@listeners.each {|li| li.on_property_changed(node, key, old_value, new_value) if li.respond_to?(:on_property_changed)}
|
210
|
-
end
|
211
|
-
|
212
|
-
def rel_property_changed(rel, key, old_value, new_value)
|
213
|
-
@listeners.each {|li| li.on_rel_property_changed(rel, key, old_value, new_value) if li.respond_to?(:on_rel_property_changed)}
|
214
|
-
end
|
215
|
-
|
216
|
-
def add_deleted_nodes(data, class_change_map, removed_node_properties_map)
|
217
|
-
data.deleted_nodes.each{|node| instance_deleted(node, removed_node_properties_map, class_change_map)}
|
218
|
-
end
|
219
|
-
|
220
|
-
def instance_created(node, class_change_map)
|
221
|
-
classname = node[:_classname]
|
222
|
-
class_change(classname, class_change_map).add(node) if classname
|
223
|
-
end
|
224
|
-
|
225
|
-
def instance_deleted(node, removed_node_properties_map, class_change_map)
|
226
|
-
properties = removed_node_properties_map.get(node.getId)
|
227
|
-
if properties
|
228
|
-
classname = properties.get("_classname")
|
229
|
-
class_change(classname, class_change_map).delete(node) if classname
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
def class_change(classname, class_change_map)
|
234
|
-
class_change_map.put(classname, ClassChanges.new) if class_change_map.get(classname).nil?
|
235
|
-
class_change_map.get(classname)
|
236
|
-
end
|
237
|
-
|
238
|
-
def classes_changed(changed_class_map)
|
239
|
-
@listeners.each {|li| li.classes_changed(changed_class_map) if li.respond_to?(:classes_changed)}
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
class ClassChanges
|
244
|
-
attr_accessor :added, :deleted
|
245
|
-
|
246
|
-
def initialize
|
247
|
-
self.added = []
|
248
|
-
self.deleted = []
|
249
|
-
end
|
250
|
-
|
251
|
-
def add(node)
|
252
|
-
self.added << node
|
253
|
-
end
|
254
|
-
|
255
|
-
def delete(node)
|
256
|
-
self.deleted << node
|
257
|
-
end
|
258
|
-
|
259
|
-
def net_change
|
260
|
-
self.added.size - self.deleted.size
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|