import { GraphQLScalarType } from 'graphql' ; import * as Nexus from 'nexus' ; import { CustomInputArg } from './builder' ; import { DmmfDocument , InternalDMMF } from './dmmf' ; import { scalarsNameValues } from './graphql' ; import { apply , Index } from './utils' ; export class Publisher { typesPublished : Index < boolean > = { } ; constructor ( public dmmf , public nexusBuilder , public scalars ) { } inputType ( customArg ) { const typeName = customArg . type . name ; if ( this . isPublished ( typeName ) ) { return Nexus . arg ( { type : getNexusTypesCompositionForInput ( customArg . arg . inputType ) . reduceRight ( apply , customArg . type . name ) as any , } ) ; } if ( customArg . arg . inputType . kind === 'scalar' ) { return this . publishScalar ( customArg . type . name ) ; } if ( customArg . arg . inputType . kind === 'enum' ) { return this . publishEnum ( customArg . type . name ) ; } const inputType = customArg . type as InternalDMMF . InputType ; return this . publishInputObjectType ( inputType ) ; } public outputType ( outputTypeName , field ) { /**
         * Rules:
         * - If outputTypeName is already published
         * - Or if outputTypeName matches a prisma model name
         * - Then simply reference the type. Types that matches a prisma model name should be published manually by users.
         */ if ( this . isPublished ( outputTypeName ) || this . dmmf . hasModel ( outputTypeName ) ) { return outputTypeName ; } if ( field . outputType . kind === 'object' ) { return this . publishObject ( outputTypeName ) ; } if ( this . dmmf . hasEnumType ( outputTypeName ) ) { return this . publishEnum ( outputTypeName ) ; } if ( field . outputType . kind === 'scalar' ) { return this . publishScalar ( outputTypeName ) ; } return outputTypeName ; } protected publishObject ( name ) { const dmmfObject = this . dmmf . getOutputType ( name ) ; this . markTypeAsPublished ( name ) ; return Nexus . objectType ( { name , definition : ( t ) => { for ( const field of dmmfObject . fields ) { t . field ( field . name , { type : getNexusTypesCompositionForOutput ( field . outputType ) . reduceRight ( apply , field . outputType . type ) as any , } ) ; } } , } ) ; } protected publishScalar ( typeName ) { if ( scalarsNameValues . includes ( typeName as any ) ) { return typeName ; } this . markTypeAsPublished ( typeName ) ; if ( this . scalars [ typeName ] ) { return this . scalars [ typeName ] ; } return Nexus . scalarType ( { name : typeName , serialize ( value ) { return value ; } , } ) ; } protected publishEnum ( typeName ) { const dmmfEnum = this . dmmf . getEnumType ( typeName ) ; this . markTypeAsPublished ( typeName ) ; return Nexus . enumType ( { name : typeName , members : dmmfEnum . values , } ) ; } publishInputObjectType ( inputType ) { this . markTypeAsPublished ( inputType . name ) ; return Nexus . inputObjectType ( { name : inputType . name , definition : ( t ) => { inputType . fields . forEach ( ( field ) => { if ( [ 'JsonFilter' , 'NullableJsonFilter' ] . includes ( field . inputType . type ) ) { return ; } let fieldType ; if ( this . isPublished ( field . inputType . type ) ) { fieldType = field . inputType . type ; } else { fieldType = this . inputType ( { arg : field , type : this . getTypeFromArg ( field ) , } ) ; } t . field ( field . name , { type : getNexusTypesCompositionForInput ( field . inputType ) . reduceRight ( apply , fieldType ) as any , } ) ; } ) ; } , } ) ; } protected getTypeFromArg ( arg ) { const kindToType = { scalar : ( typeName ) => ( { name : typeName , } ) , enum : ( typeName ) => this . dmmf . getEnumType ( typeName ) , object : ( typeName ) => this . dmmf . getInputType ( typeName ) , } ; return kindToType [ arg . inputType . kind ] ( arg . inputType . type ) ; } isPublished ( typeName ) { return this . nexusBuilder . hasType ( typeName ) || this . typesPublished [ typeName ] ; } markTypeAsPublished ( typeName ) { this . typesPublished [ typeName ] = true ; } } /**
 * Get the composition-order pipeline of Nexus type def functions that will match the nullability and list types of the Prisma field type.
 *
 * For example { isList:true, isRequired: true } would result in array of funcs: [nonNull, list, nonNull]
 */ export const getNexusTypesCompositionForInput = ( fieldType ) => { if ( fieldType . isList ) { return [ Nexus . list , Nexus . nonNull ] ; } else if ( fieldType . isRequired === true ) { return [ Nexus . nonNull ] ; } else if ( fieldType . isRequired === false ) { return [ Nexus . nullable ] ; } return [ ] as Function [ ] ; } ; export const getNexusTypesCompositionForOutput = ( fieldType ) => { if ( fieldType . isList ) { return [ Nexus . nonNull , Nexus . list , Nexus . nonNull ] ; } else if ( fieldType . isRequired === true ) { return [ Nexus . nonNull ] ; } else if ( fieldType . isRequired === false ) { return [ Nexus . nullable ] ; } return [ ] as Function [ ] ; } ;