BulkCreate upsert not working

I'm using a BulkCreate action but it seems not to upsert correctly:
No description
No description
69 Replies
tommasop#2001
tommasop#2001OPβ€’2y ago
I also tried disabling Carbonite with same result. Sorry for using screenshots but it was the easiest way to show the problem.
ZachDaniel
ZachDanielβ€’2y ago
When you say not working what do you mean? It doesn’t return results by default, that’s an option you have to pass
frankdugan3
frankdugan3β€’2y ago
I'm trying out the bulk creates with upserts and returned results for my staging seeds file, working well so far. πŸ™‚ And I have to say, it's a fantastic API for that purpose. πŸš€
tommasop#2001
tommasop#2001OPβ€’2y ago
I'm passing return_records?: true and still it's not returning the upserted record and the product record is not updated
frankdugan3
frankdugan3β€’2y ago
Do you have stop_on_error?: true? Because otherwise it might not display an error that's causing a problem (that's been my experience).
ZachDaniel
ZachDanielβ€’2y ago
Oh interesting…that sounds like a bug @frankdugan3 do you have a reproduction for the errors not appearing that you mentioned?
frankdugan3
frankdugan3β€’2y ago
I don't remember the specific circumstance... I think it was on initial create when giving some bad fields as params... If I run into it again I'll create an issue now that I know it should error.
ZachDaniel
ZachDanielβ€’2y ago
it should return the errors at least πŸ™‚
frankdugan3
frankdugan3β€’2y ago
Yeah, I may have had both those options off when that happened. lol
tommasop#2001
tommasop#2001OPβ€’2y ago
@frankdugan3 you are right with stop_on_error?: true I have the error still there is something not working as I expect (but maybe as it should πŸ˜† ) I have a :create action (also used for upsert) for a Product that needs a data_in and a category_id relationships. there is an API call used only to update product quantities that returns a list of %{sku_code: "MAGP0.6.2", quantity: 14.0} I have a :unique_sku_code identity in product I add data_in_id and category_id making data become a list of [%{category_id: "b77fa8c6-330e-422f-8ee5-84277096821b", data_in_id: "221408ba-ff99-46ce-a01d-bccacc3579c7", quantity: 14.0, sku_code: "MAGP0.6.2"}] I would expect this bulk_create to only update the product quantity but it gives me an error:
MmsBiztalk.bulk_create!(
[%{category_id: "b77fa8c6-330e-422f-8ee5-84277096821b", data_in_id: "221408ba-ff99-46ce-a01d-bccacc3579c7", quantity: 14.0, sku_code: "MAGP0.6.2"}],
MmsBiztalk.Product,
:create,
upsert?: true,
upsert_identity: :unique_sku_code,
# for bulk actions upsert_fields must be specified
upsert_fields: [:quantity],
stop_on_error?: true,
return_records?: true
)
MmsBiztalk.bulk_create!(
[%{category_id: "b77fa8c6-330e-422f-8ee5-84277096821b", data_in_id: "221408ba-ff99-46ce-a01d-bccacc3579c7", quantity: 14.0, sku_code: "MAGP0.6.2"}],
MmsBiztalk.Product,
:create,
upsert?: true,
upsert_identity: :unique_sku_code,
# for bulk actions upsert_fields must be specified
upsert_fields: [:quantity],
stop_on_error?: true,
return_records?: true
)
to update only the product quantity instead it gives me an error where it is trying to update all the fields (setting nil to some needed ones).
[%Ash.Error.Unknown{errors: [%Ash.Error.Unknown.UnknownError{error: "** (Postgrex.Error) ERROR 23502 (not_null_violation) null value in column \"description_en\" of r
elation \"products\" violates not-null constraint\n\n table: products\n column: description_en\n\nFailing row contains (05ef01a1-1e12-4295-972f-656c431f6578, MAGP0.6.2, null, nul
l, null, null, null, null, null, null, null, null, null, null, null, null, null, 2023-05-25 09:06:32.841523, 2023-05-25 09:06:32.841523, 14, not_synced, null).", field: nil, changeset:
nil, query: nil, error_context: [], vars: [], path: [:create_or_update_resources], stacktrace: #Stacktrace<>, class: :unknown}], stacktraces?: true, changeset: nil, query: nil, error_
context: [], vars: [], path: [], stacktrace: #Stacktrace<>, class: :unknown}]
[%Ash.Error.Unknown{errors: [%Ash.Error.Unknown.UnknownError{error: "** (Postgrex.Error) ERROR 23502 (not_null_violation) null value in column \"description_en\" of r
elation \"products\" violates not-null constraint\n\n table: products\n column: description_en\n\nFailing row contains (05ef01a1-1e12-4295-972f-656c431f6578, MAGP0.6.2, null, nul
l, null, null, null, null, null, null, null, null, null, null, null, null, null, 2023-05-25 09:06:32.841523, 2023-05-25 09:06:32.841523, 14, not_synced, null).", field: nil, changeset:
nil, query: nil, error_context: [], vars: [], path: [:create_or_update_resources], stacktrace: #Stacktrace<>, class: :unknown}], stacktraces?: true, changeset: nil, query: nil, error_
context: [], vars: [], path: [], stacktrace: #Stacktrace<>, class: :unknown}]
Do I need to pass also the Product id to make the upsert work even if I have the :unique_sku_code identity? Or am I using the upsert in an unproper way?
ZachDaniel
ZachDanielβ€’2y ago
okay so I need to make sure that error shows up even if stop_on_error? is false
tommasop#2001
tommasop#2001OPβ€’2y ago
apart from error rising am I using the upsert correctly and if so why isn't the poduct quantity updated?
frankdugan3
frankdugan3β€’2y ago
I don't see :unique_sku_code in your create data: How would it be able to compare it against the existing row if that's the identity field? :thinkies: Oh, is that the name your identity for :sku_code? I wonder if it wants the field name instead.
tommasop#2001
tommasop#2001OPβ€’2y ago
this is the :unique_sku_code identity
identities do
identity :unique_sku_code, :sku_code, eager_check_with: MmsBiztalk
end
identities do
identity :unique_sku_code, :sku_code, eager_check_with: MmsBiztalk
end
frankdugan3
frankdugan3β€’2y ago
I'm not sure because I generally name my single-key identities the same as the field.
tommasop#2001
tommasop#2001OPβ€’2y ago
ok I can try that easily no I have the same error giving :sku_code as the upsert_identity
ZachDaniel
ZachDanielβ€’2y ago
okay so I made some small fixes, commented about in the announcement for bulk creates specifically we were actually not honoring the return_errors? option, and it was supposed to default to false which is technically a minor breaking change but this is a new-ish feature and I'd rather not go through the whole rigamarole of the breaking change process for it. lemme look over this again and see if I can spot the issue also @tommasop#2001 are you on the latest ash and ash_postgres?
tommasop#2001
tommasop#2001OPβ€’2y ago
I am on main in both
ZachDaniel
ZachDanielβ€’2y ago
πŸ‘Œ Actually I don’t think I’ve seen the bulk insert generated sql statement yet Is that in the logs? Did I just miss it? If we can see why that’s wrong the fix should be pretty clear
tommasop#2001
tommasop#2001OPβ€’2y ago
I'm using a list with a single product to test the behavior and with a LOG_LEVEL=debug this is what I see in iex
MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_identity: :unique_sku_code, upsert_fields: [:sku_code, :quantity], return_records?: true)
** (throw) {DBConnection, #Reference<0.1826028390.1079508994.123791>, %Ash.Error.Unknown.UnknownError{error: "** (Postgrex.Error) ERROR 23502 (not_null_violation) null value in column \"description_en\" of relation \"products\" violates not-null constraint\n\n table: products\n column: description_en\n\nFailing row contains (0b584a6a-5cc9-4f45-9a49-b360b67a512b, MAGP0.6.2, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 2023-05-25 14:21:28.74044, 2023-05-25 14:21:28.74044, 14, not_synced, null).", field: nil, changeset: nil, query: nil, error_context: [], vars: [], path: [], stacktrace: #Stacktrace<>, class: :unknown}}
(db_connection 2.5.0) lib/db_connection.ex:996: DBConnection.rollback/2
(ash 2.9.11) lib/ash/data_layer/data_layer.ex:288: Ash.DataLayer.transaction/4
(ash 2.9.11) lib/ash/actions/create/bulk.ex:191: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.1) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.1) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.1) lib/stream.ex:1026: Stream.do_transform_inner_list/7
(elixir 1.14.1) lib/stream.ex:1811: Enumerable.Stream.do_each/4
(elixir 1.14.1) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.11) lib/ash/actions/create/bulk.ex:405: Ash.Actions.Create.Bulk.do_run/5
(ash 2.9.11) lib/ash/actions/create/bulk.ex:69: Ash.Actions.Create.Bulk.run/5
(ash 2.9.11) lib/ash/api/api.ex:1878: Ash.Api.bulk_create!/5
/home/tommasop/code/work/magic/mms_biztalk/lib/mms_biztalk/flows/steps/upsert_resources.ex:1: (file)
MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_identity: :unique_sku_code, upsert_fields: [:sku_code, :quantity], return_records?: true)
** (throw) {DBConnection, #Reference<0.1826028390.1079508994.123791>, %Ash.Error.Unknown.UnknownError{error: "** (Postgrex.Error) ERROR 23502 (not_null_violation) null value in column \"description_en\" of relation \"products\" violates not-null constraint\n\n table: products\n column: description_en\n\nFailing row contains (0b584a6a-5cc9-4f45-9a49-b360b67a512b, MAGP0.6.2, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 2023-05-25 14:21:28.74044, 2023-05-25 14:21:28.74044, 14, not_synced, null).", field: nil, changeset: nil, query: nil, error_context: [], vars: [], path: [], stacktrace: #Stacktrace<>, class: :unknown}}
(db_connection 2.5.0) lib/db_connection.ex:996: DBConnection.rollback/2
(ash 2.9.11) lib/ash/data_layer/data_layer.ex:288: Ash.DataLayer.transaction/4
(ash 2.9.11) lib/ash/actions/create/bulk.ex:191: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.1) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.1) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.1) lib/stream.ex:1026: Stream.do_transform_inner_list/7
(elixir 1.14.1) lib/stream.ex:1811: Enumerable.Stream.do_each/4
(elixir 1.14.1) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.11) lib/ash/actions/create/bulk.ex:405: Ash.Actions.Create.Bulk.do_run/5
(ash 2.9.11) lib/ash/actions/create/bulk.ex:69: Ash.Actions.Create.Bulk.run/5
(ash 2.9.11) lib/ash/api/api.ex:1878: Ash.Api.bulk_create!/5
/home/tommasop/code/work/magic/mms_biztalk/lib/mms_biztalk/flows/steps/upsert_resources.ex:1: (file)
ZachDaniel
ZachDanielβ€’2y ago
πŸ€” THat is pretty strange Usually there is a log for the actual query Try doing this
try do
MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_identity: :unique_sku_code, upsert_fields: [:sku_code, :quantity], return_records?: true)
catch
thing ->
thing
end
try do
MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_identity: :unique_sku_code, upsert_fields: [:sku_code, :quantity], return_records?: true)
catch
thing ->
thing
end
I'm wondering if the thrown error is causing a crash or somethign and its not getting to log the initial query attempt perhaps you can get query logs from the database somehow? We have it working in ash_postgres tests, producing queries like:
INSERT INTO "posts" ("created_at","decimal","id","price","title","type","uniq_one","uniq_two","updated_at") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9),($10,$11,$12,$13,$14,$15,$16,$17,$18) ON CONFLICT (uniq_one, uniq_two) WHERE (type = 'sponsored') DO UPDATE SET "price" = EXCLUDED."price" RETURNING "author_id","organization_id","updated_at","created_at","uniq_custom_two","uniq_custom_one","uniq_two","uniq_one","point","status_enum","status_enum","status","decimal","price","type","category","public","score","title","id" [~U[2023-05-25 14:45:01.312299Z], Decimal.new("0"), "122ba2db-c858-4347-91e7-e39bd564ff05", 1000, "something", :sponsored, "one", "two", ~U[2023-05-25 14:45:01.312299Z], ~U[2023-05-25 14:45:01.312250Z], Decimal.new("0"), "4e694979-ee64-4093-9032-63feccaa932d", 20000, "else", :sponsored, "three", "four", ~U[2023-05-25 14:45:01.312250Z]]
INSERT INTO "posts" ("created_at","decimal","id","price","title","type","uniq_one","uniq_two","updated_at") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9),($10,$11,$12,$13,$14,$15,$16,$17,$18) ON CONFLICT (uniq_one, uniq_two) WHERE (type = 'sponsored') DO UPDATE SET "price" = EXCLUDED."price" RETURNING "author_id","organization_id","updated_at","created_at","uniq_custom_two","uniq_custom_one","uniq_two","uniq_one","point","status_enum","status_enum","status","decimal","price","type","category","public","score","title","id" [~U[2023-05-25 14:45:01.312299Z], Decimal.new("0"), "122ba2db-c858-4347-91e7-e39bd564ff05", 1000, "something", :sponsored, "one", "two", ~U[2023-05-25 14:45:01.312299Z], ~U[2023-05-25 14:45:01.312250Z], Decimal.new("0"), "4e694979-ee64-4093-9032-63feccaa932d", 20000, "else", :sponsored, "three", "four", ~U[2023-05-25 14:45:01.312250Z]]
and to be 100% sure you've updated to latest ash and ash_postgres main with mix deps.update ash ash_postgres? I ask that question a lot, but its always worth asking πŸ˜† Sorry if its repetetive.
tommasop#2001
tommasop#2001OPβ€’2y ago
double checked it and I have the latest ash and ash_postgres
frankdugan3
frankdugan3β€’2y ago
Should I be able to upsert with :id as the identity?
uuid_primary_key :id, writable?: true
uuid_primary_key :id, writable?: true
ZachDaniel
ZachDanielβ€’2y ago
IIRC that is the default behavior @tommasop#2001 can you see if it works if you use the id to upsert (by not providing an upsert_identity?)
tommasop#2001
tommasop#2001OPβ€’2y ago
of course it gives me the same error
ZachDaniel
ZachDanielβ€’2y ago
tommasop#2001
tommasop#2001OPβ€’2y ago
pry(1)> MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_fields: [:sku_code, :quantity], return_records?: true) ** (throw) {DBConnection, #Reference<0.1164303867.3233546242.136685>, %Ash.Error.Unknown.UnknownError{error: "** (Postgrex.Error) ERROR 23502 (not_null_violation) null value in column \"description_en\" of relation \"products\" violates not-null constraint\n\n table: products\n column: description_en\n\nFailing row contains (126ec224-ca4e-4bc5-a1a2-251d00520876, MAGP0.6.2, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 2023-05-25 15:02:27.591724, 2023-05-25 15:02:27.591724, 14, not_synced, null).", field: nil, changeset: nil, query: nil, error_context: [], vars: [], path: [], stacktrace: #Stacktrace<>, class: :unknown}}
(db_connection 2.5.0) lib/db_connection.ex:996: DBConnection.rollback/2
(ash 2.9.12) lib/ash/data_layer/data_layer.ex:288: Ash.DataLayer.transaction/4
(ash 2.9.12) lib/ash/actions/create/bulk.ex:187: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.1) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.1) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.1) lib/stream.ex:1026: Stream.do_transform_inner_list/7
(elixir 1.14.1) lib/stream.ex:1811: Enumerable.Stream.do_each/4
(elixir 1.14.1) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.12) lib/ash/actions/create/bulk.ex:398: Ash.Actions.Create.Bulk.do_run/5
(ash 2.9.12) lib/ash/actions/create/bulk.ex:69: Ash.Actions.Create.Bulk.run/5
(ash 2.9.12) lib/ash/api/api.ex:1884: Ash.Api.bulk_create!/5
/home/tommasop/code/work/magic/mms_biztalk/lib/mms_biztalk/flows/steps/upsert_resources.ex:1: (file)
pry(1)> MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_fields: [:sku_code, :quantity], return_records?: true) ** (throw) {DBConnection, #Reference<0.1164303867.3233546242.136685>, %Ash.Error.Unknown.UnknownError{error: "** (Postgrex.Error) ERROR 23502 (not_null_violation) null value in column \"description_en\" of relation \"products\" violates not-null constraint\n\n table: products\n column: description_en\n\nFailing row contains (126ec224-ca4e-4bc5-a1a2-251d00520876, MAGP0.6.2, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 2023-05-25 15:02:27.591724, 2023-05-25 15:02:27.591724, 14, not_synced, null).", field: nil, changeset: nil, query: nil, error_context: [], vars: [], path: [], stacktrace: #Stacktrace<>, class: :unknown}}
(db_connection 2.5.0) lib/db_connection.ex:996: DBConnection.rollback/2
(ash 2.9.12) lib/ash/data_layer/data_layer.ex:288: Ash.DataLayer.transaction/4
(ash 2.9.12) lib/ash/actions/create/bulk.ex:187: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.1) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.1) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.1) lib/stream.ex:1026: Stream.do_transform_inner_list/7
(elixir 1.14.1) lib/stream.ex:1811: Enumerable.Stream.do_each/4
(elixir 1.14.1) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.12) lib/ash/actions/create/bulk.ex:398: Ash.Actions.Create.Bulk.do_run/5
(ash 2.9.12) lib/ash/actions/create/bulk.ex:69: Ash.Actions.Create.Bulk.run/5
(ash 2.9.12) lib/ash/api/api.ex:1884: Ash.Api.bulk_create!/5
/home/tommasop/code/work/magic/mms_biztalk/lib/mms_biztalk/flows/steps/upsert_resources.ex:1: (file)
this is the collection
ZachDaniel
ZachDanielβ€’2y ago
I wonder
tommasop#2001
tommasop#2001OPβ€’2y ago
pry(1)> input.resources_attributes
[
%{
category_id: "054bb31e-932d-4509-b96c-18af44abf5ad",
data_in_id: "8b58c644-c9a4-4ff7-8314-ea8262a826fb",
id: "73c7a25b-1bd3-45f4-bb5d-0dae1b293022",
quantity: 14.0,
sku_code: "MAGP0.6.2"
}
]
pry(1)> input.resources_attributes
[
%{
category_id: "054bb31e-932d-4509-b96c-18af44abf5ad",
data_in_id: "8b58c644-c9a4-4ff7-8314-ea8262a826fb",
id: "73c7a25b-1bd3-45f4-bb5d-0dae1b293022",
quantity: 14.0,
sku_code: "MAGP0.6.2"
}
]
ZachDaniel
ZachDanielβ€’2y ago
I wonder if postgres is validating the insert before trying to apply the on conflict? like "this insert would fail, and might be an insert" can you try filling in the required fields in your input? And seeing if that creates a row or if it updates
tommasop#2001
tommasop#2001OPβ€’2y ago
good idea with all the needed fields it works but it updates all the fields:
p = MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_fields: [:sku_code, :quantity], return_records?: true)
%Ash.BulkResult{
status: :success,
errors: [],
records: [
#MmsBiztalk.Product<
category: #Ash.NotLoaded<:relationship>,
data_in: #Ash.NotLoaded<:relationship>,
__meta__: #Ecto.Schema.Metadata<:loaded, "products">,
id: "1905788c-1f86-4cef-a92c-2480ede1a59f",
sku_code: "MAGP0.6.2",
brand: "lotus",
description_en: "cool",
description_full_it: nil,
description_full_en: nil,
description_full_es: nil,
description_full_de: nil,
gross_unit_weight: 1.0,
gross_unit_weight_measurement: nil,
price: 1.0,
macrofamily_code: "A",
family_code: "A",
logistic_class: "A",
created_at: nil,
quantity: 14.0,
status: :not_synced,
inserted_at: ~U[2023-05-25 15:13:14.831601Z],
updated_at: ~U[2023-05-25 15:13:14.831601Z],
deleted_at: nil,
data_in_id: nil,
category_id: nil,
aggregates: %{},
calculations: %{},
__order__: nil,
...
>
],
notifications: [],
error_count: 0
}
p = MmsBiztalk.bulk_create!(input.resources_attributes, input.resource, :create, upsert?: true, upsert_fields: [:sku_code, :quantity], return_records?: true)
%Ash.BulkResult{
status: :success,
errors: [],
records: [
#MmsBiztalk.Product<
category: #Ash.NotLoaded<:relationship>,
data_in: #Ash.NotLoaded<:relationship>,
__meta__: #Ecto.Schema.Metadata<:loaded, "products">,
id: "1905788c-1f86-4cef-a92c-2480ede1a59f",
sku_code: "MAGP0.6.2",
brand: "lotus",
description_en: "cool",
description_full_it: nil,
description_full_en: nil,
description_full_es: nil,
description_full_de: nil,
gross_unit_weight: 1.0,
gross_unit_weight_measurement: nil,
price: 1.0,
macrofamily_code: "A",
family_code: "A",
logistic_class: "A",
created_at: nil,
quantity: 14.0,
status: :not_synced,
inserted_at: ~U[2023-05-25 15:13:14.831601Z],
updated_at: ~U[2023-05-25 15:13:14.831601Z],
deleted_at: nil,
data_in_id: nil,
category_id: nil,
aggregates: %{},
calculations: %{},
__order__: nil,
...
>
],
notifications: [],
error_count: 0
}
the behavior is consistent if I use id or another identity (:unique_sku_code)
ZachDaniel
ZachDanielβ€’2y ago
are you sure its updating all the fields and not just creating a new record? if its updating more than the upsert_fields then something very very very strange is happening ohhhhh 😒 I think I found it maybe Yeah, this isn't your fault, sorry actually...okay well, I found a place that is definitely problematic and maybe we're looking somewhere along these lines its not a manual create action is it? what happens if you do this in iex
Ash.DataLayer.data_layer_can?(MmsBiztalk.Product, :bulk_create)
Ash.DataLayer.data_layer_can?(MmsBiztalk.Product, :bulk_create)
Do you get true?
tommasop#2001
tommasop#2001OPβ€’2y ago
yes
ZachDaniel
ZachDanielβ€’2y ago
😒 thought I had figured it out I fixed something, but I don't think it will help you but try pulling main anyway
tommasop#2001
tommasop#2001OPβ€’2y ago
ok thanks
ZachDaniel
ZachDanielβ€’2y ago
If this fixes it then we have some more investigating to do as to how you even got into this case anyway. But its probably not it unfortunately lets double check this: https://discord.com/channels/711271361523351632/1110978687203016764/1111312811247804457 i.e use a static id and do your upsert twice can I see the :create action?
tommasop#2001
tommasop#2001OPβ€’2y ago
create :create do
description ""

