graphql-genie
Version:
174 lines (153 loc) • 5.14 kB
text/typescript
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: DataResolver, objectName: string,
types: IntrospectionObjectType[], $schema: GraphQLSchema,
$currOutputObjectTypeDefs: Set<string>,
$currInputObjectTypes: Map<string, GraphQLInputType>,
$schemaInfo: IntrospectionType[],
$relations: 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
): any => {
return root;
});
edgeFieldResolvers.set('cursor', (
root: any
): 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
): any => {
return root;
});
edgeFieldResolvers.set('cursor', (
root: any
): any => {
const fortuneReturn = root && root.fortuneReturn ? root.fortuneReturn : root;
return fortuneReturn.id;
});
this.edgeResolvers.set(`${type.name}Edge`, edgeFieldResolvers);
});
}
public getResolvers(): Map<string, Map<string, GraphQLFieldResolver<any, any>>> {
return new Map([[this.objectName, this.resolvers], ...this.edgeResolvers]);
}
public getFieldsOnObject(): Map<string, object> {
return new Map([[this.objectName, this.fields]]);
}
private createNewTypes(typeName: string) {
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!
}
`);
}
}