neo4j 1.2.4-java → 1.2.5-java
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +13 -0
- data/CONTRIBUTORS +2 -1
- data/config/neo4j/config.yml +5 -0
- data/lib/generators/neo4j/model/model_generator.rb +4 -4
- data/lib/neo4j.rb +5 -1
- data/lib/neo4j/config.rb +1 -0
- data/lib/neo4j/event_handler.rb +57 -27
- data/lib/neo4j/identity_map.rb +143 -0
- data/lib/neo4j/index/indexer.rb +3 -5
- data/lib/neo4j/index/indexer_registry.rb +7 -7
- data/lib/neo4j/index/lucene_query.rb +2 -2
- data/lib/neo4j/load.rb +9 -5
- data/lib/neo4j/node.rb +1 -1
- data/lib/neo4j/node_mixin/class_methods.rb +1 -0
- data/lib/neo4j/rails/attributes.rb +4 -0
- data/lib/neo4j/rails/callbacks.rb +14 -9
- data/lib/neo4j/rails/persistence.rb +4 -1
- data/lib/neo4j/rails/railtie.rb +1 -0
- data/lib/neo4j/rails/rel_persistence.rb +5 -0
- data/lib/neo4j/rails/relationship.rb +2 -1
- data/lib/neo4j/rails/relationships/relationships.rb +5 -4
- data/lib/neo4j/rails/relationships/storage.rb +19 -35
- data/lib/neo4j/rails/timestamps.rb +19 -10
- data/lib/neo4j/rails/validations/uniqueness.rb +71 -32
- data/lib/neo4j/relationship_mixin/class_methods.rb +1 -0
- data/lib/neo4j/relationship_set.rb +58 -0
- data/lib/neo4j/rule/event_listener.rb +3 -5
- data/lib/neo4j/rule/rule.rb +4 -4
- data/lib/neo4j/rule/rule_node.rb +11 -10
- data/lib/neo4j/traversal/traversal.rb +4 -1
- data/lib/neo4j/traversal/traverser.rb +13 -3
- data/lib/neo4j/version.rb +1 -1
- metadata +4 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
== 1.2.5 / 2011-10-21
|
2
|
+
* Faster traversals by avoiding loading Ruby wrappers (new method 'raw' on traversals) [#189]
|
3
|
+
* Support for IdentityMap [#188]
|
4
|
+
* Improved performance in event handler (Vivek Prahlad)
|
5
|
+
* Fixing issue with validates_presence_of validation (Vivek Prahlad)
|
6
|
+
* Implemented compositions support on Neo4j::Rails::Relationship (Kalyan Akella)
|
7
|
+
* Added after_initialize callback (Deepak N)
|
8
|
+
* Fixed performance issues on node deleted (Vivek Prahlad)
|
9
|
+
* Fixed a performance issue in the index_registry (Vivek Prahlad)
|
10
|
+
* Fixed uniqueness validation for :case_sensitive => false (Vivek Prahlad)
|
11
|
+
* Fixed update_attributes deleting relations when model is invalid (Deepak N)
|
12
|
+
* Fixed timestamp rails generator (Marcio Toshio)
|
13
|
+
|
1
14
|
== 1.2.4 / 2011-10-07
|
2
15
|
* Support for traversing with Neo4j::Node#eval_paths and setting uniqueness on traversals [#187]
|
3
16
|
* Removed unnecessary node creation on database start up (class nodes attached to reference node) (Vivek Prahlad)
|
data/CONTRIBUTORS
CHANGED
data/config/neo4j/config.yml
CHANGED
@@ -7,6 +7,11 @@ storage_path: db
|
|
7
7
|
# If disabled all custom rules will also be unavailable.
|
8
8
|
enable_rules: true
|
9
9
|
|
10
|
+
# if identity map should be on or not
|
11
|
+
# It may impact the performance. Using the identity map will keep all loaded wrapper node/relationship
|
12
|
+
# object in memory for each thread and transaction - which may speed up or slow down operations.
|
13
|
+
identity_map: false
|
14
|
+
|
10
15
|
# When using the Neo4j::Model you can let neo4j automatically set timestamps when updating/creating nodes.
|
11
16
|
# If set to true neo4j.rb automatically timestamps create and update operations if the model has properties named created_at/created_on or updated_at/updated_on
|
12
17
|
# (similar to ActiveRecord).
|
@@ -27,11 +27,11 @@ class Neo4j::Generators::ModelGenerator < Neo4j::Generators::Base #:nodoc:
|
|
27
27
|
|
28
28
|
def timestamp_statements
|
29
29
|
%q{
|
30
|
-
property :created_at, DateTime
|
31
|
-
# property :created_on, Date
|
30
|
+
property :created_at, :type => DateTime
|
31
|
+
# property :created_on, :type => Date
|
32
32
|
|
33
|
-
property :updated_at, DateTime
|
34
|
-
# property :updated_on, Date
|
33
|
+
property :updated_at, :type => DateTime
|
34
|
+
# property :updated_on, :type => Date
|
35
35
|
}
|
36
36
|
end
|
37
37
|
|
data/lib/neo4j.rb
CHANGED
@@ -63,7 +63,7 @@ end
|
|
63
63
|
|
64
64
|
module Neo4j
|
65
65
|
include Java
|
66
|
-
|
66
|
+
|
67
67
|
# Enumerator has been moved to top level in Ruby 1.9.2, make it compatible with Ruby 1.8.7
|
68
68
|
Enumerator = Enumerable::Enumerator unless defined? Enumerator
|
69
69
|
end
|
@@ -72,6 +72,7 @@ require 'neo4j/version'
|
|
72
72
|
require 'neo4j/neo4j'
|
73
73
|
require 'neo4j/node'
|
74
74
|
require 'neo4j/relationship'
|
75
|
+
require 'neo4j/relationship_set'
|
75
76
|
|
76
77
|
require 'neo4j/type_converters/type_converters'
|
77
78
|
|
@@ -103,4 +104,7 @@ require 'neo4j/batch/batch'
|
|
103
104
|
|
104
105
|
require 'orm_adapter/adapters/neo4j'
|
105
106
|
|
107
|
+
require 'neo4j/identity_map'
|
108
|
+
|
109
|
+
|
106
110
|
|
data/lib/neo4j/config.rb
CHANGED
@@ -14,6 +14,7 @@ module Neo4j
|
|
14
14
|
# <tt>:timestamps</tt>:: default <tt>true</tt> for Rails Neo4j::Model - if timestamps should be used when saving the model
|
15
15
|
# <tt>:lucene</tt>:: default hash keys: <tt>:fulltext</tt>, <tt>:exact</tt> configuration how the lucene index is stored
|
16
16
|
# <tt>:enable_rules</tt>:: default true, if false the _all relationship to all instances will not be created and custom rules will not be available.
|
17
|
+
# <tt>:identity_map</tt>:: default false, See Neo4j::IdentityMap
|
17
18
|
#
|
18
19
|
class Config
|
19
20
|
# This code is copied from merb-core/config.rb.
|
data/lib/neo4j/event_handler.rb
CHANGED
@@ -12,6 +12,7 @@ module Neo4j
|
|
12
12
|
# * <tt>on_relationship_deleted</tt>
|
13
13
|
# * <tt>on_property_changed</tt>
|
14
14
|
# * <tt>on_rel_property_changed</tt>
|
15
|
+
# * <tt>on_after_commit</tt>
|
15
16
|
#
|
16
17
|
# ==== on_neo4j_started(db)
|
17
18
|
#
|
@@ -28,26 +29,33 @@ module Neo4j
|
|
28
29
|
#
|
29
30
|
# * <tt>db</tt> :: the Neo4j::Database instance
|
30
31
|
#
|
32
|
+
# ==== on_after_commit(data, state)
|
33
|
+
#
|
34
|
+
# Called after the transaction has successfully committed.
|
35
|
+
# See http://api.neo4j.org/1.4/org/neo4j/graphdb/event/TransactionEventHandler.html for the data and state parameter.
|
36
|
+
#
|
31
37
|
# ==== on_node_created(node)
|
32
38
|
#
|
33
39
|
# * <tt>node</tt> :: the node that was created
|
34
40
|
#
|
35
|
-
# ==== on_node_deleted(node, old_props,
|
41
|
+
# ==== on_node_deleted(node, old_props, deleted_relationship_set, deleted_node_identity_map)
|
36
42
|
#
|
37
43
|
# * <tt>node</tt> :: the node that was deleted
|
38
44
|
# * <tt>old_props</tt> :: a hash of the old properties this node had
|
39
|
-
# * <tt>
|
45
|
+
# * <tt>deleted_relationship_set</tt> :: the set of deleted relationships. See Neo4j::RelationshipSet
|
46
|
+
# * <tt>deleted_node_identity_map</tt> :: the identity map of deleted nodes. The key is the node id, and the value is the node
|
40
47
|
#
|
41
|
-
# ==== on_relationship_created(rel,
|
48
|
+
# ==== on_relationship_created(rel, created_node_identity_map)
|
42
49
|
#
|
43
50
|
# * <tt>rel</tt> :: the relationship that was created
|
44
|
-
# * <tt>
|
51
|
+
# * <tt>created_node_identity_map</tt> :: the identity map of created nodes. The key is the node id, and the value is the node
|
45
52
|
#
|
46
|
-
# ==== on_relationship_deleted(rel, old_props,
|
53
|
+
# ==== on_relationship_deleted(rel, old_props, deleted_relationship_set, deleted_node_identity_map)
|
47
54
|
#
|
48
55
|
# * <tt>rel</tt> :: the relationship that was created
|
49
56
|
# * <tt>old_props</tt> :: a hash of the old properties this relationship had
|
50
|
-
# * <tt>
|
57
|
+
# * <tt>deleted_relationship_set</tt> :: the set of deleted relationships. See Neo4j::RelationshipSet
|
58
|
+
# * <tt>deleted_node_identity_map</tt> :: the identity map of deleted nodes. The key is the node id, and the value is the node
|
51
59
|
#
|
52
60
|
# ==== on_property_changed(node, key, old_value, new_value)
|
53
61
|
#
|
@@ -66,7 +74,7 @@ module Neo4j
|
|
66
74
|
# == Usage
|
67
75
|
#
|
68
76
|
# class MyListener
|
69
|
-
# def on_node_deleted(node, old_props,
|
77
|
+
# def on_node_deleted(node, old_props, deleted_relationship_set, deleted_node_identity_map)
|
70
78
|
# end
|
71
79
|
# end
|
72
80
|
#
|
@@ -84,34 +92,56 @@ module Neo4j
|
|
84
92
|
|
85
93
|
|
86
94
|
def after_commit(data, state)
|
95
|
+
@listeners.each {|li| li.on_after_commit(data, state) if li.respond_to?(:on_after_commit)}
|
87
96
|
end
|
88
97
|
|
89
98
|
def after_rollback(data, state)
|
90
99
|
end
|
91
100
|
|
92
101
|
def before_commit(data)
|
102
|
+
created_node_identity_map = node_identity_map(data.created_nodes)
|
103
|
+
deleted_node_identity_map = node_identity_map(data.deleted_nodes)
|
104
|
+
deleted_relationship_set = relationship_set(data.deleted_relationships)
|
105
|
+
removed_node_properties_map = property_map(data.removed_node_properties)
|
106
|
+
removed_relationship_properties_map = property_map(data.removed_relationship_properties)
|
107
|
+
empty_map = java.util.HashMap.new
|
93
108
|
data.created_nodes.each{|node| node_created(node)}
|
94
109
|
data.assigned_node_properties.each { |tx_data| property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, tx_data.value) }
|
95
|
-
data.removed_node_properties.each { |tx_data| property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, nil) unless
|
96
|
-
data.deleted_nodes.each { |node| node_deleted(node,
|
97
|
-
data.created_relationships.each {|rel| relationship_created(rel,
|
98
|
-
data.deleted_relationships.each {|rel| relationship_deleted(rel,
|
110
|
+
data.removed_node_properties.each { |tx_data| property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, nil) unless deleted_node_identity_map.containsKey(tx_data.entity.getId) }
|
111
|
+
data.deleted_nodes.each { |node| node_deleted(node, removed_node_properties_map.get(node.getId)||empty_map, deleted_relationship_set, deleted_node_identity_map)}
|
112
|
+
data.created_relationships.each {|rel| relationship_created(rel, created_node_identity_map)}
|
113
|
+
data.deleted_relationships.each {|rel| relationship_deleted(rel, removed_relationship_properties_map.get(rel.getId)||empty_map, deleted_relationship_set, deleted_node_identity_map)}
|
99
114
|
data.assigned_relationship_properties.each { |tx_data| rel_property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, tx_data.value) }
|
100
|
-
data.removed_relationship_properties.each {|tx_data| rel_property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, nil) unless
|
115
|
+
data.removed_relationship_properties.each {|tx_data| rel_property_changed(tx_data.entity, tx_data.key, tx_data.previously_commited_value, nil) unless deleted_relationship_set.contains_rel?(tx_data.entity) }
|
101
116
|
end
|
102
117
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
118
|
+
def node_identity_map(nodes)
|
119
|
+
identity_map = java.util.HashMap.new(nodes.size)
|
120
|
+
nodes.each{|node| identity_map.put(node.neo_id,node)}#using put due to a performance regression in JRuby 1.6.4
|
121
|
+
identity_map
|
122
|
+
end
|
123
|
+
|
124
|
+
def relationship_set(relationships)
|
125
|
+
relationship_set = Neo4j::RelationshipSet.new(relationships.size)
|
126
|
+
relationships.each{|rel| relationship_set.add(rel)}
|
127
|
+
relationship_set
|
108
128
|
end
|
109
129
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
113
|
-
|
130
|
+
def property_map(properties)
|
131
|
+
map = java.util.HashMap.new
|
132
|
+
properties.each do |property|
|
133
|
+
map(property.entity.getId, map).put(property.key, property.previously_commited_value)
|
114
134
|
end
|
135
|
+
map
|
136
|
+
end
|
137
|
+
|
138
|
+
def map(key,map)
|
139
|
+
map.get(key) || add_map(key,map)
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_map(key,map)
|
143
|
+
map.put(key, java.util.HashMap.new)
|
144
|
+
map.get(key)
|
115
145
|
end
|
116
146
|
|
117
147
|
def add(listener)
|
@@ -143,16 +173,16 @@ module Neo4j
|
|
143
173
|
@listeners.each {|li| li.on_node_created(node) if li.respond_to?(:on_node_created)}
|
144
174
|
end
|
145
175
|
|
146
|
-
def node_deleted(node,old_properties,
|
147
|
-
@listeners.each {|li| li.on_node_deleted(node,old_properties,
|
176
|
+
def node_deleted(node,old_properties, deleted_relationship_set, deleted_node_identity_map)
|
177
|
+
@listeners.each {|li| li.on_node_deleted(node,old_properties, deleted_relationship_set, deleted_node_identity_map) if li.respond_to?(:on_node_deleted)}
|
148
178
|
end
|
149
179
|
|
150
|
-
def relationship_created(relationship,
|
151
|
-
@listeners.each {|li| li.on_relationship_created(relationship,
|
180
|
+
def relationship_created(relationship, created_node_identity_map)
|
181
|
+
@listeners.each {|li| li.on_relationship_created(relationship, created_node_identity_map) if li.respond_to?(:on_relationship_created)}
|
152
182
|
end
|
153
183
|
|
154
|
-
def relationship_deleted(relationship, old_props,
|
155
|
-
@listeners.each {|li| li.on_relationship_deleted(relationship, old_props,
|
184
|
+
def relationship_deleted(relationship, old_props, deleted_relationship_set, deleted_node_identity_map)
|
185
|
+
@listeners.each {|li| li.on_relationship_deleted(relationship, old_props, deleted_relationship_set, deleted_node_identity_map) if li.respond_to?(:on_relationship_deleted)}
|
156
186
|
end
|
157
187
|
|
158
188
|
def property_changed(node, key, old_value, new_value)
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/identity_map.rb
|
2
|
+
# https://github.com/rails/rails/pull/76
|
3
|
+
|
4
|
+
module Neo4j
|
5
|
+
|
6
|
+
# = Neo4j Identity Map
|
7
|
+
#
|
8
|
+
# Ensures that each object gets loaded only once by keeping every loaded
|
9
|
+
# object in a map. Looks up objects using the map when referring to them.
|
10
|
+
#
|
11
|
+
# More information on Identity Map pattern:
|
12
|
+
# http://www.martinfowler.com/eaaCatalog/identityMap.html
|
13
|
+
#
|
14
|
+
# == Configuration
|
15
|
+
#
|
16
|
+
# In order to enable IdentityMap, set <tt>config.neo4j.identity_map = true</tt>
|
17
|
+
# in your <tt>config/application.rb</tt> file. If used outside rails, set Neo4j::Config[:identity_map] = true.
|
18
|
+
#
|
19
|
+
# IdentityMap is disabled by default and still in development (i.e. use it with care).
|
20
|
+
#
|
21
|
+
module IdentityMap
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def enabled=(flag)
|
25
|
+
Thread.current[:neo4j_identity_map] = flag
|
26
|
+
end
|
27
|
+
|
28
|
+
def enabled
|
29
|
+
Thread.current[:neo4j_identity_map]
|
30
|
+
end
|
31
|
+
|
32
|
+
alias enabled? enabled
|
33
|
+
|
34
|
+
def node_repository
|
35
|
+
Thread.current[:node_identity_map] ||= java.util.HashMap.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def rel_repository
|
39
|
+
Thread.current[:rel_identity_map] ||= java.util.HashMap.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def repository_for(neo_entity)
|
43
|
+
return nil unless enabled?
|
44
|
+
if neo_entity.class == Neo4j::Node
|
45
|
+
node_repository
|
46
|
+
elsif neo_entity.class == Neo4j::Relationship
|
47
|
+
rel_repository
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def use
|
54
|
+
old, self.enabled = enabled, true
|
55
|
+
yield if block_given?
|
56
|
+
ensure
|
57
|
+
self.enabled = old
|
58
|
+
clear
|
59
|
+
end
|
60
|
+
|
61
|
+
def without
|
62
|
+
old, self.enabled = enabled, false
|
63
|
+
yield if block_given?
|
64
|
+
ensure
|
65
|
+
self.enabled = old
|
66
|
+
end
|
67
|
+
|
68
|
+
def get(neo_entity)
|
69
|
+
r = repository_for(neo_entity)
|
70
|
+
r && r.get(neo_entity.neo_id)
|
71
|
+
end
|
72
|
+
|
73
|
+
def add(neo_entity, wrapped_entity)
|
74
|
+
r = repository_for(neo_entity)
|
75
|
+
r && r.put(neo_entity.neo_id, wrapped_entity)
|
76
|
+
end
|
77
|
+
|
78
|
+
def remove(neo_entity)
|
79
|
+
r = repository_for(neo_entity)
|
80
|
+
r && r.remove(neo_entity.neo_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
def remove_node_by_id(node_id)
|
84
|
+
node_repository.remove(node_id)
|
85
|
+
end
|
86
|
+
|
87
|
+
def remove_rel_by_id(rel_id)
|
88
|
+
rel_repository.remove(rel_id)
|
89
|
+
end
|
90
|
+
|
91
|
+
def clear
|
92
|
+
node_repository.clear
|
93
|
+
rel_repository.clear
|
94
|
+
end
|
95
|
+
|
96
|
+
def on_after_commit(*)
|
97
|
+
clear
|
98
|
+
end
|
99
|
+
|
100
|
+
def on_neo4j_started(db)
|
101
|
+
if not Neo4j::Config[:identity_map]
|
102
|
+
db.event_handler.remove(self)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
class Middleware
|
110
|
+
class Body #:nodoc:
|
111
|
+
def initialize(target, original)
|
112
|
+
@target = target
|
113
|
+
@original = original
|
114
|
+
end
|
115
|
+
|
116
|
+
def each(&block)
|
117
|
+
@target.each(&block)
|
118
|
+
end
|
119
|
+
|
120
|
+
def close
|
121
|
+
@target.close if @target.respond_to?(:close)
|
122
|
+
ensure
|
123
|
+
IdentityMap.enabled = @original
|
124
|
+
IdentityMap.clear
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def initialize(app)
|
129
|
+
@app = app
|
130
|
+
end
|
131
|
+
|
132
|
+
def call(env)
|
133
|
+
enabled = IdentityMap.enabled
|
134
|
+
IdentityMap.enabled = Neo4j::Config[:identity_map]
|
135
|
+
status, headers, body = @app.call(env)
|
136
|
+
[status, headers, Body.new(body, enabled)]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
Neo4j.unstarted_db.event_handler.add(Neo4j::IdentityMap)
|
143
|
+
|
data/lib/neo4j/index/indexer.rb
CHANGED
@@ -98,15 +98,13 @@ module Neo4j
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
def remove_index_on_fields(node, props,
|
101
|
+
def remove_index_on_fields(node, props, deleted_relationship_set) #:nodoc:
|
102
102
|
@field_types.keys.each { |field| rm_index(node, field, props[field]) if props[field] }
|
103
103
|
# remove all via indexed fields
|
104
104
|
@via_relationships.each_value do |dsl|
|
105
105
|
indexer = dsl.target_class._indexer
|
106
|
-
|
107
|
-
|
108
|
-
next if node != rel._end_node
|
109
|
-
indexer.remove_index_on_fields(start_node, props, tx_data)
|
106
|
+
deleted_relationship_set.relationships(node.getId).each do |rel|
|
107
|
+
indexer.remove_index_on_fields(rel._start_node, props, deleted_relationship_set)
|
110
108
|
end
|
111
109
|
end
|
112
110
|
end
|
@@ -18,9 +18,9 @@ module Neo4j
|
|
18
18
|
@@indexers[classname]
|
19
19
|
end
|
20
20
|
|
21
|
-
def on_node_deleted(node, old_props,
|
21
|
+
def on_node_deleted(node, old_props, deleted_relationship_set, deleted_identity_map)
|
22
22
|
indexer = find_by_class(old_props['_classname'] || node.class.to_s)
|
23
|
-
indexer && indexer.remove_index_on_fields(node, old_props,
|
23
|
+
indexer && indexer.remove_index_on_fields(node, old_props, deleted_relationship_set)
|
24
24
|
end
|
25
25
|
|
26
26
|
def on_property_changed(node, field, old_val, new_val)
|
@@ -35,23 +35,23 @@ module Neo4j
|
|
35
35
|
on_property_changed(rel, field, old_val, new_val)
|
36
36
|
end
|
37
37
|
|
38
|
-
def on_relationship_created(rel,
|
38
|
+
def on_relationship_created(rel,created_identity_map)
|
39
39
|
end_node = rel._end_node
|
40
40
|
# if end_node was created in this transaction then it will be handled in on_property_changed
|
41
|
-
created =
|
41
|
+
created = created_identity_map.get(end_node.neo_id)
|
42
42
|
unless created
|
43
43
|
indexer = find_by_class(end_node['_classname'])
|
44
44
|
indexer && indexer.update_on_new_relationship(rel)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def on_relationship_deleted(rel, old_props,
|
49
|
-
on_node_deleted(rel, old_props,
|
48
|
+
def on_relationship_deleted(rel, old_props, deleted_relationship_set, deleted_identity_map)
|
49
|
+
on_node_deleted(rel, old_props, deleted_relationship_set, deleted_identity_map)
|
50
50
|
# if only the relationship has been deleted then we have to remove the index
|
51
51
|
# if both the relationship and the node has been deleted then the index will be removed in the
|
52
52
|
# on_node_deleted callback
|
53
53
|
end_node = rel._end_node
|
54
|
-
deleted =
|
54
|
+
deleted = deleted_identity_map.get(end_node.neo_id)
|
55
55
|
unless deleted
|
56
56
|
indexer = find_by_class(end_node['_classname'])
|
57
57
|
indexer && indexer.update_on_deleted_relationship(rel)
|
@@ -117,7 +117,7 @@ module Neo4j
|
|
117
117
|
|
118
118
|
# Performs a range query
|
119
119
|
# Notice that if you don't specify a type when declaring a property a String range query will be performed.
|
120
|
-
#
|
120
|
+
#
|
121
121
|
def between(lower, upper, lower_incusive=false, upper_inclusive=false)
|
122
122
|
raise "Expected a symbol. Syntax for range queries example: index(:weight).between(a,b)" unless Symbol === @query
|
123
123
|
raise "Can't only do range queries on Neo4j::NodeMixin, Neo4j::Model, Neo4j::RelationshipMixin" unless @decl_props
|
@@ -188,7 +188,7 @@ module Neo4j
|
|
188
188
|
type = case
|
189
189
|
when Float == decl_type
|
190
190
|
org.apache.lucene.search.SortField::DOUBLE
|
191
|
-
when Fixnum == decl_type
|
191
|
+
when Fixnum == decl_type || DateTime == decl_type || Date == decl_type || Time == decl_type
|
192
192
|
org.apache.lucene.search.SortField::LONG
|
193
193
|
else
|
194
194
|
org.apache.lucene.search.SortField::STRING
|
data/lib/neo4j/load.rb
CHANGED
@@ -3,9 +3,13 @@ module Neo4j
|
|
3
3
|
# === Mixin responsible for loading Ruby wrappers for Neo4j Nodes and Relationship.
|
4
4
|
#
|
5
5
|
module Load
|
6
|
-
def wrapper(
|
7
|
-
return
|
8
|
-
|
6
|
+
def wrapper(entity) # :nodoc:
|
7
|
+
return entity unless entity.property?(:_classname)
|
8
|
+
existing_instance = Neo4j::IdentityMap.get(entity)
|
9
|
+
return existing_instance if existing_instance
|
10
|
+
new_instance = to_class(entity[:_classname]).load_wrapper(entity)
|
11
|
+
Neo4j::IdentityMap.add(entity, new_instance)
|
12
|
+
new_instance
|
9
13
|
end
|
10
14
|
|
11
15
|
def to_class(class_name) # :nodoc:
|
@@ -13,8 +17,8 @@ module Neo4j
|
|
13
17
|
end
|
14
18
|
|
15
19
|
# Checks if the given entity (node/relationship) or entity id (#neo_id) exists in the database.
|
16
|
-
def exist?(
|
17
|
-
id =
|
20
|
+
def exist?(entity_or_entity_id, db = Neo4j.started_db)
|
21
|
+
id = entity_or_entity_id.kind_of?(Fixnum) ? entity_or_entity_id : entity_or_entity_id.id
|
18
22
|
_load(id, db) != nil
|
19
23
|
end
|
20
24
|
end
|
data/lib/neo4j/node.rb
CHANGED
@@ -216,6 +216,10 @@ module Neo4j
|
|
216
216
|
def attribute?(name)
|
217
217
|
name[0] != ?_ && property?(name)
|
218
218
|
end
|
219
|
+
|
220
|
+
def _classname
|
221
|
+
self[:_classname]
|
222
|
+
end
|
219
223
|
|
220
224
|
# To get ActiveModel::Dirty to work, we need to be able to call undeclared
|
221
225
|
# properties as though they have get methods
|
@@ -4,7 +4,7 @@ module Neo4j
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
CALLBACKS = [
|
7
|
-
:before_validation, :after_validation,
|
7
|
+
:after_initialize, :before_validation, :after_validation,
|
8
8
|
:before_create, :around_create, :after_create,
|
9
9
|
:before_destroy, :around_destroy, :after_destroy,
|
10
10
|
:before_save, :around_save, :after_save,
|
@@ -12,35 +12,40 @@ module Neo4j
|
|
12
12
|
].freeze
|
13
13
|
|
14
14
|
included do
|
15
|
-
[:valid?, :create_or_update, :create, :update, :destroy].each do |method|
|
15
|
+
[:initialize, :valid?, :create_or_update, :create, :update, :destroy].each do |method|
|
16
16
|
alias_method_chain method, :callbacks
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
extend ActiveModel::Callbacks
|
20
|
-
|
20
|
+
|
21
|
+
define_model_callbacks :initialize, :only => :after
|
21
22
|
define_model_callbacks :validation, :create, :save, :update, :destroy
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
def valid_with_callbacks?(*) #:nodoc:
|
25
26
|
_run_validation_callbacks { valid_without_callbacks? }
|
26
27
|
end
|
27
|
-
|
28
|
+
|
28
29
|
def destroy_with_callbacks #:nodoc:
|
29
30
|
_run_destroy_callbacks { destroy_without_callbacks }
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
private
|
33
34
|
def create_or_update_with_callbacks #:nodoc:
|
34
35
|
_run_save_callbacks { create_or_update_without_callbacks }
|
35
36
|
end
|
36
|
-
|
37
|
+
|
37
38
|
def create_with_callbacks #:nodoc:
|
38
39
|
_run_create_callbacks { create_without_callbacks }
|
39
40
|
end
|
40
|
-
|
41
|
+
|
41
42
|
def update_with_callbacks(*) #:nodoc:
|
42
43
|
_run_update_callbacks { update_without_callbacks }
|
43
44
|
end
|
45
|
+
|
46
|
+
def initialize_with_callbacks(*args, &block) #:nodoc:
|
47
|
+
_run_initialize_callbacks { initialize_without_callbacks(*args, &block) }
|
48
|
+
end
|
44
49
|
end
|
45
50
|
end
|
46
51
|
end
|
@@ -5,7 +5,7 @@ module Neo4j
|
|
5
5
|
|
6
6
|
included do
|
7
7
|
extend TxMethods
|
8
|
-
tx_methods :destroy, :create, :update, :update_nested_attributes, :delete
|
8
|
+
tx_methods :destroy, :create, :update, :update_nested_attributes, :delete, :update_attributes, :update_attributes!
|
9
9
|
end
|
10
10
|
|
11
11
|
# Persist the object to the database. Validations and Callbacks are included
|
@@ -154,6 +154,7 @@ module Neo4j
|
|
154
154
|
def create
|
155
155
|
node = Neo4j::Node.new
|
156
156
|
@_java_node = node
|
157
|
+
Neo4j::IdentityMap.add(node, self)
|
157
158
|
init_on_create
|
158
159
|
clear_changes
|
159
160
|
clear_relationships
|
@@ -172,7 +173,9 @@ module Neo4j
|
|
172
173
|
end
|
173
174
|
|
174
175
|
def reload_from_database
|
176
|
+
Neo4j::IdentityMap.remove_node_by_id(id)
|
175
177
|
if reloaded = self.class.load(id)
|
178
|
+
clear_relationships
|
176
179
|
send(:attributes=, reloaded.attributes, false)
|
177
180
|
end
|
178
181
|
reloaded
|
data/lib/neo4j/rails/railtie.rb
CHANGED
@@ -158,6 +158,7 @@ module Neo4j
|
|
158
158
|
_persist_end_node
|
159
159
|
|
160
160
|
@_java_rel = Neo4j::Relationship.new(type, start_node, end_node)
|
161
|
+
Neo4j::IdentityMap.add(@_java_rel, self)
|
161
162
|
init_on_create
|
162
163
|
clear_changes
|
163
164
|
end unless @end_node.nil?
|
@@ -193,6 +194,10 @@ module Neo4j
|
|
193
194
|
end
|
194
195
|
|
195
196
|
def reload_from_database
|
197
|
+
Neo4j::IdentityMap.remove_rel_by_id(id) if persisted?
|
198
|
+
Neo4j::IdentityMap.remove_node_by_id(@end_node.id) if @end_node && @end_node.persisted?
|
199
|
+
Neo4j::IdentityMap.remove_node_by_id(@start_node.id) if @start_node && @start_node.persisted?
|
200
|
+
|
196
201
|
if reloaded = self.class.load(id)
|
197
202
|
send(:attributes=, reloaded.attributes, false)
|
198
203
|
end
|
@@ -4,23 +4,24 @@ module Neo4j
|
|
4
4
|
|
5
5
|
|
6
6
|
def write_changed_relationships #:nodoc:
|
7
|
-
@
|
7
|
+
@_relationships.each_value do |storage|
|
8
8
|
storage.persist
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def clear_relationships #:nodoc:
|
13
|
-
@
|
13
|
+
@_relationships && @_relationships.each_value{|storage| storage.remove_from_identity_map}
|
14
|
+
@_relationships = {}
|
14
15
|
end
|
15
16
|
|
16
17
|
|
17
18
|
def _create_or_get_storage(rel_type) #:nodoc:
|
18
19
|
dsl = _decl_rels_for(rel_type.to_sym)
|
19
|
-
@
|
20
|
+
@_relationships[rel_type.to_sym] ||= Storage.new(self, rel_type, dsl)
|
20
21
|
end
|
21
22
|
|
22
23
|
def _create_or_get_storage_for_decl_rels(decl_rels) #:nodoc:
|
23
|
-
@
|
24
|
+
@_relationships[decl_rels.rel_type.to_sym] ||= Storage.new(self, decl_rels.rel_type, decl_rels)
|
24
25
|
end
|
25
26
|
|
26
27
|
|
@@ -14,9 +14,6 @@ module Neo4j
|
|
14
14
|
@target_class = (dsl && dsl.target_class) || Neo4j::Rails::Model
|
15
15
|
@outgoing_rels = []
|
16
16
|
@incoming_rels = []
|
17
|
-
@persisted_related_nodes = {}
|
18
|
-
@persisted_relationships = {}
|
19
|
-
@persisted_node_to_relationships = {}
|
20
17
|
end
|
21
18
|
|
22
19
|
def to_s #:nodoc:
|
@@ -24,6 +21,11 @@ module Neo4j
|
|
24
21
|
end
|
25
22
|
|
26
23
|
|
24
|
+
def remove_from_identity_map
|
25
|
+
@outgoing_rels.each {|r| Neo4j::IdentityMap.remove(r._java_rel)}
|
26
|
+
@incoming_rels.each {|r| Neo4j::IdentityMap.remove(r._java_rel)}
|
27
|
+
end
|
28
|
+
|
27
29
|
def size(dir)
|
28
30
|
counter = 0
|
29
31
|
# count persisted relationship
|
@@ -60,18 +62,12 @@ module Neo4j
|
|
60
62
|
def each_rel(dir, &block) #:nodoc:
|
61
63
|
relationships(dir).each { |rel| block.call rel }
|
62
64
|
if @node.persisted?
|
63
|
-
|
64
|
-
|
65
|
+
@node._java_node.getRelationships(java_rel_type, dir_to_java(dir)).each do |rel|
|
66
|
+
block.call(rel.wrapper)
|
67
|
+
end
|
65
68
|
end
|
66
69
|
end
|
67
70
|
|
68
|
-
def cache_relationships(dir)
|
69
|
-
@persisted_relationships[dir] ||= []
|
70
|
-
node._java_node.getRelationships(java_rel_type, dir_to_java(dir)).each do |rel|
|
71
|
-
@persisted_relationships[dir] << rel.wrapper
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
71
|
def each_node(dir, &block)
|
76
72
|
relationships(dir).each do |rel|
|
77
73
|
if rel.start_node == @node
|
@@ -80,31 +76,21 @@ module Neo4j
|
|
80
76
|
block.call rel.start_node
|
81
77
|
end
|
82
78
|
end
|
83
|
-
if @node.persisted?
|
84
|
-
cache_persisted_nodes_and_relationships(dir) if @persisted_related_nodes[dir].nil?
|
85
|
-
@persisted_related_nodes[dir].each {|node| block.call node unless relationship_deleted?(dir,node)}
|
86
|
-
end
|
87
|
-
end
|
88
79
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
@persisted_related_nodes[dir] << end_node
|
95
|
-
@persisted_node_to_relationships[dir][end_node]=rel
|
80
|
+
if @node.persisted?
|
81
|
+
@node._java_node.getRelationships(java_rel_type, dir_to_java(dir)).each do |rel|
|
82
|
+
end_node = rel.getOtherNode(@node._java_node).wrapper
|
83
|
+
block.call(end_node)
|
84
|
+
end
|
96
85
|
end
|
97
86
|
end
|
98
87
|
|
99
|
-
def
|
100
|
-
@persisted_node_to_relationships[dir][node].nil? || !@persisted_node_to_relationships[dir][node].exist?
|
101
|
-
end
|
102
|
-
|
103
|
-
def single_relationship(dir)
|
88
|
+
def single_relationship(dir, raw = false)
|
104
89
|
rel = relationships(dir).first
|
90
|
+
# puts "single_relationship #{dir} for #{self}, got #{rel && rel._java_rel} @node.persisted?=#{@node.persisted?}, #{@node._java_node}"
|
105
91
|
if rel.nil? && @node.persisted?
|
106
92
|
java_rel = @node._java_node.getSingleRelationship(java_rel_type, dir_to_java(dir))
|
107
|
-
java_rel && java_rel.wrapper
|
93
|
+
raw ? java_rel : java_rel && java_rel.wrapper
|
108
94
|
else
|
109
95
|
rel
|
110
96
|
end
|
@@ -115,10 +101,8 @@ module Neo4j
|
|
115
101
|
end
|
116
102
|
|
117
103
|
def single_node(dir)
|
118
|
-
rel = single_relationship(dir)
|
119
|
-
|
120
|
-
other = rel.other_node(@node)
|
121
|
-
other && other.wrapper
|
104
|
+
rel = single_relationship(dir, true)
|
105
|
+
rel && rel.other_node(@node)
|
122
106
|
end
|
123
107
|
|
124
108
|
def destroy_rels(dir, *nodes)
|
@@ -161,7 +145,7 @@ module Neo4j
|
|
161
145
|
out_rels = @outgoing_rels.clone
|
162
146
|
in_rels = @incoming_rels.clone
|
163
147
|
|
164
|
-
[@outgoing_rels, @incoming_rels
|
148
|
+
[@outgoing_rels, @incoming_rels].each{|c| c.clear}
|
165
149
|
|
166
150
|
out_rels.each do |rel|
|
167
151
|
rel.end_node.rm_incoming_rel(@rel_type.to_sym, rel) if rel.end_node
|
@@ -3,19 +3,19 @@ module Neo4j
|
|
3
3
|
# Handle all the created_at, updated_at, created_on, updated_on type stuff.
|
4
4
|
module Timestamps
|
5
5
|
extend ActiveSupport::Concern
|
6
|
-
|
6
|
+
|
7
7
|
TIMESTAMP_PROPERTIES = [ :created_at, :created_on, :updated_at, :updated_on ]
|
8
|
-
|
8
|
+
|
9
9
|
def write_changed_attributes
|
10
10
|
update_timestamp
|
11
11
|
super
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def init_on_create(*args)
|
15
15
|
create_timestamp
|
16
16
|
super
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
# Set the timestamps for this model if timestamps is set to true in the config
|
20
20
|
# and the model is set up with the correct property name, e.g.:
|
21
21
|
#
|
@@ -23,9 +23,9 @@ module Neo4j
|
|
23
23
|
# property :updated_at, :type => DateTime
|
24
24
|
# end
|
25
25
|
def update_timestamp
|
26
|
-
|
26
|
+
#definition provided whenever an :updated_at property is defined
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# Set the timestamps for this model if timestamps is set to true in the config
|
30
30
|
# and the model is set up with the correct property name, e.g.:
|
31
31
|
#
|
@@ -33,9 +33,9 @@ module Neo4j
|
|
33
33
|
# property :created_at, :type => DateTime
|
34
34
|
# end
|
35
35
|
def create_timestamp
|
36
|
-
|
36
|
+
#definition provided whenever an :created_at property is defined
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
# Write the timestamp as a Date, DateTime or Time depending on the property type
|
40
40
|
def write_date_or_timestamp(attribute)
|
41
41
|
value = case self.class._decl_props[attribute][:type].to_s
|
@@ -49,16 +49,25 @@ module Neo4j
|
|
49
49
|
|
50
50
|
send("#{attribute}=", value)
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
module ClassMethods
|
54
54
|
def property_setup(property, options)
|
55
55
|
super
|
56
|
-
|
56
|
+
define_timestamp_method(:create_timestamp,:created_at) if property == :created_at
|
57
|
+
define_timestamp_method(:update_timestamp,:updated_at) if property == :updated_at
|
57
58
|
# ensure there's always a type on the timestamp properties
|
58
59
|
if Neo4j::Config[:timestamps] && TIMESTAMP_PROPERTIES.include?(property)
|
59
60
|
_decl_props[property][:type] ||= Time
|
60
61
|
end
|
61
62
|
end
|
63
|
+
|
64
|
+
def define_timestamp_method(method_name, property)
|
65
|
+
class_eval <<-RUBY, __FILE__, __LINE__
|
66
|
+
def #{method_name}
|
67
|
+
write_date_or_timestamp(:#{property}) if Neo4j::Config[:timestamps]
|
68
|
+
end
|
69
|
+
RUBY
|
70
|
+
end
|
62
71
|
end
|
63
72
|
end
|
64
73
|
end
|
@@ -1,37 +1,76 @@
|
|
1
1
|
module Neo4j
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
2
|
+
module Rails
|
3
|
+
module Validations
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class UniquenessValidator < ActiveModel::EachValidator
|
7
|
+
def initialize(options)
|
8
|
+
super(options.reverse_merge(:case_sensitive => true))
|
9
|
+
@validator = options[:case_sensitive].nil? || options[:case_sensitive] ? ExactMatchValidator : FulltextMatchValidator
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup(klass)
|
13
|
+
@attributes.each do |attribute|
|
14
|
+
if klass.index_type_for(attribute) != @validator.index_type
|
15
|
+
raise index_error_message(klass,attribute,@validator.index_type)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def index_error_message(klass,attribute,index_type)
|
21
|
+
"Can't validate property #{attribute.inspect} on class #{klass} since there is no :#{index_type} lucene index on that property or the index declaration #{attribute} comes after the validation declaration in #{klass} (try to move it before the validation rules)"
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_each(record, attribute, value)
|
25
|
+
return if options[:allow_blank] && value.blank?
|
26
|
+
@validator.query(record.class,attribute,value).each do |rec|
|
22
27
|
if rec.id != record.id # it doesn't count if we find ourself!
|
23
|
-
|
28
|
+
if @validator.match(rec, attribute, value)
|
29
|
+
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
30
|
+
end
|
24
31
|
break
|
25
32
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class ExactMatchValidator
|
38
|
+
def self.index_type
|
39
|
+
:exact
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.query(model,attribute,value)
|
43
|
+
model.all("#{attribute}: \"#{value}\"")
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.match(rec,attribute,value)
|
47
|
+
rec[attribute] == value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class FulltextMatchValidator
|
52
|
+
def self.index_type
|
53
|
+
:fulltext
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.query(model,attribute,value)
|
57
|
+
value.blank? ? model.all("*:* -#{attribute}:[* TO *]", :type => :fulltext) : model.all("#{attribute}: \"#{value}\"", :type => :fulltext)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.match(rec,attribute,value)
|
61
|
+
downcase(rec[attribute]) == downcase(value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.downcase(value)
|
65
|
+
value.nil? ? value : value.strip.downcase
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module ClassMethods
|
70
|
+
def validates_uniqueness_of(*attr_names)
|
71
|
+
validates_with UniquenessValidator, _merge_attributes(attr_names)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
37
76
|
end
|
@@ -24,6 +24,7 @@ module Neo4j
|
|
24
24
|
type, from_node, to_node = args
|
25
25
|
rel = Neo4j::Relationship.create(type, from_node, to_node)
|
26
26
|
wrapped_rel = super()
|
27
|
+
Neo4j::IdentityMap.add(rel, wrapped_rel)
|
27
28
|
wrapped_rel.init_on_load(rel)
|
28
29
|
wrapped_rel.init_on_create(*args)
|
29
30
|
wrapped_rel
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Neo4j
|
2
|
+
# == Represents a set of relationships.
|
3
|
+
# See Neo4j::EventHandler
|
4
|
+
class RelationshipSet
|
5
|
+
def initialize(size=0)
|
6
|
+
@relationship_type_set = java.util.HashSet.new(size)
|
7
|
+
@relationship_set = java.util.HashSet.new(size)
|
8
|
+
@relationship_map = java.util.HashMap.new(size)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Adds a relationship to the set
|
12
|
+
def add(rel)
|
13
|
+
@relationship_type_set.add(RelationshipSetEntry.new(rel.getEndNode().getId(),rel.rel_type))
|
14
|
+
relationships(rel.getEndNode().getId()) << rel
|
15
|
+
@relationship_set.add(rel.getId)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a collection of relationships where the node with the specified end node id is the end node.
|
19
|
+
def relationships(end_node_id)
|
20
|
+
@relationship_map.get(end_node_id) || add_list(end_node_id)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns true if the specified relationship is in the set
|
24
|
+
def contains_rel?(rel)
|
25
|
+
@relationship_set.contains(rel.getId)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if a relationship with the specified end_node_id and relationship_type is present in the set.
|
29
|
+
def contains?(end_node_id,relationship_type)
|
30
|
+
@relationship_type_set.contains(RelationshipSetEntry.new(end_node_id,relationship_type))
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
def add_list(node_id)
|
35
|
+
@relationship_map.put(node_id,[])
|
36
|
+
@relationship_map.get(node_id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class RelationshipSetEntry
|
41
|
+
attr_accessor :nodeid, :relationship_type
|
42
|
+
def initialize(nodeid,relationship_type)
|
43
|
+
@nodeid,@relationship_type = nodeid.to_s, relationship_type.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(o)
|
47
|
+
eql?(o)
|
48
|
+
end
|
49
|
+
|
50
|
+
def eql?(other)
|
51
|
+
@nodeid == other.nodeid && @relationship_type == other.relationship_type
|
52
|
+
end
|
53
|
+
|
54
|
+
def hash
|
55
|
+
3 * @nodeid.hash + @relationship_type.hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -17,7 +17,7 @@ module Neo4j
|
|
17
17
|
Rule.trigger_rules(node, *changes) if Rule.trigger?(node)
|
18
18
|
end
|
19
19
|
|
20
|
-
def on_node_deleted(node, old_properties,
|
20
|
+
def on_node_deleted(node, old_properties, deleted_relationship_set, deleted_identity_map)
|
21
21
|
# have we deleted a rule node ?
|
22
22
|
del_rule_node = Rule.find_rule_node(node)
|
23
23
|
del_rule_node && del_rule_node.clear_rule_node
|
@@ -34,13 +34,11 @@ module Neo4j
|
|
34
34
|
rule_name = rule.rule_name.to_s
|
35
35
|
|
36
36
|
# is the rule node deleted ?
|
37
|
-
deleted_rule_node =
|
37
|
+
deleted_rule_node = deleted_identity_map.get(rule_node.rule_node.neo_id)
|
38
38
|
next if deleted_rule_node
|
39
39
|
|
40
40
|
rule.functions.each do |function|
|
41
|
-
next unless
|
42
|
-
r.getEndNode().getId() == id && r.rel_type == rule_name
|
43
|
-
end
|
41
|
+
next unless deleted_relationship_set.contains?(id,rule_name)
|
44
42
|
previous_value = old_properties[function.function_id]
|
45
43
|
function.delete(rule_name, rule_node.rule_node, previous_value) if previous_value
|
46
44
|
end if rule.functions
|
data/lib/neo4j/rule/rule.rb
CHANGED
@@ -115,16 +115,16 @@ module Neo4j
|
|
115
115
|
rule_node.execute_rules(node, *changes)
|
116
116
|
|
117
117
|
# recursively add relationships for all the parent classes with rules that also pass for this node
|
118
|
-
recursive(node,
|
118
|
+
recursive(node,rule_node.model_class,*changes)
|
119
119
|
end
|
120
120
|
|
121
121
|
private
|
122
122
|
|
123
|
-
def recursive(node,
|
124
|
-
if (clazz =
|
123
|
+
def recursive(node,model_class,*changes)
|
124
|
+
if (clazz = model_class.superclass) && clazz.include?(Neo4j::NodeMixin)
|
125
125
|
rule_node = rule_node_for(clazz)
|
126
126
|
rule_node && rule_node.execute_rules(node, *changes)
|
127
|
-
recursive(node,clazz
|
127
|
+
recursive(node,clazz,*changes)
|
128
128
|
end
|
129
129
|
end
|
130
130
|
end
|
data/lib/neo4j/rule/rule_node.rb
CHANGED
@@ -9,27 +9,28 @@ module Neo4j
|
|
9
9
|
class RuleNode
|
10
10
|
include ToJava
|
11
11
|
attr_reader :rules
|
12
|
+
attr_reader :model_class
|
12
13
|
|
13
14
|
def initialize(clazz)
|
14
|
-
@
|
15
|
-
@
|
15
|
+
@model_class = eval("#{clazz}")
|
16
|
+
@classname = clazz
|
16
17
|
@rules = []
|
17
18
|
@rule_node_key = ("rule_" + clazz.to_s).to_sym
|
18
19
|
@ref_node_key = ("rule_ref_for_" + clazz.to_s).to_sym
|
19
20
|
end
|
20
21
|
|
21
22
|
def to_s
|
22
|
-
"RuleNode #{@
|
23
|
+
"RuleNode #{@classname}, node #{rule_node} #rules: #{@rules.size}"
|
23
24
|
end
|
24
25
|
|
25
26
|
# returns true if the rule node exist yet in the database
|
26
27
|
def node_exist?
|
27
|
-
!ref_node.rel?(@
|
28
|
+
!ref_node.rel?(@classname)
|
28
29
|
end
|
29
30
|
|
30
31
|
def ref_node
|
31
|
-
if @
|
32
|
-
@
|
32
|
+
if @model_class.respond_to? :ref_node_for_class
|
33
|
+
@model_class.ref_node_for_class
|
33
34
|
else
|
34
35
|
Neo4j.ref_node
|
35
36
|
end
|
@@ -38,7 +39,7 @@ module Neo4j
|
|
38
39
|
def create_node
|
39
40
|
Neo4j::Transaction.run do
|
40
41
|
node = Neo4j::Node.new
|
41
|
-
ref_node.create_relationship_to(node, type_to_java(@
|
42
|
+
ref_node.create_relationship_to(node, type_to_java(@classname))
|
42
43
|
node
|
43
44
|
end
|
44
45
|
end
|
@@ -50,14 +51,14 @@ module Neo4j
|
|
50
51
|
end
|
51
52
|
|
52
53
|
def delete_node
|
53
|
-
if ref_node.rel?(@
|
54
|
-
ref_node.outgoing(@
|
54
|
+
if ref_node.rel?(@classname)
|
55
|
+
ref_node.outgoing(@classname).each { |n| n.del }
|
55
56
|
end
|
56
57
|
clear_rule_node
|
57
58
|
end
|
58
59
|
|
59
60
|
def find_node
|
60
|
-
ref_node.rel?(@
|
61
|
+
ref_node.rel?(@classname.to_s) && ref_node._rel(:outgoing, @classname.to_s)._end_node
|
61
62
|
end
|
62
63
|
|
63
64
|
def rule_node
|
@@ -36,7 +36,10 @@ module Neo4j
|
|
36
36
|
#
|
37
37
|
# ==== Examples
|
38
38
|
# # Find all my friends (nodes of depth 1 of type <tt>friends</tt>)
|
39
|
-
# me.outgoing(:friends).each {|friend| puts friend
|
39
|
+
# me.outgoing(:friends).each {|friend| puts friend.name}
|
40
|
+
#
|
41
|
+
# # A possible faster way, avoid loading wrapper Ruby classes, instead use raw java neo4j node objects
|
42
|
+
# me.outgoing(:friends).raw.each {|friend| puts friend[:name]}
|
40
43
|
#
|
41
44
|
# # Find all my friends and their friends (nodes of depth 1 of type <tt>friends</tt>)
|
42
45
|
# # me.outgoing(:friends).depth(2).each {|friend| puts friend[:name]}
|
@@ -194,7 +194,9 @@ module Neo4j
|
|
194
194
|
end
|
195
195
|
|
196
196
|
def size
|
197
|
-
|
197
|
+
s = 0
|
198
|
+
iterator.each { |_| s += 1 }
|
199
|
+
s
|
198
200
|
end
|
199
201
|
|
200
202
|
alias_method :length, :size
|
@@ -208,7 +210,7 @@ module Neo4j
|
|
208
210
|
end
|
209
211
|
|
210
212
|
def each
|
211
|
-
@
|
213
|
+
@raw ? iterator.each { |i| yield i } : iterator.each { |i| yield i.wrapper }
|
212
214
|
end
|
213
215
|
|
214
216
|
# Same as #each but does not wrap each node in a Ruby class, yields the Java Neo4j Node instance instead.
|
@@ -223,10 +225,18 @@ module Neo4j
|
|
223
225
|
self
|
224
226
|
end
|
225
227
|
|
226
|
-
#
|
228
|
+
# If this is called then it will not wrap the nodes but instead return the raw Java Neo4j::Node objects when traversing
|
229
|
+
#
|
230
|
+
def raw
|
231
|
+
@raw = true
|
232
|
+
self
|
233
|
+
end
|
234
|
+
|
235
|
+
# Returns an enumerable of paths instead of nodes
|
227
236
|
#
|
228
237
|
def paths
|
229
238
|
@traversal_result = :paths
|
239
|
+
@raw = true
|
230
240
|
self
|
231
241
|
end
|
232
242
|
|
data/lib/neo4j/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: neo4j
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.2.
|
5
|
+
version: 1.2.5
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- Andreas Ronge
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-21 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -84,6 +84,7 @@ files:
|
|
84
84
|
- lib/generators/neo4j/model/model_generator.rb
|
85
85
|
- lib/generators/neo4j/model/templates/model.erb
|
86
86
|
- lib/orm_adapter/adapters/neo4j.rb
|
87
|
+
- lib/neo4j/identity_map.rb
|
87
88
|
- lib/neo4j/event_handler.rb
|
88
89
|
- lib/neo4j/model.rb
|
89
90
|
- lib/neo4j/config.rb
|
@@ -92,6 +93,7 @@ files:
|
|
92
93
|
- lib/neo4j/node.rb
|
93
94
|
- lib/neo4j/load.rb
|
94
95
|
- lib/neo4j/database.rb
|
96
|
+
- lib/neo4j/relationship_set.rb
|
95
97
|
- lib/neo4j/version.rb
|
96
98
|
- lib/neo4j/equal.rb
|
97
99
|
- lib/neo4j/relationship.rb
|