neo4j 1.2.6-java → 2.0.0.alpha.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG +30 -0
  2. data/CONTRIBUTORS +1 -0
  3. data/Gemfile +16 -4
  4. data/README.rdoc +25 -3
  5. data/bin/neo4j-jars +15 -8
  6. data/bin/neo4j-shell +0 -1
  7. data/bin/neo4j-upgrade +72 -0
  8. data/config/neo4j/config.yml +5 -4
  9. data/lib/neo4j/algo/algo.rb +0 -1
  10. data/lib/neo4j/batch/inserter.rb +5 -0
  11. data/lib/neo4j/database.rb +18 -12
  12. data/lib/neo4j/event_handler.rb +76 -9
  13. data/lib/neo4j/has_list/class_methods.rb +1 -1
  14. data/lib/neo4j/has_list/mapping.rb +13 -33
  15. data/lib/neo4j/has_n/decl_relationship_dsl.rb +17 -13
  16. data/lib/neo4j/has_n/mapping.rb +6 -23
  17. data/lib/neo4j/identity_map.rb +0 -3
  18. data/lib/neo4j/index/class_methods.rb +9 -3
  19. data/lib/neo4j/index/index.rb +2 -1
  20. data/lib/neo4j/index/indexer.rb +3 -2
  21. data/lib/neo4j/index/indexer_registry.rb +1 -1
  22. data/lib/neo4j/index/lucene_query.rb +52 -33
  23. data/lib/neo4j/neo4j.rb +19 -0
  24. data/lib/neo4j/node.rb +42 -36
  25. data/lib/neo4j/node_mixin/node_mixin.rb +9 -5
  26. data/lib/neo4j/paginated.rb +23 -0
  27. data/lib/neo4j/rails/accept_id.rb +66 -0
  28. data/lib/neo4j/rails/attributes.rb +14 -9
  29. data/lib/neo4j/rails/compositions.rb +9 -1
  30. data/lib/neo4j/rails/finders.rb +5 -1
  31. data/lib/neo4j/rails/mapping/property.rb +41 -28
  32. data/lib/neo4j/rails/model.rb +2 -0
  33. data/lib/neo4j/rails/observer.rb +61 -2
  34. data/lib/neo4j/rails/persistence.rb +57 -57
  35. data/lib/neo4j/rails/rails.rb +1 -0
  36. data/lib/neo4j/rails/railtie.rb +4 -1
  37. data/lib/neo4j/rails/rel_persistence.rb +11 -12
  38. data/lib/neo4j/rails/relationship.rb +9 -4
  39. data/lib/neo4j/rails/relationships/node_dsl.rb +15 -5
  40. data/lib/neo4j/rails/relationships/relationships.rb +42 -2
  41. data/lib/neo4j/rails/relationships/rels_dsl.rb +60 -3
  42. data/lib/neo4j/rails/relationships/storage.rb +43 -5
  43. data/lib/neo4j/rails/validations/uniqueness.rb +1 -0
  44. data/lib/neo4j/rails/versioning/versioning.rb +64 -9
  45. data/lib/neo4j/relationship.rb +79 -73
  46. data/lib/neo4j/rule/event_listener.rb +7 -1
  47. data/lib/neo4j/rule/functions/count.rb +6 -0
  48. data/lib/neo4j/rule/rule.rb +20 -5
  49. data/lib/neo4j/rule/rule_node.rb +33 -20
  50. data/lib/neo4j/to_java.rb +5 -0
  51. data/lib/neo4j/traversal/traverser.rb +38 -1
  52. data/lib/neo4j/type_converters/type_converters.rb +56 -5
  53. data/lib/neo4j/version.rb +1 -1
  54. data/lib/neo4j.rb +3 -49
  55. data/neo4j.gemspec +2 -2
  56. metadata +191 -216
  57. data/bin/neo4j-shell~ +0 -108
  58. data/lib/Gemfile~ +0 -3
  59. data/lib/config2.yml~ +0 -86
  60. data/lib/neo4j/jars/core/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  61. data/lib/neo4j/jars/core/lucene-core-3.1.0.jar +0 -0
  62. data/lib/neo4j/jars/core/neo4j-backup-1.4.1.jar +0 -0
  63. data/lib/neo4j/jars/core/neo4j-graph-algo-1.4.1.jar +0 -0
  64. data/lib/neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar +0 -0
  65. data/lib/neo4j/jars/core/neo4j-kernel-1.4.1.jar +0 -0
  66. data/lib/neo4j/jars/core/neo4j-lucene-index-1.4.1.jar +0 -0
  67. data/lib/neo4j/jars/ha/log4j-1.2.16.jar +0 -0
  68. data/lib/neo4j/jars/ha/neo4j-com-1.4.1.jar +0 -0
  69. data/lib/neo4j/jars/ha/neo4j-ha-1.4.1.jar +0 -0
  70. data/lib/neo4j/jars/ha/neo4j-jmx-1.4.1.jar +0 -0
  71. data/lib/neo4j/jars/ha/neo4j-management-1.4.1.jar +0 -0
  72. data/lib/neo4j/jars/ha/neo4j-shell-1.4.1.jar +0 -0
  73. data/lib/neo4j/jars/ha/netty-3.2.1.Final.jar +0 -0
  74. data/lib/neo4j/jars/ha/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
  75. data/lib/neo4j/jars/ha/zookeeper-3.3.2.jar +0 -0
  76. data/lib/neo4j/paginate.rb +0 -25
  77. data/lib/perf.rb~ +0 -36
  78. data/lib/test.rb~ +0 -2
