neo4j 1.2.6-java → 2.0.0.alpha.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG +30 -0
  2. data/CONTRIBUTORS +1 -0
  3. data/Gemfile +16 -4
  4. data/README.rdoc +25 -3
  5. data/bin/neo4j-jars +15 -8
  6. data/bin/neo4j-shell +0 -1
  7. data/bin/neo4j-upgrade +72 -0
  8. data/config/neo4j/config.yml +5 -4
  9. data/lib/neo4j/algo/algo.rb +0 -1
  10. data/lib/neo4j/batch/inserter.rb +5 -0
  11. data/lib/neo4j/database.rb +18 -12
  12. data/lib/neo4j/event_handler.rb +76 -9
  13. data/lib/neo4j/has_list/class_methods.rb +1 -1
  14. data/lib/neo4j/has_list/mapping.rb +13 -33
  15. data/lib/neo4j/has_n/decl_relationship_dsl.rb +17 -13
  16. data/lib/neo4j/has_n/mapping.rb +6 -23
  17. data/lib/neo4j/identity_map.rb +0 -3
  18. data/lib/neo4j/index/class_methods.rb +9 -3
  19. data/lib/neo4j/index/index.rb +2 -1
  20. data/lib/neo4j/index/indexer.rb +3 -2
  21. data/lib/neo4j/index/indexer_registry.rb +1 -1
  22. data/lib/neo4j/index/lucene_query.rb +52 -33
  23. data/lib/neo4j/neo4j.rb +19 -0
  24. data/lib/neo4j/node.rb +42 -36
  25. data/lib/neo4j/node_mixin/node_mixin.rb +9 -5
  26. data/lib/neo4j/paginated.rb +23 -0
  27. data/lib/neo4j/rails/accept_id.rb +66 -0
  28. data/lib/neo4j/rails/attributes.rb +14 -9
  29. data/lib/neo4j/rails/compositions.rb +9 -1
  30. data/lib/neo4j/rails/finders.rb +5 -1
  31. data/lib/neo4j/rails/mapping/property.rb +41 -28
  32. data/lib/neo4j/rails/model.rb +2 -0
  33. data/lib/neo4j/rails/observer.rb +61 -2
  34. data/lib/neo4j/rails/persistence.rb +57 -57
  35. data/lib/neo4j/rails/rails.rb +1 -0
  36. data/lib/neo4j/rails/railtie.rb +4 -1
  37. data/lib/neo4j/rails/rel_persistence.rb +11 -12
  38. data/lib/neo4j/rails/relationship.rb +9 -4
  39. data/lib/neo4j/rails/relationships/node_dsl.rb +15 -5
  40. data/lib/neo4j/rails/relationships/relationships.rb +42 -2
  41. data/lib/neo4j/rails/relationships/rels_dsl.rb +60 -3
  42. data/lib/neo4j/rails/relationships/storage.rb +43 -5
  43. data/lib/neo4j/rails/validations/uniqueness.rb +1 -0
  44. data/lib/neo4j/rails/versioning/versioning.rb +64 -9
  45. data/lib/neo4j/relationship.rb +79 -73
  46. data/lib/neo4j/rule/event_listener.rb +7 -1
  47. data/lib/neo4j/rule/functions/count.rb +6 -0
  48. data/lib/neo4j/rule/rule.rb +20 -5
  49. data/lib/neo4j/rule/rule_node.rb +33 -20
  50. data/lib/neo4j/to_java.rb +5 -0
  51. data/lib/neo4j/traversal/traverser.rb +38 -1
  52. data/lib/neo4j/type_converters/type_converters.rb +56 -5
  53. data/lib/neo4j/version.rb +1 -1
  54. data/lib/neo4j.rb +3 -49
  55. data/neo4j.gemspec +2 -2
  56. metadata +191 -216
  57. data/bin/neo4j-shell~ +0 -108
  58. data/lib/Gemfile~ +0 -3
  59. data/lib/config2.yml~ +0 -86
  60. data/lib/neo4j/jars/core/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  61. data/lib/neo4j/jars/core/lucene-core-3.1.0.jar +0 -0
  62. data/lib/neo4j/jars/core/neo4j-backup-1.4.1.jar +0 -0
  63. data/lib/neo4j/jars/core/neo4j-graph-algo-1.4.1.jar +0 -0
  64. data/lib/neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar +0 -0
  65. data/lib/neo4j/jars/core/neo4j-kernel-1.4.1.jar +0 -0
  66. data/lib/neo4j/jars/core/neo4j-lucene-index-1.4.1.jar +0 -0
  67. data/lib/neo4j/jars/ha/log4j-1.2.16.jar +0 -0
  68. data/lib/neo4j/jars/ha/neo4j-com-1.4.1.jar +0 -0
  69. data/lib/neo4j/jars/ha/neo4j-ha-1.4.1.jar +0 -0
  70. data/lib/neo4j/jars/ha/neo4j-jmx-1.4.1.jar +0 -0
  71. data/lib/neo4j/jars/ha/neo4j-management-1.4.1.jar +0 -0
  72. data/lib/neo4j/jars/ha/neo4j-shell-1.4.1.jar +0 -0
  73. data/lib/neo4j/jars/ha/netty-3.2.1.Final.jar +0 -0
  74. data/lib/neo4j/jars/ha/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
  75. data/lib/neo4j/jars/ha/zookeeper-3.3.2.jar +0 -0
  76. data/lib/neo4j/paginate.rb +0 -25
  77. data/lib/perf.rb~ +0 -36
  78. data/lib/test.rb~ +0 -2
