mongoid 7.2.3 → 7.3.0

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 (152) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +16 -0
  5. data/lib/config/locales/en.yml +2 -2
  6. data/lib/mongoid/association/accessors.rb +1 -1
  7. data/lib/mongoid/association/constrainable.rb +1 -1
  8. data/lib/mongoid/association/depending.rb +4 -4
  9. data/lib/mongoid/association/embedded/batchable.rb +1 -1
  10. data/lib/mongoid/association/embedded/embedded_in.rb +1 -1
  11. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +10 -3
  12. data/lib/mongoid/association/nested/many.rb +1 -1
  13. data/lib/mongoid/association/nested/one.rb +4 -2
  14. data/lib/mongoid/association/proxy.rb +6 -1
  15. data/lib/mongoid/association/referenced/auto_save.rb +2 -2
  16. data/lib/mongoid/association/referenced/has_many/enumerable.rb +493 -495
  17. data/lib/mongoid/association/referenced/has_many/proxy.rb +2 -2
  18. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +2 -2
  19. data/lib/mongoid/attributes.rb +24 -13
  20. data/lib/mongoid/attributes/projector.rb +120 -0
  21. data/lib/mongoid/cacheable.rb +2 -2
  22. data/lib/mongoid/clients.rb +1 -1
  23. data/lib/mongoid/clients/factory.rb +22 -8
  24. data/lib/mongoid/config.rb +19 -2
  25. data/lib/mongoid/contextual/aggregable/mongo.rb +10 -8
  26. data/lib/mongoid/copyable.rb +1 -1
  27. data/lib/mongoid/criteria.rb +4 -5
  28. data/lib/mongoid/criteria/findable.rb +1 -1
  29. data/lib/mongoid/criteria/queryable/expandable.rb +0 -24
  30. data/lib/mongoid/criteria/queryable/extensions.rb +0 -4
  31. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  32. data/lib/mongoid/criteria/queryable/mergeable.rb +46 -20
  33. data/lib/mongoid/criteria/queryable/selectable.rb +8 -8
  34. data/lib/mongoid/document.rb +1 -15
  35. data/lib/mongoid/errors/delete_restriction.rb +8 -9
  36. data/lib/mongoid/evolvable.rb +1 -1
  37. data/lib/mongoid/extensions/boolean.rb +1 -2
  38. data/lib/mongoid/extensions/false_class.rb +1 -1
  39. data/lib/mongoid/extensions/hash.rb +2 -2
  40. data/lib/mongoid/extensions/true_class.rb +1 -1
  41. data/lib/mongoid/fields.rb +43 -5
  42. data/lib/mongoid/inspectable.rb +1 -1
  43. data/lib/mongoid/matcher.rb +7 -0
  44. data/lib/mongoid/matcher/bits.rb +41 -0
  45. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  46. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  47. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  48. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  49. data/lib/mongoid/matcher/expression.rb +4 -0
  50. data/lib/mongoid/matcher/field_operator.rb +6 -0
  51. data/lib/mongoid/matcher/mod.rb +17 -0
  52. data/lib/mongoid/matcher/type.rb +99 -0
  53. data/lib/mongoid/persistable/deletable.rb +1 -2
  54. data/lib/mongoid/persistable/destroyable.rb +8 -2
  55. data/lib/mongoid/persistable/updatable.rb +27 -2
  56. data/lib/mongoid/query_cache.rb +35 -29
  57. data/lib/mongoid/selectable.rb +5 -7
  58. data/lib/mongoid/shardable.rb +21 -5
  59. data/lib/mongoid/touchable.rb +23 -4
  60. data/lib/mongoid/version.rb +1 -1
  61. data/spec/integration/associations/embeds_many_spec.rb +44 -0
  62. data/spec/integration/associations/has_one_spec.rb +48 -0
  63. data/spec/integration/criteria/date_field_spec.rb +1 -1
  64. data/spec/integration/document_spec.rb +9 -0
  65. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  66. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  67. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  68. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  69. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  70. data/spec/integration/matcher_operator_data/in.yml +16 -0
  71. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  72. data/spec/integration/matcher_operator_data/type.yml +70 -0
  73. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  74. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  75. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  76. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  77. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  78. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  79. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  80. data/spec/integration/matcher_operator_data/type_decimal.yml +40 -0
  81. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  82. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  83. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  84. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  85. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  86. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  87. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  88. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  89. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  90. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  91. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  92. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  93. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  94. data/spec/lite_spec_helper.rb +2 -0
  95. data/spec/mongoid/association/depending_spec.rb +391 -352
  96. data/spec/mongoid/association/nested/one_spec.rb +18 -14
  97. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +25 -8
  98. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +1 -1
  99. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +1 -1
  100. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +1 -1
  101. data/spec/mongoid/association/referenced/has_one_models.rb +8 -0
  102. data/spec/mongoid/atomic/paths_spec.rb +64 -12
  103. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  104. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  105. data/spec/mongoid/attributes/projector_spec.rb +41 -0
  106. data/spec/mongoid/attributes_spec.rb +98 -6
  107. data/spec/mongoid/clients/factory_spec.rb +48 -0
  108. data/spec/mongoid/config_spec.rb +32 -0
  109. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  110. data/spec/mongoid/criteria/modifiable_spec.rb +1 -1
  111. data/spec/mongoid/criteria/queryable/expandable_spec.rb +0 -73
  112. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +1 -1
  113. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +105 -7
  114. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +229 -24
  115. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +39 -0
  116. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -565
  117. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +590 -0
  118. data/spec/mongoid/criteria_projection_spec.rb +411 -0
  119. data/spec/mongoid/criteria_spec.rb +0 -275
  120. data/spec/mongoid/document_spec.rb +13 -13
  121. data/spec/mongoid/errors/delete_restriction_spec.rb +1 -1
  122. data/spec/mongoid/extensions/false_class_spec.rb +1 -1
  123. data/spec/mongoid/extensions/string_spec.rb +5 -5
  124. data/spec/mongoid/extensions/true_class_spec.rb +1 -1
  125. data/spec/mongoid/fields/localized_spec.rb +4 -4
  126. data/spec/mongoid/fields_spec.rb +4 -4
  127. data/spec/mongoid/inspectable_spec.rb +12 -4
  128. data/spec/mongoid/persistable/deletable_spec.rb +175 -1
  129. data/spec/mongoid/persistable/destroyable_spec.rb +191 -3
  130. data/spec/mongoid/persistable/savable_spec.rb +3 -5
  131. data/spec/mongoid/persistable/upsertable_spec.rb +1 -1
  132. data/spec/mongoid/query_cache_middleware_spec.rb +8 -0
  133. data/spec/mongoid/reloadable_spec.rb +18 -1
  134. data/spec/mongoid/shardable_spec.rb +44 -0
  135. data/spec/mongoid/touchable_spec.rb +104 -16
  136. data/spec/mongoid/touchable_spec_models.rb +52 -0
  137. data/spec/mongoid/validatable_spec.rb +1 -1
  138. data/spec/spec_helper.rb +6 -2
  139. data/spec/support/client_registry.rb +9 -0
  140. data/spec/support/models/bolt.rb +8 -0
  141. data/spec/support/models/hole.rb +13 -0
  142. data/spec/support/models/mop.rb +0 -1
  143. data/spec/support/models/nut.rb +8 -0
  144. data/spec/support/models/person.rb +6 -0
  145. data/spec/support/models/sealer.rb +8 -0
  146. data/spec/support/models/shirt.rb +12 -0
  147. data/spec/support/models/spacer.rb +8 -0
  148. data/spec/support/models/threadlocker.rb +8 -0
  149. data/spec/support/models/washer.rb +8 -0
  150. metadata +97 -3
  151. metadata.gz.sig +5 -3
  152. data/spec/support/cluster_config.rb +0 -158
