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 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