tenacity 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/EXTEND.rdoc +9 -13
- data/Rakefile +6 -0
- data/history.txt +17 -0
- data/lib/tenacity.rb +13 -9
- data/lib/tenacity/associate_proxy.rb +56 -0
- data/lib/tenacity/associates_proxy.rb +5 -3
- data/lib/tenacity/association.rb +81 -9
- data/lib/tenacity/associations/belongs_to.rb +28 -16
- data/lib/tenacity/associations/has_many.rb +113 -53
- data/lib/tenacity/associations/has_one.rb +33 -14
- data/lib/tenacity/class_methods.rb +117 -9
- data/lib/tenacity/errors.rb +9 -0
- data/lib/tenacity/instance_methods.rb +40 -3
- data/lib/tenacity/orm_ext/activerecord.rb +114 -95
- data/lib/tenacity/orm_ext/couchrest.rb +132 -113
- data/lib/tenacity/orm_ext/datamapper.rb +138 -112
- data/lib/tenacity/orm_ext/helpers.rb +36 -0
- data/lib/tenacity/orm_ext/mongo_mapper.rb +102 -84
- data/lib/tenacity/orm_ext/mongoid.rb +106 -87
- data/lib/tenacity/orm_ext/sequel.rb +137 -110
- data/lib/tenacity/version.rb +1 -1
- data/tenacity.gemspec +2 -1
- data/test/association_features/belongs_to_test.rb +46 -1
- data/test/association_features/has_many_test.rb +187 -2
- data/test/association_features/has_one_test.rb +57 -2
- data/test/associations/belongs_to_test.rb +41 -7
- data/test/associations/has_many_test.rb +59 -10
- data/test/associations/has_one_test.rb +57 -2
- data/test/fixtures/active_record_car.rb +5 -4
- data/test/fixtures/active_record_climate_control_unit.rb +1 -0
- data/test/fixtures/active_record_engine.rb +1 -0
- data/test/fixtures/active_record_has_many_target.rb +7 -0
- data/test/fixtures/active_record_has_one_target.rb +7 -0
- data/test/fixtures/active_record_object.rb +19 -0
- data/test/fixtures/couch_rest_has_many_target.rb +7 -0
- data/test/fixtures/couch_rest_has_one_target.rb +7 -0
- data/test/fixtures/couch_rest_object.rb +14 -0
- data/test/fixtures/data_mapper_has_many_target.rb +23 -3
- data/test/fixtures/data_mapper_has_one_target.rb +23 -3
- data/test/fixtures/data_mapper_object.rb +14 -0
- data/test/fixtures/mongo_mapper_air_filter.rb +6 -0
- data/test/fixtures/mongo_mapper_alternator.rb +7 -0
- data/test/fixtures/mongo_mapper_autosave_false_has_many_target.rb +8 -0
- data/test/fixtures/mongo_mapper_autosave_false_has_one_target.rb +8 -0
- data/test/fixtures/mongo_mapper_autosave_true_has_many_target.rb +8 -0
- data/test/fixtures/mongo_mapper_autosave_true_has_one_target.rb +8 -0
- data/test/fixtures/mongo_mapper_circuit_board.rb +6 -0
- data/test/fixtures/mongo_mapper_dashboard.rb +5 -2
- data/test/fixtures/mongo_mapper_has_many_target.rb +7 -0
- data/test/fixtures/mongo_mapper_has_one_target.rb +7 -0
- data/test/fixtures/mongo_mapper_object.rb +14 -0
- data/test/fixtures/mongo_mapper_wheel.rb +2 -0
- data/test/fixtures/mongo_mapper_windows.rb +6 -0
- data/test/fixtures/mongoid_has_many_target.rb +7 -0
- data/test/fixtures/mongoid_has_one_target.rb +7 -0
- data/test/fixtures/mongoid_object.rb +14 -0
- data/test/fixtures/sequel_has_many_target.rb +7 -0
- data/test/fixtures/sequel_has_one_target.rb +7 -0
- data/test/fixtures/sequel_object.rb +14 -0
- data/test/helpers/active_record_test_helper.rb +87 -8
- data/test/helpers/couch_rest_test_helper.rb +7 -0
- data/test/helpers/data_mapper_test_helper.rb +41 -3
- data/test/helpers/sequel_test_helper.rb +65 -9
- data/test/orm_ext/activerecord_test.rb +1 -1
- data/test/orm_ext/datamapper_test.rb +33 -24
- data/test/orm_ext/mongo_mapper_test.rb +6 -6
- data/test/orm_ext/mongoid_test.rb +6 -6
- data/test/orm_ext/sequel_test.rb +1 -1
- data/test/test_helper.rb +18 -9
- metadata +119 -55
@@ -1,134 +1,161 @@
|
|
1
1
|
module Tenacity
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
model.
|
50
|
-
|
2
|
+
module OrmExt
|
3
|
+
# Tenacity relationships on Sequel objects require that certain columns
|
4
|
+
# exist on the associated table, and that join tables exist for one-to-many
|
5
|
+
# relationships. Take the following class for example:
|
6
|
+
#
|
7
|
+
# class Car < Sequel::Model
|
8
|
+
# include Tenacity
|
9
|
+
#
|
10
|
+
# t_has_many :wheels
|
11
|
+
# t_has_one :dashboard
|
12
|
+
# t_belongs_to :driver
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# == t_belongs_to
|
17
|
+
#
|
18
|
+
# The +t_belongs_to+ association requires that a property exist in the table
|
19
|
+
# to hold the id of the assoicated object.
|
20
|
+
#
|
21
|
+
# DB.create_table :cars do
|
22
|
+
# primary_key :id
|
23
|
+
# String :driver_id
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# == t_has_one
|
28
|
+
#
|
29
|
+
# The +t_has_one+ association requires no special column in the table, since
|
30
|
+
# the associated object holds the foreign key.
|
31
|
+
#
|
32
|
+
#
|
33
|
+
# == t_has_many
|
34
|
+
#
|
35
|
+
# The +t_has_many+ association requires that a join table exist to store the
|
36
|
+
# associations. The name of the join table follows ActiveRecord conventions.
|
37
|
+
# The name of the join table in this example would be cars_wheels, since cars
|
38
|
+
# comes before wheels when shorted alphabetically.
|
39
|
+
#
|
40
|
+
# DB.create_table :cars_wheels do
|
41
|
+
# Integer :car_id
|
42
|
+
# String :wheel_id
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
module Sequel
|
46
|
+
|
47
|
+
def self.setup(model)
|
48
|
+
require 'sequel'
|
49
|
+
if model.ancestors.include?(::Sequel::Model)
|
50
|
+
model.send :include, Sequel::InstanceMethods
|
51
|
+
model.extend Sequel::ClassMethods
|
52
|
+
end
|
53
|
+
rescue LoadError
|
54
|
+
# Sequel not available
|
51
55
|
end
|
52
|
-
rescue LoadError
|
53
|
-
# Sequel not available
|
54
|
-
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
attr_accessor :_t_belongs_to_associations
|
57
|
+
module ClassMethods #:nodoc:
|
58
|
+
include Tenacity::OrmExt::Helpers
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
attr_accessor :_t_has_one_associations
|
61
|
+
attr_accessor :_t_has_many_associations
|
62
|
+
attr_accessor :_t_belongs_to_associations
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
64
|
+
def _t_id_type
|
65
|
+
Integer
|
66
|
+
end
|
68
67
|
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
def _t_find(id)
|
69
|
+
self[_t_serialize(id)]
|
70
|
+
end
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
def _t_find_bulk(ids)
|
73
|
+
return [] if ids.nil? || ids.empty?
|
74
|
+
filter(:id => _t_serialize_ids(ids)).to_a
|
75
|
+
end
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
77
|
+
def _t_find_first_by_associate(property, id)
|
78
|
+
first(property.to_sym => _t_serialize(id))
|
79
|
+
end
|
81
80
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
81
|
+
def _t_find_all_by_associate(property, id)
|
82
|
+
filter(property => _t_serialize(id)).to_a
|
83
|
+
end
|
86
84
|
|
87
|
-
|
88
|
-
if run_callbacks
|
89
|
-
filter(:id => ids).destroy
|
90
|
-
else
|
91
|
-
filter(:id => ids).delete
|
85
|
+
def _t_initialize_tenacity
|
92
86
|
end
|
93
|
-
end
|
94
|
-
end
|
95
87
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
super
|
101
|
-
end
|
88
|
+
def _t_initialize_has_one_association(association)
|
89
|
+
@_t_has_one_associations ||= []
|
90
|
+
@_t_has_one_associations << association
|
91
|
+
end
|
102
92
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
93
|
+
def _t_initialize_has_many_association(association)
|
94
|
+
@_t_has_many_associations ||= []
|
95
|
+
@_t_has_many_associations << association
|
96
|
+
end
|
108
97
|
|
109
|
-
|
110
|
-
|
111
|
-
|
98
|
+
def _t_initialize_belongs_to_association(association)
|
99
|
+
@_t_belongs_to_associations ||= []
|
100
|
+
@_t_belongs_to_associations << association
|
101
|
+
end
|
112
102
|
|
113
|
-
|
114
|
-
|
103
|
+
def _t_delete(ids, run_callbacks=true)
|
104
|
+
if run_callbacks
|
105
|
+
filter(:id => _t_serialize_ids(ids)).destroy
|
106
|
+
else
|
107
|
+
filter(:id => _t_serialize_ids(ids)).delete
|
108
|
+
end
|
109
|
+
end
|
115
110
|
end
|
116
111
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
112
|
+
module InstanceMethods #:nodoc:
|
113
|
+
include Tenacity::OrmExt::Helpers
|
114
|
+
|
115
|
+
def after_save
|
116
|
+
_t_save_autosave_associations
|
117
|
+
|
118
|
+
associations = self.class._t_has_many_associations || []
|
119
|
+
associations.each { |association| self.class._t_save_associates(self, association) }
|
120
|
+
super
|
121
|
+
end
|
122
|
+
|
123
|
+
def after_destroy
|
124
|
+
associations = self.class._t_belongs_to_associations || []
|
125
|
+
associations.each { |association| self._t_cleanup_belongs_to_association(association) }
|
126
|
+
|
127
|
+
associations = self.class._t_has_one_associations || []
|
128
|
+
associations.each { |association| self._t_cleanup_has_one_association(association) }
|
129
|
+
|
130
|
+
associations = self.class._t_has_many_associations || []
|
131
|
+
associations.each { |association| self._t_cleanup_has_many_association(association) }
|
132
|
+
super
|
133
|
+
end
|
134
|
+
|
135
|
+
def _t_reload
|
136
|
+
reload
|
137
|
+
end
|
138
|
+
|
139
|
+
def _t_clear_associates(association)
|
140
|
+
db["delete from #{association.join_table} where #{association.association_key} = #{_t_serialize_id_for_sql(self.id)}"].delete
|
141
|
+
end
|
142
|
+
|
143
|
+
def _t_associate_many(association, associate_ids)
|
144
|
+
db.transaction do
|
145
|
+
_t_clear_associates(association)
|
146
|
+
associate_ids.each do |associate_id|
|
147
|
+
db["insert into #{association.join_table} (#{association.association_key}, #{association.association_foreign_key}) values (#{_t_serialize_id_for_sql(self.id)}, #{_t_serialize_id_for_sql(associate_id)})"].insert
|
148
|
+
end
|
122
149
|
end
|
123
150
|
end
|
124
|
-
end
|
125
151
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
152
|
+
def _t_get_associate_ids(association)
|
153
|
+
return [] if self.id.nil?
|
154
|
+
rows = db["select #{association.association_foreign_key} from #{association.join_table} where #{association.association_key} = #{_t_serialize_id_for_sql(self.id)}"].all
|
155
|
+
rows.map { |row| row[association.association_foreign_key.to_sym] }
|
156
|
+
end
|
130
157
|
end
|
131
|
-
end
|
132
158
|
|
159
|
+
end
|
133
160
|
end
|
134
161
|
end
|
data/lib/tenacity/version.rb
CHANGED
data/tenacity.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_development_dependency "rake", "~> 0.8.7"
|
23
23
|
s.add_development_dependency "rcov", "~> 0.9.9"
|
24
24
|
s.add_development_dependency "shoulda", "~> 2.11.3"
|
25
|
+
s.add_development_dependency "mocha", "~> 0.9.10"
|
25
26
|
s.add_development_dependency "yard", "~> 0.6.4"
|
26
27
|
|
27
28
|
# Relational DBs
|
@@ -33,7 +34,7 @@ Gem::Specification.new do |s|
|
|
33
34
|
|
34
35
|
# MongoDB
|
35
36
|
s.add_development_dependency "mongo_mapper", "~> 0.8.6"
|
36
|
-
s.add_development_dependency "bson_ext", "~> 1.
|
37
|
+
s.add_development_dependency "bson_ext", "~> 1.2.4"
|
37
38
|
s.add_development_dependency "mongoid", "~> 2.0.0.beta"
|
38
39
|
|
39
40
|
# CouchDB
|
@@ -30,13 +30,58 @@ class BelongsToTest < Test::Unit::TestCase
|
|
30
30
|
should "be able to specify the foreign key to use for the associated class" do
|
31
31
|
car = ActiveRecordCar.create
|
32
32
|
windshield = CouchRestWindshield.create(:active_record_car => car)
|
33
|
-
assert_equal car.id
|
33
|
+
assert_equal car.id, windshield.car_id
|
34
34
|
assert !windshield.respond_to?(:active_record_car_id)
|
35
35
|
|
36
36
|
engine = ActiveRecordEngine.create(:active_record_car => car)
|
37
37
|
assert_equal car.id, engine.car_id
|
38
38
|
assert !engine.respond_to?(:active_record_car_id)
|
39
39
|
end
|
40
|
+
|
41
|
+
should "not be able to modify the associated object if the readonly option is set" do
|
42
|
+
engine = ActiveRecordEngine.create
|
43
|
+
air_filter = MongoMapperAirFilter.create(:active_record_engine => engine)
|
44
|
+
engine = air_filter.active_record_engine
|
45
|
+
engine.prop = "value"
|
46
|
+
assert_raises(Tenacity::ReadOnlyError) { engine.save }
|
47
|
+
end
|
48
|
+
|
49
|
+
should "save the associated object if autosave is true" do
|
50
|
+
source = MongoMapperAutosaveTrueHasOneTarget.create
|
51
|
+
target = ActiveRecordObject.create(:prop => 'abc')
|
52
|
+
source.active_record_object = target
|
53
|
+
source.save
|
54
|
+
assert_equal 'abc', source.active_record_object.prop
|
55
|
+
|
56
|
+
source.active_record_object.prop = 'xyz'
|
57
|
+
source.save
|
58
|
+
source.reload && source.active_record_object(true)
|
59
|
+
assert_equal 'xyz', source.active_record_object.prop
|
60
|
+
end
|
61
|
+
|
62
|
+
should "destroy the associated object if autosave is true and object is marked for destruction" do
|
63
|
+
source = MongoMapperAutosaveTrueHasOneTarget.create
|
64
|
+
target = ActiveRecordObject.create
|
65
|
+
source.active_record_object = target
|
66
|
+
source.save
|
67
|
+
assert_not_nil source.active_record_object(true)
|
68
|
+
|
69
|
+
source.active_record_object.mark_for_destruction
|
70
|
+
assert source.active_record_object.marked_for_destruction?
|
71
|
+
source.save
|
72
|
+
source.reload
|
73
|
+
assert_nil source.active_record_object(true)
|
74
|
+
end
|
75
|
+
|
76
|
+
should "be able to create a polymorphic association" do
|
77
|
+
circuit_board = MongoMapperCircuitBoard.create
|
78
|
+
alternator = MongoMapperAlternator.create
|
79
|
+
circuit_board.diagnosable = alternator
|
80
|
+
circuit_board.save
|
81
|
+
|
82
|
+
assert_equal alternator, MongoMapperCircuitBoard.find(circuit_board.id).diagnosable
|
83
|
+
assert_equal 'MongoMapperAlternator', circuit_board.diagnosable_type
|
84
|
+
end
|
40
85
|
end
|
41
86
|
|
42
87
|
end
|
@@ -4,7 +4,7 @@ class HasManyTest < Test::Unit::TestCase
|
|
4
4
|
|
5
5
|
context "A class with a belongs_to association to another class" do
|
6
6
|
setup do
|
7
|
-
|
7
|
+
setup_all_fixtures
|
8
8
|
@car = ActiveRecordCar.create
|
9
9
|
@wheels = [MongoMapperWheel.create, MongoMapperWheel.create, MongoMapperWheel.create]
|
10
10
|
|
@@ -43,7 +43,7 @@ class HasManyTest < Test::Unit::TestCase
|
|
43
43
|
car.save
|
44
44
|
|
45
45
|
assert_set_equal [door_1, door_2, door_3], ActiveRecordCar.find(car.id).couch_rest_doors
|
46
|
-
assert_set_equal [door_1.id
|
46
|
+
assert_set_equal [door_1.id, door_2.id, door_3.id], ActiveRecordCar.find(car.id).couch_rest_door_ids
|
47
47
|
end
|
48
48
|
|
49
49
|
should "save the associate object when it is added as an associate if the parent object is saved" do
|
@@ -79,6 +79,113 @@ class HasManyTest < Test::Unit::TestCase
|
|
79
79
|
assert_set_equal [door_1], ActiveRecordCar.find(car.id).couch_rest_doors
|
80
80
|
end
|
81
81
|
|
82
|
+
should "not be able to modify an associated object if the readonly option is set" do
|
83
|
+
car = ActiveRecordCar.create
|
84
|
+
wheel_1 = MongoMapperWheel.create
|
85
|
+
wheel_2 = MongoMapperWheel.create
|
86
|
+
wheel_3 = MongoMapperWheel.create
|
87
|
+
car.mongo_mapper_wheels = [wheel_1, wheel_2, wheel_3]
|
88
|
+
car.save
|
89
|
+
|
90
|
+
wheel = car.mongo_mapper_wheels.first
|
91
|
+
wheel.prop = "value"
|
92
|
+
assert_raises(Tenacity::ReadOnlyError) { wheel.save }
|
93
|
+
end
|
94
|
+
|
95
|
+
should "only return the number of results specified by the :limit option" do
|
96
|
+
car = ActiveRecordCar.create
|
97
|
+
wheel_1 = MongoMapperWheel.create
|
98
|
+
wheel_2 = MongoMapperWheel.create
|
99
|
+
wheel_3 = MongoMapperWheel.create
|
100
|
+
wheel_4 = MongoMapperWheel.create
|
101
|
+
wheel_5 = MongoMapperWheel.create
|
102
|
+
wheel_6 = MongoMapperWheel.create
|
103
|
+
wheel_7 = MongoMapperWheel.create
|
104
|
+
wheel_8 = MongoMapperWheel.create
|
105
|
+
car.mongo_mapper_wheels = [wheel_1, wheel_2, wheel_3, wheel_4, wheel_5, wheel_6, wheel_7, wheel_8]
|
106
|
+
car.save
|
107
|
+
|
108
|
+
sorted_wheels = car.mongo_mapper_wheels.sort { |a,b| a.id.to_s <=> b.id.to_s }
|
109
|
+
sorted_wheel_ids = sorted_wheels.map { |wheel| wheel.id.to_s }
|
110
|
+
|
111
|
+
assert_set_equal [sorted_wheels[0], sorted_wheels[1], sorted_wheels[2], sorted_wheels[3], sorted_wheels[4]],
|
112
|
+
ActiveRecordCar.find(car.id).mongo_mapper_wheels
|
113
|
+
assert_set_equal [sorted_wheel_ids[0], sorted_wheel_ids[1], sorted_wheel_ids[2], sorted_wheel_ids[3], sorted_wheel_ids[4]],
|
114
|
+
ActiveRecordCar.find(car.id).mongo_mapper_wheel_ids
|
115
|
+
end
|
116
|
+
|
117
|
+
should "skip over the first group of results, as specified by the :offset option" do
|
118
|
+
car = ActiveRecordCar.create
|
119
|
+
window_1 = MongoMapperWindow.create
|
120
|
+
window_2 = MongoMapperWindow.create
|
121
|
+
window_3 = MongoMapperWindow.create
|
122
|
+
window_4 = MongoMapperWindow.create
|
123
|
+
window_5 = MongoMapperWindow.create
|
124
|
+
window_6 = MongoMapperWindow.create
|
125
|
+
window_7 = MongoMapperWindow.create
|
126
|
+
window_8 = MongoMapperWindow.create
|
127
|
+
window_9 = MongoMapperWindow.create
|
128
|
+
car.mongo_mapper_windows = [window_1, window_2, window_3, window_4, window_5, window_6, window_7, window_8, window_9]
|
129
|
+
car.save
|
130
|
+
|
131
|
+
sorted_windows = car.mongo_mapper_windows.sort { |a,b| a.id.to_s <=> b.id.to_s }
|
132
|
+
sorted_window_ids = sorted_windows.map { |window| window.id.to_s }
|
133
|
+
|
134
|
+
assert_set_equal [sorted_windows[3], sorted_windows[4], sorted_windows[5], sorted_windows[6], sorted_windows[7]],
|
135
|
+
ActiveRecordCar.find(car.id).mongo_mapper_windows
|
136
|
+
assert_set_equal [sorted_window_ids[3], sorted_window_ids[4], sorted_window_ids[5], sorted_window_ids[6], sorted_window_ids[7]],
|
137
|
+
ActiveRecordCar.find(car.id).mongo_mapper_window_ids
|
138
|
+
end
|
139
|
+
|
140
|
+
should "be able to store objects via their polymorphic interface" do
|
141
|
+
circuit_board_1 = MongoMapperCircuitBoard.create
|
142
|
+
circuit_board_2 = MongoMapperCircuitBoard.create
|
143
|
+
circuit_board_3 = MongoMapperCircuitBoard.create
|
144
|
+
engine = ActiveRecordEngine.create
|
145
|
+
engine.diagnosable = [circuit_board_1, circuit_board_2, circuit_board_3]
|
146
|
+
engine.save
|
147
|
+
|
148
|
+
components = ActiveRecordEngine.find(engine.id).diagnosable
|
149
|
+
assert_set_equal [circuit_board_1, circuit_board_2, circuit_board_3], components
|
150
|
+
assert_set_equal ['ActiveRecordEngine', 'ActiveRecordEngine', 'ActiveRecordEngine'], components.map {|c| c.diagnosable_type}
|
151
|
+
end
|
152
|
+
|
153
|
+
context "with an autosave association" do
|
154
|
+
setup do
|
155
|
+
@source = ActiveRecordObject.create
|
156
|
+
@targets = [MongoMapperAutosaveTrueHasManyTarget.create(:prop => 'abc'), MongoMapperAutosaveTrueHasManyTarget.create(:prop => 'def')]
|
157
|
+
@source.mongo_mapper_autosave_true_has_many_targets = @targets
|
158
|
+
@source.save
|
159
|
+
assert_equal 'abc', @source.mongo_mapper_autosave_true_has_many_targets(true).first.prop
|
160
|
+
end
|
161
|
+
|
162
|
+
should "save the associated object if autosave is true" do
|
163
|
+
@source.mongo_mapper_autosave_true_has_many_targets.first.prop = 'xyz'
|
164
|
+
@source.save
|
165
|
+
@source.reload && @source.mongo_mapper_autosave_true_has_many_targets(true)
|
166
|
+
assert_equal 'xyz', @source.mongo_mapper_autosave_true_has_many_targets.first.prop
|
167
|
+
end
|
168
|
+
|
169
|
+
should "destroy the associated object stored in a local variable if autosave is true and object is marked for destruction" do
|
170
|
+
object = @source.mongo_mapper_autosave_true_has_many_targets.first
|
171
|
+
object.mark_for_destruction
|
172
|
+
assert object.marked_for_destruction?
|
173
|
+
@source.save
|
174
|
+
@source.reload && @source.mongo_mapper_autosave_true_has_many_targets(true)
|
175
|
+
assert_equal 1, @source.mongo_mapper_autosave_true_has_many_targets.size
|
176
|
+
assert_equal 'def', @source.mongo_mapper_autosave_true_has_many_targets.first.prop
|
177
|
+
end
|
178
|
+
|
179
|
+
should "destroy the associated object if autosave is true and object is marked for destruction" do
|
180
|
+
@source.mongo_mapper_autosave_true_has_many_targets.first.mark_for_destruction
|
181
|
+
assert @source.mongo_mapper_autosave_true_has_many_targets.first.marked_for_destruction?
|
182
|
+
@source.save
|
183
|
+
@source.reload && @source.mongo_mapper_autosave_true_has_many_targets(true)
|
184
|
+
assert_equal 1, @source.mongo_mapper_autosave_true_has_many_targets.size
|
185
|
+
assert_equal 'def', @source.mongo_mapper_autosave_true_has_many_targets.first.prop
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
82
189
|
context "with a set of associates that need to be deleted" do
|
83
190
|
setup do
|
84
191
|
@new_car = ActiveRecordCar.create
|
@@ -104,6 +211,84 @@ class HasManyTest < Test::Unit::TestCase
|
|
104
211
|
assert_equal old_count - 3, CouchRestDoor.count
|
105
212
|
assert_set_equal [], ActiveRecordCar.find(@new_car.id).couch_rest_doors
|
106
213
|
end
|
214
|
+
|
215
|
+
context "the delete method" do
|
216
|
+
should "not delete the object from the database if no dependent option is specified" do
|
217
|
+
dashboard = MongoMapperDashboard.create
|
218
|
+
vent_1 = MongoMapperVent.create
|
219
|
+
vent_2 = MongoMapperVent.create
|
220
|
+
vent_3 = MongoMapperVent.create
|
221
|
+
dashboard.vents = [vent_1, vent_2, vent_3]
|
222
|
+
dashboard.save
|
223
|
+
assert_set_equal [vent_1, vent_2, vent_3], MongoMapperDashboard.find(dashboard.id).vents
|
224
|
+
|
225
|
+
dashboard.vents.delete(vent_1)
|
226
|
+
dashboard.save
|
227
|
+
assert_set_equal [vent_2, vent_3], MongoMapperDashboard.find(dashboard.id).vents
|
228
|
+
assert_not_nil MongoMapperVent.find(vent_1.id)
|
229
|
+
end
|
230
|
+
|
231
|
+
should "delete the associated object and issue callbacks if association is configured to :destroy dependents" do
|
232
|
+
wheel_1 = MongoMapperWheel.create
|
233
|
+
wheel_2 = MongoMapperWheel.create
|
234
|
+
wheel_3 = MongoMapperWheel.create
|
235
|
+
@new_car.mongo_mapper_wheels = [wheel_1, wheel_2, wheel_3]
|
236
|
+
@new_car.save
|
237
|
+
assert_set_equal [wheel_1, wheel_2, wheel_3], ActiveRecordCar.find(@new_car.id).mongo_mapper_wheels
|
238
|
+
|
239
|
+
@new_car.mongo_mapper_wheels.delete(wheel_1)
|
240
|
+
@new_car.save
|
241
|
+
assert_set_equal [wheel_2, wheel_3], ActiveRecordCar.find(@new_car.id).mongo_mapper_wheels
|
242
|
+
assert_nil MongoMapperWheel._t_find(wheel_1.id)
|
243
|
+
end
|
244
|
+
|
245
|
+
should "delete the associated object without issuing callbacks if association is configured to :delete_all dependents" do
|
246
|
+
@new_car.couch_rest_doors.delete(@door_1)
|
247
|
+
@new_car.save
|
248
|
+
assert_set_equal [@door_2, @door_3], ActiveRecordCar.find(@new_car.id).couch_rest_doors
|
249
|
+
assert_nil CouchRestDoor._t_find(@door_1.id)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context "the clear method" do
|
254
|
+
should "not delete the object from the database if no dependent option is specified" do
|
255
|
+
dashboard = MongoMapperDashboard.create
|
256
|
+
vent_1 = MongoMapperVent.create
|
257
|
+
vent_2 = MongoMapperVent.create
|
258
|
+
dashboard.vents = [vent_1, vent_2]
|
259
|
+
dashboard.save
|
260
|
+
assert_set_equal [vent_1, vent_2], MongoMapperDashboard.find(dashboard.id).vents
|
261
|
+
|
262
|
+
dashboard.vents.clear
|
263
|
+
dashboard.save
|
264
|
+
assert_set_equal [], MongoMapperDashboard.find(dashboard.id).vents
|
265
|
+
assert_not_nil MongoMapperVent.find(vent_1.id)
|
266
|
+
assert_not_nil MongoMapperVent.find(vent_2.id)
|
267
|
+
end
|
268
|
+
|
269
|
+
should "delete the associated object and issue callbacks if association is configured to :destroy dependents" do
|
270
|
+
wheel_1 = MongoMapperWheel.create
|
271
|
+
wheel_2 = MongoMapperWheel.create
|
272
|
+
@new_car.mongo_mapper_wheels = [wheel_1, wheel_2]
|
273
|
+
@new_car.save
|
274
|
+
assert_set_equal [wheel_1, wheel_2], ActiveRecordCar.find(@new_car.id).mongo_mapper_wheels
|
275
|
+
|
276
|
+
@new_car.mongo_mapper_wheels.clear
|
277
|
+
@new_car.save
|
278
|
+
assert_set_equal [], ActiveRecordCar.find(@new_car.id).mongo_mapper_wheels
|
279
|
+
assert_nil MongoMapperWheel._t_find(wheel_1.id)
|
280
|
+
assert_nil MongoMapperWheel._t_find(wheel_2.id)
|
281
|
+
end
|
282
|
+
|
283
|
+
should "delete the associated object without issuing callbacks if association is configured to :delete_all dependents" do
|
284
|
+
@new_car.couch_rest_doors.clear
|
285
|
+
@new_car.save
|
286
|
+
assert_set_equal [], ActiveRecordCar.find(@new_car.id).couch_rest_doors
|
287
|
+
assert_nil CouchRestDoor._t_find(@door_1.id)
|
288
|
+
assert_nil CouchRestDoor._t_find(@door_2.id)
|
289
|
+
assert_nil CouchRestDoor._t_find(@door_3.id)
|
290
|
+
end
|
291
|
+
end
|
107
292
|
end
|
108
293
|
end
|
109
294
|
|