zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

loader.ex (2949B)


      1 defmodule Ecto.Schema.Loader do
      2   @moduledoc false
      3 
      4   alias Ecto.Schema.Metadata
      5 
      6   @doc """
      7   Loads a struct to be used as a template in further operations.
      8   """
      9   def load_struct(nil, _prefix, _source), do: %{}
     10 
     11   def load_struct(schema, prefix, source) do
     12     case schema.__schema__(:loaded) do
     13       %{__meta__: %Metadata{prefix: ^prefix, source: ^source}} = struct ->
     14         struct
     15 
     16       %{__meta__: %Metadata{} = metadata} = struct ->
     17         Map.put(struct, :__meta__, %{metadata | source: source, prefix: prefix})
     18 
     19       %{} = struct ->
     20         struct
     21     end
     22   end
     23 
     24   @doc """
     25   Loads data coming from the user/embeds into schema.
     26 
     27   Assumes data does not all belongs to schema/struct
     28   and that it may also require source-based renaming.
     29   """
     30   def unsafe_load(schema, data, loader) do
     31     types = schema.__schema__(:load)
     32     struct = schema.__schema__(:loaded)
     33     unsafe_load(struct, types, data, loader)
     34   end
     35 
     36   @doc """
     37   Loads data coming from the user/embeds into struct and types.
     38 
     39   Assumes data does not all belongs to schema/struct
     40   and that it may also require source-based renaming.
     41   """
     42   def unsafe_load(struct, types, map, loader) when is_map(map) do
     43     Enum.reduce(types, struct, fn pair, acc ->
     44       {field, source, type} = field_source_and_type(pair)
     45 
     46       case fetch_string_or_atom_field(map, source) do
     47         {:ok, value} -> Map.put(acc, field, load!(struct, field, type, value, loader))
     48         :error -> acc
     49       end
     50     end)
     51   end
     52 
     53   @compile {:inline, field_source_and_type: 1, fetch_string_or_atom_field: 2}
     54   defp field_source_and_type({field, {:source, source, type}}) do
     55     {field, source, type}
     56   end
     57 
     58   defp field_source_and_type({field, type}) do
     59     {field, field, type}
     60   end
     61 
     62   defp fetch_string_or_atom_field(map, field) when is_atom(field) do
     63     case Map.fetch(map, Atom.to_string(field)) do
     64       {:ok, value} -> {:ok, value}
     65       :error -> Map.fetch(map, field)
     66     end
     67   end
     68 
     69   @compile {:inline, load!: 5}
     70   defp load!(struct, field, type, value, loader) do
     71     case loader.(type, value) do
     72       {:ok, value} ->
     73         value
     74 
     75       :error ->
     76         raise ArgumentError,
     77               "cannot load `#{inspect(value)}` as type #{inspect(type)} " <>
     78                 "for field `#{field}`#{error_data(struct)}"
     79     end
     80   end
     81 
     82   defp error_data(%{__struct__: atom}) do
     83     " in schema #{inspect(atom)}"
     84   end
     85 
     86   defp error_data(other) when is_map(other) do
     87     ""
     88   end
     89 
     90   @doc """
     91   Dumps the given data.
     92   """
     93   def safe_dump(struct, types, dumper) do
     94     Enum.reduce(types, %{}, fn {field, {source, type}}, acc ->
     95       value = Map.get(struct, field)
     96 
     97       case dumper.(type, value) do
     98         {:ok, value} ->
     99           Map.put(acc, source, value)
    100         :error ->
    101           raise ArgumentError, "cannot dump `#{inspect value}` as type #{inspect type} " <>
    102                                "for field `#{field}` in schema #{inspect struct.__struct__}"
    103       end
    104     end)
    105   end
    106 end