Current section

Files

Jump to
formex_ecto lib builder.ex
Raw

lib/builder.ex

defmodule Formex.BuilderType.Ecto do
@moduledoc false
defstruct [:form]
end
defimpl Formex.BuilderProtocol, for: Formex.BuilderType.Ecto do
alias Formex.Form
alias Formex.Field
alias Formex.FormNested
alias Formex.FormCollection
require Ecto.Query
@repo Application.get_env(:formex, :repo)
@spec create_form(Map.t) :: Map.t
def create_form(args) do
form = args.form.type.build_form(args.form)
method = if form.struct.id, do: :put, else: :post
form = form
|> Map.put(:struct, preload_assocs(form))
|> Map.put(:method, method)
|> Form.finish_creating
# form = form
# |> Map.put(:data, Keyword.put(form.data, :original_struct, form.struct))
# |> Map.put(:struct, copy_preloads_to_struct(form))
Map.put(args, :form, form)
end
@spec create_struct_info(Map.t) :: Map.t
def create_struct_info(args) do
form = args.form
struct = struct(form.struct_module)
struct_info = struct
|> Map.from_struct
|> Enum.filter(&(elem(&1, 0) !== :__meta__))
|> Enum.map(fn {k, _v} ->
v = case get_assoc_or_embed(form, k) do
%{cardinality: :many, related: module} ->
{:collection, module}
%{cardinality: :one, related: module} ->
{:nested, module}
_ -> :any
end
{k, v}
end)
form = Map.put(form, :struct_info, struct_info)
Map.put(args, :form, form)
end
#
defp preload_assocs(form) do
# TODO - creating a new struct for nested when it is nil,
# or handle that empty form and do not displaying it
form.items
|> Enum.filter(fn item ->
case item do
%FormNested{} -> true
%FormCollection{} -> true
%Field{} -> item.type == :multiple_select
_ -> false
end
end)
|> Enum.reduce(form.struct, fn item, struct ->
if is_assoc(form, item.name) do
queryable = struct.__struct__.__schema__(:association, item.name).queryable
struct
|> @repo.preload([
{item.name, Ecto.Query.from(e in queryable, order_by: e.id)}
])
else
struct
end
end)
end
# written for 0.1.5 and never used. maybe it will be useful some day
# defp copy_preloads_to_struct(form) do
# struct = form.items
# |> Enum.filter(fn item ->
# case item do
# %FormNested{} -> true
# %FormCollection{} -> true
# _ -> false
# end
# end)
# |> Enum.reduce(form.struct, fn item, struct ->
# if is_assoc(form, item.name) do
# {key, val} = case item do
# %FormNested{} ->
# {item.name, copy_preloads_to_struct(item.form)}
# %FormCollection{} ->
# {item.name, Enum.map(item.forms, fn nested ->
# copy_preloads_to_struct(nested.form)
# end)}
# end
# Map.put(struct, key, val)
# else
# struct
# end
# end)
# end
@doc false
@spec get_assoc_or_embed(form :: Form.t, name :: Atom.t) :: any
defp get_assoc_or_embed(form, name) do
if is_assoc(form, name) do
form.struct_module.__schema__(:association, name)
else
form.struct_module.__schema__(:embed, name)
end
end
@doc false
@spec is_assoc(form :: Form.t, name :: Atom.t) :: boolean
defp is_assoc(form, name) do
form.struct_module.__schema__(:association, name) != nil
end
end