mm_partial_update 0.1.0

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.
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ module MmPartialUpdate
3
+ Version = '0.1.0'
4
+ end
@@ -0,0 +1,91 @@
1
+ require 'test_helper'
2
+ require "models"
3
+
4
+ class TestDocumentPlugin < Test::Unit::TestCase
5
+
6
+ context "Document#save" do
7
+ should "respect persistence_strategy" do
8
+ Person.persistence_strategy(:changes_only)
9
+ #Person one should not have anything in the pets collection
10
+ person = Person.create! :name=>"Willard"
11
+
12
+ person2 = Person.find(person.id)
13
+ person2.pets.build :name=>"Magma"
14
+ person2.save!
15
+
16
+ person.name = "Timmy"
17
+ person.save!
18
+ person.reload
19
+ person.name.should == "Timmy"
20
+ person.pets.length.should == 1
21
+
22
+ Person.persistence_strategy(:full_document)
23
+ end
24
+ end
25
+
26
+ context "#save_to_collection" do
27
+
28
+ should "overwrite the document when the strategy is :full_document" do
29
+ #Person one should not have anything in the pets collection
30
+ person = Person.create! :name=>"Willard"
31
+
32
+ person2 = Person.find(person.id)
33
+ person2.pets.build :name=>"Magma"
34
+ person2.save!
35
+
36
+ person.name = "Timmy"
37
+ person.save_to_collection(:persistence_strategy=>:full_document) #this is the default
38
+ person.reload
39
+ person.name.should == "Timmy"
40
+ person.pets.length.should == 0
41
+ end
42
+
43
+
44
+ should "only save changes when the strategy is :changes_only" do
45
+ #Person one should not have anything in the pets collection
46
+ person = Person.create! :name=>"Willard"
47
+
48
+ person2 = Person.find(person.id)
49
+ person2.pets.build :name=>"Magma"
50
+ person2.save!
51
+
52
+ person.name = "Timmy"
53
+ person.save_to_collection(:changes_only=>true)
54
+ person.reload
55
+ person.name.should == "Timmy"
56
+ person.pets.length.should == 1
57
+ end
58
+
59
+ end
60
+
61
+ context "#determine_persistence_strategy" do
62
+ should "return a default strategy if none is set or provided" do
63
+ Person.new.send(:determine_persistence_strategy,{}).should == :full_document
64
+ end
65
+
66
+ should "return the plugin level persistence strategy if defined" do
67
+ MmPartialUpdate.default_persistence_strategy = :changes_only
68
+ Person.new.send(:determine_persistence_strategy,{}).should == :changes_only
69
+ MmPartialUpdate.default_persistence_strategy = :full_document
70
+ end
71
+
72
+ should "use class level persistence strategy if defined" do
73
+ Person.persistence_strategy(:changes_only)
74
+ Person.new.send(:determine_persistence_strategy,{}).should == :changes_only
75
+ Person.persistence_strategy(:full_document)
76
+ end
77
+
78
+ should "use persistence strategy in the options if defined" do
79
+ Person.new.send(:determine_persistence_strategy,
80
+ {:persistence_strategy=>:changes_only}).should == :changes_only
81
+ end
82
+
83
+ should "interpret :changes_only=>true in the options as a strategy of :changes_only" do
84
+ Person.new.send(:determine_persistence_strategy,:changes_only=>true).
85
+ should == :changes_only
86
+ end
87
+
88
+ end
89
+
90
+
91
+ end
@@ -0,0 +1,112 @@
1
+ require 'test_helper'
2
+ require "models"
3
+
4
+ class TestEmbeddedDocumentPlugin < Test::Unit::TestCase
5
+
6
+ context "#database_selector" do
7
+
8
+ should "be defined for new one relationships" do
9
+ person = Person.new
10
+ pet = person.favorite_pet.build
11
+ pet.database_selector.should == "favorite_pet"
12
+ end
13
+
14
+ should "be defined for one relationships loaded from the database" do
15
+ person = Person.new
16
+ person.favorite_pet.build
17
+ person.save!
18
+ person = Person.find(person.id)
19
+ person.favorite_pet.database_selector.should == "favorite_pet"
20
+ end
21
+
22
+ should "be defined for new many_embedded relationships" do
23
+ person = Person.new
24
+ pet = person.pets.build
25
+ pet.database_selector.should == "pets"
26
+ end
27
+
28
+ should "be defined for new many_embedded relationships loaded from the database" do
29
+ person = Person.new
30
+ person.pets.build
31
+ person.save!
32
+ person = Person.find(person.id)
33
+ person.pets[0].database_selector.should == "pets.0"
34
+ end
35
+
36
+ should "be defined for new nested one relationships" do
37
+ person = Person.new
38
+ person.pets.build
39
+ person.save!
40
+ person = Person.find(person.id)
41
+ flea = person.pets[0].favorite_flea.build
42
+ flea.database_selector.should == "pets.0.favorite_flea"
43
+ end
44
+
45
+ should "be defined for nested one relationships loaded from the database" do
46
+ person = Person.new
47
+ person.pets.build
48
+ person.pets[0].favorite_flea.build
49
+ person.save!
50
+ person = Person.find(person.id)
51
+ person.pets[0].favorite_flea.database_selector.should == "pets.0.favorite_flea"
52
+ end
53
+
54
+ should "be defined for new nested many relationships" do
55
+ person = Person.new
56
+ person.pets.build
57
+ person.save!
58
+ person = Person.find(person.id)
59
+ person.pets[0].fleas.build
60
+ person.pets[0].fleas[0].database_selector.should == "pets.0.fleas"
61
+ end
62
+
63
+ should "be defined for nested many relationships loaded from the database" do
64
+ person = Person.new
65
+ person.pets.build
66
+ person.pets[0].fleas.build
67
+ person.save!
68
+ person = Person.find(person.id)
69
+ person.pets[0].fleas[0].database_selector.should == "pets.0.fleas.0"
70
+ end
71
+
72
+ end
73
+
74
+ context "#save_changes" do
75
+
76
+ should "save an unsaved parent when a descendent is saved" do
77
+ person = Person.new :name=>"Willard"
78
+ pet = person.pets.build :name=>"Magma"
79
+ pet.save_changes
80
+ person = Person.find(person.id)
81
+ person.should_not be_nil
82
+ person.name.should == "Willard"
83
+ person.pets.count.should == 1
84
+ person.pets[0].name.should == "Magma"
85
+ end
86
+
87
+ should "create an embedded document that doesn't already exist" do
88
+ person = Person.create! :name=>"Nathan"
89
+ pet = person.pets.build :name=>"Magma", :age=>3
90
+ pet.save_changes
91
+ person.reload
92
+ person.pets.count.should == 1
93
+ person.pets[0].name.should == "Magma"
94
+ person.pets[0].age.should == 3
95
+ end
96
+
97
+ should "create an embedded document without saving the parent" do
98
+ person = Person.create! :name=>"Willard"
99
+ person.name = "Nevermore"
100
+ pet = person.pets.build :name=>"Magma"
101
+ pet.save_changes
102
+ pet.changed?.should be_false
103
+ person.changed?.should be_true
104
+ person.reload
105
+ person.name.should == "Willard"
106
+ person.pets.count.should == 1
107
+ person.pets[0].name.should == "Magma"
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,101 @@
1
+ require 'test_helper'
2
+ require "models"
3
+
4
+ class TestPartialUpdate < Test::Unit::TestCase
5
+ context "#save_changes" do
6
+ should "create unsaved entities" do
7
+ person = Person.new :name=>"Willard"
8
+ person.save_changes
9
+ person.reload
10
+ person.name.should == "Willard"
11
+ person.new?.should be_false
12
+ end
13
+
14
+ should "update a saved entity" do
15
+ person = Person.create! :name=>"Willard"
16
+ person.name = "Esteban"
17
+ person.save_changes
18
+ person.reload
19
+ person.name.should == "Esteban"
20
+ end
21
+
22
+ should "update changes to a saved entity, preserving unchanged values" do
23
+ person = Person.new :name=>"Willard"
24
+ person.pets.build :name=>"Magma", :age=>2
25
+ person.save!
26
+ person.name = "Esteban"
27
+ person.save_changes
28
+ person.reload
29
+ person.name.should == "Esteban"
30
+ person.pets.count.should == 1
31
+ person.pets[0].name.should == "Magma"
32
+ person.pets[0].age.should == 2
33
+ end
34
+
35
+ should "apply a variety of changes to a document graph" do
36
+ person = Person.new :name=>"Willard"
37
+ person.pets.build :name=>"Magma", :age=>3
38
+ person.pets.build :name=>"Debris"
39
+ person.pets.build :name=>"Timmy"
40
+ person.pets[0].favorite_flea.build :name=>"Fleatus"
41
+ person.pets[1].fleas.build :name=>"Fleatasia"
42
+ person.pets[1].fleas.build :name=>"Dogen Zenji"
43
+ person.favorite_pet.build :name=>"Soto", :age=>10_000
44
+ person.save!
45
+
46
+ person.pets.reject! {|p|p.name=="Timmy"}
47
+ person.name = "Fydor"
48
+ person.favorite_pet.age = 100_000
49
+ person.pets[0].favorite_flea = nil
50
+ person.pets[1].fleas[0].name = "The Horse Master"
51
+ person.pets[1].fleas.build :name=>"Raskolnikov", :age=>80
52
+
53
+ person.save_changes
54
+
55
+ person.reload
56
+
57
+ person.name.should == "Fydor"
58
+ person.pets.count.should == 2
59
+ person.pets[0].name.should == "Magma"
60
+ person.pets[1].name.should == "Debris"
61
+ person.pets[0].favorite_flea.should be_nil
62
+ person.pets[1].fleas[0].name.should == "The Horse Master"
63
+ person.favorite_pet.age.should == 100_000
64
+ person.pets[1].fleas.count.should == 3
65
+ person.pets[1].fleas[-1].name.should == "Raskolnikov"
66
+ person.pets[1].fleas[-1].age.should == 80
67
+ end
68
+
69
+ context "with dirty tracking" do
70
+ setup do
71
+ @person = Person.new :name=>"Willard"
72
+ @person.pets.build :name=>"Magma"
73
+ @person.save_changes
74
+ end
75
+
76
+ should "clear new flags when changes are saved" do
77
+ @person.new?.should be_false
78
+ end
79
+
80
+ should "clear new flags on descentends when changes are saved" do
81
+ @person.pets[0].new?.should be_false
82
+ end
83
+
84
+
85
+ should "clear dirty tracking when changes are saved" do
86
+ @person.changed?.should be_false
87
+ end
88
+
89
+ should "clear dirty tracking on descendents when changes are saved" do
90
+ @person.pets[0].changed?.should be_false
91
+ end
92
+ end
93
+
94
+ #context "when called on embedded documents" do
95
+ # should "save a new embedded document" do
96
+ # person = Person.create! :name=>"Willard"
97
+ # end
98
+ #end
99
+
100
+ end
101
+ end
@@ -0,0 +1,261 @@
1
+ require "test_helper"
2
+ require "models"
3
+
4
+ class TestUpdateCommand < Test::Unit::TestCase
5
+
6
+ context "#execute" do
7
+ setup do
8
+ @person = Person.new
9
+ @command = MmPartialUpdate::UpdateCommand.new(@person)
10
+ end
11
+
12
+ context "with no commands" do
13
+ should "do nothing" do
14
+ @command.execute
15
+ Person.find(@person.id).should be_nil
16
+ end
17
+ end
18
+
19
+ context "on a new document" do
20
+ should "create a document if it doesn't previouly exist" do
21
+ @command.set nil,"a_value"=>"for you"
22
+ @command.execute
23
+ (person = Person.find(@person.id)).should_not be_nil
24
+ person.a_value.should == "for you"
25
+ end
26
+ end
27
+
28
+ context "on an existing document" do
29
+ should "update the existing document" do
30
+ @person.save!
31
+ @command.set nil, "another_value"=>"in the house"
32
+ @command.execute
33
+ (person = Person.find(@person.id)).should_not be_nil
34
+ end
35
+
36
+ should "preserve previous values" do
37
+ @person["a_value"] = "was here"
38
+ @person.save!
39
+ @command.set nil, "another_value"=>"in the house"
40
+ @command.execute
41
+ (person = Person.find(@person.id)).should_not be_nil
42
+ person.a_value.should == "was here"
43
+ end
44
+
45
+ context "#set" do
46
+ should "set a variety of direct keys on the document" do
47
+ @command.set nil, "a"=>"b", "c"=>1, "d"=>[1,2,3]
48
+ @command.execute
49
+ person = Person.find(@person.id)
50
+ person.a.should == "b"
51
+ person.c.should == 1
52
+ person.d.should == [1,2,3]
53
+ end
54
+
55
+ should "create sub-objects" do
56
+ @command.set "favorite_pet", Pet.new(:name=>"Magma", :age=>3).to_mongo
57
+ @command.execute
58
+ @person.reload
59
+ @person.favorite_pet.should_not be_nil
60
+ @person.favorite_pet.name.should == "Magma"
61
+ @person.favorite_pet.age.should == 3
62
+ end
63
+
64
+ should "update sub-objects" do
65
+ pet = @person.favorite_pet.build :name=>"Magma"
66
+ @person.save!
67
+ @command.set "favorite_pet", {:name=>"Timmy"}
68
+ @command.execute
69
+ @person.reload
70
+ @person.favorite_pet.name.should == "Timmy"
71
+ end
72
+
73
+ should "expand sub-objects" do
74
+ pet = @person.favorite_pet.build :name=>"Magma"
75
+ @person.save!
76
+ @command.set "favorite_pet", {:age=>9}
77
+ @command.execute
78
+ @person.reload
79
+ @person.favorite_pet.age.should == 9
80
+ end
81
+
82
+ should "create deep objects" do
83
+ pet = @person.favorite_pet.build :name=>"Magma"
84
+ @person.save!
85
+ @command.set "favorite_pet.favorite_flea", Flea.new(:name=>"Fleatus").to_mongo, :replace=>true
86
+ @command.execute
87
+ @person.reload
88
+ @person.favorite_pet.favorite_flea.should_not be_nil
89
+ @person.favorite_pet.favorite_flea.name.should == "Fleatus"
90
+ end
91
+
92
+ should "update deep objects" do
93
+ pet = @person.favorite_pet.build :name=>"Magma"
94
+ flea = pet.favorite_flea.build :name=>"Fleatus"
95
+ @person.save!
96
+ @command.set "favorite_pet.favorite_flea", {:name=>"Fleatasia"}
97
+ @command.execute
98
+ @person.reload
99
+ @person.favorite_pet.favorite_flea.name.should == "Fleatasia"
100
+ end
101
+
102
+ should "update objects in arrays" do
103
+ @person.pets.build :name=>"Magma"
104
+ @person.save!
105
+ @command.set "pets.0", {:name=>"Timmy"}
106
+ @command.execute
107
+ @person.reload
108
+ @person.pets[0].name.should == "Timmy"
109
+ end
110
+
111
+ should "update objects in deep arrays" do
112
+ pet = @person.pets.build :name=>"Magma"
113
+ flea = pet.fleas.build :name=>"Fleatus"
114
+ @person.save!
115
+ @command.set "pets.0.fleas.0", :name=>"Fleatasia"
116
+ @command.execute
117
+ @person.reload
118
+ @person.pets[0].fleas[0].name.should == "Fleatasia"
119
+ end
120
+
121
+ end
122
+
123
+ context "#unset" do
124
+ should "remove a specified key" do
125
+ @person.name = "I am the walrus"
126
+ @person.save!
127
+ @command.unset "name"
128
+ @command.execute
129
+ #reload doesn't work here, because of MM implementation
130
+ #which will not apply values to fields
131
+ #that don't appear in the result set
132
+ person = Person.find(@person.id)
133
+ person.name.should be_nil
134
+ end
135
+ end
136
+
137
+ context "#push" do
138
+ should "add objects to arrays" do
139
+ @command.push "pets", :name=>"Magma", :age=>2
140
+ @command.execute
141
+ @person.reload
142
+ @person.pets.count.should == 1
143
+ @person.pets[0].name.should == "Magma"
144
+ @person.pets[0].age.should == 2
145
+ end
146
+
147
+ should "append objects to arrays" do
148
+ @person.pets.build :name=>"Magma"
149
+ @person.save!
150
+ @command.push "pets", :name=>"Timmy"
151
+ @command.execute
152
+ @person.reload
153
+ @person.pets.count.should == 2
154
+ @person.pets[1].name.should == "Timmy"
155
+ end
156
+
157
+ should "add objects to deep arrays" do
158
+ @person.pets.build :name=>"Magma"
159
+ @person.save!
160
+ @command.push "pets.0.fleas", :name=>"Fleatus"
161
+ @command.execute
162
+ @person.reload
163
+ @person.pets[0].fleas.count.should == 1
164
+ @person.pets[0].fleas[0].name.should == "Fleatus"
165
+ end
166
+
167
+ should "add multiple objects to an array" do
168
+ @command.push "pets", :name=>"Magma"
169
+ @command.push "pets", :name=>"Timmy"
170
+ @command.execute
171
+ @person.reload
172
+ @person.pets.count.should == 2
173
+ @person.pets[0].name.should == "Magma"
174
+ @person.pets[1].name.should == "Timmy"
175
+ end
176
+
177
+
178
+ end
179
+
180
+ context "#pull" do
181
+ should "remove objects from arrays" do
182
+ pet = @person.pets.build :name=>"Magma"
183
+ @person.save!
184
+ @command.pull "pets", pet._id
185
+ @command.execute
186
+ @person.reload
187
+ @person.pets.count.should == 0
188
+ end
189
+
190
+ should "remove objects from deep arrays" do
191
+ pet = @person.pets.build :name=>"Magma"
192
+ flea = pet.fleas.build :name=>"Fleatus"
193
+ @person.save!
194
+ @command.pull "pets.0.fleas", flea.id
195
+ @command.execute
196
+ @person.reload
197
+ @person.pets[0].fleas.count.should == 0
198
+ end
199
+
200
+ should "remove multiple objects from arrays" do
201
+ @person.pets.build :name=>"Magma"
202
+ @person.pets.build :name=>"Timmy"
203
+ @person.pets.build :name=>"Debris"
204
+ @person.save!
205
+ @command.pull "pets", @person.pets[0].id
206
+ @command.pull "pets", @person.pets[2].id
207
+
208
+ undeleted = @person.pets[1].id
209
+
210
+ @command.execute
211
+ @person.reload
212
+ @person.pets.count.should == 1
213
+ @person.pets[0].id.should == undeleted
214
+ end
215
+
216
+ end
217
+
218
+ context "with a variety of commands" do
219
+ should "correctly persist the document" do
220
+ @person.name = "Nathan"
221
+ @person.pets.build :name=>"Magma"
222
+ @person.pets.build :name=>"Timmy", :age=>3
223
+ @person.favorite_pet.build :name=>"Debris", :age=>1
224
+ @person.pets[0].favorite_flea.build :name=>"Fleatus"
225
+ @person.pets[1].fleas.build :name=>"Fleatasia"
226
+ @person.save!
227
+
228
+ @command.set nil, :name=>"Willard"
229
+ @command.push "pets", :name=>"Dogen", :age=>2
230
+ @command.pull "pets", @person.pets[1].id
231
+ @command.set "pets.0", :age => 99
232
+ @command.set "pets.0.favorite_flea", :name=>"Fleasy"
233
+ @command.set "pets.1.favorite_flea", {:_id=>BSON::ObjectId.new, :name=>"Rinzai"}, :replace=>true
234
+ @command.push "pets.0.fleas", :_id=>BSON::ObjectId.new, :name=>"Soto"
235
+ @command.push "pets.0.fleas", :_id=>BSON::ObjectId.new, :name=>"Basho"
236
+
237
+ @command.execute
238
+ @person.reload
239
+
240
+ @person.name.should == "Willard"
241
+ @person.pets.count.should == 2
242
+ @person.pets[0].name.should == "Magma"
243
+ @person.pets[1].name.should == "Dogen"
244
+ @person.pets[1].age.should == 2
245
+ @person.pets[0].age.should == 99
246
+ @person.favorite_pet.name.should == "Debris"
247
+ @person.pets[1].favorite_flea.should be_nil
248
+ @person.pets[1].fleas.count.should == 0
249
+ @person.pets[0].fleas.count.should == 2
250
+ @person.pets[0].fleas[0].name.should == "Soto"
251
+ @person.pets[0].fleas[1].name.should == "Basho"
252
+
253
+ end
254
+ end
255
+
256
+ end
257
+
258
+
259
+ end
260
+
261
+ end