neo4j 1.2.2-java → 1.2.3-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|