提交 5eb13fca 编写于 作者: Y Yves Senn

refactor, put `PostgreSQLColumn` into `column.rb`.

We have `connection_adapters/column.rb` so it's easier to remember
that the column in in a separate file.
上级 5e31b4ac
module ActiveRecord
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
attr_accessor :array
def initialize(name, default, oid_type, sql_type = nil, null = true)
@oid_type = oid_type
default_value = self.class.extract_value_from_default(default)
if sql_type =~ /\[\]$/
@array = true
super(name, default_value, sql_type[0..sql_type.length - 3], null)
else
@array = false
super(name, default_value, sql_type, null)
end
@default_function = default if has_default_function?(default_value, default)
end
def number?
!array && super
end
def text?
!array && super
end
# :stopdoc:
class << self
include ConnectionAdapters::PostgreSQLColumn::Cast
include ConnectionAdapters::PostgreSQLColumn::ArrayParser
attr_accessor :money_precision
end
# :startdoc:
# Extracts the value from a PostgreSQL column default definition.
def self.extract_value_from_default(default)
# This is a performance optimization for Ruby 1.9.2 in development.
# If the value is nil, we return nil straight away without checking
# the regular expressions. If we check each regular expression,
# Regexp#=== will call NilClass#to_str, which will trigger
# method_missing (defined by whiny nil in ActiveSupport) which
# makes this method very very slow.
return default unless default
case default
when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
$1
# Numeric types
when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
$1
# Character types
when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
$1.gsub(/''/, "'")
# Binary data types
when /\A'(.*)'::bytea\z/m
$1
# Date/time types
when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
$1
when /\A'(.*)'::interval\z/
$1
# Boolean type
when 'true'
true
when 'false'
false
# Geometric types
when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
$1
# Network address types
when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
$1
# Bit string types
when /\AB'(.*)'::"?bit(?: varying)?"?\z/
$1
# XML type
when /\A'(.*)'::xml\z/m
$1
# Arrays
when /\A'(.*)'::"?\D+"?\[\]\z/
$1
# Hstore
when /\A'(.*)'::hstore\z/
$1
# JSON
when /\A'(.*)'::json\z/
$1
# Object identifier types
when /\A-?\d+\z/
$1
else
# Anything else is blank, some user type, or some function
# and we can't know the value of that, so return nil.
nil
end
end
def type_cast_for_write(value)
if @oid_type.respond_to?(:type_cast_for_write)
@oid_type.type_cast_for_write(value)
else
super
end
end
def type_cast(value)
return if value.nil?
return super if encoded?
@oid_type.type_cast value
end
def accessor
@oid_type.accessor
end
private
def has_default_function?(default_value, default)
!default_value && (%r{\w+\(.*\)} === default)
end
def extract_limit(sql_type)
case sql_type
when /^bigint/i; 8
when /^smallint/i; 2
when /^timestamp/i; nil
else super
end
end
# Extracts the scale from PostgreSQL-specific data types.
def extract_scale(sql_type)
# Money type has a fixed scale of 2.
sql_type =~ /^money/ ? 2 : super
end
# Extracts the precision from PostgreSQL-specific data types.
def extract_precision(sql_type)
if sql_type == 'money'
self.class.money_precision
elsif sql_type =~ /timestamp/i
$1.to_i if sql_type =~ /\((\d+)\)/
else
super
end
end
# Maps PostgreSQL-specific data types to logical Rails types.
def simplified_type(field_type)
case field_type
# Numeric and monetary types
when /^(?:real|double precision)$/
:float
# Monetary types
when 'money'
:decimal
when 'hstore'
:hstore
when 'ltree'
:ltree
# Network address types
when 'inet'
:inet
when 'cidr'
:cidr
when 'macaddr'
:macaddr
# Character types
when /^(?:character varying|bpchar)(?:\(\d+\))?$/
:string
when /^citext(?:\(\d+\))?$/
:citext
# Binary data types
when 'bytea'
:binary
# Date/time types
when /^timestamp with(?:out)? time zone$/
:datetime
when /^interval(?:|\(\d+\))$/
:string
# Geometric types
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
:string
# Bit strings
when /^bit(?: varying)?(?:\(\d+\))?$/
:string
# XML type
when 'xml'
:xml
# tsvector type
when 'tsvector'
:tsvector
# Arrays
when /^\D+\[\]$/
:string
# Object identifier types
when 'oid'
:integer
# UUID type
when 'uuid'
:uuid
# JSON type
when 'json'
:json
# Small and big integer types
when /^(?:small|big)int$/
:integer
when /(num|date|tstz|ts|int4|int8)range$/
field_type.to_sym
# Pass through all types that are not specific to PostgreSQL.
else
super
end
end
end
end
end
......@@ -7,6 +7,7 @@
require 'active_record/connection_adapters/postgresql/schema_statements'
require 'active_record/connection_adapters/postgresql/database_statements'
require 'active_record/connection_adapters/postgresql/referential_integrity'
require 'active_record/connection_adapters/postgresql/column'
require 'arel/visitors/bind_visitor'
# Make sure we're using pg high enough for PGResult#values
......@@ -43,224 +44,6 @@ def postgresql_connection(config)
end
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
attr_accessor :array
def initialize(name, default, oid_type, sql_type = nil, null = true)
@oid_type = oid_type
default_value = self.class.extract_value_from_default(default)
if sql_type =~ /\[\]$/
@array = true
super(name, default_value, sql_type[0..sql_type.length - 3], null)
else
@array = false
super(name, default_value, sql_type, null)
end
@default_function = default if has_default_function?(default_value, default)
end
def number?
!array && super
end
def text?
!array && super
end
# :stopdoc:
class << self
include ConnectionAdapters::PostgreSQLColumn::Cast
include ConnectionAdapters::PostgreSQLColumn::ArrayParser
attr_accessor :money_precision
end
# :startdoc:
# Extracts the value from a PostgreSQL column default definition.
def self.extract_value_from_default(default)
# This is a performance optimization for Ruby 1.9.2 in development.
# If the value is nil, we return nil straight away without checking
# the regular expressions. If we check each regular expression,
# Regexp#=== will call NilClass#to_str, which will trigger
# method_missing (defined by whiny nil in ActiveSupport) which
# makes this method very very slow.
return default unless default
case default
when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
$1
# Numeric types
when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
$1
# Character types
when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
$1.gsub(/''/, "'")
# Binary data types
when /\A'(.*)'::bytea\z/m
$1
# Date/time types
when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
$1
when /\A'(.*)'::interval\z/
$1
# Boolean type
when 'true'
true
when 'false'
false
# Geometric types
when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
$1
# Network address types
when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
$1
# Bit string types
when /\AB'(.*)'::"?bit(?: varying)?"?\z/
$1
# XML type
when /\A'(.*)'::xml\z/m
$1
# Arrays
when /\A'(.*)'::"?\D+"?\[\]\z/
$1
# Hstore
when /\A'(.*)'::hstore\z/
$1
# JSON
when /\A'(.*)'::json\z/
$1
# Object identifier types
when /\A-?\d+\z/
$1
else
# Anything else is blank, some user type, or some function
# and we can't know the value of that, so return nil.
nil
end
end
def type_cast_for_write(value)
if @oid_type.respond_to?(:type_cast_for_write)
@oid_type.type_cast_for_write(value)
else
super
end
end
def type_cast(value)
return if value.nil?
return super if encoded?
@oid_type.type_cast value
end
def accessor
@oid_type.accessor
end
private
def has_default_function?(default_value, default)
!default_value && (%r{\w+\(.*\)} === default)
end
def extract_limit(sql_type)
case sql_type
when /^bigint/i; 8
when /^smallint/i; 2
when /^timestamp/i; nil
else super
end
end
# Extracts the scale from PostgreSQL-specific data types.
def extract_scale(sql_type)
# Money type has a fixed scale of 2.
sql_type =~ /^money/ ? 2 : super
end
# Extracts the precision from PostgreSQL-specific data types.
def extract_precision(sql_type)
if sql_type == 'money'
self.class.money_precision
elsif sql_type =~ /timestamp/i
$1.to_i if sql_type =~ /\((\d+)\)/
else
super
end
end
# Maps PostgreSQL-specific data types to logical Rails types.
def simplified_type(field_type)
case field_type
# Numeric and monetary types
when /^(?:real|double precision)$/
:float
# Monetary types
when 'money'
:decimal
when 'hstore'
:hstore
when 'ltree'
:ltree
# Network address types
when 'inet'
:inet
when 'cidr'
:cidr
when 'macaddr'
:macaddr
# Character types
when /^(?:character varying|bpchar)(?:\(\d+\))?$/
:string
when /^citext(?:\(\d+\))?$/
:citext
# Binary data types
when 'bytea'
:binary
# Date/time types
when /^timestamp with(?:out)? time zone$/
:datetime
when /^interval(?:|\(\d+\))$/
:string
# Geometric types
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
:string
# Bit strings
when /^bit(?: varying)?(?:\(\d+\))?$/
:string
# XML type
when 'xml'
:xml
# tsvector type
when 'tsvector'
:tsvector
# Arrays
when /^\D+\[\]$/
:string
# Object identifier types
when 'oid'
:integer
# UUID type
when 'uuid'
:uuid
# JSON type
when 'json'
:json
# Small and big integer types
when /^(?:small|big)int$/
:integer
when /(num|date|tstz|ts|int4|int8)range$/
field_type.to_sym
# Pass through all types that are not specific to PostgreSQL.
else
super
end
end
end
# The PostgreSQL adapter works with the native C (https://bitbucket.org/ged/ruby-pg) driver.
#
# Options:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册