argument :data_in_id, :uuid do
allow_nil? false
end

argument :category_id, :uuid do
allow_nil? false
end

change manage_relationship(:data_in_id, :data_in, type: :append_and_remove)
change manage_relationship(:category_id, :category, type: :append_and_remove)
end
create :create do
description ""

argument :data_in_id, :uuid do
allow_nil? false
end

argument :category_id, :uuid do
allow_nil? false
end

change manage_relationship(:data_in_id, :data_in, type: :append_and_remove)
change manage_relationship(:category_id, :category, type: :append_and_remove)
end
ZachDaniel
ZachDanielβ€’2y ago
Seems pretty standard
tommasop#2001
tommasop#2001OPβ€’2y ago
it's not upserting but creating new records
ZachDaniel
ZachDanielβ€’2y ago
even when the id matches? Do you have a default_accept? Is sku_code writable? is id writable?
tommasop#2001
tommasop#2001OPβ€’2y ago
sku_code is writable, and no default_accept?, id is writeable
ZachDaniel
ZachDanielβ€’2y ago
πŸ€” πŸ€” πŸ€” πŸ€” okay, so I think I need to see like a complete script or something as well as the resource (in an ideal world, this would be reproduced in a test in ash_postgres)
tommasop#2001
tommasop#2001OPβ€’2y ago
I can try to write a minimal reproduction test in ash_postgres
ZachDaniel
ZachDanielβ€’2y ago
that would be amazing πŸ™‚
tommasop#2001
tommasop#2001OPβ€’2y ago
will do my best πŸ™‚
frankdugan3
frankdugan3β€’2y ago
I'm trying to do a bulk insert w/ a managed relationship like this:
%{
name: "Cyberdyne Systems",
code: "CYD",
notes: "Develops military and civilian robotics, including Skynet.",
type: %{
label: "Robotics and Artificial Intelligence",
description:
"Focused on the development of military and civilian robotics, including the AI system Skynet."
}
},
%{
name: "Cyberdyne Systems",
code: "CYD",
notes: "Develops military and civilian robotics, including Skynet.",
type: %{
label: "Robotics and Artificial Intelligence",
description:
"Focused on the development of military and civilian robotics, including the AI system Skynet."
}
},
create :create do
argument :type, :map, allow_nil?: false

change manage_relationship(:type, :type,
on_lookup: :relate,
on_no_match: :create,
on_match: :ignore,
on_missing: :unrelate
)
end
create :create do
argument :type, :map, allow_nil?: false

change manage_relationship(:type, :type,
on_lookup: :relate,
on_no_match: :create,
on_match: :ignore,
on_missing: :unrelate
)
end
Which produces this error:
** (Ash.Error.Unknown) Unknown Error

* ** (ArgumentError) unknown field for :on_conflict, got: :type
(ecto 3.10.1) lib/ecto/repo/schema.ex:739: Ecto.Repo.Schema.field_source!/2
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ecto 3.10.1) lib/ecto/repo/schema.ex:703: Ecto.Repo.Schema.on_conflict/5
(ecto 3.10.1) lib/ecto/repo/schema.ex:55: Ecto.Repo.Schema.do_insert_all/7
(ash_postgres 1.3.28) lib/data_layer.ex:1096: AshPostgres.DataLayer.bulk_create/3
(ash 2.9.12) lib/ash/actions/create/bulk.ex:759: Ash.Actions.Create.Bulk.run_batch/10
(ash 2.9.12) lib/ash/actions/create/bulk.ex:229: anonymous fn/9 in Ash.Actions.Create.Bulk.do_run/5
(ecto_sql 3.10.1) lib/ecto/adapters/sql.ex:1203: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection 2.5.0) lib/db_connection.ex:1630: DBConnection.run_transaction/4
(ash 2.9.12) lib/ash/actions/create/bulk.ex:191: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.5) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/stream.ex:1026: Stream.do_transform_inner_list/7
(elixir 1.14.5) lib/stream.ex:1813: Enumerable.Stream.do_each/4
(elixir 1.14.5) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.12) lib/ash/actions/create/bulk.ex:405: Ash.Actions.Create.Bulk.do_run/5
(ash 2.9.12) lib/ash/actions/create/bulk.ex:69: Ash.Actions.Create.Bulk.run/5
(ash 2.9.12) lib/ash/api/api.ex:1878: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:131: Hsm.Seed.seed_vendors/0
(ash 2.9.12) lib/ash/api/api.ex:1881: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:131: Hsm.Seed.seed_vendors/0
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
** (Ash.Error.Unknown) Unknown Error

