neo4j 1.2.4-java → 1.2.5-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 +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
|