@@ -2,6 +2,55 @@ module Neo4j
2
2
  module Rails
3
3
  module Relationships
4
4
 
5
+ # This DSL is return when asking for all relationship from and to a node, example node.rels.each{}
6
+ #
7
+ class AllRelsDsl
8
+ include Enumerable
9
+
10
+ def initialize(rels_stores, node)
11
+ @rels_stores = rels_stores
12
+ @node = node
13
+ end
14
+
15
+ def each
16
+ @rels_stores.each_value {|storage| storage.relationships(:both).each{|r| yield r}}
17
+ @node && @node.rels.each {|r| yield r}
18
+ end
19
+
20
+ # simply traverse and count all relationship
21
+ def size
22
+ s = 0
23
+ each { |_| s += 1 }
24
+ s
25
+ end
26
+
27
+ # Find all relationships between two nodes like this *if* the node is persisted.
28
+ # Returns an Enumerable. If the node is not persisted it will raise an error.
29
+ # Notice, only persisted relationships will be returned.
30
+ def to_other(other)
31
+ raise('node.rels(...).to_other() not allowed on a node that is not persisted') unless @node
32
+ @node.rels.to_other(other)
33
+ end
34
+
35
+ def delete_all
36
+ # since some of the relationships might not be a Neo4j::Rails::Relationship we must create a transaction
37
+ Neo4j::Transaction.run do
38
+ each{|r| r.respond_to?(:delete) ? r.delete : r.del}
39
+ end
40
+ @rels_stores.clear
41
+ end
42
+
43
+ def destroy_all
44
+ Neo4j::Transaction.run do
45
+ each{|r| r.respond_to?(:destroy)? r.destroy : r.del}
46
+ end
47
+ @rels_stores.clear
48
+ end
49
+
50
+ alias_method :del, :delete_all
51
+ end
52
+
53
+
5
54
  # Instances of this class is returned from the #rels, and generated accessor methods:
6
55
  # has_n and has_one.
7
56
  # Notice, this class is very similar to the Neo4j::Rails::Relationships::NodesDSL except that
@@ -18,7 +67,6 @@ module Neo4j
18
67
  #
19
68
  class RelsDSL
20
69
  include Enumerable
21
- include Neo4j::Paginate
22
70
 
23
71
  def initialize(storage, dir=:both)
24
72
  @storage = storage
@@ -42,6 +90,13 @@ module Neo4j
42
90
  rel
43
91
  end
44
92
 
93
+ # Find all relationships between two nodes like this *if* the node is persisted.
94
+ # Returns an Enumerable. If the node is not persisted it will raise an error.
95
+ # Notice, only persisted relationships will be returned.
96
+ def to_other(other)
97
+ @storage.to_other(other)
98
+ end
99
+
45
100
  # Connects this node with an already existing other node with a new relationship.
