Ecto: Repo.all interpreting single integers as ascii characters

Created on 25 Dec 2017  路  2Comments  路  Source: elixir-ecto/ecto

Environment

  • Elixir version: Erlang/OTP 20, Elixir 1.5.2
  • Database and version: PostgreSQL 9.6
  • Ecto version (mix deps): ecto 2.2.7
  • Database adapter and version (mix deps): Postgrex 0.13.3
  • Operating system: Xubuntu 17.10

Current behavior

I've got a Chunk schema where each Chunk belongs_to a Sortable, so I'm fetching all Chunks with a given sortable_id:

iex> import Ecto.Query, only: [from: 2]
iex> alias Crowdsort.{Repo, Sortable, Chunk}
iex> query = from(c in Chunk, select: c.id, where: c.sortable_id == 12)
#Ecto.Query<from c in Crowdsort.Chunk, where: c.sortable_id == 12, select: c.id>
iex> chunk_ids = Repo.all(query)
[debug] QUERY OK source="chunks" db=1.3ms
SELECT c0."id" FROM "chunks" AS c0 WHERE (c0."sortable_id" = 12) []
'='
iex> chunk_ids
'='

The real id should have been 61, and 61 is the ascii code for '='

This happens for any query returning a single id (for example, returning the string '3' when the real id was 51). When there are multiple values, it correctly returns a list of integers. Also, Repo.one(query) correctly returns 61, but fails if there are multiple ids.

Expected behavior

It should have returned a list of ids matching my query. Like this: [61]. I can confirm that the data in the database is correct by running the resulting SQL:

crowdsort_dev=# SELECT c0."id" FROM "chunks" AS c0 WHERE (c0."sortable_id" = 12);
 id 
----
 61
(1 row)

Additional info

The code for my schema is here: https://gitlab.com/mac-chaffee/crowdsort/tree/master/lib/crowdsort/data

My migrations are here: https://gitlab.com/mac-chaffee/crowdsort/tree/master/priv/repo/migrations

And the important bits of mix ecto.dump:

CREATE TABLE sortables (
    id bigint NOT NULL,
    inserted_at timestamp without time zone NOT NULL,
    updated_at timestamp without time zone NOT NULL
);
CREATE TABLE chunks (
    id bigint NOT NULL,
    data jsonb,
    sortable_id bigint,
    inserted_at timestamp without time zone NOT NULL,
    updated_at timestamp without time zone NOT NULL
);

Most helpful comment

It is not a bug, when Elixir sees a list of integers, it prints that between single quotes as it may be a list of characters. Try this on IEx:

iex> i '='

And it will tell you more about it.

All 2 comments

I tried extending a test case to catch this bug, but I wasn't able to replicate it:

test "works with primary key value" do
  schema = %MySchema{id: 1, x: "abc"}
  TestRepo.get(MySchema, 123)
  TestRepo.get_by(MySchema, x: "abc")
  # Test that the id is not interpreted as an ascii character
  q = from(c in MySchema, select: c.id, where: c.id == 1)
  assert [1] == TestRepo.all(q)
  TestRepo.update!(schema |> Ecto.Changeset.change, force: true)
  TestRepo.delete!(schema)
end

Could it be an issue with the schema I wrote?

It is not a bug, when Elixir sees a list of integers, it prints that between single quotes as it may be a list of characters. Try this on IEx:

iex> i '='

And it will tell you more about it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tverlaan picture tverlaan  路  3Comments

yordis picture yordis  路  4Comments

wojtekmach picture wojtekmach  路  3Comments

sntran picture sntran  路  4Comments

ZhengQingchen picture ZhengQingchen  路  4Comments