Schema:
type Mutation {
removeProduct(id: String!): Product
}
type Product {
id: ID!
name: String!
slug: String!
description: String!
price: Float!
image: String!
ingredients: [String]
addOns: [String]
}
resolver:
exports.Mutation = {
removeProduct: async (parent, { id }, { Product }) => {
const deletedProduct = await Product.deleteOne({ id });
return deletedProduct;
},
};
query:
mutation{
removeProduct(id:"b55572b9-eb4d-46ea-a82f-f01cb0ba3993")
{
id
name
}
}
I need to remove a product from the db, but while deleting it, the response from graphql shows that "message": "Cannot return null for non-nullable field Product.name.",
It maybe because the product is deleted and nothing is returned because there is no product in db.
How do I write a query to delete a product ?
Note that it deletes the product from the db, but shows error in graphql response.
Related
I have data model like below
type Tag {
id: ID!
name: String!
icon: String
description: String!
links: [Link!]!
}
type Link {
id: ID!
createdAt: DateTime!
description: String!
url: String!
tags: [Tag!]!
}
I want to query all the tags based on names and i am able to do that by the below query
tags (name:"tag1"){
id
name
}
this query works
but for the same query i want to return all the links associated with the tag name like below
tags(name:"tag1") {
id
name
links {
id
description
}
}
i am getting following error when executing this
"message": "Cannot return null for non-nullable field Tag.links.",
Resolver for this query
const tags = await context.prisma
.tags({name: args.name
})
After running into an issue trying things out on my own, I tried the example from the docs and I ran into a similar issue, is the doc wrong, or am I doing something stupid?
The example I am trying to execute is the one from this page: https://www.apollographql.com/docs/apollo-server/federation/introduction/
The relevant piece of code is:
const server = new ApolloServer({
schema: buildFederatedSchema([{
typeDefs: gql`
extend type Query {
me: User
}
type User #key(fields: "id") {
id: ID!
username: String!
}
`,
resolvers: [],
}, {
typeDefs: gql`
extend type Query {
topProducts(first: Int = 5): [Product]
}
type Product #key(fields: "upc") {
upc: String!
name: String!
price: Int
}
`,
resolvers: [],
}, {
typeDefs: gql`
type Review {
body: String
author: User #provides(fields: "username")
product: Product
}
extend type User #key(fields: "id") {
id: ID! #external
reviews: [Review]
}
extend type Product #key(fields: "upc") {
upc: String! #external
reviews: [Review]
}
`,
resolvers: [],
}]),
context: ({ req }) => ({ user: req.user }),
})
Note that I left the resolvers empty on purpose, I am just trying to compile the schema.
Here is the error I get:
GraphQLSchemaValidationError: Field "User.id" can only be defined once. Field "Product.upc" can only be defined once.
Can someone help me out with that?
Let's take an example from the github repo of prisma:
We have a user, the user could have multiple posts, and one post could have multiple links.
My goal is, to retrieve all posts and all links.
This means, my response is a list (links) in a list (posts).
I want to map the values I get back as two nested lists.
datamodel.prisma
type User {
id: ID! #id
email: String! #unique
name: String
posts: [Post]!
}
type Post {
id: ID! #id
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
published: Boolean! #default(value: false)
title: String!
content: String
author: User!
links: [Link]!
}
type Link {
id: ID! #id
url: String
title: String
post: Post!
}
schema.graphql
type Query {
...
}
type Mutation {
...
}
type Link {
id: ID!
url: String
title: String
post: Post!
}
type Post {
id: ID!
createdAt: DateTime!
updatedAt: DateTime!
published: Boolean!
title: String!
content: String
author: User!
}
type User {
id: ID!
email: String!
name: String
posts: [Post]!
}
I want to query all posts of a user, and all of the links for every post in the response.
How would I query this request?
user {
id
posts {
id
links {
id
}
}
}
The above code snipper would not work.
EDIT
I want to use the following:
User: {
listPosts: (parent, args, context, info) {
return context.prisma.posts().links()
}
}
So in my response (data in front-end via react-apollo Query Component), I want to map over posts AND the links in each post.
BUT the links attribute in posts is null.
Is there another way to achieve this?!
According to the docs:
Prisma client has a fluent API to query relations in your database. Meaning you can simply chain your method calls to navigate the relation properties of the returned records. This is only possible when retrieving single records, not for lists. Meaning you can not query relation fields of records that are returned in a list.
In order to get around that limitation, you can use the $fragment method:
const fragment = `
fragment UserWithPostsAndLinks on User {
id
email
name
posts {
id
title
content
links {
id
url
title
}
}
}
`
const userWithPostsAndLinks = await prisma.user({ id: args.id }).$fragment(fragment)
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.
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