From e2797b76ae389044424539f083ee2da8cf8b13e5 Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Thu, 4 Oct 2012 16:45:16 +0200 Subject: [PATCH] Aliased fields now work with distinct queries. [ fix mongoid/moped#82 ] --- CHANGELOG.md | 2 ++ lib/mongoid/contextual/mongo.rb | 2 +- lib/mongoid/fields.rb | 31 +++++++++++++++++++++++ lib/mongoid/indexes.rb | 7 +++-- lib/mongoid/multi_parameter_attributes.rb | 2 +- lib/mongoid/persistence.rb | 2 +- lib/mongoid/validations/uniqueness.rb | 3 +-- spec/app/models/band.rb | 1 + spec/mongoid/contextual/mongo_spec.rb | 19 ++++++++++++-- 9 files changed, 58 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b82558498..90d3cca230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ For instructions on upgrading to newer versions, visit ### Resolved Issues +* mongoid/moped\#82 Aliased fields now work with `Criteria#distinct`. + * \#2423 Fixed embedded document's `update_all` to perform the correct $set when using off a criteria. diff --git a/lib/mongoid/contextual/mongo.rb b/lib/mongoid/contextual/mongo.rb index 773d3d8c57..23492cfcef 100644 --- a/lib/mongoid/contextual/mongo.rb +++ b/lib/mongoid/contextual/mongo.rb @@ -113,7 +113,7 @@ def destroy # # @since 3.0.0 def distinct(field) - query.distinct(field) + query.distinct(klass.database_field_name(field)) end # Iterate over the context. If provided a block, yield to a Mongoid diff --git a/lib/mongoid/fields.rb b/lib/mongoid/fields.rb index 300436cdbb..edf3faddac 100644 --- a/lib/mongoid/fields.rb +++ b/lib/mongoid/fields.rb @@ -109,6 +109,21 @@ def attribute_names self.class.attribute_names end + # Get the name of the provided field as it is stored in the database. + # Used in determining if the field is aliased or not. + # + # @example Get the database field name. + # model.database_field_name(:authorization) + # + # @param [ String, Symbol ] name The name to get. + # + # @return [ String ] The name of the field as it's stored in the db. + # + # @since 3.0.7 + def database_field_name(name) + self.class.database_field_name(name) + end + # Is the document using object ids? # # @note Refactored from using delegate for class load performance. @@ -175,6 +190,22 @@ def attribute_names fields.keys end + # Get the name of the provided field as it is stored in the database. + # Used in determining if the field is aliased or not. + # + # @example Get the database field name. + # Model.database_field_name(:authorization) + # + # @param [ String, Symbol ] name The name to get. + # + # @return [ String ] The name of the field as it's stored in the db. + # + # @since 3.0.7 + def database_field_name(name) + normalized = name.to_s + aliased_fields[normalized] || normalized + end + # Defines all the fields that are accessible on the Document # For each field that is defined, a getter and setter will be # added as an instance method to the Document. diff --git a/lib/mongoid/indexes.rb b/lib/mongoid/indexes.rb index 8766e582dc..7d181bc11f 100644 --- a/lib/mongoid/indexes.rb +++ b/lib/mongoid/indexes.rb @@ -115,10 +115,9 @@ def normalize_index_options(options) # # @since 3.0.7 def normalize_spec(spec) - spec.inject({}) do |normal, (name, direction)| - field_name = aliased_fields[name.to_s] || name - normal[field_name.to_sym] = direction - normal + spec.inject({}) do |normalized, (name, direction)| + normalized[database_field_name(name).to_sym] = direction + normalized end end end diff --git a/lib/mongoid/multi_parameter_attributes.rb b/lib/mongoid/multi_parameter_attributes.rb index ab7b54d04a..d5e9715fe0 100644 --- a/lib/mongoid/multi_parameter_attributes.rb +++ b/lib/mongoid/multi_parameter_attributes.rb @@ -66,7 +66,7 @@ def process_attributes(attrs = nil, role = :default, guard_protected_attributes multi_parameter_attributes.each_pair do |key, values| begin values = (values.keys.min..values.keys.max).map { |i| values[i] } - field = self.class.fields[aliased_fields[key] || key] + field = self.class.fields[database_field_name(key)] attributes[key] = instantiate_object(field, values) rescue => e errors << Errors::AttributeAssignmentError.new( diff --git a/lib/mongoid/persistence.rb b/lib/mongoid/persistence.rb index 01d303d937..c5bf30f7c8 100644 --- a/lib/mongoid/persistence.rb +++ b/lib/mongoid/persistence.rb @@ -159,7 +159,7 @@ def update_attribute(name, value) unless attribute_writable?(normalized) raise Errors::ReadonlyAttribute.new(normalized, value) end - write_attribute(aliased_fields[normalized] || normalized, value) + write_attribute(database_field_name(normalized), value) save(validate: false) end diff --git a/lib/mongoid/validations/uniqueness.rb b/lib/mongoid/validations/uniqueness.rb index bcc9e23ec1..33ffa9ccff 100644 --- a/lib/mongoid/validations/uniqueness.rb +++ b/lib/mongoid/validations/uniqueness.rb @@ -167,8 +167,7 @@ def filter(value) # @since 2.3.0 def scope(criteria, document, attribute) Array.wrap(options[:scope]).each do |item| - normalized = item.to_s - name = document.aliased_fields[normalized] || normalized + name = document.database_field_name(item) criteria = criteria.where(item => document.attributes[name]) end criteria = criteria.where(deleted_at: nil) if document.paranoid? diff --git a/spec/app/models/band.rb b/spec/app/models/band.rb index 6f467d9b65..df56b27688 100644 --- a/spec/app/models/band.rb +++ b/spec/app/models/band.rb @@ -12,6 +12,7 @@ class Band field :upserted, type: Boolean, default: false field :created, type: DateTime field :sales, type: BigDecimal + field :y, as: :years, type: Integer embeds_many :records, cascade_callbacks: true embeds_many :notes, as: :noteable, cascade_callbacks: true, validate: false diff --git a/spec/mongoid/contextual/mongo_spec.rb b/spec/mongoid/contextual/mongo_spec.rb index 9765f5a9bc..8a5abd0d10 100644 --- a/spec/mongoid/contextual/mongo_spec.rb +++ b/spec/mongoid/contextual/mongo_spec.rb @@ -256,8 +256,8 @@ describe "#distinct" do before do - Band.create(name: "Depeche Mode") - Band.create(name: "New Order") + Band.create(name: "Depeche Mode", years: 30) + Band.create(name: "New Order", years: 25) end context "when limiting the result set" do @@ -289,6 +289,21 @@ context.distinct(:name).should eq([ "Depeche Mode", "New Order" ]) end end + + context "when providing an aliased field" do + + let(:criteria) do + Band.criteria + end + + let(:context) do + described_class.new(criteria) + end + + it "returns the distinct field values" do + context.distinct(:years).should eq([ 30, 25 ]) + end + end end describe "#each" do