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 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
- rel = from._java_node.create_relationship_to(to._java_node, java_rel_type)
103
- rel[:_classname] = relationship_class.to_s if relationship_class
104
- rel.wrapper
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
@@ -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
- @indexes[type] ||= create_index_with(type)
296
+ create_index_with(type)
297
297
  end
298
298
 
299
299
  def index_for_type(type) #:nodoc:
300
- @indexes[type] ||= create_index_with(type)
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
- default_filename = @indexer_for.to_s.gsub('::', '_')
321
- @index_names ||= Hash.new{|hash,index_type| hash[index_type] = "#{default_filename}-#{index_type}"}
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
- this_db.graph.reference_node
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
@@ -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
- node._java_node.getRelationships(java_rel_type, dir_to_java(dir)).each do |rel|
62
- block.call rel.wrapper
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
- @node._java_node.getRelationships(java_rel_type, dir_to_java(dir)).each do |rel|
78
- block.call rel.getOtherNode(@node._java_node).wrapper
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
@@ -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
- # See also the Neo4j::RelationshipMixin if you want to wrap a relationship with your own Ruby class.
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
@@ -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
- !Neo4j.ref_node.rel?(@clazz)
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
- Neo4j.ref_node.create_relationship_to(node, type_to_java(@clazz))
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 Neo4j.ref_node.rel?(@clazz)
43
- Neo4j.ref_node.outgoing(@clazz).each { |n| n.del }
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
- Neo4j.ref_node.rel?(@clazz.to_s) && Neo4j.ref_node._rel(:outgoing, @clazz.to_s)._end_node
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
- @rule_node = find_node || create_node
64
+ Thread.current[@rule_node_key] = find_node || create_node
55
65
  end
56
66
 
57
67
  def rule_node
58
- @rule_node ||= find_node || create_node
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
- @rule_node == node
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
- @rule_node = nil
90
+ Thread.current[@rule_node_key] = nil
67
91
  end
68
92
 
69
93
  def rule_names
data/lib/neo4j/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Neo4j
2
- VERSION = "1.2.2"
2
+ VERSION = "1.2.3"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: neo4j
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.2.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-09-15 00:00:00 +02:00
13
+ date: 2011-10-01 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency