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

lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
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
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
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

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
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
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
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
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
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement