在AREL中分组手和手

  • 本文关键字:AREL sql ruby arel
  • 更新时间 :
  • 英文 :


我正在尝试使用arel:

查询此sql片段的等效内容。
WHERE (("participants"."accepted" = 'f' AND "participants"."contact_id" = 1) 
  OR "participants"."id" IS NULL)

我想要(accepted && contact_id=1) OR NULL

这是我在AREL中得到的

participants[:accepted].eq(false).and(participants[:contact_id].eq(1).
  or(participants[:id].is(nil)

问题是,这会产生:

("participants"."accepted" = 'f' AND "participants"."contact_id" = 1 OR "participants"."id" IS NULL)

注意我的和条件周围没有括号。我相信根据运算符优先级,我得到:

accepted && (contact_id=1 OR NULL)

在AREL查询中添加括号没有影响。任何想法吗?

您可以使用Arel::Nodes::Grouping生成括号。

participants = Arel::Table.new("participants")
arel = participants.grouping(
  participants[:accepted].eq(false).and(participants[:contact_id].eq(1))
).or(participants[:id].eq(nil))
arel.to_sql # => (("participants"."accepted" = 'f' AND "participants"."contact_id" = 1) OR "participants"."id" IS NULL)

我认为根据运算符优先级

问题是AND的优先级高于OR。因此1 AND 2 OR 3等于(1 AND 2) OR 3

作为旁注:如果您使用像这样的包装器,您可以这样写:

User.where((User[:created_at] > 3.days.ago) & (User[:enabled] == true))

为什么不把它们翻过来呢?应该相当于:

participants[:id].is(nil).or(participants[:accepted].eq(false).and(participants[:contact_id].eq(1))

希望我在上面正确地设置了父元素,但是你明白我的意思了…

这里有一个方法,允许您在代码中使用现有的AR方法,例如where和任何现有的作用域等。因此,如果需要,可以很容易地在Arel中重用现有的AR代码。

class Participant
  scope :grouped, -> {
    group1 = arel_table.grouping(where(accepted: false, contact_id: 1)).arel.constraints
    group2 = arel_table.grouping(where(id: nil).arel.constraints
    where(group1.or(group2))
  }
end

这可以在Rails 7中工作,也许在Rails 6中也可以。

相关内容

  • 没有找到相关文章

最新更新