* ** (ArgumentError) unknown field for :on_conflict, got: :type
(ecto 3.10.1) lib/ecto/repo/schema.ex:739: Ecto.Repo.Schema.field_source!/2
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ecto 3.10.1) lib/ecto/repo/schema.ex:703: Ecto.Repo.Schema.on_conflict/5
(ecto 3.10.1) lib/ecto/repo/schema.ex:55: Ecto.Repo.Schema.do_insert_all/7
(ash_postgres 1.3.28) lib/data_layer.ex:1096: AshPostgres.DataLayer.bulk_create/3
(ash 2.9.12) lib/ash/actions/create/bulk.ex:759: Ash.Actions.Create.Bulk.run_batch/10
(ash 2.9.12) lib/ash/actions/create/bulk.ex:229: anonymous fn/9 in Ash.Actions.Create.Bulk.do_run/5
(ecto_sql 3.10.1) lib/ecto/adapters/sql.ex:1203: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection 2.5.0) lib/db_connection.ex:1630: DBConnection.run_transaction/4
(ash 2.9.12) lib/ash/actions/create/bulk.ex:191: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.5) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/stream.ex:1026: Stream.do_transform_inner_list/7
(elixir 1.14.5) lib/stream.ex:1813: Enumerable.Stream.do_each/4
(elixir 1.14.5) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.12) lib/ash/actions/create/bulk.ex:405: Ash.Actions.Create.Bulk.do_run/5
(ash 2.9.12) lib/ash/actions/create/bulk.ex:69: Ash.Actions.Create.Bulk.run/5
(ash 2.9.12) lib/ash/api/api.ex:1878: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:131: Hsm.Seed.seed_vendors/0
(ash 2.9.12) lib/ash/api/api.ex:1881: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:131: Hsm.Seed.seed_vendors/0
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
Is that supported, or should I be doing separate inserts and just directly manage the :type_id?
ZachDaniel
ZachDanielβ€’2y ago
I think its fine, but what are you passing as opts? it looks like something is getting type instead of type_id perhaps your identity is wrong?
frankdugan3
frankdugan3β€’2y ago
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :code,
upsert_fields: [
:name,
:notes,
:updated_at,
:active,
:type
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_records?: true
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :code,
upsert_fields: [
:name,
:notes,
:updated_at,
:active,
:type
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_records?: true
If I use :type_id instead of :type, it doesn't upsert the types (vendors have already been created without type) and also doesn't create any errors. This is the query w/ :type_id:
[debug] QUERY OK db=1.5ms
INSERT INTO "vendors" ("active","code","id","name","notes","inserted_at","updated_at") VALUES
...
[debug] QUERY OK db=1.5ms
INSERT INTO "vendors" ("active","code","id","name","notes","inserted_at","updated_at") VALUES
...
ZachDaniel
ZachDanielβ€’2y ago
Are you on the latest ash? Just released recently? add return_errors?: true
frankdugan3
frankdugan3β€’2y ago
error_count: 0, errors: [], same otherwise.
ZachDaniel
ZachDanielβ€’2y ago
so its doing like...nothing?
frankdugan3
frankdugan3β€’2y ago
Nothing w/ the type or type_id, but all the other attributes are creating/upserting. To clarify: the types have not been created first, attempting to leverage the manage_relationship. Totally get it if that's not supported.
ZachDaniel
ZachDanielβ€’2y ago
It should be πŸ™‚ Could you try to reproduce in a test on ash_postgres?
frankdugan3
frankdugan3β€’2y ago
It was a simple test, you want it as a PR?
ZachDaniel
ZachDanielβ€’2y ago
yes please ❀️ will take a look at it tomorrow
tommasop#2001
tommasop#2001OPβ€’2y ago
I'm setting up the test and it seems the problem arises when you have attributes with allow_nil? false and without a default I will set up a test with different resources because otherwise I'll break all other tests or let me know if there is a better way
ZachDaniel
ZachDanielβ€’2y ago
Latest release includes multiple bulk create fixes
frankdugan3
frankdugan3β€’2y ago
Updated to latest releases of everything, getting a new error now. This:
def seed_vendors() do
%{status: :success, records: vendors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
notes: "Produces advanced androids and artificial intelligence systems.",
type: %{
label: "Robotics",
description:
"Specializes in the design and manufacturing of advanced robotic systems."
}
},
# ...
],
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :name,
upsert_fields: [
:code,
:notes,
:updated_at,
:active,
:type_id
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_records?: true,
return_errors?: true
)
end
def seed_vendors() do
%{status: :success, records: vendors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
notes: "Produces advanced androids and artificial intelligence systems.",
type: %{
label: "Robotics",
description:
"Specializes in the design and manufacturing of advanced robotic systems."
}
},
# ...
],
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :name,
upsert_fields: [
:code,
:notes,
:updated_at,
:active,
:type_id
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_records?: true,
return_errors?: true
)
end
Results in this:
rollback []
** (Ash.Error.Unknown) Unknown Error