46
101
  # The relationship can optionally be given a hash of properties
47
102
  # Does not save it.
@@ -81,8 +136,8 @@ module Neo4j
81
136
  self
82
137
  end
83
138
 
84
- def each(&block)
85
- @storage.each_rel(@dir, &block)
139
+ def each
140
+ @storage.each_rel(@dir) {|x| yield x}
86
141
  end
87
142
 
88
143
  # Simply counts all relationships
@@ -98,11 +153,13 @@ module Neo4j
98
153
  # Destroys all relationships object. Will not destroy the nodes.
99
154
  def destroy_all
100
155
  each {|n| n.destroy}
156
+ @storage.clear_unpersisted
101
157
  end
102
158
 
103
159
  # Delete all relationship.
104
160
  def delete_all
105
161
  each {|n| n.delete}
162
+ @storage.clear_unpersisted
106
163
  end
107
164
 
108
165
  # Same as Neo4j::Rails::Relationships::NodesDSL#find except that it searches the relationships instead of
@@ -20,12 +20,21 @@ module Neo4j
20
20
  end
21
21
 
22
22
  def to_s #:nodoc:
23
- "Storage #{object_id} node: #{@node.id} rel_type: #{@rel_type} outgoing #{@outgoing_rels.size} incoming #{@incoming_rels.size}"
23
+ "Storage #{object_id} node: #{@node.id} rel_type: #{@rel_type} outgoing #{@outgoing_rels.size}/#{@unpersisted_outgoing_rels && @unpersisted_outgoing_rels.size} incoming #{@incoming_rels.size}/#{@unpersisted_incoming_rels && @unpersisted_incoming_rels.size}"
24
+ end
25
+
26
+ def clear_unpersisted
27
+ @outgoing_rels.clear
28
+ @incoming_rels.clear
29
+ @unpersisted_outgoing_rels = nil
30
+ @unpersisted_incoming_rels = nil
24
31
  end
25
32
 
26
33
  def remove_from_identity_map
27
34
  @outgoing_rels.each {|r| Neo4j::IdentityMap.remove(r._java_rel)}
28
35
  @incoming_rels.each {|r| Neo4j::IdentityMap.remove(r._java_rel)}
36
+ @unpersisted_outgoing_rels = nil
37
+ @unpersisted_incoming_rels = nil
29
38
  end
30
39
 
31
40
  def size(dir)
@@ -37,6 +46,10 @@ module Neo4j
37
46
  counter
38
47
  end
39
48
 
49
+ def to_other(other)
50
+ (@node._java_node) ? @node._java_node.rels(@rel_type).to_other(other) : raise('node.rels(...).to_other() not allowed on a node that is not persisted')
51
+ end
52
+
40
53
  def build(attrs)
41
54
  @target_class.new(attrs)
42
55
  end
@@ -48,9 +61,9 @@ module Neo4j
48
61
  def relationships(dir)
49
62
  case dir
50
63
  when :outgoing
51
- @outgoing_rels
64
+ @unpersisted_outgoing_rels || @outgoing_rels
52
65
  when :incoming
53
- @incoming_rels
66
+ @unpersisted_incoming_rels || @incoming_rels
54
67
  when :both
55
68
  @incoming_rels + @outgoing_rels
56
69
  end
@@ -113,6 +126,11 @@ module Neo4j
113
126
  end
114
127
  end
115
128
 
129
+ def destroy_single_relationship(dir)
130
+ rel = single_relationship(dir)
131
+ rel && rel.destroy && relationships(dir).delete(rel)
132
+ end
133
+
116
134
  def all_relationships(dir)
117
135
  Enumerator.new(self, :each_rel, dir)
118
136
  end
@@ -146,6 +164,18 @@ module Neo4j
146
164
  @outgoing_rels << rel
147
165
  end
148
166
 