@@ -206,6 +206,14 @@ module Neo4j
206
206
  # :constructor => Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
207
207
  # :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
208
208
  #
209
+ def is_composed_property?(property)
210
+ composed_properties.contains(property)
211
+ end
212
+
213
+ def composed_properties
214
+ @composed_properties ||= java.util.HashSet.new
215
+ end
216
+
209
217
  def composed_of(part_id, options = {})
210
218
  options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
211
219
 
@@ -216,7 +224,7 @@ module Neo4j
216
224
  allow_nil = options[:allow_nil] || false
217
225
  constructor = options[:constructor] || :new
218
226
  converter = options[:converter]
219
-
227
+ composed_properties.add(name.to_sym)
220
228
  reader_method(name, class_name, mapping, allow_nil, constructor)
221
229
  writer_method(name, class_name, mapping, allow_nil, converter)
222
230
  end
@@ -76,7 +76,7 @@ module Neo4j
76
76
  when "0", 0, nil
77
77
  nil
78
78
  else
79
- if ((args.first.is_a?(Integer) || args.first.is_a?(String)) && args.first.to_i > 0)
79
+ if convertable_to_id?(args.first)
80
80
  find_with_ids(*args)
81
81
  else
82
82
  first(*args)
@@ -167,6 +167,10 @@ module Neo4j
167
167
  condition.is_a?(Hash) && condition[:id]
168
168
  end
169
169
 
170
+ def convertable_to_id?(value)
171
+ return false unless value
172
+ value.is_a?(Integer) || (value.is_a?(String) && value =~ /^[+-]?\d+$/)
173
+ end
170
174
 
171
175
  def conditions_in?(*args)
172
176
  return false if args.empty?
@@ -55,8 +55,7 @@ module Neo4j
55
55
  def #{rel_type}=(other)
56
56
  dsl = _decl_rels_for(:'#{rel_type}')
57
57
  storage = _create_or_get_storage_for_decl_rels(dsl)
58
- rel = storage.single_relationship(dsl.dir)
59
- rel && rel.destroy
58
+ storage.destroy_single_relationship(dsl.dir)
60
59
  storage.create_relationship_to(other, dsl.dir)
61
60
  end
62
61
  RUBY
@@ -76,9 +75,21 @@ module Neo4j
76
75
  end
77
76
 
78
77
  unless method_defined?("#{rel_type}=".to_sym)
78
+
79
+ # TODO: This is a temporary fix for allowing running neo4j with Formtastic, issue 109
80
+ # A better solution might be to implement accept_ids for has_n relationship and
81
+ # make sure (somehow) that Formtastic uses the _ids methods.
82
+
79
83
  class_eval <<-RUBY, __FILE__, __LINE__
80
84
  def #{rel_type}=(nodes)
81
- self.#{rel_type}_rels.destroy_all
85
+ if nodes.is_a?(Array) && nodes.first.is_a?(String)
86
+ if nodes.first.blank?
87
+ self.#{rel_type}_rels.destroy_all
88
+ nodes.shift
89
+ end
90
+ else
91
+ self.#{rel_type}_rels.destroy_all
92
+ end
82
93
  association = self.#{rel_type}
