mongoid_monkey 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/lib/patches/atomic.rb +225 -1
  3. data/lib/version.rb +1 -1
  4. data/spec/app/models/address.rb +17 -0
  5. data/spec/app/models/name.rb +14 -0
  6. data/spec/app/models/person.rb +39 -0
  7. data/spec/unit/{atomic_spec.rb → atomic/atomic_contextual_spec.rb} +0 -0
  8. data/spec/unit/atomic/mongoid3_style/atomic/add_to_set_spec.rb +266 -0
  9. data/spec/unit/atomic/mongoid3_style/atomic/bit_spec.rb +92 -0
  10. data/spec/unit/atomic/mongoid3_style/atomic/inc_spec.rb +137 -0
  11. data/spec/unit/atomic/mongoid3_style/atomic/pop_spec.rb +115 -0
  12. data/spec/unit/atomic/mongoid3_style/atomic/pull_all_spec.rb +81 -0
  13. data/spec/unit/atomic/mongoid3_style/atomic/pull_spec.rb +84 -0
  14. data/spec/unit/atomic/mongoid3_style/atomic/push_all_spec.rb +81 -0
  15. data/spec/unit/atomic/mongoid3_style/atomic/push_spec.rb +81 -0
  16. data/spec/unit/atomic/mongoid3_style/atomic/rename_spec.rb +46 -0
  17. data/spec/unit/atomic/mongoid3_style/atomic/sets_spec.rb +158 -0
  18. data/spec/unit/atomic/mongoid3_style/atomic/unset_spec.rb +69 -0
  19. data/spec/unit/atomic/mongoid3_style/atomic_spec.rb +220 -0
  20. data/spec/unit/atomic/mongoid4_style/incrementable_spec.rb +232 -0
  21. data/spec/unit/atomic/mongoid4_style/logical_spec.rb +262 -0
  22. data/spec/unit/atomic/mongoid4_style/poppable_spec.rb +139 -0
  23. data/spec/unit/atomic/mongoid4_style/pullable_spec.rb +172 -0
  24. data/spec/unit/atomic/mongoid4_style/pushable_spec.rb +159 -0
  25. data/spec/unit/atomic/mongoid4_style/renamable_spec.rb +139 -0
  26. data/spec/unit/atomic/mongoid4_style/settable_spec.rb +172 -0
  27. data/spec/unit/atomic/mongoid4_style/unsettable_spec.rb +28 -0
  28. metadata +46 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e5814ac5f6752cc4afee52c517ed3996b7d4373f
4
- data.tar.gz: 5c42d28b26b8a8c5aa7d1ca71c29397d3392560c
3
+ metadata.gz: 214e7694779c183b25d31b4a3acd022b6d197883
4
+ data.tar.gz: ba65a452be5ef5778673fb790872ad7e879e368e
5
5
  SHA512:
6
- metadata.gz: 858f9e0888815dcebe7974e7ddd3737e3c5ce9a5117d47dc0436c9e87626e68ad639722207760dda09202f56ec7a8180325799ba7bc39cd7aaf1dc76824bc40b
7
- data.tar.gz: d0c827a916d331114e8b36a75a12d118c83284d491fb055ec80d670c3924856765621a514f1b4acfe7df63505ec42239488704e782bf5d4a9145158aa0b6d275
6
+ metadata.gz: 9c3906fb7a21840e4e1688bc1f9f9bcbfa608d3083533d52b87cb8caf31783dfe6aea1ae462b85c6908cb9d9b05ec35cd5e04e6d83e2e0750dbcb2f231d96c1b
7
+ data.tar.gz: 9c0dc36cb5537f059791b16d43ba2dd5fb3337d3597e3dfc4600c469d3717166a6761a5d8a335731dae3e6810340aad0e7a1b51bea69136af6a78bbab17d1864
@@ -111,4 +111,228 @@ module Atomic
111
111
  end
112
112
  end
113
113
  end
