AshGraphql unknown error

Unknown Error

* ** (UndefinedFunctionError) function :ok.resource/0 is undefined (module :ok is not available)
:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1371: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
Unknown Error

* ** (UndefinedFunctionError) function :ok.resource/0 is undefined (module :ok is not available)
:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1371: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
The code for the action is this
update :accept_for_doctor do
argument :code, :string, allow_nil?: false
argument :entity_id, :string, allow_nil?: false

require_atomic? false

validate attribute_equals(:role, :doctor)
validate attribute_equals(:code, arg(:code))
validate attributes_absent(:member_id)
validate attribute_equals(:rejected, false)
validate attribute_equals(:entity_id, arg(:entity_id))

# change log("before doctor")

change relation(
:accepted_doctor,
%{entity_id: arg(:entity_id), user_id: actor(:id)},
type: :create
)

# change log("before member")

change relation(
:member,
%{entity_id: arg(:entity_id), user_id: actor(:id), role: :doctor},
type: :create
)

# change log("after member")
end
update :accept_for_doctor do
argument :code, :string, allow_nil?: false
argument :entity_id, :string, allow_nil?: false

require_atomic? false

validate attribute_equals(:role, :doctor)
validate attribute_equals(:code, arg(:code))
validate attributes_absent(:member_id)
validate attribute_equals(:rejected, false)
validate attribute_equals(:entity_id, arg(:entity_id))

# change log("before doctor")

change relation(
:accepted_doctor,
%{entity_id: arg(:entity_id), user_id: actor(:id)},
type: :create
)

# change log("before member")

change relation(
:member,
%{entity_id: arg(:entity_id), user_id: actor(:id), role: :doctor},
type: :create
)

# change log("after member")
end
I made the relation change, which is just calling manage_relationship, nothing more
Solution:
You can create in a before_action hook and use that to update the record
Jump to solution
51 Replies
Vahagn
VahagnOP4mo ago
The rest of the error message is here
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1342: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1387: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.15) lib/ash/actions/update/bulk.ex:458: Ash.Actions.Update.Bulk.run/6
(ash 3.5.15) lib/ash/actions/update/bulk.ex:132: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2

:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1342: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1387: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.15) lib/ash/actions/update/bulk.ex:458: Ash.Actions.Update.Bulk.run/6
(ash 3.5.15) lib/ash/actions/update/bulk.ex:132: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2

:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1371: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1342: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1387: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.15) lib/ash/actions/update/bulk.ex:458: Ash.Actions.Update.Bulk.run/6
(ash 3.5.15) lib/ash/actions/update/bulk.ex:132: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2
(ash 3.5.15) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1371: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1342: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.15) lib/ash/actions/update/bulk.ex:1387: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.15) lib/ash/actions/update/bulk.ex:458: Ash.Actions.Update.Bulk.run/6
(ash 3.5.15) lib/ash/actions/update/bulk.ex:132: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2
discord did not allow to send a very long message Ash.Notifier.notify has a line like this
resource_notifications
|> List.wrap()
|> Enum.group_by(& &1.resource)
resource_notifications
|> List.wrap()
|> Enum.group_by(& &1.resource)
resource notifications came as :ok but I don't have deep enough understanding of ash internal, to know where is it coming from But this test passes
test "invite doctor" do
{actor, tenant} = setup_user()

invitation =
Management.Invitation
|> Ash.Changeset.for_create(:invite, %{role: :doctor}, actor: actor, tenant: tenant)
|> Ash.create!()

assert invitation.member_id == nil

{other_actor, _} = setup_user("37499999999")

invitation =
invitation
|> Ash.Changeset.for_update(:accept_for_doctor, %{code: invitation.code, entity_id: tenant},
actor: other_actor
)
|> Ash.update!()
|> Ash.load!(:member)
|> Ash.load!(:accepted_doctor)

assert invitation.accepted_doctor_id != nil
assert invitation.member_id != nil

assert invitation.member.user_id == other_actor.id
assert invitation.member.entity_id == tenant
assert invitation.accepted_doctor != nil
end
test "invite doctor" do
{actor, tenant} = setup_user()

invitation =
Management.Invitation
|> Ash.Changeset.for_create(:invite, %{role: :doctor}, actor: actor, tenant: tenant)
|> Ash.create!()

assert invitation.member_id == nil

{other_actor, _} = setup_user("37499999999")

