-
Notifications
You must be signed in to change notification settings - Fork 21.9k
Closed
Labels
Description
Steps to reproduce
When two predicates A and B are given to a where
clause, Rails combines them using AND
, which is the expected behavior.
Model.where(col1: 1, col2: 2).to_sql
# => SELECT "models".* FROM "models" WHERE "models"."col1" = 1 AND "models"."col2" = 2
When the clause is negated (using where.not
), Rails distributes the NOT
to every predicate before combining them using AND
. Why?
Model.where.not(col1: 1, col2: 2).to_sql
# => SELECT "models".* FROM "models" WHERE ("models"."col1" != 1) AND ("models"."col2" != 2)
Expected behavior
NOT(A AND B)
= NOT(A) OR NOT(B)
In my example, the query should look like:
SELECT "models".* FROM "models" WHERE ("models"."col1" != 1) OR ("models"."col2" != 2)
Actual behavior
NOT(A AND B)
= NOT(A) AND NOT(B)
(wrong)
It's worth noting that the correct behavior can still be obtained by writing SQL directly:
Model.where.not('"models"."col1" = 1 AND "models"."col2" = 2').to_sql
# => SELECT "models".* FROM "models" WHERE (NOT ("models"."col1" = 1 AND "models"."col2" = 2))
It makes the construct where.not(...)
behave very differently depending on the kind of arguments which are passed to it.
The culprit seems to be located here :
WhereClause.new(inverted_predicates) |
System configuration
Rails version: 5.1.4
Ruby version: MRI 2.4.2
benoitjoseph, fterrazzoni, vmeyet, QuentinFchx, m16a1 and 6 morerhombl4, owen2345, feliperaul and elrosaantoinedc, adityakapoor-homebell and syabrukfterrazzoni and inopinatus