Skip to content

Commit

Permalink
Use GraphQL Codegen to generate more accurate resolver types (#5216)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Choudhury <dannychoudhury@gmail.com>
  • Loading branch information
orta and dac09 committed Apr 28, 2022
1 parent ef5a3d5 commit 7ae7183
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,9 @@ describe('users', () => {

exports[`in typescript mode creates a multi word service file 1`] = `
"import { db } from 'src/lib/db'
import type { QueryResolvers } from 'types/graphql'
export const userProfiles = () => {
export const userProfiles: QueryResolvers['userProfiles'] = () => {
return db.userProfile.findMany()
}
"
Expand Down Expand Up @@ -369,42 +370,33 @@ describe('transactions', () => {
`;

exports[`in typescript mode creates a single word service file 1`] = `
"import type { Prisma } from '@prisma/client'
import { db } from 'src/lib/db'
"import { db } from 'src/lib/db'
import type { QueryResolvers, MutationResolvers } from 'types/graphql'
export const users = () => {
export const users: QueryResolvers['users'] = () => {
return db.user.findMany()
}
export const user = ({ id }: Prisma.UserWhereUniqueInput) => {
export const user: QueryResolvers['user'] = ({ id }) => {
return db.user.findUnique({
where: { id },
})
}
interface CreateUserArgs {
input: Prisma.UserCreateInput
}
export const createUser = ({ input }: CreateUserArgs) => {
export const createUser: MutationResolvers['createUser'] = ({ input }) => {
return db.user.create({
data: input,
})
}
interface UpdateUserArgs extends Prisma.UserWhereUniqueInput {
input: Prisma.UserUpdateInput
}
export const updateUser = ({ id, input }: UpdateUserArgs) => {
export const updateUser: MutationResolvers['updateUser'] = ({ id, input }) => {
return db.user.update({
data: input,
where: { id },
})
}
export const deleteUser = ({ id }: Prisma.UserWhereUniqueInput) => {
export const deleteUser: MutationResolvers['deleteUser'] = ({ id }) => {
return db.user.delete({
where: { id },
})
Expand All @@ -413,42 +405,33 @@ export const deleteUser = ({ id }: Prisma.UserWhereUniqueInput) => {
`;

exports[`in typescript mode creates a single word service file with CRUD actions 1`] = `
"import type { Prisma } from '@prisma/client'
import { db } from 'src/lib/db'
"import { db } from 'src/lib/db'
import type { QueryResolvers, MutationResolvers } from 'types/graphql'
export const posts = () => {
export const posts: QueryResolvers['posts'] = () => {
return db.post.findMany()
}
export const post = ({ id }: Prisma.PostWhereUniqueInput) => {
export const post: QueryResolvers['post'] = ({ id }) => {
return db.post.findUnique({
where: { id },
})
}
interface CreatePostArgs {
input: Prisma.PostCreateInput
}
export const createPost = ({ input }: CreatePostArgs) => {
export const createPost: MutationResolvers['createPost'] = ({ input }) => {
return db.post.create({
data: input,
})
}
interface UpdatePostArgs extends Prisma.PostWhereUniqueInput {
input: Prisma.PostUpdateInput
}
export const updatePost = ({ id, input }: UpdatePostArgs) => {
export const updatePost: MutationResolvers['updatePost'] = ({ id, input }) => {
return db.post.update({
data: input,
where: { id },
})
}
export const deletePost = ({ id }: Prisma.PostWhereUniqueInput) => {
export const deletePost: MutationResolvers['deletePost'] = ({ id }) => {
return db.post.delete({
where: { id },
})
Expand All @@ -457,71 +440,65 @@ export const deletePost = ({ id }: Prisma.PostWhereUniqueInput) => {
`;

exports[`in typescript mode creates a single word service file with a belongsTo relation 1`] = `
"import type { Prisma } from '@prisma/client'
import type { ResolverArgs } from '@redwoodjs/graphql-server'
import { db } from 'src/lib/db'
"import { db } from 'src/lib/db'
import type { QueryResolvers, UserResolvers } from 'types/graphql'
export const users = () => {
export const users: QueryResolvers['users'] = () => {
return db.user.findMany()
}
export const user = ({ id }: Prisma.UserWhereUniqueInput) => {
export const user: QueryResolvers['user'] = ({ id }) => {
return db.user.findUnique({
where: { id },
})
}
export const User = {
identity: (_obj, { root }: ResolverArgs<ReturnType<typeof user>>) =>
export const User: UserResolvers = {
identity: (_obj, { root }) =>
db.user.findUnique({ where: { id: root.id } }).identity(),
}
"
`;

exports[`in typescript mode creates a single word service file with a hasMany relation 1`] = `
"import type { Prisma } from '@prisma/client'
import type { ResolverArgs } from '@redwoodjs/graphql-server'
import { db } from 'src/lib/db'
"import { db } from 'src/lib/db'
import type { QueryResolvers, UserResolvers } from 'types/graphql'
export const users = () => {
export const users: QueryResolvers['users'] = () => {
return db.user.findMany()
}
export const user = ({ id }: Prisma.UserWhereUniqueInput) => {
export const user: QueryResolvers['user'] = ({ id }) => {
return db.user.findUnique({
where: { id },
})
}
export const User = {
userProfiles: (_obj, { root }: ResolverArgs<ReturnType<typeof user>>) =>
export const User: UserResolvers = {
userProfiles: (_obj, { root }) =>
db.user.findUnique({ where: { id: root.id } }).userProfiles(),
}
"
`;

exports[`in typescript mode creates a single word service file with multiple relations 1`] = `
"import type { Prisma } from '@prisma/client'
import type { ResolverArgs } from '@redwoodjs/graphql-server'
import { db } from 'src/lib/db'
"import { db } from 'src/lib/db'
import type { QueryResolvers, UserResolvers } from 'types/graphql'
export const users = () => {
export const users: QueryResolvers['users'] = () => {
return db.user.findMany()
}
export const user = ({ id }: Prisma.UserWhereUniqueInput) => {
export const user: QueryResolvers['user'] = ({ id }) => {
return db.user.findUnique({
where: { id },
})
}
export const User = {
userProfiles: (_obj, { root }: ResolverArgs<ReturnType<typeof user>>) =>
export const User: UserResolvers = {
userProfiles: (_obj, { root }) =>
db.user.findUnique({ where: { id: root.id } }).userProfiles(),
identity: (_obj, { root }: ResolverArgs<ReturnType<typeof user>>) =>
identity: (_obj, { root }) =>
db.user.findUnique({ where: { id: root.id } }).identity(),
}
"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,35 @@
<% if (crud || relations.length > 0) { %>import type { Prisma } from '@prisma/client'<% } %>
<% if (relations.length) { %>import type { ResolverArgs } from '@redwoodjs/graphql-server'<% } %>

import { db } from 'src/lib/db'
import type { QueryResolvers<% if (crud) { %>, MutationResolvers<% } %><% if (relations.length) { %>, ${singularPascalName}Resolvers<% } %> } from 'types/graphql'

export const ${pluralCamelName} = () => {
export const ${pluralCamelName}: QueryResolvers['${pluralCamelName}'] = () => {
return db.${singularCamelName}.findMany()
}<% if (crud || relations.length) { %>

export const ${singularCamelName} = ({ id }: Prisma.${singularPascalName}WhereUniqueInput) => {
export const ${singularCamelName}: QueryResolvers['${singularCamelName}'] = ({ id }) => {
return db.${singularCamelName}.findUnique({
where: { id },
})
}<% } %><% if (crud) { %>

interface Create${singularPascalName}Args {
input: Prisma.${singularPascalName}CreateInput
}

export const create${singularPascalName} = ({ input }: Create${singularPascalName}Args) => {
export const create${singularPascalName}: MutationResolvers['create${singularPascalName}'] = ({ input }) => {
return db.${singularCamelName}.create({
data: input,
})
}

interface Update${singularPascalName}Args extends Prisma.${singularPascalName}WhereUniqueInput {
input: Prisma.${singularPascalName}UpdateInput
}

export const update${singularPascalName} = ({ id, input }: Update${singularPascalName}Args) => {
export const update${singularPascalName}: MutationResolvers['update${singularPascalName}'] = ({ id, input }) => {
return db.${singularCamelName}.update({
data: input,
where: { id },
})
}

export const delete${singularPascalName} = ({ id }: Prisma.${singularPascalName}WhereUniqueInput) => {
export const delete${singularPascalName}: MutationResolvers['delete${singularPascalName}'] = ({ id }) => {
return db.${singularCamelName}.delete({
where: { id },
})
}<% } %><% if (relations.length) { %>

export const ${singularPascalName} = {<% relations.forEach(relation => { %>
${relation}: (_obj, { root }: ResolverArgs<ReturnType<typeof ${singularCamelName}>>) => db.${singularCamelName}.findUnique({ where: { id: root.id } }).${relation}(),<% }) %>
export const ${singularPascalName}: ${singularPascalName}Resolvers = {<% relations.forEach(relation => { %>
${relation}: (_obj, { root }) => db.${singularCamelName}.findUnique({ where: { id: root.id } }).${relation}(),<% }) %>
}<% } %>
6 changes: 5 additions & 1 deletion packages/graphql-server/src/functions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ export type GetCurrentUser = (

export type Context = Record<string, unknown>
export type ContextFunction = (...args: any[]) => Context | Promise<Context>
export type RedwoodGraphQLContext = {

/** This is an interface so you can extend it inside your application when needed */
export interface RedwoodGraphQLContext {
event: APIGatewayProxyEvent
requestContext: LambdaContext
currentUser?: ThenArg<ReturnType<GetCurrentUser>> | AuthContextPayload | null

[index: string]: unknown
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

exports[`Generate gql typedefs api 1`] = `
"import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql';
import { RedwoodGraphQLContext } from '@redwoodjs/graphql-server/dist/functions/types';
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type ResolverFn<TResult, TParent, TContext, TArgs> = (
args: TArgs,
obj: { root: TParent; context: TContext; info: GraphQLResolveInfo }
) => Promise<Partial<TResult>> | Partial<TResult>;
export type RequireFields<T, K extends keyof T> = Omit<T, K> & { [P in K]-?: NonNullable<T[P]> };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
Expand Down Expand Up @@ -79,13 +84,6 @@ export type ResolverWithResolve<TResult, TParent, TContext, TArgs> = {
};
export type Resolver<TResult, TParent = {}, TContext = {}, TArgs = {}> = ResolverFn<TResult, TParent, TContext, TArgs> | ResolverWithResolve<TResult, TParent, TContext, TArgs>;
export type ResolverFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => Promise<TResult> | TResult;
export type SubscriptionSubscribeFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
Expand Down Expand Up @@ -174,11 +172,11 @@ export type requireAuthDirectiveArgs = {
roles?: Maybe<Array<Maybe<Scalars['String']>>>;
};
export type requireAuthDirectiveResolver<Result, Parent, ContextType = any, Args = requireAuthDirectiveArgs> = DirectiveResolverFn<Result, Parent, ContextType, Args>;
export type requireAuthDirectiveResolver<Result, Parent, ContextType = RedwoodGraphQLContext, Args = requireAuthDirectiveArgs> = DirectiveResolverFn<Result, Parent, ContextType, Args>;
export type skipAuthDirectiveArgs = { };
export type skipAuthDirectiveResolver<Result, Parent, ContextType = any, Args = skipAuthDirectiveArgs> = DirectiveResolverFn<Result, Parent, ContextType, Args>;
export type skipAuthDirectiveResolver<Result, Parent, ContextType = RedwoodGraphQLContext, Args = skipAuthDirectiveArgs> = DirectiveResolverFn<Result, Parent, ContextType, Args>;
export interface BigIntScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['BigInt'], any> {
name: 'BigInt';
Expand All @@ -200,20 +198,20 @@ export interface JSONObjectScalarConfig extends GraphQLScalarTypeConfig<Resolver
name: 'JSONObject';
}
export type MutationResolvers<ContextType = any, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = {
export type MutationResolvers<ContextType = RedwoodGraphQLContext, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = {
createTodo?: Resolver<Maybe<ResolversTypes['Todo']>, ParentType, ContextType, RequireFields<MutationcreateTodoArgs, 'body'>>;
renameTodo?: Resolver<Maybe<ResolversTypes['Todo']>, ParentType, ContextType, RequireFields<MutationrenameTodoArgs, 'body' | 'id'>>;
updateTodoStatus?: Resolver<Maybe<ResolversTypes['Todo']>, ParentType, ContextType, RequireFields<MutationupdateTodoStatusArgs, 'id' | 'status'>>;
};
export type QueryResolvers<ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
export type QueryResolvers<ContextType = RedwoodGraphQLContext, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
currentUser?: Resolver<Maybe<ResolversTypes['JSON']>, ParentType, ContextType>;
redwood?: Resolver<Maybe<ResolversTypes['Redwood']>, ParentType, ContextType>;
todos?: Resolver<Maybe<Array<Maybe<ResolversTypes['Todo']>>>, ParentType, ContextType>;
todosCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
};
export type RedwoodResolvers<ContextType = any, ParentType extends ResolversParentTypes['Redwood'] = ResolversParentTypes['Redwood']> = {
export type RedwoodResolvers<ContextType = RedwoodGraphQLContext, ParentType extends ResolversParentTypes['Redwood'] = ResolversParentTypes['Redwood']> = {
currentUser?: Resolver<Maybe<ResolversTypes['JSON']>, ParentType, ContextType>;
prismaVersion?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
version?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
Expand All @@ -224,14 +222,14 @@ export interface TimeScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes
name: 'Time';
}
export type TodoResolvers<ContextType = any, ParentType extends ResolversParentTypes['Todo'] = ResolversParentTypes['Todo']> = {
export type TodoResolvers<ContextType = RedwoodGraphQLContext, ParentType extends ResolversParentTypes['Todo'] = ResolversParentTypes['Todo']> = {
body?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
id?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
status?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type Resolvers<ContextType = any> = {
export type Resolvers<ContextType = RedwoodGraphQLContext> = {
BigInt?: GraphQLScalarType;
Date?: GraphQLScalarType;
DateTime?: GraphQLScalarType;
Expand All @@ -244,7 +242,7 @@ export type Resolvers<ContextType = any> = {
Todo?: TodoResolvers<ContextType>;
};
export type DirectiveResolvers<ContextType = any> = {
export type DirectiveResolvers<ContextType = RedwoodGraphQLContext> = {
requireAuth?: requireAuthDirectiveResolver<any, any, ContextType>;
skipAuth?: skipAuthDirectiveResolver<any, any, ContextType>;
};
Expand Down

0 comments on commit 7ae7183

Please sign in to comment.