* 1
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.14) lib/ash/error/error.ex:207: Ash.Error.to_error_class/2
(ash 2.9.14) lib/ash/api/api.ex:1887: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:134: Hsm.Seed.seed_vendors/0
(elixir 1.14.5) src/elixir_compiler.erl:66: :elixir_compiler.dispatch/4
(elixir 1.14.5) src/elixir_compiler.erl:51: :elixir_compiler.compile/3
(elixir 1.14.5) src/elixir_compiler.erl:39: :elixir_compiler.eval_or_compile/3
(elixir 1.14.5) src/elixir_lexical.erl:15: :elixir_lexical.run/3
(elixir 1.14.5) src/elixir_compiler.erl:17: :elixir_compiler.quoted/3
(elixir 1.14.5) lib/module/parallel_checker.ex:110: Module.ParallelChecker.verify/1
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
(elixir 1.14.5) src/elixir_compiler.erl:66: :elixir_compiler.dispatch/4
(elixir 1.14.5) src/elixir_compiler.erl:51: :elixir_compiler.compile/3
(ash 2.9.14) lib/ash/api/api.ex:1887: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:134: Hsm.Seed.seed_vendors/0
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
[os_mon] memory supervisor port (memsup): Erlang has closed
[os_mon] cpu supervisor port (cpu_sup): Erlang has closed
rollback []
** (Ash.Error.Unknown) Unknown Error

