Packages
ecto_tablestore
0.15.1
0.15.1
0.15.0
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.1
0.10.0
0.9.0
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.1
0.6.0
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
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.0
0.1.0
Alibaba Tablestore adapter for Ecto
Current section
Files
Jump to
Current section
Files
lib/ecto/replaceable_string.ex
defmodule Ecto.ReplaceableString do
@moduledoc """
A custom type that replace some terms for strings.
`#{inspect(__MODULE__)}` can be used when you want to replace some terms on dump/load
a field, or even both included, for example:
Before a field persisted to the database, `#{inspect(__MODULE__)}` replaces a matched pattern
with the replacement, the final replaced value will be saved into database.
field :content, #{inspect(__MODULE__)},
on_dump: pattern: "hello", replacement: "hi", options: [global: false]
After a field loaded from the database, `#{inspect(__MODULE__)}` replaces a matched pattern
with the replacement, the final replaced value will be extracted into the struct, but
no changes into the original database.
field :content, #{inspect(__MODULE__)},
on_load: pattern: ~r/test/, replacement: "TEST"
The `:pattern` and `:replacement` options are a pair required when both existed, the `:options` option
is optional, these three options are correspond completely to `String.replace/4`.
If no `:on_dump` or `:on_load` option(s) set, the following cases are equal from result perspective, but
recommend to use the `:string` type as a base type:
field :content, #{inspect(__MODULE__)}
# equals
field :content, :string
Please notice that once used this type means a string replacement will be invoked in each read or write operation
to the corresponding field, so please ensure use this type in a proper scenario to avoid a wasted performance issue,
or find a better way to satisfy the similar use case.
"""
use Ecto.ParameterizedType
@doc false
@impl true
def type(_params), do: :string
@doc false
@impl true
def init(opts) do
opts
|> Keyword.take([:on_dump, :on_load])
|> Enum.reduce(%{}, fn {key, opts}, acc ->
prepare_init(key, opts, acc)
end)
end
@doc false
@impl true
def cast(nil, _params), do: {:ok, nil}
def cast(data, _params) when not is_bitstring(data), do: :error
def cast(data, _params) do
{:ok, data}
end
@doc false
@impl true
def load(nil, _loader, _params), do: {:ok, nil}
def load(data, _loader, %{on_load: %{pattern: pattern, replacement: replacement} = on_load}) do
data = String.replace(data, pattern, replacement, Map.get(on_load, :options, []))
{:ok, data}
end
def load(data, _loader, _params), do: {:ok, data}
@doc false
@impl true
def dump(nil, _dumper, _params), do: {:ok, nil}
def dump(data, _dumper, %{on_dump: %{pattern: pattern, replacement: replacement} = on_dump}) do
data = String.replace(data, pattern, replacement, Map.get(on_dump, :options, []))
{:ok, data}
end
def dump(data, _dumper, _params), do: {:ok, data}
@doc false
@impl true
def embed_as(_format, _params) do
# make sure `load/3` will be invoked when use `on_load` case.
:dump
end
@doc false
@impl true
def equal?(a, b, _params), do: a == b
defp prepare_init(_key, nil, acc), do: acc
defp prepare_init(key, opts, acc) do
opts
|> Keyword.take([:pattern, :replacement, :options])
|> Enum.into(%{})
|> validate(key, acc)
end
defp validate(opts, _key, acc) when opts === %{} do
acc
end
defp validate(%{pattern: pattern, replacement: replacement} = opts, key, acc)
when pattern != nil and is_bitstring(replacement) do
Map.put(acc, key, opts)
end
defp validate(opts, key, _acc) do
raise ArgumentError, """
#{inspect(__MODULE__)} type must both have a `:pattern` option specified as a string or a regex
type and a `:replacement` option as a string type for `#{key}` key,
but got `#{inspect(opts)}`, they are same to String.replace/4.
For example:
field :my_field, EctoTablestore.Replaceable, on_dump:
pattern: "a,b,c", replacement: ","
or
field :my_field, EctoTablestore.Replaceable, on_dump:
pattern: "a,b,c", replacement: ",", options: [global: false]
"""
end
end