GraphQL error: Unknown argument 'deleted' on field 'removeFromPostsOnComments' - graphql

So, I have a one to many relationship from Posts to comments:
type Comments {
createdAt: DateTime!
deleted: Boolean
id: ID!
posts: Posts #relation(name: "PostsOnComments")
text: String!
updatedAt: DateTime!
user: String!
}
type Posts {
caption: String!
comments: [Comments!]! #relation(name: "PostsOnComments")
createdAt: DateTime!
displaysrc: String!
id: ID!
likes: Int
updatedAt: DateTime!
}
and wish to run a mutation, which as well as deleting the connection between a post and a comment, attempts to update the field 'deleted, on Comments, to true:
mutation removeComment ($id: ID!, $cid: ID!, $stateB: Boolean) {
removeFromPostsOnComments (postsPostsId: $id, commentsCommentsId: $cid, deleted: $stateB){
postsPosts {
__typename
id
comments {
__typename
id
text
user
deleted
posts {
__typename
id
}
}
}
}
}
Query Variables
{
"id": "cj0qkl04vep8k0177tky596og",
"cid": "cj1de905k8ya201934l84c3id"
}
But when I run the mutation I get the following error message:
GraphQL error: Unknown argument 'deleted' on field 'removeFromPostsOnComments' of type 'Mutation'. (line 2, column 74):
removeFromPostsOnComments(postsPostsId: $id, commentsCommentsId: $cid, deleted: $stateB) {
As was explained to me here, only the link between Posts and comments is deleted, not the actual 'Comment' record itself. So my thinking is, as the record is not deleted, why can I not update the 'deleted' field?
I wish to do this so that it triggers a subscription, which is monitoring the updated field 'deleted'.
The generated mutation output is as follows:
"data": null,
"errors": [
{
"message": "Unknown argument 'deleted' on field 'removeFromPostsOnComments' of type 'Mutation'. (line 2, column 77):\n removeFromPostsOnComments (postsPostsId: $id, commentsCommentsId: $cid, deleted: $stateB){\n ^",
"locations": [
{
"line": 2,
"column": 77
}
]
}
]
}
As can be seen in the image, 'deleted' is definitely included in 'Comments' my GraphCool schema:

I reproduced your issue. First of all, you're getting the error message because deleted is not part of the arguments of the removeFromPostsOnComments-mutation, you also see that in the docs:
If you want to update the deleted field on the Comments type, you have to use the updateComments-mutation:
mutation {
updateComments(id: "cj1de905k8ya201934l84c3id", deleted: true) {
id
}
}

Related

Prisma deploy: relations are expected for enums/expecting an interface, directive or definition

