neo4j 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/CHANGELOG +141 -0
  2. data/CONTRIBUTORS +15 -0
  3. data/Gemfile +3 -0
  4. data/README.rdoc +2015 -0
  5. data/lib/neo4j.old/batch_inserter.rb +144 -0
  6. data/lib/neo4j.old/config.rb +138 -0
  7. data/lib/neo4j.old/event_handler.rb +73 -0
  8. data/lib/neo4j.old/extensions/activemodel.rb +158 -0
  9. data/lib/neo4j.old/extensions/aggregate.rb +12 -0
  10. data/lib/neo4j.old/extensions/aggregate/aggregate_enum.rb +40 -0
  11. data/lib/neo4j.old/extensions/aggregate/ext/node_mixin.rb +69 -0
  12. data/lib/neo4j.old/extensions/aggregate/node_aggregate.rb +8 -0
  13. data/lib/neo4j.old/extensions/aggregate/node_aggregate_mixin.rb +331 -0
  14. data/lib/neo4j.old/extensions/aggregate/node_aggregator.rb +216 -0
  15. data/lib/neo4j.old/extensions/aggregate/node_group.rb +43 -0
  16. data/lib/neo4j.old/extensions/aggregate/prop_group.rb +30 -0
  17. data/lib/neo4j.old/extensions/aggregate/property_enum.rb +24 -0
  18. data/lib/neo4j.old/extensions/aggregate/props_aggregate.rb +8 -0
  19. data/lib/neo4j.old/extensions/aggregate/props_aggregate_mixin.rb +31 -0
  20. data/lib/neo4j.old/extensions/aggregate/props_aggregator.rb +80 -0
  21. data/lib/neo4j.old/extensions/find_path.rb +117 -0
  22. data/lib/neo4j.old/extensions/graph_algo.rb +1 -0
  23. data/lib/neo4j.old/extensions/graph_algo/all_simple_paths.rb +133 -0
  24. data/lib/neo4j.old/extensions/graph_algo/neo4j-graph-algo-0.3.jar +0 -0
  25. data/lib/neo4j.old/extensions/reindexer.rb +104 -0
  26. data/lib/neo4j.old/extensions/rest.rb +21 -0
  27. data/lib/neo4j.old/extensions/rest/rest.rb +336 -0
  28. data/lib/neo4j.old/extensions/rest/rest_mixin.rb +193 -0
  29. data/lib/neo4j.old/extensions/rest/server.rb +50 -0
  30. data/lib/neo4j.old/extensions/rest/stubs.rb +141 -0
  31. data/lib/neo4j.old/extensions/rest_master.rb +34 -0
  32. data/lib/neo4j.old/extensions/rest_slave.rb +31 -0
  33. data/lib/neo4j.old/extensions/tx_tracker.rb +392 -0
  34. data/lib/neo4j.old/indexer.rb +187 -0
  35. data/lib/neo4j.old/jars.rb +6 -0
  36. data/lib/neo4j.old/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  37. data/lib/neo4j.old/jars/neo4j-kernel-1.0.jar +0 -0
  38. data/lib/neo4j.old/mixins/java_list_mixin.rb +139 -0
  39. data/lib/neo4j.old/mixins/java_node_mixin.rb +205 -0
  40. data/lib/neo4j.old/mixins/java_property_mixin.rb +169 -0
  41. data/lib/neo4j.old/mixins/java_relationship_mixin.rb +60 -0
  42. data/lib/neo4j.old/mixins/migration_mixin.rb +157 -0
  43. data/lib/neo4j.old/mixins/node_mixin.rb +249 -0
  44. data/lib/neo4j.old/mixins/property_class_methods.rb +265 -0
  45. data/lib/neo4j.old/mixins/rel_class_methods.rb +167 -0
  46. data/lib/neo4j.old/mixins/relationship_mixin.rb +103 -0
  47. data/lib/neo4j.old/neo.rb +247 -0
  48. data/lib/neo4j.old/node.rb +49 -0
  49. data/lib/neo4j.old/reference_node.rb +15 -0
  50. data/lib/neo4j.old/relationship.rb +85 -0
  51. data/lib/neo4j.old/relationships/decl_relationship_dsl.rb +164 -0
  52. data/lib/neo4j.old/relationships/has_list.rb +101 -0
  53. data/lib/neo4j.old/relationships/has_n.rb +129 -0
  54. data/lib/neo4j.old/relationships/node_traverser.rb +138 -0
  55. data/lib/neo4j.old/relationships/relationship_dsl.rb +149 -0
  56. data/lib/neo4j.old/relationships/traversal_position.rb +50 -0
  57. data/lib/neo4j.old/relationships/wrappers.rb +51 -0
  58. data/lib/neo4j.old/search_result.rb +72 -0
  59. data/lib/neo4j.old/transaction.rb +254 -0
  60. data/lib/neo4j.old/version.rb +3 -0
  61. data/lib/neo4j.rb +50 -0
  62. data/lib/neo4j/config.rb +137 -0
  63. data/lib/neo4j/database.rb +43 -0
  64. data/lib/neo4j/equal.rb +22 -0
  65. data/lib/neo4j/event_handler.rb +91 -0
  66. data/lib/neo4j/index.rb +157 -0
  67. data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  68. data/lib/neo4j/jars/lucene-core-2.9.2.jar +0 -0
  69. data/lib/neo4j/jars/lucene-core-3.0.1.jar +0 -0
  70. data/lib/neo4j/jars/neo4j-index-1.1.jar +0 -0
  71. data/lib/neo4j/jars/neo4j-kernel-1.1.1.jar +0 -0
  72. data/lib/neo4j/jars/neo4j-kernel-1.1.jar +0 -0
  73. data/lib/neo4j/jars/neo4j-lucene-index-0.1-20100916.085626-67.jar +0 -0
  74. data/lib/neo4j/mapping/class_methods/index.rb +21 -0
  75. data/lib/neo4j/mapping/class_methods/property.rb +139 -0
  76. data/lib/neo4j/mapping/class_methods/relationship.rb +96 -0
  77. data/lib/neo4j/mapping/class_methods/rule.rb +135 -0
  78. data/lib/neo4j/mapping/decl_relationship_dsl.rb +151 -0
  79. data/lib/neo4j/mapping/has_n.rb +117 -0
  80. data/lib/neo4j/mapping/node_mixin.rb +70 -0
  81. data/lib/neo4j/neo4j.rb +65 -0
  82. data/lib/neo4j/node.rb +82 -0
  83. data/lib/neo4j/node_mixin.rb +4 -0
  84. data/lib/neo4j/node_relationship.rb +60 -0
  85. data/lib/neo4j/node_traverser.rb +141 -0
  86. data/lib/neo4j/property.rb +72 -0
  87. data/lib/neo4j/rails/lucene_connection_closer.rb +19 -0
  88. data/lib/neo4j/rails/model.rb +210 -0
  89. data/lib/neo4j/rails/railtie.rb +16 -0
  90. data/lib/neo4j/rails/transaction.rb +29 -0
  91. data/lib/neo4j/rails/value.rb +43 -0
  92. data/lib/neo4j/relationship.rb +88 -0
  93. data/lib/neo4j/relationship_traverser.rb +57 -0
  94. data/lib/neo4j/to_java.rb +17 -0
  95. data/lib/neo4j/transaction.rb +69 -0
  96. data/lib/neo4j/version.rb +3 -0
  97. data/neo4j.gemspec +30 -0
  98. metadata +243 -0