@@ -1,10 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  # encoding: utf-8
3
3
 
4
- unless defined?(Boolean)
5
- class Boolean; end
6
- end
7
-
8
4
  if defined?(ActiveSupport)
9
5
  unless defined?(ActiveSupport::TimeWithZone)
10
6
  require "active_support/time_with_zone"
@@ -33,4 +33,4 @@ module Mongoid
33
33
  end
34
34
  end
35
35
 
36
- ::Boolean.__send__(:extend, Mongoid::Criteria::Queryable::Extensions::Boolean::ClassMethods)
36
+ Mongoid::Boolean.__send__(:extend, Mongoid::Criteria::Queryable::Extensions::Boolean::ClassMethods)
@@ -227,7 +227,16 @@ module Mongoid
227
227
  end
228
228
 
229
229
  # Takes a criteria hash and expands Key objects into hashes containing
230
- # MQL corresponding to said key objects.
230
+ # MQL corresponding to said key objects. Also converts the input to
231
+ # BSON::Document to permit indifferent access.
232
+ #
233
+ # The argument must be a hash containing key-value pairs of the
234
+ # following forms:
235
+ # - {field_name: value}
236
+ # - {'field_name' => value}
237
+ # - {key_instance: value}
238
+ # - {:$operator => operator_value_expression}
239
+ # - {'$operator' => operator_value_expression}
231
240
  #