167
+ # Makes the given relationship available in callbacks
168
+ def add_unpersisted_incoming_rel(rel)
169
+ @unpersisted_incoming_rels ||= []
170
+ @unpersisted_incoming_rels << rel
171
+ end
172
+
173
+ # Makes the given relationship available in callbacks
174
+ def add_unpersisted_outgoing_rel(rel)
175
+ @unpersisted_outgoing_rels ||= []
176
+ @unpersisted_outgoing_rels << rel
177
+ end
178
+
149
179
  def rm_incoming_rel(rel)
150
180
  @incoming_rels.delete(rel)
151
181
  end
@@ -154,6 +184,16 @@ module Neo4j
154
184
  @outgoing_rels.delete(rel)
155
185
  end
156
186
 
187
+ def rm_unpersisted_incoming_rel(rel)
188
+ @unpersisted_incoming_rels.delete(rel)
189
+ @unpersisted_incoming_rels = nil if @unpersisted_incoming_rels.empty?
190
+ end
191
+
192
+ def rm_unpersisted_outgoing_rel(rel)
193
+ @unpersisted_outgoing_rels.delete(rel)
194
+ @unpersisted_outgoing_rels = nil if @unpersisted_outgoing_rels.empty?
195
+ end
196
+
157
197
  def persisted?
158
198
  @outgoing_rels.empty? && @incoming_rels.empty?
159
199
  end
@@ -165,14 +205,12 @@ module Neo4j
165
205
  [@outgoing_rels, @incoming_rels, @persisted_related_nodes, @persisted_node_to_relationships, @persisted_relationships].each{|c| c.clear}
166
206
 
167
207
  out_rels.each do |rel|
168
- rel.end_node.rm_incoming_rel(@rel_type.to_sym, rel) if rel.end_node
169
208
  success = rel.persisted? || rel.save
170
209
  # don't think this can happen - just in case, TODO
171
210
  raise "Can't save outgoing #{rel}, validation errors ? #{rel.errors.inspect}" unless success
172
211
  end
173
212
 
174
213
  in_rels.each do |rel|
175
- rel.start_node.rm_outgoing_rel(@rel_type.to_sym, rel)
176
214
  success = rel.persisted? || rel.save
177
215
  # don't think this can happen - just in case, TODO
178
216
  raise "Can't save incoming #{rel}, validation errors ? #{rel.errors.inspect}" unless success
@@ -54,6 +54,7 @@ module Neo4j
54
54
  end
55
55
 
56
56
  def self.query(model,attribute,value)
57
+ value = value.gsub("\"", "\\\"") if !value.blank?
57
58
  value.blank? ? model.all("*:* -#{attribute}:[* TO *]", :type => :fulltext) : model.all("#{attribute}: \"#{value}\"", :type => :fulltext)
58
59
  end
59
60
 
@@ -45,6 +45,16 @@ module Neo4j
45
45
  class Snapshot
46
46
  include Neo4j::NodeMixin
47
47
 
48
+ def assign(key,value)
49
+ @converted_properties = {} if @converted_properties.nil?
50
+ @converted_properties[key.to_sym] = value
51
+ end
52
+
53
+ def [](key)
54
+ return @converted_properties[key] if @converted_properties
55
+ super(key)
56
+ end
57
+
48
58
  def incoming(rel_type)
49
59
  super "version_#{rel_type.to_s}".to_sym
50
60
  end
@@ -70,7 +80,9 @@ module Neo4j
70
80
  # @param [ Integer ] number The version number to retrieve.
71
81
  # Returns nil in case a version is not found.
72
82
  def version(number)
73
- Version.find(:model_classname => _classname, :instance_id => neo_id, :number => number) {|query| query.first.nil? ? nil : query.first.end_node}
83
+ snapshot = Version.find(:model_classname => _classname, :instance_id => neo_id, :number => number) {|query| query.first.nil? ? nil : query.first.end_node}
84
+ snapshot.props.each_pair{|k,v| snapshot.assign(k,Neo4j::TypeConverters.to_ruby(self.class, k, v))} if !snapshot.nil?
85
+ snapshot
74
86
  end
75
87
 
76
88
  ##
@@ -83,40 +95,83 @@ module Neo4j
83
95
  end
84
96
  end
85
97
 
