AE
Ash Elixirβ€’3y ago
waseigo

How to Ash-idiomatically get all unique values of an attribute across all records?

App.Api.Item is a resource with an attribute :name. How can I go from the set of all records of Item (App.Api.Item |> App.Api.read!()) to a list of all unique values of the :name attribute in the most idiomatic way?
50 Replies
ZachDaniel
ZachDanielβ€’3y ago
Hello! Ash does actually have a way to do that as of recently πŸ™‚ App.Api.Item |> App.Api.list(:name) is how you'd get the list of names however, you should be able to pass uniq?: true as an option to that to get unique values, but due to a bug in the way we handle those options you can't so I'll push up a fix but this was added like last week FWIW there are still some optimizations to be made to the generated SQL there, but it won't change how they are used so you should be good
waseigo
waseigoOPβ€’3y ago
I'm getting the following (P is my aliased App.Api which is actually named Bouketo.Portfolio):
iex(4)> P.Brand |> P.list(:name)
[debug] QUERY OK db=3.5ms queue=4.5ms idle=1415.2ms
SELECT coalesce(array_agg(s0."name"::text), $1::text[])::text[][] FROM (SELECT sb0."id" AS "id", sb0."name" AS "name", sb0."discount_factor" AS "discount_factor", sb0."is_locked" AS "is_locked", sb0."created_at" AS "created_at", sb0."updated_at" AS "updated_at" FROM "brands" AS sb0) AS s0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:680
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
(ecto 3.9.4) lib/ecto/repo/queryable.ex:419: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:404: anonymous fn/4 in Ecto.Repo.Queryable.process_kv/4
(elixir 1.14.0) lib/enum.ex:1780: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:363: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:283: anonymous fn/3 in Ecto.Repo.Queryable.postprocessor/4
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ecto 3.9.4) lib/ecto/repo/queryable.ex:235: Ecto.Repo.Queryable.execute/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:151: Ecto.Repo.Queryable.one/3
(ash_postgres 1.3.8) lib/data_layer.ex:680: AshPostgres.DataLayer.run_aggregate_query/3
(ash 2.6.0) lib/ash/actions/aggregate.ex:47: Ash.Actions.Aggregate.run/4
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list/3
iex(4)> P.Brand |> P.list(:name)
[debug] QUERY OK db=3.5ms queue=4.5ms idle=1415.2ms
SELECT coalesce(array_agg(s0."name"::text), $1::text[])::text[][] FROM (SELECT sb0."id" AS "id", sb0."name" AS "name", sb0."discount_factor" AS "discount_factor", sb0."is_locked" AS "is_locked", sb0."created_at" AS "created_at", sb0."updated_at" AS "updated_at" FROM "brands" AS sb0) AS s0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:680
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
(ecto 3.9.4) lib/ecto/repo/queryable.ex:419: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:404: anonymous fn/4 in Ecto.Repo.Queryable.process_kv/4
(elixir 1.14.0) lib/enum.ex:1780: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:363: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:283: anonymous fn/3 in Ecto.Repo.Queryable.postprocessor/4
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ecto 3.9.4) lib/ecto/repo/queryable.ex:235: Ecto.Repo.Queryable.execute/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:151: Ecto.Repo.Queryable.one/3
(ash_postgres 1.3.8) lib/data_layer.ex:680: AshPostgres.DataLayer.run_aggregate_query/3
(ash 2.6.0) lib/ash/actions/aggregate.ex:47: Ash.Actions.Aggregate.run/4
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list/3
The list in here is actually the contents I want to get:
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
It also fails on aggregates:
iex(13)> P.Family |> P.list(:category_name)
{:error,
%Ash.Error.Unknown{
errors: [
%Ash.Error.Unknown.UnknownError{
error: "Must provide field type for list",
field: nil,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :unknown
}
],
stacktraces?: true,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :unknown
}}
iex(13)> P.Family |> P.list(:category_name)
{:error,
%Ash.Error.Unknown{
errors: [
%Ash.Error.Unknown.UnknownError{
error: "Must provide field type for list",
field: nil,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :unknown
}
],
stacktraces?: true,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :unknown
}}
ZachDaniel
ZachDanielβ€’3y ago
Can you update to the latest ash and ash postgres? If it’s still broken try ash postgres main
waseigo
waseigoOPβ€’3y ago
Updated to latest ash and ash_postgres; same results. Updated ash_postgres to main; same results.
ZachDaniel
ZachDanielβ€’3y ago
πŸ€” okay I'll take a look now thanks
waseigo
waseigoOPβ€’3y ago
Let me check is something is weird with my data (I'm importing a CSV file into tables) I can get all records of a resource and pick one of them.
x = P.Item |> P.read!() |> Enum.at(15)
x = P.Item |> P.read!() |> Enum.at(15)
...works fine. Once I try to load!(), I get an unknown error:
[...bunch of run_query and [debug] output with "QUERY OK"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:613
** (Ash.Error.Unknown) Unknown Error

* is invalid
(ash 2.6.3) lib/ash/error/error.ex:320: Ash.Error.to_ash_error/3
(ash 2.6.3) lib/ash/engine/request.ex:226: Ash.Engine.Request.next/1
(ash 2.6.3) lib/ash/engine/engine.ex:661: Ash.Engine.advance_request/2
(ash 2.6.3) lib/ash/engine/engine.ex:567: Ash.Engine.fully_advance_request/2
(ash 2.6.3) lib/ash/engine/engine.ex:508: Ash.Engine.do_run_iteration/2
(elixir 1.14.0) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.6.3) lib/ash/engine/engine.ex:451: Ash.Engine.run_iteration/1
(ash 2.6.3) lib/ash/engine/engine.ex:268: Ash.Engine.run_to_completion/1
(ash 2.6.3) lib/ash/engine/engine.ex:213: Ash.Engine.do_run/2
(ash 2.6.3) lib/ash/engine/engine.ex:116: Ash.Engine.run/2
(ash 2.6.3) lib/ash/actions/read.ex:170: Ash.Actions.Read.do_run/3
(ash 2.6.3) lib/ash/actions/read.ex:90: Ash.Actions.Read.run/3
(ash 2.6.3) lib/ash/api/api.ex:947: Ash.Api.load/4
(ash 2.6.3) lib/ash/api/api.ex:921: Ash.Api.load!/4
(stdlib 4.2) erl_eval.erl:744: :erl_eval.do_apply/7
(elixir 1.14.0) src/elixir.erl:283: :elixir.eval_forms/3
(elixir 1.14.0) lib/module/parallel_checker.ex:100: Module.ParallelChecker.verify/1
(iex 1.14.0) lib/iex/evaluator.ex:329: IEx.Evaluator.eval_and_inspect/3
(ash 2.6.3) lib/ash/error/error.ex:452: Ash.Error.choose_error/2
(ash 2.6.3) lib/ash/error/error.ex:207: Ash.Error.to_error_class/2
(ash 2.6.3) lib/ash/actions/read.ex:181: Ash.Actions.Read.do_run/3
(ash 2.6.3) lib/ash/actions/read.ex:90: Ash.Actions.Read.run/3
(ash 2.6.3) lib/ash/api/api.ex:947: Ash.Api.load/4
(ash 2.6.3) lib/ash/api/api.ex:921: Ash.Api.load!/4
[...bunch of run_query and [debug] output with "QUERY OK"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:613
** (Ash.Error.Unknown) Unknown Error

* is invalid
(ash 2.6.3) lib/ash/error/error.ex:320: Ash.Error.to_ash_error/3
(ash 2.6.3) lib/ash/engine/request.ex:226: Ash.Engine.Request.next/1
(ash 2.6.3) lib/ash/engine/engine.ex:661: Ash.Engine.advance_request/2
(ash 2.6.3) lib/ash/engine/engine.ex:567: Ash.Engine.fully_advance_request/2
(ash 2.6.3) lib/ash/engine/engine.ex:508: Ash.Engine.do_run_iteration/2
(elixir 1.14.0) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.6.3) lib/ash/engine/engine.ex:451: Ash.Engine.run_iteration/1
(ash 2.6.3) lib/ash/engine/engine.ex:268: Ash.Engine.run_to_completion/1
(ash 2.6.3) lib/ash/engine/engine.ex:213: Ash.Engine.do_run/2
(ash 2.6.3) lib/ash/engine/engine.ex:116: Ash.Engine.run/2
(ash 2.6.3) lib/ash/actions/read.ex:170: Ash.Actions.Read.do_run/3
(ash 2.6.3) lib/ash/actions/read.ex:90: Ash.Actions.Read.run/3
(ash 2.6.3) lib/ash/api/api.ex:947: Ash.Api.load/4
(ash 2.6.3) lib/ash/api/api.ex:921: Ash.Api.load!/4
(stdlib 4.2) erl_eval.erl:744: :erl_eval.do_apply/7
(elixir 1.14.0) src/elixir.erl:283: :elixir.eval_forms/3
(elixir 1.14.0) lib/module/parallel_checker.ex:100: Module.ParallelChecker.verify/1
(iex 1.14.0) lib/iex/evaluator.ex:329: IEx.Evaluator.eval_and_inspect/3
(ash 2.6.3) lib/ash/error/error.ex:452: Ash.Error.choose_error/2
(ash 2.6.3) lib/ash/error/error.ex:207: Ash.Error.to_error_class/2
(ash 2.6.3) lib/ash/actions/read.ex:181: Ash.Actions.Read.do_run/3
(ash 2.6.3) lib/ash/actions/read.ex:90: Ash.Actions.Read.run/3
(ash 2.6.3) lib/ash/api/api.ex:947: Ash.Api.load/4
(ash 2.6.3) lib/ash/api/api.ex:921: Ash.Api.load!/4
@Zach Daniel I don't want to send you on a wild goose chase within ash_postgres in case I have defined something the wrong way... what could be a cause of the unknown error if not ash_postgres? Notably, this doesn't happen in all resources.
ZachDaniel
ZachDanielβ€’3y ago
What are you loading? That error is pretty garbage 😒
waseigo
waseigoOPβ€’3y ago
the CSV file representing a flat database of sales items, each with its item code, manufacturer part number, product category, product family, list price, etc., and splitting it into resources with relationships. I've been writing the logic in the seeds.exs file, and allegedly all records are generated OK. I wonder whether I might have some circularity? What about this error?
ZachDaniel
ZachDanielβ€’3y ago
So the original error you showed me should definitely go away on the latest ash_postgres main are you still getting that error? Well, sorry, it won't necessarily go away but the SQL it generates would be different for sure i.e from doing this: P.Brand |> P.list(:name)
waseigo
waseigoOPβ€’3y ago
iex(7)> P.Brand |> P.list(:name)
[debug] QUERY OK source="brands" db=49.9ms queue=38.8ms idle=1130.3ms
SELECT coalesce(array_agg(b0."name"::text), $1::text[])::text[][] FROM "brands" AS b0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:690
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
(ecto 3.9.4) lib/ecto/repo/queryable.ex:419: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:404: anonymous fn/4 in Ecto.Repo.Queryable.process_kv/4
(elixir 1.14.0) lib/enum.ex:1780: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:363: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:283: anonymous fn/3 in Ecto.Repo.Queryable.postprocessor/4
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ecto 3.9.4) lib/ecto/repo/queryable.ex:235: Ecto.Repo.Queryable.execute/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:151: Ecto.Repo.Queryable.one/3
(ash_postgres 1.3.10) lib/data_layer.ex:690: AshPostgres.DataLayer.run_aggregate_query/3
(ash 2.6.3) lib/ash/actions/aggregate.ex:47: Ash.Actions.Aggregate.run/4
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list/3
iex(7)> P.Brand |> P.list(:name)
[debug] QUERY OK source="brands" db=49.9ms queue=38.8ms idle=1130.3ms
SELECT coalesce(array_agg(b0."name"::text), $1::text[])::text[][] FROM "brands" AS b0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:690
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
(ecto 3.9.4) lib/ecto/repo/queryable.ex:419: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:404: anonymous fn/4 in Ecto.Repo.Queryable.process_kv/4
(elixir 1.14.0) lib/enum.ex:1780: Enum."-map_reduce/3-lists^mapfoldl/2-0-"/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:363: Ecto.Repo.Queryable.process/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:283: anonymous fn/3 in Ecto.Repo.Queryable.postprocessor/4
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ecto 3.9.4) lib/ecto/repo/queryable.ex:235: Ecto.Repo.Queryable.execute/4
(ecto 3.9.4) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(ecto 3.9.4) lib/ecto/repo/queryable.ex:151: Ecto.Repo.Queryable.one/3
(ash_postgres 1.3.10) lib/data_layer.ex:690: AshPostgres.DataLayer.run_aggregate_query/3
(ash 2.6.3) lib/ash/actions/aggregate.ex:47: Ash.Actions.Aggregate.run/4
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list/3
Yes, the SQL is different Interestingly, ash_admin (branch phoenix-1.7) works well, I can see all records listed, relationships load fine on a record.
ZachDaniel
ZachDanielβ€’3y ago
πŸ€” what version of postgres are you on? okay, I just pushed a fix up to ash_postgres main for that error I think the version of postgres I'm testing with for whatever reason doesn't surface that error or some other dependency version, whatever it is but the fix should be there So once that is fixed, how did you get this error?: https://discord.com/channels/711271361523351632/1074452397176393808/1074754246169350174
waseigo
waseigoOPβ€’3y ago
postgres v13 from debian/bullseye which version are you on?
ZachDaniel
ZachDanielβ€’3y ago
14.6 either way, it was "broken" in both places just for some reason I wasn't getting the error ash_postgres main should do the trick now
waseigo
waseigoOPβ€’3y ago
I'm trying P.Whatever |> P.read!() |> Enum.at(0) |> P.load!(:somerelationship) on all Whatever resources I have defined. It works for some, but not for all, so maybe PEBKAC...
ZachDaniel
ZachDanielβ€’3y ago
If you can show me a specific one maybe we can hunt down the issue and find out. is invalid is unideal but might just be hinting at the thing you tried to load not actually existing
waseigo
waseigoOPβ€’3y ago
P.Brand has_many P.Family
P.Brand |> P.read!() |> Enum.at(0) |> P.load!(:families)
P.Brand |> P.read!() |> Enum.at(0) |> P.load!(:families)
works. P.Category has_many P.Family
P.Category |> P.read!() |> Enum.at(0) |> P.load!(:families)
P.Category |> P.read!() |> Enum.at(0) |> P.load!(:families)
works. P.Family belongs_to P.Category and P.Brand, and has_many P.Variant
P.Family |> P.read!() |> Enum.at(0) |> P.load!([:category, :brand, :variants])
P.Family |> P.read!() |> Enum.at(0) |> P.load!([:category, :brand, :variants])
works. P.Variant belongs_to P.Family and has_one P.Item
P.Variant |> P.read!() |> P.load!([:family, :item]) |> Enum.at(0)
P.Variant |> P.read!() |> P.load!([:family, :item]) |> Enum.at(0)
works. P.Sequence belongs_to P.Item
P.Sequence |> P.read!() |> P.load!(:items)
P.Sequence |> P.read!() |> P.load!(:items)
works. I think I found it P.Item belongs_to one P.Variant
P.Item |> P.read!() |> P.load!(:variant)
P.Item |> P.read!() |> P.load!(:variant)
fails with the Unknown Error. The [debug] output shows a SELECT query like so, and it's truncated.
SELECT i0."id", v1."mpn", v1."code", v1."name" FROM "items" AS i0 LEFT OUTER JOIN "public"."variants" AS v1 ON i0."variant_id" = v1."id" WHERE (i0."id"::uuid IN ($1::uuid,$2::uuid,$3::uuid,$4::uuid,$5::uuid,$6::uuid,$7::uuid,$8::uuid,$9::uuid,$10::uuid,$11::uuid,$12::uuid,$13::uuid,$14::uuid,$15::uuid,$16::uuid,$17::uuid,$18::uuid,$19::uuid,$20::uuid,$21::uuid,$22::uuid,$23::uuid,$24::uuid,$25::uuid,$26::uuid,$27::uuid,$28::uuid,$29::uuid,$30::uuid,$31::uuid,$32::uuid,$33::uuid,$34::uuid,$35::uuid,$36::uuid,$37::uuid,$38::uuid,$39::uuid,$40::uuid,$41::uuid,$42::uuid,$43::uuid,$44::uuid,$45::uuid,$46::uuid,$47::uuid,$48::uuid,$49::uuid,$50::uuid,$51::uuid,$52::uuid,$53::uuid,$54::uuid,$55::uuid,$56::uuid,$57::uuid,$58::uuid,$59::uuid,$60::uuid,$61::uuid,$62::uuid,$63::uuid,$64::uuid,$65::uuid,$66::uuid,$67::uuid,$68::uuid,$69::uuid,$70::uuid,$71::uuid,$72::uuid,$73::uuid,$74::uuid,$75::uuid,$76::uuid,$77::uuid,$78::uuid,$79::uuid,$80::uuid,$81::uuid,$82::uuid,$83::uuid,$84::uuid,$85::uuid,$86::uuid,$87::uuid,$88::uuid,$89::uuid,$90::uuid,$91::uuid,$92::uuid,$93::uuid,$94::uuid,$95::uuid,$96::uuid,$97::uuid,$98::uuid,$99::uuid,$100: (truncated)
SELECT i0."id", v1."mpn", v1."code", v1."name" FROM "items" AS i0 LEFT OUTER JOIN "public"."variants" AS v1 ON i0."variant_id" = v1."id" WHERE (i0."id"::uuid IN ($1::uuid,$2::uuid,$3::uuid,$4::uuid,$5::uuid,$6::uuid,$7::uuid,$8::uuid,$9::uuid,$10::uuid,$11::uuid,$12::uuid,$13::uuid,$14::uuid,$15::uuid,$16::uuid,$17::uuid,$18::uuid,$19::uuid,$20::uuid,$21::uuid,$22::uuid,$23::uuid,$24::uuid,$25::uuid,$26::uuid,$27::uuid,$28::uuid,$29::uuid,$30::uuid,$31::uuid,$32::uuid,$33::uuid,$34::uuid,$35::uuid,$36::uuid,$37::uuid,$38::uuid,$39::uuid,$40::uuid,$41::uuid,$42::uuid,$43::uuid,$44::uuid,$45::uuid,$46::uuid,$47::uuid,$48::uuid,$49::uuid,$50::uuid,$51::uuid,$52::uuid,$53::uuid,$54::uuid,$55::uuid,$56::uuid,$57::uuid,$58::uuid,$59::uuid,$60::uuid,$61::uuid,$62::uuid,$63::uuid,$64::uuid,$65::uuid,$66::uuid,$67::uuid,$68::uuid,$69::uuid,$70::uuid,$71::uuid,$72::uuid,$73::uuid,$74::uuid,$75::uuid,$76::uuid,$77::uuid,$78::uuid,$79::uuid,$80::uuid,$81::uuid,$82::uuid,$83::uuid,$84::uuid,$85::uuid,$86::uuid,$87::uuid,$88::uuid,$89::uuid,$90::uuid,$91::uuid,$92::uuid,$93::uuid,$94::uuid,$95::uuid,$96::uuid,$97::uuid,$98::uuid,$99::uuid,$100: (truncated)
ZachDaniel
ZachDanielβ€’3y ago
can I see the relationship definition? And the full error?
waseigo
waseigoOPβ€’3y ago
https://pastebin.com/3zd85kv7 This seems fishy to me
WHERE (i0."id"::uuid IN ($1::uuid,$2::uuid,$3::uuid,$4: (truncated)
WHERE (i0."id"::uuid IN ($1::uuid,$2::uuid,$3::uuid,$4: (truncated)
ZachDaniel
ZachDanielβ€’3y ago
The way that we do loads at the moment (up for change/optimization for cases like this later, i.e loading a belongs_to/has_one) is not via joins We do it in separate queries, passing down all the ids
waseigo
waseigoOPβ€’3y ago
Got it, hence the list of uuids
ZachDaniel
ZachDanielβ€’3y ago
that pastebin is gone
waseigo
waseigoOPβ€’3y ago
ah dang it lemme redo https://pastebin.com/JhE4Usjk expires in a week I'll try postgres v15 to see if it makes a difference
ZachDaniel
ZachDanielβ€’3y ago
Still says not found πŸ˜†
waseigo
waseigoOPβ€’3y ago
0bin - encrypted pastebin
0bin is a client-side-encrypted alternative pastebin. You can store code/text/images online for a set period of time and share with the world. Featuring burn after reading, history, clipboard.
ZachDaniel
ZachDanielβ€’3y ago
okay that works πŸ˜† Do you have any custom actions on the variant resource?
waseigo
waseigoOPβ€’3y ago
no
ZachDaniel
ZachDanielβ€’3y ago
Can you read the variants directly? Yeah, I see that you can something strange is going on there for sure
waseigo
waseigoOPβ€’3y ago
Would P.Item |> P.read!() |> P.load!(:variant) run OK even if one of the records is somehow broken? Maybe the issue is with one or more records not properly associated, e.g. due to dirty data in the CSV
ZachDaniel
ZachDanielβ€’3y ago
Oh, yknow
waseigo
waseigoOPβ€’3y ago
So it works on Enum.at(0) that I use as a quick test, but not across all records! Hmmmmmm :thinkies: Let me check...
ZachDaniel
ZachDanielβ€’3y ago
Something weird is going on there for sure
waseigo
waseigoOPβ€’3y ago
Gimme a few minutes... mix deps.compile takes a while on my i5-2520M ... Interesting. The first call leads to a different result to the second one.
iex(2)> P.Brand |> P.list(:name)
** (UndefinedFunctionError) function AshPostgres.DataLayer.resource_to_query/1 is undefined or private. Did you mean:

* resource_to_query/2

(ash_postgres 1.3.8) AshPostgres.DataLayer.resource_to_query(Bouketo.Portfolio.Brand)
(ash 2.6.0) lib/ash/query/query.ex:2056: Ash.Query.data_layer_query/2
(ash 2.6.0) lib/ash/actions/aggregate.ex:45: Ash.Actions.Aggregate.run/4
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list/3
iex(2)> P.Brand |> P.list(:name)
[debug] QUERY OK db=1.5ms decode=4.0ms queue=1.4ms idle=461.5ms
SELECT coalesce(array_agg(s0."name"::text), $1::text[])::text[][] FROM (SELECT sb0."id" AS "id", sb0."name" AS "name", sb0."discount_factor" AS "discount_factor", sb0."is_locked" AS "is_locked", sb0."created_at" AS "created_at", sb0."updated_at" AS "updated_at" FROM "brands" AS sb0) AS s0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:680
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
(ecto 3.9.4) lib/ecto/repo/queryable.ex:419: Ecto.Repo.Queryable.process/4
iex(2)> P.Brand |> P.list(:name)
** (UndefinedFunctionError) function AshPostgres.DataLayer.resource_to_query/1 is undefined or private. Did you mean:

* resource_to_query/2

(ash_postgres 1.3.8) AshPostgres.DataLayer.resource_to_query(Bouketo.Portfolio.Brand)
(ash 2.6.0) lib/ash/query/query.ex:2056: Ash.Query.data_layer_query/2
(ash 2.6.0) lib/ash/actions/aggregate.ex:45: Ash.Actions.Aggregate.run/4
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list/3
iex(2)> P.Brand |> P.list(:name)
[debug] QUERY OK db=1.5ms decode=4.0ms queue=1.4ms idle=461.5ms
SELECT coalesce(array_agg(s0."name"::text), $1::text[])::text[][] FROM (SELECT sb0."id" AS "id", sb0."name" AS "name", sb0."discount_factor" AS "discount_factor", sb0."is_locked" AS "is_locked", sb0."created_at" AS "created_at", sb0."updated_at" AS "updated_at" FROM "brands" AS sb0) AS s0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:680
** (ArgumentError) cannot load `["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP", "EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]` as type {:array, {:array, {:parameterized, Ash.Type.StringWrapper.EctoType, []}}}
(ecto 3.9.4) lib/ecto/repo/queryable.ex:419: Ecto.Repo.Queryable.process/4
Now on Postgres 15. Reimported all the data.
ZachDaniel
ZachDanielβ€’3y ago
πŸ€” there is definitely a dependency version issue there well...maybe not I guess? Something weird is happening though that much is sure mix hex.info ash and mix hex.info ash_postgres what do those show?
waseigo
waseigoOPβ€’3y ago
$ mix hex.info ash
A resource declaration and interaction library. Built with pluggable data layers, and
designed to be used by multiple front ends.

Config: {:ash, "~> 2.6"}
Locked version: 2.6.3
Releases: 2.6.3, 2.6.2, 2.6.1, 2.6.0, 2.5.16, 2.5.15, 2.5.14, 2.5.13, ...

Licenses: MIT
Links:
GitHub: https://github.com/ash-project/ash

$ mix hex.info ash_postgres
A postgres data layer for `Ash` resources. Leverages Ecto's postgres
support, and delegates to a configured repo.

Config: {:ash_postgres, "~> 1.3"}
Releases: 1.3.10, 1.3.9, 1.3.8, 1.3.6, 1.3.5, 1.3.4, 1.3.3, 1.3.2, ...

Licenses: MIT
Links:
GitHub: https://github.com/ash-project/ash_postgres
$ mix hex.info ash
A resource declaration and interaction library. Built with pluggable data layers, and
designed to be used by multiple front ends.

Config: {:ash, "~> 2.6"}
Locked version: 2.6.3
Releases: 2.6.3, 2.6.2, 2.6.1, 2.6.0, 2.5.16, 2.5.15, 2.5.14, 2.5.13, ...

Licenses: MIT
Links:
GitHub: https://github.com/ash-project/ash

$ mix hex.info ash_postgres
A postgres data layer for `Ash` resources. Leverages Ecto's postgres
support, and delegates to a configured repo.

Config: {:ash_postgres, "~> 1.3"}
Releases: 1.3.10, 1.3.9, 1.3.8, 1.3.6, 1.3.5, 1.3.4, 1.3.3, 1.3.2, ...

Licenses: MIT
Links:
GitHub: https://github.com/ash-project/ash_postgres
And in mix.exs:
{:ash, "~> 2.6.3"},
# {:ash_postgres, "~> 1.3.8"},
{:ash_postgres, github: "ash-project/ash_postgres", branch: "main"},
{:ash, "~> 2.6.3"},
# {:ash_postgres, "~> 1.3.8"},
{:ash_postgres, github: "ash-project/ash_postgres", branch: "main"},
oh hey, it works now! wth? wut πŸ₯΄
ZachDaniel
ZachDanielβ€’3y ago
😒
waseigo
waseigoOPβ€’3y ago
iex(2)> P.Brand |> P.list(:name)
[debug] QUERY OK source="brands" db=0.9ms decode=6.4ms queue=2.8ms idle=1036.7ms
SELECT coalesce(array_agg(b0."name"::text), $1::text[])::text[] FROM "brands" AS b0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:690
{:ok,
["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP",
"EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]}
iex(2)> P.Brand |> P.list(:name)
[debug] QUERY OK source="brands" db=0.9ms decode=6.4ms queue=2.8ms idle=1036.7ms
SELECT coalesce(array_agg(b0."name"::text), $1::text[])::text[] FROM "brands" AS b0 [[]]
↳ AshPostgres.DataLayer.run_aggregate_query/3, at: lib/data_layer.ex:690
{:ok,
["TOREX", "WAM", "OLI", "TECNO CM", "ABB", "Solimar Pneumatics", "Fike", "MAP",
"EXTRAC", "CIMMA", "TECTRA", "SEPCOM", "Telemecanique", "MVM", "Lainyl"]}
this works
ZachDaniel
ZachDanielβ€’3y ago
okay, dunno whats up with that but this is still broken? P.Item |> P.read!() |> P.load!(:variant
waseigo
waseigoOPβ€’3y ago
yep, just checked, this one is still broken oh man, thank you so much for that Ash.Api.list() !
ZachDaniel
ZachDanielβ€’3y ago
okay, can you do something like this:
P.Item
|> P.read!()
|> Enum.each(fn record ->
try do
P.load!(record, :variant)
rescue
e ->
raise """
#{inspect(record)}

#{Exception.format(:error, e, __STACKTRACE__)}
"""
end
end)
P.Item
|> P.read!()
|> Enum.each(fn record ->
try do
P.load!(record, :variant)
rescue
e ->
raise """
#{inspect(record)}

#{Exception.format(:error, e, __STACKTRACE__)}
"""
end
end)
that will print out the offending record
waseigo
waseigoOPβ€’3y ago
Indeed, it choked after a few records. Let me check. The offending record can be read, but loading :variant leads to the unknown error. I'll check my data. Actually it chokes at the very first record.
ZachDaniel
ZachDanielβ€’3y ago
can I see it?
waseigo
waseigoOPβ€’3y ago
0bin - encrypted pastebin
0bin is a client-side-encrypted alternative pastebin. You can store code/text/images online for a set period of time and share with the world. Featuring burn after reading, history, clipboard.
ZachDaniel
ZachDanielβ€’3y ago
I don't see anything wrong with that... something really strange is happening here
waseigo
waseigoOPβ€’3y ago
This is super weird. This works:
P.Variant |> Ash.Query.filter(name == "EWM400") |> P.read_one!() |> P.load!(:item)
P.Variant |> Ash.Query.filter(name == "EWM400") |> P.read_one!() |> P.load!(:item)
This also works:
P.Item |> Ash.Query.filter(variant_name == "EWM400") |> P.read_one!()
P.Item |> Ash.Query.filter(variant_name == "EWM400") |> P.read_one!()
This fails with unknown error:
P.Item |> Ash.Query.filter(variant_name == "EWM400") |> P.read_one!() |> P.load!(:variant)
P.Item |> Ash.Query.filter(variant_name == "EWM400") |> P.read_one!() |> P.load!(:variant)
ZachDaniel
ZachDanielβ€’3y ago
Can you do this:
P.Item
|> P.read!()
|> P.load!(:variant, verbose?: true)
P.Item
|> P.read!()
|> P.load!(:variant, verbose?: true)
will print out lots of output, but we can see what the last things it prints before it dies is
waseigo
waseigoOPβ€’3y ago
Interestingly, P.Item has an aggregate first :variant_code, :variant, :code, and
preparations do
prepare build(load: [:sequence_prefix, :category_code, :variant_code, :code, :tagline, :mpn])
end
preparations do
prepare build(load: [:sequence_prefix, :category_code, :variant_code, :code, :tagline, :mpn])
end
So, :variant_code based on the related :variant is successfully prepared.
waseigo
waseigoOPβ€’3y ago
0bin - encrypted pastebin
0bin is a client-side-encrypted alternative pastebin. You can store code/text/images online for a set period of time and share with the world. Featuring burn after reading, history, clipboard.
waseigo
waseigoOPβ€’3y ago
So, the :code calculation fails I'll check all the dependent values of this
calculate :code, :string, expr(type(sequence_prefix, :string) <> type(category_code, :string) <> type(variant_code, :string))
calculate :code, :string, expr(type(sequence_prefix, :string) <> type(category_code, :string) <> type(variant_code, :string))
iex(25)> P.Item |> P.list!(:sequence_prefix)
iex(25)> P.Item |> P.list!(:category_code)
iex(25)> P.Item |> P.list!(:variant_code)
iex(25)> P.Item |> P.list!(:sequence_prefix)
iex(25)> P.Item |> P.list!(:category_code)
iex(25)> P.Item |> P.list!(:variant_code)
All fail with:
** (Ash.Error.Unknown) Unknown Error

* Must provide field type for list
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.6.3) lib/ash/error/error.ex:196: Ash.Error.to_error_class/2
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list!/3
(stdlib 4.2) erl_eval.erl:744: :erl_eval.do_apply/7
(elixir 1.14.0) src/elixir.erl:283: :elixir.eval_forms/3
(elixir 1.14.0) lib/module/parallel_checker.ex:100: Module.ParallelChecker.verify/1
(iex 1.14.0) lib/iex/evaluator.ex:329: IEx.Evaluator.eval_and_inspect/3
(iex 1.14.0) lib/iex/evaluator.ex:303: IEx.Evaluator.eval_and_inspect_parsed/3
(iex 1.14.0) lib/iex/evaluator.ex:292: IEx.Evaluator.parse_eval_inspect/3
(iex 1.14.0) lib/iex/evaluator.ex:187: IEx.Evaluator.loop/1
(iex 1.14.0) lib/iex/evaluator.ex:32: IEx.Evaluator.init/4
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list!/3
** (Ash.Error.Unknown) Unknown Error

* Must provide field type for list
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.6.3) lib/ash/error/error.ex:196: Ash.Error.to_error_class/2
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list!/3
(stdlib 4.2) erl_eval.erl:744: :erl_eval.do_apply/7
(elixir 1.14.0) src/elixir.erl:283: :elixir.eval_forms/3
(elixir 1.14.0) lib/module/parallel_checker.ex:100: Module.ParallelChecker.verify/1
(iex 1.14.0) lib/iex/evaluator.ex:329: IEx.Evaluator.eval_and_inspect/3
(iex 1.14.0) lib/iex/evaluator.ex:303: IEx.Evaluator.eval_and_inspect_parsed/3
(iex 1.14.0) lib/iex/evaluator.ex:292: IEx.Evaluator.parse_eval_inspect/3
(iex 1.14.0) lib/iex/evaluator.ex:187: IEx.Evaluator.loop/1
(iex 1.14.0) lib/iex/evaluator.ex:32: IEx.Evaluator.init/4
(stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
(bouketo 0.1.0) lib/bouketo/portfolio.ex:1: Bouketo.Portfolio.list!/3
# item.ex
aggregates do
first :sequence_prefix, :sequence, :prefix
first :category_code, [:variant, :family, :category], :code
first :variant_code, :variant, :code
first :variant_name, :variant, :name
first :mpn, :variant, :mpn
end
# item.ex
aggregates do
first :sequence_prefix, :sequence, :prefix
first :category_code, [:variant, :family, :category], :code
first :variant_code, :variant, :code
first :variant_name, :variant, :name
first :mpn, :variant, :mpn
end
Weird, because the :code preparation works as intended, and P.Item |> P.read!() delivers records with code: "9381310" etc., as intended. @Zach Daniel verified. I remove :code from the preparations:
P.Item |> P.read!() |> P.load!(:variant) -> works. P.Item |> P.read!() |> P.load!(:code) -> unknown error. The other calculation, calculate :tagline, :string, expr(variant_name) , works with P.Item |> P.read!() |> P.load!(:tagline).
ZachDaniel
ZachDanielβ€’3y ago
is code on variant an aggregate? You can't aggregate over aggregates currently, which is why P.Item |> P.list!(:sequence_prefix) doesn't work I've lost track a bit of the specific issues here Could you make a separate thread for each one please? It seems like there is an issue w/ loading certain aggregates, and an issue loading a specific relationship?
waseigo
waseigoOPβ€’3y ago
code is an attribute of P.Variant, accessible within P.Item as aggregate variant_code. code is an attribute of P.Category, accessible within P.Item as aggregate category_code. P_item contains a calculation named code that concatenates aggregates variant_code and category_code. Apologies for the confusion and thank you for taking the time! I will split the issues, as it's not anymore about P.list().

Did you find this page helpful?