Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about querying a money_with_currency column using Ecto #68

Closed
scmx opened this issue May 1, 2018 · 3 comments
Closed

Question about querying a money_with_currency column using Ecto #68

scmx opened this issue May 1, 2018 · 3 comments

Comments

@scmx
Copy link

scmx commented May 1, 2018

Hi, I'm having trouble figuring out how to query a database column with the money_with_currency Money.Ecto.Composite.Type postgres type using Ecto.

MyApp.Repo.get_by(MyApp.Transaction, amount: Money.new(3000, :SEK))

[debug] QUERY ERROR source="transactions" db=2.0ms
SELECT e0."id", e0."amount", e0."inserted_at", e0."updated_at" FROM "transactions" AS e0 WHERE (e0."amount" = $1) [{"SEK", #Decimal<3000>}]
** (FunctionClauseError) no function clause matching in Ecto.Adapters.Postgres.TypeModule.encode_tuple/5

The following arguments were given to Ecto.Adapters.Postgres.TypeModule.encode_tuple/5:

    # 1
    {"SEK", #Decimal<3000>}
# 2 1
    # 3
    nil

    # 4
    {Ecto.Adapters.Postgres.TypeModule, #Reference<0.3714461165.225312769.164420>}

    # 5
    []

Attempted function clauses (showing 3 out of 3):

    defp encode_tuple(tuple, n, [oid | oids], [type | types], acc)
    defp encode_tuple(tuple, n, [], [], acc) when tuple_size(tuple) < n
    defp encode_tuple(tuple, _, [], [], _) when is_tuple(tuple)

(ecto) lib/postgrex/type_module.ex:715: Ecto.Adapters.Postgres.TypeModule.encode_tuple/5
(ecto) /myapp/deps/postgrex/lib/postgrex/type_module.ex:715: Ecto.Adapters.Postgres.TypeModule.encode_params/3
(postgrex) lib/postgrex/query.ex:45: DBConnection.Query.Postgrex.Query.encode/3
(db_connection) lib/db_connection.ex:1079: DBConnection.describe_run/5
(db_connection) lib/db_connection.ex:1150: anonymous fn/4 in DBConnection.run_meter/5
(db_connection) lib/db_connection.ex:1207: DBConnection.run_begin/3
(db_connection) lib/db_connection.ex:592: DBConnection.prepare_execute/4
(ecto) lib/ecto/adapters/postgres/connection.ex:73: Ecto.Adapters.Postgres.Connection.prepare_execute/5
(ecto) lib/ecto/adapters/sql.ex:256: Ecto.Adapters.SQL.sql_call/6
(ecto) lib/ecto/adapters/sql.ex:426: Ecto.Adapters.SQL.execute_and_cache/7
(ecto) lib/ecto/repo/queryable.ex:133: Ecto.Repo.Queryable.execute/5
(ecto) lib/ecto/repo/queryable.ex:37: Ecto.Repo.Queryable.all/4
(ecto) lib/ecto/repo/queryable.ex:70: Ecto.Repo.Queryable.one/4

Then I tried this instead
import Ecto.Query; MyApp.Repo.all(from t in MyApp.Transaction, where: t.amount == ^Money.new(3000, :SEK))
import Ecto.Query; MyApp.Repo.all(where MyApp.Transaction, [t], t.amount == ^Money.new(3000, :SEK))
they both give the same error.

I'm guessing there's just a small change in my code needed? I'd be happy to improve docs if needed.

I'm wondering if could code by added to the Money.Ecto.Composite.Type to support passing in a money struct as is? If possible I'd guess that https://hexdocs.pm/ecto/Ecto.Type.html or https://hexdocs.pm/ecto/Ecto.Query.html should give a clue as to how.

@scmx
Copy link
Author

scmx commented May 1, 2018

Here's a few ways using fragment() with raw SQL that does work:
Repo.all(from t in Transaction, where: t.amount == fragment("('SEK', 3000)::money_with_currency"))
Repo.all(from t in Transaction, where: t.amount == fragment("(?, ?)::money_with_currency", "SEK", 3000))
But there's better way right? 😀 🤔

@scmx
Copy link
Author

scmx commented May 1, 2018

import Ecto.Query; MyApp.Repo.all(from t in MyApp.Transaction, where: t.amount == type(^Money.new(3000, :SEK), t.amount))
I got this solution from @LostKobrakai in Elixir Slack. Thanks!

So, to sum it up, if you have a money variable like this amount = ~M[3000]SEK and try to pass it in to a query, you might find this diff useful:

- where: t.amount == ^amount
+ where: t.amount == type(^amount, t.amount)

@scmx
Copy link
Author

scmx commented May 1, 2018

Closing since my use case is solved. Still would be great if it was possible without doing this as well

@scmx scmx closed this as completed May 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant