mongoid/mongoid

View on GitHub
lib/mongoid/fields/foreign_key.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# encoding: utf-8
module Mongoid
  module Fields
    class ForeignKey < Standard

      # Adds the atomic changes for this type of resizable field.
      #
      # @example Add the atomic changes.
      #   field.add_atomic_changes(doc, "key", {}, [], [])
      #
      # @todo: Durran: Refactor, big time.
      #
      # @param [ Document ] document The document to add to.
      # @param [ String ] name The name of the field.
      # @param [ String ] key The atomic location of the field.
      # @param [ Hash ] mods The current modifications.
      # @param [ Array ] new The new elements to add.
      # @param [ Array ] old The old elements getting removed.
      #
      # @since 2.4.0
      def add_atomic_changes(document, name, key, mods, new_elements, old_elements)
        old = (old_elements || [])
        new = (new_elements || [])
        if new.length > old.length
          if new.first(old.length) == old
            document.atomic_array_add_to_sets[key] = new.drop(old.length)
          else
            mods[key] = document.attributes[name]
          end
        elsif new.length < old.length
          pulls = old - new
          if new == old - pulls
            document.atomic_array_pulls[key] = pulls
          else
            mods[key] = document.attributes[name]
          end
        elsif new != old
          mods[key] = document.attributes[name]
        end
      end

      # Is this field a foreign key?
      #
      # @example Is the field a foreign key?
      #   field.foreign_key?
      #
      # @return [ true, false ] If the field is a foreign key.
      #
      # @since 2.4.0
      def foreign_key?
        true
      end

      # Evolve the object into an id compatible object.
      #
      # @example Evolve the object.
      #   field.evolve(object)
      #
      # @param [ Object ] object The object to evolve.
      #
      # @return [ Object ] The evolved object.
      #
      # @since 3.0.0
      def evolve(object)
        if object_id_field? || object.is_a?(Document)
          object.__evolve_object_id__
        else
          related_id_field.evolve(object)
        end
      end

      # Does this field do lazy default evaluation?
      #
      # @example Is the field lazy?
      #   field.lazy?
      #
      # @return [ true, false ] If the field is lazy.
      #
      # @since 3.1.0
      def lazy?
        type.resizable?
      end

      # Mongoize the object into the Mongo friendly value.
      #
      # @example Mongoize the object.
      #   field.mongoize(object)
      #
      # @param [ Object ] object The object to Mongoize.
      #
      # @return [ Object ] The mongoized object.
      #
      # @since 3.0.0
      def mongoize(object)
        if type.resizable? || object_id_field?
          type.__mongoize_fk__(constraint, object)
        else
          related_id_field.mongoize(object)
        end
      end

      # Is the field a BSON::ObjectId?
      #
      # @example Is the field a BSON::ObjectId?
      #   field.object_id_field?
      #
      # @return [ true, false ] If the field is a BSON::ObjectId.
      #
      # @since 2.2.0
      def object_id_field?
        @object_id_field ||=
          metadata.polymorphic? ? true : metadata.klass.using_object_ids?
      end

      # Returns true if an array, false if not.
      #
      # @example Is the field resizable?
      #   field.resizable?
      #
      # @return [ true, false ] If the field is resizable.
      #
      # @since 3.0.2
      def resizable?
        type.resizable?
      end

      private

      # Evaluate the default proc. In some cases we need to instance exec,
      # in others we don't.
      #
      # @example Eval the default proc.
      #   field.evaluate_default_proc(band)
      #
      # @param [ Document ] doc The document.
      #
      # @return [ Object ] The called proc.
      #
      # @since 3.0.0
      def evaluate_default_proc(doc)
        serialize_default(default_val[])
      end

      # Get the id field of the relation.
      #
      # @api private
      #
      # @example Get the related id field.
      #   field.related_id_field
      #
      # @return [ Fields::Standard ] The field.
      #
      # @since 3.0.0
      def related_id_field
        @related_id_field ||= metadata.klass.fields["_id"]
      end

      # This is used when default values need to be serialized. Most of the
      # time just return the object.
      #
      # @api private
      #
      # @example Serialize the default value.
      #   field.serialize_default(obj)
      #
      # @param [ Object ] object The default.
      #
      # @return [ Object ] The serialized default.
      #
      # @since 3.0.0
      def serialize_default(object); object; end
    end
  end
end