EctoFragmentExtras (ecto_fragment_extras v0.3.0)
EctoFragmentExtras
is a collection of macros to enhance Ecto fragments.
Instead of using Ectos fragment
with ?-based interpolation, this module
provides macros (that expand into regular Ecto fragments) which allow
named or inline params.
Summary
Functions
A variant of Ecto fragment() which supports params inlined in the query string or named params depending on the number of arguments.
A variant of Ecto fragment() which supports params inlined in the query string.
A variant of Ecto fragment() which supports named params.
Functions
A variant of Ecto fragment() which supports params inlined in the query string or named params depending on the number of arguments.
When called with only a query string, this macro behaves like inline_fragment/1
.
When called with a query string and a keyword list, this macro behaves like named_fragment/2
.
defmodule TestQuery do
import Ecto.Query
import EctoFragmentExtras
@default_name "Jane Doe"
def test_query_named do
query = from users in "users",
select: frag("coalesce(#{:a}, #{:b})", a: users.name, b: ^@default_name)
Repo.all(query)
end
def test_query_inline do
query = from users in "users",
select: frag("coalesce(#{users.name}, #{^@default_name})")
Repo.all(query)
end
end
A variant of Ecto fragment() which supports params inlined in the query string.
Inline params are provided within the fragment query string as
#{}
-style string interpolation. Since this is a macro which expands to a regular
Ecto fragment, those interpolations are safe (they are no real string interpolations,
and pose no extra SQL injection risk compared to regular fragments).
So inline_fragment("coalesce(#{user.name}, #{^default})")
will
be expanded to fragment("coalesce(?, ?)", user.name, ^default)
at compile-time.
defmodule TestQuery do
import Ecto.Query
import EctoFragmentExtras
def test_query do
default = "Jane Doe"
query = from users in "users",
select: inline_fragment("coalesce(#{users.name}, #{^default})")
Repo.all(query)
end
end
SAFETY WARNING: Please note that it is NOT safe to first interpolate a string which is passed in to this macro. Unsafe example:
def unsafe_query(user_name) do
default = "Jane Doe"
fragment_string = "coalesce(#{user_name}, #{^default})"
query = from users in "users",
select: inline_fragment(fragment_string)
Repo.all(query)
end
end
The code above is UNSAFE, because the interpolation is done before the macro is called and the macro
receives the already interpolated string. This prohibits the macro from safely escaping the query params.
If the user_name
param comes from untrusted user input, this can lead to SQL injection.
A variant of Ecto fragment() which supports named params.
Nameds params are provided in a keyword list as the last argument.
The fragments query string can reference named params using the
name
syntax where name
is a key in the keyword list.
So named_fragment("coalesce(a, b, a)", a: 1, b: 2)
will
be expanded to fragment("coalesce(?, ?, ?)", 1, 2, 1)
at compile-time.
defmodule TestQuery do
import Ecto.Query
import EctoFragmentExtras
def test_query do
default = "Jane Doe"
query = from users in "users",
select: named_fragment("coalesce(a, b)", a: users.name, b: ^default)
Repo.all(query)
end
end