invitation =
invitation
|> Ash.Changeset.for_update(:accept_for_doctor, %{code: invitation.code, entity_id: tenant},
actor: other_actor
)
|> Ash.update!()
|> Ash.load!(:member)
|> Ash.load!(:accepted_doctor)

assert invitation.accepted_doctor_id != nil
assert invitation.member_id != nil

assert invitation.member.user_id == other_actor.id
assert invitation.member.entity_id == tenant
assert invitation.accepted_doctor != nil
end
ZachDaniel
ZachDaniel4mo ago
@Vahagn can you update to latest ash and provide an updated stack trace? (and make sure the issue is stil there)
Vahagn
VahagnOP4mo ago
ok same error
** (Ash.Error.Unknown)
Bread Crumbs:
> Exception raised in bulk update: Aldente.Management.Invitation.accept_for_doctor
> Exception raised in bulk update: Aldente.Management.Invitation.accept_for_doctor


Unknown Error

* ** (UndefinedFunctionError) function :ok.resource/0 is undefined (module :ok is not available)
:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1411: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1382: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1427: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.21) lib/ash/actions/update/bulk.ex:494: Ash.Actions.Update.Bulk.run/6
(ash 3.5.21) lib/ash/actions/update/bulk.ex:137: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2
** (Ash.Error.Unknown)
Bread Crumbs:
> Exception raised in bulk update: Aldente.Management.Invitation.accept_for_doctor
> Exception raised in bulk update: Aldente.Management.Invitation.accept_for_doctor


Unknown Error

* ** (UndefinedFunctionError) function :ok.resource/0 is undefined (module :ok is not available)
:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1411: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1382: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1427: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.21) lib/ash/actions/update/bulk.ex:494: Ash.Actions.Update.Bulk.run/6
(ash 3.5.21) lib/ash/actions/update/bulk.ex:137: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2
:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1411: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1382: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1427: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.21) lib/ash/actions/update/bulk.ex:494: Ash.Actions.Update.Bulk.run/6
(ash 3.5.21) lib/ash/actions/update/bulk.ex:137: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2
:ok.resource()
(elixir 1.18.4) src/elixir_erl_pass.erl:726: :elixir_erl_pass.no_parens_remote/2
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: anonymous fn/1 in Ash.Notifier.notify/1
(elixir 1.18.4) lib/enum.ex:1429: anonymous fn/4 in Enum.group_by/3
(elixir 1.18.4) lib/enum.ex:2546: Enum."-group_by/3-lists^foldl/2-0-"/3
(ash 3.5.21) lib/ash/notifier/notifier.ex:32: Ash.Notifier.notify/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1411: Ash.Actions.Update.Bulk."-do_stream_batches/7-after$^2/0-0-"/2
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1382: anonymous fn/13 in Ash.Actions.Update.Bulk.do_stream_batches/7
(elixir 1.18.4) lib/stream.ex:626: anonymous fn/4 in Stream.map/2
(elixir 1.18.4) lib/stream.ex:1761: anonymous fn/3 in Enumerable.Stream.reduce/3
(elixir 1.18.4) lib/stream.ex:302: Stream.after_chunk_while/2
(elixir 1.18.4) lib/stream.ex:1790: Enumerable.Stream.do_done/2
(elixir 1.18.4) lib/stream.ex:1773: Enumerable.Stream.do_each/4
(elixir 1.18.4) lib/stream.ex:956: Stream.do_transform/5
(elixir 1.18.4) lib/enum.ex:4515: Enum.reverse/1
(elixir 1.18.4) lib/enum.ex:3835: Enum.to_list/1
(ash 3.5.21) lib/ash/actions/update/bulk.ex:1427: Ash.Actions.Update.Bulk.run_batches/5
(ash 3.5.21) lib/ash/actions/update/bulk.ex:494: Ash.Actions.Update.Bulk.run/6
(ash 3.5.21) lib/ash/actions/update/bulk.ex:137: Ash.Actions.Update.Bulk.run/6
(ash_graphql 1.7.13) lib/graphql/resolver.ex:1635: AshGraphql.Graphql.Resolver.mutate/2
ZachDaniel
ZachDaniel4mo ago
What is this?
change relation(
:member,
%{entity_id: arg(:entity_id), user_id: actor(:id), role: :doctor},
type: :create
)
change relation(
:member,
%{entity_id: arg(:entity_id), user_id: actor(:id), role: :doctor},
type: :create
)
Is that your own thing?
Vahagn
VahagnOP4mo ago
yes, just a change that passes parameters to manage_relationship
ZachDaniel
ZachDaniel4mo ago
Does this issue happen without them?
Vahagn
VahagnOP4mo ago
So without any change to relationships?
ZachDaniel
ZachDaniel4mo ago
yes
Vahagn
VahagnOP4mo ago
it did not, but it also did not change anything
ZachDaniel
ZachDaniel4mo ago
🤔 Sorry, not following without those, the error did or did not happen?
Vahagn
VahagnOP4mo ago
defmodule Aldente.Changes.Relation do
use Ash.Resource.Change

