import { GraphQLFieldResolver , GraphQLInputObjectType , GraphQLInputType , GraphQLSchema , IntrospectionObjectType , IntrospectionType , isInterfaceType , isUnionType } from 'graphql' ; import pluralize from 'pluralize' ; import { DataResolver , TypeGenerator } from './GraphQLGenieInterfaces' ; import { InputGenerator } from './InputGenerator' ; import { Relations , getAllResolver , getRootMatchFields , queryArgs } from './TypeGeneratorUtilities' ; import { camelCase } from 'lodash' ; export class GenerateConnections implements TypeGenerator { private objectName : string ; private types : IntrospectionObjectType [ ] ; private schema : GraphQLSchema ; private dataResolver : DataResolver ; private fields : object ; private resolvers : Map < string , GraphQLFieldResolver < any , any > > ; private edgeResolvers : Map < string , Map < string , GraphQLFieldResolver < any , any > > > ; private currOutputObjectTypeDefs : Set < string > ; private currInputObjectTypes : Map < string , GraphQLInputType > ; private schemaInfo : IntrospectionType [ ] ; private relations : Relations ; constructor ( dataResolver , objectName , types , $schema , $currOutputObjectTypeDefs , $currInputObjectTypes , $schemaInfo , $relations ) { this . dataResolver = dataResolver ; this . objectName = objectName ; this . types = types ; this . schema = $schema ; this . currOutputObjectTypeDefs = $currOutputObjectTypeDefs ; this . currInputObjectTypes = $currInputObjectTypes ; this . schemaInfo = $schemaInfo ; this . relations = $relations ; this . fields = { } ; this . resolvers = new Map < string , GraphQLFieldResolver < any , any > > ( ) ; this . edgeResolvers = new Map < string , Map < string , GraphQLFieldResolver < any , any > > > ( ) ; this . currOutputObjectTypeDefs . add ( `
			"""
			Information about pagination in a connection.
			"""
			type PageInfo {
				"""
				When paginating forwards, are there more items?
				"""
				hasNextPage: Boolean!
				"""
				When paginating backwards, are there more items?
				"""
				hasPreviousPage: Boolean!
				"""
				When paginating backwards, the cursor to continue.
				"""
				startCursor: String
				"""
				When paginating forwards, the cursor to continue.
				"""
				endCursor: String
			}
		` ) ; this . generate ( ) ; } generate ( ) { Object . keys ( this . schema . getTypeMap ( ) ) . forEach ( typeName => { const type = this . schema . getType ( typeName ) ; if ( isInterfaceType ( type ) || isUnionType ( type ) ) { this . createNewTypes ( typeName ) ; const edgeFieldResolvers = new Map < string , GraphQLFieldResolver < any , any > > ( ) ; edgeFieldResolvers . set ( 'node' , ( root ) : any => { return root ; } ) ; edgeFieldResolvers . set ( 'cursor' , ( root ) : any => { const fortuneReturn = root && root . fortuneReturn ? root . fortuneReturn : root ; return fortuneReturn . id ; } ) ; this . edgeResolvers . set ( `${ typeName }Edge` , edgeFieldResolvers ) ; } } ) ; this . types . forEach ( type => { const fieldName = `${ camelCase ( pluralize ( type . name ) ) }Connection` ; this . createNewTypes ( type . name ) ; const schemaType = this . schema . getType ( type . name ) ; const generator = new InputGenerator ( schemaType , null , this . currInputObjectTypes , this . schemaInfo , this . schema , this . relations ) ; const args = Object . assign ( { where : { type : generator . generateWhereInput ( this . dataResolver . getFeatures ( ) . logicalOperators ) } , orderBy : { type : generator . generateOrderByInput ( ) } } , queryArgs , getRootMatchFields ( ( < GraphQLInputObjectType > this . currInputObjectTypes . get ( `${ type . name }MatchInput` ) ) ) ) ; this . fields [ fieldName ] = { type : `${ type . name }Connection` , args } ; this . resolvers . set ( fieldName , getAllResolver ( this . dataResolver , this . schema , type , true ) ) ; const edgeFieldResolvers = new Map < string , GraphQLFieldResolver < any , any > > ( ) ; edgeFieldResolvers . set ( 'node' , ( root ) : any => { return root ; } ) ; edgeFieldResolvers . set ( 'cursor' , ( root ) : any => { const fortuneReturn = root && root . fortuneReturn ? root . fortuneReturn : root ; return fortuneReturn . id ; } ) ; this . edgeResolvers . set ( `${ type . name }Edge` , edgeFieldResolvers ) ; } ) ; } public getResolvers ( ) { return new Map ( [ [ this . objectName , this . resolvers ] , ... this . edgeResolvers ] ) ; } public getFieldsOnObject ( ) { return new Map ( [ [ this . objectName , this . fields ] ] ) ; } private createNewTypes ( typeName ) { this . currOutputObjectTypeDefs . add ( `
		"""
		A connection to a list of items.
		"""
		type ${ typeName }Connection {
			"""
			A list of edges.
			"""
			edges: [${ typeName }Edge]
			"""
			Information to aid in pagination.
			"""
			pageInfo: PageInfo
			"""
			Meta information
			"""
			aggregate: ${ typeName }Aggregate
		}
	` ) ; this . currOutputObjectTypeDefs . add ( `
		type ${ typeName }Aggregate {
			"""
			The total number that match the where clause
			"""
			count: Int!
		}
	` ) ; this . currOutputObjectTypeDefs . add ( `
		type ${ typeName }Edge {
			node: ${ typeName }!
			cursor: String!
		}
	` ) ; } }