232
241
  # Ruby does not permit multiple symbol operators. For example,
233
242
  # {:foo.gt => 1, :foo.gt => 2} is collapsed to {:foo.gt => 2} by the
@@ -237,19 +246,23 @@ module Mongoid
237
246
  # Similarly, this method should never need to expand a literal value
238
247
  # and an operator at the same time.
239
248
  #
249
+ # This method effectively converts symbol keys to string keys in
250
+ # the input +expr+, such that the downstream code can assume that
251
+ # conditions always contain string keys.
252
+ #
240
253
  # @param [ Hash ] expr Criteria including Key instances.
241
254
  #
242
- # @return [ Hash ] The expanded criteria.
255
+ # @return [ BSON::Document ] The expanded criteria.
243
256
  private def _mongoid_expand_keys(expr)
244
257
  unless expr.is_a?(Hash)
245
258
  raise ArgumentError, 'Argument must be a Hash'
246
259
  end
247
260
 
248
- result = {}
261
+ result = BSON::Document.new
249
262
  expr.each do |field, value|
250
- field.__expr_part__(value.__expand_complex__).each do |k, v|
251
- if result[k]
252
- if result[k].is_a?(Hash)
263
+ field.__expr_part__(value.__expand_complex__, negating?).each do |k, v|
264
+ if existing = result[k]
265
+ if existing.is_a?(Hash)
253
266
  # Existing value is an operator.
254
267
  # If new value is also an operator, ensure there are no
255
268
  # conflicts and add
@@ -257,8 +270,8 @@ module Mongoid
257
270
  # The new value is also an operator.
258
271
  # If there are no conflicts, combine the hashes, otherwise
259
272
  # add new conditions to top level with $and.
260
- if (v.keys & result[k].keys).empty?
261
- result[k].update(v)
273
+ if (v.keys & existing.keys).empty?
274
+ existing.update(v)
262
275
  else
263
276
  raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
264
277
  result['$and'] ||= []
@@ -266,26 +279,39 @@ module Mongoid
266
279
  end
267
280
  else
268
281
  # The new value is a simple value.
269
- # If there isn't an $eq operator already in the query,
270
- # transform the new value into an $eq operator and add it
271
- # to the existing hash. Otherwise add the new condition
272
- # with $and to the top level.
273
- if result[k].key?('$eq')
282
+ # Transform the implicit equality to either $eq or $regexp
283
+ # depending on the type of the argument. See
284
+ # https://docs.mongodb.com/manual/reference/operator/query/eq/#std-label-eq-usage-examples
285
+ # for the description of relevant server behavior.
286
+ op = case v
287
+ when Regexp, BSON::Regexp::Raw
288
+ '$regex'
289
+ else
290
+ '$eq'
291
+ end
292
+ # If there isn't an $eq/$regex operator already in the
293
+ # query, transform the new value into an operator
294
+ # expression and add it to the existing hash. Otherwise
295
+ # add the new condition with $and to the top level.
296
+ if existing.key?(op)
274
297
  raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
275
298
  result['$and'] ||= []
276
299
  result['$and'] << {k => v}
277
300
  else
278
- result[k].update('$eq' => v)
301
+ existing.update(op => v)
279
302
  end
280
303
  end
281
304
  else
282
305
  # Existing value is a simple value.
