mongoid 8.0.4 → 8.0.6
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Rakefile +25 -0
- data/lib/mongoid/association/macros.rb +6 -0
- data/lib/mongoid/atomic.rb +7 -0
- data/lib/mongoid/attributes/processing.rb +29 -5
- data/lib/mongoid/changeable.rb +1 -3
- data/lib/mongoid/config/options.rb +3 -0
- data/lib/mongoid/config.rb +17 -0
- data/lib/mongoid/criteria/queryable/selector.rb +1 -1
- data/lib/mongoid/criteria/queryable/storable.rb +1 -1
- data/lib/mongoid/extensions/hash.rb +6 -2
- data/lib/mongoid/fields.rb +45 -18
- data/lib/mongoid/reloadable.rb +3 -5
- data/lib/mongoid/version.rb +1 -1
- data/spec/mongoid/attributes_spec.rb +27 -0
- data/spec/mongoid/config_spec.rb +9 -0
- data/spec/mongoid/contextual/mongo_spec.rb +41 -11
- data/spec/mongoid/criteria/queryable/selector_spec.rb +75 -2
- data/spec/mongoid/criteria/queryable/storable_spec.rb +72 -0
- data/spec/mongoid/extensions/hash_spec.rb +3 -3
- data/spec/mongoid/fields_spec.rb +43 -0
- data/spec/mongoid/reloadable_spec.rb +24 -0
- data/spec/mongoid_spec.rb +1 -1
- data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
- data/spec/shared/lib/mrss/lite_constraints.rb +8 -0
- data/spec/shared/shlib/server.sh +5 -5
- data/spec/support/models/person.rb +1 -0
- data/spec/support/models/purse.rb +9 -0
- data.tar.gz.sig +0 -0
- metadata +654 -652
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51995917ca452899edfb1e432aecad879c476f89057c5377e55081a5c2a989ac
|
4
|
+
data.tar.gz: b01e8f7141b1f37d0ddfc51b5e4fa889f09b85988069af8cc8af7214a00a888c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a011a2367c77d3e7abdc57a3781f45c97c71451afcaae7a3358a3e0173e8d3bc4ef09ef92d32f8d72c14ca89b5d8f3d9fccdf8b0a7b84ccb9a874329413b561
|
7
|
+
data.tar.gz: a868fc0217fc98cccfa8b6c3f9c0dccb4425354ddb4f23a1819f52dc539e2754e8dd8a508a804e05bddeeb8be73fe09ff6f027d141a22d3f479c3adc63097fcb
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/Rakefile
CHANGED
@@ -11,6 +11,15 @@ $: << File.join(ROOT, 'spec/shared/lib')
|
|
11
11
|
require "rake"
|
12
12
|
require "rspec/core/rake_task"
|
13
13
|
require 'mrss/spec_organizer'
|
14
|
+
require 'rubygems/package'
|
15
|
+
require 'rubygems/security/policies'
|
16
|
+
|
17
|
+
def signed_gem?(path_to_gem)
|
18
|
+
Gem::Package.new(path_to_gem, Gem::Security::HighSecurity).verify
|
19
|
+
true
|
20
|
+
rescue Gem::Security::Exception => e
|
21
|
+
false
|
22
|
+
end
|
14
23
|
|
15
24
|
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
16
25
|
require "mongoid/version"
|
@@ -103,3 +112,19 @@ namespace :release do
|
|
103
112
|
end
|
104
113
|
end
|
105
114
|
end
|
115
|
+
|
116
|
+
desc 'Verifies that all built gems in pkg/ are valid'
|
117
|
+
task :verify do
|
118
|
+
gems = Dir['pkg/*.gem']
|
119
|
+
if gems.empty?
|
120
|
+
puts 'There are no gems in pkg/ to verify'
|
121
|
+
else
|
122
|
+
gems.each do |gem|
|
123
|
+
if signed_gem?(gem)
|
124
|
+
puts "#{gem} is signed"
|
125
|
+
else
|
126
|
+
abort "#{gem} is not signed"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -35,10 +35,15 @@ module Mongoid
|
|
35
35
|
# @api private
|
36
36
|
class_attribute :aliased_associations
|
37
37
|
|
38
|
+
# @return [ Set<String> ] The set of associations that are configured
|
39
|
+
# with :store_as parameter.
|
40
|
+
class_attribute :stored_as_associations
|
41
|
+
|
38
42
|
self.embedded = false
|
39
43
|
self.embedded_relations = BSON::Document.new
|
40
44
|
self.relations = BSON::Document.new
|
41
45
|
self.aliased_associations = {}
|
46
|
+
self.stored_as_associations = Set.new
|
42
47
|
end
|
43
48
|
|
44
49
|
# This is convenience for libraries still on the old API.
|
@@ -219,6 +224,7 @@ module Mongoid
|
|
219
224
|
self.relations = self.relations.merge(name => assoc)
|
220
225
|
if assoc.embedded? && assoc.respond_to?(:store_as) && assoc.store_as != name
|
221
226
|
self.aliased_associations[assoc.store_as] = name
|
227
|
+
self.stored_as_associations << assoc.store_as
|
222
228
|
end
|
223
229
|
end
|
224
230
|
end
|
data/lib/mongoid/atomic.rb
CHANGED
@@ -311,6 +311,13 @@ module Mongoid
|
|
311
311
|
|
312
312
|
private
|
313
313
|
|
314
|
+
# Clears all pending atomic updates.
|
315
|
+
def reset_atomic_updates!
|
316
|
+
Atomic::UPDATES.each do |update|
|
317
|
+
send(update).clear
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
314
321
|
# Generates the atomic updates in the correct order.
|
315
322
|
#
|
316
323
|
# @example Generate the updates.
|
@@ -43,22 +43,46 @@ module Mongoid
|
|
43
43
|
# @return [ true | false ] True if pending, false if not.
|
44
44
|
def pending_attribute?(key, value)
|
45
45
|
name = key.to_s
|
46
|
-
|
47
46
|
aliased = if aliased_associations.key?(name)
|
48
47
|
aliased_associations[name]
|
49
48
|
else
|
50
49
|
name
|
51
50
|
end
|
52
|
-
|
53
51
|
if relations.has_key?(aliased)
|
54
|
-
|
52
|
+
set_pending_relation(name, aliased, value)
|
55
53
|
return true
|
56
54
|
end
|
57
55
|
if nested_attributes.has_key?(aliased)
|
58
|
-
|
56
|
+
set_pending_nested(name, aliased, value)
|
59
57
|
return true
|
60
58
|
end
|
61
|
-
|
59
|
+
false
|
60
|
+
end
|
61
|
+
|
62
|
+
# Set value of the pending relation.
|
63
|
+
#
|
64
|
+
# @param [ Symbol ] name The name of the relation.
|
65
|
+
# @param [ Symbol ] aliased The aliased name of the relation.
|
66
|
+
# @param [ Object ] value The value of the relation.
|
67
|
+
def set_pending_relation(name, aliased, value)
|
68
|
+
if stored_as_associations.include?(name)
|
69
|
+
pending_relations[aliased] = value
|
70
|
+
else
|
71
|
+
pending_relations[name] = value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Set value of the pending nested attribute.
|
76
|
+
#
|
77
|
+
# @param [ Symbol ] name The name of the nested attribute.
|
78
|
+
# @param [ Symbol ] aliased The aliased name of the nested attribute.
|
79
|
+
# @param [ Object ] value The value of the nested attribute.
|
80
|
+
def set_pending_nested(name, aliased, value)
|
81
|
+
if stored_as_associations.include?(name)
|
82
|
+
pending_nested[aliased] = value
|
83
|
+
else
|
84
|
+
pending_nested[name] = value
|
85
|
+
end
|
62
86
|
end
|
63
87
|
|
64
88
|
# Get all the pending associations that need to be set.
|
data/lib/mongoid/changeable.rb
CHANGED
@@ -25,6 +25,8 @@ module Mongoid
|
|
25
25
|
# @param [ Hash ] options Extras for the option.
|
26
26
|
#
|
27
27
|
# @option options [ Object ] :default The default value.
|
28
|
+
# @option options [ Proc | nil ] :on_change The callback to invoke when the
|
29
|
+
# setter is invoked.
|
28
30
|
def option(name, options = {})
|
29
31
|
defaults[name] = settings[name] = options[:default]
|
30
32
|
|
@@ -38,6 +40,7 @@ module Mongoid
|
|
38
40
|
|
39
41
|
define_method("#{name}=") do |value|
|
40
42
|
settings[name] = value
|
43
|
+
options[:on_change]&.call(value)
|
41
44
|
end
|
42
45
|
|
43
46
|
define_method("#{name}?") do
|
data/lib/mongoid/config.rb
CHANGED
@@ -125,6 +125,23 @@ module Mongoid
|
|
125
125
|
# always return a Hash.
|
126
126
|
option :legacy_attributes, default: false
|
127
127
|
|
128
|
+
# Allow BSON::Decimal128 to be parsed and returned directly in
|
129
|
+
# field values. When BSON 5 is present and the this option is set to false
|
130
|
+
# (the default), BSON::Decimal128 values in the database will be returned
|
131
|
+
# as BigDecimal.
|
132
|
+
#
|
133
|
+
# @note this option only has effect when BSON 5+ is present. Otherwise,
|
134
|
+
# the setting is ignored.
|
135
|
+
option :allow_bson5_decimal128, default: false, on_change: -> (allow) do
|
136
|
+
if BSON::VERSION >= '5.0.0'
|
137
|
+
if allow
|
138
|
+
BSON::Registry.register(BSON::Decimal128::BSON_TYPE, BSON::Decimal128)
|
139
|
+
else
|
140
|
+
BSON::Registry.register(BSON::Decimal128::BSON_TYPE, BigDecimal)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
128
145
|
# Has Mongoid been configured? This is checking that at least a valid
|
129
146
|
# client config exists.
|
130
147
|
#
|
@@ -47,7 +47,7 @@ module Mongoid
|
|
47
47
|
if value.is_a?(Hash) && selector[field].is_a?(Hash) &&
|
48
48
|
value.keys.all? { |key|
|
49
49
|
key_s = key.to_s
|
50
|
-
key_s.start_with?('$') && !selector[field].
|
50
|
+
key_s.start_with?('$') && !selector[field].keys.map(&:to_s).include?(key_s)
|
51
51
|
}
|
52
52
|
then
|
53
53
|
# Multiple operators can be combined on the same field by
|
@@ -38,8 +38,12 @@ module Mongoid
|
|
38
38
|
consolidated = {}
|
39
39
|
each_pair do |key, value|
|
40
40
|
if key =~ /\$/
|
41
|
-
value.
|
42
|
-
value[
|
41
|
+
value.keys.each do |key2|
|
42
|
+
value2 = value[key2]
|
43
|
+
real_key = klass.database_field_name(key2)
|
44
|
+
|
45
|
+
value.delete(key2) if real_key != key2
|
46
|
+
value[real_key] = (key == "$rename") ? value2.to_s : mongoize_for(key, klass, real_key, value2)
|
43
47
|
end
|
44
48
|
consolidated[key] ||= {}
|
45
49
|
consolidated[key].update(value)
|
data/lib/mongoid/fields.rb
CHANGED
@@ -764,33 +764,60 @@ module Mongoid
|
|
764
764
|
|
765
765
|
def field_for(name, options)
|
766
766
|
opts = options.merge(klass: self)
|
767
|
-
|
768
|
-
opts[:type] = type_mapping || unmapped_type(options)
|
769
|
-
if !opts[:type].is_a?(Class)
|
770
|
-
raise Errors::InvalidFieldType.new(self, name, options[:type])
|
771
|
-
else
|
772
|
-
if INVALID_BSON_CLASSES.include?(opts[:type])
|
773
|
-
warn_message = "Using #{opts[:type]} as the field type is not supported. "
|
774
|
-
if opts[:type] == BSON::Decimal128
|
775
|
-
warn_message += "In BSON <= 4, the BSON::Decimal128 type will work as expected for both storing and querying, but will return a BigDecimal on query in BSON 5+."
|
776
|
-
else
|
777
|
-
warn_message += "Saving values of this type to the database will work as expected, however, querying them will return a value of the native Ruby Integer type."
|
778
|
-
end
|
779
|
-
Mongoid.logger.warn(warn_message)
|
780
|
-
end
|
781
|
-
end
|
767
|
+
opts[:type] = retrieve_and_validate_type(name, options[:type])
|
782
768
|
return Fields::Localized.new(name, opts) if options[:localize]
|
783
769
|
return Fields::ForeignKey.new(name, opts) if options[:identity]
|
784
770
|
Fields::Standard.new(name, opts)
|
785
771
|
end
|
786
772
|
|
787
|
-
|
788
|
-
|
773
|
+
# Get the class for the given type.
|
774
|
+
#
|
775
|
+
# @param [ Symbol ] name The name of the field.
|
776
|
+
# @param [ Symbol | Class ] type The type of the field.
|
777
|
+
#
|
778
|
+
# @return [ Class ] The type of the field.
|
779
|
+
#
|
780
|
+
# @raises [ Mongoid::Errors::InvalidFieldType ] if given an invalid field
|
781
|
+
# type.
|
782
|
+
#
|
783
|
+
# @api private
|
784
|
+
def retrieve_and_validate_type(name, type)
|
785
|
+
result = TYPE_MAPPINGS[type] || unmapped_type(type)
|
786
|
+
raise Errors::InvalidFieldType.new(self, name, type) if !result.is_a?(Class)
|
787
|
+
|
788
|
+
if unsupported_type?(result)
|
789
|
+
warn_message = "Using #{result} as the field type is not supported. "
|
790
|
+
if result == BSON::Decimal128
|
791
|
+
warn_message += 'In BSON <= 4, the BSON::Decimal128 type will work as expected for both storing and querying, but will return a BigDecimal on query in BSON 5+. To use literal BSON::Decimal128 fields with BSON 5, set Mongoid.allow_bson5_decimal128 to true.'
|
792
|
+
else
|
793
|
+
warn_message += 'Saving values of this type to the database will work as expected, however, querying them will return a value of the native Ruby Integer type.'
|
794
|
+
end
|
795
|
+
Mongoid.logger.warn(warn_message)
|
796
|
+
end
|
797
|
+
|
798
|
+
result
|
799
|
+
end
|
800
|
+
|
801
|
+
def unmapped_type(type)
|
802
|
+
if "Boolean" == type.to_s
|
789
803
|
Mongoid::Boolean
|
790
804
|
else
|
791
|
-
|
805
|
+
type || Object
|
792
806
|
end
|
793
807
|
end
|
808
|
+
|
809
|
+
# Queries whether or not the given type is permitted as a declared field
|
810
|
+
# type.
|
811
|
+
#
|
812
|
+
# @param [ Class ] type The type to query
|
813
|
+
#
|
814
|
+
# @return [ true | false ] whether or not the type is supported
|
815
|
+
#
|
816
|
+
# @api private
|
817
|
+
def unsupported_type?(type)
|
818
|
+
return !Mongoid::Config.allow_bson5_decimal128? if type == BSON::Decimal128
|
819
|
+
INVALID_BSON_CLASSES.include?(type)
|
820
|
+
end
|
794
821
|
end
|
795
822
|
end
|
796
823
|
end
|
data/lib/mongoid/reloadable.rb
CHANGED
@@ -16,16 +16,14 @@ module Mongoid
|
|
16
16
|
#
|
17
17
|
# @return [ Document ] The document, reloaded.
|
18
18
|
def reload
|
19
|
-
if @atomic_selector
|
20
|
-
# Clear atomic_selector cache for sharded clusters. MONGOID-5076
|
21
|
-
remove_instance_variable('@atomic_selector')
|
22
|
-
end
|
23
|
-
|
24
19
|
reloaded = _reload
|
25
20
|
if Mongoid.raise_not_found_error && (reloaded.nil? || reloaded.empty?)
|
26
21
|
shard_keys = atomic_selector.with_indifferent_access.slice(*shard_key_fields, :_id)
|
27
22
|
raise Errors::DocumentNotFound.new(self.class, _id, shard_keys)
|
28
23
|
end
|
24
|
+
|
25
|
+
reset_atomic_updates!
|
26
|
+
|
29
27
|
@attributes = reloaded
|
30
28
|
@attributes_before_type_cast = @attributes.dup
|
31
29
|
@changed_attributes = {}
|
data/lib/mongoid/version.rb
CHANGED
@@ -2711,4 +2711,31 @@ describe Mongoid::Attributes do
|
|
2711
2711
|
catalog.set_field.should == Set.new([ 1, 2 ])
|
2712
2712
|
end
|
2713
2713
|
end
|
2714
|
+
|
2715
|
+
context 'when an embedded field has a capitalized store_as name' do
|
2716
|
+
let(:person) { Person.new(Purse: { brand: 'Gucci' }) }
|
2717
|
+
|
2718
|
+
it 'sets the value' do
|
2719
|
+
expect(person.purse.brand).to eq('Gucci')
|
2720
|
+
end
|
2721
|
+
|
2722
|
+
it 'saves successfully' do
|
2723
|
+
expect(person.save!).to eq(true)
|
2724
|
+
end
|
2725
|
+
|
2726
|
+
context 'when persisted' do
|
2727
|
+
before do
|
2728
|
+
person.save!
|
2729
|
+
person.reload
|
2730
|
+
end
|
2731
|
+
|
2732
|
+
it 'persists the value' do
|
2733
|
+
expect(person.reload.purse.brand).to eq('Gucci')
|
2734
|
+
end
|
2735
|
+
|
2736
|
+
it 'uses the correct key in the database' do
|
2737
|
+
expect(person.collection.find(_id: person.id).first['Purse']['_id']).to eq(person.purse.id)
|
2738
|
+
end
|
2739
|
+
end
|
2740
|
+
end
|
2714
2741
|
end
|
data/spec/mongoid/config_spec.rb
CHANGED
@@ -272,6 +272,15 @@ describe Mongoid::Config do
|
|
272
272
|
it_behaves_like "a config option"
|
273
273
|
end
|
274
274
|
|
275
|
+
context 'when setting the allow_bson5_decimal128 option in the config' do
|
276
|
+
min_bson_version '5.0'
|
277
|
+
|
278
|
+
let(:option) { :allow_bson5_decimal128 }
|
279
|
+
let(:default) { false }
|
280
|
+
|
281
|
+
it_behaves_like "a config option"
|
282
|
+
end
|
283
|
+
|
275
284
|
context 'when setting the broken_updates option in the config' do
|
276
285
|
let(:option) { :broken_updates }
|
277
286
|
let(:default) { false }
|
@@ -1179,33 +1179,49 @@ describe Mongoid::Contextual::Mongo do
|
|
1179
1179
|
let!(:person2) { Person.create!(ssn: BSON::Decimal128.new("1")) }
|
1180
1180
|
let(:tally) { Person.tally("ssn") }
|
1181
1181
|
|
1182
|
+
let(:tallied_classes) do
|
1183
|
+
tally.keys.map(&:class).sort do |a, b|
|
1184
|
+
a.to_s.casecmp(b.to_s)
|
1185
|
+
end
|
1186
|
+
end
|
1187
|
+
|
1182
1188
|
context "< BSON 5" do
|
1183
1189
|
max_bson_version '4.99.99'
|
1184
1190
|
|
1185
1191
|
it "stores the correct types in the database" do
|
1186
|
-
Person.find(person1.id).attributes["ssn"].
|
1187
|
-
Person.find(person2.id).attributes["ssn"].
|
1192
|
+
expect(Person.find(person1.id).attributes["ssn"]).to be_a BSON::Regexp::Raw
|
1193
|
+
expect(Person.find(person2.id).attributes["ssn"]).to be_a BSON::Decimal128
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
it "tallies the correct type" do
|
1197
|
+
expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
|
1198
|
+
end
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
context '>= BSON 5' do
|
1202
|
+
min_bson_version "5.0"
|
1203
|
+
|
1204
|
+
it "stores the correct types in the database" do
|
1205
|
+
expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
|
1206
|
+
expect(Person.find(person2.id).ssn).to be_a BigDecimal
|
1188
1207
|
end
|
1189
1208
|
|
1190
1209
|
it "tallies the correct type" do
|
1191
|
-
|
1192
|
-
a.to_s <=> b.to_s
|
1193
|
-
end.should == [BSON::Decimal128, BSON::Regexp::Raw]
|
1210
|
+
expect(tallied_classes).to be == [ BigDecimal, BSON::Regexp::Raw ]
|
1194
1211
|
end
|
1195
1212
|
end
|
1196
1213
|
|
1197
|
-
context
|
1214
|
+
context '>= BSON 5 with decimal128 allowed' do
|
1198
1215
|
min_bson_version "5.0"
|
1216
|
+
config_override :allow_bson5_decimal128, true
|
1199
1217
|
|
1200
1218
|
it "stores the correct types in the database" do
|
1201
|
-
Person.find(person1.id).ssn.
|
1202
|
-
Person.find(person2.id).ssn.
|
1219
|
+
expect(Person.find(person1.id).ssn).to be_a BSON::Regexp::Raw
|
1220
|
+
expect(Person.find(person2.id).ssn).to be_a BSON::Decimal128
|
1203
1221
|
end
|
1204
1222
|
|
1205
1223
|
it "tallies the correct type" do
|
1206
|
-
|
1207
|
-
a.to_s <=> b.to_s
|
1208
|
-
end.should == [BigDecimal, BSON::Regexp::Raw]
|
1224
|
+
expect(tallied_classes).to be == [ BSON::Decimal128, BSON::Regexp::Raw ]
|
1209
1225
|
end
|
1210
1226
|
end
|
1211
1227
|
end
|
@@ -3560,6 +3576,20 @@ describe Mongoid::Contextual::Mongo do
|
|
3560
3576
|
end
|
3561
3577
|
end
|
3562
3578
|
|
3579
|
+
context 'when using aliased field names' do
|
3580
|
+
before do
|
3581
|
+
context.update_all('$set' => { years: 100 })
|
3582
|
+
end
|
3583
|
+
|
3584
|
+
it "updates the first matching document" do
|
3585
|
+
expect(depeche_mode.reload.years).to eq(100)
|
3586
|
+
end
|
3587
|
+
|
3588
|
+
it "updates the last matching document" do
|
3589
|
+
expect(new_order.reload.years).to eq(100)
|
3590
|
+
end
|
3591
|
+
end
|
3592
|
+
|
3563
3593
|
context "when the attributes must be mongoized" do
|
3564
3594
|
|
3565
3595
|
before do
|
@@ -44,7 +44,7 @@ describe Mongoid::Criteria::Queryable::Selector do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
context "when selector contains a $nin" do
|
47
|
+
context "when selector contains a $nin string" do
|
48
48
|
|
49
49
|
let(:initial) do
|
50
50
|
{ "$nin" => ["foo"] }
|
@@ -72,7 +72,35 @@ describe Mongoid::Criteria::Queryable::Selector do
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
context "when selector contains a $
|
75
|
+
context "when selector contains a $nin symbol" do
|
76
|
+
|
77
|
+
let(:initial) do
|
78
|
+
{ :$nin => ["foo"] }
|
79
|
+
end
|
80
|
+
|
81
|
+
before do
|
82
|
+
selector["field"] = initial
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when merging in a new $nin" do
|
86
|
+
|
87
|
+
let(:other) do
|
88
|
+
{ "field" => { :$nin => ["bar"] } }
|
89
|
+
end
|
90
|
+
|
91
|
+
before do
|
92
|
+
selector.merge!(other)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "combines the two $nin queries into one" do
|
96
|
+
expect(selector).to eq({
|
97
|
+
"field" => { :$nin => ["foo", "bar"] }
|
98
|
+
})
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when selector contains a $in string" do
|
76
104
|
|
77
105
|
let(:initial) do
|
78
106
|
{ "$in" => [1, 2] }
|
@@ -117,6 +145,51 @@ describe Mongoid::Criteria::Queryable::Selector do
|
|
117
145
|
end
|
118
146
|
end
|
119
147
|
|
148
|
+
context "when selector contains a $in symbol" do
|
149
|
+
|
150
|
+
let(:initial) do
|
151
|
+
{ :$in => [1, 2] }
|
152
|
+
end
|
153
|
+
|
154
|
+
before do
|
155
|
+
selector["field"] = initial
|
156
|
+
end
|
157
|
+
|
158
|
+
context "when merging in a new $in with an intersecting value" do
|
159
|
+
|
160
|
+
let(:other) do
|
161
|
+
{ "field" => { :$in => [1] } }
|
162
|
+
end
|
163
|
+
|
164
|
+
before do
|
165
|
+
selector.merge!(other)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "intersects the $in values" do
|
169
|
+
expect(selector).to eq({
|
170
|
+
"field" => { :$in => [1] }
|
171
|
+
})
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "when merging in a new $in with no intersecting values" do
|
176
|
+
|
177
|
+
let(:other) do
|
178
|
+
{ "field" => { :$in => [3] } }
|
179
|
+
end
|
180
|
+
|
181
|
+
before do
|
182
|
+
selector.merge!(other)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "intersects the $in values" do
|
186
|
+
expect(selector).to eq({
|
187
|
+
"field" => { :$in => [] }
|
188
|
+
})
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
120
193
|
context "when selector is not nested" do
|
121
194
|
|
122
195
|
before do
|
@@ -210,7 +210,79 @@ describe Mongoid::Criteria::Queryable::Storable do
|
|
210
210
|
}
|
211
211
|
end
|
212
212
|
end
|
213
|
+
|
214
|
+
context 'when value is a hash combine values with different operator keys' do
|
215
|
+
let(:base) do
|
216
|
+
query.add_field_expression('foo', {'$in' => ['bar']})
|
217
|
+
end
|
218
|
+
|
219
|
+
let(:modified) do
|
220
|
+
base.add_field_expression('foo', {'$nin' => ['zoom']})
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'combines the conditions using $and' do
|
224
|
+
modified.selector.should == {
|
225
|
+
'foo' => {
|
226
|
+
'$in' => ['bar'],
|
227
|
+
'$nin' => ['zoom']
|
228
|
+
}
|
229
|
+
}
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context 'when value is a hash with symbol operator key combine values with different operator keys' do
|
234
|
+
let(:base) do
|
235
|
+
query.add_field_expression('foo', {:$in => ['bar']})
|
236
|
+
end
|
237
|
+
|
238
|
+
let(:modified) do
|
239
|
+
base.add_field_expression('foo', {:$nin => ['zoom']})
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'combines the conditions using $and' do
|
243
|
+
modified.selector.should == {
|
244
|
+
'foo' => {
|
245
|
+
:$in => ['bar'],
|
246
|
+
:$nin => ['zoom']
|
247
|
+
}
|
248
|
+
}
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
context 'when value is a hash add values with same operator keys using $and' do
|
253
|
+
let(:base) do
|
254
|
+
query.add_field_expression('foo', {'$in' => ['bar']})
|
255
|
+
end
|
256
|
+
|
257
|
+
let(:modified) do
|
258
|
+
base.add_field_expression('foo', {'$in' => ['zoom']})
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'adds the new condition using $and' do
|
262
|
+
modified.selector.should == {
|
263
|
+
'foo' => {'$in' => ['bar']},
|
264
|
+
'$and' => ['foo' => {'$in' => ['zoom']}]
|
265
|
+
}
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
context 'when value is a hash with symbol operator key add values with same operator keys using $and' do
|
270
|
+
let(:base) do
|
271
|
+
query.add_field_expression('foo', {:$in => ['bar']})
|
272
|
+
end
|
273
|
+
|
274
|
+
let(:modified) do
|
275
|
+
base.add_field_expression('foo', {:$in => ['zoom']})
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'adds the new condition using $and' do
|
279
|
+
modified.selector.should == {
|
280
|
+
'foo' => {:$in => ['bar']},
|
281
|
+
'$and' => ['foo' => {:$in => ['zoom']}]
|
282
|
+
}
|
283
|
+
end
|
213
284
|
end
|
285
|
+
end
|
214
286
|
|
215
287
|
describe '#add_operator_expression' do
|
216
288
|
let(:query_method) { :add_operator_expression }
|
@@ -178,7 +178,7 @@ describe Mongoid::Extensions::Hash do
|
|
178
178
|
|
179
179
|
it "moves the non hash values under the provided key" do
|
180
180
|
expect(consolidated).to eq({
|
181
|
-
"$set" => { name
|
181
|
+
"$set" => { 'name' => "Tool", likes: 10 }, "$inc" => { 'plays' => 1 }
|
182
182
|
})
|
183
183
|
end
|
184
184
|
end
|
@@ -195,7 +195,7 @@ describe Mongoid::Extensions::Hash do
|
|
195
195
|
|
196
196
|
it "moves the non hash values under the provided key" do
|
197
197
|
expect(consolidated).to eq({
|
198
|
-
"$set" => { likes: 10, name
|
198
|
+
"$set" => { likes: 10, 'name' => "Tool" }, "$inc" => { 'plays' => 1 }
|
199
199
|
})
|
200
200
|
end
|
201
201
|
end
|
@@ -213,7 +213,7 @@ describe Mongoid::Extensions::Hash do
|
|
213
213
|
|
214
214
|
it "moves the non hash values under the provided key" do
|
215
215
|
expect(consolidated).to eq({
|
216
|
-
"$set" => { likes: 10, name: "Tool" }, "$inc" => { plays
|
216
|
+
"$set" => { likes: 10, name: "Tool" }, "$inc" => { 'plays' => 1 }
|
217
217
|
})
|
218
218
|
end
|
219
219
|
end
|