Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use GraphQL Codegen to generate more accurate resolver types #5216

Merged
merged 8 commits into from
Apr 28, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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['createUser'] = ({ 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['createPost'] = ({ 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) { %>, ${singularCamelName}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['create${singularPascalName}'] = ({ id, input }) => {
dac09 marked this conversation as resolved.
Show resolved Hide resolved
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}: ${singularCamelName}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