Hello guys here is the scenario i have;
model User {
id Int #default(autoincrement()) #id
...
posts Post[]
comments Comment[]
}
model Post {
id Int #default(autoincrement()) #id
comments Comment[]
...
}
model Comment {
id Int #default(autoincrement()) #id
post Post #relation(fields: [postId], references: [id])
postId Int
...
}
So i'm trying to delete a comment, and below is my approach
export const deleteComment = mutationField('deleteComment', {
type: 'Comment',
args: {
where: 'CommentWhereUniqueInput',
},
resolve: async (_, { where }, ctx) => {
let comment = await ctx.prisma.comment.delete({
where: where,
include:{
author: true,
post:true
},
})
return comment
},
})
But i'm having an error message which says 'Cannot return null for non-nullable field Comment.post.'
Any idea how i can solve it?
Thanks
Maybe with npm i #paljs/plugins
https://paljs.com/plugins/delete/
or https://www.prisma.io/docs/guides/database-workflows/cascading-deletes/postgresql
Related
I have begun testing out prisma 2 and graphql in general for a new application. I am running into an issue with an explicit many to many table on being able to query relations.
Here is my apollo schema:
scalar DateTime
type Query {
user(id: String!): User
users: [User]
spaces: [Space]
roles: [Role]
}
type Mutation {
createUser(id: String!, email: String!): User!
createSpace(name: String!): Space!
}
type User {
id: ID!
email: String!
spaces: [UserSpace!]
createdAt: DateTime!
updatedAt: DateTime!
}
type Space {
id: ID!
name: String!
users: [UserSpace!]
createdAt: DateTime!
updatedAt: DateTime!
}
type Role {
id: ID!
name: String!
description: String!
users: UserSpace
createdAt: DateTime!
updatedAt: DateTime!
}
type UserSpace {
id: ID!
user: User!
space: Space!
role: Role!
createdAt: DateTime!
updatedAt: DateTime!
}
Here is my prisma schema:
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// npx prisma migrate dev
// npx prisma generate
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String #id
email String #unique
spaces UserSpace[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
model Space {
id Int #default(autoincrement()) #id
name String #unique
users UserSpace[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
model Role {
id Int #default(autoincrement()) #id
name String #unique
description String
users UserSpace[]
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
model UserSpace {
id Int #default(autoincrement()) #id
user User #relation(fields: [userId], references: [id])
userId String
space Space #relation(fields: [spaceId], references: [id])
spaceId Int
role Role #relation(fields: [roleId], references: [id])
roleId Int
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
Here is my mutations resolver:
const { prisma } = require(".prisma/client");
async function createUser(parent, args, context, info) {
return await context.prisma.user.create({
data: {
...args,
},
});
}
async function createSpace(parent, args, context, info) {
const isAuthenticated = context.authentication.isAuthenticated;
let role = null;
if(!isAuthenticated) {
throw new Error("Not Authenticated");
}
try {
role = await context.prisma.role.findUnique({
where: {
name: "Space Administrator",
},
});
}
catch(err) {
throw new Error(err);
}
return await context.prisma.space.create({
data: {
...args,
users: {
create: {
role: {
connect: { id: role.id },
},
user: {
connect: { id: context.authentication.auth0Id },
},
},
},
},
});
}
module.exports = {
createUser,
createSpace,
}
Here is my user resolver (I know this is where the problem is however I do not know how to solve the issue):
function spaces(parent, args, context, info) {
return context.prisma.user.findUnique({ where: { id: parent.id } }).spaces();
}
module.exports = {
spaces,
}
Basically when I create the space the user is added as a Space Administrator to the space and then should be able to be queried with the following:
query {
users {
id
email
spaces {
id
role {
name
}
space {
name
}
}
createdAt
}
}
However when I run the query I get the following error:
"message": "Cannot return null for non-nullable field UserSpace.role.",
How in prisma 2 do I make the resolver for the users work with an explicit many to many table and how it has the third relation in there? I am new to prisma and graphql so if there anything else that stands out also I would like to have the input.
I'm using the word type to refer to object-models in your GraphQL schema and model to refer to data-models in your Prisma Schema.
The Problem
I see that you have a User type resolver, that has a resolver function for User.spaces field in your User type. The query that you have defined in your User.spaces resolver will return the relevant userSpace records from the database.
However, these userSpace records do not by default resolve the role field, as it is a relation field. This is how prisma works (relation fields are not resolved by default, unless explicitly stated).
Solution
Create a resolver for the UserSpace type and explicitly define the the resolver function for UserSpace.role field. This is what it will look like
// UserSpace resolver module
function role(parent, args, context, info) {
return context.prisma.userSpace.findUnique({ where: { id: parent.id } }).role();
}
module.exports = {
role,
}
While there are some other ways to solve this problem, the way I have shown (along with the specific syntax) is recommended because under the hood it allows prisma to perform certain optimizations to solve the n+1 query problem. But, if you don't know what that is, you don't necessarily need to worry about it either.
Did you provide the value to users arg? like this: users(id: "string_value"). Because is id is required.
I have a User model along UserRelationship model
I have created trainer/client relationship with the UserRelationship model.
model User {
id Int #id #default(autoincrement())
trainerRelationship UserRelationship[] #relation("trainer")
traineeRelationship UserRelationship[] #relation("trainee")
}
model UserRelationship {
id Int #id #default(autoincrement())
trainerId Int?
traineeId Int?
trainerUser User? #relation("trainer", fields: [trainerId], references: [id])
traineeUser User? #relation("trainee", fields: [traineeId], references: [id])
}
I am able to query the user also able to query their relationship
For eg:
const trainer = await client.user
.findUnique({ where: { id }, include: { trainerRelationship: true } })
The output i am getting here is like:
{
id: 1,
username: hellouser
trainerRelationship: [
{
id: 4,
trainerId: 1,
traineeId: 34
}
]
}
Now i want to fetch the details of the traineeId/trainerId user details, What should be my query?
Ok, so I have solved it by the below query, incase someone is stuck:
.findUnique({ where: { id } }).trainerRelationship({
include: {
trainerUser: true,
},
})
Maybe the title is not accurate but I really don't know how to describe it anymore. I went through multiple documentations and descriptions but still couldn't figure it out.
I want to implement a basic social media like followers/following query on my type User. I am using MySQL and for that I made a separate table called Follow as it's a many-to-many connection.
Here is a pseudo-ish representation of my tables in the database without the unnecessary columns:
Table - User
user_id primary key Int
Table - Follow
follow_er foreign_key -> User(user_id) Int
follow_ed foreign_key -> User(user_id) Int
A user could "act" as a follow_er so I can get the followed people
And a user could be follow_ed, so I can get the followers.
My prisma schema look like this:
model User {
user_id Int #id #default(autoincrement())
following Follow[] #relation("follower")
followed Follow[] #relation("followed")
}
model Follow {
follow_er Int
follower User #relation("follower", fields: [follow_er], references: [user_id])
follow_ed Int
followed User #relation("followed", fields: [follow_ed], references: [user_id])
##id([follow_er, follow_ed])
##map("follow")
}
By implementing this I can get the followers and following object attached to the root query of the user:
const resolvers = {
Query: {
user: async (parent, arg, ctx) => {
const data = await ctx.user.findUnique({
where: {
user_id: arg.id
},
include: {
following: true,
followed:true
}
})
return data
}....
Here is my GraphQL schema I tried to make:
type Query{
user(id: Int!): User
}
type User{
id: ID
following: [User]
followed: [User]
}
So I can get something like:
query {
user(id: $id) {
id
following {
id
}
followed{
id
}
}
}
}
But I couldn't make it work as even if I get the the array of objects of {follow-connections}:
[
{
follow_er:1,
follow_ed:2
},
{
follow_er:1,
follow_ed:3
},
{
follow_er:3,
follow_ed:1
},
]
I can't iterate through the array. As far as I know, I have to pass either the follow_er or follow_ed, which is a user_id to get a User object.
What am I missing? Maybe I try to solve it from a wrong direction. If anybody could help me with this, or just tell me some keywords or concepts I have to look for it would be cool. Thanks!
I would suggest creating self-relations for this structure in the following format:
model User {
id Int #id #default(autoincrement())
name String?
followedBy User[] #relation("UserFollows", references: [id])
following User[] #relation("UserFollows", references: [id])
}
And then querying as follows:
await prisma.user.findUnique({
where: { id: 1 },
include: { followedBy: true, following: true },
})
So you will get a response like this:
I have a User table that contains user data. I also have a Relationship table that contains a parent_id and a child_id as well as the incrementing id. Each Parent can have many Children and I am trying to retrieve the array of children using the parent_id. I am currently getting an array, but the array only contains the Relationship table data.
How do I get the data from the User table? I was under the impression that because there is a relationship the following should work, but it doesnt.
query {
getChildren {
user{
id
name
email
}
}
}
The relevant code is as follows:
Query:
export const getChildren = queryField('getChildren', {
type: 'User',
list: true,
resolve: async (_parent, {}, ctx) => {
const userId = getUserId(ctx);
if (!userId) {
// TODO -think I might need to throw an error here
return;
}
const children = await ctx.prisma.relationship.findMany({
where: {
parent_id: userId,
},
});
return children;
},
});
schema.prisma:
model Relationship {
child_id Int
id Int #default(autoincrement()) #id
parent_id Int
child User #relation("Relationship_child_idToUser", fields: [child_id], references: [id])
parent User #relation("Relationship_parent_idToUser", fields: [parent_id], references: [id])
}
model User {
created_at DateTime #default(now())
email String? #unique
id Int #default(autoincrement()) #id
ischild Boolean #default(false)
name String?
password String
children Relationship[] #relation("Relationship_child_idToUser")
parents Relationship[] #relation("Relationship_parent_idToUser")
}
The query below should do it
prisma.relationship.findMany({
where: {
parent_id: user_id,
},
include: {
child: true,
},
})
You need to specify the include param explicitly to include the relationship in the output.
I am trying to understand graphql's query and mutation syntax. Given this example:
type Author {
id: Int!
firstName: String
lastName: String
posts: [Post]
}
type Post {
id: Int!
title: String
author: Author
votes: Int
}
type Query {
posts: [Post]
author(id: Int!): Author
}
What should the queries look like to associate a post with the author? Is this where connections come into play or is that something else? Here is my attempt at trying to solve the problem but to avail.
mutation createAuthor {
createAuthor(input: {
id: 123
firstName: "Bob"
lastName: "Smith"
}) {
id
firstName
lastName
}
}
query listAuthors {
listAuthors {
items {
id
firstName
lastName
}
}
}
mutation createPost {
createPost(input: {
id: 12345
title: "Title"
votes: 345
author: {
lastName: {
contains: "Bob"
}
}
}) {
id
title
votes
author {
id
firstName
lastName
}
}
}
Any help on this would be appreciated. My Goal is to Query an author and return all of the post's associated with that author as well as create a Post Mutation that adds a post to an author.
There are 2 questions in one, so I'll answer in the order there were asked.
1. return all of the posts associated with an author
Your schema looks correct. The query would look like:
query {
author(id: 1) {
id
posts {
id
title
}
}
}
2. create Post and attach to an author
In your example if you want to expose an interface to create a Post, then you would have to expose a mutation field in your schema
e.g:
type Mutation {
createPost(input: CreatePostInput): Post
}
if you want at the same time of creating a post, to also attach it to an author then you could add the authorId as part of the input, here we only want to attach the Post to an existing Author:
input CreatePostInput {
title: String
authorId: ID!
votes: Int
}
of course this is only the interface definition. We need to actually create the Post and link it to the Author inside the resolver.
The mutation query will look like:
mutation createPost {
createPost(input: {
title: "Title"
votes: 345
authorId: "authorId1"
}) {
id
title
votes
author {
id
firstName
lastName
}
}
}
Hope that helps!