dm-core 0.9.3 → 0.9.4
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/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
|