0

Error:

14:18:04.259 [error] GenServer MyApp.Receiver.Handlers terminating
** (Ecto.Query.CastError) deps/ecto/lib/ecto/repo/queryable.ex:382: value `1234` in `where` cannot be cast to type :string in query:

from c0 in MyApp.DB.Client,
  where: c0.client_id == ^1234,
  select: c0

    (elixir) lib/enum.ex:1940: Enum."-reduce/3-lists^foldl/2-0-"/3
    (elixir) lib/enum.ex:1431: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
    (elixir) lib/enum.ex:1940: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto) lib/ecto/repo/queryable.ex:138: Ecto.Repo.Queryable.execute/4
    (ecto) lib/ecto/repo/queryable.ex:18: Ecto.Repo.Queryable.all/3
    (ecto) lib/ecto/repo/queryable.ex:67: Ecto.Repo.Queryable.one/3
    (my_app) lib/my_app/db/db_impl/db_impl.ex:54: MyApp.DBImpl.add_update_client/1
    (my_app) lib/my_app/receiver/receiver_handlers.ex:23: MyApp.Receiver.Handlers.handle_cast/2
    (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:711: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: {:"$gen_cast", {:add_update_client, %{client_id: 1234, client_pid: #PID<0.408.0>}}}
State: %{}
@doc """
Client connects or reconnects
"""
def add_update_client(client) do
  %{client_id: client_id} = client

  # This is the line causing the error
  client_db = DB.Client |> Repo.get_by(client_id: client_id)

  create_update_client(client_db, client)
end
defmodule MyApp.DB.Client do
  use Ecto.Schema

  schema "client" do
    field :client_id, :string
    field :client_pid, :binary

    timestamps()
  end

  # This says how you can change a record
  def changeset(client, params \\ %{}) do
    client
    |> Ecto.Changeset.cast(params, [:client_id, :client_pid])
    # Use validation if need be
    |> Ecto.Changeset.validate_required([:client_id, :client_pid])
  end

  def update_client_pid_changeset(client, params \\ %{}) do
    client
    |> Ecto.Changeset.cast(params, [:client_pid])
    # Use validation if need be
    |> Ecto.Changeset.validate_required([:client_pid])
  end

end

defmodule MyApp.Repo.Migrations.CreateClient do
  use Ecto.Migration

  def change do
    create table(:client) do
      add :client_id, :string
      add :client_pid, :binary

      timestamps
    end
  end
end

I tried changing the malfunctioning line to this but still getting the same error:

client_db = Repo.one(from c in DB.Client,
  where: c.client_id == type(^client_id, :string)
)

The values that I'm using for client_id are strings of numbers eg "1234" but sometimes Ecto can't figure it out. This only happens in 1/10 or so tests. As far as I can tell it works all of the time when the code is running normally. I suspect it has something to do with the order the tests are running in but I'm not sure otherwise. Anyone else had a similar problem and potential solution?

Edit: I think what is happening is that somewhere in the code "1234" becomes 1234. I don't know how or why this is happening though. I'm pulling in these values from a json file so I thought it may have come from the parser but that doesn't seem to be happening. Also, all of the values get inserted into the db with no issues. It has tripped the changeset error once on an update so somehow the code is parsing the string into a number.

Solved: A doctest I had previously written was triggering the insert into the database and I was using 1234 in the doctest instead of correctly using "1234" so it was my error all along.

GenericJam
  • 2,915
  • 5
  • 31
  • 33

1 Answers1

0

How about trying this:

When interpolating values, you may want to explicitly tell Ecto what is the expected type of the value being interpolated:

age = "18"
Repo.all(from u in "users",
          where: u.age > type(^age, :integer),
          select: u.name)

https://hexdocs.pm/ecto/Ecto.Query.html

7stud
  • 46,922
  • 14
  • 101
  • 127
  • Is there a way to include the type when using get_by/1? – GenericJam Jun 20 '19 at 08:13
  • If you are using schemas `from u in User` instead of `from u in "users"`, Ecto would automatically do the cast for you because the schema tells the types of each column. So for example, `Repo.get_by(User, age: age)` will automatically work. – José Valim Jun 21 '19 at 08:33