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.
- data/CHANGELOG +30 -0
- data/CONTRIBUTORS +1 -0
- data/Gemfile +16 -4
- data/README.rdoc +25 -3
- data/bin/neo4j-jars +15 -8
- data/bin/neo4j-shell +0 -1
- data/bin/neo4j-upgrade +72 -0
- data/config/neo4j/config.yml +5 -4
- data/lib/neo4j/algo/algo.rb +0 -1
- data/lib/neo4j/batch/inserter.rb +5 -0
- data/lib/neo4j/database.rb +18 -12
- data/lib/neo4j/event_handler.rb +76 -9
- data/lib/neo4j/has_list/class_methods.rb +1 -1
- data/lib/neo4j/has_list/mapping.rb +13 -33
- data/lib/neo4j/has_n/decl_relationship_dsl.rb +17 -13
- data/lib/neo4j/has_n/mapping.rb +6 -23
- data/lib/neo4j/identity_map.rb +0 -3
- data/lib/neo4j/index/class_methods.rb +9 -3
- data/lib/neo4j/index/index.rb +2 -1
- data/lib/neo4j/index/indexer.rb +3 -2
- data/lib/neo4j/index/indexer_registry.rb +1 -1
- data/lib/neo4j/index/lucene_query.rb +52 -33
- data/lib/neo4j/neo4j.rb +19 -0
- data/lib/neo4j/node.rb +42 -36
- data/lib/neo4j/node_mixin/node_mixin.rb +9 -5
- data/lib/neo4j/paginated.rb +23 -0
- data/lib/neo4j/rails/accept_id.rb +66 -0
- data/lib/neo4j/rails/attributes.rb +14 -9
- data/lib/neo4j/rails/compositions.rb +9 -1
- data/lib/neo4j/rails/finders.rb +5 -1
- data/lib/neo4j/rails/mapping/property.rb +41 -28
- data/lib/neo4j/rails/model.rb +2 -0
- data/lib/neo4j/rails/observer.rb +61 -2
- data/lib/neo4j/rails/persistence.rb +57 -57
- data/lib/neo4j/rails/rails.rb +1 -0
- data/lib/neo4j/rails/railtie.rb +4 -1
- data/lib/neo4j/rails/rel_persistence.rb +11 -12
- data/lib/neo4j/rails/relationship.rb +9 -4
- data/lib/neo4j/rails/relationships/node_dsl.rb +15 -5
- data/lib/neo4j/rails/relationships/relationships.rb +42 -2
- data/lib/neo4j/rails/relationships/rels_dsl.rb +60 -3
- data/lib/neo4j/rails/relationships/storage.rb +43 -5
- data/lib/neo4j/rails/validations/uniqueness.rb +1 -0
- data/lib/neo4j/rails/versioning/versioning.rb +64 -9
- data/lib/neo4j/relationship.rb +79 -73
- data/lib/neo4j/rule/event_listener.rb +7 -1
- data/lib/neo4j/rule/functions/count.rb +6 -0
- data/lib/neo4j/rule/rule.rb +20 -5
- data/lib/neo4j/rule/rule_node.rb +33 -20
- data/lib/neo4j/to_java.rb +5 -0
- data/lib/neo4j/traversal/traverser.rb +38 -1
- data/lib/neo4j/type_converters/type_converters.rb +56 -5
- data/lib/neo4j/version.rb +1 -1
- data/lib/neo4j.rb +3 -49
- data/neo4j.gemspec +2 -2
- metadata +191 -216
- data/bin/neo4j-shell~ +0 -108
- data/lib/Gemfile~ +0 -3
- data/lib/config2.yml~ +0 -86
- data/lib/neo4j/jars/core/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/core/lucene-core-3.1.0.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-backup-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-graph-algo-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-kernel-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-lucene-index-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/log4j-1.2.16.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-com-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-ha-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-jmx-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-management-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-shell-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/netty-3.2.1.Final.jar +0 -0
- data/lib/neo4j/jars/ha/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
- data/lib/neo4j/jars/ha/zookeeper-3.3.2.jar +0 -0
- data/lib/neo4j/paginate.rb +0 -25
- data/lib/perf.rb~ +0 -36
- 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
|
85
|
-
@storage.each_rel(@dir
|
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(
|
90
|
-
|
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
|
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
|
-
|
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.
|
data/lib/neo4j/relationship.rb
CHANGED
@@ -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
|
data/lib/neo4j/rule/rule.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
124
|
-
|
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
|
data/lib/neo4j/rule/rule_node.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
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
|
-
|
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
|