neo4j 1.0.0.beta.27-java → 1.0.0.beta.28-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 (85) hide show
  1. data/CONTRIBUTORS +1 -0
  2. data/lib/neo4j.rb +38 -72
  3. data/lib/neo4j/{algo.rb → algo/algo.rb} +5 -1
  4. data/lib/neo4j/batch/batch.rb +2 -0
  5. data/lib/neo4j/batch/indexer.rb +108 -0
  6. data/lib/neo4j/batch/inserter.rb +168 -0
  7. data/lib/neo4j/database.rb +13 -8
  8. data/lib/neo4j/{mapping/class_methods/list.rb → has_list/class_methods.rb} +2 -4
  9. data/lib/neo4j/has_list/has_list.rb +3 -0
  10. data/lib/neo4j/{mapping/has_list.rb → has_list/mapping.rb} +2 -2
  11. data/lib/neo4j/{mapping/class_methods/relationship.rb → has_n/class_methods.rb} +42 -12
  12. data/lib/neo4j/has_n/decl_relationship_dsl.rb +216 -0
  13. data/lib/neo4j/has_n/has_n.rb +3 -0
  14. data/lib/neo4j/{mapping/has_n.rb → has_n/mapping.rb} +16 -7
  15. data/lib/neo4j/index/index.rb +5 -0
  16. data/lib/neo4j/index/indexer.rb +27 -22
  17. data/lib/neo4j/index/lucene_query.rb +3 -1
  18. data/lib/neo4j/jars/core/neo4j-graph-algo-0.8-1.3.M01.jar +0 -0
  19. data/lib/neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar +0 -0
  20. data/lib/neo4j/jars/core/neo4j-kernel-1.3-1.3.M01.jar +0 -0
  21. data/lib/neo4j/jars/core/neo4j-lucene-index-0.5-1.3.M01.jar +0 -0
  22. data/lib/neo4j/jars/ha/{neo4j-ha-0.6-SNAPSHOT.jar → neo4j-ha-0.6-1.3.M01.jar} +0 -0
  23. data/lib/neo4j/jars/ha/neo4j-management-1.3-1.3.M01.jar +0 -0
  24. data/lib/neo4j/jars/ha/neo4j-shell-1.3-1.3.M01.jar +0 -0
  25. data/lib/neo4j/migrations/class_methods.rb +102 -0
  26. data/lib/neo4j/migrations/extensions.rb +10 -9
  27. data/lib/neo4j/migrations/lazy_node_mixin.rb +50 -0
  28. data/lib/neo4j/migrations/migration.rb +84 -81
  29. data/lib/neo4j/migrations/migrations.rb +6 -100
  30. data/lib/neo4j/migrations/node_mixin.rb +80 -0
  31. data/lib/neo4j/migrations/ref_node_wrapper.rb +32 -0
  32. data/lib/neo4j/neo4j.rb +11 -0
  33. data/lib/neo4j/node.rb +55 -25
  34. data/lib/neo4j/{mapping/class_methods/init_node.rb → node_mixin/class_methods.rb} +3 -3
  35. data/lib/neo4j/{mapping → node_mixin}/node_mixin.rb +35 -18
  36. data/lib/neo4j/{mapping/class_methods/property.rb → property/class_methods.rb} +5 -4
  37. data/lib/neo4j/{property.rb → property/property.rb} +2 -0
  38. data/lib/neo4j/rails/finders.rb +21 -7
  39. data/lib/neo4j/rails/rails.rb +19 -0
  40. data/lib/neo4j/rails/timestamps.rb +1 -1
  41. data/lib/neo4j/relationship.rb +7 -0
  42. data/lib/neo4j/{mapping/class_methods/init_rel.rb → relationship_mixin/class_methods.rb} +4 -4
  43. data/lib/neo4j/{mapping → relationship_mixin}/relationship_mixin.rb +23 -5
  44. data/lib/neo4j/rels/rels.rb +85 -0
  45. data/lib/neo4j/rels/traverser.rb +102 -0
  46. data/lib/neo4j/{mapping/class_methods/rule.rb → rule/class_methods.rb} +11 -11
  47. data/lib/neo4j/rule/functions/count.rb +37 -0
  48. data/lib/neo4j/rule/functions/function.rb +74 -0
  49. data/lib/neo4j/rule/functions/functions.rb +3 -0
  50. data/lib/neo4j/rule/functions/sum.rb +29 -0
  51. data/lib/neo4j/rule/rule.rb +5 -0
  52. data/lib/neo4j/rule/rule_event_listener.rb +162 -0
  53. data/lib/neo4j/rule/rule_node.rb +182 -0
  54. data/lib/neo4j/to_java.rb +0 -14
  55. data/lib/neo4j/traversal/filter_predicate.rb +25 -0
  56. data/lib/neo4j/traversal/prune_evaluator.rb +14 -0
  57. data/lib/neo4j/traversal/rel_expander.rb +31 -0
  58. data/lib/neo4j/traversal/traversal.rb +90 -0
  59. data/lib/neo4j/traversal/traverser.rb +173 -0
  60. data/lib/neo4j/{type_converters.rb → type_converters/type_converters.rb} +0 -0
  61. data/lib/neo4j/version.rb +1 -1
  62. data/lib/test.rb~ +2 -0
  63. data/neo4j.gemspec +11 -10
  64. metadata +48 -37
  65. data/lib/neo4j/functions/count.rb +0 -33
  66. data/lib/neo4j/functions/function.rb +0 -72
  67. data/lib/neo4j/functions/sum.rb +0 -27
  68. data/lib/neo4j/jars/core/neo4j-graph-algo-0.8-SNAPSHOT.jar +0 -0
  69. data/lib/neo4j/jars/core/neo4j-index-1.3-SNAPSHOT.jar +0 -0
  70. data/lib/neo4j/jars/core/neo4j-kernel-1.3-SNAPSHOT.jar +0 -0
  71. data/lib/neo4j/jars/core/neo4j-lucene-index-0.5-SNAPSHOT.jar +0 -0
  72. data/lib/neo4j/jars/ha/neo4j-management-1.3-SNAPSHOT.jar +0 -0
  73. data/lib/neo4j/jars/ha/neo4j-shell-1.3-SNAPSHOT.jar +0 -0
  74. data/lib/neo4j/mapping/decl_relationship_dsl.rb +0 -214
  75. data/lib/neo4j/mapping/rule.rb +0 -158
  76. data/lib/neo4j/mapping/rule_node.rb +0 -176
  77. data/lib/neo4j/migrations.rb +0 -12
  78. data/lib/neo4j/migrations/global_migration.rb +0 -29
  79. data/lib/neo4j/migrations/lazy_migration_mixin.rb +0 -47
  80. data/lib/neo4j/migrations/migration_mixin.rb +0 -78
  81. data/lib/neo4j/node_mixin.rb +0 -4
  82. data/lib/neo4j/node_relationship.rb +0 -161
  83. data/lib/neo4j/node_traverser.rb +0 -224
  84. data/lib/neo4j/relationship_mixin.rb +0 -4
  85. data/lib/neo4j/relationship_traverser.rb +0 -92