* 1
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.14) lib/ash/error/error.ex:207: Ash.Error.to_error_class/2
(ash 2.9.14) lib/ash/api/api.ex:1887: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:134: Hsm.Seed.seed_vendors/0
(elixir 1.14.5) src/elixir_compiler.erl:66: :elixir_compiler.dispatch/4
(elixir 1.14.5) src/elixir_compiler.erl:51: :elixir_compiler.compile/3
(elixir 1.14.5) src/elixir_compiler.erl:39: :elixir_compiler.eval_or_compile/3
(elixir 1.14.5) src/elixir_lexical.erl:15: :elixir_lexical.run/3
(elixir 1.14.5) src/elixir_compiler.erl:17: :elixir_compiler.quoted/3
(elixir 1.14.5) lib/module/parallel_checker.ex:110: Module.ParallelChecker.verify/1
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
(elixir 1.14.5) src/elixir_compiler.erl:66: :elixir_compiler.dispatch/4
(elixir 1.14.5) src/elixir_compiler.erl:51: :elixir_compiler.compile/3
(ash 2.9.14) lib/ash/api/api.ex:1887: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:134: Hsm.Seed.seed_vendors/0
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
[os_mon] memory supervisor port (memsup): Erlang has closed
[os_mon] cpu supervisor port (cpu_sup): Erlang has closed
tommasop#2001
tommasop#2001OPβ€’2y ago
Here the error stays the same I added a test with a Manager resource which belongs to Organization the test passes for creation but fails for upsert hope the test makes sense πŸ™‚
ZachDaniel
ZachDanielβ€’2y ago
Will look into both tonight or tomorrow, thank you both for the tests and patience πŸ™‚ @tommasop#2001 alright, so, here is the deal that is actually not supported πŸ™‚ INSERT INTO null constraints are checked first So because it might actually do a create, this won't work You'll need to use ecto to do your update statement and/or wait until bulk updates come for Ash However, Ash should have called that invalid before you got there actually instead of a postgres error I've fixed that issue. It was a missing required check in the bulk create logic. @frankdugan3 I don't know whats going on w/ that error....seems like the error_count is somehow leaking out? Or maybe something in here...:
defp errors(result, invalid, opts) when is_list(invalid) do
Enum.reduce(invalid, {result.error_count, result.errors}, fn invalid, {error_count, errors} ->
errors(%{result | error_count: error_count, errors: errors}, invalid, opts)
end)
end

