I created a simple Post schema with a title (string) and tags (json array of string).
defmodule JsonbDemo.Post do
use Ecto.Schema
schema "posts" do
field :title, :string
field :tags, {:array, :string}
end
end
# migration
defmodule JsonbDemo.Repo.Migrations.AddPostsD do
use Ecto.Migration
def change do
create table(:posts) do
add(:title, :string)
add(:tags, :jsonb)
end
end
end
I can insert Post object using Repo.insert
, but when I try to pass post into Repo.insert_all
I’ve got Protocol.UndefinedError
. What did I do wrong?
iex(1)> p = %JsonbDemo.Post{title: "Jedi", tags: ["a", "b"]}
%JsonbDemo.Post{
__meta__: #Ecto.Schema.Metadata<:built, "posts">,
id: nil,
title: "Jedi",
tags: ["a", "b"]
}
iex(2)> JsonbDemo.Repo.insert(p)
[debug] QUERY OK db=13.9ms decode=1.1ms queue=1.2ms idle=190.2ms
INSERT INTO "posts" ("tags","title") VALUES ($1,$2) RETURNING "id" [["a", "b"], "Jedi"]
↳ :erl_eval.do_apply/6, at: erl_eval.erl:685
{:ok,
%JsonbDemo.Post{
__meta__: #Ecto.Schema.Metadata<:loaded, "posts">,
id: 1,
title: "Jedi",
tags: ["a", "b"]
}}
iex(3)> JsonbDemo.Repo.insert_all(JsonbDemo.Post, [p])
** (Protocol.UndefinedError) protocol Enumerable not implemented for %JsonbDemo.Post{__meta__: #Ecto.Schema.Metadata<:built, "posts">, id: nil, title: "Jedi", tags: ["a", "b"]} of type JsonbDemo.Post (a struct). This protocol is implemented for the following type(s): DBConnection.PrepareStream, DBConnection.Stream, Date.Range, Ecto.Adapters.SQL.Stream, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, Jason.OrderedObject, List, Map, MapSet, Phoenix.LiveView.LiveStream, Postgrex.Stream, Range, Stream
(elixir 1.14.3) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir 1.14.3) lib/enum.ex:166: Enumerable.reduce/3
(elixir 1.14.3) lib/enum.ex:4307: Enum.map_reduce/3
(ecto 3.10.1) lib/ecto/repo/schema.ex:87: anonymous fn/5 in Ecto.Repo.Schema.extract_header_and_fields/8
(elixir 1.14.3) lib/enum.ex:1780: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(ecto 3.10.1) lib/ecto/repo/schema.ex:86: Ecto.Repo.Schema.extract_header_and_fields/8
(ecto 3.10.1) lib/ecto/repo/schema.ex:48: Ecto.Repo.Schema.do_insert_all/7
However, the weir thing is if I pass raw struct to Repo.insert_all
it works.
iex(3)> JsonbDemo.Repo.insert_all(JsonbDemo.Post, [%{title: "Mario", tags: ["one", "two"]}])
[debug] QUERY OK db=8.1ms queue=1.2ms idle=588.5ms
INSERT INTO "posts" ("tags","title") VALUES ($1,$2) [["one", "two"], "Mario"]
↳ :erl_eval.do_apply/6, at: erl_eval.erl:685
{1, nil}