mongoid 5.4.1 → 6.1.1

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 (260) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +3 -3
  3. data/lib/config/locales/en.yml +19 -0
  4. data/lib/mongoid.rb +4 -4
  5. data/lib/mongoid/atomic.rb +2 -2
  6. data/lib/mongoid/atomic/modifiers.rb +8 -12
  7. data/lib/mongoid/attributes.rb +22 -21
  8. data/lib/mongoid/attributes/readonly.rb +22 -0
  9. data/lib/mongoid/cacheable.rb +36 -0
  10. data/lib/mongoid/changeable.rb +36 -0
  11. data/lib/mongoid/clients.rb +8 -63
  12. data/lib/mongoid/clients/options.rb +55 -250
  13. data/lib/mongoid/clients/storage_options.rb +1 -69
  14. data/lib/mongoid/composable.rb +29 -3
  15. data/lib/mongoid/config.rb +1 -0
  16. data/lib/mongoid/contextual/atomic.rb +5 -8
  17. data/lib/mongoid/contextual/map_reduce.rb +0 -4
  18. data/lib/mongoid/contextual/memory.rb +2 -2
  19. data/lib/mongoid/contextual/mongo.rb +40 -22
  20. data/lib/mongoid/contextual/none.rb +12 -0
  21. data/lib/mongoid/copyable.rb +13 -6
  22. data/lib/mongoid/criteria.rb +5 -2
  23. data/lib/mongoid/criteria/marshalable.rb +2 -2
  24. data/lib/mongoid/criteria/modifiable.rb +17 -1
  25. data/lib/mongoid/criteria/options.rb +25 -0
  26. data/lib/mongoid/criteria/queryable.rb +87 -0
  27. data/lib/mongoid/criteria/queryable/aggregable.rb +120 -0
  28. data/lib/mongoid/criteria/queryable/extensions.rb +28 -0
  29. data/lib/mongoid/criteria/queryable/extensions/array.rb +185 -0
  30. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +37 -0
  31. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +34 -0
  32. data/lib/mongoid/criteria/queryable/extensions/date.rb +63 -0
  33. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +53 -0
  34. data/lib/mongoid/criteria/queryable/extensions/hash.rb +200 -0
  35. data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +86 -0
  36. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +90 -0
  37. data/lib/mongoid/criteria/queryable/extensions/object.rb +206 -0
  38. data/lib/mongoid/criteria/queryable/extensions/range.rb +70 -0
  39. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +79 -0
  40. data/lib/mongoid/criteria/queryable/extensions/set.rb +34 -0
  41. data/lib/mongoid/criteria/queryable/extensions/string.rb +137 -0
  42. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +79 -0
  43. data/lib/mongoid/criteria/queryable/extensions/time.rb +60 -0
  44. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +54 -0
  45. data/lib/mongoid/criteria/queryable/forwardable.rb +65 -0
  46. data/lib/mongoid/criteria/queryable/key.rb +103 -0
  47. data/lib/mongoid/criteria/queryable/macroable.rb +27 -0
  48. data/lib/mongoid/criteria/queryable/mergeable.rb +271 -0
  49. data/lib/mongoid/criteria/queryable/optional.rb +429 -0
  50. data/lib/mongoid/criteria/queryable/options.rb +153 -0
  51. data/lib/mongoid/criteria/queryable/pipeline.rb +111 -0
  52. data/lib/mongoid/criteria/queryable/selectable.rb +662 -0
  53. data/lib/mongoid/criteria/queryable/selector.rb +212 -0
  54. data/lib/mongoid/criteria/queryable/smash.rb +104 -0
  55. data/lib/mongoid/document.rb +30 -37
  56. data/lib/mongoid/errors.rb +2 -0
  57. data/lib/mongoid/errors/ambiguous_relationship.rb +1 -1
  58. data/lib/mongoid/errors/in_memory_collation_not_supported.rb +1 -1
  59. data/lib/mongoid/errors/invalid_field.rb +2 -2
  60. data/lib/mongoid/errors/invalid_persistence_option.rb +29 -0
  61. data/lib/mongoid/errors/invalid_relation.rb +66 -0
  62. data/lib/mongoid/evolvable.rb +1 -1
  63. data/lib/mongoid/extensions.rb +0 -4
  64. data/lib/mongoid/extensions/big_decimal.rb +17 -8
  65. data/lib/mongoid/extensions/date.rb +4 -1
  66. data/lib/mongoid/extensions/decimal128.rb +3 -3
  67. data/lib/mongoid/extensions/hash.rb +1 -0
  68. data/lib/mongoid/extensions/string.rb +4 -3
  69. data/lib/mongoid/extensions/time.rb +4 -1
  70. data/lib/mongoid/fields/validators/macro.rb +18 -0
  71. data/lib/mongoid/findable.rb +2 -2
  72. data/lib/mongoid/indexable.rb +15 -13
  73. data/lib/mongoid/interceptable.rb +5 -22
  74. data/lib/mongoid/matchable.rb +13 -7
  75. data/lib/mongoid/matchable/all.rb +2 -2
  76. data/lib/mongoid/matchable/and.rb +3 -3
  77. data/lib/mongoid/matchable/default.rb +2 -2
  78. data/lib/mongoid/matchable/elem_match.rb +28 -0
  79. data/lib/mongoid/matchable/exists.rb +2 -2
  80. data/lib/mongoid/matchable/gt.rb +4 -2
  81. data/lib/mongoid/matchable/gte.rb +4 -2
  82. data/lib/mongoid/matchable/in.rb +2 -2
  83. data/lib/mongoid/matchable/lt.rb +4 -2
  84. data/lib/mongoid/matchable/lte.rb +4 -2
  85. data/lib/mongoid/matchable/ne.rb +2 -2
  86. data/lib/mongoid/matchable/nin.rb +2 -2
  87. data/lib/mongoid/matchable/or.rb +3 -3
  88. data/lib/mongoid/matchable/regexp.rb +3 -3
  89. data/lib/mongoid/matchable/size.rb +2 -2
  90. data/lib/mongoid/persistable.rb +3 -5
  91. data/lib/mongoid/persistable/creatable.rb +2 -2
  92. data/lib/mongoid/persistable/deletable.rb +1 -1
  93. data/lib/mongoid/persistable/settable.rb +1 -1
  94. data/lib/mongoid/persistable/updatable.rb +5 -12
  95. data/lib/mongoid/persistable/upsertable.rb +1 -1
  96. data/lib/mongoid/persistence_context.rb +215 -0
  97. data/lib/mongoid/query_cache.rb +3 -6
  98. data/lib/mongoid/relations/accessors.rb +3 -0
  99. data/lib/mongoid/relations/auto_save.rb +12 -4
  100. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -4
  101. data/lib/mongoid/relations/counter_cache.rb +15 -5
  102. data/lib/mongoid/relations/eager.rb +6 -11
  103. data/lib/mongoid/relations/eager/base.rb +3 -3
  104. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +2 -2
  105. data/lib/mongoid/relations/eager/has_many.rb +1 -1
  106. data/lib/mongoid/relations/embedded/batchable.rb +12 -36
  107. data/lib/mongoid/relations/embedded/in.rb +13 -1
  108. data/lib/mongoid/relations/embedded/many.rb +28 -10
  109. data/lib/mongoid/relations/embedded/one.rb +14 -1
  110. data/lib/mongoid/relations/macros.rb +9 -1
  111. data/lib/mongoid/relations/metadata.rb +3 -3
  112. data/lib/mongoid/relations/options.rb +2 -2
  113. data/lib/mongoid/relations/proxy.rb +1 -31
  114. data/lib/mongoid/relations/referenced/in.rb +19 -10
  115. data/lib/mongoid/relations/referenced/many.rb +23 -17
  116. data/lib/mongoid/relations/referenced/many_to_many.rb +20 -13
  117. data/lib/mongoid/relations/referenced/one.rb +15 -1
  118. data/lib/mongoid/relations/synchronization.rb +11 -11
  119. data/lib/mongoid/relations/touchable.rb +6 -3
  120. data/lib/mongoid/reloadable.rb +1 -1
  121. data/lib/mongoid/serializable.rb +1 -1
  122. data/lib/mongoid/traversable.rb +1 -1
  123. data/lib/mongoid/validatable/uniqueness.rb +1 -2
  124. data/lib/mongoid/version.rb +1 -1
  125. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +14 -3
  126. data/spec/app/models/album.rb +5 -1
  127. data/spec/app/models/artist.rb +21 -0
  128. data/spec/app/models/book.rb +2 -1
  129. data/spec/app/models/dokument.rb +1 -0
  130. data/spec/app/models/ordered_post.rb +5 -0
  131. data/spec/app/models/oscar.rb +1 -2
  132. data/spec/app/models/page.rb +1 -1
  133. data/spec/app/models/person.rb +3 -3
  134. data/spec/app/models/princess.rb +2 -0
  135. data/spec/app/models/record.rb +1 -0
  136. data/spec/app/models/subscription.rb +1 -0
  137. data/spec/app/models/thing.rb +1 -1
  138. data/spec/config/mongoid.yml +15 -0
  139. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  140. data/spec/mongoid/atomic_spec.rb +17 -17
  141. data/spec/mongoid/attributes/nested_spec.rb +14 -14
  142. data/spec/mongoid/attributes/readonly_spec.rb +87 -44
  143. data/spec/mongoid/attributes_spec.rb +90 -5
  144. data/spec/mongoid/cacheable_spec.rb +112 -0
  145. data/spec/mongoid/changeable_spec.rb +58 -0
  146. data/spec/mongoid/clients/factory_spec.rb +31 -3
  147. data/spec/mongoid/clients/options_spec.rb +382 -96
  148. data/spec/mongoid/clients_spec.rb +243 -101
  149. data/spec/mongoid/composable_spec.rb +7 -0
  150. data/spec/mongoid/config_spec.rb +67 -11
  151. data/spec/mongoid/contextual/atomic_spec.rb +3 -3
  152. data/spec/mongoid/contextual/mongo_spec.rb +165 -20
  153. data/spec/mongoid/contextual/none_spec.rb +15 -0
  154. data/spec/mongoid/copyable_spec.rb +13 -4
  155. data/spec/mongoid/criteria/modifiable_spec.rb +239 -7
  156. data/spec/mongoid/criteria/options_spec.rb +29 -0
  157. data/spec/mongoid/criteria/queryable/aggregable_spec.rb +370 -0
  158. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +523 -0
  159. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +59 -0
  160. data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +58 -0
  161. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +213 -0
  162. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +330 -0
  163. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +405 -0
  164. data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +58 -0
  165. data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +65 -0
  166. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +327 -0
  167. data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +65 -0
  168. data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +77 -0
  169. data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +108 -0
  170. data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +309 -0
  171. data/spec/mongoid/{extensions/origin → criteria/queryable/extensions}/regexp_raw_spec.rb +2 -2
  172. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +90 -0
  173. data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +39 -0
  174. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +302 -0
  175. data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +167 -0
  176. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +376 -0
  177. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +347 -0
  178. data/spec/mongoid/criteria/queryable/forwardable_spec.rb +87 -0
  179. data/spec/mongoid/criteria/queryable/key_spec.rb +52 -0
  180. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +49 -0
  181. data/spec/mongoid/criteria/queryable/optional_spec.rb +1799 -0
  182. data/spec/mongoid/criteria/queryable/options_spec.rb +360 -0
  183. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +200 -0
  184. data/spec/mongoid/criteria/queryable/queryable_spec.rb +137 -0
  185. data/spec/mongoid/criteria/queryable/selectable_spec.rb +4174 -0
  186. data/spec/mongoid/criteria/queryable/selector_spec.rb +844 -0
  187. data/spec/mongoid/criteria/queryable/smash_spec.rb +30 -0
  188. data/spec/mongoid/criteria_spec.rb +152 -21
  189. data/spec/mongoid/document_spec.rb +37 -88
  190. data/spec/mongoid/errors/invalid_relation_spec.rb +37 -0
  191. data/spec/mongoid/errors/mongoid_error_spec.rb +6 -3
  192. data/spec/mongoid/extensions/big_decimal_spec.rb +320 -18
  193. data/spec/mongoid/extensions/boolean_spec.rb +14 -0
  194. data/spec/mongoid/extensions/date_spec.rb +2 -6
  195. data/spec/mongoid/extensions/date_time_spec.rb +2 -6
  196. data/spec/mongoid/extensions/decimal128_spec.rb +1 -1
  197. data/spec/mongoid/extensions/float_spec.rb +8 -1
  198. data/spec/mongoid/extensions/hash_spec.rb +15 -0
  199. data/spec/mongoid/extensions/integer_spec.rb +8 -1
  200. data/spec/mongoid/extensions/object_spec.rb +11 -0
  201. data/spec/mongoid/extensions/string_spec.rb +21 -0
  202. data/spec/mongoid/extensions/time_spec.rb +2 -6
  203. data/spec/mongoid/extensions/time_with_zone_spec.rb +2 -6
  204. data/spec/mongoid/findable_spec.rb +46 -1
  205. data/spec/mongoid/indexable_spec.rb +15 -3
  206. data/spec/mongoid/interceptable_spec.rb +68 -10
  207. data/spec/mongoid/matchable/all_spec.rb +4 -4
  208. data/spec/mongoid/matchable/and_spec.rb +10 -10
  209. data/spec/mongoid/matchable/default_spec.rb +12 -12
  210. data/spec/mongoid/matchable/elem_match_spec.rb +86 -0
  211. data/spec/mongoid/matchable/exists_spec.rb +5 -5
  212. data/spec/mongoid/matchable/gt_spec.rb +18 -7
  213. data/spec/mongoid/matchable/gte_spec.rb +17 -7
  214. data/spec/mongoid/matchable/in_spec.rb +5 -5
  215. data/spec/mongoid/matchable/lt_spec.rb +18 -7
  216. data/spec/mongoid/matchable/lte_spec.rb +18 -7
  217. data/spec/mongoid/matchable/ne_spec.rb +5 -5
  218. data/spec/mongoid/matchable/nin_spec.rb +5 -5
  219. data/spec/mongoid/matchable/or_spec.rb +7 -7
  220. data/spec/mongoid/matchable/regexp_spec.rb +5 -5
  221. data/spec/mongoid/matchable/size_spec.rb +3 -3
  222. data/spec/mongoid/matchable_spec.rb +173 -53
  223. data/spec/mongoid/persistable/creatable_spec.rb +7 -2
  224. data/spec/mongoid/persistable/deletable_spec.rb +16 -1
  225. data/spec/mongoid/persistable/destroyable_spec.rb +6 -2
  226. data/spec/mongoid/persistable/savable_spec.rb +35 -30
  227. data/spec/mongoid/persistable/settable_spec.rb +45 -29
  228. data/spec/mongoid/persistable/updatable_spec.rb +184 -5
  229. data/spec/mongoid/persistence_context_spec.rb +680 -0
  230. data/spec/mongoid/positional_spec.rb +10 -10
  231. data/spec/mongoid/query_cache_spec.rb +89 -0
  232. data/spec/mongoid/relations/accessors_spec.rb +1 -1
  233. data/spec/mongoid/relations/auto_save_spec.rb +39 -6
  234. data/spec/mongoid/relations/bindings/referenced/many_to_many_spec.rb +4 -4
  235. data/spec/mongoid/relations/builders_spec.rb +37 -10
  236. data/spec/mongoid/relations/counter_cache_spec.rb +64 -3
  237. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +16 -0
  238. data/spec/mongoid/relations/eager_spec.rb +40 -0
  239. data/spec/mongoid/relations/embedded/many_spec.rb +63 -47
  240. data/spec/mongoid/relations/embedded/one_spec.rb +2 -1
  241. data/spec/mongoid/relations/macros_spec.rb +395 -7
  242. data/spec/mongoid/relations/metadata_spec.rb +15 -1
  243. data/spec/mongoid/relations/proxy_spec.rb +27 -1
  244. data/spec/mongoid/relations/referenced/in_spec.rb +41 -1
  245. data/spec/mongoid/relations/referenced/many_spec.rb +13 -25
  246. data/spec/mongoid/relations/referenced/many_to_many_spec.rb +14 -26
  247. data/spec/mongoid/relations/synchronization_spec.rb +48 -2
  248. data/spec/mongoid/relations/touchable_spec.rb +40 -0
  249. data/spec/mongoid/reloadable_spec.rb +51 -0
  250. data/spec/mongoid/serializable_spec.rb +0 -50
  251. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  252. data/spec/mongoid/validatable/uniqueness_spec.rb +18 -9
  253. data/spec/mongoid/validatable_spec.rb +16 -0
  254. data/spec/spec_helper.rb +20 -11
  255. metadata +524 -469
  256. checksums.yaml.gz.sig +0 -0
  257. data.tar.gz.sig +0 -0
  258. data/lib/mongoid/clients/thread_options.rb +0 -19
  259. data/lib/mongoid/extensions/origin/regexp_raw.rb +0 -43
  260. metadata.gz.sig +0 -0
