How to pass params to child property in GraphQL - graphql

i am pretty new to GraphQL, getting to become a huge fan :)
But, something is not clear to me. I am using Prisma with and GraphQL-Yoga with Prisma bindings.
I do not know how to pass params from my graphQL server to sub properties. Don't know if this is clear, but i will show it with code, thats hopefully easier :)
These are my types
type User {
id: ID! #unique
name: String!
posts: [Post!]!
}
type Post {
id: ID! #unique
title: String!
content: String!
published: Boolean! #default(value: "false")
author: User!
}
My schema.graphql
type Query {
hello: String
posts(searchString: String): [Post]
users(searchString: String, searchPostsTitle: String): [User]
me(id: ID): User
}
and my users resolver:
import { Context } from "../../utils";
export const user = {
hello: () => "world",
users: (parent, args, ctx: Context, info) => {
return ctx.db.query.users(
{
where: {
OR: [
{
name_contains: args.searchString
},
{
posts_some: { title_contains: args.searchPostsTitle }
}
]
}
},
info
);
},
me: (parent, args, ctx: Context, info) => {
console.log("parent", parent);
console.log("args", args);
console.log("info", info);
console.log("end_________________");
return ctx.db.query.user({ where: { id: args.id } }, info);
}
};
and my posts resolver
import { Context } from "../../utils";
export const post = {
posts: (parent, args, ctx: Context, info) => {
return ctx.db.query.posts(
{
where: {
OR: [
{
title_contains: args.searchString
},
{
content_contains: args.searchString
}
]
}
},
info
);
}
};
so, now :)
I am able to do the following when i am in the GraphQL playground on my prisma service:
{
user(where: {id: "cjhrx5kaplbu50b751a3at99d"}) {
id
name
posts(first: 1, after: "cjhweuosv5nsq0b75yc18wb2v") {
id
title
content
}
}
}
but i cant do it on the server, if i do something like that.. i am getting the error:
"error": "Response not successful: Received status code 400"
this is what i am trying:
{
me(id: "cjhrx5kaplbu50b751a3at99d") {
id
name
posts(first:1) {
id
title
content
}
}
}
does somebody know how i could do that?

since i have a custom type of user, posts does not have params like the generated one. Either i am using the the generated one, or modifying it to look like this:
type User {
id: ID!
name: String!
posts(where: PostWhereInput, orderBy: PostOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Post!]
}
EDIT 2018 June 4th
# import Post from './generated/prisma.graphql'
type Query {
hello: String
posts(searchString: String): [Post]
users(searchString: String, where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]
me(id: ID): User
}
type Mutation {
createUser(name: String!): User
createPost(
title: String!
content: String!
published: Boolean!
userId: ID!
): Post
}
I copied the params over from prisma.graphql manually.

Related

How can I make GraphQL support int8 type in Supabase?

I'm creating a simple CRUD app to learn GraphQL and am using a Supabase postgres instance. All queries and mutations work fine except for one thing, I can't get the id field from my schemas because they are of type int8 on Supabase, and GraphQL only supports Int.
I'm getting this error when I try to get a row's id using the gql Int type in my type defs: GraphQLError: Int cannot represent non-integer value: 1
I know the solution involves creating a custom scalar type as in this example, but I'm not sure how to implement this type. Also, I cannot change this on Supabase's side, so I must find a way to handle this in gql. How can I handle this type in GraphQL?
TypeDefs:
export const typeDefs = `#graphql
type User {
id: Int!
name: String!
email: String!
age: Int!
verified: Boolean!
}
type Todo {
id: Int!
title: String!
description: String!
}
type Query {
# users queries
getAllUsers: [User]
getUser(email: String!): User
# todo queries
getAllTodos: [Todo]
getTodo(id: String!): Todo
}
type Mutation {
createUser(name: String!, email: String!, age: Int!): User
createTodo(title: String!, description: String!): Todo
}
`;
Resolvers:
import { GraphQLScalarType } from 'graphql';
import { prisma } from '../lib/db.js';
const BigInt = new GraphQLScalarType({
// how do I implement this type?
});
export const resolvers = {
BigInt,
Query: {
getAllUsers() {
return prisma.user.findMany();
},
getUser(parent, args) {
return prisma.user.findUnique({
where: {
email: args.email,
},
});
},
getAllTodos() {
return prisma.todo.findMany();
},
getTodo(parent, args) {
return prisma.todo.findUnique({
where: {
id: args.id,
},
});
},
},
// parent, arge are other arguments that get passes to resolvers automatically
Mutation: {
createUser(parent, args) {
return prisma.user.create({
data: args,
});
},
createTodo(parent, args) {
return prisma.todo.create({
data: args,
});
},
},
};
Solved this by using the graphql-type-ints package. You can just install it and then add the type you need to your schemas and resolvers. However, I don't quite understand why we need to do this. If someone could explain why Supabase uses int8 and that doesn't conform to graphql's Int I would appreciate it.

