tenacity 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/EXTEND.rdoc +9 -13
  2. data/Rakefile +6 -0
  3. data/history.txt +17 -0
  4. data/lib/tenacity.rb +13 -9
  5. data/lib/tenacity/associate_proxy.rb +56 -0
  6. data/lib/tenacity/associates_proxy.rb +5 -3
  7. data/lib/tenacity/association.rb +81 -9
  8. data/lib/tenacity/associations/belongs_to.rb +28 -16
  9. data/lib/tenacity/associations/has_many.rb +113 -53
  10. data/lib/tenacity/associations/has_one.rb +33 -14
  11. data/lib/tenacity/class_methods.rb +117 -9
  12. data/lib/tenacity/errors.rb +9 -0
  13. data/lib/tenacity/instance_methods.rb +40 -3
  14. data/lib/tenacity/orm_ext/activerecord.rb +114 -95
  15. data/lib/tenacity/orm_ext/couchrest.rb +132 -113
  16. data/lib/tenacity/orm_ext/datamapper.rb +138 -112
  17. data/lib/tenacity/orm_ext/helpers.rb +36 -0
  18. data/lib/tenacity/orm_ext/mongo_mapper.rb +102 -84
  19. data/lib/tenacity/orm_ext/mongoid.rb +106 -87
  20. data/lib/tenacity/orm_ext/sequel.rb +137 -110
  21. data/lib/tenacity/version.rb +1 -1
  22. data/tenacity.gemspec +2 -1
  23. data/test/association_features/belongs_to_test.rb +46 -1
  24. data/test/association_features/has_many_test.rb +187 -2
  25. data/test/association_features/has_one_test.rb +57 -2
  26. data/test/associations/belongs_to_test.rb +41 -7
  27. data/test/associations/has_many_test.rb +59 -10
  28. data/test/associations/has_one_test.rb +57 -2
  29. data/test/fixtures/active_record_car.rb +5 -4
  30. data/test/fixtures/active_record_climate_control_unit.rb +1 -0
  31. data/test/fixtures/active_record_engine.rb +1 -0
  32. data/test/fixtures/active_record_has_many_target.rb +7 -0
  33. data/test/fixtures/active_record_has_one_target.rb +7 -0
  34. data/test/fixtures/active_record_object.rb +19 -0
  35. data/test/fixtures/couch_rest_has_many_target.rb +7 -0
  36. data/test/fixtures/couch_rest_has_one_target.rb +7 -0
  37. data/test/fixtures/couch_rest_object.rb +14 -0
  38. data/test/fixtures/data_mapper_has_many_target.rb +23 -3
  39. data/test/fixtures/data_mapper_has_one_target.rb +23 -3
  40. data/test/fixtures/data_mapper_object.rb +14 -0
  41. data/test/fixtures/mongo_mapper_air_filter.rb +6 -0
  42. data/test/fixtures/mongo_mapper_alternator.rb +7 -0
  43. data/test/fixtures/mongo_mapper_autosave_false_has_many_target.rb +8 -0
  44. data/test/fixtures/mongo_mapper_autosave_false_has_one_target.rb +8 -0
  45. data/test/fixtures/mongo_mapper_autosave_true_has_many_target.rb +8 -0
  46. data/test/fixtures/mongo_mapper_autosave_true_has_one_target.rb +8 -0
  47. data/test/fixtures/mongo_mapper_circuit_board.rb +6 -0
  48. data/test/fixtures/mongo_mapper_dashboard.rb +5 -2
  49. data/test/fixtures/mongo_mapper_has_many_target.rb +7 -0
  50. data/test/fixtures/mongo_mapper_has_one_target.rb +7 -0
  51. data/test/fixtures/mongo_mapper_object.rb +14 -0
  52. data/test/fixtures/mongo_mapper_wheel.rb +2 -0
  53. data/test/fixtures/mongo_mapper_windows.rb +6 -0
  54. data/test/fixtures/mongoid_has_many_target.rb +7 -0
  55. data/test/fixtures/mongoid_has_one_target.rb +7 -0
  56. data/test/fixtures/mongoid_object.rb +14 -0
  57. data/test/fixtures/sequel_has_many_target.rb +7 -0
  58. data/test/fixtures/sequel_has_one_target.rb +7 -0
  59. data/test/fixtures/sequel_object.rb +14 -0
  60. data/test/helpers/active_record_test_helper.rb +87 -8
  61. data/test/helpers/couch_rest_test_helper.rb +7 -0
  62. data/test/helpers/data_mapper_test_helper.rb +41 -3
  63. data/test/helpers/sequel_test_helper.rb +65 -9
  64. data/test/orm_ext/activerecord_test.rb +1 -1
  65. data/test/orm_ext/datamapper_test.rb +33 -24
  66. data/test/orm_ext/mongo_mapper_test.rb +6 -6
  67. data/test/orm_ext/mongoid_test.rb +6 -6
  68. data/test/orm_ext/sequel_test.rb +1 -1
  69. data/test/test_helper.rb +18 -9
  70. metadata +119 -55