@@ -0,0 +1,844 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Criteria::Queryable::Selector do
4
+
5
+ describe "merge!" do
6
+
7
+ let(:selector) do
8
+ described_class.new
9
+ end
10
+
11
+ context "when selector is nested" do
12
+
13
+ before do
14
+ selector[:field] = selection
15
+ selector.merge!(other)
16
+ end
17
+
18
+ let(:selection) do
19
+ { "$lt" => 50 }
20
+ end
21
+
22
+ context "when other contains same key with a hash" do
23
+
24
+ let(:other) do
25
+ { "field" => { "$gt" => 20 } }
26
+ end
27
+
28
+ it "deep merges" do
29
+ expect(selector['field']).to eq({"$lt"=>50, "$gt" => 20})
30
+ end
31
+ end
32
+
33
+ context "when other contains same key without hash" do
34
+
35
+ let(:other) do
36
+ { "field" => 10 }
37
+ end
38
+
39
+ it "merges" do
40
+ expect(selector['field']).to eq(10)
41
+ end
42
+ end
43
+ end
44
+
45
+ context "when selector contains a $nin" do
46
+
47
+ let(:initial) do
48
+ { "$nin" => ["foo"] }
49
+ end
50
+
51
+ before do
52
+ selector["field"] = initial
53
+ end
54
+
55
+ context "when merging in a new $nin" do
56
+
57
+ let(:other) do
58
+ { "field" => { "$nin" => ["bar"] } }
59
+ end
60
+
61
+ before do
62
+ selector.merge!(other)
63
+ end
64
+
65
+ it "combines the two $nin queries into one" do
66
+ expect(selector).to eq({
67
+ "field" => { "$nin" => ["foo", "bar"] }
68
+ })
69
+ end
70
+ end
71
+ end
72
+
73
+ context "when selector contains a $in" do
74
+
75
+ let(:initial) do
76
+ { "$in" => [1, 2] }
77
+ end
78
+
79
+ before do
80
+ selector["field"] = initial
81
+ end
82
+
83
+ context "when merging in a new $in with an intersecting value" do
84
+
85
+ let(:other) do
86
+ { "field" => { "$in" => [1] } }
87
+ end
88
+
89
+ before do
90
+ selector.merge!(other)
91
+ end
92
+
93
+ it "intersects the $in values" do
94
+ expect(selector).to eq({
95
+ "field" => { "$in" => [1] }
96
+ })
97
+ end
98
+ end
99
+
100
+ context "when merging in a new $in with no intersecting values" do
101
+
102
+ let(:other) do
103
+ { "field" => { "$in" => [3] } }
104
+ end
105
+
106
+ before do
107
+ selector.merge!(other)
108
+ end
109
+
110
+ it "intersects the $in values" do
111
+ expect(selector).to eq({
112
+ "field" => { "$in" => [] }
113
+ })
114
+ end
115
+ end
116
+ end
117
+
118
+ context "when selector is not nested" do
119
+
120
+ before do
121
+ selector[:field] = selection
122
+ selector.merge!(other)
123
+ end
124
+
125
+ let(:selection) do
126
+ 50
127
+ end
128
+
129
+ let(:other) do
130
+ { "field" => { "$gt" => 20 } }
131
+ end
132
+
133
+ it "merges" do
134
+ expect(selector['field']).to eq({ "$gt" => 20 })
135
+ end
136
+ end
137
+
138
+ context 'when an object does not support the | operator' do
139
+
140
+ before do
141
+ selector['start'] = selection
142
+ selector.merge!(other)
143
+ end
144
+
145
+ let(:selection) do
146
+ { '$lt' => Time.now }
147
+ end
148
+
149
+ let(:other) do
150
+ { 'start' => selection, 'name' => 'test', }
151
+ end
152
+
153
+ it "merges" do
154
+ expect(selector['name']).to eq('test')
155
+ expect(selector['start']).to eq(selection)
156
+ end
157
+ end
158
+
159
+ context "when the selector contains an $or" do
160
+
161
+ let(:initial) do
162
+ [{ "value" => 1 }]
163
+ end
164
+
165
+ before do
166
+ selector["$or"] = initial
167
+ end
168
+
169
+ context "when merging in a new $or" do
170
+
171
+ let(:other) do
172
+ [{ "value" => 2 }]
173
+ end
174
+
175
+ before do
176
+ selector.merge!({ "$or" => other })
177
+ end
178
+
179
+ it "combines the two $or queries into one" do
180
+ expect(selector).to eq({
181
+ "$or" => [{ "value" => 1 }, { "value" => 2 }]
182
+ })
183
+ end
184
+ end
185
+ end
186
+
187
+ context "when the selector contains an $and" do
188
+
189
+ let(:initial) do
190
+ [{ "value" => 1 }]
191
+ end
192
+
193
+ before do
194
+ selector["$and"] = initial
195
+ end
196
+
197
+ context "when merging in a new $and" do
198
+
199
+ let(:other) do
200
+ [{ "value" => 2 }]
201
+ end
202
+
203
+ before do
204
+ selector.merge!({ "$and" => other })
205
+ end
206
+
207
+ it "combines the two $and queries into one" do
208
+ expect(selector).to eq({
209
+ "$and" => [{ "value" => 1 }, { "value" => 2 }]
210
+ })
211
+ end
212
+ end
213
+ end
214
+
215
+ context "when the selector contains a $nor" do
216
+
217
+ let(:initial) do
218
+ [{ "value" => 1 }]
219
+ end
220
+
221
+ before do
222
+ selector["$nor"] = initial
223
+ end
224
+
225
+ context "when merging in a new $nor" do
226
+
227
+ let(:other) do
228
+ [{ "value" => 2 }]
229
+ end
230
+
231
+ before do
232
+ selector.merge!({ "$nor" => other })
233
+ end
234
+
235
+ it "combines the two $nor queries into one" do
236
+ expect(selector).to eq({
237
+ "$nor" => initial + other
238
+ })
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ describe "#__deep_copy__" do
245
+
246
+ let(:value) do
247
+ [ 1, 2, 3 ]
248
+ end
249
+
250
+ let(:selection) do
251
+ { "$in" => value }
252
+ end
253
+
254
+ let(:selector) do
255
+ described_class.new
256
+ end
257
+
258
+ before do
259
+ selector[:field] = selection
260
+ end
261
+
262
+ let(:cloned) do
263
+ selector.__deep_copy__
264
+ end
265
+
266
+ it "returns an equal copy" do
267
+ expect(cloned).to eq(selector)
268
+ end
269
+
270
+ it "performs a deep copy" do
271
+ expect(cloned["field"]).to_not equal(selection)
272
+ end
273
+
274
+ it "clones n levels deep" do
275
+ expect(cloned["field"]["$in"]).to_not equal(value)
276
+ end
277
+ end
278
+
279
+ [ :store, :[]= ].each do |method|
280
+
281
+ describe "##{method}" do
282
+
283
+ context "when aliases are provided" do
284
+
285
+ context "when the alias has no serializer" do
286
+
287
+ let(:selector) do
288
+ described_class.new({ "id" => "_id" })
289
+ end
290
+
291
+ before do
292
+ selector.send(method, "id", 1)
293
+ end
294
+
295
+ it "stores the field in the selector by database name" do
296
+ expect(selector["_id"]).to eq(1)
297
+ end
298
+ end
299
+
300
+ context "when the alias has a serializer" do
301
+
302
+ before(:all) do
303
+ class Field
304
+ def evolve(object)
305
+ Integer.evolve(object)
306
+ end
307
+
308
+ def localized?
309
+ false
310
+ end
311
+ end
312
+ end
313
+
314
+ after(:all) do
315
+ Object.send(:remove_const, :Field)
316
+ end
317
+
318
+ let(:selector) do
319
+ described_class.new(
320
+ { "id" => "_id" }, { "_id" => Field.new }
321
+ )
322
+ end
323
+
324
+ it "stores the serialized field in the selector by database name" do
325
+ selector.send(method, "id", "1")
326
+ expect(selector["_id"]).to eq(1)
327
+ end
328
+
329
+ it "stores the serialized field when selector is deeply nested" do
330
+ selector.send(method, "$or", [{'$and' => [{'_id' => '5'}]}])
331
+ expect(selector['$or'][0]['$and'][0]['_id']).to eq(5)
332
+ end
333
+ end
334
+ end
335
+
336
+ context "when no serializers are provided" do
337
+
338
+ let(:selector) do
339
+ described_class.new
340
+ end
341
+
342
+ context "when provided a standard object" do
343
+
344
+ context "when the keys are strings" do
345
+
346
+ it "does not serialize values" do
347
+ expect(selector.send(method, "key", "5")).to eq("5")
348
+ end
349
+ end
350
+
351
+ context "when the keys are symbols" do
352
+
353
+ it "does not serialize values" do
354
+ expect(selector.send(method, :key, "5")).to eq("5")
355
+ end
356
+ end
357
+ end
358
+
359
+ context "when provided a range" do
360
+
361
+ before do
362
+ selector.send(method, "key", 1..3)
363
+ end
364
+
365
+ it "serializes the range" do
366
+ expect(selector["key"]).to eq({ "$gte" => 1, "$lte" => 3 })
367
+ end
368
+ end
369
+
370
+ context "when providing an array" do
371
+
372
+ let(:big_one) do
373
+ BigDecimal.new("1.2321")
374
+ end
375
+
376
+ let(:big_two) do
377
+ BigDecimal.new("4.2222")
378
+ end
379
+
380
+ let(:array) do
381
+ [ big_one, big_two ]
382
+ end
383
+
384
+ before do
385
+ selector.send(method, "key", array)
386
+ end
387
+
388
+ it "serializes each element in the array" do
389
+ expect(selector["key"]).to eq([ big_one.to_s, big_two.to_s ])
390
+ end
391
+ end
392
+ end
393
+
394
+ context "when serializers are provided" do
395
+
396
+ context "when the serializer is not localized" do
397
+
398
+ before(:all) do
399
+ class Field
400
+ def evolve(object)
401
+ Integer.evolve(object)
402
+ end
403
+
404
+ def localized?
405
+ false
406
+ end
407
+ end
408
+ end
409
+
410
+ after(:all) do
411
+ Object.send(:remove_const, :Field)
412
+ end
413
+
414
+ let(:selector) do
415
+ described_class.new({}, { "key" => Field.new })
416
+ end
417
+
418
+ context "when the criterion is simple" do
419
+
420
+ context "when the key is a string" do
421
+
422
+ before do
423
+ selector.send(method, "key", "5")
424
+ end
425
+
426
+ it "serializes the value" do
427
+ expect(selector["key"]).to eq(5)
428
+ end
429
+ end
430
+
431
+ context "when the key is a symbol" do
432
+
433
+ before do
434
+ selector.send(method, :key, "5")
435
+ end
436
+
437
+ it "serializes the value" do
438
+ expect(selector["key"]).to eq(5)
439
+ end
440
+ end
441
+ end
442
+
443
+ context "when the criterion is complex" do
444
+
445
+ context "when the field name is the key" do
446
+
447
+ context "when the criterion is an array" do
448
+
449
+ context "when the key is a string" do
450
+
451
+ before do
452
+ selector.send(method, "key", [ "1", "2" ])
453
+ end
454
+
455
+ it "serializes the value" do
456
+ expect(selector["key"]).to eq([ 1, 2 ])
457
+ end
458
+ end
459
+
460
+ context "when the key is a symbol" do
461
+
462
+ before do
463
+ selector.send(method, :key, [ "1", "2" ])
464
+ end
465
+
466
+ it "serializes the value" do
467
+ expect(selector["key"]).to eq([ 1, 2 ])
468
+ end
469
+ end
470
+ end
471
+
472
+ context "when the criterion is a hash" do
473
+
474
+ context "when the value is non enumerable" do
475
+
476
+ context "when the key is a string" do
477
+
478
+ before do
479
+ selector.send(method, "key", { "$gt" => "5" })
480
+ end
481
+
482
+ it "serializes the value" do
483
+ expect(selector["key"]).to eq({ "$gt" => 5 })
484
+ end
485
+ end
486
+
487
+ context "when the key is a symbol" do
488
+
489
+ before do
490
+ selector.send(method, :key, { "$gt" => "5" })
491
+ end
492
+
493
+ it "serializes the value" do
494
+ expect(selector["key"]).to eq({ "$gt" => 5 })
495
+ end
496
+ end
497
+ end
498
+
499
+ context "when the value is enumerable" do
500
+
501
+ context "when the key is a string" do
502
+
503
+ before do
504
+ selector.send(method, "key", { "$in" => [ "1", "2" ] })
505
+ end
506
+
507
+ it "serializes the value" do
508
+ expect(selector["key"]).to eq({ "$in" => [ 1, 2 ] })
509
+ end
510
+ end
511
+
512
+ context "when the key is a symbol" do
513
+
514
+ before do
515
+ selector.send(method, :key, { "$in" => [ "1", "2" ] })
516
+ end
517
+
518
+ it "serializes the value" do
519
+ expect(selector["key"]).to eq({ "$in" => [ 1, 2 ] })
520
+ end
521
+ end
522
+ end
523
+
524
+ [ "$and", "$or" ].each do |operator|
525
+
526
+ context "when the criterion is a #{operator}" do
527
+
528
+ context "when the individual criteria are simple" do
529
+
530
+ context "when the keys are strings" do
531
+
532
+ before do
533
+ selector.send(method, operator, [{ "key" => "1" }])
534
+ end
535
+
536
+ it "serializes the values" do
537
+ expect(selector[operator]).to eq([{ "key" => 1 }])
538
+ end
539
+ end
540
+
541
+ context "when the keys are symbols" do
542
+
543
+ before do
544
+ selector.send(method, operator, [{ key: "1" }])
545
+ end
546
+
547
+ it "serializes the values" do
548
+ expect(selector[operator]).to eq([{ "key" => 1 }])
549
+ end
550
+ end
551
+ end
552
+
553
+ context "when the individual criteria are complex" do
554
+
555
+ context "when the keys are strings" do
556
+
557
+ before do
558
+ selector.send(
559
+ method,
560
+ operator,
561
+ [{ "field" => "1" }, { "key" => { "$gt" => "2" }}]
562
+ )
563
+ end
564
+
565
+ it "serializes the values" do
566
+ expect(selector[operator]).to eq(
567
+ [{ "field" => "1" }, { "key" => { "$gt" => 2 }}]
568
+ )
569
+ end
570
+ end
571
+
572
+ context "when the keys are symbols" do
573
+
574
+ before do
575
+ selector.send(
576
+ method,
577
+ operator,
578
+ [{ field: "1" }, { key: { "$gt" => "2" }}]
579
+ )
580
+ end
581
+
582
+ it "serializes the values" do
583
+ expect(selector[operator]).to eq(
584
+ [{ "field" => "1" }, { "key" => { "$gt" => 2 }}]
585
+ )
586
+ end
587
+ end
588
+ end
589
+ end
590
+ end
591
+ end
592
+ end
593
+ end
594
+ end
595
+
596
+ context "when the serializer is localized" do
597
+
598
+ before(:all) do
599
+ class Field
600
+ def evolve(object)
601
+ Integer.evolve(object)
602
+ end
603
+
604
+ def localized?
605
+ true
606
+ end
607
+ end
608
+ end
609
+
610
+ after(:all) do
611
+ Object.send(:remove_const, :Field)
612
+ ::I18n.locale = :en
613
+ end
614
+
615
+ let(:selector) do
616
+ described_class.new({}, { "key" => Field.new })
617
+ end
618
+
619
+ before do
620
+ ::I18n.locale = :de
621
+ end
622
+
623
+ context "when the criterion is simple" do
624
+
625
+ context "when the key is a string" do
626
+
627
+ before do
628
+ selector.send(method, "key", "5")
629
+ end
630
+
631
+ it "serializes the value" do
632
+ expect(selector["key.de"]).to eq(5)
633
+ end
634
+ end
635
+
636
+ context "when the key is a symbol" do
637
+
638
+ before do
639
+ selector.send(method, :key, "5")
640
+ end
641
+
642
+ it "serializes the value" do
643
+ expect(selector["key.de"]).to eq(5)
644
+ end
645
+ end
646
+ end
647
+
648
+ context "when the criterion is complex" do
649
+
650
+ context "when the field name is the key" do
651
+
652
+ context "when the criterion is an array" do
653
+
654
+ context "when the key is a string" do
655
+
656
+ before do
657
+ selector.send(method, "key", [ "1", "2" ])
658
+ end
659
+
660
+ it "serializes the value" do
661
+ expect(selector["key.de"]).to eq([ 1, 2 ])
662
+ end
663
+ end
664
+
665
+ context "when the key is a symbol" do
666
+
667
+ before do
668
+ selector.send(method, :key, [ "1", "2" ])
669
+ end
670
+
671
+ it "serializes the value" do
672
+ expect(selector["key.de"]).to eq([ 1, 2 ])
673
+ end
674
+ end
675
+ end
676
+
677
+ context "when the criterion is a hash" do
678
+
679
+ context "when the value is non enumerable" do
680
+
681
+ context "when the key is a string" do
682
+
683
+ let(:hash) do
684
+ { "$gt" => "5" }
685
+ end
686
+
687
+ before do
688
+ selector.send(method, "key", hash)
689
+ end
690
+
691
+ it "serializes the value" do
692
+ expect(selector["key.de"]).to eq({ "$gt" => 5 })
693
+ end
694
+
695
+ it "sets the same hash instance" do
696
+ expect(selector["key.de"]).to equal(hash)
697
+ end
698
+ end
699
+
700
+ context "when the key is a symbol" do
701
+
702
+ before do
703
+ selector.send(method, :key, { "$gt" => "5" })
704
+ end
705
+
706
+ it "serializes the value" do
707
+ expect(selector["key.de"]).to eq({ "$gt" => 5 })
708
+ end
709
+ end
710
+ end
711
+
712
+ context "when the value is enumerable" do
713
+
714
+ context "when the key is a string" do
715
+
716
+ before do
717
+ selector.send(method, "key", { "$in" => [ "1", "2" ] })
718
+ end
719
+
720
+ it "serializes the value" do
721
+ expect(selector["key.de"]).to eq({ "$in" => [ 1, 2 ] })
722
+ end
723
+ end
724
+
725
+ context "when the key is a symbol" do
726
+
727
+ before do
728
+ selector.send(method, :key, { "$in" => [ "1", "2" ] })
729
+ end
730
+
731
+ it "serializes the value" do
732
+ expect(selector["key.de"]).to eq({ "$in" => [ 1, 2 ] })
733
+ end
734
+ end
735
+ end
736
+
737
+ [ "$and", "$or" ].each do |operator|
738
+
739
+ context "when the criterion is a #{operator}" do
740
+
741
+ context "when the individual criteria are simple" do
742
+
743
+ context "when the keys are strings" do
744
+
745
+ before do
746
+ selector.send(method, operator, [{ "key" => "1" }])
747
+ end
748
+
749
+ it "serializes the values" do
750
+ expect(selector[operator]).to eq([{ "key.de" => 1 }])
751
+ end
752
+ end
753
+
754
+ context "when the keys are symbols" do
755
+
756
+ before do
757
+ selector.send(method, operator, [{ key: "1" }])
758
+ end
759
+
760
+ it "serializes the values" do
761
+ expect(selector[operator]).to eq([{ "key.de" => 1 }])
762
+ end
763
+ end
764
+ end
765
+
766
+ context "when the individual criteria are complex" do
767
+
768
+ context "when the keys are strings" do
769
+
770
+ before do
771
+ selector.send(
772
+ method,
773
+ operator,
774
+ [{ "field" => "1" }, { "key" => { "$gt" => "2" }}]
775
+ )
776
+ end
777
+
778
+ it "serializes the values" do
779
+ expect(selector[operator]).to eq(
780
+ [{ "field" => "1" }, { "key.de" => { "$gt" => 2 }}]
781
+ )
782
+ end
783
+ end
784
+
785
+ context "when the keys are symbols" do
786
+
787
+ before do
788
+ selector.send(
789
+ method,
790
+ operator,
791
+ [{ field: "1" }, { key: { "$gt" => "2" }}]
792
+ )
793
+ end
794
+
795
+ it "serializes the values" do
796
+ expect(selector[operator]).to eq(
797
+ [{ "field" => "1" }, { "key.de" => { "$gt" => 2 }}]
798
+ )
799
+ end
800
+ end
801
+ end
802
+ end
803
+ end
804
+ end
805
+ end
806
+ end
807
+ end
808
+ end
809
+ end
810
+ end
811
+
812
+ describe "#to_pipeline" do
813
+
814
+ let(:selector) do
815
+ described_class.new
816
+ end
817
+
818
+ context "when the selector is empty" do
819
+
820
+ let(:pipeline) do
821
+ selector.to_pipeline
822
+ end
823
+
824
+ it "returns an empty array" do
825
+ expect(pipeline).to be_empty
826
+ end
827
+ end
828
+
829
+ context "when the selector is not empty" do
830
+
831
+ before do
832
+ selector["name"] = "test"
833
+ end
834
+
835
+ let(:pipeline) do
836
+ selector.to_pipeline
837
+ end
838
+
839
+ it "returns the selector in a $match entry" do
840
+ expect(pipeline).to eq([{ "$match" => { "name" => "test" }}])
841
+ end
842
+ end
843
+ end
844
+ end