defp errors(result, {:error, error}, opts) do
if opts[:return_errors?] do
{result.error_count + 1, [error | result.errors]}
else
{result.error_count + 1, []}
end
end

defp errors(result, invalid, opts) do
if Enumerable.impl_for(invalid) do
invalid = Enum.to_list(invalid)
errors(result, invalid, opts)
else
errors(result, {:error, invalid}, opts)
end
end
defp errors(result, invalid, opts) when is_list(invalid) do
Enum.reduce(invalid, {result.error_count, result.errors}, fn invalid, {error_count, errors} ->
errors(%{result | error_count: error_count, errors: errors}, invalid, opts)
end)
end

defp errors(result, {:error, error}, opts) do
if opts[:return_errors?] do
{result.error_count + 1, [error | result.errors]}
else
{result.error_count + 1, []}
end
end

defp errors(result, invalid, opts) do
if Enumerable.impl_for(invalid) do
invalid = Enum.to_list(invalid)
errors(result, invalid, opts)
else
errors(result, {:error, invalid}, opts)
end
end
okay, found it Something in your request is failing @frankdugan3 but the error message was being swallowed So it might still be broken, but we should get more info πŸ™‚
frankdugan3
frankdugan3β€’2y ago
OK, latest of of everything. This:
def seed_vendors(vendor_types) do
%{status: :success, records: vendors, errors: errors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
type_id: Map.get(vendor_types, "Robotics"),
notes: "Produces advanced androids and artificial intelligence systems."
},
# ...
],
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :name,
upsert_fields: [
:type_id,
:code,
:notes,
:updated_at,
:active
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_errors?: true,
return_records?: true
)
def seed_vendors(vendor_types) do
%{status: :success, records: vendors, errors: errors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
type_id: Map.get(vendor_types, "Robotics"),
notes: "Produces advanced androids and artificial intelligence systems."
},
# ...
],
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :name,
upsert_fields: [
:type_id,
:code,
:notes,
:updated_at,
:active
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_errors?: true,
return_records?: true
)
Results in this:
** (FunctionClauseError) no function clause matching in Enum.flat_map_list/2

The following arguments were given to Enum.flat_map_list/2:

# 1
nil

# 2
#Function<12.129275706/1 in Ash.Error.flatten_preserving_keywords/1>

Attempted function clauses (showing 2 out of 2):

defp flat_map_list([head | tail], fun)
defp flat_map_list([], _fun)

(elixir 1.14.5) lib/enum.ex:4248: Enum.flat_map_list/2
(elixir 1.14.5) lib/enum.ex:4250: Enum.flat_map_list/2
(ash 2.9.15) lib/ash/error/error.ex:205: Ash.Error.to_error_class/2
(ash 2.9.15) lib/ash/api/api.ex:1887: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:253: Hsm.Seed.seed_vendors/1
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
** (FunctionClauseError) no function clause matching in Enum.flat_map_list/2

The following arguments were given to Enum.flat_map_list/2:

# 1
nil

# 2
#Function<12.129275706/1 in Ash.Error.flatten_preserving_keywords/1>

Attempted function clauses (showing 2 out of 2):

defp flat_map_list([head | tail], fun)
defp flat_map_list([], _fun)