@@ -1,134 +1,161 @@
1
1
  module Tenacity
2
- # Tenacity relationships on Sequel objects require that certain columns
3
- # exist on the associated table, and that join tables exist for one-to-many
4
- # relationships. Take the following class for example:
5
- #
6
- # class Car < Sequel::Model
7
- # include Tenacity
8
- #
9
- # t_has_many :wheels
10
- # t_has_one :dashboard
11
- # t_belongs_to :driver
12
- # end
13
- #
14
- #
15
- # == t_belongs_to
16
- #
17
- # The +t_belongs_to+ association requires that a property exist in the table
18
- # to hold the id of the assoicated object.
19
- #
20
- # DB.create_table :cars do
21
- # primary_key :id
22
- # String :driver_id
23
- # end
24
- #
25
- #
26
- # == t_has_one
27
- #
28
- # The +t_has_one+ association requires no special column in the table, since
29
- # the associated object holds the foreign key.
30
- #
31
- #
32
- # == t_has_many
33
- #
34
- # The +t_has_many+ association requires that a join table exist to store the
35
- # associations. The name of the join table follows ActiveRecord conventions.
36
- # The name of the join table in this example would be cars_wheels, since cars
37
- # comes before wheels when shorted alphabetically.
38
- #
39
- # DB.create_table :cars_wheels do
40
- # Integer :car_id
41
- # String :wheel_id
42
- # end
43
- #
44
- module Sequel
45
-
46
- def self.setup(model)
47
- require 'sequel'
48
- if model.ancestors.include?(::Sequel::Model)
49
- model.send :include, Sequel::InstanceMethods
50
- model.extend Sequel::ClassMethods
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
- module ClassMethods #:nodoc:
57
- attr_accessor :_t_has_many_associations
58
- attr_accessor :_t_belongs_to_associations
57
+ module ClassMethods #:nodoc:
58
+ include Tenacity::OrmExt::Helpers
59
59
 
60
- def _t_find(id)
61
- self[id]
62
- end
60
+ attr_accessor :_t_has_one_associations
61
+ attr_accessor :_t_has_many_associations
62
+ attr_accessor :_t_belongs_to_associations
63
63
 
64
- def _t_find_bulk(ids)
65
- return [] if ids.nil? || ids.empty?
66
- filter(:id => ids)
67
- end
64
+ def _t_id_type
65
+ Integer
66
+ end
68
67
 
69
- def _t_find_first_by_associate(property, id)
70
- first(property.to_sym => id)
71
- end
68
+ def _t_find(id)
69
+ self[_t_serialize(id)]
70
+ end
72
71
 
73
- def _t_find_all_by_associate(property, id)
74
- filter(property => id)
75
- end
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
- def _t_initialize_has_many_association(association)
78
- @_t_has_many_associations ||= []
79
- @_t_has_many_associations << association
80
- end
77
+ def _t_find_first_by_associate(property, id)
78
+ first(property.to_sym => _t_serialize(id))
79
+ end
81
80
 
82
- def _t_initialize_belongs_to_association(association)
83
- @_t_belongs_to_associations ||= []
84
- @_t_belongs_to_associations << association
85
- end
81
+ def _t_find_all_by_associate(property, id)
82
+ filter(property => _t_serialize(id)).to_a
83
+ end
86
84
 
87
- def _t_delete(ids, run_callbacks=true)
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
- module InstanceMethods #:nodoc:
97
- def before_save
98
- associations = self.class._t_belongs_to_associations || []
99
- associations.each { |association| self.class._t_stringify_belongs_to_value(self, association) }
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
- def after_save
104
- associations = self.class._t_has_many_associations || []
105
- associations.each { |association| self.class._t_save_associates(self, association) }
106
- super
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
- def _t_reload
110
- reload
111
- end
98
+ def _t_initialize_belongs_to_association(association)
99
+ @_t_belongs_to_associations ||= []
100
+ @_t_belongs_to_associations << association
101
+ end
112
102
 
113
- def _t_clear_associates(association)
114
- db["delete from #{association.join_table} where #{association.association_key} = #{self.id}"].delete
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
- def _t_associate_many(association, associate_ids)
118
- db.transaction do
119
- _t_clear_associates(association)
120
- associate_ids.each do |associate_id|
121
- db["insert into #{association.join_table} (#{association.association_key}, #{association.association_foreign_key}) values (#{self.id}, '#{associate_id}')"].insert
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
- def _t_get_associate_ids(association)
127
- return [] if self.id.nil?
128
- rows = db["select #{association.association_foreign_key} from #{association.join_table} where #{association.association_key} = #{self.id}"].all
129
- rows.map { |row| row[association.association_foreign_key.to_sym] }
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
@@ -1,3 +1,3 @@
1
1
  module Tenacity
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
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.1.3"
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.to_s, windshield.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
- setup_fixtures
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.to_s, door_2.id.to_s, door_3.id.to_s], ActiveRecordCar.find(car.id).couch_rest_door_ids
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