alias Aldente.Changes

@impl true
def init(opts) do
{:ok, opts}
end

@impl true
def atomic(changeset, opts, context) do
{:not_atomic, manage(changeset, opts, context)}
end

@impl true
def change(changeset, opts, context) do
changeset = manage(changeset, opts, context)
changeset
end

defp manage(changeset, opts, _context) do
value = Keyword.fetch!(opts, :value)
name = Keyword.fetch!(opts, :name)
opts = Keyword.fetch!(opts, :opts)

changeset
|> Ash.Changeset.manage_relationship(name, value, opts)
end
end
defmodule Aldente.Changes.Relation do
use Ash.Resource.Change

alias Aldente.Changes

@impl true
def init(opts) do
{:ok, opts}
end

@impl true
def atomic(changeset, opts, context) do
{:not_atomic, manage(changeset, opts, context)}
end

@impl true
def change(changeset, opts, context) do
changeset = manage(changeset, opts, context)
changeset
end

defp manage(changeset, opts, _context) do
value = Keyword.fetch!(opts, :value)
name = Keyword.fetch!(opts, :name)
opts = Keyword.fetch!(opts, :opts)

changeset
|> Ash.Changeset.manage_relationship(name, value, opts)
end
end
this is it without those it worked without errors
ZachDaniel
ZachDaniel4mo ago
what happens if you remove the atomic/3 implementation
Vahagn
VahagnOP4mo ago
same error
ZachDaniel
ZachDaniel4mo ago
what type of relationship is :member?
Vahagn
VahagnOP4mo ago
I am guessing from this (ash 3.5.21) lib/ash/actions/update/bulk.ex:137: Ash.Actions.Update.Bulk.run/6 that graphql runs it with bulk belongs_to But in my test I use just regular update
ZachDaniel
ZachDaniel4mo ago
can you confirm if its specifically one of those that is causing the issue?
Vahagn
VahagnOP4mo ago
and it works when I removed accepted_doctor, it worked
ZachDaniel
ZachDaniel4mo ago
Okay, so what makes accepted_doctor different from the member?
Vahagn
VahagnOP4mo ago
belongs_to :member, Management.Member, public?: true
belongs_to :accepted_doctor, Management.Doctor
belongs_to :member, Management.Member, public?: true
belongs_to :accepted_doctor, Management.Doctor
ZachDaniel
ZachDaniel4mo ago
First step is likely to update your test to use bulk updates
Vahagn
VahagnOP4mo ago
* Aldente.Management.Invitation.accept_for_doctor had no matching bulk strategy that could be used.

Requested strategies: [:atomic_batches, :atomic]

Could not use `:stream`: Not in requested strategies
Could not use `:atomic_batches`: Aldente.Changes.Relation does not implement `atomic/3`
Could not use `:atomic`: Not in requested strategies
* Aldente.Management.Invitation.accept_for_doctor had no matching bulk strategy that could be used.

Requested strategies: [:atomic_batches, :atomic]

Could not use `:stream`: Not in requested strategies
Could not use `:atomic_batches`: Aldente.Changes.Relation does not implement `atomic/3`
Could not use `:atomic`: Not in requested strategies
how do I tell it I don't need atomic updates? require_atomic? false I have this
ZachDaniel
ZachDaniel4mo ago
Add strategy: [:stream] to your bulk update options
Vahagn
VahagnOP4mo ago
Now the test passes with bulk too
test "invite doctor" do
{actor, tenant} = setup_user()

invitation =
Management.Invitation
|> Ash.Changeset.for_create(:invite, %{role: :doctor}, actor: actor, tenant: tenant)
|> Ash.create!()

assert invitation.member_id == nil

{other_actor, _} = setup_user("37499999999")

