aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/postgresql
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/postgresql')
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb76
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb19
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb8
4 files changed, 80 insertions, 59 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index f7d734a2f1..3d8f0b575c 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -62,6 +62,12 @@ module ActiveRecord
"{#{casted_values.join(',')}}"
end
+ def range_to_string(object)
+ from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin
+ to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end
+ "[#{from},#{to}#{object.exclude_end? ? ')' : ']'}"
+ end
+
def string_to_json(string)
if String === string
ActiveSupport::JSON.decode(string)
@@ -92,36 +98,6 @@ module ActiveRecord
parse_pg_array(string).map{|val| oid.type_cast val}
end
- def string_to_intrange(string)
- if string.nil?
- nil
- elsif "empty" == string
- (nil..nil)
- elsif String === string && (matches = /^(\(|\[)([0-9]+),(\s?)([0-9]+)(\)|\])$/i.match(string))
- lower_bound = ("(" == matches[1] ? (matches[2].to_i + 1) : matches[2].to_i)
- upper_bound = (")" == matches[5] ? (matches[4].to_i - 1) : matches[4].to_i)
- (lower_bound..upper_bound)
- else
- string
- end
- end
-
- def intrange_to_string(object)
- if object.nil?
- nil
- elsif Range === object
- if [object.first, object.last].all? { |el| Integer === el }
- "[#{object.first.to_i},#{object.exclude_end? ? object.last.to_i : object.last.to_i + 1})"
- elsif [object.first, object.last].all? { |el| NilClass === el }
- "empty"
- else
- nil
- end
- else
- object
- end
- end
-
private
HstorePair = begin
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 02c295983f..d90b9283ef 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -78,6 +78,64 @@ module ActiveRecord
end
end
+ class Range < Type
+ attr_reader :subtype
+ def initialize(subtype)
+ @subtype = subtype
+ end
+
+ def exctract_bounds(value)
+ from, to = value[1..-2].split(',')
+ {
+ from: (value[1] == ',' || from == '-infinity') ? infinity(:negative => true) : from,
+ to: (value[-2] == ',' || to == 'infinity') ? infinity : to,
+ exclude_start: (value[0] == '('),
+ exclude_end: (value[-1] == ')')
+ }
+ end
+
+ def infinity(options = {})
+ ::Float::INFINITY * (options[:negative] ? -1 : 1)
+ end
+
+ def infinity?(value)
+ value.respond_to?(:infinite?) && value.infinite?
+ end
+
+ def to_integer(value)
+ infinity?(value) ? value : value.to_i
+ end
+
+ def type_cast(value)
+ return if value.nil? || value == 'empty'
+ return value if value.is_a?(::Range)
+
+ extracted = exctract_bounds(value)
+
+ case @subtype
+ when :date
+ from = ConnectionAdapters::Column.value_to_date(extracted[:from])
+ from -= 1.day if extracted[:exclude_start]
+ to = ConnectionAdapters::Column.value_to_date(extracted[:to])
+ when :decimal
+ from = BigDecimal.new(extracted[:from].to_s)
+ # FIXME: add exclude start for ::Range, same for timestamp ranges
+ to = BigDecimal.new(extracted[:to].to_s)
+ when :time
+ from = ConnectionAdapters::Column.string_to_time(extracted[:from])
+ to = ConnectionAdapters::Column.string_to_time(extracted[:to])
+ when :integer
+ from = to_integer(extracted[:from]) rescue value ? 1 : 0
+ from -= 1 if extracted[:exclude_start]
+ to = to_integer(extracted[:to]) rescue value ? 1 : 0
+ else
+ return value
+ end
+
+ ::Range.new(from, to, extracted[:exclude_end])
+ end
+ end
+
class Integer < Type
def type_cast(value)
return if value.nil?
@@ -168,14 +226,6 @@ module ActiveRecord
end
end
- class IntRange < Type
- def type_cast(value)
- return if value.nil?
-
- ConnectionAdapters::PostgreSQLColumn.string_to_intrange value
- end
- end
-
class TypeMap
def initialize
@mapping = {}
@@ -241,6 +291,13 @@ module ActiveRecord
alias_type 'int8', 'int2'
alias_type 'oid', 'int2'
+ register_type 'daterange', OID::Range.new(:date)
+ register_type 'numrange', OID::Range.new(:decimal)
+ register_type 'tsrange', OID::Range.new(:time)
+ register_type 'int4range', OID::Range.new(:integer)
+ alias_type 'tstzrange', 'tsrange'
+ alias_type 'int8range', 'int4range'
+
register_type 'numeric', OID::Decimal.new
register_type 'text', OID::Identity.new
alias_type 'varchar', 'text'
@@ -278,9 +335,6 @@ module ActiveRecord
register_type 'json', OID::Json.new
register_type 'ltree', OID::Identity.new
- register_type 'int4range', OID::IntRange.new
- alias_type 'int8range', 'int4range'
-
register_type 'cidr', OID::Cidr.new
alias_type 'inet', 'cidr'
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index c2fcef94da..791b032023 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -19,6 +19,12 @@ module ActiveRecord
return super unless column
case value
+ when Range
+ if /range$/ =~ column.sql_type
+ "'#{PostgreSQLColumn.range_to_string(value)}'::#{column.sql_type}"
+ else
+ super
+ end
when Array
if column.array
"'#{PostgreSQLColumn.array_to_string(value, column, self)}'"
@@ -31,11 +37,6 @@ module ActiveRecord
when 'json' then super(PostgreSQLColumn.json_to_string(value), column)
else super
end
- when Range
- case column.sql_type
- when 'int4range', 'int8range' then super(PostgreSQLColumn.intrange_to_string(value), column)
- else super
- end
when IPAddr
case column.sql_type
when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
@@ -74,6 +75,9 @@ module ActiveRecord
return super(value, column) unless column
case value
+ when Range
+ return super(value, column) unless /range$/ =~ column.sql_type
+ PostgreSQLColumn.range_to_string(value)
when NilClass
if column.array && array_member
'NULL'
@@ -94,11 +98,6 @@ module ActiveRecord
when 'json' then PostgreSQLColumn.json_to_string(value)
else super(value, column)
end
- when Range
- case column.sql_type
- when 'int4range', 'int8range' then PostgreSQLColumn.intrange_to_string(value)
- else super(value, column)
- end
when IPAddr
return super(value, column) unless ['inet','cidr'].include? column.sql_type
PostgreSQLColumn.cidr_to_string(value)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index 8c68576bdc..73ca2c8e61 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -417,14 +417,6 @@ module ActiveRecord
when 0..6; "timestamp(#{precision})"
else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
end
- when 'intrange'
- return 'int4range' unless limit
-
- case limit
- when 1..4; 'int4range'
- when 5..8; 'int8range'
- else raise(ActiveRecordError, "No range type has byte size #{limit}. Use a numeric with precision 0 instead.")
- end
else
super
end