【问题标题】:SQL column type from Arel::Attributes::Attribute object来自 Arel::Attributes::Attribute 对象的 SQL 列类型
【发布时间】:2013-02-03 04:50:43
【问题描述】:
tl;dr 给定一个Arel::Attributes::Attribue 对象,比如Model.arel_table[:created_at] 如何获得它的SQL 类型?
背景:我正在绕过 ActiveRecord 基础架构,转而支持 Arel 编写一些需要真正高效生成的 SQL 报告。使用 Arel 的 to_sql 方法,我正在生成最终的 SQL 并通过 ActiveRecord::Base.connection.execute 直接执行它。但是,我需要将 SQL 转换应用于某些列(例如,更改存储在 GMT 中的时间戳的时区)。由于列数很大(并且根据用户输入而变化),我不想对这些转换进行硬编码。我想查看所选列的 SQL 类型并相应地应用转换。
【问题讨论】:
标签:
ruby
activerecord
arel
rails-activerecord
【解决方案1】:
如果您设置了 ActiveRecord 类,那么您可以访问其 columns 和 columns_hash 方法。这些将为您提供列对象(ActiveRecord::ConnectionAdapters::Column 的实例),您应该在那里找到type 和sql_type 方法。例如:
> Model.columns_hash['created_at'].type
=> :datetime
> Model.columns_hash['created_at'].sql_type
=> "timestamp without time zone"
sql_type 将是特定于数据库的(即上面的 PostgreSQL),type 将匹配您迁移中的类型,因此您可能希望使用它而不是 sql_type。
也就是说,您可能可以不使用通常的 ActiveRecord 关系方法(它应该为您处理转换和时区),然后在最后调用 to_sql:
sql = Model.where('created_at > ?', some_time).select('pancakes').to_sql
然后将该 SQL 提供给 execute 或 select_rows。这将使您可以使用大部分常用的 ActiveRecord 东西,同时避免创建一堆您不关心的 ActiveRecord 包装器的开销。
【解决方案2】:
type_cast_for_database 可能对 arel 有帮助。这可以在 arel 表上使用:
Model.arel_table.type_cast_for_database(:id, 'test')
=> 0
Model.arel_table.type_cast_for_database(:id, '47test')
=> 47
虽然您没有具体了解类型,但您可以查看字符串之类的值是否会转换为数字或其他内容。
编辑
请务必注意,这仅在 arel 表具有 type_caster able_to_type_cast? 时才有效。如果你从上面的模型中得到它,它应该有一个类型脚轮。