Ecto shorter notation and using is_nil/1

Suppose I have a query where(Entry, [e], e.some_id == ^some_id).
I could write as where(Entry, [some_id: ^some_id].
I like this shorter variation but I can’t figure out how to use is_nil in that notation.
So is it possible to write something like this:

where(Entry, [e], e.some_id == ^some_id and is_nil(e.some_value))

in shorter notation?
Tried a few things, one attempt was:

where(Entry, [some_id: ^some_id, some_value: ^nil])

but ecto doesn’t allow passing nil’s around.
I feel it’s not possible, maybe it could be, but also I have a hunch that maybe it shouldn’t be :sweat_smile:. Could somebody shed some light on this? Maybe some docs about this shorter way (if any, I searched, did not find anything).

Can’t you chain two where-s one after another?

Sure, I could do

Entry
|> where([some_id: ^some_id])
|> where([e], is_nil(e.some_value)

I suppose but that’s combining two notations - don’t like. I mean it’s fine, not a big deal, just curious about this.

Admittedly I never cared for such aesthetics so can’t help you with your original question I am afraid.

Yeah, it shouldn’t be because otherwise it becomes a security issue (i.e. imagine you are expecting an api token parameter, someone sets it to nil, and now you log as the first user without a token).

1 Like

Yeah, and all the NULL != NULL based things one can run into.

I assume you’re talking about my specific example of interpolating a nil value, I understand it’s a security issue. But using is_nil in a query is fine.
I’m just curious can it be written in shorter notation?
Here’s another example. So
where(Entry, [e], e.some_id == ^some_id and is_nil(e.some_value))
in shorter notation I imagine it would be:
where(Entry, [some_id: ^some_id, is_nil(:some_value)])
or since keyword list are list of tuples maybe:
where(Entry, [{:some_id, ^some_id}, {is_nil(:some_value), true}])
Admittedly, this one looks uglier than with longer notation.
So it seems to me that the shorter way is only for matching multiple values with ‘and’ operator and does not support passing functions or anything more than that, correct?

Afaik where/2 expects a bog standard keyword lists as input, unlike where/3, which is a macro with “custom” syntax all the way.

3 Likes

There is precedent in Filtering associations in the schema Ecto.Schema — Ecto v3.10.3

One could write:

has_one :api_key, APIKey, where: [expired_at: nil]

And use Repo.prelaod(@current_user, [:api_key])

1 Like

Yeah, I was just explaining why we don’t do it automatically. You have to use the query syntax.

Correct. But that happens at compile-time, so there is no chance of passing user-input through it and opening your application to a security vulnerability. :slight_smile:

1 Like