Must included all data attribute inside reference as the typeDefs value. It's okies, if the value is null.
In apollo-client: 2.6.10
TypeDefs Graphql and Mutation below:
type Product {
_id: ID
name: String!
benefit: String
country: String
vitamins: [String]
createdAt: String!
}
const [addFruit] = useMutation(ADD_FRUIT_MUTATION, {
update(cache, result) {
const cachedData = cache.readQuery({
query: GET_FRUTIS_QUERY,
});
cachedData.getFruits = [
{
...result.data.create_fruit, // name, vitamins, country, benefit
createdAt: new Date().toISOString(), // added this
_id: result.data.create_fruit.name, // added this, this only temporary and must unique.
},
...cachedData.getFruits,
];
cache.writeQuery({
query: GET_FRUTIS_QUERY,
data: { ...cachedData },
});
},
onError({ networkError, graphQLErrors }) {},
variables: fruitVariable,
});
hope this helps someone. =)
I wondering why it must all included the data attribute key? if dont, it will updated cached but not into UI.
I have a problem, thx for any help.
With prisma we can use include with where conditions for models with a relation. If I make include conditions I get the right result. If I return it to the frontend it gets overwritten. I want to return exact my result from the backend.
I have at the frontend a query (ApolloClient, gql) like. It will return an array of comments for each post, I just want to have the first Comment for each post.
const POSTS = gql`
query posts {
posts(postId: $postId) {
id
comments{ // at the backend I have conditions for the comments
id
}
}
}
`;
Backend: Primsa and graphql nexus
Prisma Schema
model Post {
id String #id #default(cuid())
comments Comment[]
}
model Comment {
id String #id #default(cuid())
post Post #relation(fields: [postId], references: [id])
postId String
}
Nexus Model
const Post = objectType({
name: 'Post',
definition(t) {
t.model.id()
t.model.comments()
})
const Comment = objectType({
name: 'Comment',
definition(t) {
t.model.id()
t.model.post()
t.model.postId()
})
Resolver
export const posts = queryField('posts', {
type: 'Post',
list: true,
args: {
...
},
resolve: async (_parent, args: any, { prisma, request }, info) => {
const posts = await prisma.post.findMany({
include: {
comments: {
take: 1
}
}
})
console.log(posts)
//Perfect result I want to return the include condition. But at the frontend I have all
//comments
return posts
},
})
The console.log(posts) is exact what I want to return!. Every post has an Array of ONE Comment.
I return the posts and at the frontend every post has an Array of ALL Comments, what I don't want. How can I prevent that the frontend query overwrite the backend return? The fields are the same.
I can't add a comment, so I am adding this to another answer.
Like I said with my PrismaSelect plugin, you can't use nexus-plugin-prisma t.model, t.crud. You will need to use Pal.Js CLI to autoGenerate all CRUD and ObjectTypes for all models.
const Post = objectType({
name: 'Post',
definition(t) {
t.model.id()
t.model.comments() // this field will overwritten by next one so this not needed
t.list.field('comments', {
type: 'Comment',
list: true,
resolve: (parent, args, { prisma }) => {
// here parent type include all other fields but not this field
return prisma.comment.findMany({ // this query is very wrong will case N+1 issue
where: {
postId: parent.id,
},
take: 1,
})
},
})
})
Example
model User {
id Int #default(autoincrement()) #id
createdAt DateTime #default(now())
email String #unique
name String?
password String
posts Post[]
comments Comment[]
}
model Post {
id Int #default(autoincrement()) #id
published Boolean #default(false)
title String
author User? #relation(fields: [authorId], references: [id])
authorId Int?
comments Comment[]
}
model Comment {
id Int #default(autoincrement()) #id
contain String
post Post #relation(fields: [postId], references: [id])
postId Int
author User? #relation(fields: [authorId], references: [id])
authorId Int?
}
Here is my Pal.Js CLI generated type for Post model
import { objectType } from '#nexus/schema'
export const Post = objectType({
name: 'Post',
definition(t) {
t.int('id', { nullable: false })
t.boolean('published', { nullable: false })
t.string('title', { nullable: false })
t.field('author', {
nullable: true,
type: 'User',
resolve(parent: any) {
return parent['author']
},
})
t.int('authorId', { nullable: true })
t.field('comments', {
nullable: false,
list: [true],
type: 'Comment',
args: {
where: 'CommentWhereInput',
orderBy: 'CommentOrderByInput',
cursor: 'CommentWhereUniqueInput',
take: 'Int',
skip: 'Int',
distinct: 'CommentDistinctFieldEnum',
},
resolve(parent: any) {
return parent['comments']
},
})
},
})
when you use my Pal.js CLI, your frontend request will be like this
query {
findOnePost(where: {id: 1}) {
comments(where: {}, take: 1){
id
}
}
}
``
The best way to handle this issue and just query what your frontend request to use my PrismaSelect plugin.
Prisma Select takes the info: GraphQLResolveInfo object in general graphql arguments (parent, args, context, info) to select object accepted by prisma client. The approach allows a better performance since you will only be using one resolver to retrieve all your request. By doing so, it also eliminates the N + 1 issue.
Also, you can use my CLI to autogenerate all CRUD from your schema.prisma file https://paljs.com/generator/nexus
I mean I can add to my Post-ObjectType a field condition like:
const Post = objectType({
name: 'Post',
definition(t) {
t.model.id()
t.model.comments()
t.list.field('comments', {
type: 'Comment',
list: true,
resolve: (parent, args, { prisma }) => {
return prisma.comment.findMany({
where: {
postId: parent.id,
},
take: 1,
})
},
})
})
This is working. But if I understood it correct I have for every post one extra request. But I have already at the mutation resolver the right result. And I don't have the comments field at the parent (t.list.field- resolver)
I'm struggling to write a nested GraphQL mutation for a React Native app I'm building with GraphQL client being AWS Amplify API. Here's my type definition file
type Game #model {
id: ID!
gameId: String!
players: [Player!]!
}
type Player #model {
id: ID!
username: String!
}
Here's my attempt to create a mutation to create a new Game
import API, { graphqlOperation } from '#aws-amplify/api';
const CreateGame = `
mutation ($gameId: String! $username: String!) {
createGame(input: {
gameId: $gameId,
players: [{ username: $username }]
}) {
id
gameId
players
}
}
`;
const gameObj = {
gameId: 'example_game_id',
username: 'example_username'
};
const queryResp = await API.graphql(graphqlOperation(CreateGame, gameObj));
console.log(queryResp.data);
Here's the error I get
"Validation error of type WrongType: argument 'input' with value 'ObjectValue{objectFields=[ObjectField{name='gameId', value=VariableReference{name='gameId'}}, ObjectField{name='players', value=ArrayValue{values=[ObjectValue{objectFields=[ObjectField{name='username', value=VariableReference{name='username'}}]}]}}]}' contains a field not in 'CreateGameInput': 'players' # 'createGame'"
I wrote simple GraphQL schemas and resolvers in studying purpose, and I could not get reason why my codes work as expected. I used Prisma for ORM, and express-graphql and graphql-import to compose the API.
type User {
id: ID!
name: String!
}
type Link {
id: ID!
url: String!
user: User!
}
type Query {
links(id: ID!): [Link!]!
}
// resolvers
const links = async (root, args, ctx) => {
const links = await ctx.prisma.links({
where: {
user {
id: args.id
}
}
}
}
// resolver for `Link` type
const user = async (root, args, ctx) => {
const user = await ctx.prisma.link({ id: parent.id }).user()
return user
}
// omitted field resolver for `url` and `id`
module.exports = {
user
}
With these codes, I expected to get id, url, user fields when I query links, but when I send the query, it returns null with user field. Which means, if I check in the server-side, the resolver for user field does not invoked at all. What is wrong with this?
I'm trying to execute a mutation query that requires a custom input type on the client. Currently it looks something like this:
import { graphql } from 'react-apollo';
...
const graphQuery = graphql(gql`
input UserSignUpInput {
firstName: String!,
lastName: String!,
email: String!,
password: String!
}
mutation userSignUp($input: UserSignUpInput!) {
createUserByEmail(input: $input) {
authToken
}
}`, {
props: ({ mutate }) => ({
signup: (firstName, lastName, email, password) =>
mutate({ variables: { input: { firstName, lastName, email, password } } }),
}),
});
...
However I'm getting the error that I'm not allowed to define input types in the query. My question is: How do I define these complex input types? It doesn't seem like I'm able to provide a Schema to ApolloClient..
The correct syntax on the client side is just:
gql`
mutation userSignUp($input: UserSignUpInput!) {
createUserByEmail(input: $input) {
authToken
}
}
`
As your input UserSignUpInput is defined on the server, everything is going fine.
server
input UserSignUpInput {
firstName: String!,
lastName: String!,
email: String!,
password: String!
}