Skip to content

Commit 42ed16a

Browse files
kamipojeremy
authored andcommitted
Schema dumping support for PostgreSQL interval type
Closes rails#27979
1 parent bb45fa0 commit 42ed16a

File tree

8 files changed

+36
-21
lines changed

8 files changed

+36
-21
lines changed

activerecord/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* PostgreSQL: schema dumping support for PostgreSQL interval type.
2+
3+
*Ryuta Kamizono*
4+
15
* Deprecate `supports_primary_key?` on connection adapters since it's
26
been long unused and unsupported.
37

activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,7 @@ def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) # :nodoc:
10701070
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
10711071
end
10721072

1073-
elsif [:datetime, :time].include?(type) && precision ||= native[:precision]
1073+
elsif [:datetime, :time, :interval].include?(type) && precision ||= native[:precision]
10741074
if (0..6) === precision
10751075
column_type_sql << "(#{precision})"
10761076
else

activerecord/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ module OID # :nodoc:
55
class SpecializedString < Type::String # :nodoc:
66
attr_reader :type
77

8-
def initialize(type)
8+
def initialize(type, **options)
99
@type = type
10+
super(options)
1011
end
1112
end
1213
end

activerecord/lib/active_record/connection_adapters/postgresql/schema_definitions.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ def inet(*args, **options)
8888
args.each { |name| column(name, :inet, options) }
8989
end
9090

91+
def interval(*args, **options)
92+
args.each { |name| column(name, :interval, options) }
93+
end
94+
9195
def int4range(*args, **options)
9296
args.each { |name| column(name, :int4range, options) }
9397
end

activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class PostgreSQLAdapter < AbstractAdapter
109109
bit: { name: "bit" },
110110
bit_varying: { name: "bit varying" },
111111
money: { name: "money" },
112+
interval: { name: "interval" },
112113
}
113114

114115
OID = PostgreSQL::OID #:nodoc:
@@ -486,8 +487,10 @@ def initialize_type_map(m)
486487
m.register_type "polygon", OID::SpecializedString.new(:polygon)
487488
m.register_type "circle", OID::SpecializedString.new(:circle)
488489

489-
# FIXME: why are we keeping these types as strings?
490-
m.alias_type "interval", "varchar"
490+
m.register_type "interval" do |_, _, sql_type|
491+
precision = extract_precision(sql_type)
492+
OID::SpecializedString.new(:interval, precision: precision)
493+
end
491494

492495
register_class_with_precision m, "time", Type::Time
493496
register_class_with_precision m, "timestamp", OID::DateTime

activerecord/test/cases/adapters/postgresql/datatype_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def setup
2828
end
2929

3030
def test_data_type_of_time_types
31-
assert_equal :string, @first_time.column_for_attribute(:time_interval).type
32-
assert_equal :string, @first_time.column_for_attribute(:scaled_time_interval).type
31+
assert_equal :interval, @first_time.column_for_attribute(:time_interval).type
32+
assert_equal :interval, @first_time.column_for_attribute(:scaled_time_interval).type
3333
end
3434

3535
def test_data_type_of_oid_types

activerecord/test/cases/schema_dumper_test.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,25 +261,31 @@ def test_schema_dump_includes_decimal_options
261261

262262
if current_adapter?(:PostgreSQLAdapter)
263263
def test_schema_dump_includes_bigint_default
264-
output = standard_dump
264+
output = dump_table_schema "defaults"
265265
assert_match %r{t\.bigint\s+"bigint_default",\s+default: 0}, output
266266
end
267267

268268
def test_schema_dump_includes_limit_on_array_type
269-
output = standard_dump
269+
output = dump_table_schema "bigint_array"
270270
assert_match %r{t\.bigint\s+"big_int_data_points\",\s+array: true}, output
271271
end
272272

273273
def test_schema_dump_allows_array_of_decimal_defaults
274-
output = standard_dump
274+
output = dump_table_schema "bigint_array"
275275
assert_match %r{t\.decimal\s+"decimal_array_default",\s+default: \["1.23", "3.45"\],\s+array: true}, output
276276
end
277277

278278
def test_schema_dump_expression_indices
279-
index_definition = standard_dump.split(/\n/).grep(/t\.index.*company_expression_index/).first.strip
279+
index_definition = dump_table_schema("companies").split(/\n/).grep(/t\.index.*company_expression_index/).first.strip
280280
assert_equal 't.index "lower((name)::text)", name: "company_expression_index", using: :btree', index_definition
281281
end
282282

283+
def test_schema_dump_interval_type
284+
output = dump_table_schema "postgresql_times"
285+
assert_match %r{t\.interval\s+"time_interval"$}, output
286+
assert_match %r{t\.interval\s+"scaled_time_interval",\s+precision: 6$}, output
287+
end
288+
283289
if ActiveRecord::Base.connection.supports_extensions?
284290
def test_schema_dump_includes_extensions
285291
connection = ActiveRecord::Base.connection

activerecord/test/schema/postgresql_specific_schema.rb

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,17 @@
2323
t.string :char2, limit: 50, default: "a varchar field"
2424
t.text :char3, default: "a text field"
2525
t.bigint :bigint_default, default: -> { "0::bigint" }
26-
t.text :multiline_default, default: '--- []
26+
t.text :multiline_default, default: "--- []
2727
28-
'
28+
"
2929
end
3030

31-
%w(postgresql_times postgresql_oids postgresql_timestamp_with_zones
31+
create_table :postgresql_times, force: true do |t|
32+
t.interval :time_interval
33+
t.interval :scaled_time_interval, precision: 6
34+
end
35+
36+
%w(postgresql_oids postgresql_timestamp_with_zones
3237
postgresql_partitioned_table postgresql_partitioned_table_parent).each do |table_name|
3338
drop_table table_name, if_exists: true
3439
end
@@ -44,14 +49,6 @@
4449
execute "SELECT setval('#{seq_name}', 100)"
4550
end
4651

47-
execute <<_SQL
48-
CREATE TABLE postgresql_times (
49-
id SERIAL PRIMARY KEY,
50-
time_interval INTERVAL,
51-
scaled_time_interval INTERVAL(6)
52-
);
53-
_SQL
54-
5552
execute <<_SQL
5653
CREATE TABLE postgresql_oids (
5754
id SERIAL PRIMARY KEY,

0 commit comments

Comments
 (0)