Ash.bulk_update!(
[invitation],
:accept_for_doctor,
%{
code: invitation.code,
entity_id: tenant
},
strategy: [:stream],
actor: other_actor
)

[invitation] =
Management.Invitation
|> Ash.Query.filter(id == ^invitation.id)
|> Ash.read!()
|> Ash.load!(:member)
|> Ash.load!(:accepted_doctor, tenant: tenant)

assert invitation.accepted_doctor_id != nil
assert invitation.member_id != nil

assert invitation.member.user_id == other_actor.id
assert invitation.member.entity_id == tenant
assert invitation.accepted_doctor != nil
end
test "invite doctor" do
{actor, tenant} = setup_user()

invitation =
Management.Invitation
|> Ash.Changeset.for_create(:invite, %{role: :doctor}, actor: actor, tenant: tenant)
|> Ash.create!()

assert invitation.member_id == nil

{other_actor, _} = setup_user("37499999999")

Ash.bulk_update!(
[invitation],
:accept_for_doctor,
%{
code: invitation.code,
entity_id: tenant
},
strategy: [:stream],
actor: other_actor
)

[invitation] =
Management.Invitation
|> Ash.Query.filter(id == ^invitation.id)
|> Ash.read!()
|> Ash.load!(:member)
|> Ash.load!(:accepted_doctor, tenant: tenant)

assert invitation.accepted_doctor_id != nil
assert invitation.member_id != nil

