neo4j 1.0.0.beta.23-java → 1.0.0.beta.24-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/neo4j.rb +7 -0
- data/lib/neo4j/config.rb +2 -9
- data/lib/neo4j/event_handler.rb +51 -1
- data/lib/neo4j/functions/count.rb +33 -0
- data/lib/neo4j/functions/function.rb +72 -0
- data/lib/neo4j/functions/sum.rb +27 -0
- data/lib/neo4j/mapping/class_methods/property.rb +2 -1
- data/lib/neo4j/mapping/class_methods/rule.rb +30 -173
- data/lib/neo4j/mapping/node_mixin.rb +3 -1
- data/lib/neo4j/mapping/rule.rb +155 -0
- data/lib/neo4j/mapping/rule_node.rb +177 -0
- data/lib/neo4j/neo4j.rb +0 -4
- data/lib/neo4j/node.rb +12 -2
- data/lib/neo4j/node_relationship.rb +1 -1
- data/lib/neo4j/node_traverser.rb +11 -1
- data/lib/neo4j/rails/finders.rb +1 -1
- data/lib/neo4j/rails/persistence.rb +1 -0
- data/lib/neo4j/rails/relationships/relationships.rb +8 -5
- data/lib/neo4j/relationship.rb +12 -1
- data/lib/neo4j/type_converters.rb +121 -62
- data/lib/neo4j/version.rb +1 -1
- data/lib/tmp/neo4j/index/lucene-store.db +0 -0
- data/lib/tmp/neo4j/lucene-fulltext/lucene-store.db +0 -0
- data/lib/tmp/neo4j/lucene/lucene-store.db +0 -0
- data/lib/tmp/neo4j/messages.log +43 -176
- data/lib/tmp/neo4j/neostore +0 -0
- data/lib/tmp/neo4j/neostore.nodestore.db +0 -0
- data/lib/tmp/neo4j/neostore.nodestore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index.keys +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.strings +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.strings.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshipstore.db +0 -0
- data/lib/tmp/neo4j/neostore.relationshipstore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/tmp/neo4j/tm_tx_log.1 +0 -0
- metadata +8 -11
- data/lib/tmp/neo4j/index.db +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/_0.cfs +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/_1.cfs +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/segments.gen +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/segments_3 +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Thing-exact/_0.cfs +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Thing-exact/segments.gen +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Thing-exact/segments_2 +0 -0
@@ -29,8 +29,10 @@ module Neo4j::Mapping
|
|
29
29
|
module NodeMixin
|
30
30
|
include Neo4j::Index
|
31
31
|
|
32
|
+
include Neo4j::Functions
|
33
|
+
|
32
34
|
delegate :[]=, :[], :property?, :props, :attributes, :update, :neo_id, :id, :rels, :rel?, :to_param, :getId,
|
33
|
-
:rel, :del, :list?, :print, :print_sub, :outgoing, :incoming, :both,
|
35
|
+
:rel, :del, :list?, :print, :print_sub, :outgoing, :incoming, :both, :get_property, :set_property,
|
34
36
|
:equal?, :eql?, :==, :exist?, :getRelationships, :getSingleRelationship, :_rels, :rel,
|
35
37
|
:to => :@_java_node, :allow_nil => true
|
36
38
|
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Neo4j::Mapping
|
2
|
+
|
3
|
+
|
4
|
+
# Holds all defined rules and trigger them when an event is received.
|
5
|
+
#
|
6
|
+
# See Neo4j::Mapping::ClassMethods::Rule
|
7
|
+
#
|
8
|
+
class Rule #:nodoc:
|
9
|
+
|
10
|
+
attr_reader :rule_name, :filter, :triggers, :functions
|
11
|
+
|
12
|
+
def initialize(rule_name, props, &block)
|
13
|
+
@rule_name = rule_name
|
14
|
+
@triggers = props[:triggers]
|
15
|
+
@functions = props[:functions]
|
16
|
+
@triggers = [@triggers] if @triggers && !@triggers.respond_to?(:each)
|
17
|
+
@functions = [@functions] if @functions && !@functions.respond_to?(:each)
|
18
|
+
@filter = block.nil? ? Proc.new { |*| true } : block
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
"Rule #{rule_name} props=#{props.inspect}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_function(function_name, function_id)
|
26
|
+
function_id = function_id.to_s
|
27
|
+
@functions && @functions.find{|f| f.function_id == function_id && f.class.function_name == function_name}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Reconstruct the properties given when created this rule
|
31
|
+
# Needed when inheriting a rule and we want to duplicate a rule
|
32
|
+
def props
|
33
|
+
props = {}
|
34
|
+
props[:triggers] = @triggers if @triggers
|
35
|
+
props[:functions] = @functions if @functions
|
36
|
+
props
|
37
|
+
end
|
38
|
+
|
39
|
+
def functions_for(property)
|
40
|
+
@functions && @functions.find_all { |f| f.calculate?(property) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def execute_filter(node)
|
44
|
+
if @filter.arity != 1
|
45
|
+
node.wrapper.instance_eval(&@filter)
|
46
|
+
else
|
47
|
+
@filter.call(node)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# ------------------------------------------------------------------------------------------------------------------
|
52
|
+
# Class Methods
|
53
|
+
# ------------------------------------------------------------------------------------------------------------------
|
54
|
+
|
55
|
+
class << self
|
56
|
+
def add(clazz, rule_name, props, &block)
|
57
|
+
@rule_nodes ||= {}
|
58
|
+
@rule_nodes[clazz.to_s] ||= RuleNode.new(clazz)
|
59
|
+
rule_node = @rule_nodes[clazz.to_s]
|
60
|
+
rule_node.remove_rule(rule_name) # remove any previously inherited rules
|
61
|
+
rule_node.add_rule(rule_name, props, &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def rule_names_for(clazz)
|
65
|
+
rule_node = rule_node_for(clazz)
|
66
|
+
rule_node.rules.map { |rule| rule.rule_name }
|
67
|
+
end
|
68
|
+
|
69
|
+
def rule_node_for(clazz)
|
70
|
+
@rule_nodes && @rule_nodes[clazz.to_s]
|
71
|
+
end
|
72
|
+
|
73
|
+
def inherit(parent_class, subclass)
|
74
|
+
# copy all the rules
|
75
|
+
if rule_node = rule_node_for(parent_class)
|
76
|
+
rule_node.inherit(subclass)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete(clazz)
|
81
|
+
if rule_node = rule_node_for(clazz)
|
82
|
+
rule_node.delete_node
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def trigger?(node)
|
87
|
+
classname = node[:_classname]
|
88
|
+
@rule_nodes && classname && rule_node_for(classname)
|
89
|
+
end
|
90
|
+
|
91
|
+
def trigger_rules(node, *changes)
|
92
|
+
classname = node[:_classname]
|
93
|
+
rule_node = rule_node_for(classname)
|
94
|
+
rule_node.execute_rules(node, *changes)
|
95
|
+
|
96
|
+
# recursively add relationships for all the parent classes with rules that also pass for this node
|
97
|
+
if (clazz = eval("#{classname}.superclass")) && clazz.include?(Neo4j::NodeMixin)
|
98
|
+
rule_node = rule_node_for(clazz)
|
99
|
+
rule_node && rule_node.execute_rules(node, *changes)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# ----------------------------------------------------------------------------------------------------------------
|
105
|
+
# Event handling methods
|
106
|
+
# ----------------------------------------------------------------------------------------------------------------
|
107
|
+
|
108
|
+
def on_relationship_created(rel, *)
|
109
|
+
trigger_start_node = trigger?(rel._start_node)
|
110
|
+
trigger_end_node = trigger?(rel._end_node)
|
111
|
+
trigger_rules(rel._start_node) if trigger_start_node
|
112
|
+
trigger_rules(rel._end_node) if trigger_end_node
|
113
|
+
end
|
114
|
+
|
115
|
+
def on_property_changed(node, *changes)
|
116
|
+
trigger_rules(node, *changes) if trigger?(node)
|
117
|
+
end
|
118
|
+
|
119
|
+
def on_node_deleted(node, old_properties, data)
|
120
|
+
# have we deleted a rule node ?
|
121
|
+
del_rule_node = @rule_nodes && @rule_nodes.values.find{|rn| rn.rule_node?(node)}
|
122
|
+
del_rule_node && del_rule_node.clear_rule_node
|
123
|
+
return if del_rule_node
|
124
|
+
|
125
|
+
# do we have prop_aggregations for this
|
126
|
+
clazz = old_properties['_classname']
|
127
|
+
rule_node = rule_node_for(clazz)
|
128
|
+
return if rule_node.nil?
|
129
|
+
|
130
|
+
id = node.getId
|
131
|
+
rule_node.rules.each do |rule|
|
132
|
+
next if rule.functions.nil?
|
133
|
+
rule_name = rule.rule_name.to_s
|
134
|
+
|
135
|
+
# is the rule node deleted ?
|
136
|
+
deleted_rule_node = data.deletedNodes.find{|n| n == rule_node.rule_node}
|
137
|
+
next if deleted_rule_node
|
138
|
+
|
139
|
+
rule.functions.each do |function|
|
140
|
+
next unless data.deletedRelationships.find do |r|
|
141
|
+
r.getEndNode().getId() == id && r.rel_type == rule_name
|
142
|
+
end
|
143
|
+
previous_value = old_properties[function.function_id]
|
144
|
+
function.delete(rule_name, rule_node.rule_node, previous_value) if previous_value
|
145
|
+
end if rule.functions
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def on_neo4j_started(*)
|
150
|
+
@rule_nodes.each_value { |rule_node| rule_node.on_neo4j_started } if @rule_nodes
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module Neo4j::Mapping
|
2
|
+
|
3
|
+
|
4
|
+
class RuleNode
|
5
|
+
attr_reader :rules
|
6
|
+
|
7
|
+
def initialize(clazz)
|
8
|
+
@clazz = clazz
|
9
|
+
@rules = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"RuleNode #{@clazz}, node #{rule_node} #rules: #{@rules.size}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def node_exist?
|
17
|
+
!Neo4j.ref_node.rel?(@clazz)
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_node
|
21
|
+
Neo4j::Transaction.run do
|
22
|
+
node = Neo4j::Node.new
|
23
|
+
Neo4j.ref_node.outgoing(@clazz) << node
|
24
|
+
node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def inherit(subclass)
|
29
|
+
@rules.each do |rule|
|
30
|
+
subclass.rule rule.rule_name, rule.props, &rule.filter
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete_node
|
35
|
+
if Neo4j.ref_node.rel?(@clazz)
|
36
|
+
Neo4j.ref_node.outgoing(@clazz).each { |n| n.del }
|
37
|
+
end
|
38
|
+
clear_rule_node
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_node
|
42
|
+
Neo4j.ref_node.rel?(@clazz.to_s) && Neo4j.ref_node._rel(:outgoing, @clazz.to_s)._end_node
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_neo4j_started
|
46
|
+
# initialize the rule node when neo4j starts
|
47
|
+
@rule_node = find_node || create_node
|
48
|
+
end
|
49
|
+
|
50
|
+
def rule_node
|
51
|
+
@rule_node ||= find_node || create_node
|
52
|
+
end
|
53
|
+
|
54
|
+
def rule_node?(node)
|
55
|
+
@rule_node == node
|
56
|
+
end
|
57
|
+
|
58
|
+
def clear_rule_node
|
59
|
+
@rule_node = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def rule_names
|
63
|
+
@rules.map { |r| r.rule_name }
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_rule(rule_name)
|
67
|
+
@rules.find { |rule| rule.rule_name == rule_name }
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_rule(rule_name, props, &block)
|
71
|
+
@rules << (rule = Rule.new(rule_name, props, &block))
|
72
|
+
rule
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_rule(rule_name)
|
76
|
+
r = find_rule(rule_name)
|
77
|
+
r && @rules.delete(r)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return a traversal object with methods for each rule and function.
|
81
|
+
# E.g. Person.all.old or Person.all.sum(:age)
|
82
|
+
def traversal(rule_name)
|
83
|
+
# define method on the traversal
|
84
|
+
traversal = rule_node.outgoing(rule_name)
|
85
|
+
@rules.each do |rule|
|
86
|
+
traversal.filter_method(rule.rule_name) do |path|
|
87
|
+
path.end_node.rel?(rule.rule_name, :incoming)
|
88
|
+
end
|
89
|
+
rule.functions && rule.functions.each do |func|
|
90
|
+
traversal.functions_method(func, self, rule_name)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
traversal
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_function(rule_name, function_name, function_id)
|
97
|
+
rule = find_rule(rule_name)
|
98
|
+
rule.find_function(function_name, function_id)
|
99
|
+
end
|
100
|
+
|
101
|
+
def execute_rules(node, *changes)
|
102
|
+
@rules.each do |rule|
|
103
|
+
execute_rule(rule, node, *changes)
|
104
|
+
execute_other_rules(rule, node)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def execute_other_rules(rule, node)
|
109
|
+
rule.triggers && rule.triggers.each do |rel_type|
|
110
|
+
node.incoming(rel_type).each { |n| n.trigger_rules }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def execute_rule(rule, node, *changes)
|
115
|
+
if rule.execute_filter(node)
|
116
|
+
if connected?(rule.rule_name, node)
|
117
|
+
# it was already connected - the node is in the same rule group but a property has changed
|
118
|
+
execute_update_functions(rule, *changes)
|
119
|
+
else
|
120
|
+
# the node has changed or is in a new rule group
|
121
|
+
connect(rule.rule_name, node)
|
122
|
+
execute_add_functions(rule, *changes)
|
123
|
+
end
|
124
|
+
else
|
125
|
+
if break_connection(rule.rule_name, node)
|
126
|
+
# the node has been removed from a rule group
|
127
|
+
execute_delete_functions(rule, *changes)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def execute_update_functions(rule, *changes)
|
133
|
+
if functions = find_functions_for_changes(rule, *changes)
|
134
|
+
functions && functions.each { |f| f.update(rule.rule_name, rule_node, changes[1], changes[2]) }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def execute_add_functions(rule, *changes)
|
139
|
+
if functions = find_functions_for_changes(rule, *changes)
|
140
|
+
functions && functions.each { |f| f.add(rule.rule_name, rule_node, changes[2]) }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def execute_delete_functions(rule, *changes)
|
145
|
+
if functions = find_functions_for_changes(rule, *changes)
|
146
|
+
functions.each { |f| f.delete(rule.rule_name, rule_node, changes[1]) }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def find_functions_for_changes(rule, *changes)
|
151
|
+
# changes = [property, old_value, new_value]
|
152
|
+
!changes.empty? && rule.functions_for(changes[0])
|
153
|
+
end
|
154
|
+
|
155
|
+
# work out if two nodes are connected by a particular relationship
|
156
|
+
# uses the end_node to start with because it's more likely to have less relationships to go through
|
157
|
+
# (just the number of superclasses it has really)
|
158
|
+
def connected?(rule_name, end_node)
|
159
|
+
end_node.incoming(rule_name).find { |n| n == rule_node }
|
160
|
+
end
|
161
|
+
|
162
|
+
def connect(rule_name, end_node)
|
163
|
+
rule_node.outgoing(rule_name) << end_node
|
164
|
+
end
|
165
|
+
|
166
|
+
# sever a direct one-to-one relationship if it exists
|
167
|
+
def break_connection(rule_name, end_node)
|
168
|
+
rel = end_node._rels(:incoming, rule_name).find { |r| r._start_node == rule_node }
|
169
|
+
rel && rel.del
|
170
|
+
!rel.nil?
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
end
|
177
|
+
|
data/lib/neo4j/neo4j.rb
CHANGED
data/lib/neo4j/node.rb
CHANGED
@@ -9,9 +9,19 @@ module Neo4j
|
|
9
9
|
include Neo4j::Index
|
10
10
|
|
11
11
|
# Delete the node and all its relationship
|
12
|
+
#
|
13
|
+
# ==== Returns
|
14
|
+
# true :: if the node was deleted
|
15
|
+
# false :: if node was not deleted, maybe it has already been deleted
|
16
|
+
#
|
12
17
|
def del
|
13
18
|
rels.each {|r| r.del}
|
14
|
-
|
19
|
+
begin
|
20
|
+
delete
|
21
|
+
true
|
22
|
+
rescue
|
23
|
+
false
|
24
|
+
end
|
15
25
|
end
|
16
26
|
|
17
27
|
# returns true if the node exists in the database
|
@@ -118,7 +128,7 @@ module Neo4j
|
|
118
128
|
# Same as load but does not return the node as a wrapped Ruby object.
|
119
129
|
#
|
120
130
|
def _load(node_id, db)
|
121
|
-
|
131
|
+
return nil if node_id.nil?
|
122
132
|
db.graph.get_node_by_id(node_id.to_i)
|
123
133
|
rescue java.lang.IllegalStateException
|
124
134
|
nil # the node has been deleted
|
@@ -116,7 +116,7 @@ module Neo4j
|
|
116
116
|
java_types = types.inject([]) { |result, type| result << type_to_java(type) }.to_java(:'org.neo4j.graphdb.RelationshipType')
|
117
117
|
get_relationships(java_types)
|
118
118
|
elsif types.size == 1
|
119
|
-
get_relationships(type_to_java(types[0], dir_to_java(dir))
|
119
|
+
get_relationships(type_to_java(types[0]), dir_to_java(dir))
|
120
120
|
elsif dir == :both
|
121
121
|
get_relationships(dir_to_java(dir))
|
122
122
|
else
|
data/lib/neo4j/node_traverser.rb
CHANGED
@@ -71,7 +71,7 @@ module Neo4j
|
|
71
71
|
break if i >= to
|
72
72
|
end
|
73
73
|
pager.replace res
|
74
|
-
pager.total_entries ||=
|
74
|
+
pager.total_entries ||= count
|
75
75
|
end
|
76
76
|
|
77
77
|
def <<(other_node)
|
@@ -118,6 +118,16 @@ module Neo4j
|
|
118
118
|
self
|
119
119
|
end
|
120
120
|
|
121
|
+
def functions_method(func, rule_node, rule_name)
|
122
|
+
singelton = class << self; self; end
|
123
|
+
singelton.send(:define_method, func.class.function_name) do |*args|
|
124
|
+
function_id = args.empty? ? "_classname" : args[0]
|
125
|
+
function = rule_node.find_function(rule_name, func.class.function_name, function_id)
|
126
|
+
function.value(rule_node.rule_node, rule_name)
|
127
|
+
end
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
121
131
|
def prune(&block)
|
122
132
|
@td = @td.prune(PruneEvaluator.new(block))
|
123
133
|
self
|
data/lib/neo4j/rails/finders.rb
CHANGED
@@ -3,7 +3,7 @@ module Neo4j
|
|
3
3
|
module Relationships
|
4
4
|
|
5
5
|
# TODO, reuse for incoming relationships ?
|
6
|
-
class OutgoingRelationship
|
6
|
+
class OutgoingRelationship #:nodoc:
|
7
7
|
include Enumerable
|
8
8
|
|
9
9
|
def initialize(from_node, mapper)
|
@@ -22,17 +22,17 @@ module Neo4j
|
|
22
22
|
end
|
23
23
|
|
24
24
|
|
25
|
-
def write_changed_relationships
|
25
|
+
def write_changed_relationships #:nodoc:
|
26
26
|
@relationships.each_value do |mapper|
|
27
27
|
mapper.persist
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
def valid_relationships?
|
31
|
+
def valid_relationships? #:nodoc:
|
32
32
|
!@relationships.values.find {|mapper| !mapper.valid?}
|
33
33
|
end
|
34
34
|
|
35
|
-
def _decl_rels_for(type)
|
35
|
+
def _decl_rels_for(type) #:nodoc:
|
36
36
|
dsl = super
|
37
37
|
if false && persisted?
|
38
38
|
dsl
|
@@ -42,11 +42,14 @@ module Neo4j
|
|
42
42
|
end
|
43
43
|
|
44
44
|
|
45
|
-
def clear_relationships
|
45
|
+
def clear_relationships #:nodoc:
|
46
46
|
@relationships = {}
|
47
47
|
end
|
48
48
|
|
49
49
|
|
50
|
+
# See, Neo4j::NodeRelationship#outgoing
|
51
|
+
# Creates or traverse relationships in memory without communicating with the neo4j database.
|
52
|
+
#
|
50
53
|
def outgoing(rel_type)
|
51
54
|
if persisted?
|
52
55
|
super
|