(elixir 1.14.5) lib/enum.ex:4248: Enum.flat_map_list/2
(elixir 1.14.5) lib/enum.ex:4250: Enum.flat_map_list/2
(ash 2.9.15) lib/ash/error/error.ex:205: Ash.Error.to_error_class/2
(ash 2.9.15) lib/ash/api/api.ex:1887: Ash.Api.bulk_create!/5
priv/repo/seeds/seed.exs:253: Hsm.Seed.seed_vendors/1
(elixir 1.14.5) lib/code.ex:1260: Code.require_file/2
(mix 1.14.5) lib/mix/tasks/run.ex:144: Mix.Tasks.Run.run/5
(mix 1.14.5) lib/mix/tasks/run.ex:84: Mix.Tasks.Run.run/1
(mix 1.14.5) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
(mix 1.14.5) lib/mix/task.ex:479: Mix.Task.run_alias/6
(mix 1.14.5) lib/mix/cli.ex:84: Mix.CLI.run_task/2
If I do this:
def seed_vendors() do
%{status: :success, records: vendors, errors: errors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
type: %{
label: "Robotics",
description:
"Specializes in the design and manufacturing of advanced robotic systems."
},
notes: "Produces advanced androids and artificial intelligence systems."
},
# ...
],
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :name,
upsert_fields: [
:type_id,
:code,
:notes,
:updated_at,
:active
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_errors?: true,
return_records?: true
)
def seed_vendors() do
%{status: :success, records: vendors, errors: errors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
type: %{
label: "Robotics",
description:
"Specializes in the design and manufacturing of advanced robotic systems."
},
notes: "Produces advanced androids and artificial intelligence systems."
},
# ...
],
Hsm.Ash.Vendors.Vendor,
:create,
upsert?: true,
upsert_identity: :name,
upsert_fields: [
:type_id,
:code,
:notes,
:updated_at,
:active
],
stop_on_error?: true,
authorize?: false,
actor: nil,
return_errors?: true,
return_records?: true
)
I actually get a proper error, and I can see I had a changeset validation problem. So I think we're making progress on the errors! πŸ˜„
%Ash.BulkResult{
status: :partial_success,
errors: [
#Ash.Changeset<
# ...
context: %{bulk_create: %{index: 0}},
valid?: false
>
# ...
],
records: [],
notifications: [],
error_count: 20
}
%Ash.BulkResult{
status: :partial_success,
errors: [
#Ash.Changeset<
# ...
context: %{bulk_create: %{index: 0}},
valid?: false
>
# ...
],
records: [],
notifications: [],
error_count: 20
}
So the upsert may be working once I fix my data input. Looks like it's just error handling that has a few edge cases.
ZachDaniel
ZachDanielβ€’2y ago
Okay, I think I found a place that could cause errors to be something like [nil] which would yield that error Just pushed a change up to main that ought to help with that
frankdugan3
frankdugan3β€’2y ago
OK, making progress, but ran into a new error. πŸ˜„ When doing this variety of bulk create:
def seed_vendors() do
%{status: :success, records: vendors, errors: errors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
tax_id_type: :None,
tax_exemption_reason: "Exempt",
type: %{
label: "Robotics",
description:
"Specializes in the design and manufacturing of advanced robotic systems."
},
notes: "Produces advanced androids and artificial intelligence systems."
},
def seed_vendors() do
%{status: :success, records: vendors, errors: errors} =
Hsm.Ash.Vendors.bulk_create!(
[
%{
name: "Tyrell Corporation",
code: "TYR",
tax_id_type: :None,
tax_exemption_reason: "Exempt",
type: %{
label: "Robotics",
description:
"Specializes in the design and manufacturing of advanced robotic systems."
},
notes: "Produces advanced androids and artificial intelligence systems."
},
with this action:
create :create do
argument :type, :map, allow_nil?: false

change manage_relationship(:type, :type,
on_lookup: :relate,
on_no_match: :create,
on_match: :ignore,
on_missing: :unrelate,
use_identities: [:id, :label]
)
end
create :create do
argument :type, :map, allow_nil?: false

change manage_relationship(:type, :type,
on_lookup: :relate,
on_no_match: :create,
on_match: :ignore,
on_missing: :unrelate,
use_identities: [:id, :label]
)
end
I get this error:
** (KeyError) key :keys not found in: nil. If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
(ash 2.9.16) lib/ash/actions/managed_relationships.ex:601: anonymous fn/2 in Ash.Actions.ManagedRelationships.pkeys/2
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.16) lib/ash/actions/managed_relationships.ex:107: anonymous fn/4 in Ash.Actions.ManagedRelationships.setup_managed_belongs_to_relationships/3
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/enum.ex:2514: Enum.reduce_while/3
(ash 2.9.16) lib/ash/actions/managed_relationships.ex:102: Ash.Actions.ManagedRelationships.setup_managed_belongs_to_relationships/3
(ash 2.9.16) lib/ash/actions/create/bulk.ex:728: anonymous fn/3 in Ash.Actions.Create.Bulk.run_batch/11
(elixir 1.14.5) lib/enum.ex:4307: anonymous fn/3 in Enum.reduce/3
(elixir 1.14.5) lib/stream.ex:1801: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/stream.ex:1813: Enumerable.Stream.do_each/4
(elixir 1.14.5) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.16) lib/ash/actions/create/bulk.ex:713: Ash.Actions.Create.Bulk.run_batch/11
(ash 2.9.16) lib/ash/actions/create/bulk.ex:225: anonymous fn/9 in Ash.Actions.Create.Bulk.do_run/5
(ecto_sql 3.10.1) lib/ecto/adapters/sql.ex:1203: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection 2.5.0) lib/db_connection.ex:1630: DBConnection.run_transaction/4
(ash 2.9.16) lib/ash/actions/create/bulk.ex:187: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.5) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/stream.ex:1026: Stream.do_transform_inner_list/7
** (KeyError) key :keys not found in: nil. If you are using the dot syntax, such as map.field, make sure the left-hand side of the dot is a map
(ash 2.9.16) lib/ash/actions/managed_relationships.ex:601: anonymous fn/2 in Ash.Actions.ManagedRelationships.pkeys/2
(elixir 1.14.5) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ash 2.9.16) lib/ash/actions/managed_relationships.ex:107: anonymous fn/4 in Ash.Actions.ManagedRelationships.setup_managed_belongs_to_relationships/3
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/enum.ex:2514: Enum.reduce_while/3
(ash 2.9.16) lib/ash/actions/managed_relationships.ex:102: Ash.Actions.ManagedRelationships.setup_managed_belongs_to_relationships/3
(ash 2.9.16) lib/ash/actions/create/bulk.ex:728: anonymous fn/3 in Ash.Actions.Create.Bulk.run_batch/11
(elixir 1.14.5) lib/enum.ex:4307: anonymous fn/3 in Enum.reduce/3
(elixir 1.14.5) lib/stream.ex:1801: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/stream.ex:1813: Enumerable.Stream.do_each/4
(elixir 1.14.5) lib/enum.ex:4307: Enum.reduce/3
(ash 2.9.16) lib/ash/actions/create/bulk.ex:713: Ash.Actions.Create.Bulk.run_batch/11
(ash 2.9.16) lib/ash/actions/create/bulk.ex:225: anonymous fn/9 in Ash.Actions.Create.Bulk.do_run/5
(ecto_sql 3.10.1) lib/ecto/adapters/sql.ex:1203: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection 2.5.0) lib/db_connection.ex:1630: DBConnection.run_transaction/4
(ash 2.9.16) lib/ash/actions/create/bulk.ex:187: anonymous fn/7 in Ash.Actions.Create.Bulk.do_run/5
(elixir 1.14.5) lib/stream.ex:612: anonymous fn/4 in Stream.map/2
(elixir 1.14.5) lib/enum.ex:4751: Enumerable.List.reduce/3
(elixir 1.14.5) lib/stream.ex:1026: Stream.do_transform_inner_list/7
^ This is on the latest released version. Also, still getting this exact error for this kind of bulk create. ^
ZachDaniel
ZachDanielβ€’2y ago
😒 I might need another test reproduction for this one
frankdugan3
frankdugan3β€’2y ago
NP, will PR a few when I get a chance.
ZachDaniel
ZachDanielβ€’2y ago
@frankdugan3 you're in luck, a client encountered this issue have a fix incoming, at least for the specific issue raising on []
frankdugan3
frankdugan3β€’2y ago
Oh, awesome! Sorry I hadn't gotten around to a repro PR, was using this for optional improvements to staging seed, had some other priorities come up ahead of it. πŸ˜… Sadly the updates to Ash/AshPostgres didn't change anything for my two cases. Will see if I can get to a repro PR today or tomorrow. 😒
ZachDaniel
ZachDanielβ€’2y ago
Hmmmm

Did you find this page helpful?