I'm trying to deploy my updated datamodel.prisma file. However, an error occurs and from what I can understand, it thinks that I'm trying to create a relation between an enum I defined above with the User type.
Here is my file:
enum Permission {
ADMIN
USER
ITEMCREATE
ITEMUPDATE
ITEMDELETE
PERMISSIONUPDATE
}
type User {
id: ID! #id
name: String!
email: String! #unique
password: String!
resetToken: String
resetTokenExpiry: String
permissions: [Permission]
}
type Item {
id: ID! #id
title: String!
description: String!
image: String
largeImage: String
price: Int!
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
}
Running prisma deploy --env-file variables.env gives me this error below:
Errors:
User
✖ Valid values for the strategy argument of `#scalarList` are: RELATION.
If I change permissions: [Permission] to permissions: Permission[], it gives this error instead (specifically, expected ImplementsInterfaces, DirectivesConst or FieldDefinitions):
ERROR: Syntax error while parsing GraphQL query. Invalid input "{\n id: ID! #id\n name: String!\n email: String! #unique\n password: String!\n resetToken: String\n resetTokenExpiry: String\n permissions: Permission[", expected ImplementsInterfaces, DirectivesConst or FieldDefinitions (line 10, column 11):
type User {
^
{
"data": {
"deploy": null
},
"errors": [
{
"locations": [
{
"line": 2,
"column": 9
}
],
"path": [
"deploy"
],
"code": 3017,
"message": "Syntax error while parsing GraphQL query. Invalid input \"{\\n id: ID! #id\\n name: String!\\n email: String! #unique\\n password: String!\\n resetToken: String\\n resetTokenExpiry: String\\n permissions: Permission[\", expected ImplementsInterfaces, DirectivesConst or FieldDefinitions (line 10, column 11):\ntype User {\n ^",
"requestId": "us1:ck6au2sum8frx0b00fviv1dom"
}
],
"status": 200
}
I'm not sure what that error means, but I do have a feeling that it doesn't understand the #unique type modifier at the email field. It wasn't there previously and deploys worked fine. Any help is greatly appreciated!
You need to specify the strategy and #scalarList directive.
This #scalarList(strategy: STRATEGY!) directive is required on any
scalar list field. The only valid argument for the strategy argument
is RELATION.
type Post {
tags: [String!]! #scalarList(strategy: RELATION)
}
It is required for all scalar and enum list fields.
See: https://www.prisma.io/docs/datamodel-and-migrations/datamodel-MYSQL-knul/##scalarlist

authenticate user and serve only their related data

I have a schema in graphcool with these nodes (not sure what the correct term is here... leaf? node? model? type??)
type User #model {
auth0UserId: String #isUnique
createdAt: DateTime!
id: ID! #isUnique
userIdentifier: String
bundleIdentifier: String
updatedAt: DateTime!
devices: [Device!]! #relation(name: "UserOnDevice")
tokens: [Token!]! #relation(name: "TokenOnUser")
}
type Device #model {
id: ID! #isUnique
deviceIdentifier: String!
users: [User!]! #relation(name: "UserOnDevice")
token: Token #relation(name: "DeviceOnToken")
}
I'd like to make it so that a user must be authenticated and be related to the device data to be able to query on it. So, for a query like:
query($deviceIdentifier: String!) {
device(deviceIdentifier: $deviceIdentifier) {
id
}
}
This should return null unless they are autthenticated and are a user in the specified relation. I was thinking I needed a permission query like this one:
query ($node_id: ID!, $user_id: ID!) {
SomeDeviceExists(filter: {
id: $node_id,
users: {
id: $user_id
}
})
}
But it turns out that is invalid. How do I do it?
query ($node_id: ID!, $user_id: ID!) {
SomeDeviceExists(filter: {
id: $node_id,
users_some: {
id: $user_id
}
})
}
but this does require submitting the user_id in the request.

Cascade delete related nodes using GraphQL and Prisma