assert invitation.member.user_id == other_actor.id
assert invitation.member.entity_id == tenant
assert invitation.accepted_doctor != nil
end
ZachDaniel
ZachDaniel4mo ago
Add notify?: true option as well
Vahagn
VahagnOP4mo ago
where should I add the options? to bulk_update
ZachDaniel
ZachDaniel4mo ago
yep
Vahagn
VahagnOP4mo ago
Ash.bulk_update!(
[invitation],
:accept_for_doctor,
%{
code: invitation.code,
entity_id: tenant
},
strategy: [:stream],
actor: other_actor,
notify?: true
)
Ash.bulk_update!(
[invitation],
:accept_for_doctor,
%{
code: invitation.code,
entity_id: tenant
},
strategy: [:stream],
actor: other_actor,
notify?: true
)
this works I don't know what it does but it does not crash
ZachDaniel
ZachDaniel4mo ago
😆 it should effectively do the same thing as what the single update does Do you see that in the SQL logs?
Vahagn
VahagnOP4mo ago
is there a way to enable sql logs in tests?
ZachDaniel
ZachDaniel4mo ago
Logger.configure(level: :debug) at the top of the test
Vahagn
VahagnOP4mo ago
Yeah, I see it inserting then updating back the inserted ID I have a guess I don't pass the tenant But I pass entity_id which is my attribute to know who the tenant is Can there be an issue with that? Anyone has an idea what can be the issue of this? How can I better debug it?
{:current_stacktrace,
[
{Process, :info, 2, [file: ~c"lib/process.ex", line: 896]},
{Ash.Actions.Update.Bulk, :store_notification, 3,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 2308]},
{Ash.Actions.Update.Bulk, :"-run_batch/11-fun-0-", 5,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 2461]},
{Enum, :"-map/2-lists^map/1-1-", 2, [file: ~c"lib/enum.ex", line: 1714]},
{Ash.Actions.Update.Bulk, :run_batch, 11,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 2402]},
{Ash.Actions.Update.Bulk, :do_handle_batch, 14,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1933]},
{Ecto.Adapters.SQL, :"-checkout_or_transaction/4-fun-0-", 3,
[file: ~c"lib/ecto/adapters/sql.ex", line: 1400]},
{DBConnection, :run_transaction, 4,
[file: ~c"lib/db_connection.ex", line: 1756]},
{Ash.Actions.Update.Bulk, :handle_batch, 11,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1828]},
{Ash.Actions.Update.Bulk, :"-do_stream_batches/7-fun-3-", 13,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1395]},
{Stream, :"-map/2-fun-0-", 4, [file: ~c"lib/stream.ex", line: 626]},
{Enumerable.Stream, :"-reduce/3-fun-0-", 3,
[file: ~c"lib/stream.ex", line: 1761]},
{Stream, :after_chunk_while, 2, [file: ~c"lib/stream.ex", line: 302]},
{Enumerable.Stream, :do_done, 2, [file: ~c"lib/stream.ex", line: 1790]},
{Enumerable.Stream, :do_each, 4, [file: ~c"lib/stream.ex", line: 1773]},
{Stream, :do_transform, 5, [file: ~c"lib/stream.ex", line: 956]},
{Enum, :reverse, 1, [file: ~c"lib/enum.ex", line: 4515]},
{Enum, :to_list, 1, [file: ~c"lib/enum.ex", line: 3835]},
{Ash.Actions.Update.Bulk, :run_batches, 5,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1427]},
{Ash.Actions.Update.Bulk, :run, 6,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 494]}
]}
{:current_stacktrace,
[
{Process, :info, 2, [file: ~c"lib/process.ex", line: 896]},
{Ash.Actions.Update.Bulk, :store_notification, 3,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 2308]},
{Ash.Actions.Update.Bulk, :"-run_batch/11-fun-0-", 5,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 2461]},
{Enum, :"-map/2-lists^map/1-1-", 2, [file: ~c"lib/enum.ex", line: 1714]},
{Ash.Actions.Update.Bulk, :run_batch, 11,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 2402]},
{Ash.Actions.Update.Bulk, :do_handle_batch, 14,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1933]},
{Ecto.Adapters.SQL, :"-checkout_or_transaction/4-fun-0-", 3,
[file: ~c"lib/ecto/adapters/sql.ex", line: 1400]},
{DBConnection, :run_transaction, 4,
[file: ~c"lib/db_connection.ex", line: 1756]},
{Ash.Actions.Update.Bulk, :handle_batch, 11,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1828]},
{Ash.Actions.Update.Bulk, :"-do_stream_batches/7-fun-3-", 13,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1395]},
{Stream, :"-map/2-fun-0-", 4, [file: ~c"lib/stream.ex", line: 626]},
{Enumerable.Stream, :"-reduce/3-fun-0-", 3,
[file: ~c"lib/stream.ex", line: 1761]},
{Stream, :after_chunk_while, 2, [file: ~c"lib/stream.ex", line: 302]},
{Enumerable.Stream, :do_done, 2, [file: ~c"lib/stream.ex", line: 1790]},
{Enumerable.Stream, :do_each, 4, [file: ~c"lib/stream.ex", line: 1773]},
{Stream, :do_transform, 5, [file: ~c"lib/stream.ex", line: 956]},
{Enum, :reverse, 1, [file: ~c"lib/enum.ex", line: 4515]},
{Enum, :to_list, 1, [file: ~c"lib/enum.ex", line: 3835]},
{Ash.Actions.Update.Bulk, :run_batches, 5,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 1427]},
{Ash.Actions.Update.Bulk, :run, 6,
[file: ~c"lib/ash/actions/update/bulk.ex", line: 494]}
]}
This is the stack of the caller who puts :ok , so when notifier tries to notify, it gets that and calls .resource on it
ZachDaniel
ZachDaniel4mo ago
The best thing to do here would be to get it reproduced I'll fix ASAP as soon as we can reproduce the issue Alternatively, you can clone down ash core locally, point your codebase at it, and then throw some IO.inspect at the problem area to see what is happening
Vahagn
VahagnOP4mo ago
That is how I got this stacktrace
ZachDaniel
ZachDaniel4mo ago
Oh, sorry I thought it was the same one So we need to find out where that :ok is coming from Likely from calls to ManagedRelationship in that module That would be the first place to look
Vahagn
VahagnOP4mo ago
Will try to find a test case that fails
ZachDaniel
ZachDaniel4mo ago
I'd throw some inspects around the falls in bulk update to manage relationships If I can get enough info to fix that will work too 🙂
Vahagn
VahagnOP4mo ago
the problem is that every time I put an inspect, I have to compile every dependency :))), so it takes some time to dig around If I find any helpful info or strange values, will report them here Can it be an issue of me using OTP 28?
ZachDaniel
ZachDaniel4mo ago
Could be 🙂 OTP 28 is not supported by any current Elixir version AFAIK
Vahagn
VahagnOP4mo ago
I had the same error yesterday on my other laptop, with OTP 27, so I don't think that is the issue and it was exactly the same error
ZachDaniel
ZachDaniel4mo ago
👍 The main issue is that the problem isn't where the stacktrace is its somewhere ahead of it that is somehow getting :ok for notifications
Vahagn
VahagnOP4mo ago
I have reproduced :)))))) The problem with my test was that when I was creating the invitation, I was giving it back to the bulk_update and it contained a tenant in the changeset so I changed my test to Ash.read!() and pass it to bulk_update, which removed the tenant that I specified in the context earlier
test "invite doctor" do
{actor, tenant} = setup_user()