114
- end
114
+
115
+ module Mongoid
116
+ module Persistence
117
+ module Atomic
118
+
119
+ # push_all is deprecated so not supported
120
+
121
+ def add_to_set_with_mongoid4(*args)
122
+ if args.length == 1 && args.first.is_a?(Hash)
123
+ adds = args.first
124
+ prepare_atomic_operation do |ops|
125
+ process_atomic_operations(adds) do |field, value|
126
+ existing = send(field) || (attributes[field] ||= [])
127
+ values = [ value ].flatten(1)
128
+ values.each do |val|
129
+ existing.push(val) unless existing.include?(val)
130
+ end
131
+ ops[atomic_attribute_name(field)] = { "$each" => values }
132
+ end
133
+ { "$addToSet" => ops }
134
+ end
135
+ else
136
+ add_to_set_without_mongoid4(*args)
137
+ end
138
+ end
139
+ alias_method_chain :add_to_set, :mongoid4
140
+
141
+ def bit_with_mongoid4(*args)
142
+ if args.length == 1 && args.first.is_a?(Hash)
143
+ operations = args.first
144
+ prepare_atomic_operation do |ops|
145
+ process_atomic_operations(operations) do |field, values|
146
+ value = attributes[field]
147
+ values.each do |op, val|
148
+ value = value & val if op.to_s == "and"
149
+ value = value | val if op.to_s == "or"
150
+ end
151
+ attributes[field] = value
152
+ ops[atomic_attribute_name(field)] = values
153
+ end
154
+ { "$bit" => ops }
155
+ end
156
+ else
157
+ bit_without_mongoid4(*args)
158
+ end
159
+ end
160
+ alias_method_chain :bit, :mongoid4
161
+
162
+ def inc_with_mongoid4(*args)
163
+ if args.length == 1 && args.first.is_a?(Hash)
164
+ increments = args.first
165
+ prepare_atomic_operation do |ops|
166
+ process_atomic_operations(increments) do |field, value|
167
+ increment = value.__to_inc__
168
+ current = attributes[field]
169
+ attributes[field] = (current || 0) + increment
170
+ ops[atomic_attribute_name(field)] = increment
171
+ end
172
+ { "$inc" => ops }
173
+ end
174
+ else
175
+ inc_without_mongoid4(*args)
176
+ end
177
+ end
178
+ alias_method_chain :inc, :mongoid4
179
+
180
+ def pop_with_mongoid4(*args)
181
+ if args.length == 1 && args.first.is_a?(Hash)
182
+ pops = args.first
183
+ prepare_atomic_operation do |ops|
184
+ process_atomic_operations(pops) do |field, value|
185
+ values = send(field)
186
+ value > 0 ? values.pop : values.shift
187
+ ops[atomic_attribute_name(field)] = value
188
+ end
189
+ { "$pop" => ops }
190
+ end
191
+ else
192
+ pop_without_mongoid4(*args)
193
+ end
194
+ end
195
+ alias_method_chain :pop, :mongoid4
196
+
197
+ def pull_with_mongoid4(*args)
198
+ if args.length == 1 && args.first.is_a?(Hash)
199
+ pulls = args.first
200
+ prepare_atomic_operation do |ops|
201
+ process_atomic_operations(pulls) do |field, value|
202
+ (send(field) || []).delete(value)
203
+ ops[atomic_attribute_name(field)] = value
204
+ end
205
+ { "$pull" => ops }
206
+ end
207
+ else
208
+ pull_without_mongoid4(*args)
209
+ end
210
+ end
211
+ alias_method_chain :pull, :mongoid4
212
+
213
+ def pull_all_with_mongoid4(*args)
214
+ if args.length == 1 && args.first.is_a?(Hash)
215
+ pulls = args.first
216
+ prepare_atomic_operation do |ops|
217
+ process_atomic_operations(pulls) do |field, value|
218
+ existing = send(field) || []
219
+ value.each{ |val| existing.delete(val) }
220
+ ops[atomic_attribute_name(field)] = value
221
+ end
222
+ { "$pullAll" => ops }
223
+ end
224
+ else
225
+ pull_all_without_mongoid4(*args)
226
+ end
227
+ end
228
+ alias_method_chain :pull_all, :mongoid4
229
+
230
+ def push_with_mongoid4(*args)
231
+ if args.length == 1 && args.first.is_a?(Hash)
232
+ pushes = args.first
233
+ prepare_atomic_operation do |ops|
234
+ process_atomic_operations(pushes) do |field, value|
235
+ existing = send(field) || (attributes[field] ||= [])
236
+ values = [ value ].flatten(1)
237
+ values.each{ |val| existing.push(val) }
238
+ ops[atomic_attribute_name(field)] = { "$each" => values }
239
+ end
240
+ { "$push" => ops }
241
+ end
242
+ else
243
+ push_without_mongoid4(*args)
244
+ end
245
+ end
246
+ alias_method_chain :push, :mongoid4
247
+
248
+ def rename_with_mongoid4(*args)
249
+ if args.length == 1 && args.first.is_a?(Hash)
250
+ renames = args.first
251
+ prepare_atomic_operation do |ops|
252
+ process_atomic_operations(renames) do |old_field, new_field|
253
+ new_name = new_field.to_s
254
+ attributes[new_name] = attributes.delete(old_field)
255
+ ops[atomic_attribute_name(old_field)] = atomic_attribute_name(new_name)
256
+ end
257
+ { "$rename" => ops }
258
+ end
259
+ else
260
+ rename_without_mongoid4(*args)
261
+ end
262
+ end
263
+ alias_method_chain :rename, :mongoid4
264
+
265
+ def set_with_mongoid4(*args)
266
+ if args.length == 1 && args.first.is_a?(Hash)
267
+ setters = args.first
268
+ prepare_atomic_operation do |ops|
269
+ process_atomic_operations(setters) do |field, value|
270
+ process_attribute(field.to_s, value)
271
+ ops[atomic_attribute_name(field)] = attributes[field]
272
+ end
273
+ { "$set" => ops }
274
+ end
275
+ else
276
+ set_without_mongoid4(*args)
277
+ end
278
+ end
279
+ alias_method_chain :set, :mongoid4
280
+
281
+ # unset params are consistent, however it returns self in Mongoid 4
282
+ # def unset_with_mongoid4(*args)
283
+ # unset_without_mongoid4(*args)
284
+ # self
285
+ # end
286
+ # alias_method_chain :unset, :mongoid4
287
+
288
+ private
289
+
290
+ def executing_atomically?
291
+ !@atomic_updates_to_execute.nil?
292
+ end
293
+
294
+ def post_process_persist(result, options = {})
295
+ post_persist unless result == false
296
+ errors.clear unless performing_validations?(options)
297
+ true
298
+ end
299
+
300
+ def prepare_atomic_operation
301
+ operations = yield({})
302
+ persist_or_delay_atomic_operation(operations)
303
+ self
304
+ end
305
+
306
+ def process_atomic_operations(operations)
307
+ operations.each do |field, value|
308
+ unless attribute_writable?(field)
309
+ raise Errors::ReadonlyAttribute.new(field, value)
310
+ end
311
+ normalized = database_field_name(field)
312
+ yield(normalized, value)
313
+ remove_change(normalized)
314
+ end
315
+ end
316
+
317
+ def persist_or_delay_atomic_operation(operation)
318
+ if executing_atomically?
319
+ operation.each do |(name, hash)|
320
+ @atomic_updates_to_execute[name] ||= {}
321
+ @atomic_updates_to_execute[name].merge!(hash)
322
+ end
323
+ else
324
+ persist_atomic_operations(operation)
325
+ end
326
+ end
327
+
328
+ def persist_atomic_operations(operations)
329
+ if persisted?
330
+ selector = atomic_selector
331
+ _root.collection.find(selector).update(operations)
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
337
+
338
+ end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module MongoidMonkey
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
@@ -1,7 +1,24 @@
1
1
 
