mongoid 7.2.0 → 7.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +1 -1
  5. data/lib/mongoid/attributes.rb +8 -1
  6. data/lib/mongoid/criteria/queryable/selector.rb +0 -4
  7. data/lib/mongoid/document.rb +3 -2
  8. data/lib/mongoid/errors/mongoid_error.rb +1 -1
  9. data/lib/mongoid/interceptable.rb +3 -1
  10. data/lib/mongoid/matcher.rb +19 -43
  11. data/lib/mongoid/matcher/elem_match.rb +2 -1
  12. data/lib/mongoid/matcher/expression.rb +5 -14
  13. data/lib/mongoid/matcher/field_expression.rb +4 -5
  14. data/lib/mongoid/matcher/field_operator.rb +7 -11
  15. data/lib/mongoid/reloadable.rb +5 -0
  16. data/lib/mongoid/validatable/associated.rb +1 -1
  17. data/lib/mongoid/validatable/presence.rb +3 -3
  18. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  19. data/lib/mongoid/version.rb +1 -1
  20. data/lib/rails/generators/mongoid/config/config_generator.rb +8 -1
  21. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +1 -1
  22. data/spec/integration/app_spec.rb +174 -84
  23. data/spec/integration/callbacks_models.rb +49 -0
  24. data/spec/integration/callbacks_spec.rb +216 -0
  25. data/spec/integration/document_spec.rb +21 -0
  26. data/spec/integration/matcher_operator_data/elem_match.yml +46 -0
  27. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  28. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  29. data/spec/integration/matcher_operator_data/implicit_traversal.yml +96 -0
  30. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  31. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  32. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  33. data/spec/lite_spec_helper.rb +3 -4
  34. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +50 -0
  35. data/spec/mongoid/atomic/paths_spec.rb +41 -0
  36. data/spec/mongoid/attributes_spec.rb +241 -0
  37. data/spec/mongoid/contextual/atomic_spec.rb +17 -4
  38. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +36 -0
  39. data/spec/mongoid/document_fields_spec.rb +26 -0
  40. data/spec/mongoid/document_query_spec.rb +51 -0
  41. data/spec/mongoid/errors/mongoid_error_spec.rb +20 -8
  42. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  43. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +68 -88
  44. data/spec/mongoid/matcher/extract_attribute_spec.rb +3 -13
  45. data/spec/mongoid/persistable/settable_spec.rb +30 -0
  46. data/spec/mongoid/persistable_spec.rb +2 -2
  47. data/spec/shared/bin/get-mongodb-download-url +17 -0
  48. data/spec/shared/bin/s3-copy +45 -0
  49. data/spec/shared/bin/s3-upload +69 -0
  50. data/spec/shared/lib/mrss/cluster_config.rb +226 -0
  51. data/spec/shared/lib/mrss/constraints.rb +71 -6
  52. data/spec/shared/lib/mrss/docker_runner.rb +271 -0
  53. data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
  54. data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
  55. data/spec/shared/lib/mrss/spec_organizer.rb +32 -2
  56. data/spec/shared/lib/mrss/utils.rb +15 -0
  57. data/spec/shared/share/Dockerfile.erb +322 -0
  58. data/spec/shared/share/haproxy-1.conf +16 -0
  59. data/spec/shared/share/haproxy-2.conf +17 -0
  60. data/spec/shared/shlib/distro.sh +73 -0
  61. data/spec/shared/shlib/server.sh +317 -0
  62. data/spec/shared/shlib/set_env.sh +131 -0
  63. data/spec/spec_helper.rb +1 -1
  64. data/spec/support/models/customer.rb +11 -0
  65. data/spec/support/models/customer_address.rb +12 -0
  66. data/spec/support/models/dictionary.rb +6 -0
  67. data/spec/support/models/mop.rb +10 -0
  68. data/spec/support/spec_config.rb +8 -0
  69. metadata +554 -508
  70. metadata.gz.sig +3 -2
@@ -1447,6 +1447,42 @@ describe Mongoid::Criteria::Queryable::Selectable do
1447
1447
  end
