├── .prettierrc ├── src ├── types │ ├── query │ │ ├── IBookQuery.ts │ │ ├── IReviewQuery.ts │ │ ├── IUserQuery.ts │ │ └── IPublisherQuery.ts │ ├── mutation │ │ ├── IBookMutation.ts │ │ ├── IUserMutation.ts │ │ ├── IReviewMutation.ts │ │ ├── IPublisherMutation.ts │ │ └── IAuthMutation.ts │ ├── IContext.ts │ ├── types.ts │ └── graphqlgen.ts ├── middlewares │ ├── index.ts │ └── permissions │ │ ├── index.ts │ │ └── rules.ts ├── errors │ └── FormatedError.ts ├── resolvers │ ├── Publisher.ts │ ├── index.ts │ ├── Rating.ts │ ├── Review.ts │ ├── User.ts │ ├── Book.ts │ ├── Query │ │ ├── index.ts │ │ ├── ReviewQuery.ts │ │ ├── BookQuery.ts │ │ ├── PublisherQuery.ts │ │ └── UserQuery.ts │ └── Mutation │ │ ├── index.ts │ │ ├── UserMutation.ts │ │ ├── PublisherMutation.ts │ │ ├── ReviewMutation.ts │ │ ├── BookMutation.ts │ │ └── AuthMutation.ts ├── validators │ ├── PublisherValidator.ts │ ├── ReviewValidation.ts │ ├── UserValidator.ts │ ├── BookValidator.ts │ └── index.ts ├── index.ts ├── helpers │ ├── errorFormater.ts │ └── jwtHelper.ts ├── prisma │ ├── datamodel.prisma │ └── generated │ │ └── prisma-client │ │ └── prisma-schema.ts ├── @types │ └── graphql-shield.d.ts ├── utils.ts └── schema.graphql ├── .env.example ├── prisma.yml ├── graphqlgen.yml ├── tsconfig.json ├── docker-compose.yml ├── LICENSE ├── .gitignore ├── package.json └── README.md /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "bracketSpacing": true, 5 | "arrowParens": "avoid", 6 | "endOfLine": "lf" 7 | } 8 | -------------------------------------------------------------------------------- /src/types/query/IBookQuery.ts: -------------------------------------------------------------------------------- 1 | import { QueryResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IBookQuery { 4 | static getBooks: QueryResolvers.GetBooksResolver; 5 | } 6 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_SECRET= 2 | PRISMA_ENDPOINT= 3 | PRISMA_API_PORT= 4 | DB_USER= 5 | DB_PASSWORD= 6 | DATABASE= 7 | DATABASE_HOST= 8 | -------------------------------------------------------------------------------- /src/types/query/IReviewQuery.ts: -------------------------------------------------------------------------------- 1 | import { QueryResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IReviewQuery { 4 | static getReviews: QueryResolvers.GetReviewsResolver; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/query/IUserQuery.ts: -------------------------------------------------------------------------------- 1 | import { QueryResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IUserQuery { 4 | static getAuthors: QueryResolvers.GetPublishersResolver; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/mutation/IBookMutation.ts: -------------------------------------------------------------------------------- 1 | import { MutationResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IBookMutation { 4 | static createBook: MutationResolvers.CreateBookResolver; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/query/IPublisherQuery.ts: -------------------------------------------------------------------------------- 1 | import { QueryResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IPublisherQuery { 4 | static getPublishers: QueryResolvers.GetPublishersResolver; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/mutation/IUserMutation.ts: -------------------------------------------------------------------------------- 1 | import { MutationResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IUserMutation { 4 | static createAuthor: MutationResolvers.CreateAuthorResolver; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/mutation/IReviewMutation.ts: -------------------------------------------------------------------------------- 1 | import { MutationResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IReviewMutation { 4 | static createReview: MutationResolvers.CreateReviewResolver; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/mutation/IPublisherMutation.ts: -------------------------------------------------------------------------------- 1 | import { MutationResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IPublisherMutation { 4 | static createPublisher: MutationResolvers.CreatePublisherResolver; 5 | } 6 | -------------------------------------------------------------------------------- /prisma.yml: -------------------------------------------------------------------------------- 1 | endpoint: '' 2 | datamodel: src/prisma/datamodel.prisma 3 | 4 | generate: 5 | - generator: typescript-client 6 | output: src/prisma/generated/prisma-client/ 7 | 8 | hooks: 9 | post-deploy: 10 | - prisma generate 11 | -------------------------------------------------------------------------------- /src/types/mutation/IAuthMutation.ts: -------------------------------------------------------------------------------- 1 | import { MutationResolvers } from '../graphqlgen'; 2 | 3 | export abstract class IAuthMutation { 4 | static signup: MutationResolvers.SignupResolver; 5 | static login: MutationResolvers.LoginResolver; 6 | } 7 | -------------------------------------------------------------------------------- /src/types/IContext.ts: -------------------------------------------------------------------------------- 1 | import { Prisma, User } from '../prisma/generated/prisma-client'; 2 | import { Request } from 'express-serve-static-core'; 3 | 4 | export interface IContext { 5 | prisma: Prisma; 6 | request: Request; 7 | user: Partial; 8 | } 9 | -------------------------------------------------------------------------------- /src/middlewares/index.ts: -------------------------------------------------------------------------------- 1 | import { IMiddlewareGenerator } from 'graphql-middleware'; 2 | 3 | import permissionsMiddleware from './permissions'; 4 | 5 | const middlewares: IMiddlewareGenerator[] = [ 6 | permissionsMiddleware, 7 | ]; 8 | 9 | export default middlewares; 10 | -------------------------------------------------------------------------------- /graphqlgen.yml: -------------------------------------------------------------------------------- 1 | language: typescript 2 | 3 | schema: ./src/schema.graphql 4 | context: ./src/types/IContext:IContext 5 | 6 | models: 7 | files: 8 | - ./src/prisma/generated/prisma-client 9 | - ./src/types/types.ts 10 | 11 | output: ./src/types/graphqlgen.ts 12 | 13 | resolver-scaffolding: 14 | output: ./src/tmp-resolvers/ 15 | layout: file-per-type 16 | -------------------------------------------------------------------------------- /src/errors/FormatedError.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | 3 | export interface IErrorState { 4 | [propertyName: string]: []; 5 | } 6 | 7 | class FormatedError extends GraphQLError { 8 | readonly state: any; 9 | 10 | constructor(message: string, errors: any) { 11 | super(message); 12 | this.state = errors; 13 | } 14 | } 15 | 16 | export default FormatedError; 17 | -------------------------------------------------------------------------------- /src/resolvers/Publisher.ts: -------------------------------------------------------------------------------- 1 | import { PublisherResolvers } from '../types/graphqlgen'; 2 | import { Book } from '../prisma/generated/prisma-client'; 3 | 4 | export const Publisher: PublisherResolvers.Type = { 5 | ...PublisherResolvers.defaultResolvers, 6 | 7 | publication: async ({ id }, args, { prisma }): Promise => { 8 | const publication: Book[] = await prisma.publisher({ id }).publication(); 9 | return publication; 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /src/resolvers/index.ts: -------------------------------------------------------------------------------- 1 | import Query from './Query'; 2 | import Mutation from './Mutation'; 3 | import { Resolvers } from '../types/graphqlgen'; 4 | import { User } from './User'; 5 | import { Book } from './Book'; 6 | import { Publisher } from './Publisher'; 7 | import { Review } from './Review'; 8 | import { Rating } from './Rating'; 9 | 10 | const resolvers: Resolvers = { 11 | Query, 12 | Mutation, 13 | User, 14 | Book, 15 | Publisher, 16 | Review, 17 | Rating, 18 | }; 19 | 20 | export default resolvers; 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "umd", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "alwaysStrict": true, 8 | "declaration": true, 9 | "rootDir": "src/", 10 | "experimentalDecorators": true, 11 | "outDir": "dist/", 12 | "lib": [ 13 | "es2017", 14 | "dom", 15 | "esnext.asynciterable" 16 | ] 17 | }, 18 | "include": [ 19 | "**/*.ts" 20 | ], 21 | "exclude": [ 22 | "node_modules" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/resolvers/Rating.ts: -------------------------------------------------------------------------------- 1 | import { RatingResolvers } from '../types/graphqlgen'; 2 | import { User, Book } from '../prisma/generated/prisma-client'; 3 | 4 | export const Rating: RatingResolvers.Type = { 5 | ...RatingResolvers.defaultResolvers, 6 | 7 | rater: async ({ id }, args, { prisma }): Promise => { 8 | const rater: User = await prisma.rating({ id }).rater(); 9 | return rater; 10 | }, 11 | book: async ({ id }, args, { prisma }): Promise => { 12 | const book: Book = await prisma.rating({ id }).book(); 13 | return book; 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/resolvers/Review.ts: -------------------------------------------------------------------------------- 1 | import { ReviewResolvers } from '../types/graphqlgen'; 2 | import { User, Book } from '../prisma/generated/prisma-client'; 3 | 4 | export const Review: ReviewResolvers.Type = { 5 | ...ReviewResolvers.defaultResolvers, 6 | 7 | reviewer: async ({ id }, args, { prisma }): Promise => { 8 | const reviewer: User = await prisma.review({ id }).reviewer(); 9 | return reviewer; 10 | }, 11 | book: async ({ id }, args, { prisma }): Promise => { 12 | const book: Book = await prisma.review({ id }).book(); 13 | return book; 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/resolvers/User.ts: -------------------------------------------------------------------------------- 1 | import { UserResolvers } from '../types/graphqlgen'; 2 | import { Book, Review } from '../prisma/generated/prisma-client'; 3 | 4 | export const User: UserResolvers.Type = { 5 | ...UserResolvers.defaultResolvers, 6 | 7 | books: async ({ id }, args, { prisma }): Promise => { 8 | const books: Book[] = await prisma.user({ id }).books(); 9 | return books; 10 | }, 11 | reviews: async ({ id }, args, { prisma }): Promise => { 12 | const reviews: Review[] = await prisma.user({ id }).reviews(); 13 | return reviews; 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/validators/PublisherValidator.ts: -------------------------------------------------------------------------------- 1 | import { Length, IsString } from 'class-validator'; 2 | 3 | interface IPublisherValidatorPayload { 4 | name: string; 5 | address: string; 6 | about: string; 7 | } 8 | 9 | export class PublisherValidator implements IPublisherValidatorPayload { 10 | @IsString() 11 | @Length(2, 50) 12 | name: string; 13 | 14 | @IsString() 15 | @Length(2, 50) 16 | address: string; 17 | 18 | @IsString() 19 | @Length(10, 250) 20 | about: string; 21 | 22 | constructor({ name, address, about }: IPublisherValidatorPayload) { 23 | this.name = name; 24 | this.about = about; 25 | this.address = address; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/validators/ReviewValidation.ts: -------------------------------------------------------------------------------- 1 | import { Length, IsOptional, IsString } from 'class-validator'; 2 | 3 | interface IReviewValidatorPayload { 4 | review: string; 5 | reviewer: string; 6 | book: string; 7 | } 8 | 9 | export class ReviewValidator implements IReviewValidatorPayload { 10 | @IsOptional() 11 | @IsString() 12 | @Length(5, 250) 13 | review: string; 14 | 15 | @IsOptional() 16 | @IsString() 17 | @Length(5, 250) 18 | reviewer: string; 19 | 20 | @IsOptional() 21 | @IsString() 22 | @Length(5, 250) 23 | book: string; 24 | 25 | constructor({ review, reviewer, book }: IReviewValidatorPayload) { 26 | this.review = review; 27 | this.reviewer = reviewer; 28 | this.book = book; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | prisma: 4 | image: prismagraphql/prisma:1.24 5 | restart: always 6 | ports: 7 | - "${PRISMA_API_PORT}:${PRISMA_API_PORT}" 8 | environment: 9 | PRISMA_CONFIG: | 10 | port: 4466 11 | # uncomment the next line and provide the env var PRISMA_MANAGEMENT_API_SECRET=my-secret to activate cluster security 12 | # managementApiSecret: my-secret 13 | databases: 14 | default: 15 | connector: postgres 16 | host: $DATABASE_HOST 17 | database: $DATABASE 18 | user: $DATABASE_USER 19 | password: $DATABASE_PASSWORD 20 | rawAccess: true 21 | port: $DATABASE_PORT 22 | migrations: true 23 | -------------------------------------------------------------------------------- /src/middlewares/permissions/index.ts: -------------------------------------------------------------------------------- 1 | import { shield } from 'graphql-shield'; 2 | import { IMiddlewareGenerator } from 'graphql-middleware'; 3 | 4 | import { isAuthenticated } from './rules'; 5 | 6 | const permissions: IMiddlewareGenerator = shield( 7 | { 8 | Query: { 9 | getPublishers: isAuthenticated, 10 | getAuthors: isAuthenticated, 11 | getBooks: isAuthenticated, 12 | getReviews: isAuthenticated, 13 | }, 14 | Mutation: { 15 | createPublisher: isAuthenticated, 16 | createAuthor: isAuthenticated, 17 | createBook: isAuthenticated, 18 | createReview: isAuthenticated, 19 | }, 20 | }, 21 | { 22 | fallbackError: new Error('You need to login to perform this operation!'), 23 | }, 24 | ); 25 | 26 | export default permissions; 27 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLServer } from 'graphql-yoga'; 2 | import * as dotenv from 'dotenv'; 3 | import { GraphQLError } from 'graphql'; 4 | 5 | import { prisma } from './prisma/generated/prisma-client/index'; 6 | import resolvers from './resolvers'; 7 | import errorFormater from './helpers/errorFormater'; 8 | import middlewares from './middlewares'; 9 | 10 | dotenv.config(); 11 | const PORT = process.env.PORT || 4000; 12 | 13 | const server = new GraphQLServer({ 14 | typeDefs: './src/schema.graphql', 15 | resolvers, 16 | context: ({ request }) => ({ 17 | request, 18 | prisma, 19 | }), 20 | middlewares, 21 | }); 22 | 23 | server.start({ 24 | port: PORT || 4000, 25 | endpoint: '/graphql', 26 | playground: '/playground', 27 | formatError: (error: GraphQLError) => errorFormater(error), 28 | }); 29 | -------------------------------------------------------------------------------- /src/validators/UserValidator.ts: -------------------------------------------------------------------------------- 1 | import { Length, IsEmail, IsOptional, IsAlphanumeric } from "class-validator"; 2 | 3 | interface IUserValidatorPayload { 4 | firstName: string; 5 | lastName: string; 6 | email: string; 7 | password: string; 8 | } 9 | 10 | export class UserValidator implements IUserValidatorPayload { 11 | @IsOptional() 12 | @Length(2, 50) 13 | firstName: string; 14 | 15 | @IsOptional() 16 | @Length(2, 50) 17 | lastName: string; 18 | 19 | @IsOptional() 20 | @IsEmail() 21 | email: string; 22 | 23 | @IsOptional() 24 | @IsAlphanumeric() 25 | @Length(8, 20) 26 | password: string; 27 | 28 | constructor({ firstName, lastName, email, password }: IUserValidatorPayload) { 29 | this.firstName = firstName; 30 | this.lastName = lastName; 31 | this.email = email; 32 | this.password = password; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/middlewares/permissions/rules.ts: -------------------------------------------------------------------------------- 1 | import { rule } from 'graphql-shield'; 2 | import { Rule } from 'graphql-shield/dist/rules'; 3 | 4 | import { decodeToken } from '../../helpers/jwtHelper'; 5 | import { IContext } from '../../types/IContext'; 6 | import { User } from '../../prisma/generated/prisma-client'; 7 | 8 | /** 9 | * @description This Rule confirms that a user is authenticated 10 | * 11 | * @param {object} parent The parent resolver object 12 | * @param {object} parent The args resolver object 13 | * @param {object} parent The context resolver object 14 | * 15 | * @returns {boolean} 16 | */ 17 | export const isAuthenticated: Rule = rule()( 18 | async (parent: any, args: any, context: IContext) => { 19 | try { 20 | const decodedToken = decodeToken(context); 21 | if (!decodedToken) return false; 22 | context.user = >decodeToken; 23 | return true; 24 | } catch (error) { 25 | return false; 26 | } 27 | }, 28 | ); 29 | -------------------------------------------------------------------------------- /src/resolvers/Book.ts: -------------------------------------------------------------------------------- 1 | import { BookResolvers } from '../types/graphqlgen'; 2 | import { 3 | Review, 4 | Publisher, 5 | User, 6 | Rating, 7 | } from '../prisma/generated/prisma-client'; 8 | 9 | export const Book: BookResolvers.Type = { 10 | ...BookResolvers.defaultResolvers, 11 | 12 | publishers: async ({ id }, args, { prisma }): Promise => { 13 | const publishers: Publisher[] = await prisma.book({ id }).publishers(); 14 | return publishers; 15 | }, 16 | authors: async ({ id }, args, { prisma }): Promise => { 17 | const authors: User[] = await prisma.book({ id }).authors(); 18 | return authors; 19 | }, 20 | ratings: async ({ id }, args, { prisma }): Promise => { 21 | const ratings: Rating[] = prisma.book({ id }).ratings(); 22 | return ratings; 23 | }, 24 | reviews: async ({ id }, args, { prisma }): Promise => { 25 | const reviews: Review[] = prisma.book({ id }).reviews(); 26 | return reviews; 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/helpers/errorFormater.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError, SourceLocation, ASTNode } from 'graphql'; 2 | 3 | import FormatedError, { IErrorState } from '../errors/FormatedError'; 4 | 5 | interface IDefaultError { 6 | state: IErrorState | undefined; 7 | message: string; 8 | locations: ReadonlyArray | undefined; 9 | path: ReadonlyArray | undefined; 10 | nodes: ReadonlyArray | undefined; 11 | stack?: string | undefined; 12 | } 13 | 14 | /** 15 | * @description Formats all errors to a uniform format 16 | * Returning a uniform error object 17 | * 18 | * @param {object} error The error object supplied by GrapgQL 19 | * 20 | * @returns {object} 21 | */ 22 | const errorFormater = (error: GraphQLError): IDefaultError => { 23 | let state; 24 | const formatedError: FormatedError = error.originalError; 25 | if (formatedError) ({ state } = formatedError); 26 | return { 27 | ...error, 28 | state, 29 | }; 30 | }; 31 | 32 | export default errorFormater; 33 | -------------------------------------------------------------------------------- /src/helpers/jwtHelper.ts: -------------------------------------------------------------------------------- 1 | import * as jwt from 'jsonwebtoken'; 2 | import { IContext } from '../types/IContext'; 3 | 4 | interface IPayload { 5 | email: string; 6 | id?: string; 7 | } 8 | 9 | const APP_SECRET = process.env.APP_SECRET; 10 | 11 | /** 12 | * @description Decodes a JWT token 13 | * Returns the payload or a false 14 | * 15 | * @param {object} context The request object in the context 16 | * 17 | * @returns {string | object | boolean} 18 | */ 19 | export const decodeToken = ({ request }: IContext): string | object | boolean => { 20 | try { 21 | const authorization = request.get('Authorization'); 22 | if (authorization) { 23 | const token = authorization.replace('Bearer ', '') 24 | return jwt.verify(token, APP_SECRET); 25 | } 26 | return false; 27 | } catch (error) { 28 | return false; 29 | } 30 | } 31 | 32 | /** 33 | * @description Signs a JWT token 34 | * 35 | * @param {object} payload The payload to sign 36 | * 37 | * @returns {string} 38 | */ 39 | export const generateToken = (payload: IPayload): string => 40 | jwt.sign(payload, APP_SECRET, { expiresIn: '72h' }); 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Chima Chukwuemeka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/types/types.ts: -------------------------------------------------------------------------------- 1 | type DateTime = string; 2 | type ID = string; 3 | 4 | export interface AuthResponse { 5 | token: string; 6 | user: Partial; 7 | } 8 | 9 | export interface User { 10 | id: ID; 11 | firstName: string; 12 | lastName: string; 13 | email: string; 14 | books: Book[]; 15 | reviews: Review[]; 16 | password: string; 17 | createdAt: DateTime; 18 | updatedAt: DateTime; 19 | } 20 | 21 | export interface Publisher { 22 | id: ID; 23 | name: string; 24 | about: string; 25 | address: string; 26 | publication: Book[]; 27 | createdAt: DateTime; 28 | updatedAt: DateTime; 29 | } 30 | 31 | export interface Book { 32 | id: ID; 33 | title: string; 34 | description: string; 35 | publishers: Publisher[]; 36 | pages: number; 37 | publishDateTime: DateTime; 38 | authors: User[]; 39 | ratings: Rating[]; 40 | isbnNo: number; 41 | createdAt: DateTime; 42 | updatedAt: DateTime; 43 | } 44 | 45 | export interface Review { 46 | id: ID; 47 | review: string; 48 | reviewer: User; 49 | book: Book; 50 | createdAt: DateTime; 51 | } 52 | 53 | export interface Rating { 54 | id: ID; 55 | rating: number; 56 | rater: User; 57 | book: Book; 58 | createdAt: DateTime; 59 | } 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | # typescript output 64 | dist 65 | -------------------------------------------------------------------------------- /src/resolvers/Query/index.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLResolveInfo } from 'graphql'; 2 | 3 | import { QueryResolvers } from '../../types/graphqlgen'; 4 | import { IContext } from '../../types/IContext'; 5 | import PublisherQuery from './PublisherQuery'; 6 | import UserQuery from './UserQuery'; 7 | import BookQuery from './BookQuery'; 8 | import ReviewQuery from './ReviewQuery'; 9 | 10 | const query: QueryResolvers.Type = { 11 | info: () => 'Welcome to my GraphQL API! 🚀 🚀', 12 | getPublishers: ( 13 | parent: undefined, 14 | args: QueryResolvers.ArgsGetPublishers, 15 | context: IContext, 16 | info: GraphQLResolveInfo, 17 | ) => PublisherQuery.getPublishers(parent, args, context, info), 18 | getAuthors: ( 19 | parent: undefined, 20 | args: any, 21 | context: IContext, 22 | info: GraphQLResolveInfo, 23 | ) => UserQuery.getAuthors(parent, args, context, info), 24 | getBooks: ( 25 | parent: undefined, 26 | args: any, 27 | context: IContext, 28 | info: GraphQLResolveInfo, 29 | ) => BookQuery.getBooks(parent, args, context, info), 30 | getReviews: ( 31 | parent: undefined, 32 | args: any, 33 | context: IContext, 34 | info: GraphQLResolveInfo, 35 | ) => ReviewQuery.getReviews(parent, args, context, info), 36 | }; 37 | 38 | export default query; 39 | -------------------------------------------------------------------------------- /src/resolvers/Query/ReviewQuery.ts: -------------------------------------------------------------------------------- 1 | import { IContext } from '../../types/IContext'; 2 | import { QueryResolvers } from '../../types/graphqlgen'; 3 | import { IReviewQuery } from '../../types/query/IReviewQuery'; 4 | import { Review } from '../../prisma/generated/prisma-client'; 5 | 6 | class ReviewQuery implements IReviewQuery { 7 | /** 8 | * @description Returns a list of reviews on the platform 9 | * Returning an ordered, filtered and paginated list of reviews 10 | * 11 | * @param {object} parent The previous GraphQL object 12 | * @param {object} args The request payload 13 | * @param {object} context The request context 14 | * 15 | * @returns {array} 16 | */ 17 | public static getReviews: QueryResolvers.GetReviewsResolver = async ( 18 | parent: undefined, 19 | { sort: reviewInput = {} }: any, 20 | { prisma }: IContext, 21 | ): Promise => { 22 | try { 23 | const { search, orderBy, offset, limit } = reviewInput; 24 | const where = { 25 | review_contains: search, 26 | }; 27 | 28 | return prisma.reviews({ 29 | where, 30 | orderBy, 31 | skip: offset, 32 | first: limit, 33 | }); 34 | } catch (err) { 35 | throw err; 36 | } 37 | }; 38 | } 39 | 40 | export default ReviewQuery; 41 | -------------------------------------------------------------------------------- /src/validators/BookValidator.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Length, 3 | IsOptional, 4 | IsArray, 5 | IsString, 6 | IsPositive, 7 | IsDateString, 8 | IsNumber, 9 | } from 'class-validator'; 10 | 11 | interface IBookValidatorPayload { 12 | title: string; 13 | description: string; 14 | publishers: string[]; 15 | pages: number; 16 | publishDateTime: string; 17 | authors: string[]; 18 | isbnNo: string; 19 | } 20 | 21 | export class BookValidator implements IBookValidatorPayload { 22 | @IsString() 23 | @Length(5, 250) 24 | title: string; 25 | 26 | @IsString() 27 | @Length(5, 250) 28 | description: string; 29 | 30 | @IsOptional() 31 | @IsArray() 32 | publishers: string[]; 33 | 34 | @IsOptional() 35 | @IsNumber() 36 | @IsPositive() 37 | pages: number; 38 | 39 | @IsDateString() 40 | publishDateTime: string; 41 | 42 | @IsArray() 43 | authors: string[]; 44 | 45 | @IsOptional() 46 | @IsString() 47 | isbnNo: string; 48 | 49 | constructor({ 50 | title, 51 | description, 52 | publishers, 53 | pages, 54 | publishDateTime, 55 | authors, 56 | isbnNo, 57 | }: IBookValidatorPayload) { 58 | this.title = title; 59 | this.description = description; 60 | this.publishers = publishers; 61 | this.pages = pages; 62 | this.publishDateTime = publishDateTime; 63 | this.authors = authors; 64 | this.isbnNo = isbnNo; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/resolvers/Query/BookQuery.ts: -------------------------------------------------------------------------------- 1 | import { Publisher, Book } from '../../prisma/generated/prisma-client'; 2 | import { IContext } from '../../types/IContext'; 3 | import { QueryResolvers } from '../../types/graphqlgen'; 4 | import { IBookQuery } from '../../types/query/IBookQuery'; 5 | 6 | class BookQuery implements IBookQuery { 7 | /** 8 | * @description Returns a list of books on the platform 9 | * Returning an ordered, filtered and paginated list of books 10 | * 11 | * @param {object} parent The previous GraphQL object 12 | * @param {object} args The request payload 13 | * @param {object} context The request context 14 | * 15 | * @returns {array} 16 | */ 17 | public static getBooks: QueryResolvers.GetBooksResolver = async ( 18 | parent: undefined, 19 | { sort: bookInput = {} }: any, 20 | { prisma }: IContext, 21 | ): Promise => { 22 | try { 23 | const { search, orderBy, offset, limit } = bookInput; 24 | const where = { 25 | OR: [ 26 | { title_contains: search }, 27 | { description_contains: search }, 28 | { isbnNo_contains: search }, 29 | ], 30 | }; 31 | 32 | return prisma.books({ 33 | where, 34 | orderBy, 35 | skip: offset, 36 | first: limit, 37 | }); 38 | } catch (err) { 39 | throw err; 40 | } 41 | }; 42 | } 43 | 44 | export default BookQuery; 45 | -------------------------------------------------------------------------------- /src/prisma/datamodel.prisma: -------------------------------------------------------------------------------- 1 | enum EnumUserRole { 2 | USER 3 | ADMIN 4 | AUTHOR 5 | } 6 | 7 | type Publisher @db(name: "publisher") { 8 | id: ID! @id(strategy: AUTO) @unique 9 | name: String! 10 | about: String 11 | address: String 12 | publication: [Book!] 13 | createdAt: DateTime! 14 | updatedAt: DateTime! 15 | } 16 | 17 | type User @db(name: "user") { 18 | id: ID! @id(strategy: AUTO) @unique 19 | firstName: String! 20 | lastName: String! 21 | type: EnumUserRole @default(value: "USER") 22 | email: String! @unique 23 | password: String 24 | books: [Book!] 25 | reviews: [Review!] 26 | ratings: [Rating!] 27 | createdAt: DateTime! 28 | updatedAt: DateTime! 29 | } 30 | 31 | type Book @db(name: "book") { 32 | id: ID! @id(strategy: AUTO) @unique 33 | title: String! 34 | description: String 35 | publishers: [Publisher!]! 36 | pages: Int 37 | publishDateTime: DateTime! 38 | authors: [User!]! 39 | ratings: [Rating!] 40 | reviews: [Review!] 41 | isbnNo: String 42 | createdAt: DateTime! 43 | updatedAt: DateTime! 44 | } 45 | 46 | type Review @db(name: "review") { 47 | id: ID! @id(strategy: AUTO) @unique 48 | review: String! 49 | reviewer: User! 50 | book: Book! 51 | createdAt: DateTime! 52 | } 53 | 54 | type Rating @db(name: "rating") { 55 | id: ID! @id(strategy: AUTO) @unique 56 | rating: Int! 57 | rater: User! 58 | book: Book! 59 | createdAt: DateTime! 60 | } 61 | -------------------------------------------------------------------------------- /src/resolvers/Query/PublisherQuery.ts: -------------------------------------------------------------------------------- 1 | import { Publisher } from '../../prisma/generated/prisma-client'; 2 | import { IContext } from '../../types/IContext'; 3 | import { QueryResolvers } from '../../types/graphqlgen'; 4 | import { IPublisherQuery } from '../../types/query/IPublisherQuery'; 5 | 6 | class PublisherQuery implements IPublisherQuery { 7 | /** 8 | * @description Returns a list of publishers on the platform 9 | * Returning an ordered, filtered and paginated list of publishers 10 | * 11 | * @param {object} parent The previous GraphQL object 12 | * @param {object} args The request payload 13 | * @param {object} context The request context 14 | * 15 | * @returns {array} 16 | */ 17 | public static getPublishers: QueryResolvers.GetPublishersResolver = async ( 18 | parent: undefined, 19 | { sort: publisherInput = {} }: any, 20 | { prisma }: IContext, 21 | ): Promise => { 22 | try { 23 | const { search, orderBy, offset, limit } = publisherInput; 24 | const where = { 25 | OR: [ 26 | { 27 | name_contains: search, 28 | }, 29 | { 30 | about_contains: search, 31 | }, 32 | ], 33 | }; 34 | return prisma.publishers({ 35 | where, 36 | orderBy, 37 | skip: offset, 38 | first: limit, 39 | }); 40 | } catch (err) { 41 | throw err; 42 | } 43 | }; 44 | } 45 | 46 | export default PublisherQuery; 47 | -------------------------------------------------------------------------------- /src/resolvers/Query/UserQuery.ts: -------------------------------------------------------------------------------- 1 | import { User } from '../../prisma/generated/prisma-client'; 2 | import { IContext } from '../../types/IContext'; 3 | import { QueryResolvers } from '../../types/graphqlgen'; 4 | import { IUserQuery } from '../../types/query/IUserQuery'; 5 | 6 | class UserQuery implements IUserQuery { 7 | /** 8 | * @description Returns a list of authors on the platform 9 | * Returning an ordered, filtered and paginated list of authors 10 | * 11 | * @param {object} parent The previous GraphQL object 12 | * @param {object} args The request payload 13 | * @param {object} context The request context 14 | * 15 | * @returns {object} 16 | */ 17 | public static getAuthors: QueryResolvers.GetAuthorsResolver = async ( 18 | parent: undefined, 19 | { sort: authorInput = {} }: any, 20 | { prisma }: IContext, 21 | ): Promise => { 22 | try { 23 | const { search, orderBy, offset, limit } = authorInput; 24 | 25 | return prisma.users({ 26 | where: { 27 | AND: [ 28 | { type: 'AUTHOR' }, 29 | { 30 | OR: [ 31 | { lastName_contains: search }, 32 | { firstName_contains: search }, 33 | { email_contains: search }, 34 | ], 35 | }, 36 | ], 37 | }, 38 | orderBy, 39 | skip: offset, 40 | first: limit, 41 | }); 42 | } catch (err) { 43 | throw err; 44 | } 45 | }; 46 | } 47 | 48 | export default UserQuery; 49 | -------------------------------------------------------------------------------- /src/@types/graphql-shield.d.ts: -------------------------------------------------------------------------------- 1 | import { Rule, LogicRule } from 'graphql-shield/dist/rules'; 2 | import { GraphQLResolveInfo } from 'graphql'; 3 | import { IRule } from 'graphql-shield'; 4 | import { ILogicRule } from 'graphql-shield/dist/types'; 5 | import { IMiddleware } from 'graphql-middleware'; 6 | 7 | // Rule 8 | declare function rule( 9 | name?: string, 10 | options?: IRuleOptions, 11 | ): (func: IRuleFunction) => Rule; 12 | 13 | type IFragment = string; 14 | type ICacheOptions = 'strict' | 'contextual' | 'no_cache' | boolean; 15 | type IRuleResult = boolean | string | Error; 16 | 17 | type IRuleFunction = ( 18 | parent?: any, 19 | args?: any, 20 | context?: any, 21 | info?: GraphQLResolveInfo, 22 | ) => IRuleResult | Promise; 23 | 24 | interface IRuleOptions { 25 | cache?: ICacheOptions; 26 | fragment?: IFragment; 27 | } 28 | 29 | // Logic 30 | declare function and(...rules: IRule[]): LogicRule; 31 | declare function or(...rules: IRule[]): LogicRule; 32 | declare function not(rule: IRule): LogicRule; 33 | declare const allow: LogicRule; 34 | declare const deny: LogicRule; 35 | 36 | type ShieldRule = IRule | ILogicRule; 37 | 38 | interface IRuleFieldMap { 39 | [key: string]: IRule; 40 | } 41 | 42 | interface IRuleTypeMap { 43 | [key: string]: IRule | IRuleFieldMap; 44 | } 45 | 46 | type IRules = ShieldRule | IRuleTypeMap; 47 | 48 | declare function shield(rules?: IRules, options?: IOptions): IMiddleware; 49 | 50 | interface IOptions { 51 | debug?: boolean; 52 | allowExternalErrors?: boolean; 53 | fallbackRule?: ShieldRule; 54 | fallbackError?: string | Error; 55 | } 56 | -------------------------------------------------------------------------------- /src/validators/index.ts: -------------------------------------------------------------------------------- 1 | import { validate } from 'class-validator'; 2 | 3 | interface IPayload { 4 | [property: string]: any; 5 | } 6 | 7 | export interface IValidationErrors { 8 | [property: string]: string[]; 9 | } 10 | 11 | export const validationMessage: string = 'Some fields are failing validation'; 12 | 13 | /** 14 | * @description Validates objects with key value pairs 15 | * And returns a false or errors object depending on the state 16 | * 17 | * @param {object} Validator The validator schema to be used 18 | * @param {object} payload The object to be validated 19 | * @param {string} action The type of validation to be performed 20 | * 21 | * @returns {boolean | object} 22 | */ 23 | const validateRequest = async ( 24 | Validator: any, 25 | payload: IPayload, 26 | action?: string, 27 | ): Promise => { 28 | let resource = new Validator(payload); 29 | let validationErrors = {}; 30 | 31 | Object.entries(payload).forEach(([key, value]) => { 32 | resource[key] = 33 | typeof value === 'string' ? value.replace(/ +/g, '').trim() : value; 34 | }); 35 | 36 | const errors = await validate(resource, { 37 | validationError: { target: false }, 38 | skipMissingProperties: action === 'update' ? true : false, 39 | }); 40 | 41 | if (errors.length === 0) { 42 | return false; 43 | } 44 | 45 | for (let error of errors) { 46 | validationErrors = { 47 | ...validationErrors, 48 | [error.property]: Object.entries(error.constraints).map( 49 | ([, value]) => value, 50 | ), 51 | }; 52 | } 53 | 54 | return validationErrors; 55 | }; 56 | 57 | export default validateRequest; 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GraphQL-API", 3 | "version": "1.0.0", 4 | "description": "A Basic GraphQL API for Books.", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "prestart": "npm run build", 9 | "start": "node dist/index.js", 10 | "dev": "nodemon --exec ts-node -- src/index.ts", 11 | "docker": "docker-compose up -d", 12 | "prisma": "prisma deploy", 13 | "generate:type": "graphqlgen", 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/chukwuemekachm/GraphQL-API.git" 19 | }, 20 | "keywords": [], 21 | "author": "", 22 | "license": "ISC", 23 | "bugs": { 24 | "url": "https://github.com/chukwuemekachm/GraphQL-API/issues" 25 | }, 26 | "homepage": "https://github.com/chukwuemekachm/GraphQL-API#readme", 27 | "husky": { 28 | "hooks": { 29 | "pre-commit": "lint-staged" 30 | } 31 | }, 32 | "lint-staged": { 33 | "*.ts": [ 34 | "prettier --write", 35 | "git add" 36 | ] 37 | }, 38 | "dependencies": { 39 | "@types/aws-lambda": "^8.10.17", 40 | "@types/bcryptjs": "^2.4.2", 41 | "@types/dotenv": "^6.1.0", 42 | "@types/jsonwebtoken": "^8.3.0", 43 | "@types/ws": "^6.0.1", 44 | "bcryptjs": "^2.4.3", 45 | "class-validator": "^0.9.1", 46 | "dotenv": "^6.2.0", 47 | "graphql-shield": "^5.1.0", 48 | "graphql-yoga": "^1.16.9", 49 | "jsonwebtoken": "^8.4.0", 50 | "merge-graphql-schemas": "^1.5.8", 51 | "prisma-client-lib": "^1.24.0", 52 | "typescript": "^3.2.2" 53 | }, 54 | "devDependencies": { 55 | "husky": "^1.3.1", 56 | "lint-staged": "^8.1.0", 57 | "nodemon": "^1.18.9", 58 | "prettier": "1.15.3", 59 | "ts-node": "^7.0.1" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/resolvers/Mutation/index.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLResolveInfo } from 'graphql'; 2 | 3 | import AuthMutation from './AuthMutation'; 4 | import { IContext } from '../../types/IContext'; 5 | import { MutationResolvers } from '../../types/graphqlgen'; 6 | import PublisherMutation from './PublisherMutation'; 7 | import UserMutation from './UserMutation'; 8 | import BookMutation from './BookMutation'; 9 | import ReviewMutation from './ReviewMutation'; 10 | 11 | const mutation: MutationResolvers.Type = { 12 | signup: ( 13 | parent: undefined, 14 | args: MutationResolvers.ArgsSignup, 15 | context: IContext, 16 | info: GraphQLResolveInfo, 17 | ) => AuthMutation.signup(parent, args, context, info), 18 | login: ( 19 | parent: undefined, 20 | args: MutationResolvers.ArgsLogin, 21 | context: IContext, 22 | info: GraphQLResolveInfo, 23 | ) => AuthMutation.login(parent, args, context, info), 24 | createPublisher: ( 25 | parent: undefined, 26 | args: MutationResolvers.ArgsCreatePublisher, 27 | context: IContext, 28 | info: GraphQLResolveInfo, 29 | ) => PublisherMutation.createPublisher(parent, args, context, info), 30 | createAuthor: ( 31 | parent: undefined, 32 | args: MutationResolvers.ArgsCreateAuthor, 33 | context: IContext, 34 | info: GraphQLResolveInfo, 35 | ) => UserMutation.createAuthor(parent, args, context, info), 36 | createBook: ( 37 | parent: undefined, 38 | args: MutationResolvers.ArgsCreateBook, 39 | context: IContext, 40 | info: GraphQLResolveInfo, 41 | ) => BookMutation.createBook(parent, args, context, info), 42 | createReview: ( 43 | parent: undefined, 44 | args: MutationResolvers.ArgsCreateReview, 45 | context: IContext, 46 | info: GraphQLResolveInfo, 47 | ) => ReviewMutation.createReview(parent, args, context, info), 48 | }; 49 | 50 | export default mutation; 51 | -------------------------------------------------------------------------------- /src/resolvers/Mutation/UserMutation.ts: -------------------------------------------------------------------------------- 1 | import { IUserMutation } from '../../types/mutation/IUserMutation'; 2 | import { MutationResolvers } from '../../types/graphqlgen'; 3 | import { IContext } from '../../types/IContext'; 4 | import { User } from '../../prisma/generated/prisma-client'; 5 | import validateRequest, { 6 | IValidationErrors, 7 | validationMessage, 8 | } from '../../validators'; 9 | import { UserValidator } from '../../validators/UserValidator'; 10 | import FormatedError from '../../errors/FormatedError'; 11 | 12 | class UserMutation implements IUserMutation { 13 | /** 14 | * @description Creates a new author on the platform 15 | * Returning the newly created author 16 | * 17 | * @param {object} parent The previous GraphQL object 18 | * @param {object} args The request payload 19 | * @param {object} context The request context 20 | * 21 | * @returns {object} 22 | */ 23 | public static createAuthor: MutationResolvers.CreateAuthorResolver = async ( 24 | parent: undefined, 25 | { user: authorInput }: any, 26 | { prisma }: IContext, 27 | ): Promise => { 28 | try { 29 | const { firstName, lastName, email } = authorInput; 30 | const errors: IValidationErrors | boolean = await validateRequest( 31 | UserValidator, 32 | authorInput, 33 | ); 34 | if (errors) { 35 | throw new FormatedError(validationMessage, errors); 36 | } 37 | 38 | const user = await prisma.user({ email }); 39 | if (!user) { 40 | const newUser: User = await prisma.createUser({ 41 | email, 42 | firstName, 43 | lastName, 44 | type: 'AUTHOR', 45 | }); 46 | return newUser; 47 | } 48 | 49 | throw new FormatedError('User with email exists', { 50 | email: [`A user with your email: ${email} already exists`], 51 | }); 52 | } catch (err) { 53 | throw err; 54 | } 55 | }; 56 | } 57 | 58 | export default UserMutation; 59 | -------------------------------------------------------------------------------- /src/resolvers/Mutation/PublisherMutation.ts: -------------------------------------------------------------------------------- 1 | import { IContext } from '../../types/IContext'; 2 | import FormatedError from '../../errors/FormatedError'; 3 | import { PublisherValidator } from '../../validators/PublisherValidator'; 4 | import validateRequest, { 5 | IValidationErrors, 6 | validationMessage, 7 | } from '../../validators'; 8 | import { Publisher } from '../../prisma/generated/prisma-client'; 9 | import { MutationResolvers } from '../../types/graphqlgen'; 10 | import { IPublisherMutation } from '../../types/mutation/IPublisherMutation'; 11 | 12 | class PublisherMutation implements IPublisherMutation { 13 | /** 14 | * @description Creates a new publisher on the platform 15 | * Returning the newly created publisher 16 | * 17 | * @param {object} parent The previous GraphQL object 18 | * @param {object} args The request payload 19 | * @param {object} context The request context 20 | * 21 | * @returns {object} 22 | */ 23 | public static createPublisher: MutationResolvers.CreatePublisherResolver = async ( 24 | parent: undefined, 25 | { publisher: publisherInput }: any, 26 | { prisma }: IContext, 27 | ): Promise => { 28 | try { 29 | const { name, about, address } = publisherInput; 30 | const errors: IValidationErrors | boolean = await validateRequest( 31 | PublisherValidator, 32 | publisherInput, 33 | ); 34 | if (errors) { 35 | throw new FormatedError(validationMessage, errors); 36 | } 37 | 38 | const publisher = await prisma.$exists.publisher({ 39 | OR: [{ name_contains: name }, { about_contains: about }], 40 | }); 41 | if (!publisher) { 42 | const newPublisher = await prisma.createPublisher({ 43 | name, 44 | about, 45 | address, 46 | }); 47 | return newPublisher; 48 | } 49 | 50 | throw new FormatedError('Publisher with similar information exist', { 51 | name: ['A publisher with similar name exists'], 52 | about: ['A publisher with similar details exists'], 53 | }); 54 | } catch (err) { 55 | throw err; 56 | } 57 | }; 58 | } 59 | 60 | export default PublisherMutation; 61 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { Prisma } from './prisma/generated/prisma-client/index'; 2 | 3 | /** 4 | * @description Checks to see if all the user ids provided exist 5 | * Returns an array of non existing ids with a message 6 | * 7 | * @param {array} authors The array of author ids to be validated 8 | * @param {object} prisma The prisma object instance 9 | * 10 | * @returns {array | boolean} 11 | */ 12 | export const checkAuthors = async (authors: string[], prisma: Prisma) => { 13 | try { 14 | const result: string[] = []; 15 | await Promise.all( 16 | authors.map(async (authorId: string) => { 17 | const author = await prisma.$exists.user({ 18 | id: authorId, 19 | type: 'AUTHOR', 20 | }); 21 | if (!author) result.push(`Author with id: ${authorId} does not exist`); 22 | }), 23 | ); 24 | if (result[0]) return result; 25 | return false; 26 | } catch (err) { 27 | throw err; 28 | } 29 | }; 30 | 31 | /** 32 | * @description Checks to see if all the publisher ids provided exist 33 | * Returns an array of non existing ids with a message 34 | * 35 | * @param {array} publishers The array of publisher ids to be validated 36 | * @param {object} prisma The prisma object instance 37 | * 38 | * @returns {array | boolean} 39 | */ 40 | export const checkPublishers = async (publishers: string[], prisma: Prisma) => { 41 | try { 42 | const result: string[] = []; 43 | await Promise.all( 44 | publishers.map(async (publishersId: string) => { 45 | const author = await prisma.$exists.publisher({ id: publishersId }); 46 | if (!author) 47 | result.push(`Publisher with id: ${publishersId} does not exist`); 48 | }), 49 | ); 50 | if (result[0]) return result; 51 | return false; 52 | } catch (err) { 53 | throw err; 54 | } 55 | }; 56 | 57 | /** 58 | * @description Capitalizes the first letter of a string 59 | * Returning the capitalized string 60 | * 61 | * @param {string} word The string to be capitalized 62 | * 63 | * @returns {string} 64 | */ 65 | export const capitalize = (word: string): string => { 66 | if (!word[1]) return word.toUpperCase(); 67 | return `${word[0].toUpperCase()}${word.substring(1)}`; 68 | }; 69 | -------------------------------------------------------------------------------- /src/resolvers/Mutation/ReviewMutation.ts: -------------------------------------------------------------------------------- 1 | import { MutationResolvers } from '../../types/graphqlgen'; 2 | import { IContext } from '../../types/IContext'; 3 | import validateRequest, { 4 | IValidationErrors, 5 | validationMessage, 6 | } from '../../validators'; 7 | import FormatedError from '../../errors/FormatedError'; 8 | import { Review } from '../../prisma/generated/prisma-client'; 9 | import { IReviewMutation } from '../../types/mutation/IReviewMutation'; 10 | import { ReviewValidator } from '../../validators/ReviewValidation'; 11 | 12 | class ReviewMutation implements IReviewMutation { 13 | /** 14 | * @description Creates a new book review on the platform 15 | * Returning the newly created review and it's relations 16 | * 17 | * @param {object} parent The previous GraphQL object 18 | * @param {object} args The request payload 19 | * @param {object} context The request context 20 | * 21 | * @returns {object} 22 | */ 23 | public static createReview: MutationResolvers.CreateReviewResolver = async ( 24 | parent: undefined, 25 | { review: reviewInput }: any, 26 | { prisma }: IContext, 27 | ): Promise => { 28 | try { 29 | const { review, reviewer, book } = reviewInput; 30 | const errors: IValidationErrors | boolean = await validateRequest( 31 | ReviewValidator, 32 | reviewInput, 33 | ); 34 | if (errors) { 35 | throw new FormatedError(validationMessage, errors); 36 | } 37 | 38 | const userExists = await prisma.$exists.user({ id: reviewer }); 39 | const bookExists = await prisma.$exists.book({ id: book }); 40 | if (!userExists) { 41 | throw new FormatedError(`User with id: ${reviewer} does not exist`, { 42 | reviewer: [`User with id: ${reviewer} does not exist`], 43 | }); 44 | } 45 | if (!bookExists) { 46 | throw new FormatedError(`Book with id: ${book} does not exist`, { 47 | book: [`Book with id: ${book} does not exist`], 48 | }); 49 | } 50 | 51 | return prisma.createReview({ 52 | review, 53 | reviewer: { connect: { id: reviewer } }, 54 | book: { connect: { id: book } }, 55 | }); 56 | } catch (err) { 57 | throw err; 58 | } 59 | }; 60 | } 61 | 62 | export default ReviewMutation; 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GraphQL-API 2 | ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=popout-square&logo=graphql&logoColor=violet) 3 | 4 | This service is a work in progress Book API built to enable the author to exploit GraphQL. 5 | 6 | ## Getting Started 7 | To setup **GraphQL-API**, the following should be installed on your machine. 8 | 9 | ### Prerequisites 10 | 11 | - [Node.js](https://nodejs.org/en/download/current/) 6 and above 12 | - [Postgres](https://www.postgresql.org/download/) Database or create an Online [Elephant sql](https://www.elephantsql.com/) database 13 | - [Git](https://git-scm.com/downloads) 14 | - [Docker](https://www.docker.com/products/docker-desktop) 15 | 16 | If you don't have these already, click on any of them to install it on your local machine. 17 | 18 | ### Installing 19 | 20 | If you have all the prerequisites you can use the steps below to setup a local copy. 21 | 22 | - **Install Prisma** 23 | ``` 24 | $ npm install -g prisma 25 | ``` 26 | 27 | - **Clone the repository** 28 | ``` 29 | $ git clone https://github.com/chukwuemekachm/GraphQL-API.git 30 | ``` 31 | 32 | - **Set up Docker & Prisma** 33 | Now let's navigate into our project directory and create the `.env` file 34 | ``` 35 | touch .env 36 | cp .env.example .env 37 | ``` 38 | 39 | Update with `.env` file with the appropriate credentials replacing the placeholders. 40 | 41 | Update the `prisma.yml` file with the port you have chosen for your prima service in this format `http://:`. 42 | 43 | 44 | Next, we will compose our docker container and deploy our prisma service to the container 45 | ``` 46 | docker-compose up -d 47 | prisma deploy 48 | ``` 49 | 50 | You should see a message something similar to this, depending on your env variables 51 | ``` 52 | Your Prisma GraphQL database endpoint is live: 53 | 54 | HTTP: http://: 55 | WS: ws://: 56 | 57 | 58 | post-deploy: 59 | Generating schema... 44ms 60 | ``` 61 | 62 | Update your `.env` file with the Prisma API endpoint 63 | Now run this to start your server 64 | ``` 65 | $ npm run dev 66 | ``` 67 | 68 | ## Built With 69 | 70 | - [graphql-yoga](https://github.com/prisma/graphql-yoga) 71 | - [prisma](https://www.prisma.io/) 72 | - [graphql-shield](https://github.com/maticzav/graphql-shield) 73 | - [class-validator](https://github.com/typestack/class-validator) 74 | - [prettier](https://prettier.io/) 75 | 76 | ## Author 77 | 78 | * **Chima Chukwuemeka** [@chukwuemekachm](https://github.com/chukwuemeka) 79 | 80 | 81 | ## License 82 | 83 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details 84 | -------------------------------------------------------------------------------- /src/resolvers/Mutation/BookMutation.ts: -------------------------------------------------------------------------------- 1 | import { MutationResolvers } from '../../types/graphqlgen'; 2 | import { IContext } from '../../types/IContext'; 3 | import validateRequest, { 4 | IValidationErrors, 5 | validationMessage, 6 | } from '../../validators'; 7 | import FormatedError from '../../errors/FormatedError'; 8 | import { BookValidator } from '../../validators/BookValidator'; 9 | import { Book } from '../../prisma/generated/prisma-client'; 10 | import { checkAuthors, checkPublishers } from '../../utils'; 11 | import { IBookMutation } from '../../types/mutation/IBookMutation'; 12 | 13 | class BookMutation implements IBookMutation { 14 | /** 15 | * @description Creates a new book on the platform 16 | * Returning the newly created book 17 | * 18 | * @param {object} parent The previous GraphQL object 19 | * @param {object} args The request payload 20 | * @param {object} context The request context 21 | * 22 | * @returns {object} 23 | */ 24 | public static createBook: MutationResolvers.CreateBookResolver = async ( 25 | parent: undefined, 26 | { book: bookInput }: any, 27 | { prisma }: IContext, 28 | ): Promise => { 29 | try { 30 | const { 31 | title, 32 | description, 33 | isbnNo, 34 | publishers, 35 | pages, 36 | publishDateTime, 37 | authors, 38 | } = bookInput; 39 | const errors: IValidationErrors | boolean = await validateRequest( 40 | BookValidator, 41 | bookInput, 42 | ); 43 | if (errors) { 44 | throw new FormatedError(validationMessage, errors); 45 | } 46 | 47 | const authorsExist = await checkAuthors(authors, prisma); 48 | if (authorsExist) { 49 | throw new FormatedError("Author(s) don't exist", { 50 | authors: authorsExist, 51 | }); 52 | } 53 | const publishersExist = await checkPublishers(publishers, prisma); 54 | if (publishersExist) { 55 | throw new FormatedError("Publishers(s) don't exist", { 56 | publishers: publishersExist, 57 | }); 58 | } 59 | 60 | const book: boolean = await prisma.$exists.book({ 61 | OR: [{ title }, { description }, { isbnNo }], 62 | }); 63 | if (!book) { 64 | return prisma.createBook({ 65 | title, 66 | description, 67 | isbnNo, 68 | pages, 69 | publishDateTime, 70 | authors: { 71 | connect: authors.map((author: string) => ({ id: author })), 72 | }, 73 | publishers: { 74 | connect: publishers.map((publisher: string) => ({ id: publisher })), 75 | }, 76 | }); 77 | } 78 | 79 | throw new FormatedError('Book with similar information exist', { 80 | title: ['A book with similar name exists'], 81 | description: ['A book with similar details exists'], 82 | isbnNo: ['A book with similar details exists'], 83 | }); 84 | } catch (err) { 85 | throw err; 86 | } 87 | }; 88 | } 89 | 90 | export default BookMutation; 91 | -------------------------------------------------------------------------------- /src/resolvers/Mutation/AuthMutation.ts: -------------------------------------------------------------------------------- 1 | import * as bcrypt from 'bcryptjs'; 2 | 3 | import { IAuthMutation } from '../../types/mutation/IAuthMutation'; 4 | import { IContext } from '../../types/IContext'; 5 | import { generateToken } from '../../helpers/jwtHelper'; 6 | import validateRequest, { 7 | validationMessage, 8 | IValidationErrors, 9 | } from '../../validators'; 10 | import { UserValidator } from '../../validators/UserValidator'; 11 | import FormatedError from '../../errors/FormatedError'; 12 | import { AuthResponse, User } from '../../types/types'; 13 | import { MutationResolvers } from '../../types/graphqlgen'; 14 | 15 | class AuthMutation implements IAuthMutation { 16 | /** 17 | * @description Signs up a user to the platform 18 | * Returning the user's token and profile 19 | * 20 | * @param {object} parent The previous GraphQL object 21 | * @param {object} args The request payload 22 | * @param {object} context The request context 23 | * 24 | * @returns {object} 25 | */ 26 | public static signup: MutationResolvers.SignupResolver = async ( 27 | parent: undefined, 28 | { user: userInput }: any, 29 | { prisma }: IContext, 30 | ): Promise => { 31 | try { 32 | const { firstName, lastName, email, password } = userInput; 33 | const errors: IValidationErrors | boolean = await validateRequest( 34 | UserValidator, 35 | userInput, 36 | ); 37 | if (errors) { 38 | throw new FormatedError(validationMessage, errors); 39 | } 40 | 41 | const user = await prisma.user({ email }); 42 | if (!user) { 43 | const passwordHash: string = await bcrypt.hash(password, 10); 44 | const newUser: Partial = await prisma.createUser({ 45 | email, 46 | password: passwordHash, 47 | firstName, 48 | lastName, 49 | }); 50 | const token = generateToken({ email, id: newUser.id }); 51 | 52 | return { 53 | token, 54 | user: newUser, 55 | }; 56 | } 57 | throw new FormatedError('User with email exists', { 58 | email: [`A user with your email: ${email} already exists`], 59 | }); 60 | } catch (err) { 61 | throw err; 62 | } 63 | }; 64 | 65 | /** 66 | * @description Login's in a user on the platform 67 | * Returning the user's token and profile 68 | * 69 | * @param {object} parent The previous GraphQL object 70 | * @param {object} args The request payload 71 | * @param {object} context The request context 72 | * 73 | * @returns {object} 74 | */ 75 | public static login: MutationResolvers.LoginResolver = async ( 76 | parent: undefined, 77 | { user: userInput }: any, 78 | { prisma }: IContext, 79 | ): Promise => { 80 | try { 81 | const { email, password } = userInput; 82 | const user: Partial = await prisma.user({ email }); 83 | if (!user) { 84 | throw new FormatedError('Invaild credentials', { 85 | email: ['Invalid email or password'], 86 | password: ['Invalid email or password'], 87 | }); 88 | } 89 | 90 | const valid = await bcrypt.compare(password, user.password); 91 | if (!valid) { 92 | throw new FormatedError('Invaild credentials', { 93 | email: ['Invalid email or password'], 94 | password: ['Invalid email or password'], 95 | }); 96 | } 97 | const token = generateToken({ email, id: user.id }); 98 | 99 | return { 100 | token, 101 | user: user, 102 | }; 103 | } catch (err) { 104 | throw err; 105 | } 106 | }; 107 | } 108 | 109 | export default AuthMutation; 110 | -------------------------------------------------------------------------------- /src/schema.graphql: -------------------------------------------------------------------------------- 1 | scalar DateTime 2 | 3 | type Query { 4 | info: String! 5 | getPublishers(sort: PublisherSearchPaginationOrderInput): [Publisher!]! 6 | getAuthors(sort: UserSearchPaginationOrderInput): [User!]! 7 | getBooks(sort: BookSearchPaginationOrderInput): [Book!]! 8 | getReviews(sort: ReviewSearchPaginationOrderInput): [Review!]! 9 | } 10 | 11 | type Mutation { 12 | signup(user: SignupInput): AuthResponse! 13 | login(user: LoginInput): AuthResponse! 14 | createPublisher(publisher: PublisherInput): Publisher! 15 | createAuthor(user: AuthorInput!): User! 16 | createBook(book: BookInput!): Book! 17 | createReview(review: ReviewInput!): Review! 18 | } 19 | 20 | type AuthResponse { 21 | token: String! 22 | user: User! 23 | } 24 | 25 | input SignupInput { 26 | firstName: String! 27 | lastName: String! 28 | email: String! 29 | password: String! 30 | } 31 | 32 | input LoginInput { 33 | email: String! 34 | password: String! 35 | } 36 | 37 | input PublisherInput { 38 | name: String! 39 | about: String! 40 | address: String! 41 | } 42 | 43 | input AuthorInput { 44 | firstName: String! 45 | lastName: String! 46 | email: String! 47 | } 48 | 49 | input BookInput { 50 | title: String! 51 | description: String! 52 | publishers: [String!]! 53 | pages: Int 54 | publishDateTime: DateTime! 55 | authors: [String!]! 56 | isbnNo: String 57 | } 58 | 59 | input ReviewInput { 60 | review: String! 61 | reviewer: String! 62 | book: String! 63 | } 64 | 65 | input PublisherSearchPaginationOrderInput { 66 | search: String 67 | orderBy: PublisherOrderBy 68 | offset: Int 69 | limit: Int 70 | } 71 | 72 | input UserSearchPaginationOrderInput { 73 | search: String 74 | orderBy: UserOrderBy 75 | offset: Int 76 | limit: Int 77 | } 78 | 79 | input BookSearchPaginationOrderInput { 80 | search: String 81 | orderBy: BookOrderBy 82 | offset: Int 83 | limit: Int 84 | } 85 | 86 | input ReviewSearchPaginationOrderInput { 87 | search: String 88 | orderBy: ReviewOrderBy 89 | offset: Int 90 | limit: Int 91 | } 92 | 93 | enum PublisherOrderBy { 94 | name_ASC 95 | name_DESC 96 | about_ASC 97 | about_DESC 98 | createdAt_ASC 99 | createdAt_DESC 100 | } 101 | 102 | enum UserOrderBy { 103 | lastName_ASC 104 | lastName_DESC 105 | firstName_ASC 106 | firstName_DESC 107 | email_ASC 108 | email_DESC 109 | id_ASC 110 | id_DESC 111 | createdAt_ASC 112 | createdAt_DESC 113 | } 114 | 115 | enum BookOrderBy { 116 | title_ASC 117 | title_DESC 118 | description_ASC 119 | description_DESC 120 | isbnNo_ASC 121 | isbnNo_DESC 122 | createdAt_ASC 123 | createdAt_DESC 124 | } 125 | 126 | enum ReviewOrderBy { 127 | review_ASC 128 | review_DESC 129 | createdAt_ASC 130 | createdAt_DESC 131 | } 132 | 133 | type Publisher { 134 | id: ID! 135 | name: String! 136 | about: String 137 | address: String 138 | publication: [Book!] 139 | createdAt: DateTime! 140 | updatedAt: DateTime! 141 | } 142 | 143 | type User { 144 | id: ID! 145 | firstName: String! 146 | lastName: String! 147 | email: String! 148 | books: [Book!] 149 | reviews: [Review!] 150 | createdAt: DateTime! 151 | updatedAt: DateTime! 152 | } 153 | 154 | type Book { 155 | id: ID! 156 | title: String! 157 | description: String 158 | publishers: [Publisher!]! 159 | pages: Int 160 | publishDateTime: DateTime! 161 | authors: [User!]! 162 | ratings: [Rating!] 163 | reviews: [Review!]! 164 | isbnNo: String 165 | createdAt: DateTime! 166 | updatedAt: DateTime! 167 | } 168 | 169 | type Review { 170 | id: ID! 171 | review: String! 172 | reviewer: User! 173 | book: Book! 174 | createdAt: DateTime! 175 | } 176 | 177 | type Rating { 178 | id: ID! 179 | rating: Int! 180 | rater: User! 181 | book: Book! 182 | createdAt: DateTime! 183 | } 184 | -------------------------------------------------------------------------------- /src/types/graphqlgen.ts: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/prisma/graphqlgen, DO NOT EDIT. 2 | 3 | import { GraphQLResolveInfo } from 'graphql'; 4 | import { 5 | Publisher, 6 | Book, 7 | User, 8 | Review, 9 | Rating, 10 | } from '../prisma/generated/prisma-client'; 11 | import { AuthResponse } from './types'; 12 | import { IContext } from './IContext'; 13 | 14 | export type PublisherOrderBy = 15 | | 'name_ASC' 16 | | 'name_DESC' 17 | | 'about_ASC' 18 | | 'about_DESC' 19 | | 'createdAt_ASC' 20 | | 'createdAt_DESC'; 21 | export type UserOrderBy = 22 | | 'lastName_ASC' 23 | | 'lastName_DESC' 24 | | 'firstName_ASC' 25 | | 'firstName_DESC' 26 | | 'email_ASC' 27 | | 'email_DESC' 28 | | 'id_ASC' 29 | | 'id_DESC' 30 | | 'createdAt_ASC' 31 | | 'createdAt_DESC'; 32 | export type BookOrderBy = 33 | | 'title_ASC' 34 | | 'title_DESC' 35 | | 'description_ASC' 36 | | 'description_DESC' 37 | | 'isbnNo_ASC' 38 | | 'isbnNo_DESC' 39 | | 'createdAt_ASC' 40 | | 'createdAt_DESC'; 41 | export type ReviewOrderBy = 42 | | 'review_ASC' 43 | | 'review_DESC' 44 | | 'createdAt_ASC' 45 | | 'createdAt_DESC'; 46 | 47 | export namespace QueryResolvers { 48 | export const defaultResolvers = {}; 49 | 50 | export interface PublisherSearchPaginationOrderInput { 51 | search?: string | null; 52 | orderBy?: PublisherOrderBy | null; 53 | offset?: number | null; 54 | limit?: number | null; 55 | } 56 | export interface UserSearchPaginationOrderInput { 57 | search?: string | null; 58 | orderBy?: UserOrderBy | null; 59 | offset?: number | null; 60 | limit?: number | null; 61 | } 62 | export interface BookSearchPaginationOrderInput { 63 | search?: string | null; 64 | orderBy?: BookOrderBy | null; 65 | offset?: number | null; 66 | limit?: number | null; 67 | } 68 | 69 | export interface ArgsGetPublishers { 70 | sort?: PublisherSearchPaginationOrderInput | null; 71 | } 72 | 73 | export interface ArgsGetAuthors { 74 | sort?: UserSearchPaginationOrderInput | null; 75 | } 76 | 77 | export interface ArgsGetBooks { 78 | sort?: BookSearchPaginationOrderInput | null; 79 | } 80 | 81 | export interface ArgsGetReviews { 82 | sort?: ReviewOrderBy | null; 83 | } 84 | 85 | export type InfoResolver = ( 86 | parent: undefined, 87 | args: {}, 88 | ctx: IContext, 89 | info: GraphQLResolveInfo, 90 | ) => string | Promise; 91 | 92 | export type GetPublishersResolver = ( 93 | parent: undefined, 94 | args: ArgsGetPublishers, 95 | ctx: IContext, 96 | info: GraphQLResolveInfo, 97 | ) => Publisher[] | Promise; 98 | 99 | export type GetAuthorsResolver = ( 100 | parent: undefined, 101 | args: ArgsGetAuthors, 102 | ctx: IContext, 103 | info: GraphQLResolveInfo, 104 | ) => User[] | Promise; 105 | 106 | export type GetBooksResolver = ( 107 | parent: undefined, 108 | args: ArgsGetBooks, 109 | ctx: IContext, 110 | info: GraphQLResolveInfo, 111 | ) => Book[] | Promise; 112 | 113 | export type GetReviewsResolver = ( 114 | parent: undefined, 115 | args: ArgsGetReviews, 116 | ctx: IContext, 117 | info: GraphQLResolveInfo, 118 | ) => Review[] | Promise; 119 | 120 | export interface Type { 121 | info: ( 122 | parent: undefined, 123 | args: {}, 124 | ctx: IContext, 125 | info: GraphQLResolveInfo, 126 | ) => string | Promise; 127 | 128 | getPublishers: ( 129 | parent: undefined, 130 | args: ArgsGetPublishers, 131 | ctx: IContext, 132 | info: GraphQLResolveInfo, 133 | ) => Publisher[] | Promise; 134 | 135 | getAuthors: ( 136 | parent: undefined, 137 | args: ArgsGetAuthors, 138 | ctx: IContext, 139 | info: GraphQLResolveInfo, 140 | ) => User[] | Promise; 141 | 142 | getBooks: ( 143 | parent: undefined, 144 | args: ArgsGetBooks, 145 | ctx: IContext, 146 | info: GraphQLResolveInfo, 147 | ) => Book[] | Promise; 148 | 149 | getReviews: ( 150 | parent: undefined, 151 | args: ArgsGetReviews, 152 | ctx: IContext, 153 | info: GraphQLResolveInfo, 154 | ) => Review[] | Promise; 155 | } 156 | } 157 | 158 | export namespace PublisherResolvers { 159 | export const defaultResolvers = { 160 | id: (parent: Publisher) => parent.id, 161 | name: (parent: Publisher) => parent.name, 162 | about: (parent: Publisher) => 163 | parent.about === undefined ? null : parent.about, 164 | address: (parent: Publisher) => 165 | parent.address === undefined ? null : parent.address, 166 | createdAt: (parent: Publisher) => parent.createdAt, 167 | updatedAt: (parent: Publisher) => parent.updatedAt, 168 | }; 169 | 170 | export type IdResolver = ( 171 | parent: Publisher, 172 | args: {}, 173 | ctx: IContext, 174 | info: GraphQLResolveInfo, 175 | ) => string | Promise; 176 | 177 | export type NameResolver = ( 178 | parent: Publisher, 179 | args: {}, 180 | ctx: IContext, 181 | info: GraphQLResolveInfo, 182 | ) => string | Promise; 183 | 184 | export type AboutResolver = ( 185 | parent: Publisher, 186 | args: {}, 187 | ctx: IContext, 188 | info: GraphQLResolveInfo, 189 | ) => string | null | Promise; 190 | 191 | export type AddressResolver = ( 192 | parent: Publisher, 193 | args: {}, 194 | ctx: IContext, 195 | info: GraphQLResolveInfo, 196 | ) => string | null | Promise; 197 | 198 | export type PublicationResolver = ( 199 | parent: Publisher, 200 | args: {}, 201 | ctx: IContext, 202 | info: GraphQLResolveInfo, 203 | ) => Book[] | null | Promise; 204 | 205 | export type CreatedAtResolver = ( 206 | parent: Publisher, 207 | args: {}, 208 | ctx: IContext, 209 | info: GraphQLResolveInfo, 210 | ) => string | Promise; 211 | 212 | export type UpdatedAtResolver = ( 213 | parent: Publisher, 214 | args: {}, 215 | ctx: IContext, 216 | info: GraphQLResolveInfo, 217 | ) => string | Promise; 218 | 219 | export interface Type { 220 | id: ( 221 | parent: Publisher, 222 | args: {}, 223 | ctx: IContext, 224 | info: GraphQLResolveInfo, 225 | ) => string | Promise; 226 | 227 | name: ( 228 | parent: Publisher, 229 | args: {}, 230 | ctx: IContext, 231 | info: GraphQLResolveInfo, 232 | ) => string | Promise; 233 | 234 | about: ( 235 | parent: Publisher, 236 | args: {}, 237 | ctx: IContext, 238 | info: GraphQLResolveInfo, 239 | ) => string | null | Promise; 240 | 241 | address: ( 242 | parent: Publisher, 243 | args: {}, 244 | ctx: IContext, 245 | info: GraphQLResolveInfo, 246 | ) => string | null | Promise; 247 | 248 | publication: ( 249 | parent: Publisher, 250 | args: {}, 251 | ctx: IContext, 252 | info: GraphQLResolveInfo, 253 | ) => Book[] | null | Promise; 254 | 255 | createdAt: ( 256 | parent: Publisher, 257 | args: {}, 258 | ctx: IContext, 259 | info: GraphQLResolveInfo, 260 | ) => string | Promise; 261 | 262 | updatedAt: ( 263 | parent: Publisher, 264 | args: {}, 265 | ctx: IContext, 266 | info: GraphQLResolveInfo, 267 | ) => string | Promise; 268 | } 269 | } 270 | 271 | export namespace BookResolvers { 272 | export const defaultResolvers = { 273 | id: (parent: Book) => parent.id, 274 | title: (parent: Book) => parent.title, 275 | description: (parent: Book) => 276 | parent.description === undefined ? null : parent.description, 277 | pages: (parent: Book) => (parent.pages === undefined ? null : parent.pages), 278 | publishDateTime: (parent: Book) => parent.publishDateTime, 279 | isbnNo: (parent: Book) => 280 | parent.isbnNo === undefined ? null : parent.isbnNo, 281 | createdAt: (parent: Book) => parent.createdAt, 282 | updatedAt: (parent: Book) => parent.updatedAt, 283 | }; 284 | 285 | export type IdResolver = ( 286 | parent: Book, 287 | args: {}, 288 | ctx: IContext, 289 | info: GraphQLResolveInfo, 290 | ) => string | Promise; 291 | 292 | export type TitleResolver = ( 293 | parent: Book, 294 | args: {}, 295 | ctx: IContext, 296 | info: GraphQLResolveInfo, 297 | ) => string | Promise; 298 | 299 | export type DescriptionResolver = ( 300 | parent: Book, 301 | args: {}, 302 | ctx: IContext, 303 | info: GraphQLResolveInfo, 304 | ) => string | null | Promise; 305 | 306 | export type PublishersResolver = ( 307 | parent: Book, 308 | args: {}, 309 | ctx: IContext, 310 | info: GraphQLResolveInfo, 311 | ) => Publisher[] | Promise; 312 | 313 | export type PagesResolver = ( 314 | parent: Book, 315 | args: {}, 316 | ctx: IContext, 317 | info: GraphQLResolveInfo, 318 | ) => number | null | Promise; 319 | 320 | export type PublishDateTimeResolver = ( 321 | parent: Book, 322 | args: {}, 323 | ctx: IContext, 324 | info: GraphQLResolveInfo, 325 | ) => string | Promise; 326 | 327 | export type AuthorsResolver = ( 328 | parent: Book, 329 | args: {}, 330 | ctx: IContext, 331 | info: GraphQLResolveInfo, 332 | ) => User[] | Promise; 333 | 334 | export type RatingsResolver = ( 335 | parent: Book, 336 | args: {}, 337 | ctx: IContext, 338 | info: GraphQLResolveInfo, 339 | ) => Rating[] | null | Promise; 340 | 341 | export type ReviewsResolver = ( 342 | parent: Book, 343 | args: {}, 344 | ctx: IContext, 345 | info: GraphQLResolveInfo, 346 | ) => Review[] | Promise; 347 | 348 | export type IsbnNoResolver = ( 349 | parent: Book, 350 | args: {}, 351 | ctx: IContext, 352 | info: GraphQLResolveInfo, 353 | ) => string | null | Promise; 354 | 355 | export type CreatedAtResolver = ( 356 | parent: Book, 357 | args: {}, 358 | ctx: IContext, 359 | info: GraphQLResolveInfo, 360 | ) => string | Promise; 361 | 362 | export type UpdatedAtResolver = ( 363 | parent: Book, 364 | args: {}, 365 | ctx: IContext, 366 | info: GraphQLResolveInfo, 367 | ) => string | Promise; 368 | 369 | export interface Type { 370 | id: ( 371 | parent: Book, 372 | args: {}, 373 | ctx: IContext, 374 | info: GraphQLResolveInfo, 375 | ) => string | Promise; 376 | 377 | title: ( 378 | parent: Book, 379 | args: {}, 380 | ctx: IContext, 381 | info: GraphQLResolveInfo, 382 | ) => string | Promise; 383 | 384 | description: ( 385 | parent: Book, 386 | args: {}, 387 | ctx: IContext, 388 | info: GraphQLResolveInfo, 389 | ) => string | null | Promise; 390 | 391 | publishers: ( 392 | parent: Book, 393 | args: {}, 394 | ctx: IContext, 395 | info: GraphQLResolveInfo, 396 | ) => Publisher[] | Promise; 397 | 398 | pages: ( 399 | parent: Book, 400 | args: {}, 401 | ctx: IContext, 402 | info: GraphQLResolveInfo, 403 | ) => number | null | Promise; 404 | 405 | publishDateTime: ( 406 | parent: Book, 407 | args: {}, 408 | ctx: IContext, 409 | info: GraphQLResolveInfo, 410 | ) => string | Promise; 411 | 412 | authors: ( 413 | parent: Book, 414 | args: {}, 415 | ctx: IContext, 416 | info: GraphQLResolveInfo, 417 | ) => User[] | Promise; 418 | 419 | ratings: ( 420 | parent: Book, 421 | args: {}, 422 | ctx: IContext, 423 | info: GraphQLResolveInfo, 424 | ) => Rating[] | null | Promise; 425 | 426 | reviews: ( 427 | parent: Book, 428 | args: {}, 429 | ctx: IContext, 430 | info: GraphQLResolveInfo, 431 | ) => Review[] | Promise; 432 | 433 | isbnNo: ( 434 | parent: Book, 435 | args: {}, 436 | ctx: IContext, 437 | info: GraphQLResolveInfo, 438 | ) => string | null | Promise; 439 | 440 | createdAt: ( 441 | parent: Book, 442 | args: {}, 443 | ctx: IContext, 444 | info: GraphQLResolveInfo, 445 | ) => string | Promise; 446 | 447 | updatedAt: ( 448 | parent: Book, 449 | args: {}, 450 | ctx: IContext, 451 | info: GraphQLResolveInfo, 452 | ) => string | Promise; 453 | } 454 | } 455 | 456 | export namespace UserResolvers { 457 | export const defaultResolvers = { 458 | id: (parent: User) => parent.id, 459 | firstName: (parent: User) => parent.firstName, 460 | lastName: (parent: User) => parent.lastName, 461 | email: (parent: User) => parent.email, 462 | createdAt: (parent: User) => parent.createdAt, 463 | updatedAt: (parent: User) => parent.updatedAt, 464 | }; 465 | 466 | export type IdResolver = ( 467 | parent: User, 468 | args: {}, 469 | ctx: IContext, 470 | info: GraphQLResolveInfo, 471 | ) => string | Promise; 472 | 473 | export type FirstNameResolver = ( 474 | parent: User, 475 | args: {}, 476 | ctx: IContext, 477 | info: GraphQLResolveInfo, 478 | ) => string | Promise; 479 | 480 | export type LastNameResolver = ( 481 | parent: User, 482 | args: {}, 483 | ctx: IContext, 484 | info: GraphQLResolveInfo, 485 | ) => string | Promise; 486 | 487 | export type EmailResolver = ( 488 | parent: User, 489 | args: {}, 490 | ctx: IContext, 491 | info: GraphQLResolveInfo, 492 | ) => string | Promise; 493 | 494 | export type BooksResolver = ( 495 | parent: User, 496 | args: {}, 497 | ctx: IContext, 498 | info: GraphQLResolveInfo, 499 | ) => Book[] | null | Promise; 500 | 501 | export type ReviewsResolver = ( 502 | parent: User, 503 | args: {}, 504 | ctx: IContext, 505 | info: GraphQLResolveInfo, 506 | ) => Review[] | null | Promise; 507 | 508 | export type CreatedAtResolver = ( 509 | parent: User, 510 | args: {}, 511 | ctx: IContext, 512 | info: GraphQLResolveInfo, 513 | ) => string | Promise; 514 | 515 | export type UpdatedAtResolver = ( 516 | parent: User, 517 | args: {}, 518 | ctx: IContext, 519 | info: GraphQLResolveInfo, 520 | ) => string | Promise; 521 | 522 | export interface Type { 523 | id: ( 524 | parent: User, 525 | args: {}, 526 | ctx: IContext, 527 | info: GraphQLResolveInfo, 528 | ) => string | Promise; 529 | 530 | firstName: ( 531 | parent: User, 532 | args: {}, 533 | ctx: IContext, 534 | info: GraphQLResolveInfo, 535 | ) => string | Promise; 536 | 537 | lastName: ( 538 | parent: User, 539 | args: {}, 540 | ctx: IContext, 541 | info: GraphQLResolveInfo, 542 | ) => string | Promise; 543 | 544 | email: ( 545 | parent: User, 546 | args: {}, 547 | ctx: IContext, 548 | info: GraphQLResolveInfo, 549 | ) => string | Promise; 550 | 551 | books: ( 552 | parent: User, 553 | args: {}, 554 | ctx: IContext, 555 | info: GraphQLResolveInfo, 556 | ) => Book[] | null | Promise; 557 | 558 | reviews: ( 559 | parent: User, 560 | args: {}, 561 | ctx: IContext, 562 | info: GraphQLResolveInfo, 563 | ) => Review[] | null | Promise; 564 | 565 | createdAt: ( 566 | parent: User, 567 | args: {}, 568 | ctx: IContext, 569 | info: GraphQLResolveInfo, 570 | ) => string | Promise; 571 | 572 | updatedAt: ( 573 | parent: User, 574 | args: {}, 575 | ctx: IContext, 576 | info: GraphQLResolveInfo, 577 | ) => string | Promise; 578 | } 579 | } 580 | 581 | export namespace ReviewResolvers { 582 | export const defaultResolvers = { 583 | id: (parent: Review) => parent.id, 584 | review: (parent: Review) => parent.review, 585 | createdAt: (parent: Review) => parent.createdAt, 586 | }; 587 | 588 | export type IdResolver = ( 589 | parent: Review, 590 | args: {}, 591 | ctx: IContext, 592 | info: GraphQLResolveInfo, 593 | ) => string | Promise; 594 | 595 | export type ReviewResolver = ( 596 | parent: Review, 597 | args: {}, 598 | ctx: IContext, 599 | info: GraphQLResolveInfo, 600 | ) => string | Promise; 601 | 602 | export type ReviewerResolver = ( 603 | parent: Review, 604 | args: {}, 605 | ctx: IContext, 606 | info: GraphQLResolveInfo, 607 | ) => User | Promise; 608 | 609 | export type BookResolver = ( 610 | parent: Review, 611 | args: {}, 612 | ctx: IContext, 613 | info: GraphQLResolveInfo, 614 | ) => Book | Promise; 615 | 616 | export type CreatedAtResolver = ( 617 | parent: Review, 618 | args: {}, 619 | ctx: IContext, 620 | info: GraphQLResolveInfo, 621 | ) => string | Promise; 622 | 623 | export interface Type { 624 | id: ( 625 | parent: Review, 626 | args: {}, 627 | ctx: IContext, 628 | info: GraphQLResolveInfo, 629 | ) => string | Promise; 630 | 631 | review: ( 632 | parent: Review, 633 | args: {}, 634 | ctx: IContext, 635 | info: GraphQLResolveInfo, 636 | ) => string | Promise; 637 | 638 | reviewer: ( 639 | parent: Review, 640 | args: {}, 641 | ctx: IContext, 642 | info: GraphQLResolveInfo, 643 | ) => User | Promise; 644 | 645 | book: ( 646 | parent: Review, 647 | args: {}, 648 | ctx: IContext, 649 | info: GraphQLResolveInfo, 650 | ) => Book | Promise; 651 | 652 | createdAt: ( 653 | parent: Review, 654 | args: {}, 655 | ctx: IContext, 656 | info: GraphQLResolveInfo, 657 | ) => string | Promise; 658 | } 659 | } 660 | 661 | export namespace RatingResolvers { 662 | export const defaultResolvers = { 663 | id: (parent: Rating) => parent.id, 664 | rating: (parent: Rating) => parent.rating, 665 | createdAt: (parent: Rating) => parent.createdAt, 666 | }; 667 | 668 | export type IdResolver = ( 669 | parent: Rating, 670 | args: {}, 671 | ctx: IContext, 672 | info: GraphQLResolveInfo, 673 | ) => string | Promise; 674 | 675 | export type RatingResolver = ( 676 | parent: Rating, 677 | args: {}, 678 | ctx: IContext, 679 | info: GraphQLResolveInfo, 680 | ) => number | Promise; 681 | 682 | export type RaterResolver = ( 683 | parent: Rating, 684 | args: {}, 685 | ctx: IContext, 686 | info: GraphQLResolveInfo, 687 | ) => User | Promise; 688 | 689 | export type BookResolver = ( 690 | parent: Rating, 691 | args: {}, 692 | ctx: IContext, 693 | info: GraphQLResolveInfo, 694 | ) => Book | Promise; 695 | 696 | export type CreatedAtResolver = ( 697 | parent: Rating, 698 | args: {}, 699 | ctx: IContext, 700 | info: GraphQLResolveInfo, 701 | ) => string | Promise; 702 | 703 | export interface Type { 704 | id: ( 705 | parent: Rating, 706 | args: {}, 707 | ctx: IContext, 708 | info: GraphQLResolveInfo, 709 | ) => string | Promise; 710 | 711 | rating: ( 712 | parent: Rating, 713 | args: {}, 714 | ctx: IContext, 715 | info: GraphQLResolveInfo, 716 | ) => number | Promise; 717 | 718 | rater: ( 719 | parent: Rating, 720 | args: {}, 721 | ctx: IContext, 722 | info: GraphQLResolveInfo, 723 | ) => User | Promise; 724 | 725 | book: ( 726 | parent: Rating, 727 | args: {}, 728 | ctx: IContext, 729 | info: GraphQLResolveInfo, 730 | ) => Book | Promise; 731 | 732 | createdAt: ( 733 | parent: Rating, 734 | args: {}, 735 | ctx: IContext, 736 | info: GraphQLResolveInfo, 737 | ) => string | Promise; 738 | } 739 | } 740 | 741 | export namespace MutationResolvers { 742 | export const defaultResolvers = {}; 743 | 744 | export interface SignupInput { 745 | firstName: string; 746 | lastName: string; 747 | email: string; 748 | password: string; 749 | } 750 | export interface LoginInput { 751 | email: string; 752 | password: string; 753 | } 754 | export interface PublisherInput { 755 | name: string; 756 | about: string; 757 | address: string; 758 | } 759 | export interface AuthorInput { 760 | firstName: string; 761 | lastName: string; 762 | email: string; 763 | } 764 | export interface BookInput { 765 | title: string; 766 | description: string; 767 | publishers: string[]; 768 | pages?: number | null; 769 | publishDateTime: string; 770 | authors: string[]; 771 | isbnNo?: string | null; 772 | } 773 | export interface ReviewInput { 774 | review: string; 775 | reviewer: string; 776 | book: string; 777 | } 778 | 779 | export interface ArgsSignup { 780 | user?: SignupInput | null; 781 | } 782 | 783 | export interface ArgsLogin { 784 | user?: LoginInput | null; 785 | } 786 | 787 | export interface ArgsCreatePublisher { 788 | publisher?: PublisherInput | null; 789 | } 790 | 791 | export interface ArgsCreateAuthor { 792 | user: AuthorInput; 793 | } 794 | 795 | export interface ArgsCreateBook { 796 | book: BookInput; 797 | } 798 | 799 | export interface ArgsCreateReview { 800 | review: ReviewInput; 801 | } 802 | 803 | export type SignupResolver = ( 804 | parent: undefined, 805 | args: ArgsSignup, 806 | ctx: IContext, 807 | info: GraphQLResolveInfo, 808 | ) => AuthResponse | Promise; 809 | 810 | export type LoginResolver = ( 811 | parent: undefined, 812 | args: ArgsLogin, 813 | ctx: IContext, 814 | info: GraphQLResolveInfo, 815 | ) => AuthResponse | Promise; 816 | 817 | export type CreatePublisherResolver = ( 818 | parent: undefined, 819 | args: ArgsCreatePublisher, 820 | ctx: IContext, 821 | info: GraphQLResolveInfo, 822 | ) => Publisher | Promise; 823 | 824 | export type CreateAuthorResolver = ( 825 | parent: undefined, 826 | args: ArgsCreateAuthor, 827 | ctx: IContext, 828 | info: GraphQLResolveInfo, 829 | ) => User | Promise; 830 | 831 | export type CreateBookResolver = ( 832 | parent: undefined, 833 | args: ArgsCreateBook, 834 | ctx: IContext, 835 | info: GraphQLResolveInfo, 836 | ) => Book | Promise; 837 | 838 | export type CreateReviewResolver = ( 839 | parent: undefined, 840 | args: ArgsCreateReview, 841 | ctx: IContext, 842 | info: GraphQLResolveInfo, 843 | ) => Review | Promise; 844 | 845 | export interface Type { 846 | signup: ( 847 | parent: undefined, 848 | args: ArgsSignup, 849 | ctx: IContext, 850 | info: GraphQLResolveInfo, 851 | ) => AuthResponse | Promise; 852 | 853 | login: ( 854 | parent: undefined, 855 | args: ArgsLogin, 856 | ctx: IContext, 857 | info: GraphQLResolveInfo, 858 | ) => AuthResponse | Promise; 859 | 860 | createPublisher: ( 861 | parent: undefined, 862 | args: ArgsCreatePublisher, 863 | ctx: IContext, 864 | info: GraphQLResolveInfo, 865 | ) => Publisher | Promise; 866 | 867 | createAuthor: ( 868 | parent: undefined, 869 | args: ArgsCreateAuthor, 870 | ctx: IContext, 871 | info: GraphQLResolveInfo, 872 | ) => User | Promise; 873 | 874 | createBook: ( 875 | parent: undefined, 876 | args: ArgsCreateBook, 877 | ctx: IContext, 878 | info: GraphQLResolveInfo, 879 | ) => Book | Promise; 880 | 881 | createReview: ( 882 | parent: undefined, 883 | args: ArgsCreateReview, 884 | ctx: IContext, 885 | info: GraphQLResolveInfo, 886 | ) => Review | Promise; 887 | } 888 | } 889 | 890 | export namespace AuthResponseResolvers { 891 | export const defaultResolvers = { 892 | token: (parent: AuthResponse) => parent.token, 893 | user: (parent: AuthResponse) => parent.user, 894 | }; 895 | 896 | export type TokenResolver = ( 897 | parent: AuthResponse, 898 | args: {}, 899 | ctx: IContext, 900 | info: GraphQLResolveInfo, 901 | ) => string | Promise; 902 | 903 | export type UserResolver = ( 904 | parent: AuthResponse, 905 | args: {}, 906 | ctx: IContext, 907 | info: GraphQLResolveInfo, 908 | ) => User | Promise; 909 | 910 | export interface Type { 911 | token: ( 912 | parent: AuthResponse, 913 | args: {}, 914 | ctx: IContext, 915 | info: GraphQLResolveInfo, 916 | ) => string | Promise; 917 | 918 | user: ( 919 | parent: AuthResponse, 920 | args: {}, 921 | ctx: IContext, 922 | info: GraphQLResolveInfo, 923 | ) => User | Promise; 924 | } 925 | } 926 | 927 | export interface Resolvers { 928 | Query: QueryResolvers.Type; 929 | Publisher: PublisherResolvers.Type; 930 | Book: BookResolvers.Type; 931 | User: UserResolvers.Type; 932 | Review: ReviewResolvers.Type; 933 | Rating: RatingResolvers.Type; 934 | Mutation: MutationResolvers.Type; 935 | [key: string]: object; 936 | } 937 | -------------------------------------------------------------------------------- /src/prisma/generated/prisma-client/prisma-schema.ts: -------------------------------------------------------------------------------- 1 | export const typeDefs = /* GraphQL */ `type AggregateBook { 2 | count: Int! 3 | } 4 | 5 | type AggregatePublisher { 6 | count: Int! 7 | } 8 | 9 | type AggregateRating { 10 | count: Int! 11 | } 12 | 13 | type AggregateReview { 14 | count: Int! 15 | } 16 | 17 | type AggregateUser { 18 | count: Int! 19 | } 20 | 21 | type BatchPayload { 22 | count: Long! 23 | } 24 | 25 | type Book { 26 | id: ID! 27 | title: String! 28 | description: String 29 | publishers(where: PublisherWhereInput, orderBy: PublisherOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Publisher!] 30 | pages: Int 31 | publishDateTime: DateTime! 32 | authors(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User!] 33 | ratings(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Rating!] 34 | reviews(where: ReviewWhereInput, orderBy: ReviewOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Review!] 35 | isbnNo: String 36 | createdAt: DateTime! 37 | updatedAt: DateTime! 38 | } 39 | 40 | type BookConnection { 41 | pageInfo: PageInfo! 42 | edges: [BookEdge]! 43 | aggregate: AggregateBook! 44 | } 45 | 46 | input BookCreateInput { 47 | title: String! 48 | description: String 49 | publishers: PublisherCreateManyWithoutPublicationInput 50 | pages: Int 51 | publishDateTime: DateTime! 52 | authors: UserCreateManyWithoutBooksInput 53 | ratings: RatingCreateManyWithoutBookInput 54 | reviews: ReviewCreateManyWithoutBookInput 55 | isbnNo: String 56 | } 57 | 58 | input BookCreateManyWithoutAuthorsInput { 59 | create: [BookCreateWithoutAuthorsInput!] 60 | connect: [BookWhereUniqueInput!] 61 | } 62 | 63 | input BookCreateManyWithoutPublishersInput { 64 | create: [BookCreateWithoutPublishersInput!] 65 | connect: [BookWhereUniqueInput!] 66 | } 67 | 68 | input BookCreateOneWithoutRatingsInput { 69 | create: BookCreateWithoutRatingsInput 70 | connect: BookWhereUniqueInput 71 | } 72 | 73 | input BookCreateOneWithoutReviewsInput { 74 | create: BookCreateWithoutReviewsInput 75 | connect: BookWhereUniqueInput 76 | } 77 | 78 | input BookCreateWithoutAuthorsInput { 79 | title: String! 80 | description: String 81 | publishers: PublisherCreateManyWithoutPublicationInput 82 | pages: Int 83 | publishDateTime: DateTime! 84 | ratings: RatingCreateManyWithoutBookInput 85 | reviews: ReviewCreateManyWithoutBookInput 86 | isbnNo: String 87 | } 88 | 89 | input BookCreateWithoutPublishersInput { 90 | title: String! 91 | description: String 92 | pages: Int 93 | publishDateTime: DateTime! 94 | authors: UserCreateManyWithoutBooksInput 95 | ratings: RatingCreateManyWithoutBookInput 96 | reviews: ReviewCreateManyWithoutBookInput 97 | isbnNo: String 98 | } 99 | 100 | input BookCreateWithoutRatingsInput { 101 | title: String! 102 | description: String 103 | publishers: PublisherCreateManyWithoutPublicationInput 104 | pages: Int 105 | publishDateTime: DateTime! 106 | authors: UserCreateManyWithoutBooksInput 107 | reviews: ReviewCreateManyWithoutBookInput 108 | isbnNo: String 109 | } 110 | 111 | input BookCreateWithoutReviewsInput { 112 | title: String! 113 | description: String 114 | publishers: PublisherCreateManyWithoutPublicationInput 115 | pages: Int 116 | publishDateTime: DateTime! 117 | authors: UserCreateManyWithoutBooksInput 118 | ratings: RatingCreateManyWithoutBookInput 119 | isbnNo: String 120 | } 121 | 122 | type BookEdge { 123 | node: Book! 124 | cursor: String! 125 | } 126 | 127 | enum BookOrderByInput { 128 | id_ASC 129 | id_DESC 130 | title_ASC 131 | title_DESC 132 | description_ASC 133 | description_DESC 134 | pages_ASC 135 | pages_DESC 136 | publishDateTime_ASC 137 | publishDateTime_DESC 138 | isbnNo_ASC 139 | isbnNo_DESC 140 | createdAt_ASC 141 | createdAt_DESC 142 | updatedAt_ASC 143 | updatedAt_DESC 144 | } 145 | 146 | type BookPreviousValues { 147 | id: ID! 148 | title: String! 149 | description: String 150 | pages: Int 151 | publishDateTime: DateTime! 152 | isbnNo: String 153 | createdAt: DateTime! 154 | updatedAt: DateTime! 155 | } 156 | 157 | input BookScalarWhereInput { 158 | id: ID 159 | id_not: ID 160 | id_in: [ID!] 161 | id_not_in: [ID!] 162 | id_lt: ID 163 | id_lte: ID 164 | id_gt: ID 165 | id_gte: ID 166 | id_contains: ID 167 | id_not_contains: ID 168 | id_starts_with: ID 169 | id_not_starts_with: ID 170 | id_ends_with: ID 171 | id_not_ends_with: ID 172 | title: String 173 | title_not: String 174 | title_in: [String!] 175 | title_not_in: [String!] 176 | title_lt: String 177 | title_lte: String 178 | title_gt: String 179 | title_gte: String 180 | title_contains: String 181 | title_not_contains: String 182 | title_starts_with: String 183 | title_not_starts_with: String 184 | title_ends_with: String 185 | title_not_ends_with: String 186 | description: String 187 | description_not: String 188 | description_in: [String!] 189 | description_not_in: [String!] 190 | description_lt: String 191 | description_lte: String 192 | description_gt: String 193 | description_gte: String 194 | description_contains: String 195 | description_not_contains: String 196 | description_starts_with: String 197 | description_not_starts_with: String 198 | description_ends_with: String 199 | description_not_ends_with: String 200 | pages: Int 201 | pages_not: Int 202 | pages_in: [Int!] 203 | pages_not_in: [Int!] 204 | pages_lt: Int 205 | pages_lte: Int 206 | pages_gt: Int 207 | pages_gte: Int 208 | publishDateTime: DateTime 209 | publishDateTime_not: DateTime 210 | publishDateTime_in: [DateTime!] 211 | publishDateTime_not_in: [DateTime!] 212 | publishDateTime_lt: DateTime 213 | publishDateTime_lte: DateTime 214 | publishDateTime_gt: DateTime 215 | publishDateTime_gte: DateTime 216 | isbnNo: String 217 | isbnNo_not: String 218 | isbnNo_in: [String!] 219 | isbnNo_not_in: [String!] 220 | isbnNo_lt: String 221 | isbnNo_lte: String 222 | isbnNo_gt: String 223 | isbnNo_gte: String 224 | isbnNo_contains: String 225 | isbnNo_not_contains: String 226 | isbnNo_starts_with: String 227 | isbnNo_not_starts_with: String 228 | isbnNo_ends_with: String 229 | isbnNo_not_ends_with: String 230 | createdAt: DateTime 231 | createdAt_not: DateTime 232 | createdAt_in: [DateTime!] 233 | createdAt_not_in: [DateTime!] 234 | createdAt_lt: DateTime 235 | createdAt_lte: DateTime 236 | createdAt_gt: DateTime 237 | createdAt_gte: DateTime 238 | updatedAt: DateTime 239 | updatedAt_not: DateTime 240 | updatedAt_in: [DateTime!] 241 | updatedAt_not_in: [DateTime!] 242 | updatedAt_lt: DateTime 243 | updatedAt_lte: DateTime 244 | updatedAt_gt: DateTime 245 | updatedAt_gte: DateTime 246 | AND: [BookScalarWhereInput!] 247 | OR: [BookScalarWhereInput!] 248 | NOT: [BookScalarWhereInput!] 249 | } 250 | 251 | type BookSubscriptionPayload { 252 | mutation: MutationType! 253 | node: Book 254 | updatedFields: [String!] 255 | previousValues: BookPreviousValues 256 | } 257 | 258 | input BookSubscriptionWhereInput { 259 | mutation_in: [MutationType!] 260 | updatedFields_contains: String 261 | updatedFields_contains_every: [String!] 262 | updatedFields_contains_some: [String!] 263 | node: BookWhereInput 264 | AND: [BookSubscriptionWhereInput!] 265 | OR: [BookSubscriptionWhereInput!] 266 | NOT: [BookSubscriptionWhereInput!] 267 | } 268 | 269 | input BookUpdateInput { 270 | title: String 271 | description: String 272 | publishers: PublisherUpdateManyWithoutPublicationInput 273 | pages: Int 274 | publishDateTime: DateTime 275 | authors: UserUpdateManyWithoutBooksInput 276 | ratings: RatingUpdateManyWithoutBookInput 277 | reviews: ReviewUpdateManyWithoutBookInput 278 | isbnNo: String 279 | } 280 | 281 | input BookUpdateManyDataInput { 282 | title: String 283 | description: String 284 | pages: Int 285 | publishDateTime: DateTime 286 | isbnNo: String 287 | } 288 | 289 | input BookUpdateManyMutationInput { 290 | title: String 291 | description: String 292 | pages: Int 293 | publishDateTime: DateTime 294 | isbnNo: String 295 | } 296 | 297 | input BookUpdateManyWithoutAuthorsInput { 298 | create: [BookCreateWithoutAuthorsInput!] 299 | delete: [BookWhereUniqueInput!] 300 | connect: [BookWhereUniqueInput!] 301 | disconnect: [BookWhereUniqueInput!] 302 | update: [BookUpdateWithWhereUniqueWithoutAuthorsInput!] 303 | upsert: [BookUpsertWithWhereUniqueWithoutAuthorsInput!] 304 | deleteMany: [BookScalarWhereInput!] 305 | updateMany: [BookUpdateManyWithWhereNestedInput!] 306 | } 307 | 308 | input BookUpdateManyWithoutPublishersInput { 309 | create: [BookCreateWithoutPublishersInput!] 310 | delete: [BookWhereUniqueInput!] 311 | connect: [BookWhereUniqueInput!] 312 | disconnect: [BookWhereUniqueInput!] 313 | update: [BookUpdateWithWhereUniqueWithoutPublishersInput!] 314 | upsert: [BookUpsertWithWhereUniqueWithoutPublishersInput!] 315 | deleteMany: [BookScalarWhereInput!] 316 | updateMany: [BookUpdateManyWithWhereNestedInput!] 317 | } 318 | 319 | input BookUpdateManyWithWhereNestedInput { 320 | where: BookScalarWhereInput! 321 | data: BookUpdateManyDataInput! 322 | } 323 | 324 | input BookUpdateOneRequiredWithoutRatingsInput { 325 | create: BookCreateWithoutRatingsInput 326 | update: BookUpdateWithoutRatingsDataInput 327 | upsert: BookUpsertWithoutRatingsInput 328 | connect: BookWhereUniqueInput 329 | } 330 | 331 | input BookUpdateOneRequiredWithoutReviewsInput { 332 | create: BookCreateWithoutReviewsInput 333 | update: BookUpdateWithoutReviewsDataInput 334 | upsert: BookUpsertWithoutReviewsInput 335 | connect: BookWhereUniqueInput 336 | } 337 | 338 | input BookUpdateWithoutAuthorsDataInput { 339 | title: String 340 | description: String 341 | publishers: PublisherUpdateManyWithoutPublicationInput 342 | pages: Int 343 | publishDateTime: DateTime 344 | ratings: RatingUpdateManyWithoutBookInput 345 | reviews: ReviewUpdateManyWithoutBookInput 346 | isbnNo: String 347 | } 348 | 349 | input BookUpdateWithoutPublishersDataInput { 350 | title: String 351 | description: String 352 | pages: Int 353 | publishDateTime: DateTime 354 | authors: UserUpdateManyWithoutBooksInput 355 | ratings: RatingUpdateManyWithoutBookInput 356 | reviews: ReviewUpdateManyWithoutBookInput 357 | isbnNo: String 358 | } 359 | 360 | input BookUpdateWithoutRatingsDataInput { 361 | title: String 362 | description: String 363 | publishers: PublisherUpdateManyWithoutPublicationInput 364 | pages: Int 365 | publishDateTime: DateTime 366 | authors: UserUpdateManyWithoutBooksInput 367 | reviews: ReviewUpdateManyWithoutBookInput 368 | isbnNo: String 369 | } 370 | 371 | input BookUpdateWithoutReviewsDataInput { 372 | title: String 373 | description: String 374 | publishers: PublisherUpdateManyWithoutPublicationInput 375 | pages: Int 376 | publishDateTime: DateTime 377 | authors: UserUpdateManyWithoutBooksInput 378 | ratings: RatingUpdateManyWithoutBookInput 379 | isbnNo: String 380 | } 381 | 382 | input BookUpdateWithWhereUniqueWithoutAuthorsInput { 383 | where: BookWhereUniqueInput! 384 | data: BookUpdateWithoutAuthorsDataInput! 385 | } 386 | 387 | input BookUpdateWithWhereUniqueWithoutPublishersInput { 388 | where: BookWhereUniqueInput! 389 | data: BookUpdateWithoutPublishersDataInput! 390 | } 391 | 392 | input BookUpsertWithoutRatingsInput { 393 | update: BookUpdateWithoutRatingsDataInput! 394 | create: BookCreateWithoutRatingsInput! 395 | } 396 | 397 | input BookUpsertWithoutReviewsInput { 398 | update: BookUpdateWithoutReviewsDataInput! 399 | create: BookCreateWithoutReviewsInput! 400 | } 401 | 402 | input BookUpsertWithWhereUniqueWithoutAuthorsInput { 403 | where: BookWhereUniqueInput! 404 | update: BookUpdateWithoutAuthorsDataInput! 405 | create: BookCreateWithoutAuthorsInput! 406 | } 407 | 408 | input BookUpsertWithWhereUniqueWithoutPublishersInput { 409 | where: BookWhereUniqueInput! 410 | update: BookUpdateWithoutPublishersDataInput! 411 | create: BookCreateWithoutPublishersInput! 412 | } 413 | 414 | input BookWhereInput { 415 | id: ID 416 | id_not: ID 417 | id_in: [ID!] 418 | id_not_in: [ID!] 419 | id_lt: ID 420 | id_lte: ID 421 | id_gt: ID 422 | id_gte: ID 423 | id_contains: ID 424 | id_not_contains: ID 425 | id_starts_with: ID 426 | id_not_starts_with: ID 427 | id_ends_with: ID 428 | id_not_ends_with: ID 429 | title: String 430 | title_not: String 431 | title_in: [String!] 432 | title_not_in: [String!] 433 | title_lt: String 434 | title_lte: String 435 | title_gt: String 436 | title_gte: String 437 | title_contains: String 438 | title_not_contains: String 439 | title_starts_with: String 440 | title_not_starts_with: String 441 | title_ends_with: String 442 | title_not_ends_with: String 443 | description: String 444 | description_not: String 445 | description_in: [String!] 446 | description_not_in: [String!] 447 | description_lt: String 448 | description_lte: String 449 | description_gt: String 450 | description_gte: String 451 | description_contains: String 452 | description_not_contains: String 453 | description_starts_with: String 454 | description_not_starts_with: String 455 | description_ends_with: String 456 | description_not_ends_with: String 457 | publishers_every: PublisherWhereInput 458 | publishers_some: PublisherWhereInput 459 | publishers_none: PublisherWhereInput 460 | pages: Int 461 | pages_not: Int 462 | pages_in: [Int!] 463 | pages_not_in: [Int!] 464 | pages_lt: Int 465 | pages_lte: Int 466 | pages_gt: Int 467 | pages_gte: Int 468 | publishDateTime: DateTime 469 | publishDateTime_not: DateTime 470 | publishDateTime_in: [DateTime!] 471 | publishDateTime_not_in: [DateTime!] 472 | publishDateTime_lt: DateTime 473 | publishDateTime_lte: DateTime 474 | publishDateTime_gt: DateTime 475 | publishDateTime_gte: DateTime 476 | authors_every: UserWhereInput 477 | authors_some: UserWhereInput 478 | authors_none: UserWhereInput 479 | ratings_every: RatingWhereInput 480 | ratings_some: RatingWhereInput 481 | ratings_none: RatingWhereInput 482 | reviews_every: ReviewWhereInput 483 | reviews_some: ReviewWhereInput 484 | reviews_none: ReviewWhereInput 485 | isbnNo: String 486 | isbnNo_not: String 487 | isbnNo_in: [String!] 488 | isbnNo_not_in: [String!] 489 | isbnNo_lt: String 490 | isbnNo_lte: String 491 | isbnNo_gt: String 492 | isbnNo_gte: String 493 | isbnNo_contains: String 494 | isbnNo_not_contains: String 495 | isbnNo_starts_with: String 496 | isbnNo_not_starts_with: String 497 | isbnNo_ends_with: String 498 | isbnNo_not_ends_with: String 499 | createdAt: DateTime 500 | createdAt_not: DateTime 501 | createdAt_in: [DateTime!] 502 | createdAt_not_in: [DateTime!] 503 | createdAt_lt: DateTime 504 | createdAt_lte: DateTime 505 | createdAt_gt: DateTime 506 | createdAt_gte: DateTime 507 | updatedAt: DateTime 508 | updatedAt_not: DateTime 509 | updatedAt_in: [DateTime!] 510 | updatedAt_not_in: [DateTime!] 511 | updatedAt_lt: DateTime 512 | updatedAt_lte: DateTime 513 | updatedAt_gt: DateTime 514 | updatedAt_gte: DateTime 515 | AND: [BookWhereInput!] 516 | OR: [BookWhereInput!] 517 | NOT: [BookWhereInput!] 518 | } 519 | 520 | input BookWhereUniqueInput { 521 | id: ID 522 | } 523 | 524 | scalar DateTime 525 | 526 | enum EnumUserRole { 527 | USER 528 | ADMIN 529 | AUTHOR 530 | } 531 | 532 | scalar Long 533 | 534 | type Mutation { 535 | createBook(data: BookCreateInput!): Book! 536 | updateBook(data: BookUpdateInput!, where: BookWhereUniqueInput!): Book 537 | updateManyBooks(data: BookUpdateManyMutationInput!, where: BookWhereInput): BatchPayload! 538 | upsertBook(where: BookWhereUniqueInput!, create: BookCreateInput!, update: BookUpdateInput!): Book! 539 | deleteBook(where: BookWhereUniqueInput!): Book 540 | deleteManyBooks(where: BookWhereInput): BatchPayload! 541 | createPublisher(data: PublisherCreateInput!): Publisher! 542 | updatePublisher(data: PublisherUpdateInput!, where: PublisherWhereUniqueInput!): Publisher 543 | updateManyPublishers(data: PublisherUpdateManyMutationInput!, where: PublisherWhereInput): BatchPayload! 544 | upsertPublisher(where: PublisherWhereUniqueInput!, create: PublisherCreateInput!, update: PublisherUpdateInput!): Publisher! 545 | deletePublisher(where: PublisherWhereUniqueInput!): Publisher 546 | deleteManyPublishers(where: PublisherWhereInput): BatchPayload! 547 | createRating(data: RatingCreateInput!): Rating! 548 | updateRating(data: RatingUpdateInput!, where: RatingWhereUniqueInput!): Rating 549 | updateManyRatings(data: RatingUpdateManyMutationInput!, where: RatingWhereInput): BatchPayload! 550 | upsertRating(where: RatingWhereUniqueInput!, create: RatingCreateInput!, update: RatingUpdateInput!): Rating! 551 | deleteRating(where: RatingWhereUniqueInput!): Rating 552 | deleteManyRatings(where: RatingWhereInput): BatchPayload! 553 | createReview(data: ReviewCreateInput!): Review! 554 | updateReview(data: ReviewUpdateInput!, where: ReviewWhereUniqueInput!): Review 555 | updateManyReviews(data: ReviewUpdateManyMutationInput!, where: ReviewWhereInput): BatchPayload! 556 | upsertReview(where: ReviewWhereUniqueInput!, create: ReviewCreateInput!, update: ReviewUpdateInput!): Review! 557 | deleteReview(where: ReviewWhereUniqueInput!): Review 558 | deleteManyReviews(where: ReviewWhereInput): BatchPayload! 559 | createUser(data: UserCreateInput!): User! 560 | updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput!): User 561 | updateManyUsers(data: UserUpdateManyMutationInput!, where: UserWhereInput): BatchPayload! 562 | upsertUser(where: UserWhereUniqueInput!, create: UserCreateInput!, update: UserUpdateInput!): User! 563 | deleteUser(where: UserWhereUniqueInput!): User 564 | deleteManyUsers(where: UserWhereInput): BatchPayload! 565 | } 566 | 567 | enum MutationType { 568 | CREATED 569 | UPDATED 570 | DELETED 571 | } 572 | 573 | interface Node { 574 | id: ID! 575 | } 576 | 577 | type PageInfo { 578 | hasNextPage: Boolean! 579 | hasPreviousPage: Boolean! 580 | startCursor: String 581 | endCursor: String 582 | } 583 | 584 | type Publisher { 585 | id: ID! 586 | name: String! 587 | about: String 588 | address: String 589 | publication(where: BookWhereInput, orderBy: BookOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Book!] 590 | createdAt: DateTime! 591 | updatedAt: DateTime! 592 | } 593 | 594 | type PublisherConnection { 595 | pageInfo: PageInfo! 596 | edges: [PublisherEdge]! 597 | aggregate: AggregatePublisher! 598 | } 599 | 600 | input PublisherCreateInput { 601 | name: String! 602 | about: String 603 | address: String 604 | publication: BookCreateManyWithoutPublishersInput 605 | } 606 | 607 | input PublisherCreateManyWithoutPublicationInput { 608 | create: [PublisherCreateWithoutPublicationInput!] 609 | connect: [PublisherWhereUniqueInput!] 610 | } 611 | 612 | input PublisherCreateWithoutPublicationInput { 613 | name: String! 614 | about: String 615 | address: String 616 | } 617 | 618 | type PublisherEdge { 619 | node: Publisher! 620 | cursor: String! 621 | } 622 | 623 | enum PublisherOrderByInput { 624 | id_ASC 625 | id_DESC 626 | name_ASC 627 | name_DESC 628 | about_ASC 629 | about_DESC 630 | address_ASC 631 | address_DESC 632 | createdAt_ASC 633 | createdAt_DESC 634 | updatedAt_ASC 635 | updatedAt_DESC 636 | } 637 | 638 | type PublisherPreviousValues { 639 | id: ID! 640 | name: String! 641 | about: String 642 | address: String 643 | createdAt: DateTime! 644 | updatedAt: DateTime! 645 | } 646 | 647 | input PublisherScalarWhereInput { 648 | id: ID 649 | id_not: ID 650 | id_in: [ID!] 651 | id_not_in: [ID!] 652 | id_lt: ID 653 | id_lte: ID 654 | id_gt: ID 655 | id_gte: ID 656 | id_contains: ID 657 | id_not_contains: ID 658 | id_starts_with: ID 659 | id_not_starts_with: ID 660 | id_ends_with: ID 661 | id_not_ends_with: ID 662 | name: String 663 | name_not: String 664 | name_in: [String!] 665 | name_not_in: [String!] 666 | name_lt: String 667 | name_lte: String 668 | name_gt: String 669 | name_gte: String 670 | name_contains: String 671 | name_not_contains: String 672 | name_starts_with: String 673 | name_not_starts_with: String 674 | name_ends_with: String 675 | name_not_ends_with: String 676 | about: String 677 | about_not: String 678 | about_in: [String!] 679 | about_not_in: [String!] 680 | about_lt: String 681 | about_lte: String 682 | about_gt: String 683 | about_gte: String 684 | about_contains: String 685 | about_not_contains: String 686 | about_starts_with: String 687 | about_not_starts_with: String 688 | about_ends_with: String 689 | about_not_ends_with: String 690 | address: String 691 | address_not: String 692 | address_in: [String!] 693 | address_not_in: [String!] 694 | address_lt: String 695 | address_lte: String 696 | address_gt: String 697 | address_gte: String 698 | address_contains: String 699 | address_not_contains: String 700 | address_starts_with: String 701 | address_not_starts_with: String 702 | address_ends_with: String 703 | address_not_ends_with: String 704 | createdAt: DateTime 705 | createdAt_not: DateTime 706 | createdAt_in: [DateTime!] 707 | createdAt_not_in: [DateTime!] 708 | createdAt_lt: DateTime 709 | createdAt_lte: DateTime 710 | createdAt_gt: DateTime 711 | createdAt_gte: DateTime 712 | updatedAt: DateTime 713 | updatedAt_not: DateTime 714 | updatedAt_in: [DateTime!] 715 | updatedAt_not_in: [DateTime!] 716 | updatedAt_lt: DateTime 717 | updatedAt_lte: DateTime 718 | updatedAt_gt: DateTime 719 | updatedAt_gte: DateTime 720 | AND: [PublisherScalarWhereInput!] 721 | OR: [PublisherScalarWhereInput!] 722 | NOT: [PublisherScalarWhereInput!] 723 | } 724 | 725 | type PublisherSubscriptionPayload { 726 | mutation: MutationType! 727 | node: Publisher 728 | updatedFields: [String!] 729 | previousValues: PublisherPreviousValues 730 | } 731 | 732 | input PublisherSubscriptionWhereInput { 733 | mutation_in: [MutationType!] 734 | updatedFields_contains: String 735 | updatedFields_contains_every: [String!] 736 | updatedFields_contains_some: [String!] 737 | node: PublisherWhereInput 738 | AND: [PublisherSubscriptionWhereInput!] 739 | OR: [PublisherSubscriptionWhereInput!] 740 | NOT: [PublisherSubscriptionWhereInput!] 741 | } 742 | 743 | input PublisherUpdateInput { 744 | name: String 745 | about: String 746 | address: String 747 | publication: BookUpdateManyWithoutPublishersInput 748 | } 749 | 750 | input PublisherUpdateManyDataInput { 751 | name: String 752 | about: String 753 | address: String 754 | } 755 | 756 | input PublisherUpdateManyMutationInput { 757 | name: String 758 | about: String 759 | address: String 760 | } 761 | 762 | input PublisherUpdateManyWithoutPublicationInput { 763 | create: [PublisherCreateWithoutPublicationInput!] 764 | delete: [PublisherWhereUniqueInput!] 765 | connect: [PublisherWhereUniqueInput!] 766 | disconnect: [PublisherWhereUniqueInput!] 767 | update: [PublisherUpdateWithWhereUniqueWithoutPublicationInput!] 768 | upsert: [PublisherUpsertWithWhereUniqueWithoutPublicationInput!] 769 | deleteMany: [PublisherScalarWhereInput!] 770 | updateMany: [PublisherUpdateManyWithWhereNestedInput!] 771 | } 772 | 773 | input PublisherUpdateManyWithWhereNestedInput { 774 | where: PublisherScalarWhereInput! 775 | data: PublisherUpdateManyDataInput! 776 | } 777 | 778 | input PublisherUpdateWithoutPublicationDataInput { 779 | name: String 780 | about: String 781 | address: String 782 | } 783 | 784 | input PublisherUpdateWithWhereUniqueWithoutPublicationInput { 785 | where: PublisherWhereUniqueInput! 786 | data: PublisherUpdateWithoutPublicationDataInput! 787 | } 788 | 789 | input PublisherUpsertWithWhereUniqueWithoutPublicationInput { 790 | where: PublisherWhereUniqueInput! 791 | update: PublisherUpdateWithoutPublicationDataInput! 792 | create: PublisherCreateWithoutPublicationInput! 793 | } 794 | 795 | input PublisherWhereInput { 796 | id: ID 797 | id_not: ID 798 | id_in: [ID!] 799 | id_not_in: [ID!] 800 | id_lt: ID 801 | id_lte: ID 802 | id_gt: ID 803 | id_gte: ID 804 | id_contains: ID 805 | id_not_contains: ID 806 | id_starts_with: ID 807 | id_not_starts_with: ID 808 | id_ends_with: ID 809 | id_not_ends_with: ID 810 | name: String 811 | name_not: String 812 | name_in: [String!] 813 | name_not_in: [String!] 814 | name_lt: String 815 | name_lte: String 816 | name_gt: String 817 | name_gte: String 818 | name_contains: String 819 | name_not_contains: String 820 | name_starts_with: String 821 | name_not_starts_with: String 822 | name_ends_with: String 823 | name_not_ends_with: String 824 | about: String 825 | about_not: String 826 | about_in: [String!] 827 | about_not_in: [String!] 828 | about_lt: String 829 | about_lte: String 830 | about_gt: String 831 | about_gte: String 832 | about_contains: String 833 | about_not_contains: String 834 | about_starts_with: String 835 | about_not_starts_with: String 836 | about_ends_with: String 837 | about_not_ends_with: String 838 | address: String 839 | address_not: String 840 | address_in: [String!] 841 | address_not_in: [String!] 842 | address_lt: String 843 | address_lte: String 844 | address_gt: String 845 | address_gte: String 846 | address_contains: String 847 | address_not_contains: String 848 | address_starts_with: String 849 | address_not_starts_with: String 850 | address_ends_with: String 851 | address_not_ends_with: String 852 | publication_every: BookWhereInput 853 | publication_some: BookWhereInput 854 | publication_none: BookWhereInput 855 | createdAt: DateTime 856 | createdAt_not: DateTime 857 | createdAt_in: [DateTime!] 858 | createdAt_not_in: [DateTime!] 859 | createdAt_lt: DateTime 860 | createdAt_lte: DateTime 861 | createdAt_gt: DateTime 862 | createdAt_gte: DateTime 863 | updatedAt: DateTime 864 | updatedAt_not: DateTime 865 | updatedAt_in: [DateTime!] 866 | updatedAt_not_in: [DateTime!] 867 | updatedAt_lt: DateTime 868 | updatedAt_lte: DateTime 869 | updatedAt_gt: DateTime 870 | updatedAt_gte: DateTime 871 | AND: [PublisherWhereInput!] 872 | OR: [PublisherWhereInput!] 873 | NOT: [PublisherWhereInput!] 874 | } 875 | 876 | input PublisherWhereUniqueInput { 877 | id: ID 878 | } 879 | 880 | type Query { 881 | book(where: BookWhereUniqueInput!): Book 882 | books(where: BookWhereInput, orderBy: BookOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Book]! 883 | booksConnection(where: BookWhereInput, orderBy: BookOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): BookConnection! 884 | publisher(where: PublisherWhereUniqueInput!): Publisher 885 | publishers(where: PublisherWhereInput, orderBy: PublisherOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Publisher]! 886 | publishersConnection(where: PublisherWhereInput, orderBy: PublisherOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): PublisherConnection! 887 | rating(where: RatingWhereUniqueInput!): Rating 888 | ratings(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Rating]! 889 | ratingsConnection(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): RatingConnection! 890 | review(where: ReviewWhereUniqueInput!): Review 891 | reviews(where: ReviewWhereInput, orderBy: ReviewOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Review]! 892 | reviewsConnection(where: ReviewWhereInput, orderBy: ReviewOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): ReviewConnection! 893 | user(where: UserWhereUniqueInput!): User 894 | users(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]! 895 | usersConnection(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): UserConnection! 896 | node(id: ID!): Node 897 | } 898 | 899 | type Rating { 900 | id: ID! 901 | rating: Int! 902 | rater: User! 903 | book: Book! 904 | createdAt: DateTime! 905 | } 906 | 907 | type RatingConnection { 908 | pageInfo: PageInfo! 909 | edges: [RatingEdge]! 910 | aggregate: AggregateRating! 911 | } 912 | 913 | input RatingCreateInput { 914 | rating: Int! 915 | rater: UserCreateOneWithoutRatingsInput! 916 | book: BookCreateOneWithoutRatingsInput! 917 | } 918 | 919 | input RatingCreateManyWithoutBookInput { 920 | create: [RatingCreateWithoutBookInput!] 921 | connect: [RatingWhereUniqueInput!] 922 | } 923 | 924 | input RatingCreateManyWithoutRaterInput { 925 | create: [RatingCreateWithoutRaterInput!] 926 | connect: [RatingWhereUniqueInput!] 927 | } 928 | 929 | input RatingCreateWithoutBookInput { 930 | rating: Int! 931 | rater: UserCreateOneWithoutRatingsInput! 932 | } 933 | 934 | input RatingCreateWithoutRaterInput { 935 | rating: Int! 936 | book: BookCreateOneWithoutRatingsInput! 937 | } 938 | 939 | type RatingEdge { 940 | node: Rating! 941 | cursor: String! 942 | } 943 | 944 | enum RatingOrderByInput { 945 | id_ASC 946 | id_DESC 947 | rating_ASC 948 | rating_DESC 949 | createdAt_ASC 950 | createdAt_DESC 951 | updatedAt_ASC 952 | updatedAt_DESC 953 | } 954 | 955 | type RatingPreviousValues { 956 | id: ID! 957 | rating: Int! 958 | createdAt: DateTime! 959 | } 960 | 961 | input RatingScalarWhereInput { 962 | id: ID 963 | id_not: ID 964 | id_in: [ID!] 965 | id_not_in: [ID!] 966 | id_lt: ID 967 | id_lte: ID 968 | id_gt: ID 969 | id_gte: ID 970 | id_contains: ID 971 | id_not_contains: ID 972 | id_starts_with: ID 973 | id_not_starts_with: ID 974 | id_ends_with: ID 975 | id_not_ends_with: ID 976 | rating: Int 977 | rating_not: Int 978 | rating_in: [Int!] 979 | rating_not_in: [Int!] 980 | rating_lt: Int 981 | rating_lte: Int 982 | rating_gt: Int 983 | rating_gte: Int 984 | createdAt: DateTime 985 | createdAt_not: DateTime 986 | createdAt_in: [DateTime!] 987 | createdAt_not_in: [DateTime!] 988 | createdAt_lt: DateTime 989 | createdAt_lte: DateTime 990 | createdAt_gt: DateTime 991 | createdAt_gte: DateTime 992 | AND: [RatingScalarWhereInput!] 993 | OR: [RatingScalarWhereInput!] 994 | NOT: [RatingScalarWhereInput!] 995 | } 996 | 997 | type RatingSubscriptionPayload { 998 | mutation: MutationType! 999 | node: Rating 1000 | updatedFields: [String!] 1001 | previousValues: RatingPreviousValues 1002 | } 1003 | 1004 | input RatingSubscriptionWhereInput { 1005 | mutation_in: [MutationType!] 1006 | updatedFields_contains: String 1007 | updatedFields_contains_every: [String!] 1008 | updatedFields_contains_some: [String!] 1009 | node: RatingWhereInput 1010 | AND: [RatingSubscriptionWhereInput!] 1011 | OR: [RatingSubscriptionWhereInput!] 1012 | NOT: [RatingSubscriptionWhereInput!] 1013 | } 1014 | 1015 | input RatingUpdateInput { 1016 | rating: Int 1017 | rater: UserUpdateOneRequiredWithoutRatingsInput 1018 | book: BookUpdateOneRequiredWithoutRatingsInput 1019 | } 1020 | 1021 | input RatingUpdateManyDataInput { 1022 | rating: Int 1023 | } 1024 | 1025 | input RatingUpdateManyMutationInput { 1026 | rating: Int 1027 | } 1028 | 1029 | input RatingUpdateManyWithoutBookInput { 1030 | create: [RatingCreateWithoutBookInput!] 1031 | delete: [RatingWhereUniqueInput!] 1032 | connect: [RatingWhereUniqueInput!] 1033 | disconnect: [RatingWhereUniqueInput!] 1034 | update: [RatingUpdateWithWhereUniqueWithoutBookInput!] 1035 | upsert: [RatingUpsertWithWhereUniqueWithoutBookInput!] 1036 | deleteMany: [RatingScalarWhereInput!] 1037 | updateMany: [RatingUpdateManyWithWhereNestedInput!] 1038 | } 1039 | 1040 | input RatingUpdateManyWithoutRaterInput { 1041 | create: [RatingCreateWithoutRaterInput!] 1042 | delete: [RatingWhereUniqueInput!] 1043 | connect: [RatingWhereUniqueInput!] 1044 | disconnect: [RatingWhereUniqueInput!] 1045 | update: [RatingUpdateWithWhereUniqueWithoutRaterInput!] 1046 | upsert: [RatingUpsertWithWhereUniqueWithoutRaterInput!] 1047 | deleteMany: [RatingScalarWhereInput!] 1048 | updateMany: [RatingUpdateManyWithWhereNestedInput!] 1049 | } 1050 | 1051 | input RatingUpdateManyWithWhereNestedInput { 1052 | where: RatingScalarWhereInput! 1053 | data: RatingUpdateManyDataInput! 1054 | } 1055 | 1056 | input RatingUpdateWithoutBookDataInput { 1057 | rating: Int 1058 | rater: UserUpdateOneRequiredWithoutRatingsInput 1059 | } 1060 | 1061 | input RatingUpdateWithoutRaterDataInput { 1062 | rating: Int 1063 | book: BookUpdateOneRequiredWithoutRatingsInput 1064 | } 1065 | 1066 | input RatingUpdateWithWhereUniqueWithoutBookInput { 1067 | where: RatingWhereUniqueInput! 1068 | data: RatingUpdateWithoutBookDataInput! 1069 | } 1070 | 1071 | input RatingUpdateWithWhereUniqueWithoutRaterInput { 1072 | where: RatingWhereUniqueInput! 1073 | data: RatingUpdateWithoutRaterDataInput! 1074 | } 1075 | 1076 | input RatingUpsertWithWhereUniqueWithoutBookInput { 1077 | where: RatingWhereUniqueInput! 1078 | update: RatingUpdateWithoutBookDataInput! 1079 | create: RatingCreateWithoutBookInput! 1080 | } 1081 | 1082 | input RatingUpsertWithWhereUniqueWithoutRaterInput { 1083 | where: RatingWhereUniqueInput! 1084 | update: RatingUpdateWithoutRaterDataInput! 1085 | create: RatingCreateWithoutRaterInput! 1086 | } 1087 | 1088 | input RatingWhereInput { 1089 | id: ID 1090 | id_not: ID 1091 | id_in: [ID!] 1092 | id_not_in: [ID!] 1093 | id_lt: ID 1094 | id_lte: ID 1095 | id_gt: ID 1096 | id_gte: ID 1097 | id_contains: ID 1098 | id_not_contains: ID 1099 | id_starts_with: ID 1100 | id_not_starts_with: ID 1101 | id_ends_with: ID 1102 | id_not_ends_with: ID 1103 | rating: Int 1104 | rating_not: Int 1105 | rating_in: [Int!] 1106 | rating_not_in: [Int!] 1107 | rating_lt: Int 1108 | rating_lte: Int 1109 | rating_gt: Int 1110 | rating_gte: Int 1111 | rater: UserWhereInput 1112 | book: BookWhereInput 1113 | createdAt: DateTime 1114 | createdAt_not: DateTime 1115 | createdAt_in: [DateTime!] 1116 | createdAt_not_in: [DateTime!] 1117 | createdAt_lt: DateTime 1118 | createdAt_lte: DateTime 1119 | createdAt_gt: DateTime 1120 | createdAt_gte: DateTime 1121 | AND: [RatingWhereInput!] 1122 | OR: [RatingWhereInput!] 1123 | NOT: [RatingWhereInput!] 1124 | } 1125 | 1126 | input RatingWhereUniqueInput { 1127 | id: ID 1128 | } 1129 | 1130 | type Review { 1131 | id: ID! 1132 | review: String! 1133 | reviewer: User! 1134 | book: Book! 1135 | createdAt: DateTime! 1136 | } 1137 | 1138 | type ReviewConnection { 1139 | pageInfo: PageInfo! 1140 | edges: [ReviewEdge]! 1141 | aggregate: AggregateReview! 1142 | } 1143 | 1144 | input ReviewCreateInput { 1145 | review: String! 1146 | reviewer: UserCreateOneWithoutReviewsInput! 1147 | book: BookCreateOneWithoutReviewsInput! 1148 | } 1149 | 1150 | input ReviewCreateManyWithoutBookInput { 1151 | create: [ReviewCreateWithoutBookInput!] 1152 | connect: [ReviewWhereUniqueInput!] 1153 | } 1154 | 1155 | input ReviewCreateManyWithoutReviewerInput { 1156 | create: [ReviewCreateWithoutReviewerInput!] 1157 | connect: [ReviewWhereUniqueInput!] 1158 | } 1159 | 1160 | input ReviewCreateWithoutBookInput { 1161 | review: String! 1162 | reviewer: UserCreateOneWithoutReviewsInput! 1163 | } 1164 | 1165 | input ReviewCreateWithoutReviewerInput { 1166 | review: String! 1167 | book: BookCreateOneWithoutReviewsInput! 1168 | } 1169 | 1170 | type ReviewEdge { 1171 | node: Review! 1172 | cursor: String! 1173 | } 1174 | 1175 | enum ReviewOrderByInput { 1176 | id_ASC 1177 | id_DESC 1178 | review_ASC 1179 | review_DESC 1180 | createdAt_ASC 1181 | createdAt_DESC 1182 | updatedAt_ASC 1183 | updatedAt_DESC 1184 | } 1185 | 1186 | type ReviewPreviousValues { 1187 | id: ID! 1188 | review: String! 1189 | createdAt: DateTime! 1190 | } 1191 | 1192 | input ReviewScalarWhereInput { 1193 | id: ID 1194 | id_not: ID 1195 | id_in: [ID!] 1196 | id_not_in: [ID!] 1197 | id_lt: ID 1198 | id_lte: ID 1199 | id_gt: ID 1200 | id_gte: ID 1201 | id_contains: ID 1202 | id_not_contains: ID 1203 | id_starts_with: ID 1204 | id_not_starts_with: ID 1205 | id_ends_with: ID 1206 | id_not_ends_with: ID 1207 | review: String 1208 | review_not: String 1209 | review_in: [String!] 1210 | review_not_in: [String!] 1211 | review_lt: String 1212 | review_lte: String 1213 | review_gt: String 1214 | review_gte: String 1215 | review_contains: String 1216 | review_not_contains: String 1217 | review_starts_with: String 1218 | review_not_starts_with: String 1219 | review_ends_with: String 1220 | review_not_ends_with: String 1221 | createdAt: DateTime 1222 | createdAt_not: DateTime 1223 | createdAt_in: [DateTime!] 1224 | createdAt_not_in: [DateTime!] 1225 | createdAt_lt: DateTime 1226 | createdAt_lte: DateTime 1227 | createdAt_gt: DateTime 1228 | createdAt_gte: DateTime 1229 | AND: [ReviewScalarWhereInput!] 1230 | OR: [ReviewScalarWhereInput!] 1231 | NOT: [ReviewScalarWhereInput!] 1232 | } 1233 | 1234 | type ReviewSubscriptionPayload { 1235 | mutation: MutationType! 1236 | node: Review 1237 | updatedFields: [String!] 1238 | previousValues: ReviewPreviousValues 1239 | } 1240 | 1241 | input ReviewSubscriptionWhereInput { 1242 | mutation_in: [MutationType!] 1243 | updatedFields_contains: String 1244 | updatedFields_contains_every: [String!] 1245 | updatedFields_contains_some: [String!] 1246 | node: ReviewWhereInput 1247 | AND: [ReviewSubscriptionWhereInput!] 1248 | OR: [ReviewSubscriptionWhereInput!] 1249 | NOT: [ReviewSubscriptionWhereInput!] 1250 | } 1251 | 1252 | input ReviewUpdateInput { 1253 | review: String 1254 | reviewer: UserUpdateOneRequiredWithoutReviewsInput 1255 | book: BookUpdateOneRequiredWithoutReviewsInput 1256 | } 1257 | 1258 | input ReviewUpdateManyDataInput { 1259 | review: String 1260 | } 1261 | 1262 | input ReviewUpdateManyMutationInput { 1263 | review: String 1264 | } 1265 | 1266 | input ReviewUpdateManyWithoutBookInput { 1267 | create: [ReviewCreateWithoutBookInput!] 1268 | delete: [ReviewWhereUniqueInput!] 1269 | connect: [ReviewWhereUniqueInput!] 1270 | disconnect: [ReviewWhereUniqueInput!] 1271 | update: [ReviewUpdateWithWhereUniqueWithoutBookInput!] 1272 | upsert: [ReviewUpsertWithWhereUniqueWithoutBookInput!] 1273 | deleteMany: [ReviewScalarWhereInput!] 1274 | updateMany: [ReviewUpdateManyWithWhereNestedInput!] 1275 | } 1276 | 1277 | input ReviewUpdateManyWithoutReviewerInput { 1278 | create: [ReviewCreateWithoutReviewerInput!] 1279 | delete: [ReviewWhereUniqueInput!] 1280 | connect: [ReviewWhereUniqueInput!] 1281 | disconnect: [ReviewWhereUniqueInput!] 1282 | update: [ReviewUpdateWithWhereUniqueWithoutReviewerInput!] 1283 | upsert: [ReviewUpsertWithWhereUniqueWithoutReviewerInput!] 1284 | deleteMany: [ReviewScalarWhereInput!] 1285 | updateMany: [ReviewUpdateManyWithWhereNestedInput!] 1286 | } 1287 | 1288 | input ReviewUpdateManyWithWhereNestedInput { 1289 | where: ReviewScalarWhereInput! 1290 | data: ReviewUpdateManyDataInput! 1291 | } 1292 | 1293 | input ReviewUpdateWithoutBookDataInput { 1294 | review: String 1295 | reviewer: UserUpdateOneRequiredWithoutReviewsInput 1296 | } 1297 | 1298 | input ReviewUpdateWithoutReviewerDataInput { 1299 | review: String 1300 | book: BookUpdateOneRequiredWithoutReviewsInput 1301 | } 1302 | 1303 | input ReviewUpdateWithWhereUniqueWithoutBookInput { 1304 | where: ReviewWhereUniqueInput! 1305 | data: ReviewUpdateWithoutBookDataInput! 1306 | } 1307 | 1308 | input ReviewUpdateWithWhereUniqueWithoutReviewerInput { 1309 | where: ReviewWhereUniqueInput! 1310 | data: ReviewUpdateWithoutReviewerDataInput! 1311 | } 1312 | 1313 | input ReviewUpsertWithWhereUniqueWithoutBookInput { 1314 | where: ReviewWhereUniqueInput! 1315 | update: ReviewUpdateWithoutBookDataInput! 1316 | create: ReviewCreateWithoutBookInput! 1317 | } 1318 | 1319 | input ReviewUpsertWithWhereUniqueWithoutReviewerInput { 1320 | where: ReviewWhereUniqueInput! 1321 | update: ReviewUpdateWithoutReviewerDataInput! 1322 | create: ReviewCreateWithoutReviewerInput! 1323 | } 1324 | 1325 | input ReviewWhereInput { 1326 | id: ID 1327 | id_not: ID 1328 | id_in: [ID!] 1329 | id_not_in: [ID!] 1330 | id_lt: ID 1331 | id_lte: ID 1332 | id_gt: ID 1333 | id_gte: ID 1334 | id_contains: ID 1335 | id_not_contains: ID 1336 | id_starts_with: ID 1337 | id_not_starts_with: ID 1338 | id_ends_with: ID 1339 | id_not_ends_with: ID 1340 | review: String 1341 | review_not: String 1342 | review_in: [String!] 1343 | review_not_in: [String!] 1344 | review_lt: String 1345 | review_lte: String 1346 | review_gt: String 1347 | review_gte: String 1348 | review_contains: String 1349 | review_not_contains: String 1350 | review_starts_with: String 1351 | review_not_starts_with: String 1352 | review_ends_with: String 1353 | review_not_ends_with: String 1354 | reviewer: UserWhereInput 1355 | book: BookWhereInput 1356 | createdAt: DateTime 1357 | createdAt_not: DateTime 1358 | createdAt_in: [DateTime!] 1359 | createdAt_not_in: [DateTime!] 1360 | createdAt_lt: DateTime 1361 | createdAt_lte: DateTime 1362 | createdAt_gt: DateTime 1363 | createdAt_gte: DateTime 1364 | AND: [ReviewWhereInput!] 1365 | OR: [ReviewWhereInput!] 1366 | NOT: [ReviewWhereInput!] 1367 | } 1368 | 1369 | input ReviewWhereUniqueInput { 1370 | id: ID 1371 | } 1372 | 1373 | type Subscription { 1374 | book(where: BookSubscriptionWhereInput): BookSubscriptionPayload 1375 | publisher(where: PublisherSubscriptionWhereInput): PublisherSubscriptionPayload 1376 | rating(where: RatingSubscriptionWhereInput): RatingSubscriptionPayload 1377 | review(where: ReviewSubscriptionWhereInput): ReviewSubscriptionPayload 1378 | user(where: UserSubscriptionWhereInput): UserSubscriptionPayload 1379 | } 1380 | 1381 | type User { 1382 | id: ID! 1383 | firstName: String! 1384 | lastName: String! 1385 | type: EnumUserRole 1386 | email: String! 1387 | password: String 1388 | books(where: BookWhereInput, orderBy: BookOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Book!] 1389 | reviews(where: ReviewWhereInput, orderBy: ReviewOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Review!] 1390 | ratings(where: RatingWhereInput, orderBy: RatingOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Rating!] 1391 | createdAt: DateTime! 1392 | updatedAt: DateTime! 1393 | } 1394 | 1395 | type UserConnection { 1396 | pageInfo: PageInfo! 1397 | edges: [UserEdge]! 1398 | aggregate: AggregateUser! 1399 | } 1400 | 1401 | input UserCreateInput { 1402 | firstName: String! 1403 | lastName: String! 1404 | type: EnumUserRole 1405 | email: String! 1406 | password: String 1407 | books: BookCreateManyWithoutAuthorsInput 1408 | reviews: ReviewCreateManyWithoutReviewerInput 1409 | ratings: RatingCreateManyWithoutRaterInput 1410 | } 1411 | 1412 | input UserCreateManyWithoutBooksInput { 1413 | create: [UserCreateWithoutBooksInput!] 1414 | connect: [UserWhereUniqueInput!] 1415 | } 1416 | 1417 | input UserCreateOneWithoutRatingsInput { 1418 | create: UserCreateWithoutRatingsInput 1419 | connect: UserWhereUniqueInput 1420 | } 1421 | 1422 | input UserCreateOneWithoutReviewsInput { 1423 | create: UserCreateWithoutReviewsInput 1424 | connect: UserWhereUniqueInput 1425 | } 1426 | 1427 | input UserCreateWithoutBooksInput { 1428 | firstName: String! 1429 | lastName: String! 1430 | type: EnumUserRole 1431 | email: String! 1432 | password: String 1433 | reviews: ReviewCreateManyWithoutReviewerInput 1434 | ratings: RatingCreateManyWithoutRaterInput 1435 | } 1436 | 1437 | input UserCreateWithoutRatingsInput { 1438 | firstName: String! 1439 | lastName: String! 1440 | type: EnumUserRole 1441 | email: String! 1442 | password: String 1443 | books: BookCreateManyWithoutAuthorsInput 1444 | reviews: ReviewCreateManyWithoutReviewerInput 1445 | } 1446 | 1447 | input UserCreateWithoutReviewsInput { 1448 | firstName: String! 1449 | lastName: String! 1450 | type: EnumUserRole 1451 | email: String! 1452 | password: String 1453 | books: BookCreateManyWithoutAuthorsInput 1454 | ratings: RatingCreateManyWithoutRaterInput 1455 | } 1456 | 1457 | type UserEdge { 1458 | node: User! 1459 | cursor: String! 1460 | } 1461 | 1462 | enum UserOrderByInput { 1463 | id_ASC 1464 | id_DESC 1465 | firstName_ASC 1466 | firstName_DESC 1467 | lastName_ASC 1468 | lastName_DESC 1469 | type_ASC 1470 | type_DESC 1471 | email_ASC 1472 | email_DESC 1473 | password_ASC 1474 | password_DESC 1475 | createdAt_ASC 1476 | createdAt_DESC 1477 | updatedAt_ASC 1478 | updatedAt_DESC 1479 | } 1480 | 1481 | type UserPreviousValues { 1482 | id: ID! 1483 | firstName: String! 1484 | lastName: String! 1485 | type: EnumUserRole 1486 | email: String! 1487 | password: String 1488 | createdAt: DateTime! 1489 | updatedAt: DateTime! 1490 | } 1491 | 1492 | input UserScalarWhereInput { 1493 | id: ID 1494 | id_not: ID 1495 | id_in: [ID!] 1496 | id_not_in: [ID!] 1497 | id_lt: ID 1498 | id_lte: ID 1499 | id_gt: ID 1500 | id_gte: ID 1501 | id_contains: ID 1502 | id_not_contains: ID 1503 | id_starts_with: ID 1504 | id_not_starts_with: ID 1505 | id_ends_with: ID 1506 | id_not_ends_with: ID 1507 | firstName: String 1508 | firstName_not: String 1509 | firstName_in: [String!] 1510 | firstName_not_in: [String!] 1511 | firstName_lt: String 1512 | firstName_lte: String 1513 | firstName_gt: String 1514 | firstName_gte: String 1515 | firstName_contains: String 1516 | firstName_not_contains: String 1517 | firstName_starts_with: String 1518 | firstName_not_starts_with: String 1519 | firstName_ends_with: String 1520 | firstName_not_ends_with: String 1521 | lastName: String 1522 | lastName_not: String 1523 | lastName_in: [String!] 1524 | lastName_not_in: [String!] 1525 | lastName_lt: String 1526 | lastName_lte: String 1527 | lastName_gt: String 1528 | lastName_gte: String 1529 | lastName_contains: String 1530 | lastName_not_contains: String 1531 | lastName_starts_with: String 1532 | lastName_not_starts_with: String 1533 | lastName_ends_with: String 1534 | lastName_not_ends_with: String 1535 | type: EnumUserRole 1536 | type_not: EnumUserRole 1537 | type_in: [EnumUserRole!] 1538 | type_not_in: [EnumUserRole!] 1539 | email: String 1540 | email_not: String 1541 | email_in: [String!] 1542 | email_not_in: [String!] 1543 | email_lt: String 1544 | email_lte: String 1545 | email_gt: String 1546 | email_gte: String 1547 | email_contains: String 1548 | email_not_contains: String 1549 | email_starts_with: String 1550 | email_not_starts_with: String 1551 | email_ends_with: String 1552 | email_not_ends_with: String 1553 | password: String 1554 | password_not: String 1555 | password_in: [String!] 1556 | password_not_in: [String!] 1557 | password_lt: String 1558 | password_lte: String 1559 | password_gt: String 1560 | password_gte: String 1561 | password_contains: String 1562 | password_not_contains: String 1563 | password_starts_with: String 1564 | password_not_starts_with: String 1565 | password_ends_with: String 1566 | password_not_ends_with: String 1567 | createdAt: DateTime 1568 | createdAt_not: DateTime 1569 | createdAt_in: [DateTime!] 1570 | createdAt_not_in: [DateTime!] 1571 | createdAt_lt: DateTime 1572 | createdAt_lte: DateTime 1573 | createdAt_gt: DateTime 1574 | createdAt_gte: DateTime 1575 | updatedAt: DateTime 1576 | updatedAt_not: DateTime 1577 | updatedAt_in: [DateTime!] 1578 | updatedAt_not_in: [DateTime!] 1579 | updatedAt_lt: DateTime 1580 | updatedAt_lte: DateTime 1581 | updatedAt_gt: DateTime 1582 | updatedAt_gte: DateTime 1583 | AND: [UserScalarWhereInput!] 1584 | OR: [UserScalarWhereInput!] 1585 | NOT: [UserScalarWhereInput!] 1586 | } 1587 | 1588 | type UserSubscriptionPayload { 1589 | mutation: MutationType! 1590 | node: User 1591 | updatedFields: [String!] 1592 | previousValues: UserPreviousValues 1593 | } 1594 | 1595 | input UserSubscriptionWhereInput { 1596 | mutation_in: [MutationType!] 1597 | updatedFields_contains: String 1598 | updatedFields_contains_every: [String!] 1599 | updatedFields_contains_some: [String!] 1600 | node: UserWhereInput 1601 | AND: [UserSubscriptionWhereInput!] 1602 | OR: [UserSubscriptionWhereInput!] 1603 | NOT: [UserSubscriptionWhereInput!] 1604 | } 1605 | 1606 | input UserUpdateInput { 1607 | firstName: String 1608 | lastName: String 1609 | type: EnumUserRole 1610 | email: String 1611 | password: String 1612 | books: BookUpdateManyWithoutAuthorsInput 1613 | reviews: ReviewUpdateManyWithoutReviewerInput 1614 | ratings: RatingUpdateManyWithoutRaterInput 1615 | } 1616 | 1617 | input UserUpdateManyDataInput { 1618 | firstName: String 1619 | lastName: String 1620 | type: EnumUserRole 1621 | email: String 1622 | password: String 1623 | } 1624 | 1625 | input UserUpdateManyMutationInput { 1626 | firstName: String 1627 | lastName: String 1628 | type: EnumUserRole 1629 | email: String 1630 | password: String 1631 | } 1632 | 1633 | input UserUpdateManyWithoutBooksInput { 1634 | create: [UserCreateWithoutBooksInput!] 1635 | delete: [UserWhereUniqueInput!] 1636 | connect: [UserWhereUniqueInput!] 1637 | disconnect: [UserWhereUniqueInput!] 1638 | update: [UserUpdateWithWhereUniqueWithoutBooksInput!] 1639 | upsert: [UserUpsertWithWhereUniqueWithoutBooksInput!] 1640 | deleteMany: [UserScalarWhereInput!] 1641 | updateMany: [UserUpdateManyWithWhereNestedInput!] 1642 | } 1643 | 1644 | input UserUpdateManyWithWhereNestedInput { 1645 | where: UserScalarWhereInput! 1646 | data: UserUpdateManyDataInput! 1647 | } 1648 | 1649 | input UserUpdateOneRequiredWithoutRatingsInput { 1650 | create: UserCreateWithoutRatingsInput 1651 | update: UserUpdateWithoutRatingsDataInput 1652 | upsert: UserUpsertWithoutRatingsInput 1653 | connect: UserWhereUniqueInput 1654 | } 1655 | 1656 | input UserUpdateOneRequiredWithoutReviewsInput { 1657 | create: UserCreateWithoutReviewsInput 1658 | update: UserUpdateWithoutReviewsDataInput 1659 | upsert: UserUpsertWithoutReviewsInput 1660 | connect: UserWhereUniqueInput 1661 | } 1662 | 1663 | input UserUpdateWithoutBooksDataInput { 1664 | firstName: String 1665 | lastName: String 1666 | type: EnumUserRole 1667 | email: String 1668 | password: String 1669 | reviews: ReviewUpdateManyWithoutReviewerInput 1670 | ratings: RatingUpdateManyWithoutRaterInput 1671 | } 1672 | 1673 | input UserUpdateWithoutRatingsDataInput { 1674 | firstName: String 1675 | lastName: String 1676 | type: EnumUserRole 1677 | email: String 1678 | password: String 1679 | books: BookUpdateManyWithoutAuthorsInput 1680 | reviews: ReviewUpdateManyWithoutReviewerInput 1681 | } 1682 | 1683 | input UserUpdateWithoutReviewsDataInput { 1684 | firstName: String 1685 | lastName: String 1686 | type: EnumUserRole 1687 | email: String 1688 | password: String 1689 | books: BookUpdateManyWithoutAuthorsInput 1690 | ratings: RatingUpdateManyWithoutRaterInput 1691 | } 1692 | 1693 | input UserUpdateWithWhereUniqueWithoutBooksInput { 1694 | where: UserWhereUniqueInput! 1695 | data: UserUpdateWithoutBooksDataInput! 1696 | } 1697 | 1698 | input UserUpsertWithoutRatingsInput { 1699 | update: UserUpdateWithoutRatingsDataInput! 1700 | create: UserCreateWithoutRatingsInput! 1701 | } 1702 | 1703 | input UserUpsertWithoutReviewsInput { 1704 | update: UserUpdateWithoutReviewsDataInput! 1705 | create: UserCreateWithoutReviewsInput! 1706 | } 1707 | 1708 | input UserUpsertWithWhereUniqueWithoutBooksInput { 1709 | where: UserWhereUniqueInput! 1710 | update: UserUpdateWithoutBooksDataInput! 1711 | create: UserCreateWithoutBooksInput! 1712 | } 1713 | 1714 | input UserWhereInput { 1715 | id: ID 1716 | id_not: ID 1717 | id_in: [ID!] 1718 | id_not_in: [ID!] 1719 | id_lt: ID 1720 | id_lte: ID 1721 | id_gt: ID 1722 | id_gte: ID 1723 | id_contains: ID 1724 | id_not_contains: ID 1725 | id_starts_with: ID 1726 | id_not_starts_with: ID 1727 | id_ends_with: ID 1728 | id_not_ends_with: ID 1729 | firstName: String 1730 | firstName_not: String 1731 | firstName_in: [String!] 1732 | firstName_not_in: [String!] 1733 | firstName_lt: String 1734 | firstName_lte: String 1735 | firstName_gt: String 1736 | firstName_gte: String 1737 | firstName_contains: String 1738 | firstName_not_contains: String 1739 | firstName_starts_with: String 1740 | firstName_not_starts_with: String 1741 | firstName_ends_with: String 1742 | firstName_not_ends_with: String 1743 | lastName: String 1744 | lastName_not: String 1745 | lastName_in: [String!] 1746 | lastName_not_in: [String!] 1747 | lastName_lt: String 1748 | lastName_lte: String 1749 | lastName_gt: String 1750 | lastName_gte: String 1751 | lastName_contains: String 1752 | lastName_not_contains: String 1753 | lastName_starts_with: String 1754 | lastName_not_starts_with: String 1755 | lastName_ends_with: String 1756 | lastName_not_ends_with: String 1757 | type: EnumUserRole 1758 | type_not: EnumUserRole 1759 | type_in: [EnumUserRole!] 1760 | type_not_in: [EnumUserRole!] 1761 | email: String 1762 | email_not: String 1763 | email_in: [String!] 1764 | email_not_in: [String!] 1765 | email_lt: String 1766 | email_lte: String 1767 | email_gt: String 1768 | email_gte: String 1769 | email_contains: String 1770 | email_not_contains: String 1771 | email_starts_with: String 1772 | email_not_starts_with: String 1773 | email_ends_with: String 1774 | email_not_ends_with: String 1775 | password: String 1776 | password_not: String 1777 | password_in: [String!] 1778 | password_not_in: [String!] 1779 | password_lt: String 1780 | password_lte: String 1781 | password_gt: String 1782 | password_gte: String 1783 | password_contains: String 1784 | password_not_contains: String 1785 | password_starts_with: String 1786 | password_not_starts_with: String 1787 | password_ends_with: String 1788 | password_not_ends_with: String 1789 | books_every: BookWhereInput 1790 | books_some: BookWhereInput 1791 | books_none: BookWhereInput 1792 | reviews_every: ReviewWhereInput 1793 | reviews_some: ReviewWhereInput 1794 | reviews_none: ReviewWhereInput 1795 | ratings_every: RatingWhereInput 1796 | ratings_some: RatingWhereInput 1797 | ratings_none: RatingWhereInput 1798 | createdAt: DateTime 1799 | createdAt_not: DateTime 1800 | createdAt_in: [DateTime!] 1801 | createdAt_not_in: [DateTime!] 1802 | createdAt_lt: DateTime 1803 | createdAt_lte: DateTime 1804 | createdAt_gt: DateTime 1805 | createdAt_gte: DateTime 1806 | updatedAt: DateTime 1807 | updatedAt_not: DateTime 1808 | updatedAt_in: [DateTime!] 1809 | updatedAt_not_in: [DateTime!] 1810 | updatedAt_lt: DateTime 1811 | updatedAt_lte: DateTime 1812 | updatedAt_gt: DateTime 1813 | updatedAt_gte: DateTime 1814 | AND: [UserWhereInput!] 1815 | OR: [UserWhereInput!] 1816 | NOT: [UserWhereInput!] 1817 | } 1818 | 1819 | input UserWhereUniqueInput { 1820 | id: ID 1821 | email: String 1822 | } 1823 | `; 1824 | --------------------------------------------------------------------------------