aboutsummaryrefslogblamecommitdiffstats
path: root/activerecord/lib/active_record/type/value.rb
blob: 7f41d525e18e90c56ca0730c72544d9cdf0889eb (plain) (tree)
1
2
3
4
5
6
7
8
9

                   
               

                                            



                                                            

         
                             
 





                                                                             

                                        

         
                                                                               






                                                                               
       
                                                                   



                                    



                                                                             
                                       
             

         


                                                                               


                     

                                                                           



                         
                           


             
                           


             
                         

         



                                                                              
                              

         
                                                                           
















                                                                              


             






                                         
             
 




                                                                             

                                           
 

                                                                            

                                                                          
                                   




             
module ActiveRecord
  module Type
    class Value
      attr_reader :precision, :scale, :limit

      def initialize(precision: nil, limit: nil, scale: nil)
        @precision = precision
        @scale = scale
        @limit = limit
      end

      def type; end # :nodoc:

      # Convert a value from database input to the appropriate ruby type. The
      # return value of this method will be returned from
      # +ActiveRecord::AttributeMethods::Read#read_attribute+. See also
      # +type_cast+ and +cast_value+
      #
      # +value+ The raw input, as provided from the database
      def type_cast_from_database(value)
        type_cast(value)
      end

      # Type casts a value from user input (e.g. from a setter). This value may
      # be a string from the form builder, or a ruby object passed to a setter.
      # There is currently no way to differentiate between which source it came
      # from.
      #
      # The return value of this method will be returned from
      # +ActiveRecord::AttributeMethods::Read#read_attribute+. See also:
      # +type_cast+ and +cast_value+
      #
      # +value+ The raw input, as provided to the attribute setter.
      def type_cast_from_user(value)
        type_cast(value)
      end

      # Cast a value from the ruby type to a type that the database knows how
      # to understand. The returned value from this method should be a
      # +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
      # +nil+
      def type_cast_for_database(value)
        value
      end

      # Type cast a value for schema dumping. This method is private, as we are
      # hoping to remove it entirely.
      def type_cast_for_schema(value) # :nodoc:
        value.inspect
      end

      # These predicates are not documented, as I need to look further into
      # their use, and see if they can be removed entirely.
      def text? # :nodoc:
        false
      end

      def number? # :nodoc:
        false
      end

      def binary? # :nodoc:
        false
      end

      def klass # :nodoc:
      end

      # Determines whether a value has changed for dirty checking. +old_value+
      # and +new_value+ will always be type-cast. Types should not need to
      # override this method.
      def changed?(old_value, new_value, _new_value_before_type_cast)
        old_value != new_value
      end

      # Determines whether the mutable value has been modified since it was
      # read. Returns +false+ by default. If your type returns an object
      # which could be mutated, you should override this method. You will need
      # to either:
      #
      # - pass +new_value+ to +type_cast_for_database+ and compare it to
      #   +raw_old_value+
      #
      # or
      #
      # - pass +raw_old_value+ to +type_cast_from_database+ and compare it to
      #   +new_value+
      #
      # +raw_old_value+ The original value, before being passed to
      # +type_cast_from_database+.
      #
      # +new_value+ The current value, after type casting.
      def changed_in_place?(raw_old_value, new_value)
        false
      end

      def ==(other)
        self.class == other.class &&
          precision == other.precision &&
          scale == other.scale &&
          limit == other.limit
      end

      private

      # Convenience method. If you don't need separate behavior for
      # +type_cast_from_database+ and +type_cast_from_user+, you can override
      # this method instead. The default behavior of both methods is to call
      # this one. See also +cast_value+
      def type_cast(value) # :doc:
        cast_value(value) unless value.nil?
      end

      # Convenience method for types which do not need separate type casting
      # behavior for user and database inputs. Called by
      # +type_cast_from_database+ and +type_cast_from_user+ for all values
      # except +nil+.
      def cast_value(value) # :doc:
        value
      end
    end
  end
end