This commit is contained in:
2026-07-14 22:50:46 +04:00
parent 27143319e3
commit bd19e0682b
3116 changed files with 467189 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
defmodule Ecto.Adapters.SQLite3.Codec do
@moduledoc false
def bool_decode(0), do: {:ok, false}
def bool_decode("0"), do: {:ok, false}
def bool_decode("FALSE"), do: {:ok, false}
def bool_decode(1), do: {:ok, true}
def bool_decode("1"), do: {:ok, true}
def bool_decode("TRUE"), do: {:ok, true}
def bool_decode(v), do: {:ok, v}
def json_decode(v) when is_binary(v) do
case Application.get_env(:ecto_sqlite3, :json_library, Jason).decode(v) do
{:ok, decoded} -> {:ok, decoded}
{:error, _reason} -> :error
end
end
def json_decode(v), do: {:ok, v}
def float_decode(%Decimal{} = decimal), do: {:ok, Decimal.to_float(decimal)}
def float_decode(x) when is_integer(x), do: {:ok, x / 1}
def float_decode(x), do: {:ok, x}
def decimal_decode(nil), do: {:ok, nil}
def decimal_decode(x) when is_float(x) do
{:ok, Decimal.from_float(x)}
catch
Decimal.Error -> :error
end
def decimal_decode(x) when is_binary(x) or is_integer(x) do
{:ok, Decimal.new(x)}
catch
Decimal.Error -> :error
end
def decimal_decode(_), do: :error
def utc_datetime_decode(nil), do: {:ok, nil}
def utc_datetime_decode(val) do
with {:ok, naive} <- NaiveDateTime.from_iso8601(val),
{:ok, dt} <- DateTime.from_naive(naive, "Etc/UTC") do
{:ok, dt}
else
_ -> :error
end
end
def naive_datetime_decode(nil), do: {:ok, nil}
def naive_datetime_decode(val) do
case NaiveDateTime.from_iso8601(val) do
{:ok, dt} -> {:ok, dt}
_ -> :error
end
end
def date_decode(nil), do: {:ok, nil}
def date_decode(val) do
case Date.from_iso8601(val) do
{:ok, d} -> {:ok, d}
_ -> :error
end
end
def date_encode(val), do: date_encode(val, :iso8601)
def date_encode(%Date{} = val, :iso8601) do
case Date.to_iso8601(val) do
date when is_bitstring(date) -> {:ok, date}
_ -> :error
end
end
def time_decode(nil), do: {:ok, nil}
def time_decode(%Time{} = value) do
{:ok, value}
end
def time_decode(value) do
case Time.from_iso8601(value) do
{:ok, _time} = result -> result
{:error, _} -> :error
end
end
def json_encode(value) when is_bitstring(value), do: {:ok, value}
def json_encode(value) do
{:ok, Application.get_env(:ecto_sqlite3, :json_library, Jason).encode!(value)}
rescue
_err -> :error
end
def blob_encode(nil), do: {:ok, nil}
def blob_encode(value), do: {:ok, {:blob, value}}
def bool_encode(nil), do: {:ok, nil}
def bool_encode(false), do: {:ok, 0}
def bool_encode(true), do: {:ok, 1}
def decimal_encode(nil), do: {:ok, nil}
def decimal_encode(%Decimal{} = x) do
{:ok, Decimal.to_string(x, :normal)}
end
def time_encode(value) do
{:ok, value}
end
@text_datetime_format "%Y-%m-%d %H:%M:%S"
def utc_datetime_encode(nil, :iso8601), do: {:ok, nil}
def utc_datetime_encode(nil, :text_datetime), do: {:ok, nil}
def utc_datetime_encode(%DateTime{time_zone: "Etc/UTC"} = value, :iso8601) do
{:ok, DateTime.to_iso8601(value)}
end
def utc_datetime_encode(%{time_zone: "Etc/UTC"} = value, :text_datetime) do
{:ok, Calendar.strftime(value, @text_datetime_format)}
end
def utc_datetime_encode(%{time_zone: "Etc/UTC"}, type) do
raise ArgumentError,
"expected datetime type to be either `:iso8601` or `:text_datetime`, but received #{inspect(type)}"
end
def naive_datetime_encode(nil, :iso8601), do: {:ok, nil}
def naive_datetime_encode(nil, :text_datetime), do: {:ok, nil}
def naive_datetime_encode(value, :iso8601) do
{:ok, NaiveDateTime.to_iso8601(value)}
end
def naive_datetime_encode(value, :text_datetime) do
{:ok, Calendar.strftime(value, @text_datetime_format)}
end
def naive_datetime_encode(_value, type) do
raise ArgumentError,
"expected datetime type to be either `:iso8601` or `:text_datetime`, but received `#{inspect(type)}`"
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
defmodule Ecto.Adapters.SQLite3.DataType do
@moduledoc false
# Simple column types. Note that we ignore options like :size, :precision,
# etc. because columns do not have types, and SQLite will not coerce any
# stored value. Thus, "strings" are all text and "numerics" have arbitrary
# precision regardless of the declared column type. Decimals are the
# only exception.
@spec column_type(atom(), Keyword.t()) :: String.t()
def column_type(:id, _opts), do: "INTEGER"
def column_type(:serial, _opts), do: "INTEGER"
def column_type(:bigserial, _opts), do: "INTEGER"
def column_type(:boolean, _opts), do: "INTEGER"
def column_type(:integer, _opts), do: "INTEGER"
def column_type(:bigint, _opts), do: "INTEGER"
def column_type(:string, _opts), do: "TEXT"
def column_type(:float, _opts), do: "NUMERIC"
def column_type(:binary, _opts), do: "BLOB"
def column_type(:date, _opts), do: "TEXT"
def column_type(:utc_datetime, _opts), do: "TEXT"
def column_type(:utc_datetime_usec, _opts), do: "TEXT"
def column_type(:naive_datetime, _opts), do: "TEXT"
def column_type(:naive_datetime_usec, _opts), do: "TEXT"
def column_type(:time, _opts), do: "TEXT"
def column_type(:time_usec, _opts), do: "TEXT"
def column_type(:timestamp, _opts), do: "TEXT"
def column_type(:decimal, nil), do: "DECIMAL"
def column_type(:decimal, opts) do
# We only store precision and scale for DECIMAL.
precision = Keyword.get(opts, :precision)
scale = Keyword.get(opts, :scale, 0)
if precision do
"DECIMAL(#{precision},#{scale})"
else
"DECIMAL"
end
end
def column_type(:array, _opts) do
case Application.get_env(:ecto_sqlite3, :array_type, :string) do
:string -> "TEXT"
:binary -> "BLOB"
end
end
def column_type({:array, _}, _opts) do
case Application.get_env(:ecto_sqlite3, :array_type, :string) do
:string -> "TEXT"
:binary -> "BLOB"
end
end
def column_type(:binary_id, _opts) do
case Application.get_env(:ecto_sqlite3, :binary_id_type, :string) do
:string -> "TEXT"
:binary -> "BLOB"
end
end
def column_type(:map, _opts) do
case Application.get_env(:ecto_sqlite3, :map_type, :string) do
:string -> "TEXT"
:binary -> "BLOB"
end
end
def column_type({:map, _}, _opts) do
case Application.get_env(:ecto_sqlite3, :map_type, :string) do
:string -> "TEXT"
:binary -> "BLOB"
end
end
def column_type(:uuid, _opts) do
case Application.get_env(:ecto_sqlite3, :uuid_type, :string) do
:string -> "TEXT"
:binary -> "BLOB"
end
end
def column_type(type, _) when is_atom(type) do
type
|> Atom.to_string()
|> String.upcase()
end
def column_type(type, _) do
raise ArgumentError,
"unsupported type `#{inspect(type)}`. The type can either be an atom, a string " <>
"or a tuple of the form `{:map, t}` or `{:array, t}` where `t` itself follows the same conditions."
end
end

View File

@@ -0,0 +1,31 @@
defmodule Ecto.Adapters.SQLite3.TypeExtension do
@moduledoc """
A behaviour that defines the API for extensions providing custom data loaders and dumpers
for Ecto schemas.
"""
@type primitive_type :: atom | {:map, type :: atom}
@type ecto_type :: atom
@doc """
Takes a primitive type and, if it knows how to decode it into an
appropriate Elixir data structure, returns a two-element list in
the form `[(db_data :: any -> term), elixir_type :: atom]`.
The function that is the first element will be called whenever
the `primitive_type` appears in a schema and data is fetched from
the database for it.
"""
@callback loaders(primitive_type, ecto_type) :: list | nil
@doc """
Takes a primitive type and, if it knows how to encode it for storage
in the database, returns a two-element list in
the form `[elixir_type :: atom, (term -> db_data :: any)]`.
The function that is the second element will be called whenever
the `primitive_type` appears in a schema and data is about to be
sent to the database for storage.
"""
@callback dumpers(ecto_type, primitive_type) :: list | nil
end