105 lines
2.3 KiB
Elixir
105 lines
2.3 KiB
Elixir
defmodule ISN do
|
|
@behaviour Postgrex.Extension
|
|
@isn ~w(ean13 isbn13 ismn13 issn13 isbn ismn issn upc)
|
|
|
|
@moduledoc """
|
|
A Postgrex.Extension enabling the use of postgresql data types from the isn
|
|
extension.
|
|
|
|
In lib/ directory create a file with the following content:
|
|
|
|
Postgrex.Types.define(MyApp.PostgrexTypes, [ISN], [])
|
|
|
|
Add the following lines in conig.exs:
|
|
|
|
config :my_app, MyApp.Repo,
|
|
types: MyApp.PostgrexTypes
|
|
|
|
Then you can do Ecto.Migrations like this:
|
|
|
|
defmodule MyApp.Repo.Migrations.CreateBook do
|
|
use Ecto.Migration
|
|
|
|
def change do
|
|
create table(:books) do
|
|
add :isbn, :isbn13
|
|
# other fields
|
|
end
|
|
end
|
|
end
|
|
|
|
You can also define Ecto.Models using the matching custom Ecto.Types:
|
|
|
|
defmodule MyApp.Book do
|
|
use MyApp.Web, :model
|
|
|
|
schema "books" do
|
|
field :isbn, ISN.ISBN13, read_after_writes: true
|
|
# other fields
|
|
end
|
|
end
|
|
"""
|
|
|
|
def init(opts), do: Keyword.get(opts, :decode_copy, :reference)
|
|
|
|
def matching(_), do: Enum.zip(Stream.cycle([:type]), @isn)
|
|
|
|
def format(_), do: :text
|
|
|
|
def encode(_opts) do
|
|
quote do
|
|
thing ->
|
|
[<<IO.iodata_length(thing)::int32()>> | thing]
|
|
end
|
|
end
|
|
|
|
def decode(:copy) do
|
|
quote do
|
|
<<len::int32(), thing::binary-size(len)>> ->
|
|
:binary.copy(thing)
|
|
end
|
|
end
|
|
|
|
def decode(:reference) do
|
|
quote do
|
|
<<len::int32(), thing::binary-size(len)>> ->
|
|
thing
|
|
end
|
|
end
|
|
end
|
|
|
|
# Generate Ecto.Type modules for all supported data types in the `isn`
|
|
# postgresql module.
|
|
for module <- ~w(ISBN ISMN ISSN ISBN13 ISMN13 ISSN13 UPC EAN13) do
|
|
module_name = Module.concat([ISN, module])
|
|
ecto_type = module |> String.downcase() |> String.to_atom()
|
|
|
|
defmodule module_name do
|
|
@moduledoc """
|
|
Definition for the ISN.#{module} module.
|
|
|
|
How to use this in an Ecto.Model
|
|
|
|
defmodule MyApp.Thing do
|
|
use MyApp.Web, :model
|
|
|
|
schema "things" do
|
|
field :#{ecto_type}, ISN.#{module}
|
|
# other fields
|
|
end
|
|
end
|
|
"""
|
|
|
|
use Ecto.Type
|
|
|
|
def type, do: unquote(ecto_type)
|
|
|
|
def cast(nil), do: :error
|
|
def cast(isn), do: {:ok, to_string(isn)}
|
|
|
|
def load(isn), do: {:ok, to_string(isn)}
|
|
|
|
def dump(isn), do: {:ok, to_string(isn)}
|
|
end
|
|
end
|