dm-core 0.9.3 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTING +51 -0
- data/FAQ +26 -8
- data/Manifest.txt +2 -0
- data/Rakefile +2 -1
- data/lib/dm-core.rb +8 -3
- data/lib/dm-core/adapters/abstract_adapter.rb +2 -2
- data/lib/dm-core/adapters/data_objects_adapter.rb +18 -4
- data/lib/dm-core/adapters/mysql_adapter.rb +8 -4
- data/lib/dm-core/adapters/postgres_adapter.rb +12 -3
- data/lib/dm-core/adapters/sqlite3_adapter.rb +1 -1
- data/lib/dm-core/associations.rb +1 -0
- data/lib/dm-core/associations/many_to_one.rb +7 -1
- data/lib/dm-core/associations/one_to_many.rb +1 -1
- data/lib/dm-core/associations/relationship.rb +14 -13
- data/lib/dm-core/auto_migrations.rb +57 -5
- data/lib/dm-core/collection.rb +2 -1
- data/lib/dm-core/logger.rb +5 -6
- data/lib/dm-core/model.rb +17 -2
- data/lib/dm-core/naming_conventions.rb +57 -25
- data/lib/dm-core/property.rb +6 -5
- data/lib/dm-core/query.rb +20 -16
- data/lib/dm-core/resource.rb +24 -7
- data/lib/dm-core/version.rb +1 -1
- data/script/performance.rb +2 -1
- data/script/profile.rb +1 -0
- data/spec/integration/association_spec.rb +131 -81
- data/spec/integration/association_through_spec.rb +87 -42
- data/spec/integration/associations/many_to_many_spec.rb +76 -16
- data/spec/integration/associations/many_to_one_spec.rb +6 -1
- data/spec/integration/associations/one_to_many_spec.rb +69 -0
- data/spec/integration/collection_spec.rb +7 -0
- data/spec/integration/query_spec.rb +24 -7
- data/spec/integration/resource_spec.rb +59 -10
- data/spec/integration/sti_spec.rb +23 -0
- data/spec/models/zoo.rb +2 -3
- data/spec/spec_helper.rb +9 -1
- data/spec/unit/adapters/postgres_adapter_spec.rb +9 -1
- data/spec/unit/associations/many_to_one_spec.rb +6 -0
- data/spec/unit/auto_migrations_spec.rb +2 -1
- data/spec/unit/naming_conventions_spec.rb +26 -18
- data/spec/unit/property_spec.rb +3 -4
- data/spec/unit/resource_spec.rb +19 -22
- data/tasks/gemspec.rb +23 -0
- data/tasks/hoe.rb +9 -1
- metadata +6 -14
data/lib/dm-core/collection.rb
CHANGED
@@ -509,7 +509,8 @@ module DataMapper
|
|
509
509
|
assert_kind_of 'query', query, Query
|
510
510
|
|
511
511
|
unless block_given?
|
512
|
-
|
512
|
+
# It can be helpful (relationship.rb: 112-13, used for SEL) to have a non-lazy Collection.
|
513
|
+
block = lambda {}
|
513
514
|
end
|
514
515
|
|
515
516
|
@query = query
|
data/lib/dm-core/logger.rb
CHANGED
@@ -4,10 +4,10 @@ require "time" # httpdate
|
|
4
4
|
# Logger taken from Merb :)
|
5
5
|
#
|
6
6
|
# To replace an existing logger with a new one:
|
7
|
-
#
|
7
|
+
# DataMapper.logger.set_log(log{String, IO},level{Symbol, String})
|
8
8
|
#
|
9
|
-
# Available logging levels are
|
10
|
-
#
|
9
|
+
# Available logging levels are:
|
10
|
+
# :off, :fatal, :error, :warn, :info, :debug
|
11
11
|
#
|
12
12
|
# Logging via:
|
13
13
|
# DataMapper.logger.fatal(message<String>)
|
@@ -25,7 +25,7 @@ require "time" # httpdate
|
|
25
25
|
# ==== Private DataMapper Logger API
|
26
26
|
#
|
27
27
|
# To initialize the logger you create a new object, proxies to set_log.
|
28
|
-
# DataMapper::Logger.new(log{String, IO},level{Symbol, String})
|
28
|
+
# DataMapper::Logger.new(log{String, IO}, level{Symbol, String})
|
29
29
|
#
|
30
30
|
# Logger will not create the file until something is actually logged
|
31
31
|
# This avoids file creation on DataMapper init when it creates the
|
@@ -147,8 +147,7 @@ module DataMapper
|
|
147
147
|
end
|
148
148
|
|
149
149
|
# To replace an existing logger with a new one:
|
150
|
-
#
|
151
|
-
#
|
150
|
+
# DataMapper.logger.set_log(log{String, IO},level{Symbol, String})
|
152
151
|
#
|
153
152
|
# @param log<IO,String> either an IO object or a name of a logfile.
|
154
153
|
# @param log_level<Symbol> a symbol representing the log level from
|
data/lib/dm-core/model.rb
CHANGED
@@ -31,6 +31,7 @@ module DataMapper
|
|
31
31
|
def self.extended(model)
|
32
32
|
model.instance_variable_set(:@storage_names, Hash.new { |h,k| h[k] = repository(k).adapter.resource_naming_convention.call(model.send(:default_storage_name)) })
|
33
33
|
model.instance_variable_set(:@properties, Hash.new { |h,k| h[k] = k == Repository.default_name ? PropertySet.new : h[Repository.default_name].dup })
|
34
|
+
model.instance_variable_set(:@field_naming_conventions, Hash.new { |h,k| h[k] = repository(k).adapter.field_naming_convention })
|
34
35
|
extra_extensions.each { |extension| model.extend(extension) }
|
35
36
|
end
|
36
37
|
|
@@ -39,7 +40,13 @@ module DataMapper
|
|
39
40
|
target.instance_variable_set(:@properties, Hash.new { |h,k| h[k] = k == Repository.default_name ? PropertySet.new : h[Repository.default_name].dup })
|
40
41
|
target.instance_variable_set(:@base_model, self.base_model)
|
41
42
|
target.instance_variable_set(:@paranoid_properties, @paranoid_properties)
|
42
|
-
target.instance_variable_set(:@
|
43
|
+
target.instance_variable_set(:@field_naming_conventions, @field_naming_conventions.dup)
|
44
|
+
|
45
|
+
if self.respond_to?(:validators)
|
46
|
+
@validations.contexts.each do |context, validators|
|
47
|
+
validators.each { |validator| target.validators.context(context) << validator }
|
48
|
+
end
|
49
|
+
end
|
43
50
|
|
44
51
|
@properties.each do |repository_name,properties|
|
45
52
|
repository(repository_name) do
|
@@ -120,6 +127,14 @@ module DataMapper
|
|
120
127
|
@storage_names
|
121
128
|
end
|
122
129
|
|
130
|
+
##
|
131
|
+
# The field naming conventions for this resource across all repositories.
|
132
|
+
#
|
133
|
+
# @return <Hash(Symbol => String)> All available field naming conventions
|
134
|
+
def field_naming_conventions
|
135
|
+
@field_naming_conventions
|
136
|
+
end
|
137
|
+
|
123
138
|
##
|
124
139
|
# defines a property on the resource
|
125
140
|
#
|
@@ -262,7 +277,7 @@ module DataMapper
|
|
262
277
|
|
263
278
|
##
|
264
279
|
# This method is deprecated, and will be removed from dm-core.
|
265
|
-
#
|
280
|
+
#
|
266
281
|
def create!(attributes = {})
|
267
282
|
warn("Model#create! is deprecated. It is moving to dm-validations, and will be used to create a record without validations")
|
268
283
|
resource = create(attributes)
|
@@ -4,7 +4,7 @@ module DataMapper
|
|
4
4
|
# The default is UnderscoredAndPluralized.
|
5
5
|
# You assign a naming convention like so:
|
6
6
|
#
|
7
|
-
# repository(:default).adapter.resource_naming_convention = NamingConventions::Underscored
|
7
|
+
# repository(:default).adapter.resource_naming_convention = NamingConventions::Resource::Underscored
|
8
8
|
#
|
9
9
|
# You can also easily assign a custom convention with a Proc:
|
10
10
|
#
|
@@ -21,32 +21,64 @@ module DataMapper
|
|
21
21
|
# use code like this:
|
22
22
|
#
|
23
23
|
# adapter = DataMapper.setup(:default, "mock://localhost/mock")
|
24
|
-
# adapter.resource_naming_convention = DataMapper::NamingConventions::Underscored
|
24
|
+
# adapter.resource_naming_convention = DataMapper::NamingConventions::Resource::Underscored
|
25
25
|
module NamingConventions
|
26
26
|
|
27
|
-
module
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
27
|
+
module Resource
|
28
|
+
|
29
|
+
module UnderscoredAndPluralized
|
30
|
+
def self.call(name)
|
31
|
+
Extlib::Inflection.pluralize(Extlib::Inflection.underscore(name)).gsub('/','_')
|
32
|
+
end
|
33
|
+
end # module UnderscoredAndPluralized
|
34
|
+
|
35
|
+
module UnderscoredAndPluralizedWithoutModule
|
36
|
+
def self.call(name)
|
37
|
+
Extlib::Inflection.pluralize(Extlib::Inflection.underscore(Extlib::Inflection.demodulize(name)))
|
38
|
+
end
|
39
|
+
end # module UnderscoredAndPluralizedWithoutModule
|
40
|
+
|
41
|
+
module Underscored
|
42
|
+
def self.call(name)
|
43
|
+
Extlib::Inflection.underscore(name)
|
44
|
+
end
|
45
|
+
end # module Underscored
|
46
|
+
|
47
|
+
module Yaml
|
48
|
+
def self.call(name)
|
49
|
+
Extlib::Inflection.pluralize(Extlib::Inflection.underscore(name)) + ".yaml"
|
50
|
+
end
|
51
|
+
end # module Yaml
|
52
|
+
|
53
|
+
end # module Resource
|
54
|
+
|
55
|
+
module Field
|
56
|
+
|
57
|
+
module UnderscoredAndPluralized
|
58
|
+
def self.call(property)
|
59
|
+
Extlib::Inflection.pluralize(Extlib::Inflection.underscore(property.name.to_s)).gsub('/','_')
|
60
|
+
end
|
61
|
+
end # module UnderscoredAndPluralized
|
62
|
+
|
63
|
+
module UnderscoredAndPluralizedWithoutModule
|
64
|
+
def self.call(property)
|
65
|
+
Extlib::Inflection.pluralize(Extlib::Inflection.underscore(Extlib::Inflection.demodulize(property.name.to_s)))
|
66
|
+
end
|
67
|
+
end # module UnderscoredAndPluralizedWithoutModule
|
68
|
+
|
69
|
+
module Underscored
|
70
|
+
def self.call(property)
|
71
|
+
Extlib::Inflection.underscore(property.name.to_s)
|
72
|
+
end
|
73
|
+
end # module Underscored
|
74
|
+
|
75
|
+
module Yaml
|
76
|
+
def self.call(property)
|
77
|
+
Extlib::Inflection.pluralize(Extlib::Inflection.underscore(property.name.to_s)) + ".yaml"
|
78
|
+
end
|
79
|
+
end # module Yaml
|
80
|
+
|
81
|
+
end # module Field
|
50
82
|
|
51
83
|
end # module NamingConventions
|
52
84
|
end # module DataMapper
|
data/lib/dm-core/property.rb
CHANGED
@@ -279,7 +279,7 @@ module DataMapper
|
|
279
279
|
|
280
280
|
attr_reader :primitive, :model, :name, :instance_variable_name,
|
281
281
|
:type, :reader_visibility, :writer_visibility, :getter, :options,
|
282
|
-
:default, :precision, :scale, :track
|
282
|
+
:default, :precision, :scale, :track, :extra_options
|
283
283
|
|
284
284
|
# Supplies the field in the data-store which the property corresponds to
|
285
285
|
#
|
@@ -510,8 +510,9 @@ module DataMapper
|
|
510
510
|
raise ArgumentError, "+type+ was #{type.inspect}, which is not a supported type: #{TYPES * ', '}", caller
|
511
511
|
end
|
512
512
|
|
513
|
-
|
514
|
-
|
513
|
+
@extra_options = {}
|
514
|
+
(options.keys - PROPERTY_OPTIONS).each do |key|
|
515
|
+
@extra_options[key] = options.delete(key)
|
515
516
|
end
|
516
517
|
|
517
518
|
@model = model
|
@@ -548,7 +549,7 @@ module DataMapper
|
|
548
549
|
@length = @options.fetch(:length, @options.fetch(:size, DEFAULT_LENGTH))
|
549
550
|
elsif BigDecimal == @primitive || Float == @primitive
|
550
551
|
@precision = @options.fetch(:precision, DEFAULT_PRECISION)
|
551
|
-
|
552
|
+
|
552
553
|
default_scale = (Float == @primitive) ? DEFAULT_SCALE_FLOAT : DEFAULT_SCALE_BIGDECIMAL
|
553
554
|
@scale = @options.fetch(:scale, default_scale)
|
554
555
|
# @scale = @options.fetch(:scale, DEFAULT_SCALE_BIGDECIMAL)
|
@@ -575,7 +576,7 @@ module DataMapper
|
|
575
576
|
end
|
576
577
|
|
577
578
|
def fields
|
578
|
-
@fields ||= Hash.new { |h,k| h[k] =
|
579
|
+
@fields ||= Hash.new { |h,k| h[k] = self.model.field_naming_conventions[k].call(self) }
|
579
580
|
end
|
580
581
|
|
581
582
|
def determine_visibility # :nodoc:
|
data/lib/dm-core/query.rb
CHANGED
@@ -47,7 +47,7 @@ module DataMapper
|
|
47
47
|
# only overwrite the attributes with non-default values
|
48
48
|
@reload = other.reload? unless other.reload? == false
|
49
49
|
@unique = other.unique? unless other.unique? == false
|
50
|
-
@offset = other.offset
|
50
|
+
@offset = other.offset if other.reload? || other.offset != 0
|
51
51
|
@limit = other.limit unless other.limit == nil
|
52
52
|
@order = other.order unless other.order == model.default_order
|
53
53
|
@add_reversed = other.add_reversed? unless other.add_reversed? == false
|
@@ -189,8 +189,6 @@ module DataMapper
|
|
189
189
|
@links = normalize_links(@links)
|
190
190
|
@includes = normalize_includes(@includes)
|
191
191
|
|
192
|
-
translate_custom_types(@properties, options)
|
193
|
-
|
194
192
|
# treat all non-options as conditions
|
195
193
|
(options.keys - OPTIONS - OPTIONS.map { |option| option.to_s }).each do |k|
|
196
194
|
append_condition(k, options[k])
|
@@ -218,17 +216,6 @@ module DataMapper
|
|
218
216
|
@conditions = original.conditions.map { |tuple| tuple.dup }
|
219
217
|
end
|
220
218
|
|
221
|
-
def translate_custom_types(properties, options)
|
222
|
-
options.each do |key, value|
|
223
|
-
case key
|
224
|
-
when DataMapper::Query::Operator
|
225
|
-
options[key] = properties[key.target].type.dump(value, properties[key.target]) if properties.has_property?(key.target) && properties[key.target].custom?
|
226
|
-
when Symbol, String
|
227
|
-
options[key] = properties[key].type.dump(value, properties[key]) if properties.has_property?(key) && properties[key].custom?
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
219
|
# validate the options
|
233
220
|
def assert_valid_options(options)
|
234
221
|
# validate the reload option and unique option
|
@@ -440,9 +427,26 @@ module DataMapper
|
|
440
427
|
raise ArgumentError, "Clause #{clause.inspect} does not map to a DataMapper::Property", caller(2)
|
441
428
|
end
|
442
429
|
|
430
|
+
bind_value = dump_custom_value(property, bind_value)
|
431
|
+
|
443
432
|
@conditions << [ operator, property, bind_value ]
|
444
433
|
end
|
445
434
|
|
435
|
+
def dump_custom_value(property_or_path, bind_value)
|
436
|
+
case property_or_path
|
437
|
+
when DataMapper::Query::Path
|
438
|
+
dump_custom_value(property_or_path.property, bind_value)
|
439
|
+
when Property
|
440
|
+
if property_or_path.custom?
|
441
|
+
property_or_path.type.dump(bind_value, property_or_path)
|
442
|
+
else
|
443
|
+
bind_value
|
444
|
+
end
|
445
|
+
else
|
446
|
+
bind_value
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
446
450
|
# TODO: check for other mutually exclusive operator + property
|
447
451
|
# combinations. For example if self's conditions were
|
448
452
|
# [ :gt, :amount, 5 ] and the other's condition is [ :lt, :amount, 2 ]
|
@@ -565,8 +569,8 @@ module DataMapper
|
|
565
569
|
|
566
570
|
class Path
|
567
571
|
include Assertions
|
568
|
-
|
569
|
-
|
572
|
+
|
573
|
+
%w[ id type ].each { |m| undef_method m }
|
570
574
|
|
571
575
|
attr_reader :relationships, :model, :property, :operator
|
572
576
|
|
data/lib/dm-core/resource.rb
CHANGED
@@ -167,6 +167,17 @@ module DataMapper
|
|
167
167
|
|
168
168
|
alias == eql?
|
169
169
|
|
170
|
+
# Computes a hash for the resource
|
171
|
+
#
|
172
|
+
# ==== Returns
|
173
|
+
# <Integer>:: the hash value of the resource
|
174
|
+
#
|
175
|
+
# -
|
176
|
+
# @api public
|
177
|
+
def hash
|
178
|
+
model.hash + key.hash
|
179
|
+
end
|
180
|
+
|
170
181
|
# Inspection of the class name and the attributes
|
171
182
|
#
|
172
183
|
# ==== Returns
|
@@ -233,7 +244,7 @@ module DataMapper
|
|
233
244
|
|
234
245
|
def key
|
235
246
|
key_properties.map do |property|
|
236
|
-
property.get!(self)
|
247
|
+
original_values[property.name] || property.get!(self)
|
237
248
|
end
|
238
249
|
end
|
239
250
|
|
@@ -259,19 +270,22 @@ module DataMapper
|
|
259
270
|
# same API through out all of dm-more. dm-validations requires a
|
260
271
|
# context to be passed
|
261
272
|
|
262
|
-
|
273
|
+
associations_saved = false
|
274
|
+
child_associations.each { |a| associations_saved |= a.save }
|
263
275
|
|
264
|
-
|
276
|
+
saved = if dirty? || (new_record? && key_properties.any? { |p| p.serial? })
|
265
277
|
new_record? ? create : update
|
266
278
|
end
|
267
279
|
|
268
|
-
if
|
280
|
+
if saved
|
269
281
|
original_values.clear
|
270
282
|
end
|
271
283
|
|
272
|
-
parent_associations.each { |a| a.save }
|
284
|
+
parent_associations.each { |a| associations_saved |= a.save }
|
273
285
|
|
274
|
-
|
286
|
+
# We should return true if the model (or any of its associations)
|
287
|
+
# were saved.
|
288
|
+
(saved | associations_saved) == true
|
275
289
|
end
|
276
290
|
|
277
291
|
# destroy the instance, remove it from the repository
|
@@ -503,7 +517,10 @@ module DataMapper
|
|
503
517
|
#-
|
504
518
|
# @api public
|
505
519
|
def update_attributes(hash, *update_only)
|
506
|
-
|
520
|
+
unless hash.is_a?(Hash)
|
521
|
+
raise ArgumentError, "Expecting the first parameter of " +
|
522
|
+
"update_attributes to be a hash; got #{hash.inspect}"
|
523
|
+
end
|
507
524
|
loop_thru = update_only.empty? ? hash.keys : update_only
|
508
525
|
loop_thru.each { |attr| send("#{attr}=", hash[attr]) }
|
509
526
|
save
|
data/lib/dm-core/version.rb
CHANGED
data/script/performance.rb
CHANGED
@@ -23,6 +23,7 @@ socket_file = Pathname.glob(%w[
|
|
23
23
|
tmp/mysql.sock
|
24
24
|
/tmp/mysql.sock
|
25
25
|
/var/mysql/mysql.sock
|
26
|
+
/var/run/mysqld/mysqld.sock
|
26
27
|
]).find { |path| path.socket? }
|
27
28
|
|
28
29
|
configuration_options = {
|
@@ -130,7 +131,7 @@ puts "Benchmarks will now run #{TIMES} times"
|
|
130
131
|
RBench.run(TIMES) do
|
131
132
|
|
132
133
|
column :times
|
133
|
-
column :dm, :title => "DM 0.9.
|
134
|
+
column :dm, :title => "DM 0.9.4"
|
134
135
|
column :ar, :title => "AR 2.1"
|
135
136
|
column :diff, :compare => [:dm,:ar]
|
136
137
|
|
data/script/profile.rb
CHANGED
@@ -165,6 +165,19 @@ if ADAPTER
|
|
165
165
|
belongs_to :parent, :class_name => 'Node', :child_key => [ :parent_id ]
|
166
166
|
end
|
167
167
|
|
168
|
+
class MadeUpThing
|
169
|
+
include DataMapper::Resource
|
170
|
+
|
171
|
+
def self.default_repository_name
|
172
|
+
ADAPTER
|
173
|
+
end
|
174
|
+
|
175
|
+
property :id, Serial
|
176
|
+
property :name, String
|
177
|
+
belongs_to :area
|
178
|
+
belongs_to :machine
|
179
|
+
end
|
180
|
+
|
168
181
|
module Models
|
169
182
|
class Project
|
170
183
|
include DataMapper::Resource
|
@@ -227,6 +240,7 @@ if ADAPTER
|
|
227
240
|
|
228
241
|
belongs_to :galaxy
|
229
242
|
end
|
243
|
+
|
230
244
|
end
|
231
245
|
|
232
246
|
describe DataMapper::Associations do
|
@@ -274,6 +288,7 @@ if ADAPTER
|
|
274
288
|
before do
|
275
289
|
Machine.auto_migrate!(ADAPTER)
|
276
290
|
Area.auto_migrate!(ADAPTER)
|
291
|
+
MadeUpThing.auto_migrate!(ADAPTER)
|
277
292
|
|
278
293
|
machine1 = Machine.create(:name => 'machine1')
|
279
294
|
machine2 = Machine.create(:name => 'machine2')
|
@@ -299,10 +314,9 @@ if ADAPTER
|
|
299
314
|
end
|
300
315
|
|
301
316
|
it 'should save both the object and parent if both are new' do
|
302
|
-
pending "This is fixed"
|
303
317
|
area1 = Area.new(:name => 'area1')
|
304
318
|
area1.machine = Machine.new(:name => 'machine1')
|
305
|
-
area1.
|
319
|
+
area1.save
|
306
320
|
area1.machine_id.should == area1.machine.id
|
307
321
|
end
|
308
322
|
|
@@ -338,6 +352,16 @@ if ADAPTER
|
|
338
352
|
Area.new(:machine => machine).machine_id.should == machine.id
|
339
353
|
end
|
340
354
|
|
355
|
+
it "should be able to set an association obtained from another association" do
|
356
|
+
machine1 = Machine.first(:name => 'machine1')
|
357
|
+
area1 = Area.first(:name => 'area1')
|
358
|
+
area1.machine = machine1
|
359
|
+
|
360
|
+
m = MadeUpThing.create(:machine => area1.machine, :name => "Weird")
|
361
|
+
|
362
|
+
m.machine_id.should == machine1.id
|
363
|
+
end
|
364
|
+
|
341
365
|
it 'should save the parent upon saving of child' do
|
342
366
|
e = Machine.new(:name => 'machine10')
|
343
367
|
y = Area.create(:name => 'area10', :machine => e)
|
@@ -346,6 +370,13 @@ if ADAPTER
|
|
346
370
|
Machine.first(:name => 'machine10').should_not be_nil
|
347
371
|
end
|
348
372
|
|
373
|
+
it 'should set and retrieve associations on not yet saved objects' do
|
374
|
+
e = Machine.create(:name => 'machine10')
|
375
|
+
y = e.areas.build(:name => 'area10')
|
376
|
+
|
377
|
+
y.machine.name.should == 'machine10'
|
378
|
+
end
|
379
|
+
|
349
380
|
it 'should convert NULL parent ids into nils' do
|
350
381
|
Area.first(:name => 'area2').machine.should be_nil
|
351
382
|
end
|
@@ -379,6 +410,17 @@ if ADAPTER
|
|
379
410
|
|
380
411
|
lambda { y.reload }.should_not raise_error
|
381
412
|
end
|
413
|
+
|
414
|
+
it "should have machine when created using machine_id" do
|
415
|
+
m = Machine.create(:name => 'machineX')
|
416
|
+
a = Area.new(:machine_id => m.id)
|
417
|
+
a.machine.should == m
|
418
|
+
end
|
419
|
+
|
420
|
+
it "should not have a machine when orphaned" do
|
421
|
+
a = Area.new(:machine_id => 42)
|
422
|
+
a.machine.should be_nil
|
423
|
+
end
|
382
424
|
end
|
383
425
|
|
384
426
|
describe 'one to one associations' do
|
@@ -697,7 +739,7 @@ if ADAPTER
|
|
697
739
|
end
|
698
740
|
property :id, Serial
|
699
741
|
property :name, String
|
700
|
-
belongs_to :shop
|
742
|
+
belongs_to :shop
|
701
743
|
has 1, :wife
|
702
744
|
has n, :children
|
703
745
|
has n, :toys, :through => :children
|
@@ -1178,18 +1220,19 @@ if ADAPTER
|
|
1178
1220
|
@li = LeftItem.new(:name => "li#{number}")
|
1179
1221
|
end
|
1180
1222
|
|
1181
|
-
it "should add to the
|
1182
|
-
pending "Waiting on Many To Many to be implemented"
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1223
|
+
it "should add to the association from the left" do
|
1224
|
+
pending "Waiting on Many To Many to be implemented" do
|
1225
|
+
create_item_pair "0000"
|
1226
|
+
@ri.save; @li.save
|
1227
|
+
@ri.should_not be_new_record
|
1228
|
+
@li.should_not be_new_record
|
1187
1229
|
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1230
|
+
@li.right_items << @ri
|
1231
|
+
@li.right_items.should include(@ri)
|
1232
|
+
@li.reload
|
1233
|
+
@ri.reload
|
1234
|
+
@li.right_items.should include(@ri)
|
1235
|
+
end
|
1193
1236
|
end
|
1194
1237
|
|
1195
1238
|
it "should add to the association from the right" do
|
@@ -1205,93 +1248,100 @@ if ADAPTER
|
|
1205
1248
|
@ri.left_items.should include(@li)
|
1206
1249
|
end
|
1207
1250
|
|
1208
|
-
it "should load the
|
1209
|
-
pending "Waiting on Many To Many to be implemented"
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1251
|
+
it "should load the associated collection from the either side" do
|
1252
|
+
pending "Waiting on Many To Many to be implemented" do
|
1253
|
+
create_item_pair "0020"
|
1254
|
+
@ri.save; @li.save
|
1255
|
+
@ri.left_items << @li
|
1256
|
+
@ri.reload; @li.reload
|
1214
1257
|
|
1215
|
-
|
1216
|
-
|
1258
|
+
@ri.left_items.should include(@li)
|
1259
|
+
@li.right_items.should include(@ri)
|
1260
|
+
end
|
1217
1261
|
end
|
1218
1262
|
|
1219
|
-
it "should load the
|
1220
|
-
pending "Waiting on Many To Many to be implemented"
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
@ri.left_items.should include(@li)
|
1227
|
-
@li.right_items.should include(@ri)
|
1263
|
+
it "should load the associated collection from the right" do
|
1264
|
+
pending "Waiting on Many To Many to be implemented" do
|
1265
|
+
create_item_pair "0030"
|
1266
|
+
@ri.save; @li.save
|
1267
|
+
@li.right_items << @li
|
1268
|
+
@ri.reload; @li.reload
|
1228
1269
|
|
1270
|
+
@ri.left_items.should include(@li)
|
1271
|
+
@li.right_items.should include(@ri)
|
1272
|
+
end
|
1229
1273
|
end
|
1230
1274
|
|
1231
1275
|
it "should save the left side of the association if new record" do
|
1232
|
-
pending "Waiting on Many To Many to be implemented"
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1276
|
+
pending "Waiting on Many To Many to be implemented" do
|
1277
|
+
create_item_pair "0040"
|
1278
|
+
@ri.save
|
1279
|
+
@li.should be_new_record
|
1280
|
+
@ri.left_items << @li
|
1281
|
+
@li.should_not be_new_record
|
1282
|
+
end
|
1238
1283
|
end
|
1239
1284
|
|
1240
|
-
it "should save the right side of the
|
1241
|
-
pending "Waiting on Many To Many to be implemented"
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1285
|
+
it "should save the right side of the association if new record" do
|
1286
|
+
pending "Waiting on Many To Many to be implemented" do
|
1287
|
+
create_item_pair "0050"
|
1288
|
+
@li.save
|
1289
|
+
@ri.should be_new_record
|
1290
|
+
@li.right_items << @ri
|
1291
|
+
@ri.should_not be_new_record
|
1292
|
+
end
|
1247
1293
|
end
|
1248
1294
|
|
1249
|
-
it "should save both side of the
|
1250
|
-
pending "Waiting on Many To Many to be implemented"
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1295
|
+
it "should save both side of the association if new record" do
|
1296
|
+
pending "Waiting on Many To Many to be implemented" do
|
1297
|
+
create_item_pair "0060"
|
1298
|
+
@li.should be_new_record
|
1299
|
+
@ri.should be_new_record
|
1300
|
+
@ri.left_items << @li
|
1301
|
+
@ri.should_not be_new_record
|
1302
|
+
@li.should_not be_new_record
|
1303
|
+
end
|
1257
1304
|
end
|
1258
1305
|
|
1259
1306
|
it "should remove an item from the left collection without destroying the item" do
|
1260
|
-
pending "Waiting on Many To Many to be implemented"
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1307
|
+
pending "Waiting on Many To Many to be implemented" do
|
1308
|
+
create_item_pair "0070"
|
1309
|
+
@li.save; @ri.save
|
1310
|
+
@ri.left_items << @li
|
1311
|
+
@ri.reload; @li.reload
|
1312
|
+
@ri.left_items.should include(@li)
|
1313
|
+
@ri.left_items.delete(@li)
|
1314
|
+
@ri.left_items.should_not include(@li)
|
1315
|
+
@li.reload
|
1316
|
+
LeftItem.get(@li.id).should_not be_nil
|
1317
|
+
end
|
1270
1318
|
end
|
1271
1319
|
|
1272
1320
|
it "should remove an item from the right collection without destroying the item" do
|
1273
|
-
pending "Waiting on Many To Many to be implemented"
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1321
|
+
pending "Waiting on Many To Many to be implemented" do
|
1322
|
+
create_item_pair "0080"
|
1323
|
+
@li.save; @ri.save
|
1324
|
+
@li.right_items << @ri
|
1325
|
+
@li.reload; @ri.reload
|
1326
|
+
@li.right_items.should include(@ri)
|
1327
|
+
@li.right_items.delete(@ri)
|
1328
|
+
@li.right_items.should_not include(@ri)
|
1329
|
+
@ri.reload
|
1330
|
+
RightItem.get(@ri.id).should_not be_nil
|
1331
|
+
end
|
1283
1332
|
end
|
1284
1333
|
|
1285
1334
|
it "should remove the item from the collection when an item is deleted" do
|
1286
|
-
pending "Waiting on Many To Many to be implemented"
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1335
|
+
pending "Waiting on Many To Many to be implemented" do
|
1336
|
+
create_item_pair "0090"
|
1337
|
+
@li.save; @ri.save
|
1338
|
+
@ri.left_items << @li
|
1339
|
+
@ri.reload; @li.reload
|
1340
|
+
@ri.left_items.should include(@li)
|
1341
|
+
@li.destroy
|
1342
|
+
@ri.reload
|
1343
|
+
@ri.left_items.should_not include(@li)
|
1344
|
+
end
|
1295
1345
|
end
|
1296
1346
|
end
|
1297
1347
|
end
|