Packages
mazurka
0.3.22
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.3.39
0.3.38
0.3.37
0.3.36
0.3.35
0.3.34
0.3.33
0.3.32
0.3.31
0.3.30
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
hypermedia api toolkit
Current section
Files
Jump to
Current section
Files
lib/mazurka/model.ex
defmodule Mazurka.Model do
@moduledoc """
"""
defmacro __using__(_) do
quote do
use Ecto.Model
use Mazurka.Model.Relation
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(_ENV) do
module = __CALLER__.module
relations = Mazurka.Model.Relation.get(module)
struct_fields = Module.get_attribute(module, :struct_fields)
fields = format_struct_fields(struct_fields)
field_vars = format_struct_vars(struct_fields)
valid_fields = format_valid_fields(struct_fields)
{primary_key, _, _} = Module.get_attribute(module, :primary_key)
field_clauses = for field <- valid_fields do
keys = [field, to_string(field)]
quote do
def fetch(model = %{unquote(primary_key) => id, __meta__: %{state: :built, repo: repo, opts: opts} = meta}, key, ref) when key in unquote(keys) do
pid = Etude.Async.spawn(ref, fn ->
unquote(field_vars) = repo.get!(unquote(module), id, opts)
model = Map.put(unquote(field_vars), :__meta__, %{meta | state: :loaded})
{:ok, model}
end)
{:pending, pid, %{model | __meta__: %{meta | state: :loading}}}
end
def fetch(model = %{__meta__: %{state: :loading}}, key, _) when key in unquote(keys) do
{:pending, model}
end
def fetch(model = %{__meta__: %{state: :loaded}}, key, ref) when key in unquote(keys) do
{:ok, Map.get(model, unquote(field)), model}
end
end
end
keys = valid_fields |> Enum.reject(&(&1 == primary_key))
quote do
def get(var!(repo), var!(id), var!(opts)) do
{:ok, unquote({:%{}, [], [{:__struct__, module} | fields]})}
end
defimpl Etude.Dict, for: unquote(module) do
use Etude.Dict
def keys(model, _) do
{:ok, unquote(keys), model}
end
def cache_key(%{unquote(primary_key) => id, __meta__: %{repo: repo, opts: opts}}) do
{repo, unquote(module), to_string(id), :erlang.phash2(opts)}
end
def cache_key(%{unquote(primary_key) => id}) do
{unquote(module), to_string(id)}
end
def fetch(model = %{unquote(primary_key) => id}, :id, _) do
{:ok, id, model}
end
unquote_splicing(relations || [])
unquote_splicing(field_clauses || [])
def fetch(model, key, _) do
{:error, model}
end
end
end
end
defp format_struct_fields(fields) do
Enum.reduce(fields, [], fn
({:id, _}, acc) ->
[{:id, Macro.var(:id, nil)} | acc]
({_key, %Ecto.Association.NotLoaded{}}, acc) ->
acc
({:__meta__, meta}, acc) ->
meta = Map.merge(meta, %{
__struct__: Mazurka.Model.Metadata,
repo: Macro.var(:repo, nil),
opts: Macro.var(:opts, nil)
}) |> Map.to_list
[{:__meta__, {:%{}, [], meta}} | acc]
({key, _}, acc) ->
[{key, nil} | acc]
end)
end
defp format_valid_fields(fields) do
Enum.reduce(fields, [], fn
({_, %Ecto.Association.NotLoaded{}}, acc) ->
acc
({:__meta__, _}, acc) ->
acc
({key, _}, acc) when is_binary(key) ->
[String.to_atom(key) | acc]
({key, _}, acc) ->
[key | acc]
end)
end
defp format_struct_vars(fields) do
{:%{}, [], Enum.reduce(fields, [], fn
({_, %Ecto.Association.NotLoaded{}}, acc) ->
acc
({:__meta__, _}, acc) ->
acc
({key, _}, acc) ->
[{key, Macro.var(key, nil)} | acc]
end)}
end
end