graphql-genie
Version:
714 lines (661 loc) • 29.7 kB
text/typescript
import { GraphQLBoolean, GraphQLEnumType, GraphQLField, GraphQLInputFieldConfigMap, GraphQLInputObjectType, GraphQLInputType, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLScalarType, GraphQLSchema, IntrospectionField, IntrospectionObjectType, IntrospectionType, getNamedType, getNullableType, isEnumType, isInputType, isInterfaceType, isListType, isNonNullType, isObjectType, isScalarType, isUnionType } from 'graphql';
import { camelCase, each, get, isEmpty, merge } from 'lodash';
import pluralize from 'pluralize';
import { GenerateConfig } from './GraphQLGenieInterfaces';
import { getReturnType, typeIsList } from './GraphQLUtils';
import { Mutation, Relations, capFirst, fortuneFilters } from './TypeGeneratorUtilities';
export class InputGenerator {
private type: GraphQLNamedType;
private config: GenerateConfig;
private currInputObjectTypes: Map<string, GraphQLInputType>;
private schemaInfo: IntrospectionType[];
private schema: GraphQLSchema;
private relations: Relations;
private nestedGenerators: Map<string, {'function': () => GraphQLInputType, 'args': Array<any>, 'this': InputGenerator}>;
private dummy: boolean;
constructor($type: GraphQLNamedType, $config: GenerateConfig, $currInputObjectTypes: Map<string, GraphQLInputType>,
$schemaInfo: IntrospectionType[], $schema: GraphQLSchema, $relations: Relations, $dummy = false) {
this.type = $type;
this.config = $config;
this.currInputObjectTypes = $currInputObjectTypes;
this.schemaInfo = $schemaInfo;
this.schema = $schema;
this.relations = $relations;
this.nestedGenerators = new Map<string, {'function': () => GraphQLInputType, 'args': Array<any>, 'this': InputGenerator}>();
this.dummy = $dummy;
}
private handleNestedGenerators() {
this.nestedGenerators.forEach((generator) => {
if (generator.function) {
generator.function.apply(generator.this, generator.args);
}
generator.function = null;
});
}
private generateInputTypeForField(field: GraphQLField<any, any, {[argName: string]: any; }>,
manyWithout: (fieldType: GraphQLNamedType, relationFieldName: string) => GraphQLInputType,
oneWithout: (fieldType: GraphQLNamedType, relationFieldName: string) => GraphQLInputType,
many: (fieldType: GraphQLNamedType) => GraphQLInputType,
one: (fieldType: GraphQLNamedType) => GraphQLInputType,
nameOfTypeFieldIsOn: string
): GraphQLInputType {
let inputType: GraphQLInputType;
const fieldType = getNamedType(field.type);
const relationFieldName = this.relations.getInverseWithoutName(fieldType.name, field.name, nameOfTypeFieldIsOn);
const isList = typeIsList(field.type);
// tslint:disable-next-line:prefer-conditional-expression
if (relationFieldName) {
inputType = isList ? manyWithout.call(this, fieldType, relationFieldName) : oneWithout.call(this, fieldType, relationFieldName);
} else {
inputType = isList ? many.call(this, fieldType) : one.call(this, fieldType);
}
return inputType;
}
private isAutomaticField(field: IntrospectionField): boolean {
let isAutoField = false;
if (field) {
if (field.name === 'id') {
isAutoField = true;
} else if (get(field, 'metadata.updatedTimestamp') === true && !get(field, 'metadata.updatedTimestampAllowManual', false) ) {
isAutoField = true;
} else if (get(field, 'metadata.createdTimestamp') === true && !get(field, 'metadata.createdTimestampAllowManual', false)) {
isAutoField = true;
}
}
return isAutoField;
}
private generateInputTypeForFieldInfo(field: IntrospectionField, mutation: Mutation, nameOfTypeFieldIsOn: string): GraphQLInputType {
let inputType: GraphQLInputType;
const fieldTypeName = getReturnType(field.type);
const schemaType = this.schema.getType(fieldTypeName);
if (isInputType(schemaType)) {
if (mutation === Mutation.Update && !this.isAutomaticField(field)) {
const nullableType = getNullableType(schemaType);
const namedType = getNamedType(schemaType);
// tslint:disable-next-line:prefer-conditional-expression
if (typeIsList(field.type) && (isScalarType(namedType) || isEnumType(namedType))) {
inputType = this.getScalarListInput(namedType);
} else {
inputType = nullableType;
}
} else {
inputType = schemaType;
}
} else {
const isArray = typeIsList(field.type);
let fieldInputName = schemaType.name;
let fieldSuffix = Mutation[mutation];
fieldSuffix += isArray ? 'Many' : 'One';
const relationFieldName = this.relations.getInverseWithoutName(fieldTypeName, field.name, nameOfTypeFieldIsOn);
fieldSuffix += relationFieldName ? 'Without' : '';
fieldInputName += fieldSuffix + capFirst(relationFieldName) + 'Input';
if (isInterfaceType(schemaType) || isUnionType(schemaType)) {
if (this.currInputObjectTypes.has(fieldInputName)) {
inputType = this.currInputObjectTypes.get(fieldInputName);
} else {
const fields = {};
const possibleTypes = this.schemaInfo[fieldTypeName]['possibleTypes'];
possibleTypes.forEach(typeInfo => {
const typeName = isArray ? pluralize(typeInfo.name) : typeInfo.name;
const fieldName = camelCase(typeName);
const fieldInputTypeName = typeInfo.name + fieldSuffix + capFirst(relationFieldName) + 'Input';
merge(fields, this.generateFieldForInput(
fieldName,
new GraphQLInputObjectType({name: fieldInputTypeName, fields: {}})));
const functionName = `generate${fieldSuffix}Input`;
if (!this.dummy && !this.nestedGenerators.has(fieldInputTypeName)) {
const possibleSchemaType = getNamedType(this.schema.getType(typeInfo.name));
const possibleTypeGenerator = new InputGenerator(possibleSchemaType, this.config, this.currInputObjectTypes, this.schemaInfo, this.schema, this.relations, true);
this.nestedGenerators.set(fieldInputTypeName, {
'function': possibleTypeGenerator[functionName],
'args': [possibleSchemaType, relationFieldName],
'this': possibleTypeGenerator
});
}
});
const newInputObject = new GraphQLInputObjectType({
name: fieldInputName,
fields
});
if (!this.dummy) {
this.currInputObjectTypes.set(fieldInputName, newInputObject);
}
inputType = newInputObject;
}
} else {
if (!this.dummy) {
const typeGenerator = new InputGenerator(schemaType, this.config, this.currInputObjectTypes, this.schemaInfo, this.schema, this.relations, true);
const functionName = `generate${fieldSuffix}Input`;
inputType = typeGenerator[functionName].apply(typeGenerator, [schemaType, relationFieldName]);
} else {
inputType = new GraphQLInputObjectType({name: fieldInputName, fields: {}});
}
}
}
if (!this.dummy) {
this.handleNestedGenerators();
}
return inputType;
}
private generateFieldForInput = (fieldName: string, inputType: GraphQLInputType, defaultValue?: string): object => {
const field = {};
field[fieldName] = {
type: inputType,
defaultValue: defaultValue
};
return field;
}
generateWhereUniqueInput(fieldType: GraphQLNamedType = this.type): GraphQLInputObjectType {
const name = fieldType.name + 'WhereUniqueInput';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
const infoType = <IntrospectionObjectType>this.schemaInfo[fieldType.name];
infoType.fields.forEach(field => {
if (get(field, 'metadata.unique') === true) {
const isArray = typeIsList(field.type);
const schemaType = this.schema.getType(getReturnType(field.type));
let inputType;
if (isInputType(schemaType)) {
inputType = schemaType;
} else {
const fieldInputName = schemaType.name + 'WhereUniqueInput';
inputType = new GraphQLInputObjectType({name: fieldInputName, fields: {}});
}
if (isArray) {
inputType = new GraphQLList(inputType);
}
merge(fields, this.generateFieldForInput(
field.name,
inputType,
get(field, 'metadata.defaultValue')));
}
});
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return <GraphQLInputObjectType>this.currInputObjectTypes.get(name);
}
private getWhereInput(typeName: string, fields: GraphQLInputFieldConfigMap, existsFields: GraphQLInputFieldConfigMap, matchFields: GraphQLInputFieldConfigMap, rangeFields: GraphQLInputFieldConfigMap, addLogicalOperators: boolean): GraphQLInputType {
const name = typeName + 'WhereInput';
const existsName = typeName + 'ExistsInput';
const matchName = typeName + 'MatchInput';
const rangeName = typeName + 'RangeInput';
const existsInput = new GraphQLInputObjectType({
name: existsName,
description: 'Specifies if a field should exist or not (true or false)',
fields: existsFields
});
const matchInput = new GraphQLInputObjectType({
name: matchName,
description: 'Match the supplied values for each field',
fields: matchFields
});
const rangeInput = new GraphQLInputObjectType({
name: rangeName,
description: 'Filter between lower and upper bounds, takes precedence over match',
fields: rangeFields
});
this.currInputObjectTypes.set(existsName, existsInput);
this.currInputObjectTypes.set(matchName, matchInput);
this.currInputObjectTypes.set(rangeName, rangeInput);
merge(fields, {
exists: {type: existsInput},
match: {type: matchInput},
range: {type: rangeInput}
});
if (addLogicalOperators) {
const dummyListOfFilterInput = new GraphQLInputObjectType({name, fields: {}});
merge(fields, {
and: {type: new GraphQLList(new GraphQLNonNull(dummyListOfFilterInput))},
or: {type: new GraphQLList(new GraphQLNonNull(dummyListOfFilterInput))},
not: {type: dummyListOfFilterInput}
});
}
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
return this.currInputObjectTypes.get(name);
}
generateWhereInput(addLogicalOperators: boolean, fieldType: GraphQLNamedType = this.type, ): GraphQLInputType {
const name = fieldType.name + 'WhereInput';
if (!this.currInputObjectTypes.has(name)) {
const existsFields = {};
const matchFields = {};
const rangeFields = {};
const fields = {};
const infoType = <IntrospectionObjectType>this.schemaInfo[fieldType.name];
infoType.fields.forEach(field => {
const schemaType = this.schema.getType(getReturnType(field.type));
merge(existsFields, this.generateFieldForInput(
field.name,
GraphQLBoolean));
let inputType;
if (isInputType(schemaType)) {
inputType = getNamedType(schemaType);
merge(matchFields, this.generateFieldForInput(
field.name,
new GraphQLList(new GraphQLNonNull(inputType))));
merge(rangeFields, this.generateFieldForInput(
field.name,
new GraphQLList(inputType)));
} else {
const fieldInputName = schemaType.name + 'WhereInput';
let fieldName = field.name;
if (!this.currInputObjectTypes.has(fieldInputName) && !this.dummy && (isInterfaceType(schemaType) || isUnionType(schemaType))) {
const interfaceExistsFields = {};
const interfaceMatchFields = {};
const interfaceRangeFields = {};
const interfaceFields = {};
const possibleTypes: IntrospectionObjectType[] = this.schemaInfo[schemaType.name].possibleTypes;
possibleTypes.forEach(typeInfo => {
const possibleSchemaType = getNamedType(this.schema.getType(typeInfo.name));
const possibleTypeGenerator = new InputGenerator(possibleSchemaType, this.config, this.currInputObjectTypes, this.schemaInfo, this.schema, this.relations, true);
const possibleTypeFilter = possibleTypeGenerator.generateWhereInput(addLogicalOperators);
const possibleTypeFieldMap = (<GraphQLInputObjectType>possibleTypeFilter).getFields();
merge(interfaceFields, possibleTypeFieldMap);
merge(interfaceExistsFields, (<GraphQLInputObjectType>possibleTypeFieldMap['exists'].type).getFields());
merge(interfaceMatchFields, (<GraphQLInputObjectType>possibleTypeFieldMap['match'].type).getFields());
merge(interfaceRangeFields, (<GraphQLInputObjectType>possibleTypeFieldMap['range'].type).getFields());
});
inputType = this.getWhereInput(schemaType.name, interfaceFields, interfaceExistsFields, interfaceMatchFields, interfaceRangeFields, addLogicalOperators);
} else {
inputType = new GraphQLInputObjectType({name: fieldInputName, fields: {}});
if (fortuneFilters.includes(fieldName)) {
fieldName = 'f_' + fieldName;
}
}
merge(fields, this.generateFieldForInput(
fieldName,
inputType));
}
});
this.getWhereInput(fieldType.name, fields, existsFields, matchFields, rangeFields, addLogicalOperators);
}
return this.currInputObjectTypes.get(name);
}
generateOrderByInput(fieldType: GraphQLNamedType = this.type): GraphQLInputType {
const name = fieldType.name + 'OrderByInput';
if (!this.currInputObjectTypes.has(name)) {
const orderByEnum = <GraphQLEnumType>this.schema.getType('ORDER_BY_OPTIONS');
const fields = {};
const infoType = <IntrospectionObjectType>this.schemaInfo[fieldType.name];
infoType.fields.forEach(field => {
const schemaType = this.schema.getType(getReturnType(field.type));
let inputType;
if (isInputType(schemaType)) {
inputType = getNamedType(schemaType);
merge(fields, this.generateFieldForInput(
field.name,
orderByEnum
));
} else {
const fieldInputName = schemaType.name + 'OrderByInput';
if (!this.currInputObjectTypes.has(fieldInputName) && !this.dummy && (isInterfaceType(schemaType) || isUnionType(schemaType))) {
const interfaceFields = {};
const possibleTypes: IntrospectionObjectType[] = this.schemaInfo[schemaType.name].possibleTypes;
possibleTypes.forEach(typeInfo => {
const possibleSchemaType = getNamedType(this.schema.getType(typeInfo.name));
const possibleTypeGenerator = new InputGenerator(possibleSchemaType, this.config, this.currInputObjectTypes, this.schemaInfo, this.schema, this.relations, true);
const possibleTypeFilter = possibleTypeGenerator.generateOrderByInput();
const possibleTypeFieldMap = (<GraphQLInputObjectType>possibleTypeFilter).getFields();
merge(interfaceFields, possibleTypeFieldMap);
});
inputType = new GraphQLInputObjectType({
name: fieldInputName,
fields: interfaceFields
});
this.currInputObjectTypes.set(fieldInputName, inputType);
} else {
inputType = new GraphQLInputObjectType({name: fieldInputName, fields: {}});
}
merge(fields, this.generateFieldForInput(
field.name,
inputType));
}
});
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateCreateWithoutInput(fieldType: GraphQLNamedType = this.type, relationFieldName?: string): GraphQLInputType {
let name = fieldType.name + 'Create';
name += relationFieldName ? 'Without' + capFirst(relationFieldName) : '';
name += 'Input';
if (!relationFieldName) {
return new GraphQLInputObjectType({name, fields: {}});
}
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
const infoType = <IntrospectionObjectType>this.schemaInfo[fieldType.name];
infoType.fields.forEach(field => {
if (!this.isAutomaticField(field) && field.name !== relationFieldName) {
let inputType = this.generateInputTypeForFieldInfo(field, Mutation.Create, fieldType.name);
if (field.type.kind === 'NON_NULL' && field.type.ofType.kind !== 'LIST') {
inputType = new GraphQLNonNull(inputType);
}
merge(fields, this.generateFieldForInput(
field.name,
inputType,
get(field, 'metadata.defaultValue')));
}
});
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateCreateManyWithoutInput(fieldType: GraphQLNamedType = this.type, relationFieldName: string): GraphQLInputType {
const name = fieldType.name + 'CreateManyWithout' + capFirst(relationFieldName) + 'Input';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: new GraphQLList(new GraphQLNonNull(this.generateCreateWithoutInput(fieldType, relationFieldName)))};
fields['connect'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateCreateOneWithoutInput(fieldType: GraphQLNamedType, relationFieldName: string): GraphQLInputType {
const name = fieldType.name + 'CreateOneWithout' + capFirst(relationFieldName) + 'Input';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: this.generateCreateWithoutInput(fieldType, relationFieldName)};
fields['connect'] = {type: this.generateWhereUniqueInput(fieldType)};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateCreateManyInput(fieldType: GraphQLNamedType): GraphQLInputType {
const name = fieldType.name + 'CreateManyInput';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: new GraphQLList(new GraphQLNonNull(this.generateCreateWithoutInput(fieldType)))};
fields['connect'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateCreateOneInput(fieldType: GraphQLNamedType): GraphQLInputType {
const name = fieldType.name + 'CreateOneInput';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: this.generateCreateWithoutInput(fieldType)};
fields['connect'] = {type: this.generateWhereUniqueInput(fieldType)};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateCreateInput(): GraphQLInputType {
const name = this.type.name + 'CreateInput';
const infoType = this.schemaInfo[this.type.name];
const fields = {};
if (isObjectType(this.type) && !this.currInputObjectTypes.has(name)) {
const infoTypeFields: IntrospectionField[] = infoType.fields;
each(this.type.getFields(), field => {
if (field.name !== 'id') {
let inputType;
const fieldNullableType = getNullableType(field.type);
if (isInputType(field.type)) {
const infoTypeField = infoTypeFields.find(infoTypeField => infoTypeField.name === field.name);
if (!this.isAutomaticField(infoTypeField)) {
inputType = isListType(fieldNullableType) ? fieldNullableType : field.type;
}
} else if (isObjectType(field.type)) {
inputType = this.generateInputTypeForField(field, this.generateCreateManyWithoutInput,
this.generateCreateOneWithoutInput,
this.generateCreateManyInput,
this.generateCreateOneInput,
this.type.name);
} else {
inputType = this.generateInputTypeForFieldInfo(
infoTypeFields.find(currField => currField.name === field.name),
Mutation.Create,
this.type.name);
}
if (inputType && !isListType(fieldNullableType) && isNonNullType(field.type) && !isNonNullType(inputType)) {
inputType = new GraphQLNonNull(inputType);
}
if (inputType) {
merge(fields, this.generateFieldForInput(
field.name,
inputType,
get(this.schemaInfo[this.type.name].fields.find((introField) => introField.name === field.name), 'metadata.defaultValue')));
}
}
});
if (isEmpty(fields)) {
throw new Error(`Types must have at least one field other than ID, ${this.type.name} does not`);
}
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpdateWithoutInput(fieldType: GraphQLNamedType, relationFieldName?: string): GraphQLInputType {
let name = fieldType.name + 'Update';
name += relationFieldName ? 'Without' + capFirst(relationFieldName) : '';
name += 'Input';
if (!relationFieldName) {
return new GraphQLInputObjectType({name, fields: {}});
}
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
const infoType = <IntrospectionObjectType>this.schemaInfo[fieldType.name];
infoType.fields.forEach(field => {
if (!this.isAutomaticField(field) && field.name !== relationFieldName) {
const inputType = this.generateInputTypeForFieldInfo(field, Mutation.Update, fieldType.name);
merge(fields, this.generateFieldForInput(
field.name,
inputType));
}
});
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpdateWithWhereUniqueWithoutInput(fieldType: GraphQLNamedType, relationFieldName?: string): GraphQLInputType {
const name = fieldType.name + 'UpdateWithWhereUniqueWithout' + capFirst(relationFieldName) + 'Input';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['data'] = {type: new GraphQLNonNull(this.generateUpdateWithoutInput(fieldType, relationFieldName))};
fields['where'] = {type: new GraphQLNonNull(this.generateWhereUniqueInput(fieldType))};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpdateManyWithoutInput(fieldType: GraphQLNamedType, relationFieldName: string): GraphQLInputType {
const name = fieldType.name + 'UpdateManyWithout' + capFirst(relationFieldName) + 'Input';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: new GraphQLList(new GraphQLNonNull(this.generateCreateWithoutInput(fieldType, relationFieldName)))};
fields['connect'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
fields['disconnect'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
fields['delete'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
fields['update'] = {type: new GraphQLList(new GraphQLNonNull(this.generateUpdateWithWhereUniqueWithoutInput(fieldType, relationFieldName)))};
if (this.config.generateUpsert) {
fields['upsert'] = {type: new GraphQLList(new GraphQLNonNull(this.generateUpsertWithWhereUniqueWithoutInput(fieldType, relationFieldName)))};
}
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpdateOneWithoutInput(fieldType: GraphQLNamedType, relationFieldName: string): GraphQLInputType {
const name = fieldType.name + 'UpdateOneWithout' + capFirst(relationFieldName) + 'Input';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: this.generateCreateWithoutInput(fieldType, relationFieldName)};
fields['connect'] = {type: this.generateWhereUniqueInput(fieldType)};
fields['disconnect'] = {type: GraphQLBoolean};
fields['delete'] = {type: GraphQLBoolean};
fields['update'] = {type: this.generateUpdateWithoutInput(fieldType, relationFieldName)};
if (this.config.generateUpsert) {
fields['upsert'] = {type: this.generateUpsertWithoutInput(fieldType, relationFieldName)};
}
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpdateManyInput(fieldType: GraphQLNamedType): GraphQLInputType {
const name = fieldType.name + 'UpdateManyInput';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: new GraphQLList(new GraphQLNonNull(this.generateCreateWithoutInput(fieldType)))};
fields['connect'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
fields['disconnect'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
fields['delete'] = {type: new GraphQLList(new GraphQLNonNull(this.generateWhereUniqueInput(fieldType)))};
fields['update'] = {type: new GraphQLList(new GraphQLNonNull(this.generateUpdateWithWhereUniqueWithoutInput(fieldType)))};
if (this.config.generateUpsert) {
fields['upsert'] = {type: new GraphQLList(new GraphQLNonNull(this.generateUpsertWithWhereUniqueWithoutInput(fieldType)))};
}
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpdateOneInput(fieldType: GraphQLNamedType): GraphQLInputType {
const name = fieldType.name + 'UpdateOneInput';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['create'] = {type: this.generateCreateWithoutInput(fieldType)};
fields['connect'] = {type: this.generateWhereUniqueInput(fieldType)};
fields['disconnect'] = {type: GraphQLBoolean};
fields['delete'] = {type: GraphQLBoolean};
fields['update'] = {type: this.generateUpdateWithoutInput(fieldType)};
if (this.config.generateUpsert) {
fields['upsert'] = {type: this.generateUpsertWithoutInput(fieldType)};
}
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpdateInput(): GraphQLInputType {
const name = this.type.name + 'UpdateInput';
const fields = {};
if (isObjectType(this.type) && !this.currInputObjectTypes.has(name)) {
const infoTypeFields: IntrospectionField[] = this.schemaInfo[this.type.name].fields;
each(this.type.getFields(), field => {
if (field.name !== 'id') {
let inputType;
if (isInputType(field.type)) {
const infoTypeField = infoTypeFields.find(infoTypeField => infoTypeField.name === field.name);
if (!this.isAutomaticField(infoTypeField)) {
const nullableType = getNullableType(field.type);
const namedType = getNamedType(field.type);
// tslint:disable-next-line:prefer-conditional-expression
if (isListType(nullableType) && (isScalarType(namedType) || isEnumType(namedType))) {
inputType = this.getScalarListInput(namedType);
} else {
inputType = nullableType;
}
}
} else if (isObjectType(field.type)) {
inputType = this.generateInputTypeForField(field, this.generateUpdateManyWithoutInput,
this.generateUpdateOneWithoutInput,
this.generateUpdateManyInput,
this.generateUpdateOneInput,
this.type.name);
} else {
inputType = this.generateInputTypeForFieldInfo(
infoTypeFields.find(currField => currField.name === field.name),
Mutation.Update,
this.type.name);
}
if (inputType) {
merge(fields, this.generateFieldForInput(
field.name,
inputType));
}
}
});
if (isEmpty(fields)) {
throw new Error(`Types must have at least one field other than ID, ${this.type.name} does not`);
}
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpsertWithoutInput(fieldType: GraphQLNamedType, relationFieldName?: string): GraphQLInputType {
let name = fieldType.name + 'Upsert';
name += relationFieldName ? 'Without' + capFirst(relationFieldName) : '';
name += 'Input';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['update'] = {type: new GraphQLNonNull(this.generateUpdateWithoutInput(fieldType, relationFieldName))};
fields['create'] = {type: new GraphQLNonNull(this.generateCreateWithoutInput(fieldType, relationFieldName))};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
generateUpsertWithWhereUniqueWithoutInput(fieldType: GraphQLNamedType, relationFieldName?: string): GraphQLInputType {
const name = fieldType.name + 'UpsertWithWhereUniqueWithout' + capFirst(relationFieldName) + 'Input';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['update'] = {type: new GraphQLNonNull(this.generateUpdateWithoutInput(fieldType, relationFieldName))};
fields['create'] = {type: new GraphQLNonNull(this.generateCreateWithoutInput(fieldType, relationFieldName))};
fields['where'] = {type: new GraphQLNonNull(this.generateWhereUniqueInput(fieldType))};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
private getScalarListInput(scalarType: GraphQLScalarType | GraphQLEnumType): GraphQLInputType {
const name = scalarType.name + 'ScalarListInput';
if (!this.currInputObjectTypes.has(name)) {
const fields = {};
fields['set'] = {type: new GraphQLList(scalarType)};
fields['push'] = {type: new GraphQLList(scalarType)};
fields['pull'] = {type: new GraphQLList(scalarType)};
this.currInputObjectTypes.set(name, new GraphQLInputObjectType({
name,
fields
}));
}
return this.currInputObjectTypes.get(name);
}
}