How to add item into an list field?

I want to add members to chatRoom member list by passing memberId to graphql mutation function. But it pop up some errors. I have attached most code that relevant to this question as below. Please help me to figure it out. I guess create: {connect } might be the cause of this issue.
//Here is Mutation function
async function addMemberToChatRoom(parent, args, context, info) {
const member = await context.prisma.users({
where: {
id: args.memberId
}
});
const chatRoom = await context.prisma.updateChatRoom({
where: {
id: args.roomId
},
data: {
users: {
create: {
{ connect: { id: args.memberId } }
}
}
}
})
return chatRoom
}
//Here is prisma datamodel
type User {
id: ID! #id
name: String!
email: String! #unique
password: String!
}
type ChatRoom {
id: ID! #id
name: String!
users: [User]!
}
type Message {
id: ID! #id
content: String!
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
}
//Here is Schema.graphql
type Query {
info: String!
users: [User!]!
}
type Mutation {
signup(email: String!, password: String!, name: String!): AuthPayload
login(email: String!, password: String!): AuthPayload
createChatRoom(name: String!): ChatRoom
addMemberToChatRoom(roomId: String!, memberId: String!): ChatRoom
}
type AuthPayload {
token: String!
user: User!
}
type User {
id: ID!
name: String!
email: String!
}
type ChatRoom {
id: ID!
name: String!
users: [User!]
}
//Here is index.js
const { GraphQLServer } = require('graphql-yoga')
const { prisma } = require('./generated/prisma-client')
const Query = require('./resolvers/Query')
const Mutation = require('./resolvers/Mutation')
// const User = require('./resolvers/User')
const resolvers = {
Query,
Mutation
}
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
context: request => {
return {
...request,
prisma,
}
},
tracing: true,
})
server.start(() => console.log(`Server is running on http://localhost:4000`))
//Here is error
{
"data": {
"addMemberToChatRoom": null
},
"errors": [
{
"message": "Variable '$data' expected value of type 'ChatRoomUpdateInput!' but got: {\"users\":{\"create\":{\"id\":\"cjuzcf7lx75g60b953w50uwdc\"}}}. Reason: 'users.create[0].name' Expected non-null value, found null. (line 1, column 46):\nmutation ($where: ChatRoomWhereUniqueInput!, $data: ChatRoomUpdateInput!) {\n ^",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"addMemberToChatRoom"
]
}
]
}
I remove create and change it to
users:
{
connect: { id: args.memberId }
}
then it works.
async function addMemberToChatRoom(parent, args, context, info) {
const member = await context.prisma.users({
where: {
id: args.memberId
}
});
const chatRoom = await context.prisma.updateChatRoom({
where: {
id: args.roomId
},
data: {
users: {
connect: { id: args.memberId }
}
}
})
const returnedChatRoom = await context.prisma.chatRooms({
where: {
id: args.roomId
}
});
return returnedChatRoom
}

Prisma graphql computed fields on relations

I have the following datamodel:
type Tvshow {
id: ID! #unique
title: String!
pricing: [Pricing]
startDate: DateTime!
endDate: DateTime!
subscribers: [Tvshowsubscription!]
.....
}
type FavoriteTvshow {
id: ID! #unique
tvshow: Tvshow!
user: User!
}
type User {
id: ID! #unique
name: String
email: String! #unique
password: String
googleID: String #unique
resetToken: String
resetTokenExpiry: String
permissions: [Permission]
address: Address
phone: String
favorites: [FavoriteTvshow!]
tvshowSubscriptions: [Tvshowsubscription!]
}
I have my custom Tvshow resolver using addFragmentToInfo:
resolver-queries.js
const Query = {
...
favoriteTvshows: forwardTo('db'),
tvshow: (parent, args, ctx, info) => {
const fragment = `fragment EnsureComputedFields on Tvshow { pricing { minQuantity maxQuantity unitPrice} subscribers { id }}`
return ctx.db.query.tvshow({}, addFragmentToInfo(info, fragment))
},
....
};
tvshow-resolver.js
const Tvshow = {
countSubscribers: (parent) => {
return parent.subscribers.length;
},
}
This is an example, I have more computed fields for Tvshow
I can query Tvshows with countSubscribers, It works fine doing something like this:
query SINGLE_TVSHOW_QUERY($id: ID!) {
tvshow(where: { id: $id }) {
id
title
pricing {
minQuantity
maxQuantity
unitPrice
}
startDate
endDate
countSubscribers
}
}
But what I want to do is to get all the favorite Tvshows from an user returning the countSubscribers, a query for that could be something like this:
query FAVORITES_FROM_USER($userId: ID!) {
favoriteTvshows(where: { user: {id: $userId} }) {
tvshow {
id
title
startDate
endDate
countSubscribers
}
}
}
The problem is that when I query this, in the tvshow-resolver.js I mentioned before, the parent doesn’t have any subscribers object
The error was very silly but I will post it anyway. I needed subscribers in the query
query FAVORITES_FROM_USER($userId: ID!) {
favoriteTvshows(where: { user: {id: $userId} }) {
tvshow {
id
title
startDate
endDate
subscribers { <---
id
quantity
}
countSubscribers
}
}
}
That way the parent in tvshow-resolver.js will have subscribers object

