Dear list
I am working with a legacy MySQL database which has dates stored as
UNIX timestamps. Ideally, I would like to have the dates converted to
proper Ruby objects when fetched from the database, and converted to
UNIX timestamps when saved to the database.
What would be the proper way to accomodate this?
Best regards
Christian
Dear list
I am working with a legacy MySQL database which has dates stored as
UNIX timestamps. Ideally, I would like to have the dates converted to
proper Ruby objects when fetched from the database, and converted to
UNIX timestamps when saved to the database.
What would be the proper way to accomodate this?
something like
def some_date
Time.at(self[:some_date])
end
def some_date= value
self[:some_date]= value.to_i
end
This provides only rudimentary support for UNIX timestamps in the
database.
For example, it breaks when I do:
named_scope :recent, lambda { { :conditions => ['date > ?',
1.month.ago] } }
The resulting condition on the database becomes:
WHERE (date > '2008-07-15 16:27:58')
...which is not the intention: I want the Ruby time converted to a
UNIX timestamp whenever used in the database. I suspect this needs to
be done on a deeper level, possibly by monkey patching MysqlAdapter
and MysqlColumn.
In [1] Raimonds Simanovskis has a modified Oracle ConnectionAdapter
which emulates booleans stored in the database as NUMBER(1). Also, he
catches field names ending in "name" and let's them
emulate :datetime.
I'd like to do the same with the MysqlAdapter, but I am not quite sure
what is the best way to do it.
I suppose I'd have to let MysqlColumn#simplified_type(field_type)
catch the integer fields I'd like to emulate :datetime.
But where do I perform the actual conversion? One options is to
override MysqlAdapter#select_rows – but it seems a little tedious.
Also, I need to hook in somewhere to perform the conversion the other
way – from Ruby times to UNIX timestamps in the database.
Any clues would be appreciated!
Best regards
Christian
[1] Some issues with Oracle views as ActiveRecord source
something like
def some_date
Time.at(self[:some_date])
end
def some_date= value
self[:some_date]= value.to_i
end
This provides only rudimentary support for UNIX timestamps in the
database.
For example, it breaks when I do:
named_scope :recent, lambda { { :conditions => ['date > ?',
1.month.ago] } }
The resulting condition on the database becomes:
WHERE (date > '2008-07-15 16:27:58')
I think you could do that by overriding the quote method on your
database adapter.
...which is not the intention: I want the Ruby time converted to a
UNIX timestamp whenever used in the database. I suspect this needs to
be done on a deeper level, possibly by monkey patching MysqlAdapter
and MysqlColumn.
In [1] Raimonds Simanovskis has a modified Oracle ConnectionAdapter
which emulates booleans stored in the database as NUMBER(1). Also, he
catches field names ending in "name" and let's them
emulate :datetime.
I'd like to do the same with the MysqlAdapter, but I am not quite sure
what is the best way to do it.
I suppose I'd have to let MysqlColumn#simplified_type(field_type)
catch the integer fields I'd like to emulate :datetime.
But where do I perform the actual conversion? One options is to
override MysqlAdapter#select_rows – but it seems a little tedious.
The conversion there happens in the type_cast method in
schema_definitions.rb
Fred
Indeed it does. Thank you!
Here's a quick implementation:
module ActiveRecord
module ConnectionAdapters
class MysqlColumn
def is_unix_timestamp?(name, field_type)
field_type.downcase.index("int") && name =~ /(^|_)date(_|$)/
end
def simplified_type_with_unix_timestamp(field_type)
if is_unix_timestamp?(name, field_type)
:datetime
else
simplified_type_without_unix_timestamp(field_type)
end
end
alias_method_chain :simplified_type, :unix_timestamp
def type_cast_with_unix_timestamp(value)
if is_unix_timestamp?(name, sql_type)
Time.at(value.to_i)
else
type_cast_without_unix_timestamp(value)
end
end
alias_method_chain :type_cast, :unix_timestamp
end
class MysqlAdapter
def quote_with_unix_timestamp(value, column = nil)
if value.kind_of?(Time)
value.to_i
else
quote_without_unix_timestamp(value, column)
end
end
alias_method_chain :quote, :unix_timestamp
end
end
end
All Ruby times are quoted as UNIX timestamps when quering the
database, and integer fields in the databse are converted to Ruby
times if they contain "date".
Christian