Skip to content

Commit 5a26648

Browse files
Merge pull request rails#42297 from robertomiranda/r/default-precision-datime
Set precision 6 by default for datetime columns
2 parents 6ae78e9 + c2a6f61 commit 5a26648

File tree

11 files changed

+100
-17
lines changed

11 files changed

+100
-17
lines changed

activerecord/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Set precision 6 by default for `datetime` columns
2+
3+
By default, datetime columns will have microseconds precision instead of seconds precision.
4+
5+
*Roberto Miranda*
6+
17
* Allow preloading of associations with instance dependent scopes
28

39
*John Hawthorn*, *John Crepezzi*, *Adam Hess*, *Eileen M. Uchitelle*, *Dinah Shi*

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,12 @@ def column(name, type, index: nil, **options)
411411
end
412412
end
413413

414+
if @conn.supports_datetime_with_precision?
415+
if type == :datetime && !options.key?(:precision)
416+
options[:precision] = 6
417+
end
418+
end
419+
414420
@columns_hash[name] = new_column_definition(name, type, **options)
415421

416422
if index

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,12 @@ def drop_table(table_name, **options)
613613
def add_column(table_name, column_name, type, **options)
614614
return if options[:if_not_exists] == true && column_exists?(table_name, column_name)
615615

616+
if supports_datetime_with_precision?
617+
if type == :datetime && !options.key?(:precision)
618+
options[:precision] = 6
619+
end
620+
end
621+
616622
at = create_alter_table table_name
617623
at.add_column(column_name, type, **options)
618624
execute schema_creation.accept at

activerecord/lib/active_record/migration/compatibility.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,11 @@ def timestamps(**options)
295295
options[:null] = true if options[:null].nil?
296296
super
297297
end
298+
299+
def column(name, type, index: nil, **options)
300+
options[:precision] ||= nil
301+
super
302+
end
298303
end
299304

300305
def add_reference(table_name, ref_name, **options)
@@ -324,6 +329,14 @@ def remove_index(table_name, column_name = nil, **options)
324329
super
325330
end
326331

332+
def add_column(table_name, column_name, type, **options)
333+
if type == :datetime
334+
options[:precision] ||= nil
335+
end
336+
337+
super
338+
end
339+
327340
private
328341
def compatible_table_definition(t)
329342
class << t

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def test_adds_column_as_custom_type
125125

126126
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:datetimes_as_enum] = { name: "custom_time_format" }
127127
with_postgresql_datetime_type(:datetimes_as_enum) do
128-
ActiveRecord::Migration.new.add_column :postgresql_timestamp_with_zones, :times, :datetime
128+
ActiveRecord::Migration.new.add_column :postgresql_timestamp_with_zones, :times, :datetime, precision: nil
129129

130130
assert_equal({ "data_type" => "USER-DEFINED", "udt_name" => "custom_time_format" },
131131
PostgresqlTimestampWithZone.connection.execute("select data_type, udt_name from information_schema.columns where column_name = 'times'").to_a.first)

activerecord/test/cases/date_time_precision_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ def test_datetime_precision_is_truncated_on_assignment
4848
unless current_adapter?(:Mysql2Adapter)
4949
def test_no_datetime_precision_isnt_truncated_on_assignment
5050
@connection.create_table(:foos, force: true)
51-
@connection.add_column :foos, :created_at, :datetime
52-
@connection.add_column :foos, :updated_at, :datetime, precision: 6
51+
@connection.add_column :foos, :created_at, :datetime, precision: nil
52+
@connection.add_column :foos, :updated_at, :datetime
5353

5454
time = ::Time.now.change(nsec: 123)
5555
foo = Foo.new(created_at: time, updated_at: time)

activerecord/test/cases/defaults_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ class PostgresqlDefaultExpressionTest < ActiveRecord::TestCase
9191
output = dump_table_schema("defaults")
9292
if ActiveRecord::Base.connection.database_version >= 100000
9393
assert_match %r/t\.date\s+"modified_date",\s+default: -> { "CURRENT_DATE" }/, output
94-
assert_match %r/t\.datetime\s+"modified_time",\s+default: -> { "CURRENT_TIMESTAMP" }/, output
94+
assert_match %r/t\.datetime\s+"modified_time",\s+precision: 6,\s+default: -> { "CURRENT_TIMESTAMP" }/, output
9595
else
9696
assert_match %r/t\.date\s+"modified_date",\s+default: -> { "\('now'::text\)::date" }/, output
97-
assert_match %r/t\.datetime\s+"modified_time",\s+default: -> { "now\(\)" }/, output
97+
assert_match %r/t\.datetime\s+"modified_time",\s+precision: 6,\s+default: -> { "now\(\)" }/, output
9898
end
9999
assert_match %r/t\.date\s+"modified_date_function",\s+default: -> { "now\(\)" }/, output
100-
assert_match %r/t\.datetime\s+"modified_time_function",\s+default: -> { "now\(\)" }/, output
100+
assert_match %r/t\.datetime\s+"modified_time_function",\s+precision: 6,\s+default: -> { "now\(\)" }/, output
101101
end
102102
end
103103
end

activerecord/test/cases/migration/change_schema_test.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,11 @@ def test_add_column_with_postgresql_datetime_type
300300
assert_equal :datetime, column.type
301301

