Skip to content
This repository has been archived by the owner on Dec 8, 2021. It is now read-only.

Commit

Permalink
feat(gg): simplify and make safer __resolveType (#411)
Browse files Browse the repository at this point in the history
* feat(gg): simplify and make safer resolver type resovler

Safer because:

- strings constants are used to specifiy which graphql
objects names may be returned.
- null cannot be returned
- undefined cannot be returned

Simpler because:

- no nesting of type-generics
- only permits returning names of graphql objects (not objects)

closes #409
  • Loading branch information
Jason Kuhrt authored Jan 25, 2019
1 parent 039fbe9 commit fb31ba7
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 40 deletions.
2 changes: 1 addition & 1 deletion packages/graphqlgen/src/generators/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ const array = (
return config.innerUnion ? `${innerType}[]` : `Array<${innerType}>`
}

const union = (types: string[]): string => {
export const union = (types: string[]): string => {
return types.join(' | ')
}

Expand Down
22 changes: 5 additions & 17 deletions packages/graphqlgen/src/generators/flow-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
createInterfacesMap,
createUnionsMap,
} from './common'
import { renderTypeResolveTypeResolver } from './ts-generator'

export function format(code: string, options: prettier.Options = {}) {
try {
Expand Down Expand Up @@ -76,11 +77,9 @@ export function generate(args: GenerateArgs): string {

const interfacesMap = createInterfacesMap(args.interfaces)
const unionsMap = createUnionsMap(args.unions)
const hasPolymorphicObjects =
Object.keys(interfacesMap).length > 0 || Object.keys(unionsMap).length > 0

return `\
${renderHeader(args, { hasPolymorphicObjects })}
${renderHeader(args)}
${renderEnums(args)}
Expand All @@ -97,14 +96,7 @@ export function generate(args: GenerateArgs): string {
`
}

type HeaderOptions = {
hasPolymorphicObjects?: boolean
}

function renderHeader(
args: GenerateArgs,
{ hasPolymorphicObjects = false }: HeaderOptions = {},
): string {
function renderHeader(args: GenerateArgs): string {
const modelsToImport = Object.keys(args.modelMap).map(k => args.modelMap[k])
const modelsByImportPaths = groupModelsNameByImportPath(modelsToImport)

Expand All @@ -117,9 +109,7 @@ function renderHeader(
)
.join(os.EOL)

const graphQLImports = hasPolymorphicObjects
? ['GraphQLResolveInfo', 'GraphQLTypeResolver']
: ['GraphQLResolveInfo']
const graphQLImports = ['GraphQLResolveInfo']

return `/* @flow */
// Code generated by github.com/prisma/graphqlgen, DO NOT EDIT.
Expand Down Expand Up @@ -223,9 +213,7 @@ function renderUnionNamespace(
): string {
return `\
export interface ${graphQLTypeObject.name}_Resolvers {
__resolveType?: GraphQLTypeResolver<${graphQLTypeObject.types
.map(interfaceType => getModelName(interfaceType, args.modelMap))
.join(' | ')}, ${getContextName(args.context)}>;
__resolveType?: ${renderTypeResolveTypeResolver(graphQLTypeObject, args)}
}
`
}
Expand Down
49 changes: 41 additions & 8 deletions packages/graphqlgen/src/generators/ts-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
UnionsMap,
createInterfacesMap,
createUnionsMap,
union,
} from './common'
import { TypeAliasDefinition } from '../introspection/types'
import { upperFirst } from '../utils'
Expand Down Expand Up @@ -108,7 +109,7 @@ function renderHeader(
{ hasPolymorphicObjects = false }: HeaderOptions = {},
): string {
const imports = hasPolymorphicObjects
? ['GraphQLResolveInfo', 'GraphQLTypeResolver', 'GraphQLIsTypeOfFn']
? ['GraphQLResolveInfo', 'GraphQLIsTypeOfFn']
: ['GraphQLResolveInfo']

return `
Expand Down Expand Up @@ -237,24 +238,50 @@ function renderInterfaceNamespace(
)}
export interface Type {
__resolveType: GraphQLTypeResolver<${graphQLTypeObject.implementors
.map(interfaceType => getModelName(interfaceType, args.modelMap))
.join(' | ')}, ${getContextName(args.context)}>;
__resolveType: ${renderTypeResolveTypeResolver(graphQLTypeObject, args)}
}
}
`
}

export const renderTypeResolveTypeResolver = (
abstractType: GraphQLInterfaceObject | GraphQLUnionObject,
args: GenerateArgs,
): string => {
const modelNames: string[] = []
const gqlObjectNameTypes: string[] = []
const gqlObjects =
abstractType.kind === 'interface'
? abstractType.implementors
: abstractType.types

for (const gqlObj of gqlObjects) {
modelNames.push(getModelName(gqlObj, args.modelMap))
gqlObjectNameTypes.push(renderStringConstant(gqlObj.name))
}

return `
(
value: ${union(modelNames)},
context: ${getContextName(args.context)},
info: GraphQLResolveInfo
) => ${resolverReturnType(union(gqlObjectNameTypes))}
`
}

const renderStringConstant = (x: unknown) => `"${x}"`

function renderUnionNamespace(
graphQLTypeObject: GraphQLUnionObject,
args: GenerateArgs,
): string {
return `\
export namespace ${graphQLTypeObject.name}Resolvers {
export interface Type {
__resolveType?: GraphQLTypeResolver<${graphQLTypeObject.types
.map(interfaceType => getModelName(interfaceType, args.modelMap))
.join(' | ')}, ${getContextName(args.context)}>;
__resolveType?: ${renderTypeResolveTypeResolver(
graphQLTypeObject,
args,
)}
}
}
`
Expand Down Expand Up @@ -430,6 +457,7 @@ function renderResolverFunctionInterfaces(
.join(os.EOL)
}

// MARK
function renderResolverFunctionInterface(
field: GraphQLTypeField,
type: GraphQLTypeObject,
Expand Down Expand Up @@ -468,10 +496,15 @@ function renderResolverFunctionInterface(
}

return `
export type ${resolverName} = ${resolverDefinition} => ${returnType} | Promise<${returnType}>
export type ${resolverName} = ${resolverDefinition} => ${resolverReturnType(
returnType,
)}
`
}

const resolverReturnType = (returnType: string): string =>
union([returnType, `Promise<${returnType}>`])

function renderResolverTypeInterface(
type: GraphQLTypeObject | GraphQLInterfaceObject,
modelMap: ModelMap,
Expand Down
4 changes: 4 additions & 0 deletions packages/graphqlgen/src/source-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ export type GraphQLEnumObject = {

export type GraphQLUnionObject = {
name: string
kind: 'union'
type: GraphQLTypeDefinition
types: GraphQLTypeDefinition[]
}

export type GraphQLInterfaceObject = {
name: string
kind: 'interface'
type: GraphQLTypeDefinition
fields: GraphQLTypeField[]
implementors: GraphQLTypeDefinition[]
Expand Down Expand Up @@ -345,6 +347,7 @@ function extractGraphQLUnions(schema: GraphQLSchema) {
})
types.push({
name: node.name,
kind: 'union',
type: {
name: node.name,
isObject: false,
Expand Down Expand Up @@ -380,6 +383,7 @@ function extractGraphQLInterfaces(
if (implementorTypes.length) {
interfaces.push({
name: node.name,
kind: 'interface',
type: {
name: node.name,
isObject: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ exports[`basic union 1`] = `
"/* @flow */
// Code generated by github.com/prisma/graphqlgen, DO NOT EDIT.
import type { GraphQLResolveInfo, GraphQLTypeResolver } from \\"graphql\\";
import type { GraphQLResolveInfo } from \\"graphql\\";
import type { Student, Professor, User } from \\"../../fixtures/union/flow-types\\";
type Context = any;
Expand Down Expand Up @@ -719,7 +719,11 @@ export interface User_Resolvers {
}
export interface UserType_Resolvers {
__resolveType?: GraphQLTypeResolver<Student | Professor, Context>;
__resolveType?: (
value: Student | Professor,
context: Context,
info: GraphQLResolveInfo
) => \\"Student\\" | \\"Professor\\" | Promise<\\"Student\\" | \\"Professor\\">;
}
export interface Resolvers {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,7 @@ export const resolvers: Resolvers = {
exports[`basic interface 1`] = `
"// Code generated by github.com/prisma/graphqlgen, DO NOT EDIT.

import {
GraphQLResolveInfo,
GraphQLTypeResolver,
GraphQLIsTypeOfFn
} from \\"graphql\\";
import { GraphQLResolveInfo, GraphQLIsTypeOfFn } from \\"graphql\\";
import { Dimensions, Image, Video } from \\"../../../fixtures/interface/types\\";
type Context = any;

Expand Down Expand Up @@ -518,7 +514,11 @@ export namespace VideoResolvers {

export namespace MediaResolvers {
export interface Type {
__resolveType: GraphQLTypeResolver<Image | Video, Context>;
__resolveType: (
value: Image | Video,
context: Context,
info: GraphQLResolveInfo
) => \\"Image\\" | \\"Video\\" | Promise<\\"Image\\" | \\"Video\\">;
}
}

Expand Down Expand Up @@ -1106,11 +1106,7 @@ export const resolvers: Resolvers = {
exports[`basic union 1`] = `
"// Code generated by github.com/prisma/graphqlgen, DO NOT EDIT.

import {
GraphQLResolveInfo,
GraphQLTypeResolver,
GraphQLIsTypeOfFn
} from \\"graphql\\";
import { GraphQLResolveInfo, GraphQLIsTypeOfFn } from \\"graphql\\";
import { Student, Professor, User } from \\"../../fixtures/union/types\\";
type Context = any;

Expand Down Expand Up @@ -1225,7 +1221,11 @@ export namespace UserResolvers {

export namespace UserTypeResolvers {
export interface Type {
__resolveType?: GraphQLTypeResolver<Student | Professor, Context>;
__resolveType?: (
value: Student | Professor,
context: Context,
info: GraphQLResolveInfo
) => \\"Student\\" | \\"Professor\\" | Promise<\\"Student\\" | \\"Professor\\">;
}
}

Expand Down

0 comments on commit fb31ba7

Please sign in to comment.