Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grouping ands and ors in AREL

Tags:

sql

ruby

arel

I'm trying to query the equivalent of this sql snippet using arel:

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

So I want (accepted && contact_id=1) OR NULL

Here's what I've got in AREL

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

Problem is, this generates:

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

Note the lack of parentheses around my and conditions. I believe that according to the operator precedence, that I'm getting:

accepted && (contact_id=1 OR NULL)

Adding parentheses in in the AREL query has no affect. Any thoughts?

like image 307
brad Avatar asked Nov 10 '11 16:11

brad


3 Answers

I believe that according to the operator precedence

The problem is that AND has higher precedence than OR. So 1 AND 2 OR 3 is equivalent to (1 AND 2) OR 3.

As a side note: if you use a wrapper like this one, you can write:

User.where((User[:created_at] > 3.days.ago) & (User[:enabled] == true))
like image 147
tokland Avatar answered Nov 07 '22 00:11

tokland


You can generate parentheses using 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)
like image 40
Brian Hahn Avatar answered Nov 07 '22 02:11

Brian Hahn


Why not flip them around. Should be equivalent to:

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

hopefully I've got the parens properly set in the above, but you see what I mean...

like image 2
Taryn East Avatar answered Nov 07 '22 00:11

Taryn East