98
+ ##
99
+ # Reverts this instance to a specified version
100
+ # @param [ Integer ] version_number The version number to revert to.
101
+ # Reverting the instance will increment the current version number.
102
+ def revert_to(version_number)
103
+ snapshot = version(version_number)
104
+ self.props.each_pair{|k,v| self[k] = nil if !snapshot.props.has_key?(k)}
105
+ snapshot.props.each_pair{|k,v| self[k] = v if self.props[k].nil?}
106
+ Neo4j::Transaction.run do
107
+ restore_relationships(snapshot)
108
+ save
109
+ end
110
+ end
111
+
86
112
  private
87
113
  def revise
88
114
  Neo4j::Transaction.run do
89
- snapshot = Snapshot.new(self.props.reject{|key, value| key.to_sym == :_classname})
90
- version_relationships(snapshot)
115
+ snapshot = Snapshot.new(converted_properties)
116
+ each_versionable_relationship{|rel| create_version_relationship(rel,snapshot)}
91
117
  delete_old_version if version_max.present? && number_of_versions >= version_max
92
118
  Version.new(:version, self, snapshot, :model_classname => _classname, :instance_id => neo_id, :number => current_version)
93
119
  end
94
120
  end
95
121
 
122
+ def converted_properties
123
+ properties = self.props.reject{|key, value| key.to_sym == :_classname}
124
+ properties.inject({}) { |h,(k,v)| h[k] = Neo4j::TypeConverters.to_java(self.class, k, v); h }
125
+ end
126
+
96
127
  def number_of_versions
97
128
  Version.find(:model_classname => _classname, :instance_id => neo_id) {|query| query.size}
98
129
  end
99
130
 
100
- def version_relationships(snapshot)
131
+ def each_versionable_relationship
132
+ rule_relationships = java.util.HashSet.new(Neo4j::Rule::Rule.rule_names_for(_classname))
101
133
  self._java_node.getRelationships().each do |rel|
102
- if (self._java_node == rel.getStartNode())
103
- snapshot._java_node.createRelationshipTo(rel.getEndNode(), relationship_type(rel.getType()))
104
- else
105
- rel.getStartNode().createRelationshipTo(snapshot._java_node, relationship_type(rel.getType()))
106
- end
134
+ yield rel unless rule_relationships.contains(rel.getType().name().to_sym) || rel.getType.name.to_sym == :version
107
135
  end
108
136
  end
109
137
 
138
+ def create_version_relationship(rel,snapshot)
139
+ create_relationship(self._java_node,snapshot._java_node, rel, relationship_type(rel.getType()))
140
+ end
141
+
110
142
  def relationship_type(rel_type)
111
143
  org.neo4j.graphdb.DynamicRelationshipType.withName( "version_#{rel_type.name}" )
112
144
  end
113
145
 
146
+ def restore_relationship_type(snapshot_rel_type)
147
+ org.neo4j.graphdb.DynamicRelationshipType.withName( "#{snapshot_rel_type.name.gsub("version_","")}" )
148
+ end
149
+
114
150
  def delete_old_version
115
151
  versions = Version.find(:model_classname => _classname).asc(:number)
116
152
  versions.first.del
117
153
  versions.close
118
154
  end
119
155
 
156
+ def restore_relationships(snapshot)
157
+ each_versionable_relationship{|rel| rel.del}
158
+ snapshot._java_node.getRelationships().each do |rel|
159
+ restore_relationship(rel,snapshot) unless rel.getType.name.to_sym == :version
160
+ end
161
+ end
162
+
163
+ def restore_relationship(rel,snapshot)
164
+ create_relationship(snapshot._java_node, self._java_node, rel, restore_relationship_type(rel.getType()))
165
+ end
166
+
167
+ def create_relationship(comparison_node,connection_node,rel, relationship_type)
168
+ if (comparison_node == rel.getStartNode())
169
+ connection_node.createRelationshipTo(rel.getEndNode(), relationship_type)
170
+ else
171
+ rel.getStartNode().createRelationshipTo(connection_node, relationship_type)
172
+ end
173
+ end
174
+
120
175
  module ClassMethods #:nodoc:
121
176
 