2
2
  class Address
3
3
  include Mongoid::Document
4
+ field :address_type
5
+ field :number, type: Integer
6
+ field :no, type: Integer
7
+ field :h, as: :house, type: Integer
4
8
  field :street
9
+ field :city
10
+ field :state
11
+ field :post_code
12
+ field :parent_title
13
+ field :services, type: Array
14
+ field :aliases, as: :a, type: Array
15
+ field :test, type: Array
16
+ field :latlng, type: Array
17
+ field :map, type: Hash
18
+ field :move_in, type: DateTime
19
+ field :end_date, type: Date
20
+ field :s, type: String, as: :suite
5
21
  field :name, localize: true
22
+
6
23
  embedded_in :addressable, polymorphic: true
7
24
  end
@@ -0,0 +1,14 @@
1
+ class Name
2
+ include Mongoid::Document
3
+
4
+ field :first_name, type: String
5
+ field :last_name, type: String
6
+ field :parent_title, type: String
7
+ field :middle, type: String
8
+
9
+ embedded_in :namable, polymorphic: true
10
+
11
+ def set_parent=(set = false)
12
+ self.parent_title = namable.title if set
13
+ end
14
+ end
@@ -8,4 +8,43 @@ class Person
8
8
  index name: 1
9
9
  index title: 1
