1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Allow precision option for postgresql datetimes

This patch addresses the difficulty of retrieving datetime fields. By default, the database holds a higher precision than the time as a String.

This issue is discussed at length at the following links:
- [#3519](https://github.com/rails/rails/issues/3519)
- [#3520](https://github.com/rails/rails/issues/3520)

Also, kudos to @mattscilipoti
This commit is contained in:
Tony Schneider 2012-06-21 17:40:54 -04:00
parent a232831f2d
commit 6657ec9a0a
3 changed files with 87 additions and 0 deletions

View file

@ -1,5 +1,17 @@
## Rails 4.0.0 (unreleased) ## ## Rails 4.0.0 (unreleased) ##
* Added support for specifying the precision of a timestamp in the postgresql
adapter. So, instead of having to incorrectly specify the precision using the
`:limit` option, you may use `:precision`, as intended. For example, in a migration:
def change
create_table :foobars do |t|
t.timestamps :precision => 0
end
end
*Tony Schneider*
* Allow ActiveRecord::Relation#pluck to accept multiple columns. Returns an * Allow ActiveRecord::Relation#pluck to accept multiple columns. Returns an
array of arrays containing the typecasted values: array of arrays containing the typecasted values:

View file

@ -187,6 +187,7 @@ module ActiveRecord
case sql_type case sql_type
when /^bigint/i; 8 when /^bigint/i; 8
when /^smallint/i; 2 when /^smallint/i; 2
when /^timestamp/i; nil
else super else super
end end
end end
@ -201,6 +202,8 @@ module ActiveRecord
def extract_precision(sql_type) def extract_precision(sql_type)
if sql_type == 'money' if sql_type == 'money'
self.class.money_precision self.class.money_precision
elsif sql_type =~ /timestamp/i
$1.to_i if sql_type =~ /\((\d+)\)/
else else
super super
end end
@ -1285,6 +1288,13 @@ module ActiveRecord
when 5..8; 'bigint' when 5..8; 'bigint'
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.") else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
end end
when 'datetime'
return super unless precision
case precision
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
else else
super super
end end

View file

@ -27,4 +27,69 @@ class TimestampTest < ActiveRecord::TestCase
d = Developer.create!(:name => 'aaron', :updated_at => -1.0 / 0.0) d = Developer.create!(:name => 'aaron', :updated_at => -1.0 / 0.0)
assert_equal(-1.0 / 0.0, d.updated_at) assert_equal(-1.0 / 0.0, d.updated_at)
end end
def test_default_datetime_precision
ActiveRecord::Base.connection.create_table(:foos)
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_timestamp_data_type_with_precision
ActiveRecord::Base.connection.create_table(:foos)
ActiveRecord::Base.connection.add_column :foos, :created_at, :datetime, :precision => 0
ActiveRecord::Base.connection.add_column :foos, :updated_at, :datetime, :precision => 5
assert_equal 0, 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) do |t|
t.timestamps :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_timestamp_does_not_set_limit
ActiveRecord::Base.connection.create_table(:foos) do |t|
t.timestamps :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_timestamp_precision_raises_error
assert_raises ActiveRecord::ActiveRecordError do
ActiveRecord::Base.connection.create_table(:foos) do |t|
t.timestamps :precision => 7
end
end
end
def test_postgres_agrees_with_activerecord_about_precision
ActiveRecord::Base.connection.create_table(:foos) do |t|
t.timestamps :precision => 4
end
assert_equal '4', pg_datetime_precision('foos', 'created_at')
assert_equal '4', pg_datetime_precision('foos', 'updated_at')
end
private
def pg_datetime_precision(table_name, column_name)
results = ActiveRecord::Base.connection.execute("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