122
177
  # Sets the maximum number of versions to store.
@@ -7,79 +7,6 @@ require 'neo4j/to_java'
7
7
 
8
8
  module Neo4j
9
9
 
10
- org.neo4j.kernel.impl.core.RelationshipProxy.class_eval do
11
- include Neo4j::Property
12
- include Neo4j::Equal
13
-
14
- alias_method :_end_node, :getEndNode
15
- alias_method :_start_node, :getStartNode
16
- alias_method :_other_node, :getOtherNode
17
-
18
-
19
- # Deletes the relationship between the start and end node
20
- #
21
- # May raise an exception if delete was unsuccessful.
22
- #
23
- # ==== Returns
24
- # nil
25
- #
26
- def del
27
- delete
28
- end
29
-
30
- def end_node # :nodoc:
31
- getEndNode.wrapper
32
- end
33
-
34
- def start_node # :nodoc:
35
- getStartNode.wrapper
36
- end
37
-
38
- def other_node(node) # :nodoc:
39
- getOtherNode(node._java_node).wrapper
40
- end
41
-
42
-
43
- # same as _java_rel
44
- # Used so that we have same method for both relationship and nodes
45
- def wrapped_entity
46
- self
47
- end
48
-
49
- def _java_rel
50
- self
51
- end
52
-
53
-
54
- # Returns true if the relationship exists
55
- def exist?
56
- Neo4j::Relationship.exist?(self)
57
- end
58
-
59
- # Loads the Ruby wrapper for this node
60
- # If there is no _classname property for this node then it will simply return itself.
61
- # Same as Neo4j::Node.load_wrapper(node)
62
- def wrapper
63
- self.class.wrapper(self)
64
- end
65
-
66
-
67
- # Returns the relationship name
68
- #
69
- # ==== Example
70
- # a = Neo4j::Node.new
71
- # a.outgoing(:friends) << Neo4j::Node.new
72
- # a.rels.first.rel_type # => 'friends'
73
- #
74
- def rel_type
75
- getType().name()
76
- end
77
-
78
- def class
79
- Neo4j::Relationship
80
- end
81
-
82
- end
83
10
 
84
11
  #
85
12
  # A relationship between two nodes in the graph. A relationship has a start node, an end node and a type.
@@ -224,6 +151,85 @@ module Neo4j
224
151
  nil
225
152
  end
226
153
 
154
+ def extend_java_class(java_clazz) #:nodoc:
155
+ java_clazz.class_eval do
156
+ include Neo4j::Property
157
+ include Neo4j::Equal
158
+
159
+ alias_method :_end_node, :getEndNode
160
+ alias_method :_start_node, :getStartNode
161
+ alias_method :_other_node, :getOtherNode
162
+
163
+
164
+ # Deletes the relationship between the start and end node
165
+ #
166
+ # May raise an exception if delete was unsuccessful.
167
+ #
168
+ # ==== Returns
169
+ # nil
170
+ #
171
+ def del
172
+ delete
173
+ end
174
+
175
+ def end_node # :nodoc:
176
+ getEndNode.wrapper
177
+ end
178
+
179
+ def start_node # :nodoc:
180
+ getStartNode.wrapper
181
+ end
182
+
183
+ def other_node(node) # :nodoc:
184
+ getOtherNode(node._java_node).wrapper
185
+ end
186
+
187
+
188
+ # same as _java_rel
189
+ # Used so that we have same method for both relationship and nodes
190
+ def wrapped_entity
191
+ self
192
+ end
193
+
194
+ def _java_rel
195
+ self
196
+ end
197
+
198
+
199
+ # Returns true if the relationship exists
200
+ def exist?
201
+ Neo4j::Relationship.exist?(self)
202
+ end
203
+
204
+ # Loads the Ruby wrapper for this node
205
+ # If there is no _classname property for this node then it will simply return itself.
206
+ # Same as Neo4j::Node.load_wrapper(node)
207
+ def wrapper
208
+ self.class.wrapper(self)
209
+ end
210
+
211
+
212
+ # Returns the relationship name
213
+ #
214
+ # ==== Example
215
+ # a = Neo4j::Node.new
216
+ # a.outgoing(:friends) << Neo4j::Node.new
217
+ # a.rels.first.rel_type # => 'friends'
218
+ #
219
+ def rel_type
220
+ getType().name()
221
+ end
222
+
223
+ def class
224
+ Neo4j::Relationship
225
+ end
226
+
227
+ end
228
+
229
+ end
230
+
231
+ Neo4j::Relationship.extend_java_class(org.neo4j.kernel.impl.core.RelationshipProxy)
232
+
227
233
  end
228
234
 
229
235
  end
@@ -30,7 +30,7 @@ module Neo4j
30
30
 
31
31
  id = node.getId
32
32
  rule_node.rules.each do |rule|
33
- next if rule.functions.nil?
33
+ next if rule.functions.nil? || rule.bulk_update?
34
34
  rule_name = rule.rule_name.to_s
35
35
 
36
36
  # is the rule node deleted ?
@@ -45,6 +45,12 @@ module Neo4j
45
45
  end
46
46
  end
47
47
 
48
+ def classes_changed(changed_class_map)
49
+ changed_class_map.each_pair do |clazz,class_change|
50
+ Rule.bulk_trigger_rules(clazz,class_change,changed_class_map)
51
+ end
52
+ end
53
+
48
54
  def on_neo4j_started(db)
49
55
  if not Neo4j::Config[:enable_rules]
50
56
  db.event_handler.remove(self)
@@ -28,6 +28,12 @@ module Neo4j
28
28
  # we are only counting, not interested in property changes
29
29
  end
30
30
 
31
+ def classes_changed(rule_name, rule_node, class_change)
32
+ key = rule_node_property(rule_name)
33
+ rule_node[key] ||= 0
34
+ rule_node[key] += class_change.net_change
35
+ end
36
+
31
37
  def self.function_name
32
38
  :count
33
39
  end
@@ -24,6 +24,7 @@ module Neo4j
24
24
  @triggers = [@triggers] if @triggers && !@triggers.respond_to?(:each)
25
25
  @functions = [@functions] if @functions && !@functions.respond_to?(:each)
26
26
  @filter = block
27
+ @bulk_update = !@functions.nil? && @functions.size == 1 && @functions.first.class.function_name == :count && @filter.nil?
27
28
  end
28
29
 
29
30
  def to_s
@@ -58,6 +59,10 @@ module Neo4j
58
59
  end
59
60
  end
60
61
 
62
+ def bulk_update?
63
+ @bulk_update
64
+ end
65
+
61
66
  # ------------------------------------------------------------------------------------------------------------------
62
67
  # Class Methods
63
68
  # ------------------------------------------------------------------------------------------------------------------
@@ -74,7 +79,7 @@ module Neo4j
74
79
  def has_rules?(clazz)
75
80
  !@rule_nodes[clazz.to_s].nil?
76
81
  end
77
-
82
+
78
83
  def rule_names_for(clazz)
79
84
  rule_node = rule_node_for(clazz)
80
85
  rule_node.rules.map { |rule| rule.rule_name }
@@ -105,7 +110,7 @@ module Neo4j
105
110
 
106
111
  def trigger?(node)
107
112
  classname = node[:_classname]
108
- @rule_nodes && classname && rule_node_for(classname)
113
+ @rule_nodes && classname && rule_node_for(classname) && !rule_node_for(classname).bulk_update?
109
114
  end
110
115
 
111
116
  def trigger_rules(node, *changes)
@@ -118,15 +123,25 @@ module Neo4j
118
123
  recursive(node,rule_node.model_class,*changes)
119
124
  end
120
125
 
121
- private
126
+ def bulk_trigger_rules(classname,class_change, map)
127
+ rule_node = rule_node_for(classname)
128
+ rule_node.classes_changed(class_change)
129
+ if (clazz = rule_node.model_class.superclass) && clazz.include?(Neo4j::NodeMixin)
130
+ bulk_trigger_rules(clazz.name,class_change,map) if clazz != Neo4j::Rails::Model
131
+ end
132
+ end
133
+
134
+ private
122
135
 
123
- def recursive(node,model_class,*changes)
124
- if (clazz = model_class.superclass) && clazz.include?(Neo4j::NodeMixin)
136
+ def recursive(node,model_class,*changes)
137
+ if (clazz = model_class.superclass) && clazz.include?(Neo4j::NodeMixin)
138
+ if clazz != Neo4j::Rails::Model
125
139
  rule_node = rule_node_for(clazz)
126
140
  rule_node && rule_node.execute_rules(node, *changes)
127
141
  recursive(node,clazz,*changes)
128
142
  end
129
143
  end
144
+ end
130
145
  end
131
146
  end
132
147
  end
@@ -10,9 +10,11 @@ module Neo4j
10
10
  include ToJava
11
11
  attr_reader :rules
12
12
  attr_reader :model_class
13
+ @@rule_nodes = {}
13
14
 
14
15
  def initialize(clazz)
15
- @model_class = eval("#{clazz}")
16
+ classname = clazz.to_s
17
+ @model_class = classname[0,1] == "#" ? eval(classname) : classname.split('::').inject(Kernel) {|sc, const_name| sc.const_get(const_name)}
16
18
  @classname = clazz
17
19
  @rules = []
18
20
  @rule_node_key = ("rule_" + clazz.to_s).to_sym
@@ -27,7 +29,21 @@ module Neo4j
27
29
  def node_exist?
28
30
  !ref_node.rel?(@classname)
29
31
  end
30
-
32
+
33
+ def rule_node
34
+ ref_node._java_node.synchronized do
35
+ @@rule_nodes[key] ||= find_node || create_node
36
+ end
37
+ end
38
+
39
+ def rule_node?(node)
40
+ @@rule_nodes[key] == node
41
+ end
42
+
43
+ def key
44
+ "#{ref_node}#{@ref_node_key}".to_sym
45
+ end
46
+
31
47
  def ref_node
32
48
  if @model_class.respond_to? :ref_node_for_class
33
49
  @model_class.ref_node_for_class
@@ -61,11 +77,6 @@ module Neo4j
61
77
  ref_node.rel?(@classname.to_s) && ref_node._rel(:outgoing, @classname.to_s)._end_node
62
78
  end
63
79
 
64
- def rule_node
65
- clear_rule_node if ref_node_changed?
66
- Thread.current[@rule_node_key] ||= find_node || create_node
67
- end
68
-
69
80
  def ref_node_changed?
70
81
  if ref_node != Thread.current[@ref_node_key]
71
82
  Thread.current[@ref_node_key] = ref_node
@@ -75,16 +86,8 @@ module Neo4j
75
86
  end
76
87
  end
77
88
 
78
- def rule_node?(node)
79
- cached_rule_node == node
80
- end
81
-
82
- def cached_rule_node
83
- Thread.current[@rule_node_key]
84
- end
85
-
86
89
  def clear_rule_node
87
- Thread.current[@rule_node_key] = nil
90
+ @@rule_nodes[key] = nil
88
91
  end
89
92
 
90
93
  def rule_names
@@ -186,7 +189,7 @@ module Neo4j
186
189
  end
187
190
 
188
191
  def connect(rule_name, end_node)
189
- rule_node.outgoing(rule_name) << end_node
192
+ rule_node._java_node.createRelationshipTo(end_node._java_node, org.neo4j.graphdb.DynamicRelationshipType.withName(rule_name))
190
193
  end
191
194
 
192
195
  # sever a direct one-to-one relationship if it exists
@@ -196,9 +199,19 @@ module Neo4j
196
199
  !rel.nil?
197
200
  end
198
201
 
199
- end
200
-
202
+ def bulk_update?
203
+ @rules.size == 1 && @rules.first.bulk_update?
204
+ end
201
205
 
206
+ def classes_changed(total)
207
+ @rules.each do |rule|
208
+ if rule.bulk_update?
209
+ rule.functions.first.classes_changed(rule.rule_name, rule_node, total)
210
+ total.added.each{|node| connect(rule.rule_name, node)}
211
+ total.deleted.each{|node| break_connection(rule.rule_name, node)}
212
+ end
213
+ end
214
+ end
215
+ end
202
216
  end
203
-
204
217
  end