10
10
  index({ ssn: 1 }, { unique: true })
11
+ field :username, default: -> { "arthurnn#{rand(0..10)}" }
12
+ field :title
13
+ field :terms, type: Boolean
14
+ field :pets, type: Boolean, default: false
15
+ field :age, type: Integer, default: "100"
16
+ field :dob, type: Date
17
+ field :employer_id
18
+ field :lunch_time, type: Time
19
+ field :aliases, type: Array
20
+ field :map, type: Hash
21
+ field :map_with_default, type: Hash, default: {}
22
+ field :score, type: Integer
23
+ field :blood_alcohol_content, type: Float, default: ->{ 0.0 }
24
+ field :last_drink_taken_at, type: Date, default: ->{ 1.day.ago.in_time_zone("Alaska") }
25
+ field :ssn
26
+ field :owner_id, type: Integer
27
+ field :security_code
28
+ field :reading, type: Object
29
+ field :pattern, type: Regexp
30
+ field :override_me, type: Integer
31
+ field :at, as: :aliased_timestamp, type: Time
32
+ field :t, as: :test, type: String
33
+ field :i, as: :inte, type: Integer
34
+ field :a, as: :array, type: Array
35
+ field :desc, localize: true
36
+ field :test_array, type: Array
37
+ field :overridden_setter, type: String
38
+ field :arrays, type: Array
39
+ field :range, type: Range
40
+
41
+ embeds_many :addresses, as: :addressable, validate: false
42
+ embeds_one :name, as: :namable, validate: false do
43
+ def extension
44
+ "Testing"
45
+ end
46
+ def dawkins?
47
+ first_name == "Richard" && last_name == "Dawkins"
48
+ end
49
+ end
11
50
  end
