Sebb

Sebb

Create a behaviour that uses Ecto.Type

For loading a JSON into structs using Ecto-Schema I need some custom EctoTypes.
They are all the same: one of a list of atoms. So I tried to encapsulate that into a behaviour but I get an error I do not understand:

defmodule EctoAtomId do
  defmacro __using__(opts) do
    quote location: :keep, bind_quoted: [opts: opts] do
      use Ecto.Type

      @behaviour EctoAtomId

      @ids Keyword.fetch!(opts, :ids)
      @ids_as_string for(id <- @ids, do: Atom.to_string(id))
      @type_name Keyword.fetch!(opts, :type_name)

      def type, do: @type_name

      def cast(data) when data in @ids_as_string, do: {:ok, String.to_exisiting_atom(data)}
      def cast(data) when data in @ids, do: {:ok, data}
      def cast(), do: :error

      def load(data) when data in @ids_as_string, do: {:ok, String.to_exisiting_atom(data)}
      def load(_), :error

      def dump(id), do: {:ok, Atom.to_string(atom)}
    end
  end
end

when using it in this module:

defmodule Job do
  use EctoAtomId, ids: [:job_mechanic, :job_doc, :job_programmer], type_name: :job
end

I get this error:

== Compilation error in file lib/job.ex ==
** (CompileError) lib/ecto_atom.ex:4: missing :do option in "def"
    lib/job.ex:4: (module)

Marked As Solved

moogle19

moogle19

You forgot the do: in you def load(_) function.

Also Liked

Sebb

Sebb

:dizzy_face:

ok, that was stupid. Works now. Very nice.

defmodule EctoAtomId do
  @callback dummy() :: any()
  @optional_callbacks dummy: 0

  defmacro __using__(opts) do
    quote location: :keep, bind_quoted: [opts: opts] do
      @behaviour EctoAtomId

      use Ecto.Type

      @ids Keyword.fetch!(opts, :ids)
      @ids_as_string for(id <- @ids, do: Atom.to_string(id))
      @type_name Keyword.fetch!(opts, :type_name)

      def type, do: @type_name

      def cast(data) when data in @ids_as_string, do: {:ok, String.to_existing_atom(data)}
      def cast(data) when data in @ids, do: {:ok, data}
      def cast(), do: :error

      def load(data) when data in @ids_as_string, do: {:ok, String.to_existing_atom(data)}
      def load(_), do: :error
      def dump(id), do: {:ok, Atom.to_string(id)}
    end
  end
end

Example for using these types:

defmodule Person do
  use Ecto.Schema

  @primary_key false
  embedded_schema do
    field(:id, :integer)
    field(:name, :string, null: false)
    field(:age, :integer)
    field(:job, Job)
    field(:hobbies, {:array, Hobby})
    field(:friends, {:array, :integer})
  end
end
iex(2)> data = %{id: 1, name: "Bob", age: "18", job: "job_programmer", friends: [2, 4711], hobbies: ["hobby_freeclimbing", "hobby_painting"]}
...

iex(3)> p = Ecto.Changeset.cast(%Person{}, data, Map.keys(data)) |> Ecto.Changeset.apply_changes()  
%Person{
  age: 18,
  friends: [2, 4711],
  hobbies: [:hobby_freeclimbing, :hobby_painting],
  id: 1,
  job: :job_programmer,
  name: "Bob"
}

Where Next?

Popular in Questions Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30877 112
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New

We're in Beta

About us Mission Statement