283
- # If we are adding an operator, and the operator is not $eq,
284
- # convert existing value into $eq and add the new operator
285
- # to the same hash. Otherwise add the new condition with $and
286
- # to the top level.
287
- if v.is_a?(Hash) && !v.key?('$eq')
288
- result[k] = {'$eq' => result[k]}.update(v)
306
+ # See the notes above about transformations to $eq/$regex.
307
+ op = case existing
308
+ when Regexp, BSON::Regexp::Raw
309
+ '$regex'
310
+ else
311
+ '$eq'
312
+ end
313
+ if v.is_a?(Hash) && !v.key?(op)
314
+ result[k] = {op => existing}.update(v)
289
315
  else
290
316
  raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
291
317
  result['$and'] ||= []
@@ -195,11 +195,11 @@ module Mongoid
195
195
  end
196
196
 
197
197
  typed_override(criterion, "$exists") do |value|
198
- ::Boolean.evolve(value)
198
+ Mongoid::Boolean.evolve(value)
199
199
  end
200
200
  end
201
201
  key :exists, :override, "$exists" do |value|
202
- ::Boolean.evolve(value)
202
+ Mongoid::Boolean.evolve(value)
203
203
  end
204
204
 
205
205
  # Add a $geoIntersects or $geoWithin selection. Symbol operators must
@@ -882,19 +882,19 @@ module Mongoid
882
882
  if criterion.nil?
883
883
  raise ArgumentError, 'Criterion cannot be nil here'
884
884
  end
885
+ unless Hash === criterion
886
+ raise Errors::InvalidQuery, "Expression must be a Hash: #{Errors::InvalidQuery.truncate_expr(criterion)}"
887
+ end
885
888
 
889
+ normalized = _mongoid_expand_keys(criterion)
886
890
  clone.tap do |query|
887
- unless Hash === criterion
888
- raise Errors::InvalidQuery, "Expression must be a Hash: #{Errors::InvalidQuery.truncate_expr(criterion)}"
889
- end
890
- criterion.each do |field, value|
891
+ normalized.each do |field, value|
891
892
  field_s = field.to_s
892
893
  if field_s[0] == ?$
893
894
  # Query expression-level operator, like $and or $where
894
895
  query.add_operator_expression(field_s, value)
895
896
  else
896
- exp_field, exp_value = expand_one_condition(field, value)
897
- query.add_field_expression(exp_field, exp_value)
897
+ query.add_field_expression(field, value)
898
898
  end
899
899
  end
900
900
  query.reset_strategies!
@@ -151,7 +151,7 @@ module Mongoid
151
151
  #
152
152
  # @since 2.4.0
153
153
  def to_key
154
- (persisted? || destroyed?) ? [ id.to_s ] : nil
154
+ (persisted? || destroyed?) ? [ _id.to_s ] : nil
155
155
  end
156
156
 
157
157
  # Return an array with this +Document+ only in it.
@@ -273,20 +273,6 @@ module Mongoid
273
273
  @model_cache_key ||= self.class.model_name.cache_key
274
274
  end
275
275
 
276
- # Implement this for calls to flatten on array.
277
- #
278
- # @example Get the document as an array.
279
- # document.to_ary
280
- #
281
- # @return [ nil ] Always nil.
282
- #
283
- # @since 2.1.0
284
- def to_ary
285
- nil
286
- end
287
-
288
- private
289
-
290
276
  def as_attributes
291
277
  return attributes if frozen?
292
278
  embedded_relations.each_pair do |name, meta|
@@ -4,24 +4,23 @@
4
4
  module Mongoid
5
5
  module Errors
6
6
 
7
- # This error is raised when calling #save! or .create! on a model when one
8
- # of the callbacks returns false.
7
+ # This error is raised when attempting to destroy a model which has
8
+ # an association with dependency option set to restrict.
9
9
  class DeleteRestriction < MongoidError
10
10
 
11
11
  # Create the new callbacks error.
12
12
  #
13
- # @example Create the new callbacks error.
14
- # Callbacks.new(Post, :create!)
15
- #
16
- # @param [ Class ] document
17
- # @param [ Symbol ] association
13
+ # @param [ Document ] document The document that was attempted to be
14
+ # destroyed.
15
+ # @param [ Symbol ] association_name The name of the dependent
16
+ # association that prevents the document from being deleted.
18
17
  #
19
18
  # @since 3.0.0
