Ash.Query.filter creates filter with OR condition instead of AND

Ash.Query.filter function documentation explicitly says that a filter will be added with the AND condition, but it seems that this is not the case when fragments is used. For example, if I do this:
import Ash.Query

FeedbackCupcake.Feedbacks.Template
|> Ash.Query.new()
|> Ash.Query.for_read(:read, %{})
|> Ash.Query.filter(expr(name == "a"))
|> Ash.Query.filter(expr(fragment("? %> ?", "a", "a")))
import Ash.Query

FeedbackCupcake.Feedbacks.Template
|> Ash.Query.new()
|> Ash.Query.for_read(:read, %{})
|> Ash.Query.filter(expr(name == "a"))
|> Ash.Query.filter(expr(fragment("? %> ?", "a", "a")))
This will correctly generate the following query:
#Ash.Query<
resource: FeedbackCupcake.Feedbacks.Template,
filter: #Ash.Filter<name == "a" and fragment(
{:raw, ""},
{:expr, "a"},
{:raw, " %> "},
{:expr, "a"},
{:raw, ""}
)>
>
#Ash.Query<
resource: FeedbackCupcake.Feedbacks.Template,
filter: #Ash.Filter<name == "a" and fragment(
{:raw, ""},
{:expr, "a"},
{:raw, " %> "},
{:expr, "a"},
{:raw, ""}
)>
>
But, if I add another fragment to the condition, like this:
import Ash.Query

FeedbackCupcake.Feedbacks.Template
|> Ash.Query.new()
|> Ash.Query.for_read(:read, %{})
|> Ash.Query.filter(expr(name == "a"))
|> Ash.Query.filter(expr(fragment("? %> ?", "a", "a")))
|> Ash.Query.filter(expr(fragment("? %> ?", "b", "b")))
import Ash.Query

FeedbackCupcake.Feedbacks.Template
|> Ash.Query.new()
|> Ash.Query.for_read(:read, %{})
|> Ash.Query.filter(expr(name == "a"))
|> Ash.Query.filter(expr(fragment("? %> ?", "a", "a")))
|> Ash.Query.filter(expr(fragment("? %> ?", "b", "b")))
Now it concatenates the last fragment with a OR:
#Ash.Query<
resource: FeedbackCupcake.Feedbacks.Template,
filter: #Ash.Filter<(name == "a" and fragment(
{:raw, ""},
{:expr, "a"},
{:raw, " %> "},
{:expr, "a"},
{:raw, ""}
)) or fragment(
{:raw, ""},
{:expr, "b"},
{:raw, " %> "},
{:expr, "b"},
{:raw, ""}
)>
>
#Ash.Query<
resource: FeedbackCupcake.Feedbacks.Template,
filter: #Ash.Filter<(name == "a" and fragment(
{:raw, ""},
{:expr, "a"},
{:raw, " %> "},
{:expr, "a"},
{:raw, ""}
)) or fragment(
{:raw, ""},
{:expr, "b"},
{:raw, " %> "},
{:expr, "b"},
{:raw, ""}
)>
>
From what I tested, I only was able to reproduce this when adding more than one fragment to the query.
7 Replies
Blibs
BlibsOP2y ago
Just in case that helps, I did some digging and the issue happens when it reached this specific case condition in Ash.Query.BooleanExpression https://github.com/ash-project/ash/blob/7566de2f0e80630979909529d0106d6326db98db/lib/ash/query/boolean_expression.ex#L263
dblack
dblack2y ago
I recall having to wrap fragments in brackets under certain conditions, does doing expr(fragment("(? %> ?)", "a", "a")) help?
ZachDaniel
ZachDaniel2y ago
Yep, you should wrap fragments in parens when it could be ambiguous
Blibs
BlibsOP2y ago
Hmm, it still changes to or anyway:
import Ash.Query

FeedbackCupcake.Feedbacks.Template
|> Ash.Query.new()
|> Ash.Query.for_read(:read, %{})
|> Ash.Query.filter(expr(name == "a"))
|> Ash.Query.filter(expr(fragment("(? %> ?)", "a", "a")))
|> Ash.Query.filter(expr(fragment("(? %> ?)", "b", "b")))
import Ash.Query

FeedbackCupcake.Feedbacks.Template
|> Ash.Query.new()
|> Ash.Query.for_read(:read, %{})
|> Ash.Query.filter(expr(name == "a"))
|> Ash.Query.filter(expr(fragment("(? %> ?)", "a", "a")))
|> Ash.Query.filter(expr(fragment("(? %> ?)", "b", "b")))
Which still gives me or instead of and:
#Ash.Query<
resource: FeedbackCupcake.Feedbacks.Template,
filter: #Ash.Filter<(name == "a" and fragment(
{:raw, "("},
{:expr, "a"},
{:raw, " %> "},
{:expr, "a"},
{:raw, ")"}
)) or fragment(
{:raw, "("},
{:expr, "b"},
{:raw, " %> "},
{:expr, "b"},
{:raw, ")"}
)>
>
#Ash.Query<
resource: FeedbackCupcake.Feedbacks.Template,
filter: #Ash.Filter<(name == "a" and fragment(
{:raw, "("},
{:expr, "a"},
{:raw, " %> "},
{:expr, "a"},
{:raw, ")"}
)) or fragment(
{:raw, "("},
{:expr, "b"},
{:raw, " %> "},
{:expr, "b"},
{:raw, ")"}
)>
>
ZachDaniel
ZachDaniel2y ago
Can you update to the latest version of ash and try again?
Blibs
BlibsOP2y ago
you mean from main branch? I'm already in the latest version 2.13.4 I just tried using the main branch, working great there
ZachDaniel
ZachDaniel2y ago
For some reason CI didn’t release 2.14.0 I’ll release it when I get home Okay I was able to do it from my phone so a release should be building now

Did you find this page helpful?