neo4j 1.2.6-java → 2.0.0.alpha.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 +30 -0
- data/CONTRIBUTORS +1 -0
- data/Gemfile +16 -4
- data/README.rdoc +25 -3
- data/bin/neo4j-jars +15 -8
- data/bin/neo4j-shell +0 -1
- data/bin/neo4j-upgrade +72 -0
- data/config/neo4j/config.yml +5 -4
- data/lib/neo4j/algo/algo.rb +0 -1
- data/lib/neo4j/batch/inserter.rb +5 -0
- data/lib/neo4j/database.rb +18 -12
- data/lib/neo4j/event_handler.rb +76 -9
- data/lib/neo4j/has_list/class_methods.rb +1 -1
- data/lib/neo4j/has_list/mapping.rb +13 -33
- data/lib/neo4j/has_n/decl_relationship_dsl.rb +17 -13
- data/lib/neo4j/has_n/mapping.rb +6 -23
- data/lib/neo4j/identity_map.rb +0 -3
- data/lib/neo4j/index/class_methods.rb +9 -3
- data/lib/neo4j/index/index.rb +2 -1
- data/lib/neo4j/index/indexer.rb +3 -2
- data/lib/neo4j/index/indexer_registry.rb +1 -1
- data/lib/neo4j/index/lucene_query.rb +52 -33
- data/lib/neo4j/neo4j.rb +19 -0
- data/lib/neo4j/node.rb +42 -36
- data/lib/neo4j/node_mixin/node_mixin.rb +9 -5
- data/lib/neo4j/paginated.rb +23 -0
- data/lib/neo4j/rails/accept_id.rb +66 -0
- data/lib/neo4j/rails/attributes.rb +14 -9
- data/lib/neo4j/rails/compositions.rb +9 -1
- data/lib/neo4j/rails/finders.rb +5 -1
- data/lib/neo4j/rails/mapping/property.rb +41 -28
- data/lib/neo4j/rails/model.rb +2 -0
- data/lib/neo4j/rails/observer.rb +61 -2
- data/lib/neo4j/rails/persistence.rb +57 -57
- data/lib/neo4j/rails/rails.rb +1 -0
- data/lib/neo4j/rails/railtie.rb +4 -1
- data/lib/neo4j/rails/rel_persistence.rb +11 -12
- data/lib/neo4j/rails/relationship.rb +9 -4
- data/lib/neo4j/rails/relationships/node_dsl.rb +15 -5
- data/lib/neo4j/rails/relationships/relationships.rb +42 -2
- data/lib/neo4j/rails/relationships/rels_dsl.rb +60 -3
- data/lib/neo4j/rails/relationships/storage.rb +43 -5
- data/lib/neo4j/rails/validations/uniqueness.rb +1 -0
- data/lib/neo4j/rails/versioning/versioning.rb +64 -9
- data/lib/neo4j/relationship.rb +79 -73
- data/lib/neo4j/rule/event_listener.rb +7 -1
- data/lib/neo4j/rule/functions/count.rb +6 -0
- data/lib/neo4j/rule/rule.rb +20 -5
- data/lib/neo4j/rule/rule_node.rb +33 -20
- data/lib/neo4j/to_java.rb +5 -0
- data/lib/neo4j/traversal/traverser.rb +38 -1
- data/lib/neo4j/type_converters/type_converters.rb +56 -5
- data/lib/neo4j/version.rb +1 -1
- data/lib/neo4j.rb +3 -49
- data/neo4j.gemspec +2 -2
- metadata +191 -216
- data/bin/neo4j-shell~ +0 -108
- data/lib/Gemfile~ +0 -3
- data/lib/config2.yml~ +0 -86
- data/lib/neo4j/jars/core/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/core/lucene-core-3.1.0.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-backup-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-graph-algo-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-kernel-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-lucene-index-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/log4j-1.2.16.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-com-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-ha-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-jmx-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-management-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-shell-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/netty-3.2.1.Final.jar +0 -0
- data/lib/neo4j/jars/ha/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
- data/lib/neo4j/jars/ha/zookeeper-3.3.2.jar +0 -0
- data/lib/neo4j/paginate.rb +0 -25
- data/lib/perf.rb~ +0 -36
- 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
|
data/lib/neo4j/rails/finders.rb
CHANGED
@@ -76,7 +76,7 @@ module Neo4j
|
|
76
76
|
when "0", 0, nil
|
77
77
|
nil
|
78
78
|
else
|
79
|
-
if
|
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
|
-
|
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
|
-
|
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
|
110
|
-
# Set a default
|
111
|
-
# Property must be there
|
112
|
-
# Property has a length limit
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
170
183
|
end
|
data/lib/neo4j/rails/model.rb
CHANGED
@@ -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
|
data/lib/neo4j/rails/observer.rb
CHANGED
@@ -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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
15
|
+
create_or_update
|
16
16
|
end
|
17
17
|
|
18
18
|
# Persist the object to the database. Validations and Callbacks are included
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
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
|
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
|
-
|
266
|
-
|
265
|
+
end
|
266
|
+
end
|
267
267
|
end
|
268
268
|
|
data/lib/neo4j/rails/rails.rb
CHANGED
@@ -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'
|
data/lib/neo4j/rails/railtie.rb
CHANGED
@@ -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
|
-
|
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.
|
155
|
-
@end_node.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
170
|
-
@storage.each_node(@dir
|
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
|
-
|
70
|
-
|
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
|