require'time'require'date'moduleSQLite3# The Translator class encapsulates the logic and callbacks necessary for# converting string data to a value of some specified type. Every Database# instance may have a Translator instance, in order to assist in type# translation (Database#type_translation).## Further, applications may define their own custom type translation logic# by registering translator blocks with the corresponding database's# translator instance (Database#translator).classTranslator# Create a new Translator instance. It will be preinitialized with default# translators for most SQL data types.definitialize@translators=Hash.new(proc{|type,value|value})@type_name_cache={}register_default_translatorsend# Add a new translator block, which will be invoked to process type# translations to the given type. The type should be an SQL datatype, and# may include parentheses (i.e., "VARCHAR(30)"). However, any parenthetical# information is stripped off and discarded, so type translation decisions# are made solely on the "base" type name.## The translator block itself should accept two parameters, "type" and# "value". In this case, the "type" is the full type name (including# parentheses), so the block itself may include logic for changing how a# type is translated based on the additional data. The "value" parameter# is the (string) data to convert.## The block should return the translated value.defadd_translator(type,&block)# :yields: type, valuewarn(<<-eowarn)if$VERBOSE#{caller[0]} is calling `SQLite3::Translator#add_translator`. Built-in translators are deprecated and will be removed in version 2.0.0.
eowarn@translators[type_name(type)]=blockend# Translate the given string value to a value of the given type. In the# absence of an installed translator block for the given type, the value# itself is always returned. Further, +nil+ values are never translated,# and are always passed straight through regardless of the type parameter.deftranslate(type,value)unlessvalue.nil?# FIXME: this is a hack to support Sequeliftype&&%w{ datetime timestamp }.include?(type.downcase)@translators[type_name(type)].call(type,value.to_s)else@translators[type_name(type)].call(type,value)endendend# A convenience method for working with type names. This returns the "base"# type name, without any parenthetical data.deftype_name(type)@type_name_cache[type]||=begintype=""iftype.nil?type=$1iftype=~/^(.*?)\(/type.upcaseendendprivate:type_name# Register the default translators for the current Translator instance.# This includes translators for most major SQL data types.defregister_default_translators["time","timestamp"].each{|type|add_translator(type){|t,v|Time.parse(v)}}add_translator("date"){|t,v|Date.parse(v)}add_translator("datetime"){|t,v|DateTime.parse(v)}["decimal","float","numeric","double","real","dec","fixed"].each{|type|add_translator(type){|t,v|v.to_f}}["integer","smallint","mediumint","int","bigint"].each{|type|add_translator(type){|t,v|v.to_i}}["bit","bool","boolean"].eachdo|type|add_translator(type)do|t,v|!(v.strip.gsub(/00+/,"0")=="0"||v.downcase=="false"||v.downcase=="f"||v.downcase=="no"||v.downcase=="n")endendadd_translator("tinyint")do|type,value|iftype=~/\(\s*1\s*\)/value.to_i==1elsevalue.to_iendendendprivate:register_default_translatorsendend