Allow precision option for MySQL datetimes.

This commit is contained in:
Ryuta Kamizono 2014-11-19 19:59:14 +09:00
parent b63382ec06
commit ae419af666
6 changed files with 164 additions and 1 deletions

@ -1,3 +1,7 @@
* Allow precision option for MySQL datetimes.
*Ryuta Kamizono*
* Fix `reaping_frequency` option when the value is a string.
This usually happens when it is configured using `DATABASE_URL`.

@ -591,6 +591,13 @@ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
when 0x1000000..0xffffffff; 'longtext'
else raise(ActiveRecordError, "No text type has character length #{limit}")
end
when 'datetime'
return super unless precision
case precision
when 0..6; "datetime(#{precision})"
else raise(ActiveRecordError, "No datetime type has precision of #{precision}. The allowed range of precision is from 0 to 6")
end
else
super
end
@ -679,6 +686,11 @@ def initialize_type_map(m) # :nodoc:
m.alias_type %r(year)i, 'integer'
m.alias_type %r(bit)i, 'binary'
m.register_type(%r(datetime)i) do |sql_type|
precision = extract_precision(sql_type)
Type::DateTime.new(precision: precision)
end
m.register_type(%r(enum)i) do |sql_type|
limit = sql_type[/^enum\((.+)\)/i, 1]
.split(',').map{|enum| enum.strip.length - 2}.max

@ -0,0 +1,70 @@
require 'cases/helper'
if mysql_56?
class DateTimeTest < ActiveRecord::TestCase
def test_default_datetime_precision
ActiveRecord::Base.connection.create_table(:foos, force: true)
ActiveRecord::Base.connection.add_column :foos, :created_at, :datetime
ActiveRecord::Base.connection.add_column :foos, :updated_at, :datetime
assert_nil activerecord_column_option('foos', 'created_at', 'precision')
end
def test_datetime_data_type_with_precision
ActiveRecord::Base.connection.create_table(:foos, force: true)
ActiveRecord::Base.connection.add_column :foos, :created_at, :datetime, precision: 1
ActiveRecord::Base.connection.add_column :foos, :updated_at, :datetime, precision: 5
assert_equal 1, activerecord_column_option('foos', 'created_at', 'precision')
assert_equal 5, activerecord_column_option('foos', 'updated_at', 'precision')
end
def test_timestamps_helper_with_custom_precision
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 4
end
assert_equal 4, activerecord_column_option('foos', 'created_at', 'precision')
assert_equal 4, activerecord_column_option('foos', 'updated_at', 'precision')
end
def test_passing_precision_to_datetime_does_not_set_limit
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 4
end
assert_nil activerecord_column_option('foos', 'created_at', 'limit')
assert_nil activerecord_column_option('foos', 'updated_at', 'limit')
end
def test_invalid_datetime_precision_raises_error
assert_raises ActiveRecord::ActiveRecordError do
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 7
end
end
end
def test_mysql_agrees_with_activerecord_about_precision
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 4
end
assert_equal 4, mysql_datetime_precision('foos', 'created_at')
assert_equal 4, mysql_datetime_precision('foos', 'updated_at')
end
private
def mysql_datetime_precision(table_name, column_name)
results = ActiveRecord::Base.connection.exec_query("SELECT column_name, datetime_precision FROM information_schema.columns WHERE table_name ='#{table_name}'")
result = results.find do |result_hash|
result_hash["column_name"] == column_name
end
result && result["datetime_precision"]
end
def activerecord_column_option(tablename, column_name, option)
result = ActiveRecord::Base.connection.columns(tablename).find do |column|
column.name == column_name
end
result && result.send(option)
end
end
end

@ -0,0 +1,70 @@
require 'cases/helper'
if mysql_56?
class DateTimeTest < ActiveRecord::TestCase
def test_default_datetime_precision
ActiveRecord::Base.connection.create_table(:foos, force: true)
ActiveRecord::Base.connection.add_column :foos, :created_at, :datetime
ActiveRecord::Base.connection.add_column :foos, :updated_at, :datetime
assert_nil activerecord_column_option('foos', 'created_at', 'precision')
end
def test_datetime_data_type_with_precision
ActiveRecord::Base.connection.create_table(:foos, force: true)
ActiveRecord::Base.connection.add_column :foos, :created_at, :datetime, precision: 1
ActiveRecord::Base.connection.add_column :foos, :updated_at, :datetime, precision: 5
assert_equal 1, activerecord_column_option('foos', 'created_at', 'precision')
assert_equal 5, activerecord_column_option('foos', 'updated_at', 'precision')
end
def test_timestamps_helper_with_custom_precision
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 4
end
assert_equal 4, activerecord_column_option('foos', 'created_at', 'precision')
assert_equal 4, activerecord_column_option('foos', 'updated_at', 'precision')
end
def test_passing_precision_to_datetime_does_not_set_limit
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 4
end
assert_nil activerecord_column_option('foos', 'created_at', 'limit')
assert_nil activerecord_column_option('foos', 'updated_at', 'limit')
end
def test_invalid_datetime_precision_raises_error
assert_raises ActiveRecord::ActiveRecordError do
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 7
end
end
end
def test_mysql_agrees_with_activerecord_about_precision
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.timestamps null: true, precision: 4
end
assert_equal 4, mysql_datetime_precision('foos', 'created_at')
assert_equal 4, mysql_datetime_precision('foos', 'updated_at')
end
private
def mysql_datetime_precision(table_name, column_name)
results = ActiveRecord::Base.connection.exec_query("SELECT column_name, datetime_precision FROM information_schema.columns WHERE table_name ='#{table_name}'")
result = results.find do |result_hash|
result_hash["column_name"] == column_name
end
result && result["datetime_precision"]
end
def activerecord_column_option(tablename, column_name, option)
result = ActiveRecord::Base.connection.columns(tablename).find do |column|
column.name == column_name
end
result && result.send(option)
end
end
end

@ -232,6 +232,13 @@ def test_schema_dumps_index_type
end
end
if mysql_56?
def test_schema_dump_includes_datetime_precision
output = standard_dump
assert_match %r{t.datetime\s+"written_on",\s+precision: 6$}, output
end
end
def test_schema_dump_includes_decimal_options
output = dump_all_table_schema([/^[^n]/])
assert_match %r{precision: 3,[[:space:]]+scale: 2,[[:space:]]+default: 2.78}, output

@ -726,7 +726,7 @@ def except(adapter_names_to_exclude)
t.string :author_name
t.string :author_email_address
if mysql_56?
t.datetime :written_on, limit: 6
t.datetime :written_on, precision: 6
else
t.datetime :written_on
end