mongoid_monkey 0.1.3 → 0.1.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.
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