Current section
Files
Jump to
Current section
Files
lib/parse.ex
defmodule Bind.Parse do
import Ecto.Query
@doc """
Parses the sort parameter to determine the sort direction and field.
## Parameters
- `param`: The sort parameter as a string.
## Examples
> Bind.Parse.sort_field("-age")
[desc: :age]
> Bind.Parse.sort_field("name")
[asc: :name]
"""
def sort_field(param) do
case String.starts_with?(param, "-") do
true ->
[desc: String.to_atom(String.trim(param, "-"))]
false ->
[asc: String.to_atom(param)]
end
end
@doc """
Parses a where parameter to extract the field name and constraint.
## Parameters
- `param`: The where parameter as a string.
## Examples
> Bind.Parse.where_field("name[eq]")
[:name, "eq"]
> Bind.Parse.where_field("age[gte]")
[:age, "gte"]
"""
def where_field(param) do
case Regex.match?(~r/^\w+\[\w+\]$/, param) do
true ->
[prop, constraint] = String.split(param, "[")
constraint = String.trim(constraint, "]")
[String.to_atom(prop), constraint]
false ->
nil
end
end
@doc """
Parses a constraint and returns a dynamic query fragment.
## Parameters
- `field`: The field to apply the constraint to.
- `constraint`: The type of constraint (e.g., "eq", "gte").
- `value`: The value to compare the field against.
## Examples
> Bind.Parse.constraint(:name, "eq", "Alice")
dynamic([r], r.name == ^"Alice")
> Bind.Parse.constraint(:age, "gte", 30)
dynamic([r], r.age > ^30)
"""
def constraint(field, "eq", value) do
dynamic([r], field(r, ^field) == ^value)
end
def constraint(field, "neq", value) do
dynamic([r], field(r, ^field) != ^value)
end
def constraint(field_name, "gt", value) do
dynamic([r], field(r, ^field_name) > ^value)
end
def constraint(field_name, "gte", value) do
dynamic([r], field(r, ^field_name) >= ^value)
end
def constraint(field, "lt", value) do
dynamic([r], field(r, ^field) < ^value)
end
def constraint(field, "lte", value) do
dynamic([r], field(r, ^field) <= ^value)
end
def constraint(field, "true", _value) do
dynamic([r], field(r, ^field) == true)
end
def constraint(field, "false", _value) do
dynamic([r], field(r, ^field) == false)
end
def constraint(field, "starts_with", value) do
dynamic([r], ilike(field(r, ^field), ^"%#{value}"))
end
def constraint(field, "ends_with", value) do
dynamic([r], ilike(field(r, ^field), ^"#{value}%"))
end
def constraint(field, "in", value) do
values = String.split(value, ",")
dynamic([r], field(r, ^field) in ^values)
end
def constraint(field, "contains", value) do
dynamic([r], ilike(field(r, ^field), ^"%#{value}%"))
end
def constraint(field, "nil", value) when value in ["true", true] do
dynamic([r], is_nil(field(r, ^field)))
end
def constraint(field, "nil", value) when value in ["false", false] do
dynamic([r], not is_nil(field(r, ^field)))
end
def constraint(_field, constraint, _value) do
# Here we add an error clause that matches any unknown constraint.
{:error, "Invalid constraint: #{constraint}"}
end
end