83
94
  nodes.each { |node| association << node }
84
95
  end
@@ -106,10 +117,10 @@ module Neo4j
106
117
 
107
118
  # Handles options for the property
108
119
  #
109
- # Set the property type :type => Time
110
- # Set a default :default => "default"
111
- # Property must be there :null => false
112
- # Property has a length limit :limit => 128
120
+ # Set the property type :type => Time
121
+ # Set a default :default => "default"
122
+ # Property must be there :null => false
123
+ # Property has a length limit :limit => 128
113
124
  def property(*args)
114
125
  options = args.extract_options!
115
126
  args.each do |property_sym|
@@ -132,39 +143,41 @@ module Neo4j
132
143
  validates(property, :non_nil => true, :on => :create)
133
144
  validates(property, :non_nil => true, :on => :update)
134
145
  end
135
- validates(property, :length => { :maximum => options[:limit] }) if options[:limit]
136
- end
137
-
138
- def define_property_methods_for(property, options)
139
- unless method_defined?(property)
140
- class_eval <<-RUBY, __FILE__, __LINE__
141
- def #{property}
142
- send(:[], "#{property}")
143
- end
146
+ validates(property, :length => { :maximum => options[:limit] }) if options[:limit]
147
+ end
148
+
149
+ def define_property_methods_for(property, options)
150
+ unless method_defined?(property)
151
+ class_eval <<-RUBY, __FILE__, __LINE__
152
+ def #{property}
153
+ send(:[], "#{property}")
154
+ end
144
155
  RUBY
145
156
  end
146
157
 
147
158
  unless method_defined?("#{property}=".to_sym)
148
159
  class_eval <<-RUBY, __FILE__, __LINE__
149
- def #{property}=(value)
150
- send(:[]=, "#{property}", value)
151
- end
152
- RUBY
153
- end
154
- end
160
+ def #{property}=(value)
161
+ send(:[]=, "#{property}", value)
162
+ end
163
+ RUBY
164
+ end
165
+ end
155
166
 
156
167
  def define_property_before_type_cast_methods_for(property, options)
157
168
  property_before_type_cast = "#{property}_before_type_cast"
158
169
  class_eval <<-RUBY, __FILE__, __LINE__