@@ -0,0 +1,37 @@
1
+ module Neo4j
2
+ module Rule
3
+ module Functions
4
+
5
+ # A function for counting number of nodes of a given class.
6
+ class Count < Function
7
+ def initialize
8
+ @property = '_classname'
9
+ end
10
+
11
+ def calculate?(changed_property)
12
+ true
13
+ end
14
+
15
+ def delete(rule_name, rule_node, old_value)
16
+ key = rule_node_property(rule_name)
17
+ rule_node[key] ||= 0
18
+ rule_node[key] -= 1
19
+ end
20
+
21
+ def add(rule_name, rule_node, new_value)
22
+ key = rule_node_property(rule_name)
23
+ rule_node[key] ||= 0
24
+ rule_node[key] += 1
25
+ end
26
+
27
+ def update(*)
28
+ # we are only counting, not interested in property changes
29
+ end
30
+
31
+ def self.function_name
32
+ :count
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,74 @@
1
+ module Neo4j
2
+ module Rule
3
+ module Functions
4
+
5
+ # The base class of rule functions.
6
+ #
7
+ # You are expected to at least implement two methods:
8
+ # * update :: update the rule node value of this function
9
+ # * function_name :: the name of this function, the name of the generated method - A class method !
10
+ #
11
+ class Function
12
+
13
+ # Initialize the the function with a property which is usually the same as the function identity.
14
+ # See the #calculate? method how this property is used.
15
+ #
16
+ def initialize(property)
17
+ @property = property.to_s
18
+ end
19
+
20
+ def to_s
21
+ "Function #{self.class.function_name} function_id: #{function_id}"
22
+ end
23
+
24
+ # Decides if the function should be called are not
25
+ #
26
+ def calculate?(changed_property)
27
+ @property == changed_property
28
+ end
29
+
30
+
31
+ # The identity of the function.
32
+ # Used to identify function.
33
+ #
34
+ # ==== Example
35
+ # Person.sum(:young, :age)
36
+ #
37
+ # In the example above the property :age is the used to identify which function will be called
38
+ # since there could be several sum method. In the example we want use the sum method that uses the :age property.
39
+ #
40
+ def function_id
41
+ @property
42
+ end
43
+
44
+ # The value of the rule
45
+ def value(rule_node, rule_name)
46
+ key = rule_node_property(rule_name)
47
+ rule_node[key] || 0
48
+ end
49
+
50
+ # Called when a node is removed from a rule group
51
+ # Default is calling update method which is expected to be implemented in a subclass
52
+ def delete(rule_name, rule_node, old_value)
53
+ update(rule_name, rule_node, old_value, nil)
54
+ end
55
+
56
+ # Called when a node is added to a rule group
57
+ # Default is calling update method which is expected to be implemented in a subclass
58
+ def add(rule_name, rule_node, new_value)
59
+ update(rule_name, rule_node, nil, new_value)
60
+ end
61
+
62
+ # the name of the property that holds the value of the function
63
+ def rule_node_property(rule_name)
64
+ self.class.rule_node_property(self.class.function_name, rule_name, @property)
65
+ end
66
+
67
+ def self.rule_node_property(function_name, rule_name, prop)
68
+ "_#{function_name}_#{rule_name}_#{prop}"
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,3 @@
1
+ require "neo4j/rule/functions/function"
2
+ require "neo4j/rule/functions/count"
3
+ require "neo4j/rule/functions/sum"
@@ -0,0 +1,29 @@
1
+ module Neo4j
2
+ module Rule
3
+ module Functions
4
+
5
+ class Sum < Function
6
+ # Updates the function's value.
7
+ # Called after the transactions commits and a property has been changed on a node.
8
+ #
9
+ # ==== Arguments
10
+ # * rule_name :: the name of the rule group
11
+ # * rule_node :: the node which contains the value of this function
12
+ # * old_value new value :: the changed value of the property (when the transaction commits)
13
+ def update(rule_name, rule_node, old_value, new_value)
14
+ key = rule_node_property(rule_name)
15
+ rule_node[key] ||= 0
16
+ old_value ||= 0
17
+ new_value ||= 0
18
+ rule_node[key] += new_value - old_value
19
+ end
20
+
21
+ def self.function_name
22
+ :sum
23
+ end
24
+ end
25
+
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ require 'neo4j/rule/rule_event_listener'
2
+ require 'neo4j/rule/class_methods'
3
+ require 'neo4j/rule/rule_node'
4
+
5
+ require 'neo4j/rule/functions/functions'
@@ -0,0 +1,162 @@
1
+ module Neo4j
2
+ module Rule
3
+
4
+
5
+ # Holds all defined rules and trigger them when an event is received.
6
+ #
7
+ # See Neo4j::Rule::ClassMethods
8
+ #
9
+ class RuleEventListener #:nodoc:
10
+
11
+ attr_reader :rule_name, :filter, :triggers, :functions
12
+
13
+ def initialize(rule_name, props, &block)
14
+ @rule_name = rule_name
15
+ @triggers = props[:triggers]
16
+ @functions = props[:functions]
17
+ @triggers = [@triggers] if @triggers && !@triggers.respond_to?(:each)
18
+ @functions = [@functions] if @functions && !@functions.respond_to?(:each)
19
+ @filter = block
20
+ end
21
+
22
+ def to_s
23
+ "RuleEventListener #{rule_name} props=#{props.inspect}"
24
+ end
25
+
26
+ def find_function(function_name, function_id)
27
+ function_id = function_id.to_s
28
+ @functions && @functions.find { |f| f.function_id == function_id && f.class.function_name == function_name }
29
+ end
30
+
31
+ # Reconstruct the properties given when created this rule
32
+ # Needed when inheriting a rule and we want to duplicate a rule
33
+ def props
34
+ props = {}
35
+ props[:triggers] = @triggers if @triggers
36
+ props[:functions] = @functions if @functions
37
+ props
38
+ end
39
+
40
+ def functions_for(property)
41
+ @functions && @functions.find_all { |f| f.calculate?(property) }
42
+ end
43
+
44
+ def execute_filter(node)
45
+ if @filter.nil?
46
+ true
47
+ elsif @filter.arity != 1
48
+ node.wrapper.instance_eval(&@filter)
49
+ else
50
+ @filter.call(node)
51
+ end
52
+ end
53
+
54
+ # ------------------------------------------------------------------------------------------------------------------
55
+ # Class Methods
56
+ # ------------------------------------------------------------------------------------------------------------------
57
+
58
+ class << self
59
+ def add(clazz, rule_name, props, &block)
60
+ rule_node = rule_node_for(clazz.to_s)
61
+ rule_node.remove_rule(rule_name) # remove any previously inherited rules
62
+ rule = RuleEventListener.new(rule_name, props, &block)
63
+ rule_node.add_rule(rule)
64
+ rule
65
+ end
66
+
67
+ def rule_names_for(clazz)
68
+ rule_node = rule_node_for(clazz)
69
+ rule_node.rules.map { |rule| rule.rule_name }
70
+ end
71
+
72
+ def rule_node_for(clazz)
73
+ return nil if clazz.nil?
74
+ @rule_nodes ||= {}
75
+ @rule_nodes[clazz.to_s] ||= RuleNode.new(clazz)
76
+ end
77
+
78
+ def inherit(parent_class, subclass)
79
+ # copy all the rules
80
+ if rule_node = rule_node_for(parent_class)
81
+ rule_node.inherit(subclass)
82
+ end
83
+ end
84
+
85
+ def delete(clazz)
86
+ if rule_node = rule_node_for(clazz)
87
+ rule_node.delete_node
88
+ end
89
+ end
90
+
91
+ def trigger?(node)
92
+ classname = node[:_classname]
93
+ @rule_nodes && classname && rule_node_for(classname)
94
+ end
95
+
96
+ def trigger_rules(node, *changes)
97
+ classname = node[:_classname]
98
+ return unless classname # there are no rules if there is not a :_classname property
99
+ rule_node = rule_node_for(classname)
100
+ rule_node.execute_rules(node, *changes)
101
+
102
+ # recursively add relationships for all the parent classes with rules that also pass for this node
103
+ if (clazz = eval("#{classname}.superclass")) && clazz.include?(Neo4j::NodeMixin)
104
+ rule_node = rule_node_for(clazz)
105
+ rule_node && rule_node.execute_rules(node, *changes)
106
+ end
107
+ end
108
+
109
+
110
+ # ----------------------------------------------------------------------------------------------------------------
111
+ # Event handling methods
112
+ # ----------------------------------------------------------------------------------------------------------------
113
+
114
+ def on_relationship_created(rel, *)
115
+ trigger_start_node = trigger?(rel._start_node)
116
+ trigger_end_node = trigger?(rel._end_node)
117
+ trigger_rules(rel._start_node) if trigger_start_node
118
+ trigger_rules(rel._end_node) if trigger_end_node
119
+ end
120
+
121
+ def on_property_changed(node, *changes)
122
+ trigger_rules(node, *changes) if trigger?(node)
123
+ end
124
+
125
+ def on_node_deleted(node, old_properties, data)
126
+ # have we deleted a rule node ?
127
+ del_rule_node = @rule_nodes && @rule_nodes.values.find { |rn| rn.rule_node?(node) }
128
+ del_rule_node && del_rule_node.clear_rule_node
129
+ return if del_rule_node
130
+
131
+ # do we have prop_aggregations for this
132
+ clazz = old_properties['_classname']
133
+ rule_node = rule_node_for(clazz)
134
+ return if rule_node.nil?
135
+
136
+ id = node.getId
137
+ rule_node.rules.each do |rule|
138
+ next if rule.functions.nil?
139
+ rule_name = rule.rule_name.to_s
140
+
141
+ # is the rule node deleted ?
142
+ deleted_rule_node = data.deletedNodes.find { |n| n == rule_node.rule_node }
143
+ next if deleted_rule_node
144
+
145
+ rule.functions.each do |function|
146
+ next unless data.deletedRelationships.find do |r|
147
+ r.getEndNode().getId() == id && r.rel_type == rule_name
148
+ end
149
+ previous_value = old_properties[function.function_id]
150
+ function.delete(rule_name, rule_node.rule_node, previous_value) if previous_value
151
+ end if rule.functions
152
+ end
153
+ end
154
+
155
+ def on_neo4j_started(*)
156
+ @rule_nodes.each_value { |rule_node| rule_node.on_neo4j_started } if @rule_nodes
157
+ end
158
+
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,182 @@
1
+ module Neo4j
2
+ module Rule
3
+
4
+ # This is the node that has relationships to all nodes of a given class.
5
+ # For example if the PersonNode has a rule then it will also have one RuleNode
6
+ # from where it will create relationships to each created node of type PersonNode.
7
+ # The RuleNode can also be used to hold properties for functions, like sum and count.
8
+ #
9
+ class RuleNode
10
+ attr_reader :rules
11
+
12
+ def initialize(clazz)
13
+ @clazz = clazz
14
+ @rules = []
15
+ end
16
+
17
+ def to_s
18
+ "RuleNode #{@clazz}, node #{rule_node} #rules: #{@rules.size}"
19
+ end
20
+
21
+ # returns true if the rule node exist yet in the database
22
+ def node_exist?
23
+ !Neo4j.ref_node.rel?(@clazz)
24
+ end
25
+
26
+ def create_node
27
+ Neo4j::Transaction.run do
28
+ node = Neo4j::Node.new
29
+ Neo4j.ref_node.outgoing(@clazz) << node
30
+ node
31
+ end
32
+ end
33
+
34
+ def inherit(subclass)
35
+ @rules.each do |rule|
36
+ subclass.rule rule.rule_name, rule.props, &rule.filter
37
+ end
38
+ end
39
+
40
+ def delete_node
41
+ if Neo4j.ref_node.rel?(@clazz)
42
+ Neo4j.ref_node.outgoing(@clazz).each { |n| n.del }
43
+ end
44
+ clear_rule_node
45
+ end
46
+
47
+ def find_node
48
+ Neo4j.ref_node.rel?(@clazz.to_s) && Neo4j.ref_node._rel(:outgoing, @clazz.to_s)._end_node
49
+ end
50
+
51
+ def on_neo4j_started
52
+ # initialize the rule node when neo4j starts
53
+ @rule_node = find_node || create_node
54
+ end
55
+
56
+ def rule_node
57
+ @rule_node ||= find_node || create_node
58
+ end
59
+
60
+ def rule_node?(node)
61
+ @rule_node == node
62
+ end
63
+
64
+ def clear_rule_node
65
+ @rule_node = nil
66
+ end
67
+
68
+ def rule_names
69
+ @rules.map { |r| r.rule_name }
70
+ end
71
+
72
+ def find_rule(rule_name)
73
+ @rules.find { |rule| rule.rule_name == rule_name }
74
+ end
75
+
76
+ def add_rule(rule)
77
+ @rules << rule
78
+ end
79
+
80
+ def remove_rule(rule_name)
81
+ r = find_rule(rule_name)
82
+ r && @rules.delete(r)
83
+ end
84
+
85
+ # Return a traversal object with methods for each rule and function.
86
+ # E.g. Person.all.old or Person.all.sum(:age)
87
+ def traversal(rule_name)
88
+ # define method on the traversal
89
+ traversal = rule_node.outgoing(rule_name)
90
+ @rules.each do |rule|
91
+ traversal.filter_method(rule.rule_name) do |path|
92
+ path.end_node.rel?(rule.rule_name, :incoming)
93
+ end
94
+ rule.functions && rule.functions.each do |func|
95
+ traversal.functions_method(func, self, rule_name)
96
+ end
97
+ end
98
+ traversal
99
+ end
100
+
101
+ def find_function(rule_name, function_name, function_id)
102
+ rule = find_rule(rule_name)
103
+ rule.find_function(function_name, function_id)
104
+ end
105
+
106
+ def execute_rules(node, *changes)
107
+ @rules.each do |rule|
108
+ execute_rule(rule, node, *changes)
109
+ execute_other_rules(rule, node)
110
+ end
111
+ end
112
+
113
+ def execute_other_rules(rule, node)
114
+ rule.triggers && rule.triggers.each do |rel_type|
115
+ node.incoming(rel_type).each { |n| n.trigger_rules }
116
+ end
117
+ end
118
+
119
+ def execute_rule(rule, node, *changes)
120
+ if rule.execute_filter(node)
121
+ if connected?(rule.rule_name, node)
122
+ # it was already connected - the node is in the same rule group but a property has changed
123
+ execute_update_functions(rule, *changes)
124
+ else
125
+ # the node has changed or is in a new rule group
126
+ connect(rule.rule_name, node)
127
+ execute_add_functions(rule, *changes)
128
+ end
129
+ else
130
+ if break_connection(rule.rule_name, node)
131
+ # the node has been removed from a rule group
132
+ execute_delete_functions(rule, *changes)
133
+ end
134
+ end
135
+ end
136
+
137
+ def execute_update_functions(rule, *changes)
138
+ if functions = find_functions_for_changes(rule, *changes)
139
+ functions && functions.each { |f| f.update(rule.rule_name, rule_node, changes[1], changes[2]) }
140
+ end
141
+ end
142
+
143
+ def execute_add_functions(rule, *changes)
144
+ if functions = find_functions_for_changes(rule, *changes)
145
+ functions && functions.each { |f| f.add(rule.rule_name, rule_node, changes[2]) }
146
+ end
147
+ end
148
+
149
+ def execute_delete_functions(rule, *changes)
150
+ if functions = find_functions_for_changes(rule, *changes)
151
+ functions.each { |f| f.delete(rule.rule_name, rule_node, changes[1]) }
152
+ end
153
+ end
154
+
155
+ def find_functions_for_changes(rule, *changes)
156
+ !changes.empty? && rule.functions_for(changes[0])
157
+ end
158
+
159
+ # work out if two nodes are connected by a particular relationship
160
+ # uses the end_node to start with because it's more likely to have less relationships to go through
161
+ # (just the number of superclasses it has really)
162
+ def connected?(rule_name, end_node)
163
+ end_node.incoming(rule_name).find { |n| n == rule_node }
164
+ end
165
+
166
+ def connect(rule_name, end_node)
167
+ rule_node.outgoing(rule_name) << end_node
168
+ end
169
+
170
+ # sever a direct one-to-one relationship if it exists
171
+ def break_connection(rule_name, end_node)
172
+ rel = end_node._rels(:incoming, rule_name).find { |r| r._start_node == rule_node }
173
+ rel && rel.del
174
+ !rel.nil?
175
+ end
176
+
177
+ end
178
+
179
+
180
+ end
181
+
182
+ end