invitation =
Management.Invitation
|> Ash.Changeset.for_create(:invite, %{role: :doctor}, actor: actor, tenant: tenant)
|> Ash.create!()

assert invitation.member_id == nil

{other_actor, _} = setup_user("37499454545")

domain = Aldente.Management

IO.inspect(invitation, label: "INV")

invitations = Management.Invitation |> Ash.Query.filter(id == ^invitation.id) |> Ash.read!()

Ash.bulk_update!(
invitations,
:accept_for_doctor,
%{
code: invitation.code,
entity_id: tenant
},
return_errors?: true,
notify?: true,
allow_stream_with: :full_read,
return_records?: true,
authorize?: AshGraphql.Domain.Info.authorize?(domain),
read_action: :read,
domain: domain,
actor: other_actor,
notify?: true,
strategy: [:atomic, :stream, :atomic_batches]
)

[invitation] =
Management.Invitation
|> Ash.Query.filter(id == ^invitation.id)
|> Ash.read!()
|> Ash.load!(:member)
|> Ash.load!(:accepted_doctor, tenant: tenant)

assert invitation.accepted_doctor_id != nil
assert invitation.member_id != nil

assert invitation.member.user_id == other_actor.id
assert invitation.member.entity_id == tenant
assert invitation.accepted_doctor != nil
end
test "invite doctor" do
{actor, tenant} = setup_user()

invitation =
Management.Invitation
|> Ash.Changeset.for_create(:invite, %{role: :doctor}, actor: actor, tenant: tenant)
|> Ash.create!()

assert invitation.member_id == nil

{other_actor, _} = setup_user("37499454545")

domain = Aldente.Management

IO.inspect(invitation, label: "INV")

invitations = Management.Invitation |> Ash.Query.filter(id == ^invitation.id) |> Ash.read!()

Ash.bulk_update!(
invitations,
:accept_for_doctor,
%{
code: invitation.code,
entity_id: tenant
},
return_errors?: true,
notify?: true,
allow_stream_with: :full_read,
return_records?: true,
authorize?: AshGraphql.Domain.Info.authorize?(domain),
read_action: :read,
domain: domain,
actor: other_actor,
notify?: true,
strategy: [:atomic, :stream, :atomic_batches]
)

[invitation] =
Management.Invitation
|> Ash.Query.filter(id == ^invitation.id)
|> Ash.read!()
|> Ash.load!(:member)
|> Ash.load!(:accepted_doctor, tenant: tenant)

assert invitation.accepted_doctor_id != nil
assert invitation.member_id != nil

assert invitation.member.user_id == other_actor.id
assert invitation.member.entity_id == tenant
assert invitation.accepted_doctor != nil
end
this is the new test I just added the same opt's from graphql code I don't know which of them is neccessary
ZachDaniel
ZachDaniel4mo ago
Nice 👍 Next step is making it so I can reproduce it 😆
Vahagn
VahagnOP4mo ago
:)))) if I specify a multitenancy block in a resource, and not provide a tenant in context, but provide the attribute, will it work? I am guessing that is the problem here
ZachDaniel
ZachDaniel4mo ago
Interesting 🤔 I don't see why that would be related but no, that shouldn't work Unless you've set global? true
Vahagn
VahagnOP4mo ago
ohhh can I set global? true in manage_relationship?
ZachDaniel
ZachDaniel4mo ago
No, but you can bypass multitenancy in the individual actions
Vahagn
VahagnOP4mo ago
so inside action I can set global? true ?
ZachDaniel
ZachDaniel4mo ago
Hmm...actually it looks like we only support doing that for read actions at the moment 😢 https://hexdocs.pm/ash/dsl-ash-resource.html#actions-read-multitenancy that option hasn't been added to the other action types My suggestion: swap out your manage relationships with calls to create the other resources
Vahagn
VahagnOP4mo ago
How should I create? just manually create and manually update the original one in after_action?
Solution
ZachDaniel
ZachDaniel4mo ago
You can create in a before_action hook and use that to update the record
Vahagn
VahagnOP4mo ago
Thanks a lot, it worked

Did you find this page helpful?