【问题标题】:Is it possible to emit PostgreSQL style type cast in Arel instead of doing it with Ruby in Type::Value descendant?是否可以在 Arel 中发出 PostgreSQL 样式类型转换,而不是在 Type::Value 后代中使用 Ruby 进行转换?
【发布时间】:2020-06-23 22:48:26
【问题描述】:

我想在 PostgreSQL 数据库中使用 regclass 类型的列。显然 Rails 不知道这种类型,因为我得到了unknown OID 2205: failed to recognize type of 'relname'. It will be treated as String.。将其视为字符串可以读取,但是在尝试将内容存储回数据库时会出现问题。

据我了解,通常定义一个 Type::Value 类的后代来执行来回转换。这个转换有点麻烦,因为通常在 SQL 中使用'some_table'::regclass。在 Ruby 中这样做会导致另一个数据库往返。

是否可以让 Arel(?) 在最终的 SQL 语句中发出这样的构造?因此,如果我执行Something.find(relname: 'some_table'),它会发出... WHERE "relname" = $1 :: regclass,也就是说,如果我提供了一个字符串类型的对象,它会在PostgreSQL 端使用强制转换。或者更好的是WHERE "relname"::text = $1

我知道我可以做到where("relname::text=?", 'some_table')。但是,如果我使用#first_or_create!,我必须明确指定这个。我很好奇它是否可以更加无缝。

【问题讨论】:

    标签: rails-activerecord arel


    【解决方案1】:

    使用 Arel 实现此目的的一种潜在方法是生成 CAST 函数。

    # Replace `Model` with your ActiveRecord model
    
    def relname_as_text
      Arel::Nodes::NamedFunction.new(
        'CAST',
        [
          Arel::Nodes::As.new(
            Model.arel_table[:relname],
            Arel::Nodes::SqlLiteral.new('text')
          ),
        ]
      )
    end
    
    Model.where(relname_as_text.eq('some_table'))
    

    【讨论】:

    • 我收到了NoMethodError: undefined method 'relation' for #<Arel::Nodes::NamedFunction:0x00007fffd665dfc8>。我有Model.where(...).where(relname_as_text.eq('some_table')).first_or_create! do |m|
    • Model.where(relname_as_text.eq('some_table')).to_sql 的输出是什么?
    • #to_sql 产生合理的输出,实际上它适用于搜索!然而,这个错误只出现在#first_or_create :( 也许 Arel 试图为该函数计算反转?是否可以指示 Arel 为此类列自动转换字符串,以便可以使用普通的 where(relname: 'some_table')
    猜你喜欢
    • 2010-09-27
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 2018-04-04
    • 2011-04-01
    • 1970-01-01
    • 2013-05-29
    • 2015-04-01
    相关资源
    最近更新 更多