I'm trying to figure out cascade deletion in GraphQL.
I'm attempting to delete a node of type Question, but type QuestionVote has a required relation to Question. I'm looking for a way to delete a Question and all its votes at once.
Mutation for deleting a Question:
type Mutation {
deleteQuestion(where: QuestionWhereUniqueInput!): Question!
}
And its resolver (I'm using Prisma):
function deleteQuestion(parent, args, context, info) {
const userId = getUserId(context)
return context.db.mutation.deleteQuestion(
{
where: {id: args.id}
},
info,
)
}
How can I modify that mutation to also delete related QuestionVote nodes? Or should I add a separate mutation that deletes one or multiple instances of QuestionVote?
In case it's important, here are the mutations that create Question and QuestionVote:
function createQuestion(parent, args, context, info) {
const userId = getUserId(context)
return context.db.mutation.createQuestion(
{
data: {
content: args.content,
postedBy: { connect: { id: userId } },
},
},
info,
)
}
async function voteOnQuestion(parent, args, context, info) {
const userId = getUserId(context)
const questionExists = await context.db.exists.QuestionVote({
user: { id: userId },
question: { id: args.questionId },
})
if (questionExists) {
throw new Error(`Already voted for question: ${args.questionId}`)
}
return context.db.mutation.createQuestionVote(
{
data: {
user: { connect: { id: userId } },
question: { connect: { id: args.questionId } },
},
},
info,
)
}
Thanks!
You can set up cascade deletion by modifying your datamodel.
Given your question, I assume your datamodel looks somewhat like this:
type Question {
id: ID! #unique
votes: [QuestionVote!]! #relation(name: "QuestionVotes")
text: String!
}
type QuestionVote {
id: ID! #unique
question: Question #relation(name: "QuestionVotes")
isUpvote: Boolean!
}
Then you have to add the onCascade: DELETE field to the #relation directive like so:
type Question {
id: ID! #unique
votes: [QuestionVote!]! #relation(name: "QuestionVotes" onDelete: CASCADE)
text: String!
}
type QuestionVote {
id: ID! #unique
question: Question #relation(name: "QuestionVotes")
isUpvote: Boolean!
}
Now, every time a Question node is deleted, all related QuestionVote nodes are also deleted.
Note: If omitting onDelete, the value is automatically set to onDelete: SET_NULL by default. This means that deleting a node results in setting the other side of the relation to null.
You can read more about cascading deletes in Prisma in the documentation.

Graphql with mutation spring boot

My schema file is
type Mutation {
createCustomer(name: String!, email: String!, product: [Product]): Customer
}
input Product {
id: ID!
name: String!
price: Int
}
interface Person {
id: ID!
name: String!
email: String!
}
type Customer implements Person {
id: ID!
name: String!
email: String!
product: [Product]
}
I want to insert customer detail here which has product list as input. My query is
mutation {
createCustomer(
name: "kitte",
email: "kitte#gmail.com",
product: [
{
name: "soap",
price: 435,
}
]
)
{
id
name
email
product{name}
}
}
But I am getting exception
{
"data": null,
"errors": [
{
"validationErrorType": "WrongType",
"message": "Validation error of type WrongType: argument value ArrayValue{values=[ObjectValue{objectFields=[ObjectField{name='name', value=StringValue{value='dars76788hi'}}, ObjectField{name='price', value=IntValue{value=123}}]}, ObjectValue{objectFields=[ObjectField{name='name', value=StringValue{value='darr'}}, ObjectField{name='price', value=IntValue{value=145}}]}]} has wrong type",
"locations": [
{
"line": 5,
"column": 5
}
],
"errorType": "ValidationError"
}
]
}
I don't understand what is the error. And how to pass list to mutation. I have referred some examples but not able to insert product as list.
Make sure you are passing the right type of objects to your mutation. GraphQL needs separate types for input fields. In your schema, Product types should be something like this and you should change the mutation accordingly.
type Product {
id: ID!
name: String!
price: Int
}
input ProductInput {
name: String!
price: Int
}
input CustomerInput {
...
products: [ProductInput]
}
There are couple of very useful examples in the docs, see Mutations and Input Types

GraphQL: Subscription not firing when mutation run

So, I'm testing subscriptions on Graphcool and would appreciate some clarification on how exactly they work.
I have a one to many relationship from Posts on Comments:
Schema
type Posts {
caption: String!
comments: [Comments!]! #relation(name: "PostsOnComments")
createdAt: DateTime!
displaysrc: String!
id: ID!
likes: Int
updatedAt: DateTime!
}
type Comments {
createdAt: DateTime!
id: ID!
posts: Posts #relation(name: "PostsOnComments")
text: String!
updatedAt: DateTime!
user: String!
}
The subscription I run in Graphcool is as follows:
subscription CreatedDeletedComments {
Comments(
filter: {
mutation_in: [CREATED, DELETED]
}
) {
mutation
node {
id
user
text
}
}
}
If I run the following in my React app, a created notification is fired:
return this.props.client.mutate({
mutation: gql`
mutation createComment ($id: ID, $textVal: String!, $userVal: String!) {
createComments (postsId: $id, text: $textVal, user: $userVal){
id
text
user
}
}
`,
variables: {
"id": postID,
"textVal": textVal,
"userVal": userVal
},
// forceFetch: true,
})
But if I run the following, no deleted notification is fired:
return this.props.client.mutate({
mutation: gql`
mutation removeComment ($id: ID!, $cid: ID!) {
removeFromPostsOnComments (postsPostsId: $id, commentsCommentsId: $cid){
postsPosts {
id
displaysrc
likes
comments {
id
text
user
}
}
}
}
`,
variables: {
"id": postID,
"cid": commentID
},
// forceFetch: true,
})
What am I overlooking here?
With the subscription
subscription CreatedDeletedComments {
Comments(
filter: {
mutation_in: [CREATED, DELETED]
}
) {
mutation
node {
id
user
text
}
}
}
you are subscribing to comment nodes being created or deleted. However, with the mutation removeFromPostsOnComments, you are not deleting any comment nodes. Instead, you are only deleting the connection between a post and a comment.
You can adjust your mutation request to delete the comment entirely instead of disconnecting it from the post:
return this.props.client.mutate({
mutation: gql`
mutation removeComment ($cid: ID!) {
deleteComment(id: $cid) {
id
}
}
`,
variables: {
"cid": commentID
},
// forceFetch: true,
})
If you don't want to delete the comment entirely but still want to hide it in your app, you could have a boolean field deleted that acts as a soft deletion marker.
Then you could subscribe to UPDATED comments instead of DELETED comments and check if the field deleted was updated. Refer to the
docs for more information on how to do that with updatedFields.
Subscriptions for relations is also already part of our roadmap.

Resources