1448
1448
  end
1449
1449
  end
1450
+
1451
+ context 'when using multiple criteria and symbol operators' do
1452
+ context 'when using fields that meaningfully evolve values' do
1453
+
1454
+ let(:query) do
1455
+ Dictionary.any_of({a: 1}, :published.gt => Date.new(2020, 2, 3))
1456
+ end
1457
+
1458
+ it 'generates the expected query' do
1459
+ query.selector.should == {'$or' => [
1460
+ {'a' => 1},
1461
+ # Date instance is converted to a Time instance in local time,
1462
+ # because we are querying on a Time field and dates are interpreted
1463
+ # in local time when assigning to Time fields
1464
+ {'published' => {'$gt' => Time.local(2020, 2, 3)}},
1465
+ ]}
1466
+ end
1467
+ end
1468
+
1469
+ context 'when using fields that do not meaningfully evolve values' do
1470
+
1471
+ let(:query) do
1472
+ Dictionary.any_of({a: 1}, :submitted_on.gt => Date.new(2020, 2, 3))
1473
+ end
1474
+
1475
+ it 'generates the expected query' do
1476
+ query.selector.should == {'$or' => [
1477
+ {'a' => 1},
1478
+ # Date instance is converted to a Time instance in UTC,
1479
+ # because we are querying on a Date field and dates are interpreted
1480
+ # in UTC when persisted as dates by Mongoid
1481
+ {'submitted_on' => {'$gt' => Time.utc(2020, 2, 3)}},
1482
+ ]}
1483
+ end
1484
+ end
1485
+ end
1450
1486
  end
1451
1487
 
1452
1488
  describe "#not" do
@@ -85,4 +85,30 @@ describe Mongoid::Document do
85
85
  end
86
86
  end
87
87
  end
88
+
89
+ context 'Regexp field' do
90
+ shared_examples "persists strings as regexp" do |type|
91
+ it 'persists strings as regexp' do
92
+ mop = Mop.create!(regexp_field: 'foo')
93
+ expect(mop.regexp_field).to be_a Regexp
94
+ expect(Mop.find(mop.id).regexp_field).to be_a BSON::Regexp::Raw
95
+ expect(
96
+ Mop.collection.find(
97
+ "_id" => mop.id,
98
+ "regexp_field" => { "$type" => type }
99
+ ).count
100
+ ).to be == 1
101
+ end
102
+ end
103
+
104
+ context "< 3.2" do
105
+ max_server_version("3.1")
106
+ include_examples "persists strings as regexp", 11
107
+ end
108
+
109
+ context ">= 3.2" do
110
+ min_server_version("3.2")
111
+ it_behaves_like "persists strings as regexp", "regex"
112
+ end
113
+ end
88
114
  end
@@ -36,4 +36,55 @@ describe Mongoid::Document do
36
36
  expect(_person.age).to be 42
37
37
  end
38
38
  end
39
+
40
+ context 'when projecting with #without' do
41
+ before do
42
+ duck = Pet.new(name: 'Duck')
43
+ Person.create!(username: 'Dev', title: 'CEO', pet: duck)
44
+ end
45
+
46
+ let(:person) { Person.where(username: 'Dev').without(:title).first }
47
+
48
+ it 'allows access to attribute of embedded document' do
49
+ expect(person.pet.name).to eq 'Duck'
50
+ end
51
+
52
+ context 'when exclusion starts with association name but is not the association' do
53
+
54
+ let(:person) { Person.where(username: 'Dev').without(:pet_).first }
55
+
56
+ it 'allows access to attribute of embedded document' do
57
+ expect(person.pet.name).to eq 'Duck'
58
+ end
59
+ end
60
+
61
+ context 'when exclusion starts with prefix of association name' do
62
+
63
+ let(:person) { Person.where(username: 'Dev').without(:pe).first }
64
+
65
+ it 'allows access to attribute of embedded document' do
66
+ expect(person.pet.name).to eq 'Duck'
67
+ end
68
+ end
69
+
70
+ context 'when another attribute of the association is excluded' do
71
+
72
+ let(:person) { Person.where(username: 'Dev').without('pet.weight').first }
73
+
74
+ it 'allows access to non-excluded attribute of embedded document' do
75
+ expect(person.pet.name).to eq 'Duck'
76
+ end
77
+ end
78
+
79
+ context 'when the excluded attribute of the association is retrieved' do
80
+
81
+ let(:person) { Person.where(username: 'Dev').without('pet.name').first }
82
+
83
+ it 'prohibits the retrieval' do
84
+ lambda do
85
+ person.pet.name
86
+ end.should raise_error(ActiveModel::MissingAttributeError)
87
+ end
88
+ end
89
+ end
39
90
  end