@@ -0,0 +1,12 @@
1
+ require 'set'
2
+ require 'neo4j/extensions/aggregate/ext/node_mixin'
3
+ require 'neo4j/extensions/rule/node_rule_mixin'
4
+ require 'neo4j/extensions/rule/props_rule_mixin'
5
+ require 'neo4j/extensions/rule/node_rule'
6
+ require 'neo4j/extensions/rule/props_rule'
7
+ require 'neo4j/extensions/rule/rule_enum'
8
+ require 'neo4j/extensions/rule/node_aggregator'
9
+ require 'neo4j/extensions/rule/node_group'
10
+ require 'neo4j/extensions/rule/prop_group'
11
+ require 'neo4j/extensions/rule/property_enum'
12
+ require 'neo4j/extensions/rule/props_aggregator'
@@ -0,0 +1,40 @@
1
+ module Neo4j::Aggregate
2
+ # Used for an enumerable result of aggregates
3
+ # See Neo4j::NodeMixin#aggregates
4
+ #
5
+ # :api: private
6
+ class AggregateEnum #:nodoc:
7
+ include Enumerable
8
+
9
+ def initialize(node)
10
+ @node = node
11
+ end
12
+
13
+ def empty?
14
+ each {true}.nil?
15
+ end
16
+
17
+ def each
18
+ # if node is an aggregate group then we should look for parent aggregates
19
+ if (@node.property?(:aggregate_group))
20
+ @node.rels.incoming.nodes.each do |parent_group|
21
+ next unless parent_group.property?(:aggregate_size)
22
+ # if it has the property aggregate_group then it is a group node
23
+ if (parent_group.property?(:aggregate_group))
24
+ AggregateEnum.new(parent_group).each {|agg| yield agg}
25
+ else
26
+ # aggregate found
27
+ yield parent_group
28
+ end
29
+ end
30
+ else
31
+ # the given node (@node) is not a group, we guess it is an leaf in an aggregate
32
+ # get all the groups that this leaf belongs to and then those groups aggregate nodes
33
+ @node.rels.incoming(:aggregate).nodes.each do |group|
34
+ AggregateEnum.new(group ).each {|agg| yield agg}
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,69 @@
1
+ org.neo4j.kernel.impl.core.NodeProxy.class_eval do
2
+
3
+ # Returns an enumeration of aggregates that this nodes belongs to.
4
+ #
5
+ # Is used in combination with the Neo4j::AggregateNodeMixin
6
+ #
7
+ # ==== Example
8
+ #
9
+ # class MyNode
10
+ # include Neo4j::NodeMixin
11
+ # include Neo4j::NodeAggregateMixin
12
+ # end
13
+ #
14
+ # agg1 = MyNode
15
+ # agg1.aggregate([node1,node2]).group_by(:colour)
16
+ #
17
+ # agg2 = MyNode
18
+ # agg2.aggregate([node1,node2]).group_by(:age)
19
+ #
20
+ # [*node1.aggregates] # => [agg1, agg2]
21
+ #
22
+ def aggregates
23
+ Neo4j::Aggregate::AggregateEnum.new(self)
24
+ end
25
+
26
+ # Returns an enumeration of groups that this nodes belongs to.
27
+ #
28
+ # Is used in combination with the Neo4j::AggregateNodeMixin
29
+ #
30
+ # ==== Parameters
31
+ #
32
+ # * group which aggregate group we want, default is :all - an enumeration of all groups will be return
33
+ #
34
+ #
35
+ # ==== Returns
36
+ # an enumeration of all groups that this node belongs to, or if the group parameter was used
37
+ # only the given group or nil if not found.
38
+ #
39
+ # ==== Example
40
+ #
41
+ # class MyNode
42
+ # include Neo4j::NodeMixin
43
+ # include Neo4j::AggregateNodeMixin
44
+ # end
45
+ #
46
+ # agg1 = MyNode
47
+ # agg1.aggregate(:colours).group_by(:colour)
48
+ #
49
+ # agg2 = MyNode
50
+ # agg2.aggregate(:age).group_by(:age)
51
+ #
52
+ # agg1 << node1
53
+ # agg2 << node1
54
+ #
55
+ # [*node1.aggregate_groups] # => [agg1[some_group], agg2[some_other_group]]
56
+ #
57
+ def aggregate_groups(group = :all)
58
+ return rels.incoming(:aggregate).nodes if group == :all
59
+ [*rels.incoming(:aggregate).filter{self[:aggregate_group] == group.to_s}.nodes][0]
60
+ end
61
+
62
+ end
63
+
64
+
65
+ module Neo4j
66
+ module NodeMixin
67
+ def_delegators :@_java_node, :aggregate_groups, :aggregates
68
+ end
69
+ end
@@ -0,0 +1,8 @@
1
+ module Neo4j::Aggregate
2
+
3
+ class NodeAggregate
4
+ include Neo4j::NodeMixin
5
+ include Neo4j::Aggregate::NodeAggregateMixin
6
+ end
7
+
8
+ end
@@ -0,0 +1,331 @@
1
+ module Neo4j::Aggregate
2
+
3
+
4
+
5
+ # Enables aggregation of nodes into groups.
6
+ # An aggregation is a node which in contains group nodes.
7
+ # A group node aggregates the properties of the nodes that belongs to its group.
8
+ #
9
+ # There are two ways of creating an aggregate.
10
+ # * Providing an enumeration of nodes.
11
+ # * Register a Node class. All nodes of this class will (can) be part of the aggregate.
12
+ #
13
+ # One example of usage of providing an enumeration of nodes is by taking the output from
14
+ # the Neo4j::NodeMixin#traverse as input to the aggregate method, or even
15
+ # create aggregates over aggregates.
16
+ #
17
+ # This mixin includes the Enumerable mixin.
18
+ #
19
+ # There is also a different aggregation which aggregates on properties
20
+ # instead of nodes - Neo4j::Aggregate::PropsAggregateMixin
21
+ #
22
+ # ==== Example - group by one property
23
+ #
24
+ # Let say we have nodes with properties :colour and we want to group them by colour:
25
+ #
26
+ # a = AggregateNode.new
27
+ #
28
+ # a.aggregate(nodes).group_by(:colour).execute
29
+ #
30
+ # The execute method is only needed when providing nodes (instead of a NodeClass) for the aggregate method.
31
+ # Print all three groups, one for each colour
32
+ #
33
+ # a.each{|n| puts n[:colour]}
34
+ #
35
+ # Print all nodes belonging to one colour group:
36
+ #
37
+ # a[:red].each {|node| puts node}
38
+ #
39
+ # ==== Example - Aggregating Properties
40
+ #
41
+ # The aggregator also aggregate properties. If a property does not exist on an aggregated group it will traverse all nodes in its group and
42
+ # return an enumeration of its values.
43
+ #
44
+ # Get an enumeration of names of people having favorite colour 'red'
45
+ #
46
+ # [*a[:red][:name]] => ['bertil', 'adam', 'adam']
47
+ #
48
+ # ==== Example - group by a property value which is transformed
49
+ #
50
+ # Let say way want to have group which include a range of values.
51
+ # Example - group by an age range, 0-4, 5-9, 10-14 etc...
52
+ #
53
+ # a = AggregateNode.new
54
+ # a.aggregate(an enumeration of nodes).group_by(:age).of_value{|age| age / 5}
55
+ #
56
+ # # traverse all people in age group 10-14 (3 maps to range 10-14)
57
+ # a[3].each {|x| ...}
58
+ #
59
+ # # traverse all groups
60
+ # a.each {|x| ...}
61
+ #
62
+ # # how many age groups are there ?
63
+ # a.aggregate_size
64
+ #
65
+ # # how many people are in age group 10-14
66
+ # a[3].aggregate_size
67
+ #
68
+ # ==== Example - Group by several properties
69
+ #
70
+ # The group_by method takes one or more property keys which it combines into one or more groups.
71
+ #
72
+ # node1 = Neo4j::Node.new; node1[:colour] = 'red'; node1[:type] = 'A'
73
+ # node2 = Neo4j::Node.new; node2[:colour] = 'red'; node2[:type] = 'B'
74
+ #
75
+ # agg_node = MyAggregateNode.new
76
+ # agg_node.aggregate([node1, node2]).group_by(:colour, :type)
77
+ #
78
+ # # node1 is member of two groups, red and A
79
+ # [*node1.aggregate_groups] # => [agg_node[:red], agg_node[:A]]
80
+ #
81
+ # # group A contains node1
82
+ # agg_node[:A].include?(node1) # => true
83
+ #
84
+ # # group red also contains node1
85
+ # agg_node[:red].include?(node1) # => true
86
+ #
87
+ # ==== Example - Appending new nodes to aggregates
88
+ #
89
+ # The aggregate node mixin implements the << operator that allows you to append nodes to the aggregate and the
90
+ # appended node will be put in the correct group.
91
+ #
92
+ # a = AggregateNode.new
93
+ # a.aggregate.group_by(:age).of_value{|age| age / 5}
94
+ #
95
+ # a << node1 << node2
96
+ #
97
+ # Notice that we do not need call the execute method. That method will be called each time we append nodes to the aggregate.
98
+ #
99
+ # ==== Example - trees of aggregates
100
+ #
101
+ # One example where this is needed is for having a tree structure of nodes with latitude and longitude grouped by a 'zoom' factor
102
+ #
103
+ # create an aggregation of groups where members have the same latitude longitude integer values (to_i)
104
+ # reg1 = agg_root.aggregate().group_by(:latitude, :longitude).map_value{|lat, lng| "#{(lat*1000).to_i}_#{(lng*1000).to_i}"}
105
+ #
106
+ # create another aggregation of groups where members have the same latitude longitude 1/10 value
107
+ # reg2 = agg_root.aggregate(reg1).group_by(:latitude, :longitude).map_value{|lat, lng| "#{(lat*100).to_i}_#{(lng*100).to_i" }
108
+ #
109
+ # Notice how the second aggregate uses the first aggregate (reg1). This will create the following structure with
110
+ # * node n1 - (latitude 42.1234 and longitude 12.1234) and
111
+ # * node n2 (latitude 42.1299 and longitude 12.1298)
112
+ # * node n3 (latitude 42.1333 and longitude 12.1298)
113
+ #
114
+ # Root agg_root
115
+ # | |
116
+ # Group 4212_1212 Group 4213_1212
117
+ # | |
118
+ # Group 42123_12123 Group 42133_12129
119
+ # | | |
120
+ # n1 n2 n3
121
+ #
122
+ # When the nodes n1,n2,n3 are added to the agg_root, e.g:
123
+ # agg_root << n1 << n2 << n3
124
+ #
125
+ #
126
+ # ==== Example - Add and remove nodes by events
127
+ #
128
+ # We want to both create and delete nodes and the aggregates should be updated automatically
129
+ # This is done by providing a NodeClass for the aggregate method.
130
+ # (it registering the aggregate dsl method as an event listener
131
+ #
132
+ # Here is an example that update the aggregate a on all nodes of type MyNode
133
+ # a = AggregateNode.new
134
+ #
135
+ # # the aggreate will get notified when nodes of type MyNode get changed
136
+ # a.aggregate(MyNode).group_by(:colour)
137
+ #
138
+ # Neo4j::Transaction.run { blue_node = MyNode.new; a.colour = 'blue' }
139
+ # # then the aggregate will be updated automatically since it listen to property change events
140
+ # a['blue'].size = 1
141
+ # [*a['blue']][0] # => blue_node
142
+ #
143
+ # blue_node[:colour] = 'red'
144
+ # a['blue'] # => nil
145
+ # [*a['red']] # => [blue_node]
146
+ # blue_node.delete
147
+ # a['red'] # => nil
148
+ #
149
+ #
150
+ # ===== TODO Only Aggregate ???
151
+ #
152
+ # a.aggregate([n1,n2])
153
+ # [*a] => [n1, n2]
154
+ #
155
+ # OR without aggregate method
156
+ # a << n1 << n2
157
+ #
158
+ # ===== Example Group by Each (1)
159
+ #
160
+ # class MyRoot
161
+ # include AggregateEach
162
+ # end
163
+ #
164
+ # a = MyRoot.new
165
+ #
166
+ # n1 = [jan=>1, feb=>5, mars=>2, apr=>10, ...]
167
+ # n2 = [jan=>2, feb=>0, mars=>2, apr=>10, ...]
168
+ #
169
+ # a.aggregate_each([n1,n2]).group(:jan,:feb,:mars).by(:q1)
170
+ # [*a[:q1]] = [g1,g2]
171
+ # g1.props => [n1.neo_id, jan=>1, feb=>5, ..., dec=>]
172
+ # [*g1] => [1,5,2]
173
+ #
174
+ # ===== Example Group by Each (2)
175
+ #
176
+ # n1 = [:colour => 'red', :age => 10]
177
+ # n2 = [:colour => 'blue', :age => 11]
178
+ # n3 = [:colour => 'red', :age => 12]
179
+ #
180
+ # a.aggregate_each([n1,n2,n3]).group_by(:colour, :age)
181
+ # n1.aggregate_groups = [g1]
182
+ # [*g1] = ['red', 10]
183
+ # [*a] => [g1,g2,g3]
184
+ #
185
+ # [*g2] = ['blue', 11]
186
+ # g1.props => [
187
+ #
188
+ #
189
+ # ===== Example Group by new property
190
+ #
191
+ # q1.aggregate_each(nodes).group_by(:jan,:feb,:mars)
192
+ # q2.aggregate_each(nodes).group_by(:apr,:may,:june)
193
+ #
194
+ #
195
+ # T O D O - G R O U P _ B Y the only needed one (not group and by)
196
+ # n1 = [jan=>1, feb=>5, mars=>2, apr=>10, ...]
197
+ # n2 = [jan=>2, feb=>0, mars=>2, apr=>10, ...]
198
+ #
199
+ # [*q1] => [g1,g2]
200
+ # [*g1] => [1,5,2]
201
+ # [*g2] => [2,0,2]
202
+ #
203
+ # [*q2] => [g3,g4]
204
+ # n1.aggregate_groups = [g1,g2]
205
+ # n1[:q1] => nil OR [1,5,2] ????
206
+ # a[:q1] => [1,5,2,2,0,2]
207
+ # n1.each {|n| n[:q1]}
208
+ #
209
+ # SUM
210
+ # a.aggregate([n1,n2]).group(:jan,:feb,:mars).by(:q1).sum
211
+ # n1[:q1] => 8
212
+ # a[:q1] => 12
213
+ #
214
+ #
215
+ # m1 = [revenue => 1000]
216
+ # m2 = [revenue => 500]
217
+ # m3 = [revenue => 2000]
218
+ # a2.aggregate([m1,m2,m3]).group(:revenue).by(:rev).map_value{|v| v >= 1000 ? "good" : "bad"}.count
219
+ #
220
+ # a[:rev] => ["good", "good", "bad"]
221
+ # a[:rev]["good"] => 2
222
+ # a[:rev]["bad"] => 1
223
+ module NodeAggregateMixin
224
+ include Neo4j::NodeMixin
225
+ include Enumerable
226
+
227
+
228
+ # The number of groups that this aggregate contains
229
+ def aggregate_size
230
+ _java_node.set_property("aggregate_size", 0) unless _java_node.has_property("aggregate_size")
231
+ self[:aggregate_size]
232
+ end
233
+
234
+
235
+ # Internal method - set the number of groups that this node contains
236
+ # We can then use this property instead of traversing and counting each node in order to find out how many groups there are.
237
+ def aggregate_size=(value) # :nodoc:
238
+ self[:aggregate_size] = value
239
+ end
240
+
241
+ # Creates aggregated nodes by grouping nodes by one or more property values.
242
+ # Raises an exception if the aggregation already exists.
243
+ #
244
+ # ==== Parameters
245
+ # * aggregate(optional an enumeration) - specifies which nodes it should aggregate into groups of nodes
246
+ #
247
+ # If the no argument is given for the aggregate method then nodes can be appended to the aggregate using the << method.
248
+ #
249
+ # ==== Returns
250
+ # an object that has the following methods
251
+ # * group_by(*keys) - specifies which property or properties values it should group by
252
+ # * group_each_by - same as group_by but instead of combinding the properties it creates new groups for each given property
253
+ # * execute - executes the aggregation, creates new nodes that groups the specified nodes
254
+ #
255
+ # :api: public
256
+ def aggregate(nodes_or_filter=nil)
257
+ # setting a property here using neo4j.rb might trigger events which we do not want
258
+ @aggregator = NodeAggregator.new(self, nodes_or_filter)
259
+ end
260
+
261
+ # Appends one or a whole enumeration of nodes to the existing aggregation.
262
+ # Each node will be put into aggregate groups that was specified using the aggregate method.
263
+ #
264
+ # If the node does not have a property(ies) used for grouping nodes then the node will node be appendend to the aggreation.
265
+ # Example:
266
+ # my_agg.aggregate.group_by(:colour)
267
+ # my_agg << Neo4j::Node.new # this node will not be added since it is missing the colour property
268
+ #
269
+ # ==== Parameter
270
+ # * node(an enumeration, or one node) - specifies which node(s) should be appneit should aggregate into groups of nodes
271
+ #
272
+ # ==== Returns
273
+ # self
274
+ #
275
+ def <<(node)
276
+ # @aggregator.execute if @aggregator
277
+ if node.kind_of?(Enumerable)
278
+ @aggregator.execute(node)
279
+ else
280
+ @aggregator.execute([node])
281
+ end
282
+ self
283
+ end
284
+
285
+
286
+ # Checks if the given node is include in this aggregate
287
+ #
288
+ # ==== Returns
289
+ # true if the aggregate includes the given node.
290
+ #
291
+ # :api: public
292
+ def include_node?(node)
293
+ key = @aggregator.group_key_of(node)
294
+ group = group_node(key)
295
+ return false if group.nil?
296
+ group.include?(node)
297
+ end
298
+
299
+ # Returns the group with the given key
300
+ # If there is no group with that key it returns nil
301
+ #
302
+ # :api: public
303
+ def group_node(key)
304
+ @aggregator.execute if @aggregator
305
+ rels.outgoing(key).nodes.find{|n| n.kind_of? NodeGroup}
306
+ end
307
+
308
+
309
+ # Overrides the [] method
310
+ #
311
+ # If there is a relationship of the given key, and that node is kind_of?
312
+ # that that relationships point to will be returned (as an Enumeration).
313
+ # Otherwise, return the property of this node.
314
+ #
315
+ def [](key)
316
+ node = group_node(key)
317
+ return node unless node.nil?
318
+ super(key)
319
+ end
320
+
321
+
322
+ def each
323
+ @aggregator.execute if @aggregator
324
+ rels.outgoing.nodes.each {|n| yield n if n.kind_of? NodeGroup}
325
+ end
326
+
327
+ end
328
+
329
+
330
+
331
+ end