neo4j 1.2.2-java → 1.2.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 +10 -0
- data/lib/neo4j/has_n/decl_relationship_dsl.rb +7 -4
- data/lib/neo4j/index/indexer.rb +8 -9
- data/lib/neo4j/neo4j.rb +26 -1
- data/lib/neo4j/rails/attributes.rb +1 -0
- data/lib/neo4j/rails/mapping/property.rb +26 -2
- data/lib/neo4j/rails/model.rb +50 -0
- data/lib/neo4j/rails/persistence.rb +18 -17
- data/lib/neo4j/rails/relationships/node_dsl.rb +10 -2
- data/lib/neo4j/rails/relationships/relationships.rb +11 -0
- data/lib/neo4j/rails/relationships/rels_dsl.rb +2 -2
- data/lib/neo4j/rails/relationships/storage.rb +34 -12
- data/lib/neo4j/relationship.rb +51 -2
- data/lib/neo4j/rule/class_methods.rb +19 -1
- data/lib/neo4j/rule/rule_node.rb +33 -9
- data/lib/neo4j/version.rb +1 -1
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 1.2.3 / 2011-10-01
|
2
|
+
* Multitenancy support by namespaced-indices & changeable reference node (Vivek Prahlad, pull 41)
|
3
|
+
* Added a Neo4j::Rails::Model#columns which returns all defined properties [#186]
|
4
|
+
* Fixed validation associated entities, parent model should be invalid if its nested model(s) is invalid (Vivek Prahlad)
|
5
|
+
* Fixed property validation to read value before conversion as per active model conventions (Deepak N)
|
6
|
+
* Fixed property_before_type_cast for loaded models (Deepak N)
|
7
|
+
* Better support for nested models via ActionView field_for [#185]
|
8
|
+
* BUG: fix for null pointer issue after delete_all on Neo4j::Rails::Model#has_n relationships (Vivek Prahlad)
|
9
|
+
* BUG: init_on_create was not called when creating a new relationship via the << operator [#183]
|
10
|
+
|
1
11
|
== 1.2.2 / 2011-09-15
|
2
12
|
* Added compositions support for rails mode (Deepak N)
|
3
13
|
* Added support for nested transactions at the Rails model level (Vivek Prahlad)
|
@@ -99,9 +99,12 @@ module Neo4j
|
|
99
99
|
|
100
100
|
def create_relationship_to(node, other) # :nodoc:
|
101
101
|
from, to = incoming? ? [other, node] : [node, other]
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
|
103
|
+
if relationship_class
|
104
|
+
relationship_class.new(@rel_type, from._java_node, to._java_node)
|
105
|
+
else
|
106
|
+
from._java_node.create_relationship_to(to._java_node, java_rel_type)
|
107
|
+
end
|
105
108
|
end
|
106
109
|
|
107
110
|
# Specifies an outgoing relationship.
|
@@ -232,7 +235,7 @@ module Neo4j
|
|
232
235
|
end
|
233
236
|
|
234
237
|
def relationship_class # :nodoc:
|
235
|
-
@relationship
|
238
|
+
@relationship
|
236
239
|
end
|
237
240
|
end
|
238
241
|
end
|
data/lib/neo4j/index/indexer.rb
CHANGED
@@ -91,7 +91,7 @@ module Neo4j
|
|
91
91
|
|
92
92
|
field = field.to_s
|
93
93
|
@via_relationships[field] = rel_dsl
|
94
|
-
via_indexer.index(field, conf_no_via)
|
94
|
+
via_indexer.index(field, conf_no_via)
|
95
95
|
else
|
96
96
|
@field_types[field.to_s] = conf[:type] || :exact
|
97
97
|
end
|
@@ -226,7 +226,7 @@ module Neo4j
|
|
226
226
|
# (by Rack).
|
227
227
|
#
|
228
228
|
# === Example, with a block
|
229
|
-
#
|
229
|
+
#
|
230
230
|
# Person.find('name: kalle') {|query| puts "#{[*query].join(', )"}
|
231
231
|
#
|
232
232
|
# ==== Example
|
@@ -293,11 +293,11 @@ module Neo4j
|
|
293
293
|
|
294
294
|
def index_for_field(field) #:nodoc:
|
295
295
|
type = @field_types[field]
|
296
|
-
|
296
|
+
create_index_with(type)
|
297
297
|
end
|
298
298
|
|
299
299
|
def index_for_type(type) #:nodoc:
|
300
|
-
|
300
|
+
create_index_with(type)
|
301
301
|
end
|
302
302
|
|
303
303
|
def lucene_config(type) #:nodoc:
|
@@ -317,12 +317,11 @@ module Neo4j
|
|
317
317
|
end
|
318
318
|
|
319
319
|
def index_names
|
320
|
-
|
321
|
-
|
320
|
+
@index_names ||= Hash.new do |hash,index_type|
|
321
|
+
default_filename = Neo4j.index_prefix + @indexer_for.to_s.gsub('::', '_')
|
322
|
+
hash.fetch(index_type) {"#{default_filename}-#{index_type}"}
|
323
|
+
end
|
322
324
|
end
|
323
|
-
|
324
325
|
end
|
325
|
-
|
326
326
|
end
|
327
|
-
|
328
327
|
end
|
data/lib/neo4j/neo4j.rb
CHANGED
@@ -125,13 +125,38 @@ module Neo4j
|
|
125
125
|
this_db.shutdown if this_db
|
126
126
|
end
|
127
127
|
|
128
|
+
|
129
|
+
# Returns the default reference node, which is a "starting point" in the node space.
|
130
|
+
#
|
131
|
+
def default_ref_node(this_db = self.started_db)
|
132
|
+
this_db.graph.reference_node
|
133
|
+
end
|
134
|
+
|
128
135
|
# Returns the reference node, which is a "starting point" in the node space.
|
136
|
+
# In case the ref_node has been assigned via the threadlocal_ref_node method, then that node will be returned instead.
|
129
137
|
#
|
130
138
|
# Usually, a client attaches relationships to this node that leads into various parts of the node space.
|
131
139
|
# For more information about common node space organizational patterns, see the design guide at http://wiki.neo4j.org/content/Design_Guide
|
132
140
|
#
|
133
141
|
def ref_node(this_db = self.started_db)
|
134
|
-
|
142
|
+
return Thread.current[:local_ref_node] if Thread.current[:local_ref_node]
|
143
|
+
default_ref_node(this_db)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Changes the reference node on a threadlocal basis.
|
147
|
+
# This can be used to achieve multitenancy. All new entities will be attached to the new ref_node,
|
148
|
+
# which effectively partitions the graph, and hence scopes traversals.
|
149
|
+
def threadlocal_ref_node=(reference_node)
|
150
|
+
Thread.current[:local_ref_node] = reference_node.nil? ? nil : reference_node._java_node
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns a prefix for lucene indices based on the name property of the current reference node.
|
154
|
+
# This allows the index names to be prefixed by the reference node name, and hence scopes lucene indexes
|
155
|
+
# to all entities under the current reference node.
|
156
|
+
def index_prefix
|
157
|
+
return "" if not running?
|
158
|
+
ref_node_name = ref_node[:name]
|
159
|
+
ref_node_name.nil? || ref_node_name.empty? ? "" : ref_node_name + "_"
|
135
160
|
end
|
136
161
|
|
137
162
|
# Returns a Management JMX Bean.
|
@@ -244,6 +244,7 @@ module Neo4j
|
|
244
244
|
|
245
245
|
# Wrap the setter in a conversion from Ruby to Java
|
246
246
|
def write_local_property_with_type_conversion(property, value)
|
247
|
+
self.send("#{property}_before_type_cast=", value) if respond_to?("#{property}_before_type_cast=")
|
247
248
|
write_local_property_without_type_conversion(property, Neo4j::TypeConverters.to_java(self.class, property, value))
|
248
249
|
end
|
249
250
|
end
|
@@ -6,18 +6,30 @@ module Neo4j
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
|
9
|
+
# Create two new methods: rel_name and rel_name_rels
|
10
|
+
# The first one returns an Neo4j::Rails::Relationships::NodesDSL
|
11
|
+
# the second generate method (with the _rels postfix) returns a
|
12
|
+
# Neo4j::Rails::Relationships::RelsDSL
|
13
|
+
#
|
14
|
+
# See also Neo4j::NodeMixin#has_n which only work with persisted relationships.
|
15
|
+
#
|
9
16
|
def has_n(*args)
|
10
17
|
options = args.extract_options!
|
11
18
|
define_has_n_methods_for(args.first, options)
|
12
19
|
end
|
13
20
|
|
21
|
+
# See #has_n
|
14
22
|
def has_one(*args)
|
15
23
|
options = args.extract_options!
|
16
24
|
define_has_one_methods_for(args.first, options)
|
17
25
|
end
|
18
26
|
|
27
|
+
# Returns all defined properties
|
28
|
+
def columns
|
29
|
+
self._decl_props.keys
|
30
|
+
end
|
19
31
|
|
20
|
-
def define_has_one_methods_for(rel_type, options)
|
32
|
+
def define_has_one_methods_for(rel_type, options) #:nodoc:
|
21
33
|
unless method_defined?(rel_type)
|
22
34
|
class_eval <<-RUBY, __FILE__, __LINE__
|
23
35
|
def #{rel_type}
|
@@ -52,7 +64,7 @@ module Neo4j
|
|
52
64
|
_decl_rels[rel_type.to_sym] = Neo4j::HasN::DeclRelationshipDsl.new(rel_type, true, self)
|
53
65
|
end
|
54
66
|
|
55
|
-
def define_has_n_methods_for(rel_type, options)
|
67
|
+
def define_has_n_methods_for(rel_type, options) #:nodoc:
|
56
68
|
unless method_defined?(rel_type)
|
57
69
|
class_eval <<-RUBY, __FILE__, __LINE__
|
58
70
|
def #{rel_type}
|
@@ -100,6 +112,7 @@ module Neo4j
|
|
100
112
|
_decl_props[property] = options
|
101
113
|
handle_property_options_for(property, options)
|
102
114
|
define_property_methods_for(property, options)
|
115
|
+
define_property_before_type_cast_methods_for(property, options)
|
103
116
|
end
|
104
117
|
|
105
118
|
def handle_property_options_for(property, options)
|
@@ -129,6 +142,17 @@ module Neo4j
|
|
129
142
|
RUBY
|
130
143
|
end
|
131
144
|
end
|
145
|
+
|
146
|
+
def define_property_before_type_cast_methods_for(property, options)
|
147
|
+
property_before_type_cast = "#{property}_before_type_cast"
|
148
|
+
class_eval <<-RUBY, __FILE__, __LINE__
|
149
|
+
attr_writer :#{property_before_type_cast}
|
150
|
+
|
151
|
+
def #{property_before_type_cast}
|
152
|
+
instance_variable_defined?(:@#{property_before_type_cast}) ? @#{property_before_type_cast} : self.#{property}
|
153
|
+
end
|
154
|
+
RUBY
|
155
|
+
end
|
132
156
|
end
|
133
157
|
end
|
134
158
|
end
|
data/lib/neo4j/rails/model.rb
CHANGED
@@ -5,6 +5,21 @@ module Neo4j
|
|
5
5
|
# That means for example that you don't have to care about transactions since they will be
|
6
6
|
# automatically be created when needed.
|
7
7
|
#
|
8
|
+
# ==== Included Mixins
|
9
|
+
#
|
10
|
+
# * Neo4j::Rails::Persistence :: handles how to save, create and update the model
|
11
|
+
# * Neo4j::Rails::Attributes :: handles how to save and retrieve attributes
|
12
|
+
# * Neo4j::Rails::Mapping::Property :: allows some additional options on the #property class method
|
13
|
+
# * Neo4j::Rails::Serialization :: enable to_xml and to_json
|
14
|
+
# * Neo4j::Rails::Timestamps :: handle created_at, updated_at timestamp properties
|
15
|
+
# * Neo4j::Rails::Validations :: enable validations
|
16
|
+
# * Neo4j::Rails::Callbacks :: enable callbacks
|
17
|
+
# * Neo4j::Rails::Finders :: ActiveRecord style find
|
18
|
+
# * Neo4j::Rails::Relationships :: handles persisted and none persisted relationships.
|
19
|
+
# * Neo4j::Rails::Compositions :: see Neo4j::Rails::Compositions::ClassMethods, similar to http://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html
|
20
|
+
# * ActiveModel::Observing # enable observers, see Rails documentation.
|
21
|
+
# * ActiveModel::Translation - class mixin
|
22
|
+
#
|
8
23
|
# ==== Traversals
|
9
24
|
# This class only expose a limited set of traversals.
|
10
25
|
# If you want to access the raw java node to do traversals use the _java_node.
|
@@ -19,6 +34,13 @@ module Neo4j
|
|
19
34
|
#
|
20
35
|
# The has_n and has_one relationship accessors returns objects of type Neo4j::Rails::Relationships::RelsDSL
|
21
36
|
# and Neo4j::Rails::Relationships::NodesDSL which behaves more like the Active Record relationships.
|
37
|
+
# Notice that unlike Neo4j::NodeMixin new relationships are kept in memory until @save@ is called.
|
38
|
+
#
|
39
|
+
# ==== Callbacks
|
40
|
+
#
|
41
|
+
# The following callbacks are supported :validation, :create, :destroy, :save, :update.
|
42
|
+
# It works with before, after and around callbacks, see the Rails documentation.
|
43
|
+
# Notice you can also do callbacks using the Neo4j::Rails::Callbacks module (check the Rails documentation)
|
22
44
|
#
|
23
45
|
class Model
|
24
46
|
include Neo4j::NodeMixin
|
@@ -69,6 +91,34 @@ module Neo4j
|
|
69
91
|
new? ? self.__id__ == other.__id__ : @_java_node == (other)
|
70
92
|
end
|
71
93
|
|
94
|
+
##
|
95
|
+
# :singleton-method: property
|
96
|
+
#
|
97
|
+
# See Neo4j::Rails::Mapping::Property::ClassMethods#property
|
98
|
+
|
99
|
+
##
|
100
|
+
# :singleton-method: has_one
|
101
|
+
#
|
102
|
+
# Generates a has_one methods which returns an object of type Neo4j::Rails::Relationships::NodesDSL
|
103
|
+
# and a has_one method postfixed @_rel@ which return a Neo4j::Rails::Relationships::RelsDSL
|
104
|
+
#
|
105
|
+
# See also Neo4j::Rails::Mapping::Property::ClassMethods#has_one
|
106
|
+
#
|
107
|
+
|
108
|
+
##
|
109
|
+
# :singleton-method: columns
|
110
|
+
#
|
111
|
+
# Returns all defined properties as an array
|
112
|
+
|
113
|
+
##
|
114
|
+
# :singleton-method: has_n
|
115
|
+
#
|
116
|
+
# Generates a has_n method which returns an object of type Neo4j::Rails::Relationships::NodesDSL
|
117
|
+
# and a has_n method postfixed @_rel@ which return a Neo4j::Rails::Relationships::RelsDSL
|
118
|
+
#
|
119
|
+
# See also Neo4j::Rails::Mapping::Property::ClassMethods#has_n
|
120
|
+
#
|
121
|
+
|
72
122
|
|
73
123
|
# --------------------------------------
|
74
124
|
# Public Class Methods
|
@@ -2,7 +2,7 @@ module Neo4j
|
|
2
2
|
module Rails
|
3
3
|
module Persistence
|
4
4
|
extend ActiveSupport::Concern
|
5
|
-
|
5
|
+
|
6
6
|
included do
|
7
7
|
extend TxMethods
|
8
8
|
tx_methods :destroy, :create, :update, :update_nested_attributes, :delete
|
@@ -14,7 +14,7 @@ module Neo4j
|
|
14
14
|
def save(*)
|
15
15
|
create_or_update
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
# Persist the object to the database. Validations and Callbacks are included
|
19
19
|
# by default but validation can be disabled by passing :validate => false
|
20
20
|
# to #save!.
|
@@ -25,7 +25,7 @@ module Neo4j
|
|
25
25
|
raise RecordInvalidError.new(self)
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# Updates a single attribute and saves the record.
|
30
30
|
# This is especially useful for boolean flags on existing records. Also note that
|
31
31
|
#
|
@@ -37,25 +37,25 @@ module Neo4j
|
|
37
37
|
respond_to?("#{name}=") ? send("#{name}=", value) : self[name] = value
|
38
38
|
save(:validate => false)
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
# Removes the node from Neo4j and freezes the object.
|
42
42
|
def destroy
|
43
43
|
delete
|
44
44
|
freeze
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
# Same as #destroy but doesn't run destroy callbacks and doesn't freeze
|
48
48
|
# the object
|
49
49
|
def delete
|
50
50
|
del unless new_record?
|
51
51
|
set_deleted_properties
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
# Returns true if the object was destroyed.
|
55
55
|
def destroyed?()
|
56
56
|
@_deleted || Neo4j::Node._load(id).nil?
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved.
|
60
60
|
# If saving fails because the resource is invalid then false will be returned.
|
61
61
|
def update_attributes(attributes)
|
@@ -68,7 +68,7 @@ module Neo4j
|
|
68
68
|
self.attributes = attributes
|
69
69
|
save!
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
# Reload the object from the DB.
|
73
73
|
def reload(options = nil)
|
74
74
|
clear_changes
|
@@ -86,14 +86,14 @@ module Neo4j
|
|
86
86
|
def persisted?
|
87
87
|
!new_record? && !destroyed?
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
# Returns true if the record hasn't been saved to Neo4j yet.
|
91
91
|
def new_record?
|
92
92
|
_java_node.nil?
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
alias :new? :new_record?
|
96
|
-
|
96
|
+
|
97
97
|
# Freeze the properties hash.
|
98
98
|
def freeze
|
99
99
|
@properties.freeze; self
|
@@ -197,12 +197,12 @@ module Neo4j
|
|
197
197
|
write_attribute(attribute, value) if changed_attributes.has_key?(attribute)
|
198
198
|
end
|
199
199
|
end
|
200
|
-
|
200
|
+
|
201
201
|
def _create_entity(rel_type, attr)
|
202
202
|
clazz = self.class._decl_rels[rel_type.to_sym].target_class
|
203
203
|
_add_relationship(rel_type, clazz.new(attr))
|
204
204
|
end
|
205
|
-
|
205
|
+
|
206
206
|
def _add_relationship(rel_type, node)
|
207
207
|
if respond_to?("#{rel_type}=")
|
208
208
|
send("#{rel_type}=", node)
|
@@ -215,6 +215,7 @@ module Neo4j
|
|
215
215
|
end
|
216
216
|
|
217
217
|
def _find_node(rel_type, id)
|
218
|
+
return nil if id.nil?
|
218
219
|
if respond_to?("#{rel_type}=")
|
219
220
|
send("#{rel_type}")
|
220
221
|
elsif respond_to?("#{rel_type}")
|
@@ -224,7 +225,7 @@ module Neo4j
|
|
224
225
|
raise "oops #{rel_type}"
|
225
226
|
end
|
226
227
|
end
|
227
|
-
|
228
|
+
|
228
229
|
def _has_relationship(rel_type, id)
|
229
230
|
!_find_node(rel_type,id).nil?
|
230
231
|
end
|
@@ -234,7 +235,7 @@ module Neo4j
|
|
234
235
|
begin
|
235
236
|
# Check if we want to destroy not found nodes (e.g. {..., :_destroy => '1' } ?
|
236
237
|
destroy = allow_destroy && attr[:_destroy] && attr[:_destroy] != '0'
|
237
|
-
found = Neo4j::Node.load(attr[:id])
|
238
|
+
found = _find_node(rel_type, attr[:id]) || Neo4j::Node.load(attr[:id])
|
238
239
|
if destroy
|
239
240
|
found.destroy if found
|
240
241
|
else
|
@@ -242,8 +243,8 @@ module Neo4j
|
|
242
243
|
_create_entity(rel_type, attr) #Create new node from scratch
|
243
244
|
else
|
244
245
|
#Create relationship to existing node in case it doesn't exist already
|
245
|
-
_add_relationship(rel_type, found) if (not _has_relationship(rel_type,attr[:id]))
|
246
|
-
found.update_attributes(attr)
|
246
|
+
_add_relationship(rel_type, found) if (not _has_relationship(rel_type,attr[:id]))
|
247
|
+
found.update_attributes(attr)
|
247
248
|
end
|
248
249
|
end
|
249
250
|
end unless reject_if?(reject_if, attr)
|
@@ -29,13 +29,13 @@ module Neo4j
|
|
29
29
|
# Person.friends.build(:name => 'kalle') # creates a Person and Friends class.
|
30
30
|
# Person.knows.build(:name => 'kalle') # creates a Neo4j::Rails::Model and Neo4j::Rails::Relationship class
|
31
31
|
#
|
32
|
-
def build(attrs)
|
32
|
+
def build(attrs = {})
|
33
33
|
self << (node = @storage.build(attrs))
|
34
34
|
node
|
35
35
|
end
|
36
36
|
|
37
37
|
# Same as #build except that the relationship and node are saved.
|
38
|
-
def create(attrs)
|
38
|
+
def create(attrs = {})
|
39
39
|
self << (node = @storage.create(attrs))
|
40
40
|
node.save
|
41
41
|
node
|
@@ -54,6 +54,14 @@ module Neo4j
|
|
54
54
|
self
|
55
55
|
end
|
56
56
|
|
57
|
+
def persisted?
|
58
|
+
@storage.persisted?
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_ary
|
62
|
+
all.to_a
|
63
|
+
end
|
64
|
+
|
57
65
|
# Specifies the depth of the traversal
|
58
66
|
def depth(d)
|
59
67
|
adapt_to_traverser.depth(d)
|
@@ -45,7 +45,18 @@ module Neo4j
|
|
45
45
|
end
|
46
46
|
|
47
47
|
# See Neo4j::Rels#rels.
|
48
|
+
#
|
48
49
|
# Will also allow to access unsaved relationships - like the #outgoing and #incoming method.
|
50
|
+
# It one argument - the relationship type.
|
51
|
+
#
|
52
|
+
# To only find all the persisted relationship, node._java_node.rels
|
53
|
+
#
|
54
|
+
# === Example
|
55
|
+
#
|
56
|
+
# node.outgoing(:foo) << node2
|
57
|
+
# node.rels(:foo).outgoing #=> [node2]
|
58
|
+
# node.rels(:foo).incoming #=> []
|
59
|
+
# node.rels(:foo) #=> [node2] - incoming and outgoing
|
49
60
|
#
|
50
61
|
def rels(*rel_types)
|
51
62
|
storage = _create_or_get_storage(rel_types.first)
|
@@ -27,14 +27,14 @@ module Neo4j
|
|
27
27
|
|
28
28
|
# Same as Neo4j::Rails::Relationships::NodesDSL#build except that you specify the properties of the
|
29
29
|
# relationships and it returns a relationship
|
30
|
-
def build(attrs)
|
30
|
+
def build(attrs = {})
|
31
31
|
node = @storage.build(attrs)
|
32
32
|
@storage.create_relationship_to(node, @dir)
|
33
33
|
end
|
34
34
|
|
35
35
|
# Same as Neo4j::Rails::Relationships::NodesDSL#create except that you specify the properties of the
|
36
36
|
# relationships and it returns a relationship
|
37
|
-
def create(attrs)
|
37
|
+
def create(attrs = {})
|
38
38
|
node = @storage.create(attrs)
|
39
39
|
rel = @storage.create_relationship_to(node, @dir)
|
40
40
|
node.save
|
@@ -14,6 +14,9 @@ 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 = {}
|
17
20
|
end
|
18
21
|
|
19
22
|
def to_s #:nodoc:
|
@@ -55,14 +58,19 @@ module Neo4j
|
|
55
58
|
end
|
56
59
|
|
57
60
|
def each_rel(dir, &block) #:nodoc:
|
58
|
-
relationships(dir).each { |rel| block.call rel }
|
59
|
-
|
61
|
+
relationships(dir).each { |rel| block.call rel }
|
60
62
|
if @node.persisted?
|
61
|
-
|
62
|
-
|
63
|
-
end
|
63
|
+
cache_relationships(dir) if @persisted_relationships[dir].nil?
|
64
|
+
@persisted_relationships[dir].each {|rel| block.call rel unless !rel.exist?}
|
64
65
|
end
|
65
66
|
end
|
67
|
+
|
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
|
66
74
|
|
67
75
|
def each_node(dir, &block)
|
68
76
|
relationships(dir).each do |rel|
|
@@ -72,14 +80,26 @@ module Neo4j
|
|
72
80
|
block.call rel.start_node
|
73
81
|
end
|
74
82
|
end
|
75
|
-
|
76
83
|
if @node.persisted?
|
77
|
-
|
78
|
-
|
79
|
-
end
|
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)}
|
80
86
|
end
|
81
87
|
end
|
82
88
|
|
89
|
+
def cache_persisted_nodes_and_relationships(dir)
|
90
|
+
@persisted_related_nodes[dir] ||= []
|
91
|
+
@persisted_node_to_relationships[dir] ||= {}
|
92
|
+
@node._java_node.getRelationships(java_rel_type, dir_to_java(dir)).each do |rel|
|
93
|
+
end_node = rel.getOtherNode(@node._java_node).wrapper
|
94
|
+
@persisted_related_nodes[dir] << end_node
|
95
|
+
@persisted_node_to_relationships[dir][end_node]=rel
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def relationship_deleted?(dir,node)
|
100
|
+
@persisted_node_to_relationships[dir][node].nil? || !@persisted_node_to_relationships[dir][node].exist?
|
101
|
+
end
|
102
|
+
|
83
103
|
def single_relationship(dir)
|
84
104
|
rel = relationships(dir).first
|
85
105
|
if rel.nil? && @node.persisted?
|
@@ -133,12 +153,15 @@ module Neo4j
|
|
133
153
|
@outgoing_rels.delete(rel)
|
134
154
|
end
|
135
155
|
|
156
|
+
def persisted?
|
157
|
+
@outgoing_rels.empty? && @incoming_rels.empty?
|
158
|
+
end
|
159
|
+
|
136
160
|
def persist
|
137
161
|
out_rels = @outgoing_rels.clone
|
138
162
|
in_rels = @incoming_rels.clone
|
139
163
|
|
140
|
-
@outgoing_rels.clear
|
141
|
-
@incoming_rels.clear
|
164
|
+
[@outgoing_rels, @incoming_rels, @persisted_related_nodes, @persisted_node_to_relationships, @persisted_relationships].each{|c| c.clear}
|
142
165
|
|
143
166
|
out_rels.each do |rel|
|
144
167
|
rel.end_node.rm_incoming_rel(@rel_type.to_sym, rel) if rel.end_node
|
@@ -154,7 +177,6 @@ module Neo4j
|
|
154
177
|
raise "Can't save incoming #{rel}, validation errors ? #{rel.errors.inspect}" unless success
|
155
178
|
end
|
156
179
|
end
|
157
|
-
|
158
180
|
end
|
159
181
|
end
|
160
182
|
end
|
data/lib/neo4j/relationship.rb
CHANGED
@@ -66,7 +66,7 @@ module Neo4j
|
|
66
66
|
|
67
67
|
# Returns the relationship name
|
68
68
|
#
|
69
|
-
# ====Example
|
69
|
+
# ==== Example
|
70
70
|
# a = Neo4j::Node.new
|
71
71
|
# a.outgoing(:friends) << Neo4j::Node.new
|
72
72
|
# a.rels.first.rel_type # => 'friends'
|
@@ -106,7 +106,14 @@ module Neo4j
|
|
106
106
|
# Furthermore, Neo4j guarantees that a relationship is never "hanging freely,"
|
107
107
|
# i.e. start_node, end_node and other_node are guaranteed to always return valid, non-null nodes.
|
108
108
|
#
|
109
|
-
#
|
109
|
+
# === Wrapping
|
110
|
+
#
|
111
|
+
# Notice that the Neo4j::Relationship.new does not create a Ruby object. Instead, it returns a Java
|
112
|
+
# org.neo4j.graphdb.Relationship object which has been modified to feel more rubyish (like Neo4j::Node).
|
113
|
+
#
|
114
|
+
# === See also
|
115
|
+
# * Neo4j::RelationshipMixin if you want to wrap a relationship with your own Ruby class.
|
116
|
+
# * http://api.neo4j.org/1.4/org/neo4j/graphdb/Relationship.html
|
110
117
|
#
|
111
118
|
# === Included Mixins
|
112
119
|
# * Neo4j::Property
|
@@ -124,6 +131,48 @@ module Neo4j
|
|
124
131
|
include Neo4j::ToJava
|
125
132
|
|
126
133
|
|
134
|
+
##
|
135
|
+
# :method: start_node
|
136
|
+
#
|
137
|
+
# Returns the start node of this relationship
|
138
|
+
|
139
|
+
|
140
|
+
##
|
141
|
+
# :method: end_node
|
142
|
+
#
|
143
|
+
# Returns the start node of this relationship
|
144
|
+
|
145
|
+
##
|
146
|
+
# :method: other_node
|
147
|
+
#
|
148
|
+
# A convenience operation that, given a node that is attached to this relationship, returns the other node.
|
149
|
+
# For example if node is a start node, the end node will be returned, and vice versa.
|
150
|
+
# This is a very convenient operation when you're manually traversing the node space by invoking one of the #rels
|
151
|
+
# method on a node. For example, to get the node "at the other end" of a relationship, use the following:
|
152
|
+
#
|
153
|
+
# end_node = node.rels.first.other_node(node)
|
154
|
+
#
|
155
|
+
# This operation will throw a runtime exception if node is neither this relationship's start node nor its end node.
|
156
|
+
#
|
157
|
+
# === Parameters
|
158
|
+
#
|
159
|
+
# node :: the node that we don't want to return
|
160
|
+
|
161
|
+
|
162
|
+
##
|
163
|
+
# :method: del
|
164
|
+
#
|
165
|
+
# Deletes this relationship. Invoking any methods on this relationship after delete() has returned is invalid and will lead t
|
166
|
+
|
167
|
+
# :method rel_type
|
168
|
+
#
|
169
|
+
# Returns the type of this relationship.
|
170
|
+
# A relationship's type is an immutable attribute that is specified at Relationship creation.
|
171
|
+
# The relationship type is othen used when traversing nodes, example finding all the
|
172
|
+
# outgoing nodes of relationship type :friends
|
173
|
+
#
|
174
|
+
# node.outgoing(:friends)
|
175
|
+
|
127
176
|
# Returns a org.neo4j.graphdb.Relationship java object (!)
|
128
177
|
# Will trigger a event that the relationship was created.
|
129
178
|
#
|
@@ -79,7 +79,7 @@ module Neo4j
|
|
79
79
|
#
|
80
80
|
# Example of usage:
|
81
81
|
# class Person
|
82
|
-
# include Neo4j
|
82
|
+
# include Neo4j::NodeMixin
|
83
83
|
# property :age
|
84
84
|
# rule :all
|
85
85
|
# rule :young { self[:age] < 10 }
|
@@ -123,6 +123,24 @@ module Neo4j
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
def ref_node_for_class
|
127
|
+
Neo4j.ref_node #The reference node for a type falls back to the threadlocal ref node by default.
|
128
|
+
end
|
129
|
+
|
130
|
+
# Assigns the reference node for a class via a supplied block.
|
131
|
+
# Example of usage:
|
132
|
+
# class Person
|
133
|
+
# include Neo4j::NodeMixin
|
134
|
+
# ref_node { Neo4j.default_ref_node }
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
def ref_node(&block)
|
138
|
+
singleton = class << self;
|
139
|
+
self;
|
140
|
+
end
|
141
|
+
singleton.send(:define_method, :ref_node_for_class) { block.call }
|
142
|
+
end
|
143
|
+
|
126
144
|
def inherit_rules_from(clazz)
|
127
145
|
Rule.inherit(clazz, self)
|
128
146
|
end
|
data/lib/neo4j/rule/rule_node.rb
CHANGED
@@ -11,8 +11,10 @@ module Neo4j
|
|
11
11
|
attr_reader :rules
|
12
12
|
|
13
13
|
def initialize(clazz)
|
14
|
+
@type = eval("#{clazz}")
|
14
15
|
@clazz = clazz
|
15
16
|
@rules = []
|
17
|
+
@rule_node_key = ("rule_" + clazz.to_s).to_sym
|
16
18
|
end
|
17
19
|
|
18
20
|
def to_s
|
@@ -21,13 +23,21 @@ module Neo4j
|
|
21
23
|
|
22
24
|
# returns true if the rule node exist yet in the database
|
23
25
|
def node_exist?
|
24
|
-
!
|
26
|
+
!ref_node.rel?(@clazz)
|
27
|
+
end
|
28
|
+
|
29
|
+
def ref_node
|
30
|
+
if @type.respond_to? :ref_node_for_class
|
31
|
+
@type.ref_node_for_class
|
32
|
+
else
|
33
|
+
Neo4j.ref_node
|
34
|
+
end
|
25
35
|
end
|
26
36
|
|
27
37
|
def create_node
|
28
38
|
Neo4j::Transaction.run do
|
29
39
|
node = Neo4j::Node.new
|
30
|
-
|
40
|
+
ref_node.create_relationship_to(node, type_to_java(@clazz))
|
31
41
|
node
|
32
42
|
end
|
33
43
|
end
|
@@ -39,31 +49,45 @@ module Neo4j
|
|
39
49
|
end
|
40
50
|
|
41
51
|
def delete_node
|
42
|
-
if
|
43
|
-
|
52
|
+
if ref_node.rel?(@clazz)
|
53
|
+
ref_node.outgoing(@clazz).each { |n| n.del }
|
44
54
|
end
|
45
55
|
clear_rule_node
|
46
56
|
end
|
47
57
|
|
48
58
|
def find_node
|
49
|
-
|
59
|
+
ref_node.rel?(@clazz.to_s) && ref_node._rel(:outgoing, @clazz.to_s)._end_node
|
50
60
|
end
|
51
61
|
|
52
62
|
def on_neo4j_started
|
53
63
|
# initialize the rule node when neo4j starts
|
54
|
-
@
|
64
|
+
Thread.current[@rule_node_key] = find_node || create_node
|
55
65
|
end
|
56
66
|
|
57
67
|
def rule_node
|
58
|
-
|
68
|
+
clear_rule_node if ref_node_changed?
|
69
|
+
Thread.current[@rule_node_key] ||= find_node || create_node
|
70
|
+
end
|
71
|
+
|
72
|
+
def ref_node_changed?
|
73
|
+
if ref_node != Thread.current[:rule_cached_ref_node]
|
74
|
+
Thread.current[:rule_cached_ref_node] = ref_node
|
75
|
+
true
|
76
|
+
else
|
77
|
+
false
|
78
|
+
end
|
59
79
|
end
|
60
80
|
|
61
81
|
def rule_node?(node)
|
62
|
-
|
82
|
+
cached_rule_node == node
|
83
|
+
end
|
84
|
+
|
85
|
+
def cached_rule_node
|
86
|
+
Thread.current[@rule_node_key]
|
63
87
|
end
|
64
88
|
|
65
89
|
def clear_rule_node
|
66
|
-
@
|
90
|
+
Thread.current[@rule_node_key] = nil
|
67
91
|
end
|
68
92
|
|
69
93
|
def rule_names
|
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.3
|
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-
|
13
|
+
date: 2011-10-01 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|