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)
Related
I just tried to implement the Relay in Frontend for this graphql tutorial, In that tutorial, they created graphql server to store URL(Link) bookmarks with the User who posted those URLs.
The relationship between the link and the users is:
Link belongs_to :user,
User has_many :links.
And I listed out all the Links with Users in Frontend, at the time I got the below error.
Warning: RelayResponseNormalizer: Invalid record 1. Expected __typename to be consistent, but the record was assigned conflicting types Link and User. The GraphQL server likely violated the globally unique id requirement by returning the same id for different objects
I'm not aware of how much it will impact the application. because I got the expected result from Frontend.
Frontend View of Query.
I read this relay official blog for this kind of error, but there is no example to know how exactly to resolve this. so can someone help to resolve this?
Relay Query
graphql`
query LinkListQuery {
allLinks {
id,
description,
url,
postedBy {
id,
name
}
}
}`
Schema:
input AUTH_PROVIDER_CREDENTIALS {
email: String!
password: String!
}
input AuthProviderSignupData {
credentials: AUTH_PROVIDER_CREDENTIALS
}
type Link implements Node {
description: String!
id: ID!
postedBy: User
url: String!
votes: [Vote!]!
}
input LinkFilter {
OR: [LinkFilter!]
descriptionContains: String
urlContains: String
}
type Mutation {
createLink(description: String!, url: String!): Link!
createUser(name: String!, authProvider: AuthProviderSignupData): User!
createVote(linkId: ID): Vote!
signinUser(credentials: AUTH_PROVIDER_CREDENTIALS): SignInUserPayload
}
"""An object with an ID."""
interface Node {
"""ID of the object."""
id: ID!
}
type Query {
allLinks(filter: LinkFilter, first: Int, skip: Int): [Link]!
"""Fetches an object given its ID."""
node(
"""ID of the object."""
id: ID!
): Node
}
"""Autogenerated return type of SignInUser"""
type SignInUserPayload {
token: String
user: User
}
type User implements Node {
email: String!
id: ID!
links: [Link!]!
name: String!
votes: [Vote!]!
}
type Vote {
id: ID!
link: Link!
user: User!
}
I am using ApolloServer/Prisma2/GraphQL/Typescript/MySQL
I have created two models, User, and Post. My createUser and createPost mutations are working fine. However, I am having trouble getting my delete mutations working. Focusing on the deletePost, here is what I have in my code.
<<schema.graphql>>
type Query {
posts: [Post!]!
users: [User!]!
}
type Mutation {
createPost(title: String!, body: String!): Post!
createUser(name: String!, email: String!, password: String!): User!
deletePost(postId: ID!): Post
deleteAllPosts: [Post!]!
}
type Post {
id: ID!
title: String!
body: String!
author: User
published: Boolean!
}
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
<<schema.prisma>>
model Post {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt #default(now())
title String
body String
published Boolean #default(false)
postedBy User? #relation(fields: [authorId], references: [id])
authorId Int?
}
model User {
id Int #id #default(autoincrement())
name String
email String #unique
password String
posts Post[]
}
<<Mutation.ts>>
async function deletePost(parent, { postId }, context, info) {
return await context.prisma.post.delete(
{
where {
id: parseInt(postId)
}
},
info
)
}
Note that the createPost and createUser are also in the Mutation.ts file and are working correctly. So I'm assuming there is no issue with the Apollo server.
When I use the GraphQL playground I use the following:
mutation {
deletePost(postId: "1") {
id
}
}
with the following result:
{
"data": {
"deletePost": null
}
}
I want the mutation to return the deleted post (at least the id if nothing else). In addition, the database is not deleting anything. I'd appreciate any help.
I am fairly new to GraphQL Prisma combo, I cannot seem to order nested relationships without error because the only available orderBy fields are regarding the ID.
My intended goal in the playground would be to create a query that looks similar to the following:
getPosts{
connections(orderBy: "text_asc"){
id
text
}
}
Resolver
getPosts(parent, args, ctx, info){
return ctx.db.query.posts({}, info)
}
Data Model
type Post {
id: ID! #id
isPublished: Boolean! #default(value: false)
title: String!
text: String!
connections: [Connection!]! #relation(name: "ClientConnect")
}
type Link {
id: ID! #id
text: String!
url: String!
}
type Connection {
id: ID! #unique #id
client: Link #relation(name: "LinkConnect")
}
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.
I am trying to append extra fields to the info object when querying data from prisma database. I have seen this post but I can't get fragments working.
I have below migrations:
type User {
id: ID! #unique
name: String
}
type Video {
id: ID! #unique
name: String
likes: [Like]
}
type Like {
id: ID! #unique
user: User
createdAt: DateTime!
}
Now, I would like to query all videos and check if current user has already liked a video. If so, the likes object should read the createdAt value, otherwise it would be empty.
I am doing this in playground via following query:
query {
videos() {
id
name
hasVoted: likes(where: {user: {id: "cjr7r85jy00rc0892dfwpu96u"}){
createdAt
}
}
}
this works but I would like to add the hasVoted to my query resolver to automatically append it to all queries. How can I do this ?
I tried solving it via fragments but without luck:
videos: {
fragment: `fragment hasVoted on Video {
hasVoted: likes (where: {user: {id: "cjr7r85jy00rc0892dfwpu96u"}}){
createdAt
}
}`,
resolve: async (_, args, ctx, info) => {
return await ctx.prisma.query.videos({},info);
}
}
Anyone has some ideas how I can do this? thx!
You can use addFragmentToInfo from graphql-bindings
https://oss.prisma.io/content/graphql-binding/02-api-reference#addfragmenttoinfo