diff --git a/docs/reference/inheritance.txt b/docs/reference/inheritance.txt index dcba02a96..240647702 100644 --- a/docs/reference/inheritance.txt +++ b/docs/reference/inheritance.txt @@ -32,7 +32,7 @@ fields, associations, validations and scopes are copied to the child document. class Browser < Canvas field :version, type: Integer - scope :recent, ->{ where(:version.gt => 3) } + scope :recent, ->{ gt(version: 3) } end class Firefox < Browser diff --git a/docs/reference/map-reduce.txt b/docs/reference/map-reduce.txt index 2251ffa91..025423d2a 100644 --- a/docs/reference/map-reduce.txt +++ b/docs/reference/map-reduce.txt @@ -48,7 +48,7 @@ functions. } } - Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: 1) + Band.gt(likes: 100).map_reduce(map, reduce).out(inline: 1) Just like criteria, map/reduce calls are lazily evaluated. So nothing will hit the database until you iterate over the results, or make a call on the @@ -80,7 +80,7 @@ or its aliases ``raw`` and ``results``: .. code-block:: ruby - mr = Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: 1) + mr = Band.gt(likes: 100).map_reduce(map, reduce).out(inline: 1) mr.execute # => {"results"=>[{"_id"=>"Tool", "value"=>{"likes"=>200.0}}], @@ -111,7 +111,7 @@ The following code illustrates retrieving the statistics: .. code-block:: ruby - mr = Band.where(:likes.gt => 100).map_reduce(map, reduce).out(inline: 1) + mr = Band.gt(likes: 100).map_reduce(map, reduce).out(inline: 1) mr.counts # => {"input"=>4, "emit"=>4, "reduce"=>1, "output"=>1} diff --git a/docs/reference/queries.txt b/docs/reference/queries.txt index 8dcae9b27..746cea97a 100644 --- a/docs/reference/queries.txt +++ b/docs/reference/queries.txt @@ -23,7 +23,7 @@ A more complex query utilizing various Mongoid features could be as follows: .. code-block:: ruby Band. - where(:founded.gte => "1980-01-01"). + gte(founded: "1980-01-01"). in(name: [ "Tool", "Deftones" ]). union. in(name: [ "Melvins" ]) @@ -59,14 +59,14 @@ Criteria instance with the new conditions added to the existing conditions: .. code-block:: ruby - scope = Band.where(:founded.gte => "1980-01-01") + scope = Band.gte(founded: "1980-01-01") # => #{"$gte"=>"1980-01-01"}} # options: {} # class: Band # embedded: false> - scope.where(:founded.lte => "2020-01-01") + scope.lte(founded: "2020-01-01") # => #{"$gte"=>"1980-01-01", "$lte"=>"2020-01-01"}} # options: {} @@ -156,6 +156,12 @@ An MQL operator may be specified on any field using the hash syntax: Symbol Operator Syntax ---------------------- +.. warning:: + + Symbol operator syntax is deprecated and will be extracted to a gem + in Mongoid 10. It is strongly recommended to switch to either + field syntax or MQL syntax as shown above. + MQL operators may be specified as methods on symbols for the respective field name, as follows: diff --git a/docs/release-notes/mongoid-9.0.txt b/docs/release-notes/mongoid-9.0.txt index 8a32c94a6..a69f572e9 100644 --- a/docs/release-notes/mongoid-9.0.txt +++ b/docs/release-notes/mongoid-9.0.txt @@ -127,6 +127,35 @@ Deprecated functionality removed definitions without replacement. +Symbol query operator syntax deprecated +--------------------------------------- + +The following query syntax which monkey-patches the Symbol class is +deprecated as of Mongoid 9. It will be removed in Mongoid 10. + +.. code-block:: ruby + + # Deprecated symbol operator query syntax + Band.where(:founded.gt => 1980) + +Please replace this syntax with one of the following: + +.. code-block:: ruby + + # Field query syntax + Band.gt(founded: 1980) + + # MQL query syntax + Band.where(founded: { '$gt' => 1980 }) + +Note that the above syntaxes can equivalently do everything +the symbol operator syntax can. + +Although we strongly recommend to migrate your code, +if you would like to continue using the deprecated syntax, +please add the 'mongoid-symbol-operators' gem to your Gemfile. + + ``touch`` method now clears changed state ----------------------------------------- diff --git a/lib/mongoid/criteria/queryable/extensions/symbol.rb b/lib/mongoid/criteria/queryable/extensions/symbol.rb index dd195e3ba..d8fb7d31e 100644 --- a/lib/mongoid/criteria/queryable/extensions/symbol.rb +++ b/lib/mongoid/criteria/queryable/extensions/symbol.rb @@ -22,23 +22,6 @@ def __expr_part__(value, negating = false) end module ClassMethods - - # Adds a method on symbol as a convenience for the MongoDB operator. - # - # @example Add the $in method. - # Symbol.add_key(:in, "$in") - # - # @param [ Symbol ] name The name of the method. - # @param [ Symbol ] strategy The name of the merge strategy. - # @param [ String ] operator The MongoDB operator. - # @param [ String ] additional The additional MongoDB operator. - def add_key(name, strategy, operator, additional = nil, &block) - define_method(name) do - method = :"__#{strategy}__" - Key.new(self, method, operator, additional, &block) - end - end - # Evolves the symbol into a MongoDB friendly value - in this case # a symbol. # diff --git a/lib/mongoid/criteria/queryable/macroable.rb b/lib/mongoid/criteria/queryable/macroable.rb index acb76d797..995367b81 100644 --- a/lib/mongoid/criteria/queryable/macroable.rb +++ b/lib/mongoid/criteria/queryable/macroable.rb @@ -17,9 +17,87 @@ module Macroable # @param [ Symbol ] strategy The merge strategy. # @param [ String ] operator The MongoDB operator. # @param [ String ] additional The additional MongoDB operator. - def key(name, strategy, operator, additional = nil, &block) - ::Symbol.add_key(name, strategy, operator, additional, &block) + # + # @deprecated Will be moved to the mongoid-symbol-operators gem. + def define_key(name, strategy, operator, additional = nil, &block) + warning_name = :"symbol_selector_#{name}_deprecated" + + Mongoid::Warnings.warning warning_name, + "The query selector method Symbol##{name} is deprecated and " \ + "will be removed in Mongoid 10. Please use either Criteria##{name}, " \ + "the #{operator} operator, or add gem 'mongoid-symbol-operators' " \ + 'to your Gemfile.' + + ::Symbol.define_method(name) do + Mongoid::Warnings.send(:"warn_#{warning_name}") unless selectors_gem_present? + Mongoid::Criteria::Queryable::Key.new(self, :"__#{strategy}__", operator, additional, &block) + end + end + + def selectors_gem_present? + return @selectors_gem_present if defined?(@selectors_gem_present) + + @selectors_gem_present = !defined?(Bundler) || + !!Gem::Specification.find_by_name('mongoid-symbol-operators') + end + + define_key :all, :union, '$all' + + define_key :elem_match, :override, '$elemMatch' + + define_key :exists, :override, '$exists' do |value| + Mongoid::Boolean.evolve(value) end + + define_key :eq, :override, '$eq' + + define_key :gt, :override, '$gt' + + define_key :gte, :override, '$gte' + + define_key :in, :intersect, '$in' + + define_key :lt, :override, '$lt' + + define_key :lte, :override, '$lte' + + define_key :mod, :override, '$mod' + + define_key :ne, :override, '$ne' + + define_key :near, :override, '$near' + + define_key :near_sphere, :override, '$nearSphere' + + define_key :nin, :intersect, '$nin' + + define_key :not, :override, '$not' + + define_key :with_type, :override, '$type' do |value| + ::Integer.evolve(value) + end + + define_key :with_size, :override, '$size' do |value| + ::Integer.evolve(value) + end + + define_key :intersects_line, :override, '$geoIntersects', '$geometry' do |value| + { 'type' => Mongoid::Criteria::Queryable::Selectable::LINE_STRING, 'coordinates' => value } + end + + define_key :intersects_point, :override, '$geoIntersects', '$geometry' do |value| + { 'type' => Mongoid::Criteria::Queryable::Selectable::POINT, 'coordinates' => value } + end + + define_key :intersects_polygon, :override, '$geoIntersects', '$geometry' do |value| + { 'type' => Mongoid::Criteria::Queryable::Selectable::POLYGON, 'coordinates' => value } + end + + define_key :within_polygon, :override, '$geoWithin', '$geometry' do |value| + { 'type' => Mongoid::Criteria::Queryable::Selectable::POLYGON, 'coordinates' => value } + end + + define_key :within_box, :override, '$geoWithin', '$box' end end end diff --git a/lib/mongoid/criteria/queryable/selectable.rb b/lib/mongoid/criteria/queryable/selectable.rb index cc4e86a20..f358e0768 100644 --- a/lib/mongoid/criteria/queryable/selectable.rb +++ b/lib/mongoid/criteria/queryable/selectable.rb @@ -8,7 +8,6 @@ module Queryable # document from the database. The selectable module brings all functionality # to the selectable that has to do with building MongoDB selectors. module Selectable - extend Macroable # Constant for a LineString $geometry. LINE_STRING = 'LineString' @@ -54,7 +53,6 @@ def all(*criteria) end.reset_strategies! end alias_method :all_in, :all - key :all, :union, '$all' # Add the $and criterion. # @@ -142,7 +140,6 @@ def elem_match(criterion) and_with_operator(criterion, '$elemMatch') end - key :elem_match, :override, '$elemMatch' # Add the $exists selection. # @@ -165,9 +162,6 @@ def exists(criterion) Mongoid::Boolean.evolve(value) end end - key :exists, :override, '$exists' do |value| - Mongoid::Boolean.evolve(value) - end # Add a $geoIntersects or $geoWithin selection. Symbol operators must # be used as shown in the examples to expand the criteria. @@ -209,20 +203,6 @@ def geo_spatial(criterion) __merge__(criterion) end - key :intersects_line, :override, '$geoIntersects', '$geometry' do |value| - { 'type' => LINE_STRING, 'coordinates' => value } - end - key :intersects_point, :override, '$geoIntersects', '$geometry' do |value| - { 'type' => POINT, 'coordinates' => value } - end - key :intersects_polygon, :override, '$geoIntersects', '$geometry' do |value| - { 'type' => POLYGON, 'coordinates' => value } - end - key :within_polygon, :override, '$geoWithin', '$geometry' do |value| - { 'type' => POLYGON, 'coordinates' => value } - end - key :within_box, :override, '$geoWithin', '$box' - # Add the $eq criterion to the selector. # # @example Add the $eq criterion. @@ -239,7 +219,6 @@ def eq(criterion) and_with_operator(criterion, '$eq') end - key :eq, :override, '$eq' # Add the $gt criterion to the selector. # @@ -257,7 +236,6 @@ def gt(criterion) and_with_operator(criterion, '$gt') end - key :gt, :override, '$gt' # Add the $gte criterion to the selector. # @@ -275,7 +253,6 @@ def gte(criterion) and_with_operator(criterion, '$gte') end - key :gte, :override, '$gte' # Adds the $in selection to the selectable. # @@ -307,7 +284,6 @@ def in(condition) end end alias_method :any_in, :in - key :in, :intersect, '$in' # Add the $lt criterion to the selector. # @@ -325,7 +301,6 @@ def lt(criterion) and_with_operator(criterion, '$lt') end - key :lt, :override, '$lt' # Add the $lte criterion to the selector. # @@ -343,7 +318,6 @@ def lte(criterion) and_with_operator(criterion, '$lte') end - key :lte, :override, '$lte' # Add a $maxDistance selection to the selectable. # @@ -376,7 +350,6 @@ def mod(criterion) and_with_operator(criterion, '$mod') end - key :mod, :override, '$mod' # Adds $ne selection to the selectable. # @@ -395,7 +368,6 @@ def ne(criterion) and_with_operator(criterion, '$ne') end alias_method :excludes, :ne - key :ne, :override, '$ne' # Adds a $near criterion to a geo selection. # @@ -413,7 +385,6 @@ def near(criterion) and_with_operator(criterion, '$near') end - key :near, :override, '$near' # Adds a $nearSphere criterion to a geo selection. # @@ -431,7 +402,6 @@ def near_sphere(criterion) and_with_operator(criterion, '$nearSphere') end - key :near_sphere, :override, '$nearSphere' # Adds the $nin selection to the selectable. # @@ -463,7 +433,6 @@ def nin(condition) end end alias_method :not_in, :nin - key :nin, :intersect, '$nin' # Adds $nor selection to the selectable. # @@ -526,7 +495,6 @@ def not(*criteria) end end end - key :not, :override, '$not' # Negate the arguments, constraining the query to only those documents # that do NOT match the arguments. @@ -668,9 +636,6 @@ def with_size(criterion) ::Integer.evolve(value) end end - key :with_size, :override, '$size' do |value| - ::Integer.evolve(value) - end # Adds a $type selection to the selectable. # @@ -692,9 +657,6 @@ def with_type(criterion) ::Integer.evolve(value) end end - key :with_type, :override, '$type' do |value| - ::Integer.evolve(value) - end # Construct a text search selector. #