20
- def initialize(document, relation)
19
+ def initialize(document, association_name)
21
20
  super(
22
21
  compose_message(
23
22
  "delete_restriction",
24
- { document: document.class, relation: relation }
23
+ { document: document.class, relation: association_name }
25
24
  )
26
25
  )
27
26
  end
@@ -15,7 +15,7 @@ module Mongoid
15
15
  #
16
16
  # @since 3.0.0
17
17
  def __evolve_object_id__
18
- id
18
+ _id
19
19
  end
20
20
  end
21
21
  end
@@ -16,9 +16,8 @@ module Mongoid
16
16
  #
17
17
  # @since 3.0.0
18
18
  def mongoize(object)
19
- ::Boolean.evolve(object)
19
+ evolve(object)
20
20
  end
21
- alias :evolve :mongoize
22
21
  end
23
22
  end
24
23
  end
@@ -28,7 +28,7 @@ module Mongoid
28
28
  #
29
29
  # @since 1.0.0
30
30
  def is_a?(other)
31
- if other == ::Boolean || other.class == ::Boolean
31
+ if other == Mongoid::Boolean || other.class == Mongoid::Boolean
32
32
  return true
33
33
  end
34
34
  super(other)
@@ -117,7 +117,7 @@ module Mongoid
117
117
  #
118
118
  # @since 3.0.2
119
119
  def delete_id
120
- delete("_id") || delete("id") || delete(:id) || delete(:_id)
120
+ delete("_id") || delete(:_id) || delete("id") || delete(:id)
121
121
  end
122
122
 
123
123
  # Get the id attribute from this hash, whether it's prefixed with an
@@ -130,7 +130,7 @@ module Mongoid
130
130
  #
131
131
  # @since 2.3.2
132
132
  def extract_id
133
- self["_id"] || self["id"] || self[:id] || self[:_id]
133
+ self["_id"] || self[:_id] || self["id"] || self[:id]
134
134
  end
135
135
 
136
136
  # Fetch a nested value via dot syntax.
@@ -28,7 +28,7 @@ module Mongoid
28
28
  #
29
29
  # @since 1.0.0
30
30
  def is_a?(other)
31
- if other == ::Boolean || other.class == ::Boolean
31
+ if other == Mongoid::Boolean || other.class == Mongoid::Boolean
32
32
  return true
33
33
  end
34
34
  super(other)
@@ -13,6 +13,7 @@ module Mongoid
13
13
  extend ActiveSupport::Concern
14
14
 
15
15
  StringifiedSymbol = Mongoid::StringifiedSymbol
16
+ Boolean = Mongoid::Boolean
16
17
 
17
18
  # For fields defined with symbols use the correct class.
18
19
  #
@@ -37,10 +38,48 @@ module Mongoid
37
38
  time: Time
38
39
  }.with_indifferent_access
39
40
 
40
- # Constant for all names of the id field in a document.
41
+ # Constant for all names of the _id field in a document.
41
42
  #
42
- # @since 5.0.0
43
- IDS = [ :_id, :id, '_id', 'id' ].freeze
43
+ # This does not include aliases of _id field.
44
+ #
45
+ # @api private
46
+ IDS = [ :_id, '_id', ].freeze
47
+
48
+ module ClassMethods
49
+ # Returns the list of id fields for this model class, as both strings
50
+ # and symbols.
51
+ #
52
+ # @return [ Array<Symbol | String> ] List of id fields.
53
+ #
54
+ # @api private
55
+ def id_fields
56
+ IDS.dup.tap do |id_fields|
57
+ aliased_fields.each do |k, v|
58
+ if v == '_id'
59
+ id_fields << k.to_sym
60
+ id_fields << k
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ # Extracts the id field from the specified attributes hash based on
67
+ # aliases defined in this class.
68
+ #
69
+ # @param [ Hash ] attributes The attributes to inspect.
70
+ #
71
+ # @return [ Object ] The id value.
72
+ #
73
+ # @api private
74
+ def extract_id_field(attributes)
75
+ id_fields.each do |k|
76
+ if v = attributes[k]
77
+ return v
78
+ end
79
+ end
80
+ nil
81
+ end
82
+ end
44
83
 
45
84
  included do
46
85
  class_attribute :aliased_fields
@@ -62,8 +101,7 @@ module Mongoid
62
101
  type: BSON::ObjectId