302302
if current_adapter?(:PostgreSQLAdapter)
303-
assert_equal "timestamp without time zone", column.sql_type
303+
assert_equal "timestamp(6) without time zone", column.sql_type
304304
elsif current_adapter?(:Mysql2Adapter)
305-
assert_equal "datetime", column.sql_type
305+
assert_equal "datetime(6)", column.sql_type
306306
else
307-
assert_equal connection.type_to_sql("datetime"), column.sql_type
307+
assert_equal connection.type_to_sql("datetime(6)"), column.sql_type
308308
end
309309
end
310310

@@ -318,7 +318,7 @@ def test_add_column_with_datetime_in_timestamptz_mode
318318
column = connection.columns(:testings).find { |c| c.name == "foo" }
319319

320320
assert_equal :datetime, column.type
321-
assert_equal "timestamp with time zone", column.sql_type
321+
assert_equal "timestamp(6) with time zone", column.sql_type
322322
end
323323
end
324324
end
@@ -341,7 +341,7 @@ def test_change_column_with_timestamp_type
341341
elsif current_adapter?(:OracleAdapter)
342342
assert_equal "TIMESTAMP(6)", column.sql_type
343343
else
344-
assert_equal connection.type_to_sql("datetime"), column.sql_type
344+
assert_equal connection.type_to_sql("datetime(6)"), column.sql_type
345345
end
346346
end
347347

activerecord/test/cases/migration/compatibility_test.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,58 @@ def migrate(x)
335335
assert connection.index_exists?(:testings, [:gizmo_type, :gizmo_id], name: :index_testings_on_gizmo_type_and_gizmo_id)
336336
end
337337

338+
def test_datetime_doesnt_set_precision_on_create_table
339+
migration = Class.new(ActiveRecord::Migration[4.2]) {
340+
def migrate(x)
341+
create_table :more_testings do |t|
342+
t.datetime :published_at
343+
end
344+
end
345+
}.new
346+
347+
ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
348+
349+
assert connection.column_exists?(:more_testings, :published_at, **precision_implicit_default)
350+
ensure
351+
connection.drop_table :more_testings rescue nil
352+
end
353+
354+
def test_datetime_doesnt_set_precision_on_change_table
355+
create_migration = Class.new(ActiveRecord::Migration[4.2]) {
356+
def migrate(x)
357+
create_table :more_testings do |t|
358+
t.datetime :published_at
359+
end
360+
end
361+
}.new
362+
363+
change_migration = Class.new(ActiveRecord::Migration[4.2]) {
364+
def migrate(x)
365+
change_table :more_testings do |t|
366+
t.datetime :published_at, default: Time.now
367+
end
368+
end
369+
}.new
370+
371+
ActiveRecord::Migrator.new(:up, [create_migration, change_migration], @schema_migration).migrate
372+
373+
assert connection.column_exists?(:more_testings, :published_at, **precision_implicit_default)
374+
ensure
375+
connection.drop_table :more_testings rescue nil
376+
end
377+
378+
def test_datetime_doesnt_set_precision_on_add_column
379+
migration = Class.new(ActiveRecord::Migration[4.2]) {
380+
def migrate(x)
381+
add_column :testings, :published_at, :datetime, default: Time.now
382+
end
383+
}.new
384+
385+
ActiveRecord::Migrator.new(:up, [migration], @schema_migration).migrate
386+
387+
assert connection.column_exists?(:testings, :published_at, **precision_implicit_default)
388+
end
389+
338390
private
339391
def precision_implicit_default
340392
if current_adapter?(:Mysql2Adapter)

activerecord/test/cases/schema_dumper_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ def test_schema_dump_defaults_with_universally_supported_types
837837

838838
assert_match %r{t\.string\s+"string_with_default",.*?default: "Hello!"}, output
839839
assert_match %r{t\.date\s+"date_with_default",\s+default: "2014-06-05"}, output
840-
assert_match %r{t\.datetime\s+"datetime_with_default",\s+default: "2014-06-05 07:17:04"}, output
840+
assert_match %r{t\.datetime\s+"datetime_with_default",\s+precision: 6,\s+default: "2014-06-05 07:17:04"}, output
841841
assert_match %r{t\.time\s+"time_with_default",\s+default: "2000-01-01 07:17:04"}, output
842842
assert_match %r{t\.decimal\s+"decimal_with_default",\s+precision: 20,\s+scale: 10,\s+default: "1234567890.0123456789"}, output
843843
end
@@ -847,8 +847,8 @@ def test_schema_dump_with_column_infinity_default
847847
output = dump_table_schema("infinity_defaults")
848848
assert_match %r{t\.float\s+"float_with_inf_default",\s+default: ::Float::INFINITY}, output
849849
assert_match %r{t\.float\s+"float_with_nan_default",\s+default: ::Float::NAN}, output
850-
assert_match %r{t\.datetime\s+"beginning_of_time",\s+default: -::Float::INFINITY}, output
851-
assert_match %r{t\.datetime\s+"end_of_time",\s+default: ::Float::INFINITY}, output
850+
assert_match %r{t\.datetime\s+"beginning_of_time",\s+precision: 6,\s+default: -::Float::INFINITY}, output
851+
assert_match %r{t\.datetime\s+"end_of_time",\s+precision: 6,\s+default: ::Float::INFINITY}, output
852852
assert_match %r{t\.date\s+"date_with_neg_inf_default",\s+default: -::Float::INFINITY}, output
853853
assert_match %r{t\.date\s+"date_with_pos_inf_default",\s+default: ::Float::INFINITY}, output
854854
end

0 commit comments

Comments
 (0)