Se crea el parser para customfilter. Agregamos variables de entorno para manejar url de adjuntos con o sin clave de encriptacion.
This commit is contained in:
7
.env
7
.env
@ -4,7 +4,6 @@ DATABASE_URL=ecto://postgres:1nf0rm3@127.0.0.1/dicomscp
|
|||||||
CHECK_ORIGIN=https://estudios.nobissalud.com.ar
|
CHECK_ORIGIN=https://estudios.nobissalud.com.ar
|
||||||
PHX_PORT=4001
|
PHX_PORT=4001
|
||||||
PHX_HOST=127.0.0.1
|
PHX_HOST=127.0.0.1
|
||||||
#PHX_HOST=pacientes.sdlc.com.ar
|
|
||||||
ROOT_PATH=/api
|
ROOT_PATH=/api
|
||||||
SCHEME=https
|
SCHEME=https
|
||||||
#si es true debe estar escrito siempre en mayuscula (por que llega como string no como boolean)
|
#si es true debe estar escrito siempre en mayuscula (por que llega como string no como boolean)
|
||||||
@ -16,8 +15,10 @@ PYTHON_SCRIPT=/home/informemedico/impacs/cgi/soffice/generar_pdf_api.py
|
|||||||
TEMPLATE_NAME=Con Membrete
|
TEMPLATE_NAME=Con Membrete
|
||||||
pr2_statusname=FINAL
|
pr2_statusname=FINAL
|
||||||
IDSITE=86
|
IDSITE=86
|
||||||
#ESCANEADOS=https://cedialcom.informemedico.com.ar:4443/cgi-bin/imageasjpeg.bf/imageasjpeg/
|
ESCANEADOS=https://estudios.nobissalud.com.ar/
|
||||||
ESCANEADOS=https://estudios.nobissalud.com.ar/#
|
# ESCANEADOS_CLAVE=
|
||||||
|
ADJUNTOS=https://estudios.nobissalud.com.ar/api/attachment/
|
||||||
|
ADJUNTOS_CLAVE=1nf0rm3
|
||||||
acceso_ed=IDSTUDY
|
acceso_ed=IDSTUDY
|
||||||
IDENTIFIERFIELD=IDSTUDY
|
IDENTIFIERFIELD=IDSTUDY
|
||||||
|
|
||||||
|
@ -3,14 +3,23 @@ defmodule Api.Studies do
|
|||||||
alias Api.Repo
|
alias Api.Repo
|
||||||
|
|
||||||
def studies_sql_query(filters) do
|
def studies_sql_query(filters) do
|
||||||
|
customfilter =
|
||||||
|
case Map.get(filters, "customfilter") do
|
||||||
|
nil -> dynamic([_], true)
|
||||||
|
"" -> dynamic([_], true)
|
||||||
|
expr ->
|
||||||
|
case ExpressionParser.parse(expr) do
|
||||||
|
{:ok, ast} -> ExpressionToEcto.to_dynamic(ast)
|
||||||
|
{:error, _reason} -> raise "Error al parsear customfilter"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
page = filters["page"] || 1
|
page = filters["page"] || 1
|
||||||
size = filters["size"] || 24
|
size = filters["size"] || 24
|
||||||
|
|
||||||
filter = filters["filter"] || []
|
filter = filters["filter"] || []
|
||||||
sort = filters["sort"] || [%{"dir" => "desc", "field" => "studydate"}]
|
sort = filters["sort"] || [%{"dir" => "desc", "field" => "studydate"}]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Construcción de condiciones de filtro dinámicas
|
# Construcción de condiciones de filtro dinámicas
|
||||||
filter_conditions =
|
filter_conditions =
|
||||||
Enum.reduce(filter, dynamic(true), fn f, acc ->
|
Enum.reduce(filter, dynamic(true), fn f, acc ->
|
||||||
@ -23,7 +32,7 @@ defmodule Api.Studies do
|
|||||||
dynamic([s], ilike(s.modality, ^"%#{value}%"))
|
dynamic([s], ilike(s.modality, ^"%#{value}%"))
|
||||||
|
|
||||||
"idstudy" ->
|
"idstudy" ->
|
||||||
dynamic([s], s.idstudy == ^String.to_integer(value))
|
dynamic([s], like(fragment("CAST(? AS TEXT)", s.idstudy), ^"#{value}%"))
|
||||||
|
|
||||||
"studydate" ->
|
"studydate" ->
|
||||||
dynamic([s], fragment("CAST(? AS DATE)::text LIKE ?", s.studydate, ^"%#{value}%"))
|
dynamic([s], fragment("CAST(? AS DATE)::text LIKE ?", s.studydate, ^"%#{value}%"))
|
||||||
@ -82,35 +91,37 @@ defmodule Api.Studies do
|
|||||||
{direction, field}
|
{direction, field}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
combined_filter =
|
||||||
|
dynamic([q], ^filter_conditions and ^customfilter)
|
||||||
|
|
||||||
query =
|
query =
|
||||||
from s in "study",
|
from s in "study",
|
||||||
join: p in "patient",
|
join: p in "patient",
|
||||||
on: p.idpatient == s.idpatient,
|
on: p.idpatient == s.idpatient,
|
||||||
left_join: sr in "studyreport",
|
left_join: sr in "studyreport",
|
||||||
on: sr.idstudy == s.idstudy,
|
on: sr.idstudy == s.idstudy,
|
||||||
left_join: st in "statuses",
|
left_join: st in "statuses",
|
||||||
on: st.idstatus == sr.idstudyreport,
|
on: st.idstatus == sr.idstudyreport,
|
||||||
where: ^filter_conditions,
|
where: ^combined_filter,
|
||||||
select: %{
|
select: %{
|
||||||
recordstotal: fragment("count(*) over()"),
|
recordstotal: fragment("count(*) over()"),
|
||||||
idstudy: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", s.idstudy),
|
idstudy: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", s.idstudy),
|
||||||
#idstudy: s.idstudy,
|
#idstudy: s.idstudy,
|
||||||
accessionnumber: s.accessionnumber,
|
accessionnumber: s.accessionnumber,
|
||||||
studydate: s.studydate,
|
studydate: s.studydate,
|
||||||
studytime: s.studytime,
|
studytime: s.studytime,
|
||||||
patientname: fragment("select replace(?, '^', ' ')", p.patientname),
|
patientname: fragment("select replace(?, '^', ' ')", p.patientname),
|
||||||
proceduredescription: s.studydescription,
|
proceduredescription: s.studydescription,
|
||||||
modality: s.modality,
|
modality: s.modality,
|
||||||
sitename: s.institutionname,
|
sitename: s.institutionname,
|
||||||
insurer: s.insurer,
|
insurer: s.insurer,
|
||||||
nrodocumento: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", p.patientid),
|
nrodocumento: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", p.patientid),
|
||||||
#nrodocumento: p.patientid,
|
#nrodocumento: p.patientid,
|
||||||
hasaudio: fragment("CASE WHEN ? IS NOT NULL THEN true ELSE false END", s.audiofile)
|
hasaudio: fragment("CASE WHEN ? IS NOT NULL THEN true ELSE false END", s.audiofile)
|
||||||
},
|
},
|
||||||
order_by: ^sort_conditions,
|
order_by: ^sort_conditions,
|
||||||
limit: ^size,
|
limit: ^size,
|
||||||
offset: ^((page - 1) * size)
|
offset: ^((page - 1) * size)
|
||||||
|
|
||||||
|
|
||||||
result = Repo.one(
|
result = Repo.one(
|
||||||
|
@ -9,7 +9,6 @@ defmodule Api.Study do
|
|||||||
|
|
||||||
idsite = Envar.get("IDSITE") |> String.to_integer
|
idsite = Envar.get("IDSITE") |> String.to_integer
|
||||||
domain = Envar.get("CHECK_ORIGIN")
|
domain = Envar.get("CHECK_ORIGIN")
|
||||||
escaneados = Envar.get("ESCANEADOS")
|
|
||||||
|
|
||||||
id_study = if Envar.get("IDENTIFIERFIELD") == "ACCESSIONNUMBER" do
|
id_study = if Envar.get("IDENTIFIERFIELD") == "ACCESSIONNUMBER" do
|
||||||
query =
|
query =
|
||||||
@ -25,15 +24,6 @@ defmodule Api.Study do
|
|||||||
|
|
||||||
id_study = if is_integer(id_study), do: id_study, else: String.to_integer(id_study)
|
id_study = if is_integer(id_study), do: id_study, else: String.to_integer(id_study)
|
||||||
|
|
||||||
|
|
||||||
# accession_fragment =
|
|
||||||
# if Envar.get("IDENTIFIERFIELD") == "ACCESSIONNUMBER" do
|
|
||||||
# fragment("?::text", ^accession)
|
|
||||||
# else
|
|
||||||
# fragment("?::integer", ^id_study)
|
|
||||||
# end
|
|
||||||
|
|
||||||
|
|
||||||
Logger.info("id_study -------> #{inspect(id_study)}")
|
Logger.info("id_study -------> #{inspect(id_study)}")
|
||||||
|
|
||||||
# Las siguientes consultas obtienen la información completa
|
# Las siguientes consultas obtienen la información completa
|
||||||
@ -70,56 +60,109 @@ defmodule Api.Study do
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# escaneados
|
# escaneados
|
||||||
subquery2 = subquery(
|
escaneados_clave = Envar.get("ESCANEADOS_CLAVE")
|
||||||
from s in "study",
|
base_escaneados = Envar.get("ESCANEADOS")
|
||||||
join: ss in "studyscans", on: ss.idstudy == s.idstudy,
|
|
||||||
join: sc in "scanclasses", on: sc.idscanclass == ss.idscanclass,
|
escaneados_expr =
|
||||||
join: p in "patient", on: s.idpatient == p.idpatient,
|
if escaneados_clave do
|
||||||
where: s.idstudy == ^id_study,
|
dynamic([_, ss, _, _],
|
||||||
select: %{
|
fragment(
|
||||||
idsite: type(^idsite, :integer),
|
"concat(?::text, substring(encrypt(?::text::bytea, ?, 'aes')::text from 3))",
|
||||||
|
^base_escaneados,
|
||||||
|
ss.idstudyscan,
|
||||||
|
^escaneados_clave
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
dynamic([_, ss, _, _],
|
||||||
|
fragment(
|
||||||
|
"concat(?::text, ?::text)",
|
||||||
|
^base_escaneados,
|
||||||
|
ss.idstudyscan
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
select_expr_es =
|
||||||
|
dynamic([s, ss, sc, p], %{
|
||||||
|
idsite: type(^idsite, :integer),
|
||||||
iddocument: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", ss.idstudyscan),
|
iddocument: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", ss.idstudyscan),
|
||||||
document_name: sc.scanclass,
|
document_name: sc.scanclass,
|
||||||
document_type: "url",
|
document_type: "url",
|
||||||
url: fragment(
|
url: ^escaneados_expr,
|
||||||
"concat(?::text, substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3))",
|
|
||||||
^escaneados,
|
|
||||||
ss.idstudyscan
|
|
||||||
),
|
|
||||||
patientname: p.patientname,
|
patientname: p.patientname,
|
||||||
proceduredescription: s.studydescription,
|
proceduredescription: s.studydescription,
|
||||||
studydate: fragment("TO_CHAR(?, 'YYYY-MM-DD')", s.studydate),
|
studydate: fragment("TO_CHAR(?, 'YYYY-MM-DD')", s.studydate),
|
||||||
studytime: fragment("TO_CHAR(?, 'HH24:MI:SS')", s.studytime),
|
studytime: fragment("TO_CHAR(?, 'HH24:MI:SS')", s.studytime),
|
||||||
accessionnumber: s.idstudy,
|
accessionnumber: s.idstudy,
|
||||||
patientid: p.patientid
|
patientid: p.patientid
|
||||||
}
|
})
|
||||||
|
|
||||||
|
subquery2 = subquery(
|
||||||
|
from s in "study",
|
||||||
|
join: ss in "studyscans", on: ss.idstudy == s.idstudy,
|
||||||
|
join: sc in "scanclasses", on: sc.idscanclass == ss.idscanclass,
|
||||||
|
join: p in "patient", on: s.idpatient == p.idpatient,
|
||||||
|
where: s.idstudy == ^id_study,
|
||||||
|
select: ^select_expr_es
|
||||||
)
|
)
|
||||||
|
|
||||||
# adjuntos
|
# adjuntos
|
||||||
subquery3 =
|
adjuntos_clave = Envar.get("ADJUNTOS_CLAVE")
|
||||||
|
base_adjuntos = Envar.get("ADJUNTOS")
|
||||||
|
|
||||||
|
adjuntos_expr =
|
||||||
|
if adjuntos_clave do
|
||||||
|
dynamic([_, sa, _],
|
||||||
|
fragment(
|
||||||
|
"concat(?::text, substring(encrypt(?::text::bytea, ?, 'aes')::text from 3))",
|
||||||
|
^base_adjuntos,
|
||||||
|
sa.idstudyattachment,
|
||||||
|
^adjuntos_clave
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
dynamic([_, sa, _],
|
||||||
|
fragment(
|
||||||
|
"concat(?::text, ?::text)",
|
||||||
|
^base_adjuntos,
|
||||||
|
sa.idstudyattachment
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
select_expr_ad =
|
||||||
|
dynamic([s, sa, p], %{
|
||||||
|
idsite: type(^idsite, :integer),
|
||||||
|
iddocument:
|
||||||
|
fragment(
|
||||||
|
"substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)",
|
||||||
|
sa.idstudyattachment
|
||||||
|
),
|
||||||
|
document_name: sa.name,
|
||||||
|
document_type:
|
||||||
|
fragment(
|
||||||
|
"CASE WHEN ? NOT IN ('jpg', 'jpeg', 'png') THEN 'attachment' ELSE 'url' END",
|
||||||
|
sa.format
|
||||||
|
),
|
||||||
|
url: ^adjuntos_expr,
|
||||||
|
patientname: p.patientname,
|
||||||
|
proceduredescription: s.studydescription,
|
||||||
|
studydate: fragment("TO_CHAR(?, 'YYYY-MM-DD')", s.studydate),
|
||||||
|
studytime: fragment("TO_CHAR(?, 'HH24:MI:SS')", s.studytime),
|
||||||
|
accessionnumber: s.idstudy,
|
||||||
|
patientid: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
subquery3 = subquery(
|
||||||
from s in "study",
|
from s in "study",
|
||||||
join: sa in "studyattachments", on: sa.idstudy == s.idstudy,
|
join: sa in "studyattachments", on: sa.idstudy == s.idstudy,
|
||||||
join: p in "patient", on: p.idpatient == s.idpatient,
|
join: p in "patient", on: p.idpatient == s.idpatient,
|
||||||
where: s.idstudy == ^id_study,
|
where: s.idstudy == ^id_study,
|
||||||
select: %{
|
select: ^select_expr_ad
|
||||||
idsite: type(^idsite, :integer),
|
)
|
||||||
iddocument: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", sa.idstudyattachment),
|
|
||||||
document_name: sa.name,
|
|
||||||
document_type: fragment("CASE WHEN ? NOT IN ('jpg', 'jpeg', 'png') THEN 'attachment' ELSE 'url' END", sa.format),
|
|
||||||
url: fragment(
|
|
||||||
"concat(?::text, ?::text, substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3))",
|
|
||||||
^domain,
|
|
||||||
"/api/attachment/",
|
|
||||||
sa.idstudyattachment
|
|
||||||
),
|
|
||||||
patientname: p.patientname,
|
|
||||||
proceduredescription: s.studydescription,
|
|
||||||
studydate: fragment("TO_CHAR(?, 'YYYY-MM-DD')", s.studydate),
|
|
||||||
studytime: fragment("TO_CHAR(?, 'HH24:MI:SS')", s.studytime),
|
|
||||||
accessionnumber: s.idstudy,
|
|
||||||
patientid: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# Si no encontró informes, ni adjuntos, ni nada
|
# Si no encontró informes, ni adjuntos, ni nada
|
||||||
# se traen sólo los datos básicos del estudio
|
# se traen sólo los datos básicos del estudio
|
||||||
|
@ -10,7 +10,7 @@ defmodule Api.Application do
|
|||||||
children = [
|
children = [
|
||||||
ApiWeb.Telemetry,
|
ApiWeb.Telemetry,
|
||||||
Api.Repo,
|
Api.Repo,
|
||||||
{Api.Autosender, 1000 * 62 * 4},
|
# {Api.Autosender, 1000 * 60},
|
||||||
# {DNSCluster, query: Application.get_env(:api, :dns_cluster_query) || :ignore},
|
# {DNSCluster, query: Application.get_env(:api, :dns_cluster_query) || :ignore},
|
||||||
{Phoenix.PubSub, name: Api.PubSub},
|
{Phoenix.PubSub, name: Api.PubSub},
|
||||||
# Start the Finch HTTP client for sending emails
|
# Start the Finch HTTP client for sending emails
|
||||||
|
@ -13,6 +13,7 @@ defmodule Api.Emailtosend do
|
|||||||
field :errormsg, :string
|
field :errormsg, :string
|
||||||
field :forcereprocess, :boolean
|
field :forcereprocess, :boolean
|
||||||
field :sentdatetime, :naive_datetime
|
field :sentdatetime, :naive_datetime
|
||||||
|
field :registered, :utc_datetime
|
||||||
end
|
end
|
||||||
|
|
||||||
def changeset(emailtosend, attrs) do
|
def changeset(emailtosend, attrs) do
|
||||||
|
124
lib/api/parser/expression_parser.ex
Normal file
124
lib/api/parser/expression_parser.ex
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
defmodule ExpressionParser do
|
||||||
|
import NimbleParsec
|
||||||
|
|
||||||
|
whitespace = ignore(optional(ascii_string([?\s, ?\t, ?\n, ?\r], min: 1)))
|
||||||
|
|
||||||
|
identifier =
|
||||||
|
ascii_string([?a..?z, ?A..?Z, ?_, ?0..?9], min: 1)
|
||||||
|
|> label("identifier")
|
||||||
|
|> unwrap_and_tag(:field)
|
||||||
|
|
||||||
|
quoted_string =
|
||||||
|
ignore(string("\""))
|
||||||
|
|> repeat(utf8_char(not: ?"))
|
||||||
|
|> reduce({List, :to_string, []})
|
||||||
|
|> ignore(string("\""))
|
||||||
|
|
||||||
|
number =
|
||||||
|
ascii_string([?0..?9], min: 1)
|
||||||
|
|> map({String, :to_integer, []})
|
||||||
|
|
||||||
|
atom_value =
|
||||||
|
ignore(string("'"))
|
||||||
|
|> ascii_string([?a..?z, ?A..?Z], min: 1)
|
||||||
|
|> ignore(string("'"))
|
||||||
|
|> map({__MODULE__, :identity, []})
|
||||||
|
|
||||||
|
list_item =
|
||||||
|
choice([
|
||||||
|
number,
|
||||||
|
atom_value,
|
||||||
|
quoted_string |> unwrap_and_tag(:string)
|
||||||
|
])
|
||||||
|
|
||||||
|
atom_list =
|
||||||
|
ignore(string("["))
|
||||||
|
|> optional(whitespace)
|
||||||
|
|> repeat(
|
||||||
|
list_item
|
||||||
|
|> optional(ignore(string(",")))
|
||||||
|
|> optional(whitespace)
|
||||||
|
)
|
||||||
|
|> ignore(string("]"))
|
||||||
|
|> tag(:list)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
operator =
|
||||||
|
choice([
|
||||||
|
string("ilike") |> replace(:ilike),
|
||||||
|
string(">=") |> replace(:>=),
|
||||||
|
string("<=") |> replace(:<=),
|
||||||
|
string("!=") |> replace(:!=),
|
||||||
|
string(">") |> replace(:>),
|
||||||
|
string("<") |> replace(:<),
|
||||||
|
string("=") |> replace(:==),
|
||||||
|
string("in") |> replace(:in)
|
||||||
|
])
|
||||||
|
|
||||||
|
value =
|
||||||
|
choice([
|
||||||
|
quoted_string |> unwrap_and_tag(:string),
|
||||||
|
number |> unwrap_and_tag(:number),
|
||||||
|
atom_list
|
||||||
|
])
|
||||||
|
|
||||||
|
comparison =
|
||||||
|
identifier
|
||||||
|
|> ignore(whitespace)
|
||||||
|
|> concat(operator)
|
||||||
|
|> ignore(whitespace)
|
||||||
|
|> concat(value)
|
||||||
|
|> tag(:comparison)
|
||||||
|
|
||||||
|
defcombinatorp :expr, parsec(:logic_expr)
|
||||||
|
|
||||||
|
paren_expr =
|
||||||
|
ignore(string("("))
|
||||||
|
|> ignore(whitespace)
|
||||||
|
|> parsec(:expr)
|
||||||
|
|> ignore(whitespace)
|
||||||
|
|> ignore(string(")"))
|
||||||
|
|
||||||
|
logic_term =
|
||||||
|
choice([
|
||||||
|
paren_expr,
|
||||||
|
comparison
|
||||||
|
])
|
||||||
|
|
||||||
|
logical_op =
|
||||||
|
ignore(whitespace)
|
||||||
|
|> choice([
|
||||||
|
string("and") |> replace(:and),
|
||||||
|
string("or") |> replace(:or)
|
||||||
|
])
|
||||||
|
|> ignore(whitespace)
|
||||||
|
|
||||||
|
logic_expr =
|
||||||
|
logic_term
|
||||||
|
|> repeat(
|
||||||
|
logical_op
|
||||||
|
|> concat(logic_term)
|
||||||
|
)
|
||||||
|
|> reduce({__MODULE__, :reduce_logic, []})
|
||||||
|
|
||||||
|
defparsec :logic_expr, logic_expr
|
||||||
|
|
||||||
|
def parse(input) do
|
||||||
|
case logic_expr(input) do
|
||||||
|
{:ok, result, "", _, _, _} -> {:ok, result}
|
||||||
|
{:ok, _, rest, _, _, _} -> {:error, "Unexpected remaining input: #{inspect(rest)}"}
|
||||||
|
{:error, reason, _, _, _, _} -> {:error, reason}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reduce_logic([head | tail]) do
|
||||||
|
Enum.chunk_every(tail, 2)
|
||||||
|
|> Enum.reduce(head, fn [op, right], acc ->
|
||||||
|
{op, acc, right}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def identity(value), do: value
|
||||||
|
|
||||||
|
end
|
59
lib/api/parser/expression_to_ecto.ex
Normal file
59
lib/api/parser/expression_to_ecto.ex
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
defmodule ExpressionToEcto do
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
def to_dynamic([]), do: true
|
||||||
|
|
||||||
|
def to_dynamic([single]), do: build_dynamic(single)
|
||||||
|
|
||||||
|
def to_dynamic(ast), do: build_dynamic(ast)
|
||||||
|
|
||||||
|
# Operadores lógicos
|
||||||
|
defp build_dynamic({:or, left, right}) do
|
||||||
|
dynamic([q], ^build_dynamic(left) or ^build_dynamic(right))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp build_dynamic({:and, left, right}) do
|
||||||
|
dynamic([q], ^build_dynamic(left) and ^build_dynamic(right))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Comparaciones con número
|
||||||
|
defp build_dynamic({:comparison, [{:field, field}, op, {:number, val}]}) do
|
||||||
|
field_atom = String.to_atom(field)
|
||||||
|
|
||||||
|
case op do
|
||||||
|
:== -> dynamic([q], field(q, ^field_atom) == ^val)
|
||||||
|
:!= -> dynamic([q], field(q, ^field_atom) != ^val)
|
||||||
|
:> -> dynamic([q], field(q, ^field_atom) > ^val)
|
||||||
|
:< -> dynamic([q], field(q, ^field_atom) < ^val)
|
||||||
|
:>= -> dynamic([q], field(q, ^field_atom) >= ^val)
|
||||||
|
:<= -> dynamic([q], field(q, ^field_atom) <= ^val)
|
||||||
|
other -> raise "Operador no soportado: #{inspect(other)}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Comparaciones con string
|
||||||
|
defp build_dynamic({:comparison, [{:field, field}, op, {:string, val}]}) when op in [:==, :!=] do
|
||||||
|
field_atom = String.to_atom(field)
|
||||||
|
case op do
|
||||||
|
:== -> dynamic([q], field(q, ^field_atom) == ^val)
|
||||||
|
:!= -> dynamic([q], field(q, ^field_atom) != ^val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ILIKE
|
||||||
|
defp build_dynamic({:comparison, [{:field, field}, :ilike, {:string, val}]}) do
|
||||||
|
field_atom = String.to_atom(field)
|
||||||
|
pattern = "#{val}"
|
||||||
|
dynamic([q], ilike(field(q, ^field_atom), ^pattern))
|
||||||
|
end
|
||||||
|
|
||||||
|
# IN
|
||||||
|
defp build_dynamic({:comparison, [{:field, field}, :in, {:list, vals}]}) do
|
||||||
|
field_atom = String.to_atom(field)
|
||||||
|
dynamic([q], field(q, ^field_atom) in ^vals)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp build_dynamic(other) do
|
||||||
|
raise "AST no soportado o mal formado: #{inspect(other)}"
|
||||||
|
end
|
||||||
|
end
|
3
mix.exs
3
mix.exs
@ -64,7 +64,8 @@ defmodule Api.MixProject do
|
|||||||
{:ex_heroicons, "~> 2.0.0"},
|
{:ex_heroicons, "~> 2.0.0"},
|
||||||
{:castore, "~> 1.0.10"},
|
{:castore, "~> 1.0.10"},
|
||||||
{:dotenv, "~> 3.1"},
|
{:dotenv, "~> 3.1"},
|
||||||
{:httpoison, "~> 2.2"}
|
{:httpoison, "~> 2.2"},
|
||||||
|
{:nimble_parsec, "~> 1.4"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user