@@ -0,0 +1,266 @@
1
+ require "spec_helper"
2
+
3
+ if Mongoid::VERSION =~ /\A3\./
4
+
5
+ describe Mongoid::Persistence::Atomic::AddToSet do
6
+
7
+ describe "#persist" do
8
+
9
+ context "when the document is new" do
10
+
11
+ let(:person) do
12
+ Person.new
13
+ end
14
+
15
+ context "when adding a single value" do
16
+
17
+ let!(:added) do
18
+ person.add_to_set(:aliases, "Bond")
19
+ end
20
+
21
+ it "adds the value onto the array" do
22
+ person.aliases.should eq([ "Bond" ])
23
+ end
24
+
25
+ it "does not reset the dirty flagging" do
26
+ person.changes["aliases"].should eq([nil, ["Bond"]])
27
+ end
28
+
29
+ it "returns the new array value" do
30
+ added.should eq([ "Bond" ])
31
+ end
32
+ end
33
+
34
+ context "when adding multiple values" do
35
+
36
+ let!(:added) do
37
+ person.add_to_set(:aliases, [ "Bond", "James" ])
38
+ end
39
+
40
+ it "adds the value onto the array" do
41
+ person.aliases.should eq([ "Bond", "James" ])
42
+ end
43
+
44
+ it "does not reset the dirty flagging" do
45
+ person.changes["aliases"].should eq([nil, ["Bond", "James"]])
46
+ end
47
+
48
+ it "returns the new array value" do
49
+ added.should eq([ "Bond", "James" ])
50
+ end
51
+ end
52
+ end
53
+
54
+ context "when the field exists" do
55
+
56
+ context "when the value is unique" do
57
+
58
+ let(:person) do
59
+ Person.create(aliases: [ "007" ])
60
+ end
61
+
62
+ context "when adding a single value" do
63
+
64
+ let!(:added) do
65
+ person.add_to_set(:aliases, "Bond")
66
+ end
67
+
68
+ let(:reloaded) do
69
+ person.reload
70
+ end
71
+
72
+ it "adds the value onto the array" do
73
+ person.aliases.should eq([ "007", "Bond" ])
74
+ end
75
+
76
+ it "persists the data" do
77
+ reloaded.aliases.should eq([ "007", "Bond" ])
78
+ end
79
+
80
+ it "removes the field from the dirty attributes" do
81
+ person.changes["aliases"].should be_nil
82
+ end
83
+
84
+ it "resets the document dirty flag" do
85
+ person.should_not be_changed
86
+ end
87
+
88
+ it "returns the new array value" do
89
+ added.should eq([ "007", "Bond" ])
90
+ end
91
+ end
92
+
93
+ context "when adding a multiple values" do
94
+
95
+ let!(:added) do
96
+ person.add_to_set(:aliases, [ "Bond", "James" ])
97
+ end
98
+
99
+ let(:reloaded) do
100
+ person.reload
101
+ end
102
+
103
+ it "adds the value onto the array" do
104
+ person.aliases.should eq([ "007", "Bond", "James" ])
105
+ end
106
+
107
+ it "persists the data" do
108
+ reloaded.aliases.should eq([ "007", "Bond", "James" ])
109
+ end
110
+
111
+ it "removes the field from the dirty attributes" do
112
+ person.changes["aliases"].should be_nil
113
+ end
114
+
115
+ it "resets the document dirty flag" do
116
+ person.should_not be_changed
117
+ end
118
+
119
+ it "returns the new array value" do
120
+ added.should eq([ "007", "Bond", "James" ])
121
+ end
122
+ end
123
+ end
124
+
125
+ context "when the value is not unique" do
126
+
127
+ let(:person) do
128
+ Person.create(aliases: [ "Bond" ])
129
+ end
130
+
131
+ context "when adding a single value" do
132
+
133
+ let!(:added) do
134
+ person.add_to_set(:aliases, "Bond")
135
+ end
136
+
137
+ let(:reloaded) do
138
+ person.reload
139
+ end
140
+
141
+ it "does not add the value" do
142
+ person.aliases.should eq([ "Bond" ])
143
+ end
144
+
145
+ it "persists the data" do
146
+ reloaded.aliases.should eq([ "Bond" ])
147
+ end
148
+
149
+ it "removes the field from the dirty attributes" do
150
+ person.changes["aliases"].should be_nil
151
+ end
152
+
153
+ it "resets the document dirty flag" do
154
+ person.should_not be_changed
155
+ end
156
+
157
+ it "returns the array value" do
158
+ added.should eq([ "Bond" ])
159
+ end
160
+ end
161
+
162
+ context "when adding multiple values" do
163
+
164
+ let!(:added) do
165
+ person.add_to_set(:aliases, [ "Bond", "James" ])
166
+ end
167
+
168
+ let(:reloaded) do
169
+ person.reload
170
+ end
171
+
172
+ it "does not add the duplicate value" do
173
+ person.aliases.should eq([ "Bond", "James" ])
174
+ end
175
+
176
+ it "persists the data" do
177
+ reloaded.aliases.should eq([ "Bond", "James" ])
178
+ end
179
+
180
+ it "removes the field from the dirty attributes" do
181
+ person.changes["aliases"].should be_nil
182
+ end
183
+
184
+ it "resets the document dirty flag" do
185
+ person.should_not be_changed
186
+ end
187
+
188
+ it "returns the array value" do
189
+ added.should eq([ "Bond", "James" ])
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ context "when the field does not exist" do
196
+
197
+ let(:person) do
198
+ Person.create
199
+ end
200
+
201
+ context "when adding a single value" do
202
+
203
+ let!(:added) do
204
+ person.add_to_set(:aliases, "Bond")
205
+ end
206
+
207
+ let(:reloaded) do
208
+ person.reload
209
+ end
210
+
211
+ it "adds the value onto the array" do
212
+ person.aliases.should eq([ "Bond" ])
213
+ end
214
+
215
+ it "persists the data" do
216
+ reloaded.aliases.should eq([ "Bond" ])
217
+ end
218
+
219
+ it "removes the field from the dirty attributes" do
220
+ person.changes["aliases"].should be_nil
221
+ end
222
+
223
+ it "resets the document dirty flag" do
224
+ person.should_not be_changed
225
+ end
226
+
227
+ it "returns the new array value" do
228
+ added.should eq([ "Bond" ])
229
+ end
230
+ end
231
+
232
+ context "when adding multiple values" do
233
+
234
+ let!(:added) do
235
+ person.add_to_set(:aliases, [ "Bond", "James" ])
236
+ end
237
+
238
+ let(:reloaded) do
239
+ person.reload
240
+ end
241
+
242
+ it "adds the value onto the array" do
243
+ person.aliases.should eq([ "Bond", "James" ])
244
+ end
245
+
246
+ it "persists the data" do
247
+ reloaded.aliases.should eq([ "Bond", "James" ])
248
+ end
249
+
250
+ it "removes the field from the dirty attributes" do
251
+ person.changes["aliases"].should be_nil
252
+ end
253
+
254
+ it "resets the document dirty flag" do
255
+ person.should_not be_changed
256
+ end
257
+
258
+ it "returns the new array value" do
259
+ added.should eq([ "Bond", "James" ])
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ end
@@ -0,0 +1,92 @@
1
+ require "spec_helper"
2
+
3
+ if Mongoid::VERSION =~ /\A3\./
4
+
5
+ describe Mongoid::Persistence::Atomic::Bit do
6
+
7
+ describe "#bit" do
8
+
9
+ let(:person) do
10
+ Person.create(age: 60)
11
+ end
12
+
13
+ let(:reloaded) do
14
+ person.reload
15
+ end
16
+
17
+ context "when performing a bitwise and" do
18
+
19
+ let!(:bit) do
20
+ person.bit(:age, { and: 13 })
21
+ end
22
+
23
+ it "performs the bitwise operation" do
24
+ person.age.should eq(12)
25
+ end
26
+
27
+ it "returns the new value" do
28
+ bit.should eq(12)
29
+ end
30
+
31
+ it "persists the changes" do
32
+ reloaded.age.should eq(12)
33
+ end
34
+
35
+ it "resets the dirty attributes" do
36
+ person.changes["age"].should be_nil
37
+ end
38
+ end
39
+
40
+ context "when performing a bitwise or" do
41
+
42
+ let!(:bit) do
43
+ person.bit(:age, { or: 13 })
44
+ end
45
+
46
+ it "performs the bitwise operation" do
47
+ person.age.should eq(61)
48
+ end
49
+
50
+ it "returns the new value" do
51
+ bit.should eq(61)
52
+ end
53
+
54
+ it "persists the changes" do
55
+ reloaded.age.should eq(61)
56
+ end
57
+
58
+ it "resets the dirty attributes" do
59
+ person.changes["age"].should be_nil
60
+ end
61
+ end
62
+
63
+ context "when chaining bitwise operations" do
64
+
65
+ let(:hash) do
66
+ { and: 13, or: 10 }
67
+ end
68
+
69
+ let!(:bit) do
70
+ person.bit(:age, hash)
71
+ end
72
+
73
+ it "performs the bitwise operation" do
74
+ person.age.should eq(14)
75
+ end
76
+
77
+ it "returns the new value" do
78
+ bit.should eq(14)
79
+ end
80
+
81
+ it "persists the changes" do
82
+ reloaded.age.should eq(14)
83
+ end
84
+
85
+ it "resets the dirty attributes" do
86
+ person.changes["age"].should be_nil
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ end