neo4j 1.2.6-java → 2.0.0.alpha.3-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.
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