How to build a many-to-many insert mutation in Hasura? - graphql

I am building my first many-to-many insert mutation in Hasura and finding it difficult. The syntax in the docs and the accompanying explanation is very difficult to follow.
I am simply trying to add a connection between a component and a module.
Here is the state of my current query.
mutation MyMutation {
insert_component(objects: {component_module: {data: {module: {data: {id: "775c9e27-c974-4cfa-a01f-af50bd742726"}, on_conflict: {constraint: module_id_key, update_columns: id}}}}}) {
affected_rows
returning {
id
component_modules
}
}
}
Here is the error I get.
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.insert_component.args.objects[0].component_module.data",
"code": "constraint-violation"
},
"message": "Not-NULL violation. null value in column \"component_id\" violates not-null constraint"
}
]
}
Here is my component table
Here is my module table
Here is my component_module bridge table
Thanks in advance for your help.

Your mutation is not working because you are inserting the id manually and when Hasura generates the query it won't have the id in the parent.
When doing nested inserts the best is to let PostgreSQL generate the ids for you. This way you will be able to insert with either side of the relationship.
In your example you don't really need to have the component_modules column in each table. When doing many to many inserts you can use the id of each table as the foreign key.
For example:
component
- id
- created_at
- updated_at
- name
module
- id
- created_at
- updated_at
- name
component_module
- component_id
- module_id
And the mutation should be something like:
mutation {
insert_component(objects: {
name:"component name",
component_modules: {
data: {
module: {
data: {
name: "module name"
}
}
}
}
}) {
returning {
id
component_modules {
component {
name
}
}
}
}
}

Related

BelongsToMany create operation with Pivot Data - PHP Lighthouse Laravel

