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

Interface and union resolvers #149

Merged
merged 21 commits into from
Jan 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/graphqlgen/benchmarks/micro/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Benchmark from '../lib/benchmark'

const type = {
name: 'Z',
implements: null,
type: {
name: 'Z',
isInput: false,
Expand All @@ -18,6 +19,7 @@ const type = {
const typeMap: Core.InputTypesMap = {
A: {
name: 'A',
implements: null,
type: {
name: 'A',
isInput: true,
Expand All @@ -41,6 +43,7 @@ const typeMap: Core.InputTypesMap = {
isUnion: false,
isRequired: false,
isArray: false,
isArrayRequired: false,
},
},
{
Expand All @@ -56,12 +59,14 @@ const typeMap: Core.InputTypesMap = {
isUnion: false,
isRequired: false,
isArray: false,
isArrayRequired: false,
},
},
],
},
B: {
name: 'B',
implements: null,
type: {
name: 'B',
isInput: true,
Expand All @@ -85,12 +90,14 @@ const typeMap: Core.InputTypesMap = {
isUnion: false,
isRequired: false,
isArray: false,
isArrayRequired: false,
},
},
],
},
C: {
name: 'C',
implements: null,
type: {
name: 'C',
isInput: true,
Expand All @@ -114,12 +121,14 @@ const typeMap: Core.InputTypesMap = {
isUnion: false,
isRequired: false,
isArray: false,
isArrayRequired: false,
},
},
],
},
D: {
name: 'D',
implements: null,
type: {
name: 'D',
isInput: true,
Expand All @@ -143,6 +152,7 @@ const typeMap: Core.InputTypesMap = {
isUnion: false,
isRequired: false,
isArray: false,
isArrayRequired: false,
},
},
],
Expand Down
1 change: 1 addition & 0 deletions packages/graphqlgen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"watch": "tsc -w",
"lint": "tslint --project tsconfig.json {src,test}/**/*.ts",
"test": "jest",
"check:types": "yarn tsc --noEmit",
"test:watch": "jest --watch",
"test:ci": "npm run lint && jest --maxWorkers 4",
"gen": "ts-node --files src/index.ts"
Expand Down
8 changes: 7 additions & 1 deletion packages/graphqlgen/src/generators/common.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as Source from '../source-helper'
import * as Common from './common'

it('getDistinctInputTypes', () => {
const Z = {
const Z: Source.GraphQLTypeObject = {
name: 'Z',
type: {
name: 'Z',
Expand All @@ -13,11 +14,13 @@ it('getDistinctInputTypes', () => {
isUnion: false,
},
fields: [],
implements: null,
}

const typeMap: Common.InputTypesMap = {
A: {
name: 'A',
implements: null,
type: {
name: 'A',
isInput: true,
Expand Down Expand Up @@ -64,6 +67,7 @@ it('getDistinctInputTypes', () => {
},
B: {
name: 'B',
implements: null,
type: {
name: 'B',
isInput: true,
Expand Down Expand Up @@ -94,6 +98,7 @@ it('getDistinctInputTypes', () => {
},
C: {
name: 'C',
implements: null,
type: {
name: 'C',
isInput: true,
Expand Down Expand Up @@ -124,6 +129,7 @@ it('getDistinctInputTypes', () => {
},
D: {
name: 'D',
implements: null,
type: {
name: 'D',
isInput: true,
Expand Down
76 changes: 70 additions & 6 deletions packages/graphqlgen/src/generators/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import * as os from 'os'

import {
GraphQLTypeObject,
GraphQLType,
GraphQLTypeDefinition,
GraphQLTypeField,
getGraphQLEnumValues,
GraphQLInterfaceObject,
GraphQLUnionObject,
} from '../source-helper'
import { ModelMap, ContextDefinition, GenerateArgs, Model } from '../types'
import {
Expand All @@ -28,6 +30,24 @@ export interface TypeToInputTypeAssociation {
[objectTypeName: string]: string[]
}

export type InterfacesMap = Record<string, GraphQLTypeDefinition[]>

export const createInterfacesMap = (
interfaces: GraphQLInterfaceObject[],
): InterfacesMap =>
interfaces.reduce<InterfacesMap>((interfacesMap, inter) => {
interfacesMap[inter.name] = inter.implementors
return interfacesMap
}, {})

export type UnionsMap = Record<string, GraphQLTypeDefinition[]>

export const createUnionsMap = (unions: GraphQLUnionObject[]): UnionsMap =>
unions.reduce<UnionsMap>((unionsMap, union) => {
unionsMap[union.name] = union.types
return unionsMap
}, {})

export function fieldsFromModelDefinition(
modelDef: TypeDefinition,
): FieldDefinition[] {
Expand Down Expand Up @@ -114,7 +134,7 @@ export function getContextName(context?: ContextDefinition) {
}

export function getModelName(
type: GraphQLType,
type: GraphQLTypeDefinition,
modelMap: ModelMap,
emptyType: string = '{}',
): string {
Expand Down Expand Up @@ -199,21 +219,63 @@ const kv = (
return `${key}${isOptional ? '?' : ''}: ${value}`
}

const array = (innerType: string, config: { innerUnion?: boolean } = {}) => {
const array = (
innerType: string,
config: { innerUnion?: boolean } = {},
): string => {
return config.innerUnion ? `${innerType}[]` : `Array<${innerType}>`
}

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

type FieldPrintOptions = {
isReturn?: boolean
}

export const printFieldLikeType = (
field: GraphQLTypeField,
modelMap: ModelMap,
interfacesMap: InterfacesMap,
unionsMap: UnionsMap,
options: FieldPrintOptions = {
isReturn: false,
},
): string => {
if (field.type.isInterface || field.type.isUnion) {
const typesMap = field.type.isInterface ? interfacesMap : unionsMap

const modelNames = typesMap[field.type.name].map(type =>
getModelName(type, modelMap),
)

let rendering = union(modelNames)

if (!field.type.isRequired) {
rendering = nullable(rendering)
}

if (field.type.isArray) {
rendering = array(rendering, { innerUnion: false })
}

if (!field.type.isArrayRequired) {
rendering = nullable(rendering)
}

// We do not have to handle defaults becuase graphql only
// supports defaults on field params but conversely
// interfaces and unions are only supported on output. Therefore
// these two features will never cross.

// No check for isReturn option because unions and interfaces
// cannot be used to type graphql field parameters which implies
// this branch will always be for a return case.

return rendering
}

const name = field.type.isScalar
? getTypeFromGraphQLType(field.type.name)
: field.type.isInput || field.type.isEnum
Expand Down Expand Up @@ -335,11 +397,13 @@ export function isParentType(name: string) {

export function groupModelsNameByImportPath(models: Model[]) {
return models.reduce<{ [importPath: string]: string[] }>((acc, model) => {
if (acc[model.importPathRelativeToOutput] === undefined) {
acc[model.importPathRelativeToOutput] = []
const fileModels = acc[model.importPathRelativeToOutput] || []

if (!fileModels.includes(model.definition.name)) {
fileModels.push(model.definition.name)
}

acc[model.importPathRelativeToOutput].push(model.definition.name)
acc[model.importPathRelativeToOutput] = fileModels

return acc
}, {})
Expand Down
Loading