zf

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

type.ex (43258B)


      1 defmodule Ecto.Type do
      2   @moduledoc """
      3   Defines functions and the `Ecto.Type` behaviour for implementing
      4   basic custom types.
      5 
      6   Ecto provides two types of custom types: basic types and
      7   parameterized types. Basic types are simple, requiring only four
      8   callbacks to be implemented, and are enough for most occasions.
      9   Parameterized types can be customized on the field definition and
     10   provide a wide variety of callbacks.
     11 
     12   The definition of basic custom types and all of their callbacks are
     13   available in this module. You can learn more about parameterized
     14   types in `Ecto.ParameterizedType`. If in doubt, prefer to use
     15   basic custom types and rely on parameterized types if you need
     16   the extra functionality.
     17 
     18   ## Example
     19 
     20   Imagine you want to store a URI struct as part of a schema in a
     21   url-shortening service. There isn't an Ecto field type to support
     22   that value at runtime therefore a custom one is needed.
     23 
     24   You also want to query not only by the full url, but for example
     25   by specific ports used. This is possible by putting the URI data
     26   into a map field instead of just storing the plain
     27   string representation.
     28 
     29       from s in ShortUrl,
     30         where: fragment("?->>? ILIKE ?", s.original_url, "port", "443")
     31 
     32   So the custom type does need to handle the conversion from
     33   external data to runtime data (`c:cast/1`) as well as
     34   transforming that runtime data into the `:map` Ecto native type and
     35   back (`c:dump/1` and `c:load/1`).
     36 
     37       defmodule EctoURI do
     38         use Ecto.Type
     39         def type, do: :map
     40 
     41         # Provide custom casting rules.
     42         # Cast strings into the URI struct to be used at runtime
     43         def cast(uri) when is_binary(uri) do
     44           {:ok, URI.parse(uri)}
     45         end
     46 
     47         # Accept casting of URI structs as well
     48         def cast(%URI{} = uri), do: {:ok, uri}
     49 
     50         # Everything else is a failure though
     51         def cast(_), do: :error
     52 
     53         # When loading data from the database, as long as it's a map,
     54         # we just put the data back into a URI struct to be stored in
     55         # the loaded schema struct.
     56         def load(data) when is_map(data) do
     57           data =
     58             for {key, val} <- data do
     59               {String.to_existing_atom(key), val}
     60             end
     61           {:ok, struct!(URI, data)}
     62         end
     63 
     64         # When dumping data to the database, we *expect* a URI struct
     65         # but any value could be inserted into the schema struct at runtime,
     66         # so we need to guard against them.
     67         def dump(%URI{} = uri), do: {:ok, Map.from_struct(uri)}
     68         def dump(_), do: :error
     69       end
     70 
     71   Now we can use our new field type above in our schemas:
     72 
     73       defmodule ShortUrl do
     74         use Ecto.Schema
     75 
     76         schema "posts" do
     77           field :original_url, EctoURI
     78         end
     79       end
     80 
     81   Note: `nil` values are always bypassed and cannot be handled by
     82   custom types.
     83 
     84   ## Custom types and primary keys
     85 
     86   Remember that, if you change the type of your primary keys,
     87   you will also need to change the type of all associations that
     88   point to said primary key.
     89 
     90   Imagine you want to encode the ID so they cannot enumerate the
     91   content in your application. An Ecto type could handle the conversion
     92   between the encoded version of the id and its representation in the
     93   database. For the sake of simplicity, we'll use base64 encoding in
     94   this example:
     95 
     96       defmodule EncodedId do
     97         use Ecto.Type
     98 
     99         def type, do: :id
    100 
    101         def cast(id) when is_integer(id) do
    102           {:ok, encode_id(id)}
    103         end
    104         def cast(_), do: :error
    105 
    106         def dump(id) when is_binary(id) do
    107           Base.decode64(id)
    108         end
    109 
    110         def load(id) when is_integer(id) do
    111           {:ok, encode_id(id)}
    112         end
    113 
    114         defp encode_id(id) do
    115           id
    116           |> Integer.to_string()
    117           |> Base.encode64
    118         end
    119       end
    120 
    121   To use it as the type for the id in our schema, we can use the
    122   `@primary_key` module attribute:
    123 
    124       defmodule BlogPost do
    125         use Ecto.Schema
    126 
    127         @primary_key {:id, EncodedId, autogenerate: true}
    128         schema "posts" do
    129           belongs_to :author, Author, type: EncodedId
    130           field :content, :string
    131         end
    132       end
    133 
    134       defmodule Author do
    135         use Ecto.Schema
    136 
    137         @primary_key {:id, EncodedId, autogenerate: true}
    138         schema "authors" do
    139           field :name, :string
    140           has_many :posts, BlogPost
    141         end
    142       end
    143 
    144   The `@primary_key` attribute will tell ecto which type to
    145   use for the id.
    146 
    147   Note the `type: EncodedId` option given to `belongs_to` in
    148   the `BlogPost` schema. By default, Ecto will treat
    149   associations as if their keys were `:integer`s. Our primary
    150   keys are a custom type, so when Ecto tries to cast those
    151   ids, it will fail.
    152 
    153   Alternatively, you can set `@foreign_key_type EncodedId`
    154   after `@primary_key` to automatically configure the type
    155   of all `belongs_to` fields.
    156   """
    157 
    158   import Kernel, except: [match?: 2]
    159 
    160   @doc false
    161   defmacro __using__(_opts) do
    162     quote location: :keep do
    163       @behaviour Ecto.Type
    164       def embed_as(_), do: :self
    165       def equal?(term1, term2), do: term1 == term2
    166       defoverridable [embed_as: 1, equal?: 2]
    167     end
    168   end
    169 
    170   @typedoc "An Ecto type, primitive or custom."
    171   @type t :: primitive | custom
    172 
    173   @typedoc "Primitive Ecto types (handled by Ecto)."
    174   @type primitive :: base | composite
    175 
    176   @typedoc "Custom types are represented by user-defined modules."
    177   @type custom :: module | {:parameterized, module, term}
    178 
    179   @type base :: :integer | :float | :boolean | :string | :map |
    180                  :binary | :decimal | :id | :binary_id |
    181                  :utc_datetime | :naive_datetime | :date | :time | :any |
    182                  :utc_datetime_usec | :naive_datetime_usec | :time_usec
    183 
    184   @type composite :: {:array, t} | {:map, t} | private_composite
    185 
    186   @typep private_composite :: {:maybe, t} | {:in, t} | {:param, :any_datetime}
    187 
    188   @base ~w(
    189     integer float decimal boolean string map binary id binary_id any
    190     utc_datetime naive_datetime date time
    191     utc_datetime_usec naive_datetime_usec time_usec
    192   )a
    193   @composite ~w(array map maybe in param)a
    194 
    195   @doc """
    196   Returns the underlying schema type for the custom type.
    197 
    198   For example, if you want to provide your own date
    199   structures, the type function should return `:date`.
    200 
    201   Note this function is not required to return Ecto primitive
    202   types, the type is only required to be known by the adapter.
    203   """
    204   @callback type :: t
    205 
    206   @doc """
    207   Casts the given input to the custom type.
    208 
    209   This callback is called on external input and can return any type,
    210   as long as the `dump/1` function is able to convert the returned
    211   value into an Ecto native type. There are two situations where
    212   this callback is called:
    213 
    214     1. When casting values by `Ecto.Changeset`
    215     2. When passing arguments to `Ecto.Query`
    216 
    217   You can return `:error` if the given term cannot be cast.
    218   A default error message of "is invalid" will be added to the
    219   changeset.
    220 
    221   You may also return `{:error, keyword()}` to customize the
    222   changeset error message and its metadata. Passing a `:message`
    223   key, will override the default message. It is not possible to
    224   override the `:type` key.
    225 
    226   For `{:array, CustomType}` or `{:map, CustomType}` the returned
    227   keyword list will be erased and the default error will be shown.
    228   """
    229   @callback cast(term) :: {:ok, term} | :error | {:error, keyword()}
    230 
    231   @doc """
    232   Loads the given term into a custom type.
    233 
    234   This callback is called when loading data from the database and
    235   receives an Ecto native type. It can return any type, as long as
    236   the `dump/1` function is able to convert the returned value back
    237   into an Ecto native type.
    238   """
    239   @callback load(term) :: {:ok, term} | :error
    240 
    241   @doc """
    242   Dumps the given term into an Ecto native type.
    243 
    244   This callback is called with any term that was stored in the struct
    245   and it needs to validate them and convert it to an Ecto native type.
    246   """
    247   @callback dump(term) :: {:ok, term} | :error
    248 
    249   @doc """
    250   Checks if two terms are semantically equal.
    251   """
    252   @callback equal?(term, term) :: boolean
    253 
    254   @doc """
    255   Dictates how the type should be treated inside embeds.
    256 
    257   By default, the type is sent as itself, without calling
    258   dumping to keep the higher level representation. But
    259   it can be set to `:dump` so that it is dumped before
    260   being encoded.
    261   """
    262   @callback embed_as(format :: atom) :: :self | :dump
    263 
    264   @doc """
    265   Generates a loaded version of the data.
    266 
    267   This is callback is invoked when a custom type is given
    268   to `field` with the `:autogenerate` flag.
    269   """
    270   @callback autogenerate() :: term()
    271 
    272   @optional_callbacks autogenerate: 0
    273 
    274   ## Functions
    275 
    276   @doc """
    277   Checks if we have a primitive type.
    278 
    279       iex> primitive?(:string)
    280       true
    281       iex> primitive?(Another)
    282       false
    283 
    284       iex> primitive?({:array, :string})
    285       true
    286       iex> primitive?({:array, Another})
    287       true
    288 
    289   """
    290   @spec primitive?(t) :: boolean
    291   def primitive?({:parameterized, _, _}), do: true
    292   def primitive?({composite, _}) when composite in @composite, do: true
    293   def primitive?(base) when base in @base, do: true
    294   def primitive?(_), do: false
    295 
    296   @doc """
    297   Checks if the given atom can be used as composite type.
    298 
    299       iex> composite?(:array)
    300       true
    301       iex> composite?(:string)
    302       false
    303 
    304   """
    305   @spec composite?(atom) :: boolean
    306   def composite?(atom), do: atom in @composite
    307 
    308   @doc """
    309   Checks if the given atom can be used as base type.
    310 
    311       iex> base?(:string)
    312       true
    313       iex> base?(:array)
    314       false
    315       iex> base?(Custom)
    316       false
    317 
    318   """
    319   @spec base?(atom) :: boolean
    320   def base?(atom), do: atom in @base
    321 
    322   @doc """
    323   Gets how the type is treated inside embeds for the given format.
    324 
    325   See `c:embed_as/1`.
    326   """
    327   def embed_as({:parameterized, module, params}, format), do: module.embed_as(format, params)
    328   def embed_as({composite, type}, format) when composite in @composite, do: embed_as(type, format)
    329   def embed_as(base, _format) when base in @base, do: :self
    330   def embed_as(mod, format), do: mod.embed_as(format)
    331 
    332   @doc """
    333   Dumps the `value` for `type` considering it will be embedded in `format`.
    334 
    335   ## Examples
    336 
    337       iex> Ecto.Type.embedded_dump(:decimal, Decimal.new("1"), :json)
    338       {:ok, Decimal.new("1")}
    339 
    340   """
    341   def embedded_dump(type, value, format) do
    342     case embed_as(type, format) do
    343       :self -> {:ok, value}
    344       :dump -> dump(type, value, &embedded_dump(&1, &2, format))
    345     end
    346   end
    347 
    348   @doc """
    349   Loads the `value` for `type` considering it was embedded in `format`.
    350 
    351   ## Examples
    352 
    353       iex> Ecto.Type.embedded_load(:decimal, "1", :json)
    354       {:ok, Decimal.new("1")}
    355 
    356   """
    357   def embedded_load(type, value, format) do
    358     case embed_as(type, format) do
    359       :self ->
    360         case cast(type, value) do
    361           {:ok, _} = ok -> ok
    362           _ -> :error
    363         end
    364 
    365       :dump ->
    366         load(type, value, &embedded_load(&1, &2, format))
    367     end
    368   end
    369 
    370   @doc """
    371   Retrieves the underlying schema type for the given, possibly custom, type.
    372 
    373       iex> type(:string)
    374       :string
    375       iex> type(Ecto.UUID)
    376       :uuid
    377 
    378       iex> type({:array, :string})
    379       {:array, :string}
    380       iex> type({:array, Ecto.UUID})
    381       {:array, :uuid}
    382 
    383       iex> type({:map, Ecto.UUID})
    384       {:map, :uuid}
    385 
    386   """
    387   @spec type(t) :: t
    388   def type(type)
    389   def type({:parameterized, type, params}), do: type.type(params)
    390   def type({:array, type}), do: {:array, type(type)}
    391   def type({:map, type}), do: {:map, type(type)}
    392   def type(type) when type in @base, do: type
    393   def type(type) when is_atom(type), do: type.type()
    394   def type(type), do: type
    395 
    396   @doc """
    397   Checks if a given type matches with a primitive type
    398   that can be found in queries.
    399 
    400       iex> match?(:string, :any)
    401       true
    402       iex> match?(:any, :string)
    403       true
    404       iex> match?(:string, :string)
    405       true
    406 
    407       iex> match?({:array, :string}, {:array, :any})
    408       true
    409 
    410       iex> match?(Ecto.UUID, :uuid)
    411       true
    412       iex> match?(Ecto.UUID, :string)
    413       false
    414 
    415   """
    416   @spec match?(t, primitive) :: boolean
    417   def match?(schema_type, query_type) do
    418     if primitive?(schema_type) do
    419       do_match?(schema_type, query_type)
    420     else
    421       do_match?(schema_type.type, query_type)
    422     end
    423   end
    424 
    425   defp do_match?(_left, :any),  do: true
    426   defp do_match?(:any, _right), do: true
    427   defp do_match?({outer, left}, {outer, right}), do: match?(left, right)
    428   defp do_match?(:decimal, type) when type in [:float, :integer], do: true
    429   defp do_match?(:binary_id, :binary), do: true
    430   defp do_match?(:id, :integer), do: true
    431   defp do_match?(type, type), do: true
    432   defp do_match?(:naive_datetime, {:param, :any_datetime}), do: true
    433   defp do_match?(:naive_datetime_usec, {:param, :any_datetime}), do: true
    434   defp do_match?(:utc_datetime, {:param, :any_datetime}), do: true
    435   defp do_match?(:utc_datetime_usec, {:param, :any_datetime}), do: true
    436   defp do_match?(_, _), do: false
    437 
    438   @doc """
    439   Dumps a value to the given type.
    440 
    441   Opposite to casting, dumping requires the returned value
    442   to be a valid Ecto type, as it will be sent to the
    443   underlying data store.
    444 
    445       iex> dump(:string, nil)
    446       {:ok, nil}
    447       iex> dump(:string, "foo")
    448       {:ok, "foo"}
    449 
    450       iex> dump(:integer, 1)
    451       {:ok, 1}
    452       iex> dump(:integer, "10")
    453       :error
    454 
    455       iex> dump(:binary, "foo")
    456       {:ok, "foo"}
    457       iex> dump(:binary, 1)
    458       :error
    459 
    460       iex> dump({:array, :integer}, [1, 2, 3])
    461       {:ok, [1, 2, 3]}
    462       iex> dump({:array, :integer}, [1, "2", 3])
    463       :error
    464       iex> dump({:array, :binary}, ["1", "2", "3"])
    465       {:ok, ["1", "2", "3"]}
    466 
    467   """
    468   @spec dump(t, term) :: {:ok, term} | :error
    469   @spec dump(t, term, (t, term -> {:ok, term} | :error)) :: {:ok, term} | :error
    470   def dump(type, value, dumper \\ &dump/2)
    471 
    472   def dump({:parameterized, module, params}, value, dumper) do
    473     module.dump(value, dumper, params)
    474   end
    475 
    476   def dump(_type, nil, _dumper) do
    477     {:ok, nil}
    478   end
    479 
    480   def dump({:maybe, type}, value, dumper) do
    481     case dump(type, value, dumper) do
    482       {:ok, _} = ok -> ok
    483       :error -> {:ok, value}
    484     end
    485   end
    486 
    487   def dump({:in, type}, value, dumper) do
    488     case dump({:array, type}, value, dumper) do
    489       {:ok, value} -> {:ok, {:in, value}}
    490       :error -> :error
    491     end
    492   end
    493 
    494   def dump({:array, {_, _, _} = type}, value, dumper), do: array(value, type, dumper, false, [])
    495   def dump({:array, type}, value, dumper), do: array(value, type, dumper, true, [])
    496   def dump({:map, type}, value, dumper), do: map(value, type, dumper, false, %{})
    497 
    498   def dump(:any, value, _dumper), do: {:ok, value}
    499   def dump(:integer, value, _dumper), do: same_integer(value)
    500   def dump(:float, value, _dumper), do: dump_float(value)
    501   def dump(:boolean, value, _dumper), do: same_boolean(value)
    502   def dump(:map, value, _dumper), do: same_map(value)
    503   def dump(:string, value, _dumper), do: same_binary(value)
    504   def dump(:binary, value, _dumper), do: same_binary(value)
    505   def dump(:id, value, _dumper), do: same_integer(value)
    506   def dump(:binary_id, value, _dumper), do: same_binary(value)
    507   def dump(:decimal, value, _dumper), do: same_decimal(value)
    508   def dump(:date, value, _dumper), do: same_date(value)
    509   def dump(:time, value, _dumper), do: dump_time(value)
    510   def dump(:time_usec, value, _dumper), do: dump_time_usec(value)
    511   def dump(:naive_datetime, value, _dumper), do: dump_naive_datetime(value)
    512   def dump(:naive_datetime_usec, value, _dumper), do: dump_naive_datetime_usec(value)
    513   def dump(:utc_datetime, value, _dumper), do: dump_utc_datetime(value)
    514   def dump(:utc_datetime_usec, value, _dumper), do: dump_utc_datetime_usec(value)
    515   def dump({:param, :any_datetime}, value, _dumper), do: dump_any_datetime(value)
    516   def dump(mod, value, _dumper) when is_atom(mod), do: mod.dump(value)
    517 
    518   defp dump_float(term) when is_float(term), do: {:ok, term}
    519   defp dump_float(_), do: :error
    520 
    521   defp dump_time(%Time{} = term), do: {:ok, check_no_usec!(term, :time)}
    522   defp dump_time(_), do: :error
    523 
    524   defp dump_time_usec(%Time{} = term), do: {:ok, check_usec!(term, :time_usec)}
    525   defp dump_time_usec(_), do: :error
    526 
    527   defp dump_any_datetime(%NaiveDateTime{} = term), do: {:ok, term}
    528   defp dump_any_datetime(%DateTime{} = term), do: {:ok, term}
    529   defp dump_any_datetime(_), do: :error
    530 
    531   defp dump_naive_datetime(%NaiveDateTime{} = term), do:
    532     {:ok, check_no_usec!(term, :naive_datetime)}
    533 
    534   defp dump_naive_datetime(_), do: :error
    535 
    536   defp dump_naive_datetime_usec(%NaiveDateTime{} = term),
    537     do: {:ok, check_usec!(term, :naive_datetime_usec)}
    538 
    539   defp dump_naive_datetime_usec(_), do: :error
    540 
    541   defp dump_utc_datetime(%DateTime{} = datetime) do
    542     kind = :utc_datetime
    543     {:ok, datetime |> check_utc_timezone!(kind) |> check_no_usec!(kind)}
    544   end
    545 
    546   defp dump_utc_datetime(_), do: :error
    547 
    548   defp dump_utc_datetime_usec(%DateTime{} = datetime) do
    549     kind = :utc_datetime_usec
    550     {:ok, datetime |> check_utc_timezone!(kind) |> check_usec!(kind)}
    551   end
    552 
    553   defp dump_utc_datetime_usec(_), do: :error
    554 
    555   @doc """
    556   Loads a value with the given type.
    557 
    558       iex> load(:string, nil)
    559       {:ok, nil}
    560       iex> load(:string, "foo")
    561       {:ok, "foo"}
    562 
    563       iex> load(:integer, 1)
    564       {:ok, 1}
    565       iex> load(:integer, "10")
    566       :error
    567 
    568   """
    569   @spec load(t, term) :: {:ok, term} | :error
    570   @spec load(t, term, (t, term -> {:ok, term} | :error)) :: {:ok, term} | :error
    571   def load(type, value, loader \\ &load/2)
    572 
    573   def load({:parameterized, module, params}, value, loader) do
    574     module.load(value, loader, params)
    575   end
    576 
    577   def load(_type, nil, _loader) do
    578     {:ok, nil}
    579   end
    580 
    581   def load({:maybe, type}, value, loader) do
    582     case load(type, value, loader) do
    583       {:ok, _} = ok -> ok
    584       :error -> {:ok, value}
    585     end
    586   end
    587 
    588   def load({:array, {_, _, _} = type}, value, loader), do: array(value, type, loader, false, [])
    589   def load({:array, type}, value, loader), do: array(value, type, loader, true, [])
    590   def load({:map, type}, value, loader), do: map(value, type, loader, false, %{})
    591 
    592   def load(:any, value, _loader), do: {:ok, value}
    593   def load(:integer, value, _loader), do: same_integer(value)
    594   def load(:float, value, _loader), do: load_float(value)
    595   def load(:boolean, value, _loader), do: same_boolean(value)
    596   def load(:map, value, _loader), do: same_map(value)
    597   def load(:string, value, _loader), do: same_binary(value)
    598   def load(:binary, value, _loader), do: same_binary(value)
    599   def load(:id, value, _loader), do: same_integer(value)
    600   def load(:binary_id, value, _loader), do: same_binary(value)
    601   def load(:decimal, value, _loader), do: same_decimal(value)
    602   def load(:date, value, _loader), do: same_date(value)
    603   def load(:time, value, _loader), do: load_time(value)
    604   def load(:time_usec, value, _loader), do: load_time_usec(value)
    605   def load(:naive_datetime, value, _loader), do: load_naive_datetime(value)
    606   def load(:naive_datetime_usec, value, _loader), do: load_naive_datetime_usec(value)
    607   def load(:utc_datetime, value, _loader), do: load_utc_datetime(value)
    608   def load(:utc_datetime_usec, value, _loader), do: load_utc_datetime_usec(value)
    609   def load(mod, value, _loader), do: mod.load(value)
    610 
    611   defp load_float(term) when is_float(term), do: {:ok, term}
    612   defp load_float(term) when is_integer(term), do: {:ok, :erlang.float(term)}
    613   defp load_float(_), do: :error
    614 
    615   defp load_time(%Time{} = time), do: {:ok, truncate_usec(time)}
    616   defp load_time(_), do: :error
    617 
    618   defp load_time_usec(%Time{} = time), do: {:ok, pad_usec(time)}
    619   defp load_time_usec(_), do: :error
    620 
    621   # This is a downcast, which is always fine, and in case
    622   # we try to send a naive datetime where a datetime is expected,
    623   # the adapter will either explicitly error (Postgres) or it will
    624   # accept the data (MySQL), which is fine as we always assume UTC
    625   defp load_naive_datetime(%DateTime{} = datetime),
    626     do: {:ok, datetime |> check_utc_timezone!(:naive_datetime) |> DateTime.to_naive() |> truncate_usec()}
    627 
    628   defp load_naive_datetime(%NaiveDateTime{} = naive_datetime),
    629     do: {:ok, truncate_usec(naive_datetime)}
    630 
    631   defp load_naive_datetime(_), do: :error
    632 
    633   defp load_naive_datetime_usec(%DateTime{} = datetime),
    634     do: {:ok, datetime |> check_utc_timezone!(:naive_datetime_usec) |> DateTime.to_naive() |> pad_usec()}
    635 
    636   defp load_naive_datetime_usec(%NaiveDateTime{} = naive_datetime),
    637     do: {:ok, pad_usec(naive_datetime)}
    638 
    639   defp load_naive_datetime_usec(_), do: :error
    640 
    641   # This is an upcast but because we assume the database
    642   # is always in UTC, we can perform it.
    643   defp load_utc_datetime(%NaiveDateTime{} = naive_datetime),
    644     do: {:ok, naive_datetime |> truncate_usec() |> DateTime.from_naive!("Etc/UTC")}
    645 
    646   defp load_utc_datetime(%DateTime{} = datetime),
    647     do: {:ok, datetime |> check_utc_timezone!(:utc_datetime) |> truncate_usec()}
    648 
    649   defp load_utc_datetime(_),
    650     do: :error
    651 
    652   defp load_utc_datetime_usec(%NaiveDateTime{} = naive_datetime),
    653     do: {:ok, naive_datetime |> pad_usec() |> DateTime.from_naive!("Etc/UTC")}
    654 
    655   defp load_utc_datetime_usec(%DateTime{} = datetime),
    656     do: {:ok, datetime |> check_utc_timezone!(:utc_datetime_usec) |> pad_usec()}
    657 
    658   defp load_utc_datetime_usec(_),
    659     do: :error
    660 
    661   @doc """
    662   Casts a value to the given type.
    663 
    664   `cast/2` is used by the finder queries and changesets to cast outside values to
    665   specific types.
    666 
    667   Note that nil can be cast to all primitive types as data stores allow nil to be
    668   set on any column.
    669 
    670   NaN and infinite decimals are not supported, use custom types instead.
    671 
    672       iex> cast(:any, "whatever")
    673       {:ok, "whatever"}
    674 
    675       iex> cast(:any, nil)
    676       {:ok, nil}
    677       iex> cast(:string, nil)
    678       {:ok, nil}
    679 
    680       iex> cast(:integer, 1)
    681       {:ok, 1}
    682       iex> cast(:integer, "1")
    683       {:ok, 1}
    684       iex> cast(:integer, "1.0")
    685       :error
    686 
    687       iex> cast(:id, 1)
    688       {:ok, 1}
    689       iex> cast(:id, "1")
    690       {:ok, 1}
    691       iex> cast(:id, "1.0")
    692       :error
    693 
    694       iex> cast(:float, 1.0)
    695       {:ok, 1.0}
    696       iex> cast(:float, 1)
    697       {:ok, 1.0}
    698       iex> cast(:float, "1")
    699       {:ok, 1.0}
    700       iex> cast(:float, "1.0")
    701       {:ok, 1.0}
    702       iex> cast(:float, "1-foo")
    703       :error
    704 
    705       iex> cast(:boolean, true)
    706       {:ok, true}
    707       iex> cast(:boolean, false)
    708       {:ok, false}
    709       iex> cast(:boolean, "1")
    710       {:ok, true}
    711       iex> cast(:boolean, "0")
    712       {:ok, false}
    713       iex> cast(:boolean, "whatever")
    714       :error
    715 
    716       iex> cast(:string, "beef")
    717       {:ok, "beef"}
    718       iex> cast(:binary, "beef")
    719       {:ok, "beef"}
    720 
    721       iex> cast(:decimal, Decimal.new("1.0"))
    722       {:ok, Decimal.new("1.0")}
    723       iex> cast(:decimal, "1.0bad")
    724       :error
    725 
    726       iex> cast({:array, :integer}, [1, 2, 3])
    727       {:ok, [1, 2, 3]}
    728       iex> cast({:array, :integer}, ["1", "2", "3"])
    729       {:ok, [1, 2, 3]}
    730       iex> cast({:array, :string}, [1, 2, 3])
    731       :error
    732       iex> cast(:string, [1, 2, 3])
    733       :error
    734 
    735   """
    736   @spec cast(t, term) :: {:ok, term} | {:error, keyword()} | :error
    737   def cast({:parameterized, type, params}, value), do: type.cast(value, params)
    738   def cast({:in, _type}, nil), do: :error
    739   def cast(_type, nil), do: {:ok, nil}
    740 
    741   def cast({:maybe, type}, value) do
    742     case cast(type, value) do
    743       {:ok, _} = ok -> ok
    744       _ -> {:ok, value}
    745     end
    746   end
    747 
    748   def cast(type, value) do
    749     cast_fun(type).(value)
    750   end
    751 
    752   defp cast_fun(:integer), do: &cast_integer/1
    753   defp cast_fun(:float), do: &cast_float/1
    754   defp cast_fun(:boolean), do: &cast_boolean/1
    755   defp cast_fun(:map), do: &cast_map/1
    756   defp cast_fun(:string), do: &cast_binary/1
    757   defp cast_fun(:binary), do: &cast_binary/1
    758   defp cast_fun(:id), do: &cast_integer/1
    759   defp cast_fun(:binary_id), do: &cast_binary/1
    760   defp cast_fun(:any), do: &{:ok, &1}
    761   defp cast_fun(:decimal), do: &cast_decimal/1
    762   defp cast_fun(:date), do: &cast_date/1
    763   defp cast_fun(:time), do: &maybe_truncate_usec(cast_time(&1))
    764   defp cast_fun(:time_usec), do: &maybe_pad_usec(cast_time(&1))
    765   defp cast_fun(:naive_datetime), do: &maybe_truncate_usec(cast_naive_datetime(&1))
    766   defp cast_fun(:naive_datetime_usec), do: &maybe_pad_usec(cast_naive_datetime(&1))
    767   defp cast_fun(:utc_datetime), do: &maybe_truncate_usec(cast_utc_datetime(&1))
    768   defp cast_fun(:utc_datetime_usec), do: &maybe_pad_usec(cast_utc_datetime(&1))
    769   defp cast_fun({:param, :any_datetime}), do: &cast_any_datetime(&1)
    770   defp cast_fun({:parameterized, mod, params}), do: &mod.cast(&1, params)
    771   defp cast_fun({:in, type}), do: cast_fun({:array, type})
    772 
    773   defp cast_fun({:array, {:parameterized, _, _} = type}) do
    774     fun = cast_fun(type)
    775     &array(&1, fun, false, [])
    776   end
    777 
    778   defp cast_fun({:array, type}) do
    779     fun = cast_fun(type)
    780     &array(&1, fun, true, [])
    781   end
    782 
    783   defp cast_fun({:map, {:parameterized, _, _} = type}) do
    784     fun = cast_fun(type)
    785     &map(&1, fun, false, %{})
    786   end
    787 
    788   defp cast_fun({:map, type}) do
    789     fun = cast_fun(type)
    790     &map(&1, fun, true, %{})
    791   end
    792 
    793   defp cast_fun(mod) when is_atom(mod) do
    794     fn
    795       nil -> {:ok, nil}
    796       value -> mod.cast(value)
    797     end
    798   end
    799 
    800   defp cast_integer(term) when is_binary(term) do
    801     case Integer.parse(term) do
    802       {integer, ""} -> {:ok, integer}
    803       _ -> :error
    804     end
    805   end
    806 
    807   defp cast_integer(term) when is_integer(term), do: {:ok, term}
    808   defp cast_integer(_), do: :error
    809 
    810   defp cast_float(term) when is_binary(term) do
    811     case Float.parse(term) do
    812       {float, ""} -> {:ok, float}
    813       _ -> :error
    814     end
    815   end
    816 
    817   defp cast_float(term) when is_float(term), do: {:ok, term}
    818   defp cast_float(term) when is_integer(term), do: {:ok, :erlang.float(term)}
    819   defp cast_float(_), do: :error
    820 
    821   defp cast_decimal(term) when is_binary(term) do
    822     case Decimal.parse(term) do
    823       {:ok, decimal} -> check_decimal(decimal, false)
    824       # The following two clauses exist to support earlier versions of Decimal.
    825       {decimal, ""} -> check_decimal(decimal, false)
    826       {_, remainder} when is_binary(remainder) and byte_size(remainder) > 0 -> :error
    827       :error -> :error
    828     end
    829   end
    830   defp cast_decimal(term), do: same_decimal(term)
    831 
    832   defp cast_boolean(term) when term in ~w(true 1),  do: {:ok, true}
    833   defp cast_boolean(term) when term in ~w(false 0), do: {:ok, false}
    834   defp cast_boolean(term) when is_boolean(term), do: {:ok, term}
    835   defp cast_boolean(_), do: :error
    836 
    837   defp cast_binary(term) when is_binary(term), do: {:ok, term}
    838   defp cast_binary(_), do: :error
    839 
    840   defp cast_map(term) when is_map(term), do: {:ok, term}
    841   defp cast_map(_), do: :error
    842 
    843   ## Shared helpers
    844 
    845   @compile {:inline, same_integer: 1, same_boolean: 1, same_map: 1, same_decimal: 1, same_date: 1}
    846   defp same_integer(term) when is_integer(term), do: {:ok, term}
    847   defp same_integer(_), do: :error
    848 
    849   defp same_boolean(term) when is_boolean(term), do: {:ok, term}
    850   defp same_boolean(_), do: :error
    851 
    852   defp same_binary(term) when is_binary(term), do: {:ok, term}
    853   defp same_binary(_), do: :error
    854 
    855   defp same_map(term) when is_map(term), do: {:ok, term}
    856   defp same_map(_), do: :error
    857 
    858   defp same_decimal(term) when is_integer(term), do: {:ok, Decimal.new(term)}
    859   defp same_decimal(term) when is_float(term), do: {:ok, Decimal.from_float(term)}
    860   defp same_decimal(%Decimal{} = term), do: check_decimal(term, true)
    861   defp same_decimal(_), do: :error
    862 
    863   defp same_date(%Date{} = term), do: {:ok, term}
    864   defp same_date(_), do: :error
    865 
    866   @doc false
    867   @spec filter_empty_values(t, any, [any]) :: {:ok, any} | :empty
    868   def filter_empty_values({:array, type}, value, empty_values) when is_list(value) do
    869     value =
    870       for elem <- value,
    871         {:ok, elem} <- [filter_empty_values(type, elem, empty_values)],
    872         do: elem
    873 
    874     if value in empty_values do
    875       :empty
    876     else
    877       {:ok, value}
    878     end
    879   end
    880 
    881   def filter_empty_values(_type, value, empty_values) do
    882     if value in empty_values do
    883       :empty
    884     else
    885       {:ok, value}
    886     end
    887   end
    888 
    889   ## Adapter related
    890 
    891   @doc false
    892   def adapter_autogenerate(adapter, type) do
    893     type
    894     |> type()
    895     |> adapter.autogenerate()
    896   end
    897 
    898   @doc false
    899   def adapter_load(adapter, {:parameterized, module, params} = type, value) do
    900     process_loaders(adapter.loaders(module.type(params), type), {:ok, value}, adapter)
    901   end
    902   def adapter_load(_adapter, _type, nil) do
    903     {:ok, nil}
    904   end
    905   def adapter_load(adapter, type, value) do
    906     if of_base_type?(type, value) do
    907       {:ok, value}
    908     else
    909       process_loaders(adapter.loaders(type(type), type), {:ok, value}, adapter)
    910     end
    911   end
    912 
    913   defp process_loaders(_, :error, _adapter),
    914     do: :error
    915   defp process_loaders([fun|t], {:ok, value}, adapter) when is_function(fun),
    916     do: process_loaders(t, fun.(value), adapter)
    917   defp process_loaders([type|t], {:ok, value}, adapter),
    918     do: process_loaders(t, load(type, value, &adapter_load(adapter, &1, &2)), adapter)
    919   defp process_loaders([], {:ok, _} = acc, _adapter),
    920     do: acc
    921 
    922   @doc false
    923   def adapter_dump(adapter, {:parameterized, module, params} = type, value) do
    924     process_dumpers(adapter.dumpers(module.type(params), type), {:ok, value}, adapter)
    925   end
    926   def adapter_dump(_adapter, type, nil) do
    927     dump(type, nil)
    928   end
    929   def adapter_dump(adapter, type, value) do
    930     process_dumpers(adapter.dumpers(type(type), type), {:ok, value}, adapter)
    931   end
    932 
    933   defp process_dumpers(_, :error, _adapter),
    934     do: :error
    935   defp process_dumpers([fun|t], {:ok, value}, adapter) when is_function(fun),
    936     do: process_dumpers(t, fun.(value), adapter)
    937   defp process_dumpers([type|t], {:ok, value}, adapter),
    938     do: process_dumpers(t, dump(type, value, &adapter_dump(adapter, &1, &2)), adapter)
    939   defp process_dumpers([], {:ok, _} = acc, _adapter),
    940     do: acc
    941 
    942   ## Date
    943 
    944   defp cast_date(binary) when is_binary(binary) do
    945     case Date.from_iso8601(binary) do
    946       {:ok, _} = ok ->
    947         ok
    948       {:error, _} ->
    949         case NaiveDateTime.from_iso8601(binary) do
    950           {:ok, naive_datetime} -> {:ok, NaiveDateTime.to_date(naive_datetime)}
    951           {:error, _} -> :error
    952         end
    953     end
    954   end
    955   defp cast_date(%{"year" => empty, "month" => empty, "day" => empty}) when empty in ["", nil],
    956     do: {:ok, nil}
    957   defp cast_date(%{year: empty, month: empty, day: empty}) when empty in ["", nil],
    958     do: {:ok, nil}
    959   defp cast_date(%{"year" => year, "month" => month, "day" => day}),
    960     do: cast_date(to_i(year), to_i(month), to_i(day))
    961   defp cast_date(%{year: year, month: month, day: day}),
    962     do: cast_date(to_i(year), to_i(month), to_i(day))
    963   defp cast_date(_),
    964     do: :error
    965 
    966   defp cast_date(year, month, day) when is_integer(year) and is_integer(month) and is_integer(day) do
    967     case Date.new(year, month, day) do
    968       {:ok, _} = ok -> ok
    969       {:error, _} -> :error
    970     end
    971   end
    972   defp cast_date(_, _, _),
    973     do: :error
    974 
    975   ## Time
    976 
    977   defp cast_time(<<hour::2-bytes, ?:, minute::2-bytes>>),
    978     do: cast_time(to_i(hour), to_i(minute), 0, nil)
    979   defp cast_time(binary) when is_binary(binary) do
    980     case Time.from_iso8601(binary) do
    981       {:ok, _} = ok -> ok
    982       {:error, _} -> :error
    983     end
    984   end
    985   defp cast_time(%{"hour" => empty, "minute" => empty}) when empty in ["", nil],
    986     do: {:ok, nil}
    987   defp cast_time(%{hour: empty, minute: empty}) when empty in ["", nil],
    988     do: {:ok, nil}
    989   defp cast_time(%{"hour" => hour, "minute" => minute} = map),
    990     do: cast_time(to_i(hour), to_i(minute), to_i(Map.get(map, "second")), to_i(Map.get(map, "microsecond")))
    991   defp cast_time(%{hour: hour, minute: minute, second: second, microsecond: {microsecond, precision}}),
    992     do: cast_time(to_i(hour), to_i(minute), to_i(second), {to_i(microsecond), to_i(precision)})
    993   defp cast_time(%{hour: hour, minute: minute} = map),
    994     do: cast_time(to_i(hour), to_i(minute), to_i(Map.get(map, :second)), to_i(Map.get(map, :microsecond)))
    995   defp cast_time(_),
    996     do: :error
    997 
    998   defp cast_time(hour, minute, sec, usec) when is_integer(usec) do
    999     cast_time(hour, minute, sec, {usec, 6})
   1000   end
   1001   defp cast_time(hour, minute, sec, nil) do
   1002     cast_time(hour, minute, sec, {0, 0})
   1003   end
   1004   defp cast_time(hour, minute, sec, {usec, precision})
   1005        when is_integer(hour) and is_integer(minute) and
   1006             (is_integer(sec) or is_nil(sec)) and is_integer(usec) and is_integer(precision) do
   1007     case Time.new(hour, minute, sec || 0, {usec, precision}) do
   1008       {:ok, _} = ok -> ok
   1009       {:error, _} -> :error
   1010     end
   1011   end
   1012   defp cast_time(_, _, _, _) do
   1013     :error
   1014   end
   1015 
   1016   defp cast_any_datetime(%DateTime{} = datetime), do: cast_utc_datetime(datetime)
   1017   defp cast_any_datetime(other), do: cast_naive_datetime(other)
   1018 
   1019   ## Naive datetime
   1020 
   1021   defp cast_naive_datetime("-" <> rest) do
   1022     with {:ok, naive_datetime} <- cast_naive_datetime(rest) do
   1023       {:ok, %{naive_datetime | year: naive_datetime.year * -1}}
   1024     end
   1025   end
   1026 
   1027   defp cast_naive_datetime(<<year::4-bytes, ?-, month::2-bytes, ?-, day::2-bytes, sep, hour::2-bytes, ?:, minute::2-bytes>>)
   1028        when sep in [?\s, ?T] do
   1029     case NaiveDateTime.new(to_i(year), to_i(month), to_i(day), to_i(hour), to_i(minute), 0) do
   1030       {:ok, _} = ok -> ok
   1031       _ -> :error
   1032     end
   1033   end
   1034 
   1035   defp cast_naive_datetime(binary) when is_binary(binary) do
   1036     case NaiveDateTime.from_iso8601(binary) do
   1037       {:ok, _} = ok -> ok
   1038       {:error, _} -> :error
   1039     end
   1040   end
   1041 
   1042   defp cast_naive_datetime(%{"year" => empty, "month" => empty, "day" => empty,
   1043                              "hour" => empty, "minute" => empty}) when empty in ["", nil],
   1044     do: {:ok, nil}
   1045 
   1046   defp cast_naive_datetime(%{year: empty, month: empty, day: empty,
   1047                              hour: empty, minute: empty}) when empty in ["", nil],
   1048     do: {:ok, nil}
   1049 
   1050   defp cast_naive_datetime(%{} = map) do
   1051     with {:ok, %Date{} = date} <- cast_date(map),
   1052          {:ok, %Time{} = time} <- cast_time(map) do
   1053       NaiveDateTime.new(date, time)
   1054     else
   1055       _ -> :error
   1056     end
   1057   end
   1058 
   1059   defp cast_naive_datetime(_) do
   1060     :error
   1061   end
   1062 
   1063   ## UTC datetime
   1064 
   1065   defp cast_utc_datetime("-" <> rest) do
   1066     with {:ok, utc_datetime} <- cast_utc_datetime(rest) do
   1067       {:ok, %{utc_datetime | year: utc_datetime.year * -1}}
   1068     end
   1069   end
   1070 
   1071   defp cast_utc_datetime(<<year::4-bytes, ?-, month::2-bytes, ?-, day::2-bytes, sep, hour::2-bytes, ?:, minute::2-bytes>>)
   1072        when sep in [?\s, ?T] do
   1073     case NaiveDateTime.new(to_i(year), to_i(month), to_i(day), to_i(hour), to_i(minute), 0) do
   1074       {:ok, naive_datetime} -> {:ok, DateTime.from_naive!(naive_datetime, "Etc/UTC")}
   1075       _ -> :error
   1076     end
   1077   end
   1078 
   1079   defp cast_utc_datetime(binary) when is_binary(binary) do
   1080     case DateTime.from_iso8601(binary) do
   1081       {:ok, datetime, _offset} -> {:ok, datetime}
   1082       {:error, :missing_offset} ->
   1083         case NaiveDateTime.from_iso8601(binary) do
   1084           {:ok, naive_datetime} -> {:ok, DateTime.from_naive!(naive_datetime, "Etc/UTC")}
   1085           {:error, _} -> :error
   1086         end
   1087       {:error, _} -> :error
   1088     end
   1089   end
   1090   defp cast_utc_datetime(%DateTime{time_zone: "Etc/UTC"} = datetime), do: {:ok, datetime}
   1091   defp cast_utc_datetime(%DateTime{} = datetime) do
   1092     case (datetime |> DateTime.to_unix(:microsecond) |> DateTime.from_unix(:microsecond)) do
   1093       {:ok, _} = ok -> ok
   1094       {:error, _} -> :error
   1095     end
   1096   end
   1097   defp cast_utc_datetime(value) do
   1098     case cast_naive_datetime(value) do
   1099       {:ok, %NaiveDateTime{} = naive_datetime} ->
   1100         {:ok, DateTime.from_naive!(naive_datetime, "Etc/UTC")}
   1101       {:ok, _} = ok ->
   1102         ok
   1103       :error ->
   1104         :error
   1105     end
   1106   end
   1107 
   1108   @doc """
   1109   Checks if two terms are equal.
   1110 
   1111   Depending on the given `type` performs a structural or semantical comparison.
   1112 
   1113   ## Examples
   1114 
   1115       iex> equal?(:integer, 1, 1)
   1116       true
   1117       iex> equal?(:decimal, Decimal.new("1"), Decimal.new("1.00"))
   1118       true
   1119 
   1120   """
   1121   @spec equal?(t, term, term) :: boolean
   1122   def equal?(_, nil, nil), do: true
   1123 
   1124   def equal?(type, term1, term2) do
   1125     if fun = equal_fun(type) do
   1126       fun.(term1, term2)
   1127     else
   1128       term1 == term2
   1129     end
   1130   end
   1131 
   1132   @doc """
   1133   Checks if `collection` includes a `term`.
   1134 
   1135   Depending on the given `type` performs a structural or semantical comparison.
   1136 
   1137   ## Examples
   1138 
   1139       iex> include?(:integer, 1, 1..3)
   1140       true
   1141       iex> include?(:decimal, Decimal.new("1"), [Decimal.new("1.00"), Decimal.new("2.00")])
   1142       true
   1143 
   1144   """
   1145   @spec include?(t, term, Enum.t()) :: boolean
   1146   def include?(type, term, collection) do
   1147     if fun = equal_fun(type) do
   1148       Enum.any?(collection, &fun.(term, &1))
   1149     else
   1150       term in collection
   1151     end
   1152   end
   1153 
   1154   defp equal_fun(:decimal), do: &equal_decimal?/2
   1155   defp equal_fun(t) when t in [:time, :time_usec], do: &equal_time?/2
   1156   defp equal_fun(t) when t in [:utc_datetime, :utc_datetime_usec], do: &equal_utc_datetime?/2
   1157   defp equal_fun(t) when t in [:naive_datetime, :naive_datetime_usec], do: &equal_naive_datetime?/2
   1158   defp equal_fun(t) when t in @base, do: nil
   1159 
   1160   defp equal_fun({:array, type}) do
   1161     if fun = equal_fun(type) do
   1162       &equal_list?(fun, &1, &2)
   1163     end
   1164   end
   1165 
   1166   defp equal_fun({:map, type}) do
   1167     if fun = equal_fun(type) do
   1168       &equal_map?(fun, &1, &2)
   1169     end
   1170   end
   1171 
   1172   defp equal_fun({:parameterized, mod, params}) do
   1173     &mod.equal?(&1, &2, params)
   1174   end
   1175 
   1176   defp equal_fun(mod) when is_atom(mod), do: &mod.equal?/2
   1177 
   1178   defp equal_decimal?(%Decimal{} = a, %Decimal{} = b), do: Decimal.equal?(a, b)
   1179   defp equal_decimal?(_, _), do: false
   1180 
   1181   defp equal_time?(%Time{} = a, %Time{} = b), do: Time.compare(a, b) == :eq
   1182   defp equal_time?(_, _), do: false
   1183 
   1184   defp equal_utc_datetime?(%DateTime{} = a, %DateTime{} = b), do: DateTime.compare(a, b) == :eq
   1185   defp equal_utc_datetime?(_, _), do: false
   1186 
   1187   defp equal_naive_datetime?(%NaiveDateTime{} = a, %NaiveDateTime{} = b),
   1188     do: NaiveDateTime.compare(a, b) == :eq
   1189   defp equal_naive_datetime?(_, _),
   1190     do: false
   1191 
   1192   defp equal_list?(fun, [nil | xs], [nil | ys]), do: equal_list?(fun, xs, ys)
   1193   defp equal_list?(fun, [x | xs], [y | ys]), do: fun.(x, y) and equal_list?(fun, xs, ys)
   1194   defp equal_list?(_fun, [], []), do: true
   1195   defp equal_list?(_fun, _, _), do: false
   1196 
   1197   defp equal_map?(_fun, map1, map2) when map_size(map1) != map_size(map2) do
   1198     false
   1199   end
   1200 
   1201   defp equal_map?(fun, %{} = map1, %{} = map2) do
   1202     equal_map?(fun, Map.to_list(map1), map2)
   1203   end
   1204 
   1205   defp equal_map?(fun, [{key, nil} | tail], other_map) do
   1206     case other_map do
   1207       %{^key => nil} -> equal_map?(fun, tail, other_map)
   1208       _ -> false
   1209     end
   1210   end
   1211 
   1212   defp equal_map?(fun, [{key, val} | tail], other_map) do
   1213     case other_map do
   1214       %{^key => other_val} -> fun.(val, other_val) and equal_map?(fun, tail, other_map)
   1215       _ -> false
   1216     end
   1217   end
   1218 
   1219   defp equal_map?(_fun, [], _) do
   1220     true
   1221   end
   1222 
   1223   defp equal_map?(_fun, _, _) do
   1224     false
   1225   end
   1226 
   1227   ## Helpers
   1228 
   1229   # Checks if a value is of the given primitive type.
   1230   defp of_base_type?(:any, _), do: true
   1231   defp of_base_type?(:id, term), do: is_integer(term)
   1232   defp of_base_type?(:float, term), do: is_float(term)
   1233   defp of_base_type?(:integer, term), do: is_integer(term)
   1234   defp of_base_type?(:boolean, term), do: is_boolean(term)
   1235   defp of_base_type?(:binary, term), do: is_binary(term)
   1236   defp of_base_type?(:string, term), do: is_binary(term)
   1237   defp of_base_type?(:map, term), do: is_map(term) and not Map.has_key?(term, :__struct__)
   1238   defp of_base_type?(:decimal, value), do: Kernel.match?(%Decimal{}, value)
   1239   defp of_base_type?(:date, value), do: Kernel.match?(%Date{}, value)
   1240   defp of_base_type?(_, _), do: false
   1241 
   1242   defp array([nil | t], fun, true, acc) do
   1243     array(t, fun, true, [nil | acc])
   1244   end
   1245 
   1246   defp array([h | t], fun, skip_nil?, acc) do
   1247     case fun.(h) do
   1248       {:ok, h} -> array(t, fun, skip_nil?, [h | acc])
   1249       :error -> :error
   1250       {:error, _custom_errors} -> :error
   1251     end
   1252   end
   1253 
   1254   defp array([], _fun, _skip_nil?,acc) do
   1255     {:ok, Enum.reverse(acc)}
   1256   end
   1257 
   1258   defp array(_, _, _, _) do
   1259     :error
   1260   end
   1261 
   1262   defp map(map, fun, skip_nil?, acc) when is_map(map) do
   1263     map_each(Map.to_list(map), fun, skip_nil?, acc)
   1264   end
   1265 
   1266   defp map(_, _, _, _) do
   1267     :error
   1268   end
   1269 
   1270   defp map_each([{key, nil} | t], fun, true, acc) do
   1271     map_each(t, fun, true, Map.put(acc, key, nil))
   1272   end
   1273 
   1274   defp map_each([{key, value} | t], fun, skip_nil?, acc) do
   1275     case fun.(value) do
   1276       {:ok, value} -> map_each(t, fun, skip_nil?, Map.put(acc, key, value))
   1277       :error -> :error
   1278       {:error, _custom_errors} -> :error
   1279     end
   1280   end
   1281 
   1282   defp map_each([], _fun, _skip_nil?, acc) do
   1283     {:ok, acc}
   1284   end
   1285 
   1286   defp array([nil | t], type, fun, true, acc) do
   1287     array(t, type, fun, true, [nil | acc])
   1288   end
   1289 
   1290   defp array([h | t], type, fun, skip_nil?, acc) do
   1291     case fun.(type, h) do
   1292       {:ok, h} -> array(t, type, fun, skip_nil?, [h | acc])
   1293       :error -> :error
   1294     end
   1295   end
   1296 
   1297   defp array([], _type, _fun, _skip_nil?, acc) do
   1298     {:ok, Enum.reverse(acc)}
   1299   end
   1300 
   1301   defp array(_, _, _, _, _) do
   1302     :error
   1303   end
   1304 
   1305   defp map(map, type, fun, skip_nil?, acc) when is_map(map) do
   1306     map_each(Map.to_list(map), type, fun, skip_nil?, acc)
   1307   end
   1308 
   1309   defp map(_, _, _, _, _) do
   1310     :error
   1311   end
   1312 
   1313   defp map_each([{key, value} | t], type, fun, skip_nil?, acc) do
   1314     case fun.(type, value) do
   1315       {:ok, value} -> map_each(t, type, fun, skip_nil?, Map.put(acc, key, value))
   1316       :error -> :error
   1317     end
   1318   end
   1319 
   1320   defp map_each([], _type, _fun, _skip_nil?, acc) do
   1321     {:ok, acc}
   1322   end
   1323 
   1324   defp to_i(nil), do: nil
   1325   defp to_i(int) when is_integer(int), do: int
   1326   defp to_i(bin) when is_binary(bin) do
   1327     case Integer.parse(bin) do
   1328       {int, ""} -> int
   1329       _ -> nil
   1330     end
   1331   end
   1332 
   1333   defp maybe_truncate_usec({:ok, struct}), do: {:ok, truncate_usec(struct)}
   1334   defp maybe_truncate_usec(:error), do: :error
   1335 
   1336   defp maybe_pad_usec({:ok, struct}), do: {:ok, pad_usec(struct)}
   1337   defp maybe_pad_usec(:error), do: :error
   1338 
   1339   defp truncate_usec(nil), do: nil
   1340   defp truncate_usec(%{microsecond: {0, 0}} = struct), do: struct
   1341   defp truncate_usec(struct), do: %{struct | microsecond: {0, 0}}
   1342 
   1343   defp pad_usec(nil), do: nil
   1344   defp pad_usec(%{microsecond: {_, 6}} = struct), do: struct
   1345 
   1346   defp pad_usec(%{microsecond: {microsecond, _}} = struct),
   1347     do: %{struct | microsecond: {microsecond, 6}}
   1348 
   1349   defp check_utc_timezone!(%{time_zone: "Etc/UTC"} = datetime, _kind), do: datetime
   1350 
   1351   defp check_utc_timezone!(datetime, kind) do
   1352     raise ArgumentError,
   1353           "#{inspect kind} expects the time zone to be \"Etc/UTC\", got `#{inspect(datetime)}`"
   1354   end
   1355 
   1356   defp check_usec!(%{microsecond: {_, 6}} = datetime, _kind), do: datetime
   1357 
   1358   defp check_usec!(datetime, kind) do
   1359     raise ArgumentError,
   1360           "#{inspect(kind)} expects microsecond precision, got: #{inspect(datetime)}"
   1361   end
   1362 
   1363   defp check_no_usec!(%{microsecond: {0, 0}} = datetime, _kind), do: datetime
   1364 
   1365   defp check_no_usec!(%struct{} = datetime, kind) do
   1366     raise ArgumentError, """
   1367     #{inspect(kind)} expects microseconds to be empty, got: #{inspect(datetime)}
   1368 
   1369     Use `#{inspect(struct)}.truncate(#{kind}, :second)` (available in Elixir v1.6+) to remove microseconds.
   1370     """
   1371   end
   1372 
   1373   defp check_decimal(%Decimal{coef: coef} = decimal, _) when is_integer(coef), do: {:ok, decimal}
   1374   defp check_decimal(_decimal, false), do: :error
   1375   defp check_decimal(decimal, true) do
   1376     raise ArgumentError, """
   1377     #{inspect(decimal)} is not allowed for type :decimal
   1378 
   1379     `+Infinity`, `-Infinity`, and `NaN` values are not supported, even though the `Decimal` library handles them. \
   1380     To support them, you can create a custom type.
   1381     """
   1382   end
   1383 end