In PHP Lighthouse you can have ManyToMany relationships. Using nested operations allows you to create say an Author, Post and connect them using a pivot table post_author ALL in one operation.
Lighthouse also allows you to store data in the pivot table. In their docs, they give an example of how to connect a record with some pivot table data. There is no example available on how to do a create operation with extra pivot table data.
Docs pivot data update operation: https://lighthouse-php.com/master/eloquent/nested-mutations.html#storing-pivot-data
type Mutation {
createPost(input: CreatePostInput! #spread): Post #create
}
input CreatePostInput {
title: String!
authors: CreateAuthorBelongsToMany
}
input CreateAuthorBelongsToMany {
create: [CreateAuthorInput!]
}
input CreateAuthorInput {
name: String!
#contribution_percentage: Int! #Pivot table column
}
#query:
mutation {
createPost(
input: {
title: "My new Post"
authors: {
create: [{ name: "Herbert", contribution_percentage: 50 }]
}
}
) {
id
authors {
name
}
}
}
I tried fiddling with the scheme to "guess" the correct scheme, to no avail.
My objective is: Create an Author, Post, and connect them using a post_author pivot table WITH extra pivot data, ALL in one operation.

Upsert Graphql Mutation with conflict constraint on nested object

I am trying to do an upsert in a single mutation. Here I have two tables Users table [id,isVerified,type] and Customers table [id,name,deviceToken] Here,Customers.id is a foreign key of Users.Id.
The following is the mutation-
MyMutation {
insert_Users(objects: [{isVerified: false, name: "+9100000000", type: "customer",
Customers: {data: {deviceToken: "TestToken001"}}}],
on_conflict: {
constraint: Users_name_key,
update_columns: [isVerified]
}) {
affected_rows
returning {
Customers{
deviceToken
}
}
}
} ```
//But when I run this, I get the exception
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.insert_Users.args.objects[0].Customers.data",
"code": "constraint-violation"
},
"message": "Uniqueness violation. duplicate key value violates unique constraint \"Customers_pkey\""
}
]
}
This seems to be because I am not setting conflict constraint on the nested Customers Object. How do I add the conflict constraint for a nested object?
You need to add the constraint object inside the nested data as well.
Something like:
MyMutation {
insert_Users(objects: [{isVerified: false, name: "+9100000000", type: "customer",
Customers: {
data: {deviceToken: "TestToken001"},
on_conflict: {
constraint: Customers_pkey,
update_columns: [deviceToken]
}
}}],
on_conflict: {
constraint: Users_name_key,
update_columns: [isVerified]
}) {
affected_rows
returning {
Customers{
deviceToken
}
}
}
}

How to upsert nested tables values in Hasura GraphQL?

wanted to ask if it is possible to upsert nested objects? for example, if i have a 'Users' table and a 'Students' table, and I'm inserting a new User(with a taken id), i want to update all fields (using on_conflict and update_columns) including the fields in the 'Students' table.
Basically replace all user's fields except the primary key.
mutation($UsersData: [core_users_insert_input!]!) {
insert_core_users(
objects: $UsersData
on_conflict: {
constraint: core_users_id_unique
update_columns: [first_name, last_name, gender]
}
) {
affected_rows
}
}
The update_column array should include fields from the 'Students' table but i can't figure it out.
It is possible, relevant documentation is here: https://hasura.io/docs/1.0/graphql/manual/mutations/upsert.html#upsert-in-nested-mutations
It is possible to use on_conflict key on any level (top, or nested) where you want to resolve updating an existing record.
mutation upsert_author_article {
insert_author(
objects: [
{
name: "John",
articles: {
data: [
{
title: "Article 3",
content: "Article 3 content"
}
],
on_conflict: {
constraint: article_title_key,
update_columns: [content]
}
}
}
]
) {
affected_rows
}
}

How to reshape a GraphQL (via Hasura) query response?

I have a CHAT_MESSAGE_FRAGMENT that returns all the message data from my Hasura graphql api.
However, the Gifted Chat react-native component requires the data in a specific structure so I'm attempting to convert it with the query below.
I'm able to alias all the top level data but can't figure out how to add a nested level of data.
I'm guessing it isn't possible but I thought I'd ask in case I'm missing something.
const GIFTED_CHAT_GROUP_MESSAGES_QUERY = gql`
query chatGroupMessages($chatGroupId: Int!) {
chat_message(
where: { to: { id: { _eq: $chatGroupId } } }
) {
_id: id,
# user: {
# _id: from.id, <== How do I add
# name: from.name, <== this secondary level?
# },
text: message,
image: image_url,
createdAt: created_at,
system: message_type,
}
}
${CHAT_MESSAGE_FRAGMENT}
`;
Assuming you already have chat_message.user_id -> users.id foreign key constraint set up, you'll also need to alias the from object in addition aliasing any of its nested fields:
const GIFTED_CHAT_GROUP_MESSAGES_QUERY = gql`
query chatGroupMessages($chatGroupId: Int!) {
chat_message(
where: { to: { id: { _eq: $chatGroupId } } }
) {
_id: id,
from: user: {
_id: id,
name
},
text: message,
image: image_url,
createdAt: created_at,
system: message_type,
}
}
${CHAT_MESSAGE_FRAGMENT}
`;
The secondary level of data is basically nested object queries in Hasura. You can nest any number of queries as long as a relationship has been created.
In this case, assuming the chat_message table has a user_id field, you can establish a foreign key constraint for chat_message.user_id -> users.id, where users is a table with id as primary key.
Once the foreign key constraint is created, Hasura Console automatically suggests relationships. Here user would be an object relationship in chat_message table.
Here's the official docs link for Creating a relationship

How can I insert records in AwsAppSync mutation with proper #connection values?

I have added a resources table to my schema, connecting to a Plants table:
type Resource #model
{
id: ID!
name: String!
Plants: [Plant] #connection(name: "ResourcePlant")
}
Ran amplify push, and all resources were created properly.
Now I wanted to add a Resource, and link it to all Plants properly.
Do you know how is the sintaxe I should use to run the recently created mutation createResource in order to add the items on Plant I want to include to that resource?
I tried to run like this:
mutation CreateResource {
createResource (input: {
name: "Plant",
Plants : {
items :
{ id: "f9a0468e-da74-41d5-8287-1cb6a76b25a5" }
}
}
) {
name,
Plants {
items {
id
}
nextToken
}
}
}
This was the error message:
Validation error of type WrongType: argument 'input' with value
'ObjectValue{objectFields=[ObjectField{name='name',
value=StringValue{value='Plant'}}, ObjectField{name='Plants',
value=ObjectValue{objectFields=[ObjectField{name='items', value=ObjectValue{objectFields=[ObjectField{name='id',
value=StringValue{value='f9a0468e-da74-41d5-8287-1cb6a76b25a5'}}]}}]}}]}'
contains a field not in 'CreateResourceInput': 'Plants' # 'createResource'
How did you define Plant?
And have you checked this example? https://aws-amplify.github.io/docs/cli-toolchain/graphql#connection
Ok, after some headache, I found what was missing in my model. For me so far it has proved to be the best way of doing this relationship...
I have added on my Plant type, on schema definition, a field named plantResourceId (other than the one used for the #connection directive). What I found out was that, by convention, when inserting/updating a record on "Plant" and adding the resource "id" field content of the resource I want to "connect" to that plant, it will automatically be retrieved when "Resources" is queried, for each item - what is better: Out-of-the-box from codegen.
Insert example
mutation CreatePlant {
createPlant(input:{
name: "MyPlant",
plantResourceId: "id-for-connected-resource"
}) {
name,
plantResourceId
}
}
Query example to retrieve items:
query listPlantsOnResource {
listResources(filter: {
name: {
contains: "myfilter"
}
}) {
items {
id
name
Plants
{
items {
id
name
description
}
}
}
}
}
It worked very well!
Thanks all who contributed!

Resources