Querying NOT NULL GraphQL with Prisma

Schema:
type TrackUser {
id: ID! #unique
createdAt: DateTime!
user: User #note there is no `!`
}
type User {
id: ID! #unique
name: String! #unique
}
I want to get Alls TrackUser where User is not null. What would be the query?
This would be a possible query:
query c {
trackUsers(where: { NOT: [{ user: null }] }) {
name
}
}
Here you can see how it looks in the Playground. I added a name to Trackuser in the datamodel in order to be able to create it from that side without a user.
this works, but I guess it is just a hack..
query TrackUsersQuery($orderBy: TrackUserOrderByInput!, $where: TrackUserWhereInput, $first: Int, $skip: Int) {
trackUsers(where: $where, orderBy: $orderBy, first: $first, skip: $skip) {
id
createdAt
user {
id
name
}
}
}
variables = {
where: {
user: {
name_contains: ''
}
}
}
UPDATE:
For Prisma2, here you have the possibilities:
For products that have no invoice, you can use the following:
const data = await prisma.product.findMany({
where: {
invoices: {
none: {
id: undefined,
},
},
},
})
And for Invoices that do not have a product associated:
const data = await prisma.invoice.findMany({
where: {
productId: null,
},
})
more details here: https://github.com/prisma/prisma/discussions/3461

How to pass the values of a connection to a subscription?

I'm trying to return a subscription which consists of the following:
const postsSubscription = gql`
subscription postAdded {
postAdded {
id
title
description
author{
name
}
}
}
`
What happens is that Author is type of User, and I just pass an authorId. That means that I don't have the author name when I create the Post:
createPost: async (root, req, { posts }) => {
const Item = {
id: uuid.v4(),
authorId: '565dbdc0-36f2-4bba-be67-c126d0c71fff',
...req
}
await posts.create({ Item })
pubsub.publish('postAdded', { postAdded: Item })
return Item
},
Here is the Author resolver:
Post: {
author: async({ authorId }, req, { users }) => {
const Key = { id: authorId }
const { Item } = await users.get({ Key })
return Item
}
}
Here is the schema:
type Post {
id: ID
title: String
description: String
author: User #relation(name: "PostAuthor")
}
type User {
id: ID
name: String
email: String
password: String
posts: [Post] #relation(name: "UserPosts")
}
type PostPayload {
post: Post
}
type CreateUserPayload {
user: User
}
type Query {
allPosts: [Post]
allUsers: [User]
post(id: ID!): Post
user(id: ID!): User
}
type Mutation {
createPost(input: CreatePostInput!): PostPayload
updatePost(input : UpdatePostInput!): PostPayload
createUser(input : CreateUserInput!): CreateUserPayload
}
type Subscription {
postAdded: Post
}
input CreatePostInput {
title: String!
description: String!
}
input UpdatePostInput {
id: ID!
title: String!,
description: String!
}
input CreateUserInput {
name: String!
email: String!
password: String!
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
So, my question is, how to pass all required fields (including the connections) to the subscription?
I made it work, but not as I wanted.
1) I had to remove this part of the code:
Post: {
author: async({ authorId }, req, { users }) => {
const Key = { id: authorId }
const { Item } = await users.get({ Key })
return Item
}
}
and added this function to the createPost function itself:
createPost: async (root, { input }, { posts, users }) => {
const Key = { id: '3b1884b8-9ee7-4d9d-ab2f-ff32bcd69b9a' }
const user = await users.get({ Key })
const Item = {
id: uuid.v4(),
author: user.Item,
...input
}
await posts.create({ Item })
await pubsub.publish(POST_ADDED_TOPIC, { [POST_ADDED_TOPIC]: Item })
return { post: Item }
}
So this is kinda fixed. But, if you know how to fix this, using the first approach (Post: author thingy) I'll appreciate.

Resources