159
- attr_writer :#{property_before_type_cast}
170
+ def #{property_before_type_cast}=(value)
171
+ @properties_before_type_cast[:#{property}]=value
172
+ end
160
173
 
161
174
  def #{property_before_type_cast}
162
- instance_variable_defined?(:@#{property_before_type_cast}) ? @#{property_before_type_cast} : self.#{property}
175
+ @properties_before_type_cast.has_key?(:#{property}) ? @properties_before_type_cast[:#{property}] : self.#{property}
163
176
  end
164
177
  RUBY
165
178
  end
166
- end
167
- end
168
- end
169
- end
179
+ end
180
+ end
181
+ end
182
+ end
170
183
  end
@@ -48,6 +48,7 @@ module Neo4j
48
48
 
49
49
  # Initialize a Node with a set of properties (or empty if nothing is passed)
50
50
  def initialize(attributes = {})
51
+ @properties_before_type_cast=java.util.HashMap.new
51
52
  reset_attributes
52
53
  clear_relationships
53
54
  self.attributes = attributes if attributes.is_a?(Hash)
@@ -269,6 +270,7 @@ module Neo4j
269
270
  include Finders # ActiveRecord style find
270
271
  include Relationships # for none persisted relationships
271
272
  include Compositions
273
+ include AcceptId
272
274
  end
273
275
  end
274
276
  end
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/class/attribute_accessors'
2
+
1
3
  module Neo4j
2
4
  module Rails
3
5
  # Observer classes respond to life cycle callbacks to implement trigger-like
@@ -86,11 +88,26 @@ module Neo4j
86
88
  # In order to activate an observer, list it in the +config.neo4j.observers+
87
89
  # configuration setting in your +config/application.rb+ file.
88
90
  #
89
- # config.neo4j.observers = :comment_observer, :signup_observer
91
+ # config.neo4j.observers = [:comment_observer, :signup_observer]
90
92
  #
91
93
  # Observers will not be invoked unless you define them in your
92
94
  # application configuration.
93
95
  #
96
+ # During testing you may want (and probably should) to disable all the observers.
97
+ # Most of the time you don't want any kind of emails to be sent when creating objects.
98
+ # This should improve the speed of your tests and isolate the models and observer logic.
99
+ #
100
+ # For example, the following will disable the observers in RSpec:
101
+ #
102
+ # config.before(:each) { Neo4j::Rails::Observer.disable_observers }
103
+ #
104
+ # But if you do want to run a particular observer(s) as part of the test,
105
+ # you can temporarily enable it:
106
+ #
107
+ # Neo4j::Rails::Observer.with_observers(:user_recorder, :account_observer) do
108
+ # # Any code here will work with observers enabled
109
+ # end
110
+ #
94
111
  # == Loading
95
112
  #
96
113
  # Observers register themselves with the model class that they observe,
@@ -113,6 +130,48 @@ module Neo4j
113
130
  super and observed_descendants.each { |klass| add_observer!(klass) }
114
131
  end
115
132
 
133
+ cattr_accessor :default_observers_enabled, :observers_enabled
134
+
135
+ # TODO: Add docs
136
+ class << self
137
+ # Enables all observers (default behavior)
138
+ def enable_observers
139
+ self.default_observers_enabled = true
140
+ end
141
+
142
+ # Disables all observers
143
+ def disable_observers
144
+ self.default_observers_enabled = false
145
+ end
146
+
147
+ # Run a block with a specific set of observers enabled
148
+ def with_observers(*observer_syms)
149
+ self.observers_enabled = Array(observer_syms).map do |o|
150
+ o.respond_to?(:instance) ? o.instance : o.to_s.classify.constantize.instance
151
+ end
152
+ yield
153
+ ensure
154
+ self.observers_enabled = []
155
+ end
156
+
157
+ # Determines whether an observer is enabled. Either:
158
+ # - All observers are enabled OR
159
+ # - The observer is in the whitelist
160
+ def observer_enabled?(observer)
161
+ default_observers_enabled or self.observers_enabled.include?(observer)
162
+ end
163
+ end
164
+
165
+
166
+ # Determines whether this observer should be run
167
+ def observer_enabled?
168
+ self.class.observer_enabled?(self)
169
+ end
170
+
171
+ # By default, enable all observers
172
+ enable_observers
173
+ self.observers_enabled = []
174
+
116
175
  protected
117
176
 
118
177
  # Get all the child observers.
@@ -149,7 +208,7 @@ module Neo4j
149
208
  callback_meth = :"_notify_#{observer_name}_for_#{callback}"
150
209
  unless klass.respond_to?(callback_meth)
151
210
  klass.send(:define_method, callback_meth) do |&block|
152
- observer.send(callback, self, &block)
211
+ observer.send(callback, self, &block) if observer.observer_enabled?
153
212
  end
154
213
  klass.send(callback, callback_meth)
155
214
  end
@@ -1,62 +1,62 @@
1
1
  module Neo4j
2
- module Rails
3
- module Persistence
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- extend TxMethods
8
- tx_methods :destroy, :create, :update, :update_nested_attributes, :delete, :update_attributes, :update_attributes!
9
- end
10
-
11
- # Persist the object to the database. Validations and Callbacks are included
12
- # by default but validation can be disabled by passing :validate => false
13
- # to #save.
2
+ module Rails
3
+ module Persistence
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ extend TxMethods
8
+ tx_methods :destroy, :create, :update, :update_nested_attributes, :delete, :update_attributes, :update_attributes!
9
+ end
10
+
11
+ # Persist the object to the database. Validations and Callbacks are included
12
+ # by default but validation can be disabled by passing :validate => false
13
+ # to #save.
14
14
  def save(*)
15
- create_or_update
15
+ create_or_update
16
16
  end
17
17
 
18
18
  # Persist the object to the database. Validations and Callbacks are included
19
- # by default but validation can be disabled by passing :validate => false
20
- # to #save!.
21
- #
22
- # Raises a RecordInvalidError if there is a problem during save.
19
+ # by default but validation can be disabled by passing :validate => false
20
+ # to #save!.
21
+ #
22
+ # Raises a RecordInvalidError if there is a problem during save.
23
23
  def save!(*args)
24
- unless save(*args)
25
- raise RecordInvalidError.new(self)
26
- end
27
- end
28
-
29
- # Updates a single attribute and saves the record.
30
- # This is especially useful for boolean flags on existing records. Also note that
31
- #
32
- # * Validation is skipped.
33
- # * Callbacks are invoked.
34
- # * Updates all the attributes that are dirty in this object.
35
- #
36
- def update_attribute(name, value)
37
- respond_to?("#{name}=") ? send("#{name}=", value) : self[name] = value
38
- save(:validate => false)
39
- end
40
-
41
- # Removes the node from Neo4j and freezes the object.
42
- def destroy
43
- delete
44
- freeze
45
- end
46
-
47
- # Same as #destroy but doesn't run destroy callbacks and doesn't freeze
48
- # the object
49
- def delete
50
- del unless new_record?
51
- set_deleted_properties
52
- end
53
-
54
- # Returns true if the object was destroyed.
55
- def destroyed?()
24
+ unless save(*args)
25
+ raise RecordInvalidError.new(self)
26
+ end
27
+ end
28
+
29
+ # Updates a single attribute and saves the record.
30
+ # This is especially useful for boolean flags on existing records. Also note that
31
+ #
32
+ # * Validation is skipped.
33
+ # * Callbacks are invoked.
34
+ # * Updates all the attributes that are dirty in this object.
35
+ #
36
+ def update_attribute(name, value)
37
+ respond_to?("#{name}=") ? send("#{name}=", value) : self[name] = value
38
+ save(:validate => false)
39
+ end
40
+
41
+ # Removes the node from Neo4j and freezes the object.
42
+ def destroy
43
+ delete
44
+ freeze
45
+ end
46
+
47
+ # Same as #destroy but doesn't run destroy callbacks and doesn't freeze
48
+ # the object
49
+ def delete
50
+ del unless new_record?
51
+ set_deleted_properties
52
+ end
53
+
54
+ # Returns true if the object was destroyed.
55
+ def destroyed?()
56
56
  @_deleted || Neo4j::Node._load(id).nil?
57
57
  end
58
58
 
59
- # Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved.
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)
62
62
  self.attributes = attributes
@@ -95,9 +95,9 @@ module Neo4j
95
95
  alias :new? :new_record?
96
96
 
97
97
  # Freeze the properties hash.
98
- def freeze
99
- @properties.freeze; self
100
- end
98
+ def freeze
99
+ @properties.freeze; self
100
+ end
101
101
 
102
102
  # Returns +true+ if the properties hash has been frozen.
103
103
  def frozen?
@@ -162,7 +162,7 @@ module Neo4j
162
162
  end
163
163
 
164
164
  def init_on_create(*)
165
- self["_classname"] = self.class.to_s
165
+ self._classname = self.class.to_s
166
166
  write_default_attributes
167
167
  write_changed_attributes
168
168
  write_changed_relationships
@@ -190,7 +190,7 @@ module Neo4j
190
190
  # Ensure any defaults are stored in the DB
191
191
  def write_default_attributes
192
192
  attribute_defaults.each do |attribute, value|
193
- write_attribute(attribute, Neo4j::TypeConverters.convert(value, attribute, self.class)) unless changed_attributes.has_key?(attribute) || _java_node.has_property?(attribute)
193
+ write_attribute(attribute, Neo4j::TypeConverters.convert(value, attribute, self.class, false)) unless changed_attributes.has_key?(attribute) || _java_node.has_property?(attribute)
194
194
  end
195
195
  end
196
196
 
@@ -262,7 +262,7 @@ module Neo4j
262
262
  super(@record.errors.full_messages.join(", "))
263
263
  end
264
264
  end
265
- end
266
- end
265
+ end
266
+ end
267
267
  end
268
268
 
@@ -11,6 +11,7 @@ require 'neo4j/rails/validations'
11
11
  require 'neo4j/rails/callbacks'
12
12
  require 'neo4j/rails/observer'
13
13
  require 'neo4j/rails/compositions'
14
+ require 'neo4j/rails/accept_id'
14
15
  require 'neo4j/rails/timestamps'
15
16
  require 'neo4j/rails/serialization'
16
17
  require 'neo4j/rails/attributes'
@@ -15,7 +15,10 @@ module Neo4j
15
15
  # Starting Neo after :load_config_initializers allows apps to
16
16
  # register migrations in config/initializers
17
17
  initializer "neo4j.start", :after => :load_config_initializers do |app|
18
- Neo4j::Config.setup.merge!(app.config.neo4j.to_hash)
18
+ cfg = app.config.neo4j
19
+ # Set Rails specific defaults
20
+ cfg.storage_path = "#{app.config.root}/db/neo4j-#{::Rails.env}" unless cfg.storage_path
21
+ Neo4j::Config.setup.merge!(cfg.to_hash)
19
22
  end
20
23
 
21
24
  # Instantitate any registered observers after Rails initialization and
@@ -151,17 +151,20 @@ module Neo4j
151
151
  def create()
152
152
  begin
153
153
  # prevent calling create twice
154
- @start_node.rm_outgoing_rel(type, self)
155
- @end_node.rm_incoming_rel(type, self)
154
+ @start_node.add_unpersisted_outgoing_rel(type, self)
155
+ @end_node.add_unpersisted_incoming_rel(type, self)
156
156
 
157
- _persist_start_node
158
- _persist_end_node
157
+ return unless _persist_start_node && _persist_end_node
159
158
 
160
159
  @_java_rel = Neo4j::Relationship.new(type, start_node, end_node)
161
160
  Neo4j::IdentityMap.add(@_java_rel, self)
162
161
  init_on_create
163
162
  clear_changes
164
- end unless @end_node.nil?
163
+
164
+ @start_node.rm_unpersisted_outgoing_rel(type, self)
165
+ @end_node.rm_unpersisted_incoming_rel(type, self)
166
+
167
+ end unless @end_node.nil? or @start_node.nil?
165
168
  true
166
169
  end
167
170
 
@@ -170,18 +173,14 @@ module Neo4j
170
173
  end
171
174
 
172
175
  def _persist_start_node
173
- unless @start_node.persisted? || @start_node.save
174
- # not sure if this can happen - probably a bug
175
- raise "Can't save start_node #{@start_node} id #{@start_node.id}"
176
- end
176
+ (!@start_node.persisted? || @start_node.relationships_changed?) ? @start_node.save : true
177
177
  end
178
178
 
179
179
  def _persist_end_node
180
- unless @end_node.persisted? || @end_node.save
181
- raise "Can't save end_node #{@end_node} id #{@end_node.id}"
182
- end
180
+ (!@end_node.persisted? || @end_node.relationships_changed?) ? @end_node.save : true
183
181
  end
184
182
 
183
+
185
184
  def init_on_create(*)
186
185
  #self["_classname"] = self.class.to_s
187
186
  write_default_attributes
@@ -21,7 +21,8 @@ module Neo4j
21
21
 
22
22
  # Initialize a Node with a set of properties (or empty if nothing is passed)
23
23
  def initialize(*args)
24
- @type = args[0]
24
+ @properties_before_type_cast=java.util.HashMap.new
25
+ @type = args[0].to_s
25
26
  self.start_node = args[1]
26
27
  self.end_node = args[2]
27
28
  attributes = args[3]
@@ -39,11 +40,15 @@ module Neo4j
39
40
 
40
41
 
41
42
  alias_method :get_other_node, :other_node # so it looks like the java version
42
-
43
+
44
+ def rel_type
45
+ persisted? ? _java_entity.rel_type : @type
46
+ end
47
+
43
48
  def to_s
44
49
  "id: #{self.object_id} start_node: #{start_node.id} end_node: #{end_node.id} type:#{@type}"
45
50
  end
46
-
51
+
47
52
  def id
48
53
  _java_rel.nil? || neo_id.nil? ? nil : neo_id.to_s
49
54
  end
@@ -111,7 +116,7 @@ module Neo4j
111
116
  def _all
112
117
  _indexer.find(:_classname => self)
113
118
  end
114
-
119
+
115
120
  def load(*ids) # TODO Copied from finders.rb
116
121
  result = ids.map { |id| entity_load(id) }
117
122
  if ids.length == 1
@@ -9,7 +9,6 @@ module Neo4j
9
9
  #
10
10
  class NodesDSL
11
11
  include Enumerable
12
- include Neo4j::Paginate
13
12
 
14
13
  def initialize(storage, dir)
15
14
  @storage = storage
@@ -51,7 +50,14 @@ module Neo4j
51
50
 
52
51
  # Adds a new node to the relationship
53
52
  def <<(other)
54
- @storage.create_relationship_to(other, @dir)
53
+ if other.is_a?(String)
54
+ # this is typically called in an assignment operator, person.friends = ['42', '32']
55
+ node = Neo4j::Node.load(other)
56
+ @storage.create_relationship_to(node, @dir) unless all.include?(node)
57
+ else
58
+ # allow multiple relationships to the same node
59
+ @storage.create_relationship_to(other, @dir)
60
+ end
55
61
  self
56
62
  end
57
63
 
@@ -166,8 +172,8 @@ module Neo4j
166
172
 
167
173
  alias :length :size
168
174
 
169
- def each(&block)
170
- @storage.each_node(@dir, &block)
175
+ def each
176
+ @storage.each_node(@dir) {|n| yield n} # Why passing the &block through doesn't work on JRuby 1.9?
171
177
  end
172
178
 
173
179
  def delete(*nodes)
@@ -185,7 +191,11 @@ module Neo4j
185
191
  def to_s
186
192
  "Node dir: #{@dir}, #{@storage}"
187
193
  end
188
-
194
+
195
+ def rel_changed?
196
+ @storage.persisted?
197
+ end
198
+
189
199
  protected
190
200
 
191
201
 
@@ -30,6 +30,9 @@ module Neo4j
30
30
  @_relationships[decl_rels.rel_type.to_sym] ||= Storage.new(self, decl_rels.rel_type, decl_rels)
31
31
  end
32
32
 
33
+ def _storage_for(rel_type) #:nodoc:
34
+ @_relationships[rel_type.to_sym]
35
+ end
33
36
 
34
37
  # If the node is persisted and it does not have any unsaved relationship it returns a Neo4j::NodeTraverser.
35
38
  # Otherwise it will return a NodesDSL which behaves like the Neo4j::NodeTraverser except that it does not
@@ -66,8 +69,12 @@ module Neo4j
66
69
  # node.rels(:foo) #=> [node2] - incoming and outgoing
67
70
  #
68
71
  def rels(*rel_types)
69
- storage = _create_or_get_storage(rel_types.first)
70
- RelsDSL.new(storage)
72
+ if rel_types.empty?
73
+ AllRelsDsl.new(@_relationships, _java_node)
74
+ else
75
+ storage = _create_or_get_storage(rel_types.first)
76
+ RelsDSL.new(storage)
77
+ end
71
78
  end
72
79
 
73
80
  def add_outgoing_rel(rel_type, rel) #:nodoc:
@@ -86,6 +93,39 @@ module Neo4j
86
93
  _create_or_get_storage(rel_type).rm_outgoing_rel(rel)
87
94
  end
88
95
 
96
+ def rm_outgoing_rel(rel_type, rel) #:nodoc:
97
+ _create_or_get_storage(rel_type).rm_outgoing_rel(rel)
98
+ end
99
+
100
+ def add_unpersisted_incoming_rel(rel_type, rel) #:nodoc
101
+ if (storage = _create_or_get_storage(rel_type))
102
+ # move the relationship since we are now about to store the relationship
103
+ storage.add_unpersisted_incoming_rel(rel)
104
+ storage.rm_incoming_rel(rel)
105
+ end
106
+ end
107
+
108
+ def add_unpersisted_outgoing_rel(rel_type, rel) #:nodoc
109
+ if (storage = _create_or_get_storage(rel_type))
110
+ # move the relationship since we are now about to store the relationship
111
+ storage.add_unpersisted_outgoing_rel(rel)
112
+ storage.rm_outgoing_rel(rel)
113
+ end
114
+ end
115
+
116
+ def rm_unpersisted_outgoing_rel(rel_type, rel) #:nodoc
117
+ if (storage = _storage_for(rel_type))
118
+ storage.rm_unpersisted_outgoing_rel(rel)
119
+ end
120
+ end
121
+
122
+ def rm_unpersisted_incoming_rel(rel_type, rel) #:nodoc
123
+ if (storage = _storage_for(rel_type))
124
+ storage.rm_unpersisted_incoming_rel(rel)
125
+ end
126
+ end
127
+
128
+
89
129
  end
90
130
  end
91
131
  end