From 0ada76cb7c879261e76bc96d02b60d81f86a6f5f Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@thoughtbot.com>
Date: Tue, 1 Jul 2014 08:11:59 -0600
Subject: Use a type object for type casting behavior on SQLite3

Note: I'm not sure we actually need to be logging when this happens.
This code would be a fair bit cleaner if we didn't need to log it.
---
 .../connection_adapters/sqlite3_adapter.rb         | 50 ++++++++++++++++------
 1 file changed, 37 insertions(+), 13 deletions(-)

(limited to 'activerecord/lib')

diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index e6163771e8..360922dfaa 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -50,6 +50,34 @@ module ActiveRecord
       end
     end
 
+    class SQLite3String < Type::String # :nodoc:
+      def initialize(logger, *args)
+        @logger = logger
+        super(*args)
+      end
+
+      def type_cast_for_database(value)
+        return unless value
+
+        if value.encoding == Encoding::ASCII_8BIT
+          @logger.error "Binary data inserted for `string` type" if @logger
+          value.encode Encoding::UTF_8
+        else
+          value
+        end
+      end
+
+      class Factory
+        def initialize(logger)
+          @logger = logger
+        end
+
+        def new(*args)
+          SQLite3String.new(@logger, *args)
+        end
+      end
+    end
+
     # The SQLite3 adapter works SQLite 3.6.16 or newer
     # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
     #
@@ -227,6 +255,14 @@ module ActiveRecord
         end
       end
 
+      def _type_cast(value) # :nodoc:
+        if value.is_a?(BigDecimal)
+          value.to_f
+        else
+          super
+        end
+      end
+
       def quote_string(s) #:nodoc:
         @connection.class.quote(s)
       end
@@ -249,19 +285,6 @@ module ActiveRecord
         end
       end
 
-      def type_cast(value, column) # :nodoc:
-        return value.to_f if BigDecimal === value
-        return super unless String === value
-        return super unless column && value
-
-        value = super
-        if column.type == :string && value.encoding == Encoding::ASCII_8BIT
-          logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
-          value = value.encode Encoding::UTF_8
-        end
-        value
-      end
-
       # DATABASE STATEMENTS ======================================
 
       def explain(arel, binds = [])
@@ -503,6 +526,7 @@ module ActiveRecord
         def initialize_type_map(m)
           super
           m.register_type(/binary/i, SQLite3Binary.new)
+          register_class_with_limit m, %r(char)i, SQLite3String::Factory.new(logger)
         end
 
         def select(sql, name = nil, binds = []) #:nodoc:
-- 
cgit v1.2.3