AshGraphql: Updating a managed has_many relationship
moxley:
I’m getting
"In field \"id\": Unknown field."
in the GraphQL response error. It’s referring to the
id
provided in the has_many related record .
# This is the updateWebSite input argument. It's a UpdateWebSiteInput type.
input = %{
# The has_many relationship
components: [
%{
# This is the primary key of the associated record (UpdateWebSiteComponentsInput)
id: "38f61258-0e8f-4a99-8bae-0cb892e6ccaa",
value: "new value",
key: "test-component",
}
]
}
Here are the relevant parts of my WebSite resource:
actions do
# Add a set of simple actions. You'll customize these later.
defaults [:read, :destroy]
update :update do
argument :components, {:array, :map}
# I'm not sure what options to pass here.
# These current options I got from looking at the AshGraphql tests
change manage_relationship(
:components,
type: :direct_control,
on_lookup: :relate,
on_no_match: :create
)
end
end
managed_relationships do
managed_relationship :create, :components
# I'm not sure what options to pass here
managed_relationship :update, :components
# managed_relationship :update, :components, lookup_with_primary_key?: true
end
I tried playing with the options both for
change manage_relationship()
and
managed_relationship()
. I got different errors. I’m not quite understanding the documentation yet.
ZachDaniel:
Have you had a look at the generated types for those
managed_relationship
fields?
ZachDaniel:
like in the graphql playground?
ZachDaniel:
The options for
manage_relationship
are discussed here
ZachDaniel:
There are a lot of considerations to be made on that front. What exactly should happen with the values provided in the
components
key?
ZachDaniel:
You likely want
lookup_with_primary_key?: true
in your managed_relationship to cause it to add the
:id
field if you’re doing something that should lookup/update existing records. What exactly ought to happen with the input you provide to components? What if something is left out of the list? Should it be removed?
moxley:
The options for manage_relationship are discussed here
Yep, I read that. There’s a lot of read. I’m having difficulty understanding it.
There are a lot of considerations to be made on that front. What exactly should happen with the values provided in the components key?
The list of values in the
components
key are the attributes for each component under a WebSite. These should be used as the attributes to insert or update each component with. The
id
field in each item is the component’s ID. It should be used to look up the component record in the database for updating. If no ID is given, a new record should be inserted. If the WebSite has a component whose ID is not in the list of component items, that record should be deleted. This is the behavior I’m used to working with when using Ecto’s cast_assoc for has_many relationships.
moxley:
When adding
lookup_with_primary_key?: true
to the
managed_relationship
call, there’s a compiler error:
** (Protocol.UndefinedError) protocol Enumerable not implemented for %Absinthe.Blueprint.Schema.FieldDefinition{name: "id", identifier: :id...
ZachDaniel:
you’re having a time of it
ZachDaniel:
Got it, so you want
type: :direct_control
ZachDaniel:
whats the stack trace for that error?
moxley:
I’m using
:direct_control
moxley:
== Compilation error in file lib/gf_web/graphql/absinthe_schema.ex ==
** (Protocol.UndefinedError) protocol Enumerable not implemented for %Absinthe.Blueprint.Schema.FieldDefinition{name: "id", identifier: :id, type: :id, module: GfWeb.GraphQL.AbsintheSchema, description: nil, deprecation: nil, config: nil, triggers: [], default_value: nil, arguments: [], directives: [], complexity: nil, source_location: nil, middleware: [], function_ref: nil, flags: %{}, errors: [], __reference__: %{location: %{file: "/Users/mstratto/work/moxley/gf-core/deps/ash_graphql/lib/resource/resource.ex", line: 2847}, module: AshGraphql.Resource}, __private__: []} of type Absinthe.Blueprint.Schema.FieldDefinition (a struct)
(elixir 1.14.3) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir 1.14.3) lib/enum.ex:166: Enumerable.reduce/3
(elixir 1.14.3) lib/enum.ex:4307: Enum.map/2
(ash_graphql 0.22.11) lib/resource/resource.ex:1638: AshGraphql.Resource.manage_pkey_fields/4
(ash_graphql 0.22.11) lib/resource/resource.ex:1319: AshGraphql.Resource.managed_relationship_input/6
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(elixir 1.14.3) lib/enum.ex:4249: Enum.flat_map_list/2
(elixir 1.14.3) lib/enum.ex:4250: Enum.flat_map_list/2
ZachDaniel:
Yeah, I was meaning you wouldn’t need the additional options
moxley:
Do you mean these options:
on_lookup: :relate,
on_no_match: :create
ZachDaniel:
yes
ZachDaniel:
Is that stacktrace from the latest ash_graphql release?
moxley:
No. I’ll update it and report back.
ZachDaniel:
awesome, thanks 😄
moxley:
I just upgraded to ash_graphql 0.23.0, ash 2.6.26, and ash_postgres 1.3.17. So far I’m getting this:
mix test test/gf_web/graphql/absinthe_schema/web_component_test.exs:153
Compiling 117 files (.ex)
== Compilation error in file lib/gf_web/graphql/absinthe_schema.ex ==
** (Absinthe.Schema.Error) Compilation failed:
---------------------------------------
## Locations
/Users/mstratto/work/moxley/gf-core/deps/ash_graphql/lib/resource/resource.ex:3083
In Web_site, nil is not defined in your schema.
Types must exist if referenced.
---------------------------------------
## Locations
/Users/mstratto/work/moxley/gf-core/deps/ash_graphql/lib/resource/resource.ex:2246
In Web_site, :_filter_input is not defined in your schema.
Types must exist if referenced.
(absinthe 1.7.0) lib/absinthe/schema.ex:366: Absinthe.Schema.__after_compile__/2
(stdlib 4.2) lists.erl:1350: :lists.foldl/3
ZachDaniel:
🤔 do you have any resources that have the
AshGraphql.Resource
extension but
not
a
type :type
configuration?
moxley:
Um, I’m not sure. I don’t know what a
AshGraphql.Resource
extension is.
ZachDaniel:
when you add it to your resource you do
extensions: [AshGraphql.Resource]
in the resource
ZachDaniel:
So we’re looking for resources where you’ve done that but not defined a type
moxley:
Oh wait. I commented out a bunch of code, and that’s probably what caused that. One moment…
ZachDaniel:
I’m adding a check for that now
ZachDaniel:
(we should be ignoring resources that don’t have a configured type
moxley:
Okay, I’m seeing the new warnings you were mentioning before. I’ll address those first.
ZachDaniel:
You should just be able to add the config, don’t need to worry about step 1 🙂
moxley:
Okay, got through all of that, and no more warnings. The GraphQL response is the same:
[warning] GQL result errors for operation UpdateWebSite: [%{locations: [%{column: 26, line: 2}], message: "Argument \"input\" has invalid value $input.\nIn field \"components\": Expected type \"[UpdateComponentsInput!]\", found [{attrs: [{key: \"class\", value: \"test\"}], id: \"722ea0b1-ad77-452b-ba2d-724cc94c7c9d\", key: \"test-component\", type: \"HTML\", value: \"new value\"}].\nIn element #1: Expected type \"UpdateComponentsInput\", found {attrs: [{key: \"class\", value: \"test\"}], id: \"722ea0b1-ad77-452b-ba2d-724cc94c7c9d\", key: \"test-component\", type: \"HTML\", value: \"new value\"}.\nIn field \"id\": Unknown field."}]
This time, I can add the
lookup_with_primary_key?: true
option to
managed_relationship()
, and there’s no compiler error, but the GraphQL response is the same.
moxley:
"In field \"id\": Unknown field."
ZachDaniel:
Okay, so we’re compiling, its just not including the primary key field which you naturally need for the “or update” component of all of this.
ZachDaniel:
lemme take a look
moxley:
Thanks!
ZachDaniel:
fun fact, looks like we just aren’t adding primary key for updates
ZachDaniel:
lemme confirm/try something out
moxley:
Oh! Hmm.
ZachDaniel:
oh, nvm, just getting my brain back in this code
ZachDaniel:
okay, do me a favor and try out the main branch?
moxley:
Yep, one moment…
moxley:
Sorry, I got lost watching the Erlang Movie.
ZachDaniel:
😆 no worries lol
moxley:
It works!
ZachDaniel:
🥳
ZachDaniel:
I’m adding an automated test as well for this case in the future
ZachDaniel:
I’ll cut a release once the test is in
moxley:
Sweet! I’ll add some more tests on my end to verify all the cases for managing the association.
moxley:
The three cases are covered in my tests: items can be added, updated, or deleted.
ZachDaniel:
Just wait til you get to nested managed relationships 😆
ZachDaniel:
okay, made some small tweaks, added some tests and released it.
ZachDaniel:
LMK if the update works for you, when you get a chance 🙂
moxley:
I updated to the new patch version, and my tests are still passing. It’s looking good.
ZachDaniel:
Thanks for bearing with me on that 😅
moxley:
Thanks for being quick to respond!