@@ -10,14 +10,26 @@ describe Mongoid::Errors::MongoidError do
10
10
  let(:options) { {} }
11
11
 
12
12
  before do
13
- {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
14
- expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", {}).and_return(name)
15
- end
16
-
17
- ["message", "summary", "resolution"].each do |name|
18
- expect(::I18n).to receive(:translate).
19
- with("mongoid.errors.messages.#{key}.#{name}", {}).
20
- and_return(name)
13
+ if RUBY_VERSION.start_with?('3.', '2.7')
14
+ {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
15
+ expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", **{}).and_return(name)
16
+ end
17
+
18
+ ["message", "summary", "resolution"].each do |name|
19
+ expect(::I18n).to receive(:translate).
20
+ with("mongoid.errors.messages.#{key}.#{name}", **{}).
21
+ and_return(name)
22
+ end
23
+ else
24
+ {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
25
+ expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", {}).and_return(name)
26
+ end
27
+
28
+ ["message", "summary", "resolution"].each do |name|
29
+ expect(::I18n).to receive(:translate).
30
+ with("mongoid.errors.messages.#{key}.#{name}", {}).
31
+ and_return(name)
32
+ end
21
33
  end
22
34
 
23
35
  error.compose_message(key, options)
@@ -0,0 +1,104 @@
1
+ - name: string key - matches
2
+ document:
3
+ # Document field names in MongoDB are always strings.
4
+ '42': foo
5
+ # The paths are also always strings.
6
+ key: '42'
7
+
8
+ result:
9
+ - foo
10
+
11
+ - name: string key - does not match
12
+ document:
13
+ # Document field names in MongoDB are always strings.
14
+ '42': foo
15
+ # The paths are also always strings.
16
+ key: '4'
17
+
18
+ result: []
19
+
20
+ - name: array value - matches
21
+ document:
22
+ '42':
23
+ - foo
24
+ key: '42'
25
+
26
+ result:
27
+ - ['foo']
28
+
29
+ - name: subfield of numeric key - matches
30
+ document:
31
+ '42':
32
+ foo: bar
33
+ key: 42.foo
34
+
35
+ result:
36
+ - bar
37
+
38
+ - name: numeric key under array
39
+ document:
40
+ a:
41
+ -
42
+ '42': bar
43
+
44
+ key: a.42
45
+
46
+ result:
47
+ - bar
48
+
49
+ - name: multiple values under numeric key under array
50
+ document: &numeric-key-under-array
51
+ a:
52
+ -
53
+ '42': bar
54
+ -
55
+ '42': foo
56
+
57
+ key: a.42
58
+
59
+ result:
60
+ - bar
61
+ - foo
62
+
63
+ - name: array indexing with values under numeric key under array
64
+ document: *numeric-key-under-array
65
+
66
+ key: a.1
67
+
68
+ result:
69
+ -
70
+ '42': foo
71
+
72
+ - name: multiple values under array under numeric key
73
+ document:
74
+ a:
75
+ '42':
76
+ -
77
+ foo: bar
78
+ -
79
+ foo: baq
80
+
81
+ key: a.42.foo
82
+
83
+ result:
84
+ - bar
85
+ - baq
86
+
87
+ - name: path component interpretable as both array index and hash key
88
+ document:
89
+ a:
90
+ -
91
+ '1': bar
92
+ -
93
+ '1': foo
94
+
95
+ key: a.1
96
+
97
+ result:
98
+ # The order of these results isn't guaranteed:
99
+ # 1 interpreted as the array index:
100
+ -
101
+ '1': foo
102
+ # 1 interpreted as hash key:
103
+ - bar
104
+ - foo
@@ -3,9 +3,8 @@
3
3
  name: foo
4
4
  key: name
5
5
 
6
- exists: true
7
- value: foo
8
- expanded: false
6
+ result:
7
+ - foo
9
8
 
10
9
  - name: scalar leaf
11
10
  document: &foo-bar-foo-bar-2
@@ -16,20 +15,26 @@
16
15
  2
17
16
  key: foo.bar.foo.bar
18
17
 
19
- exists: true
20
- value: 2
21
- expanded: false
18
+ result:
19
+ - 2
22
20
 
23
21
  - name: scalar non-leaf
24
22
  document: *foo-bar-foo-bar-2
25
23
  key: foo.bar
26
24
 
27
- exists: true
28
- value:
29
- foo:
30
- bar:
31
- 2
32
- expanded: false
25
+ result:
26
+ -
27
+ foo:
28
+ bar:
29
+ 2
30
+
31
+ - name: null leaf
32
+ document:
33
+ name:
34
+ key: name
35
+
36
+ result:
37
+ - ~
33
38
 
34
39
  - name: array leaf
35
40
  document: &foo-bar-foo-bar-array-2
@@ -40,21 +45,18 @@
40
45
  - 2
41
46
  key: foo.bar.foo.bar
42
47
 
43
- exists: true
44
- value:
45
- - 2
46
- expanded: false
48
+ result:
49
+ - [2]
47
50
 
48
51
  - name: scalar non-leaf
49
52
  document: *foo-bar-foo-bar-array-2
50
53
  key: foo.bar
51
54
 
52
- exists: true
53
- value:
54
- foo:
55
- bar:
56
- - 2
57
- expanded: false
55
+ result:
56
+ -
57
+ foo:
58
+ bar:
59
+ - 2
58
60
 
59
61
  - name: array non-leaf
60
62
  document: &foo-bar-array-foo-bar-2
@@ -66,30 +68,24 @@
66
68
  2
67
69
  key: foo.bar.foo.bar
68
70
 
69
- exists: true
70
- value:
71
+ result:
71
72
  - 2
72
- expanded: true
73
73
 
74
74
  - name: array non-leaf with non-leaf query
75
75
  document: *foo-bar-array-foo-bar-2
76
76
  key: foo.bar
77
77
 
78
- exists: true
79
- value:
78
+ result:
80
79
  -
81
80
  foo:
82
81
  bar:
83
82
  2
84
- expanded: true
85
83
 
86
84
  - name: array non-leaf with query for missing non-leaf key
87
85
  document: *foo-bar-array-foo-bar-2
88
86
  key: foo.missing
89
87
 
90
- exists: false
91
- value: []
92
- expanded: true
88
+ result: []
93
89
 
94
90
  - name: path past end of document
95
91
  document: &foo-hello-world
@@ -97,17 +93,23 @@
97
93
  hello: world
98
94
  key: foo.bar.foo.bar
99
95
 
100
- exists: false
101
- value: ~
102
- expanded: false
96
+ result: []
103
97
 
104
98
  - name: query for missing leaf key
105
99
  document: *foo-hello-world
106
100
  key: foo.bar
107
101
 
108
- exists: false
109
- value: ~
110
- expanded: false
102
+ result: []
103
+
104
+ - name: numeric path component when traversing hash
105
+ document:
106
+ foo:
107
+ "10":
108
+ 42
109
+ key: "foo.10"
110
+
111
+ result:
112
+ - 42
111
113
 
112
114
  - name: array index - hash leaf
113
115
  document: &foo-one-two
@@ -117,42 +119,35 @@
117
119
  bar: [3, 4]
118
120
  key: foo.1.two
119
121
 
120
- exists: true
121
- value: 2
122
- expanded: false
122
+ result:
123
+ - 2
123
124
 
124
125
  - name: array index - hash non-leaf
125
126
  document: *foo-one-two
126
127
  key: foo.1
127
128
 
128
- exists: true
129
- value:
130
- two: 2
131
- expanded: false
129
+ result:
130
+ -
131
+ two: 2
132
132
 
133
133
  - name: array index - scalar leaf
134
134
  document: *foo-one-two
135
135
  key: bar.1
136
136
 
137
- exists: true
138
- value: 4
139
- expanded: false
137
+ result:
138
+ - 4
140
139
 
141
140
  - name: array index - scalar leaf - missing
142
141
  document: *foo-one-two
143
142
  key: bar.2
144
143
 
145
- exists: false
146
- value: ~
147
- expanded: false
144
+ result: []
148
145
 
149
146
  - name: array index - scalar leaf - missing with further hash subscription
150
147
  document: *foo-one-two
151
148
  key: bar.2.any
152
149
 
153
- exists: false
154
- value: ~
155
- expanded: false
150
+ result: []
156
151
 
157
152
  - name: non-sequential nested arrays - hash leaf - one value
158
153
  document: &books-authors
@@ -166,30 +161,27 @@
166
161
  - name: Pasha
167
162
  key: books.0.authors.name
168
163
 
169
- exists: true
170
- value: [Steve]
171
- expanded: true
164
+ result:
165
+ - Steve
172
166
 
173
167
  - name: non-sequential nested arrays - hash non-leaf - one value
174
168
  document: *books-authors
175
169
  key: books.0
176
170
 
177
- exists: true
178
- value:
179
- authors:
180
- - name: Steve
181
- expanded: false
171
+ result:
172
+ -
173
+ authors:
174
+ - name: Steve
182
175
 
183
176
  - name: non-sequential nested arrays - hash non-leaf - multiple values
184
177
  document: *books-authors
185
178
  key: books.1
186
179
 
187
- exists: true
188
- value:
189
- authors:
190
- - name: Boris
191
- - name: Pasha
192
- expanded: false
180
+ result:
181
+ -
182
+ authors:
183
+ - name: Boris
184
+ - name: Pasha
193
185
 
194
186
  - name: sequential nested arrays - numerically indexed leaf
195
187
  document: &groups
@@ -197,41 +189,32 @@
197
189
  - [1]
198
190
  key: groups.0.0
199
191
 
200
- exists: true
201
- value: 1
202
- expanded: false
192
+ result:
193
+ - 1
203
194
 
204
195
  - name: sequential nested arrays - numerically indexed leaf - missing
205
196
  document: *groups
206
197
  key: groups.0.1
207
198
 
208
- exists: false
209
- value: ~
210
- expanded: false
199
+ result: []
211
200
 
212
201
  - name: sequential nested arrays - missing hash path through non-leaf
213
202
  document: *groups
214
203
  key: groups.missing
215
204
 
216
- exists: false
217
- value: []
218
- expanded: true
205
+ result: []
219
206
 
220
207
  - name: sequential nested arrays - missing hash path through leaf
221
208
  document: *groups
222
209
  key: groups.0.missing
223
210
 
224
- exists: false
225
- value: []
226
- expanded: true
211
+ result: []
227
212
 
228
213
  - name: sequential nested arrays - missing hash path past leaf
229
214
  document: *groups
230
215
  key: groups.0.0.missing
231
216
 
232
- exists: false
233
- value: ~
234
- expanded: false
217
+ result: []
235
218
 
236
219
  - name: mix of arrays and hashes in an array
237
220
  document:
@@ -242,9 +225,8 @@
242
225
  - bar: 2
243
226
  key: foo.bar
244
227
 
245
- exists: true
246
- value: [2]
247
- expanded: true
228
+ result:
229
+ - 2
248
230
 
249
231
  - name: numeric index through a primitive value not supporting subscription operator
250
232
  document:
@@ -254,6 +236,4 @@
254
236
  key:
255
237
  occupants.0.age.0
256
238
 
257
- exists: false
258
- value: ~
259
- expanded: false
239
+ result: []