diff options
Diffstat (limited to 'activerecord/lib/active_record/type/value.rb')
-rw-r--r-- | activerecord/lib/active_record/type/value.rb | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/type/value.rb b/activerecord/lib/active_record/type/value.rb new file mode 100644 index 0000000000..7338920f3b --- /dev/null +++ b/activerecord/lib/active_record/type/value.rb @@ -0,0 +1,112 @@ +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 # :nodoc: + end + + # 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 + # Value#type_cast and Value#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: + # Value#type_cast and Value#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 binary? # :nodoc: + false + 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 Value#type_cast_for_database and compare it to + # +raw_old_value+ + # + # or + # + # - pass +raw_old_value+ to Value#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 + # Value#type_cast_from_database and Value#type_cast_from_user, you can override + # this method instead. The default behavior of both methods is to call + # this one. See also Value#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 Value#type_cast for + # values except +nil+. + def cast_value(value) # :doc: + value + end + end + end +end |