63
102
  )
64
103
 
65
- alias :id :_id
66
- alias :id= :_id=
104
+ alias_attribute(:id, :_id)
67
105
  end
68
106
 
69
107
  # Apply all default values to the document which are not procs.
@@ -20,7 +20,7 @@ module Mongoid
20
20
  def inspect
21
21
  inspection = []
22
22
  inspection.concat(inspect_fields).concat(inspect_dynamic_fields)
23
- "#<#{self.class.name} _id: #{id}, #{inspection * ', '}>"
23
+ "#<#{self.class.name} _id: #{_id}, #{inspection * ', '}>"
24
24
  end
25
25
 
26
26
  private
@@ -79,6 +79,11 @@ end
79
79
 
80
80
  require 'mongoid/matcher/all'
81
81
  require 'mongoid/matcher/and'
82
+ require 'mongoid/matcher/bits'
83
+ require 'mongoid/matcher/bits_all_clear'
84
+ require 'mongoid/matcher/bits_all_set'
85
+ require 'mongoid/matcher/bits_any_clear'
86
+ require 'mongoid/matcher/bits_any_set'
82
87
  require 'mongoid/matcher/elem_match'
83
88
  require 'mongoid/matcher/elem_match_expression'
84
89
  require 'mongoid/matcher/eq'
@@ -92,6 +97,7 @@ require 'mongoid/matcher/gte'
92
97
  require 'mongoid/matcher/in'
93
98
  require 'mongoid/matcher/lt'
94
99
  require 'mongoid/matcher/lte'
100
+ require 'mongoid/matcher/mod'
95
101
  require 'mongoid/matcher/ne'
96
102
  require 'mongoid/matcher/nin'
97
103
  require 'mongoid/matcher/nor'
@@ -99,5 +105,6 @@ require 'mongoid/matcher/not'
99
105
  require 'mongoid/matcher/or'
100
106
  require 'mongoid/matcher/regex'
101
107
  require 'mongoid/matcher/size'
108
+ require 'mongoid/matcher/type'
102
109
  require 'mongoid/matcher/expression_operator'
103
110
  require 'mongoid/matcher/field_operator'
@@ -0,0 +1,41 @@
1
+ module Mongoid
2
+ module Matcher
3
+
4
+ # @api private
5
+ module Bits
6
+ def matches?(exists, value, condition)
7
+ case value
8
+ when BSON::Binary
9
+ value = value.data.split('').map { |n| '%02x' % n.ord }.join.to_i(16)
10
+ end
11
+ case condition
12
+ when Array
13
+ array_matches?(value, condition)
14
+ when BSON::Binary
15
+ int_cond = condition.data.split('').map { |n| '%02x' % n.ord }.join.to_i(16)
16
+ int_matches?(value, int_cond)
17
+ when Integer
18
+ if condition < 0
19
+ raise Errors::InvalidQuery, "Invalid value for $#{operator_name} argument: negative integers are not allowed: #{condition}"
20
+ end
21
+ int_matches?(value, condition)
22
+ when Float
23
+ if (int_cond = condition.to_i).to_f == condition
24
+ if int_cond < 0
25
+ raise Errors::InvalidQuery, "Invalid value for $#{operator_name} argument: negative numbers are not allowed: #{condition}"
26
+ end
27
+ int_matches?(value, int_cond)
28
+ else
29
+ raise Errors::InvalidQuery, "Invalid type for $#{operator_name} argument: not representable as an integer: #{condition}"
30
+ end
31
+ else
32
+ raise Errors::InvalidQuery, "Invalid type for $#{operator_name} argument: #{condition}"
33
+ end
34
+ end
35
+
36
+ module_function def operator_name
37
+ name.sub(/.*::/, '').sub(/\A(.)/) { |l| l.downcase }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ module Mongoid
2
+ module Matcher
3
+
4
+ # @api private
5
+ module BitsAllClear
6
+ include Bits
7
+ extend self
8
+
9
+ def array_matches?(value, condition)
10
+ condition.all? do |c|
11
+ value & (1<<c) == 0
12
+ end
13
+ end
14
+
15
+ def int_matches?(value, condition)
16
+ value & condition == 0
17
+ end
18
+ end
19
+ end
20
+ end