From 305f45d3da6cd4fcf515c28ebb3190855a3fc44a Mon Sep 17 00:00:00 2001 From: getlarge Date: Wed, 13 May 2020 11:14:15 +0200 Subject: [PATCH] replace duplicate typing functions in operation.ts and replace duplicated naming function in ProtocolGraphQLConfiguration --- .../ProtocolGraphQLConfiguration.ts | 158 ++--- src/graphqlProtocol/generator.ts | 9 +- src/graphqlProtocol/io.ts | 2 +- src/graphqlProtocol/mutation.ts | 595 +---------------- src/graphqlProtocol/operation.ts | 608 ++++++++++++++++++ src/graphqlProtocol/subscription.ts | 601 +---------------- 6 files changed, 711 insertions(+), 1262 deletions(-) create mode 100644 src/graphqlProtocol/operation.ts diff --git a/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts index 5cbeea7f..d9faf201 100644 --- a/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts +++ b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts @@ -7,6 +7,7 @@ import { } from './util'; import { MAX_PAGE_SIZE } from './protocolGraphqlConstants'; import { ProtocolConfiguration } from '../engine/protocol/ProtocolConfiguration'; +import { Mutation, Subscription, Entity } from '..'; export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { constructor() { @@ -20,6 +21,9 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { 'mutationNested', 'mutationById', 'mutationByUniqueness', + 'subscription', + 'subscriptionNested', + 'subscriptionById', ], true, ); @@ -85,26 +89,6 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { return generateTypeNamePascalCase(`${typeName}-${fieldName}-i18n`); } - generateMutationI18nAttributeInputTypeName(entity, mutation, attribute) { - const typeName = this.generateEntityTypeName(entity); - const fieldName = this.generateFieldName(attribute); - return generateTypeNamePascalCase( - `${mutation.name}-${typeName}-${fieldName}-i18n-input`, - ); - } - - generateSubscriptionI18nAttributeInputTypeName( - entity, - subscription, - attribute, - ) { - const typeName = this.generateEntityTypeName(entity); - const fieldName = this.generateFieldName(attribute); - return generateTypeNamePascalCase( - `${subscription.name}-${typeName}-${fieldName}-i18n-input`, - ); - } - generateListQueryTypeName(entity) { const typeNamePlural = this.generateEntityTypeNamePlural(entity); return generateTypeName(`all-${typeNamePlural}`); @@ -120,26 +104,6 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { return generateTypeName(`${typeName}-by-${fieldName}`); } - generateMutationInstanceInputTypeName(entity, mutation) { - const typeName = this.generateEntityTypeName(entity); - return generateTypeNamePascalCase( - `${mutation.name}-${typeName}-instance-input`, - ); - } - - generateMutationInputTypeName(entity, mutation) { - const typeName = this.generateEntityTypeName(entity); - return generateTypeNamePascalCase(`${mutation.name}-${typeName}-input`); - } - - generateMutationByPrimaryAttributeInputTypeName(entity, mutation, attribute) { - const typeName = this.generateEntityTypeName(entity); - const fieldName = this.generateFieldName(attribute); - return generateTypeNamePascalCase( - `${mutation.name}-${typeName}-by-${fieldName}-input`, - ); - } - generateUniquenessAttributesName(_entity, attributes) { return generateTypeName(attributes.join('-and-')); } @@ -162,41 +126,6 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateMutationInstanceNestedInputTypeName(entity, mutation) { - const typeName = this.generateEntityTypeName(entity); - return generateTypeNamePascalCase( - `${mutation.name}-${typeName}-instance-nested-input`, - ); - } - - generateMutationNestedInputTypeName(entity, mutation) { - const typeName = this.generateEntityTypeName(entity); - return generateTypeNamePascalCase( - `${mutation.name}-${typeName}-nested-input`, - ); - } - - generateMutationOutputTypeName(entity, mutation) { - const typeName = this.generateEntityTypeName(entity); - return generateTypeNamePascalCase(`${mutation.name}-${typeName}-output`); - } - - generateMutationTypeName(entity, mutation) { - const typeName = this.generateEntityTypeName(entity); - return generateTypeName(`${mutation.name}-${typeName}`); - } - - generateMutationNestedTypeName(entity, mutation) { - const typeName = this.generateEntityTypeName(entity); - return generateTypeName(`${mutation.name}-${typeName}-nested`); - } - - generateMutationByPrimaryAttributeTypeName(entity, mutation, attribute) { - const typeName = this.generateEntityTypeName(entity); - const fieldName = this.generateFieldName(attribute); - return generateTypeName(`${mutation.name}-${typeName}-by-${fieldName}`); - } - generateActionTypeName(action) { return generateTypeName(action.name); } @@ -275,69 +204,100 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { return generateTypeNamePascalCase(`${typeName}-connection`); } - generateSubscriptionInstanceInputTypeName(entity, subscription) { + generateOperationI18nAttributeInputTypeName( + entity: Entity | any, + operation: Mutation | Subscription | any, + attribute, + ) { const typeName = this.generateEntityTypeName(entity); + const fieldName = this.generateFieldName(attribute); return generateTypeNamePascalCase( - `${subscription.name}-${typeName}-instance-input`, + `${operation.name}-${typeName}-${fieldName}-i18n-input`, ); } - generateSubscriptionInputTypeName(entity, subscription) { + generateOperationInstanceInputTypeName( + entity: Entity, + operation: Mutation | Subscription, + ) { const typeName = this.generateEntityTypeName(entity); - return generateTypeNamePascalCase(`${subscription.name}-${typeName}-input`); + return generateTypeNamePascalCase( + `${operation.name}-${typeName}-instance-input`, + ); } - generateSubscriptionByPrimaryAttributeInputTypeName( - entity, - subscription, + generateOperationInputTypeName( + entity: Entity, + operation: Mutation | Subscription, + ) { + const typeName = this.generateEntityTypeName(entity); + return generateTypeNamePascalCase(`${operation.name}-${typeName}-input`); + } + + generateOperationByPrimaryAttributeInputTypeName( + entity: Entity, + operation: Mutation | Subscription, attribute, ) { const typeName = this.generateEntityTypeName(entity); const fieldName = this.generateFieldName(attribute); return generateTypeNamePascalCase( - `${subscription.name}-${typeName}-by-${fieldName}-input`, + `${operation.name}-${typeName}-by-${fieldName}-input`, ); } - generateSubscriptionInstanceNestedInputTypeName(entity, subscription) { + generateOperationInstanceNestedInputTypeName( + entity: Entity, + operation: Mutation | Subscription, + ) { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase( - `${subscription.name}-${typeName}-instance-nested-input`, + `${operation.name}-${typeName}-instance-nested-input`, ); } - generateSubscriptionNestedInputTypeName(entity, subscription) { + generateOperationNestedInputTypeName( + entity: Entity, + operation: Mutation | Subscription, + ) { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase( - `${subscription.name}-${typeName}-nested-input`, + `${operation.name}-${typeName}-nested-input`, ); } - generateSubscriptionOutputTypeName(entity, subscription) { + generateOperationOutputTypeName( + entity: Entity, + operation: Mutation | Subscription, + ) { const typeName = this.generateEntityTypeName(entity); - return generateTypeNamePascalCase( - `${subscription.name}-${typeName}-output`, - ); + return generateTypeNamePascalCase(`${operation.name}-${typeName}-output`); } - generateSubscriptionTypeName(entity, subscription) { + generateOperationTypeName( + entity: Entity, + operation: Mutation | Subscription, + ) { const typeName = this.generateEntityTypeName(entity); - return generateTypeName(`${subscription.name}-${typeName}`); + return generateTypeName(`${operation.name}-${typeName}`); } - generateSubscriptionNestedTypeName(entity, subscription) { + generateOperationNestedTypeName( + entity: Entity, + operation: Mutation | Subscription, + ) { const typeName = this.generateEntityTypeName(entity); - return generateTypeName(`${subscription.name}-${typeName}-nested`); + return generateTypeName(`${operation.name}-${typeName}-nested`); } - generateSubscriptionByPrimaryAttributeTypeName( - entity, - subscription, + generateOperationByPrimaryAttributeTypeName( + entity: Entity, + operation: Mutation | Subscription, attribute, ) { const typeName = this.generateEntityTypeName(entity); const fieldName = this.generateFieldName(attribute); - return generateTypeName(`${subscription.name}-${typeName}-by-${fieldName}`); + return generateTypeName(`${operation.name}-${typeName}-by-${fieldName}`); } } diff --git a/src/graphqlProtocol/generator.ts b/src/graphqlProtocol/generator.ts index 9a6fe5d2..768950a9 100644 --- a/src/graphqlProtocol/generator.ts +++ b/src/graphqlProtocol/generator.ts @@ -35,6 +35,7 @@ import { } from '../engine/action/Action'; import { isViewEntity } from '../engine/entity/ViewEntity'; import { isShadowEntity } from '../engine/entity/ShadowEntity'; +import { generateInstanceUniquenessInputs } from './operation'; export const getTypeForEntityFromGraphRegistry = entity => { const typeName = entity.graphql.typeName; @@ -342,6 +343,8 @@ export const generateGraphQLSchema = configuration => { } }); + generateInstanceUniquenessInputs(graphRegistry); + // build the query type const queryType = new GraphQLObjectType({ name: 'Query', @@ -388,12 +391,6 @@ export const generateGraphQLSchema = configuration => { fields: () => { const subscriptions = generateSubscriptions(graphRegistry); - // Object.keys(subscriptions).forEach(sub => { - // console.log('generate subscriptions', { - // name: sub, - // args: subscriptions[sub].args, - // }); - // }); return subscriptions; }, diff --git a/src/graphqlProtocol/io.ts b/src/graphqlProtocol/io.ts index 0e89d0a4..3e47a92d 100644 --- a/src/graphqlProtocol/io.ts +++ b/src/graphqlProtocol/io.ts @@ -73,7 +73,7 @@ const generateDataInputField = ( param.gqlFieldNameI18n = protocolConfiguration.generateI18nFieldName(param); - const i18nFieldTypeName = protocolConfiguration.generateMutationI18nAttributeInputTypeName( + const i18nFieldTypeName = protocolConfiguration.generateOperationI18nAttributeInputTypeName( { name: baseName, }, diff --git a/src/graphqlProtocol/mutation.ts b/src/graphqlProtocol/mutation.ts index 4ea74011..14c8fed5 100644 --- a/src/graphqlProtocol/mutation.ts +++ b/src/graphqlProtocol/mutation.ts @@ -1,579 +1,24 @@ -import { - GraphQLString, - GraphQLID, - GraphQLNonNull, - GraphQLInputObjectType, - GraphQLObjectType, - GraphQLInt, - GraphQLInputFieldConfigMap, - GraphQLFieldConfigMap, -} from 'graphql'; - -import { fromGlobalId } from 'graphql-relay'; +import { GraphQLNonNull } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; -import { getEntityUniquenessAttributes } from './helper'; import { getMutationResolver } from './resolver'; -import { isEntity } from '../engine/entity/Entity'; - -const i18nInputFieldTypesCache = {}; - -const generateI18nInputFieldType = (entity, entityMutation, attribute) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const i18nFieldTypeName = protocolConfiguration.generateMutationI18nAttributeInputTypeName( - entity, - entityMutation, - attribute, - ); - - if (i18nInputFieldTypesCache[i18nFieldTypeName]) { - return i18nInputFieldTypesCache[i18nFieldTypeName]; - } - - const attributeType = attribute.type; - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - const languages = protocolConfiguration - .getParentConfiguration() - .getLanguages(); - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - const i18nFieldType = new GraphQLInputObjectType({ - name: i18nFieldTypeName, - description: `**\`${entityMutation.name}\`** mutation translations input type for **\`${typeNamePascalCase}.${attribute.gqlFieldName}\`**`, - - fields: () => { - const i18nFields = {}; - - languages.map((language, langIdx) => { - const type = - langIdx === 0 && attribute.required && !entityMutation.ignoreRequired - ? new GraphQLNonNull(fieldType) - : fieldType; - - i18nFields[language] = { - type, - }; - }); - - return i18nFields; - }, - }); - - i18nInputFieldTypesCache[i18nFieldTypeName] = i18nFieldType; - - return i18nFieldType; -}; - -export const generateMutationInstanceInput = (entity, entityMutation) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityMutationInstanceInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateMutationInstanceInputTypeName( - entity, - entityMutation, - ), - description: `**\`${entityMutation.name}\`** mutation input type for **\`${typeNamePascalCase}\`**`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = {}; - - const entityAttributes = entity.getAttributes(); - - _.forEach(entityMutation.attributes, attributeName => { - const attribute = entityAttributes[attributeName]; - - let attributeType = attribute.type; - - // it's a reference - if (isEntity(attributeType)) { - const targetEntity = attributeType; - const primaryAttribute = targetEntity.getPrimaryAttribute(); - attributeType = primaryAttribute.type; - } - - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - fields[attribute.gqlFieldName] = { - type: - attribute.required && - !entityMutation.ignoreRequired && - !attribute.i18n && - !attribute.defaultValue - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - - if (attribute.i18n) { - const i18nFieldType = generateI18nInputFieldType( - entity, - entityMutation, - attribute, - ); - - fields[attribute.gqlFieldNameI18n] = { - type: i18nFieldType, - }; - } - }); - - return fields; - }, - }); - - return entityMutationInstanceInputType; -}; - -export const generateMutationInput = ( - entity, - typeName, - entityMutation, - entityMutationInstanceInputType, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityMutationInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateMutationInputTypeName( - entity, - entityMutation, - ), - description: `Mutation input type for **\`${typeNamePascalCase}\`**`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = { - clientMutationId: { - type: GraphQLString, - }, - }; - - if (entityMutation.needsInstance) { - fields.nodeId = { - type: new GraphQLNonNull(GraphQLID), - }; - } - - if (entityMutationInstanceInputType) { - fields[typeName] = { - type: new GraphQLNonNull(entityMutationInstanceInputType), - }; - } - - return fields; - }, - }); - - return entityMutationInputType; -}; - -export const generateMutationByPrimaryAttributeInput = ( - entity, - typeName, - entityMutation, - entityMutationInstanceInputType, - primaryAttribute, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const fieldName = primaryAttribute.gqlFieldName; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - primaryAttribute.type, - entity.name, - true, - ); - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityMutationInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateMutationByPrimaryAttributeInputTypeName( - entity, - entityMutation, - primaryAttribute, - ), - description: `Mutation input type for **\`${typeNamePascalCase}\`** using the **\`${fieldName}\`**`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = { - clientMutationId: { - type: GraphQLString, - }, - }; - - if (entityMutation.needsInstance) { - fields[fieldName] = { - type: new GraphQLNonNull(fieldType), - }; - } - - if (entityMutationInstanceInputType) { - fields[typeName] = { - type: new GraphQLNonNull(entityMutationInstanceInputType), - }; - } - - return fields; - }, - }); - - return entityMutationInputType; -}; - -export const generateInstanceUniquenessInput = ( - entity, - uniquenessAttributes, - graphRegistry, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityInstanceInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateInstanceUniquenessInputTypeName( - entity, - uniquenessAttributes.uniquenessName, - ), - description: `Input type for **\`${typeNamePascalCase}\`** using data uniqueness (${uniquenessAttributes.attributes}) to resolve the ID`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = {}; - - const entityAttributes = entity.getAttributes(); - - _.forEach(uniquenessAttributes.attributes, attributeName => { - const attribute = entityAttributes[attributeName]; - - let attributeType = attribute.type; - - if (isEntity(attributeType)) { - const targetEntity = attributeType; - const primaryAttribute = targetEntity.getPrimaryAttribute(); - const targetTypeName = targetEntity.graphql.typeName; - - attributeType = primaryAttribute.type; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - const uniquenessAttributesList = getEntityUniquenessAttributes( - targetEntity, - ); - - if (uniquenessAttributesList.length === 0) { - fields[attribute.gqlFieldName] = { - type: attribute.required - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - } else { - fields[attribute.gqlFieldName] = { - type: fieldType, - }; - - const registryType = graphRegistry.types[targetTypeName]; - registryType.instanceUniquenessInputs = - registryType.instanceUniquenessInputs || {}; - - uniquenessAttributesList.map(({ uniquenessName }) => { - const fieldName = protocolConfiguration.generateUniquenessAttributesFieldName( - entity, - attribute, - uniquenessName, - ); - fields[fieldName] = { - type: registryType.instanceUniquenessInputs[uniquenessName], - }; - }); - } - } else { - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - fields[attribute.gqlFieldName] = { - type: new GraphQLNonNull(fieldType), - }; - } - }); - - return fields; - }, - }); - - return entityInstanceInputType; -}; - -export const generateInstanceUniquenessInputs = graphRegistry => { - _.forEach(graphRegistry.types, ({ entity }, typeName) => { - const uniquenessAttributesList = getEntityUniquenessAttributes(entity); - - const registryType = graphRegistry.types[typeName]; - registryType.instanceUniquenessInputs = - registryType.instanceUniquenessInputs || {}; - - uniquenessAttributesList.map(uniquenessAttributes => { - const instanceUniquenessInput = generateInstanceUniquenessInput( - entity, - uniquenessAttributes, - graphRegistry, - ); - registryType.instanceUniquenessInputs[ - uniquenessAttributes.uniquenessName - ] = instanceUniquenessInput; - }); - }); -}; - -export const generateMutationInstanceNestedInput = ( - entity, - entityMutation, - graphRegistry, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityMutationInstanceInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateMutationInstanceNestedInputTypeName( - entity, - entityMutation, - ), - description: `**\`${entityMutation.name}\`** mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = {}; - - const entityAttributes = entity.getAttributes(); - - _.forEach(entityMutation.attributes, attributeName => { - const attribute = entityAttributes[attributeName]; - - let attributeType = attribute.type; - - if (isEntity(attributeType)) { - const targetEntity = attributeType; - const primaryAttribute = targetEntity.getPrimaryAttribute(); - const targetTypeName = targetEntity.graphql.typeName; - - attributeType = primaryAttribute.type; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - const uniquenessAttributesList = getEntityUniquenessAttributes( - targetEntity, - ); - - if (uniquenessAttributesList.length === 0) { - fields[attribute.gqlFieldName] = { - type: - attribute.required && - !entityMutation.ignoreRequired && - !attribute.defaultValue - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - } else { - fields[attribute.gqlFieldName] = { - type: fieldType, - }; - - const registryType = graphRegistry.types[targetTypeName]; - registryType.instanceUniquenessInputs = - registryType.instanceUniquenessInputs || {}; - - uniquenessAttributesList.map(({ uniquenessName }) => { - const fieldName = protocolConfiguration.generateUniquenessAttributesFieldName( - entity, - attribute, - uniquenessName, - ); - fields[fieldName] = { - type: registryType.instanceUniquenessInputs[uniquenessName], - }; - }); - } - } else { - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - fields[attribute.gqlFieldName] = { - type: - attribute.required && - !entityMutation.ignoreRequired && - !attribute.i18n && - !attribute.defaultValue - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - - if (attribute.i18n) { - const i18nFieldType = generateI18nInputFieldType( - entity, - entityMutation, - attribute, - ); - - fields[attribute.gqlFieldNameI18n] = { - type: i18nFieldType, - }; - } - } - }); - - return fields; - }, - }); - - return entityMutationInstanceInputType; -}; - -export const generateMutationNestedInput = ( - entity, - typeName, - entityMutation, - entityMutationInstanceUniquenessInputType, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityMutationInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateMutationNestedInputTypeName( - entity, - entityMutation, - ), - description: `Mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = { - clientMutationId: { - type: GraphQLString, - }, - }; - - if (entityMutation.needsInstance) { - fields.nodeId = { - type: new GraphQLNonNull(GraphQLID), - }; - } - - if (entityMutationInstanceUniquenessInputType) { - fields[typeName] = { - type: new GraphQLNonNull(entityMutationInstanceUniquenessInputType), - }; - } - - return fields; - }, - }); - - return entityMutationInputType; -}; - -export const generateMutationOutput = ( - entity, - typeName, - type, - entityMutation, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityMutationOutputType = new GraphQLObjectType({ - name: protocolConfiguration.generateMutationOutputTypeName( - entity, - entityMutation, - ), - description: `Mutation output type for **\`${typeNamePascalCase}\`**`, - - fields: () => { - const fields: GraphQLFieldConfigMap = { - clientMutationId: { - type: GraphQLString, - }, - }; - - if (entityMutation.isTypeDelete) { - fields.deleteRowCount = { - type: new GraphQLNonNull(GraphQLInt), - description: 'Number of deleted rows', - }; - - const primaryAttribute = entity.getPrimaryAttribute(); - - if (primaryAttribute) { - const fieldName = primaryAttribute.gqlFieldName; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - primaryAttribute.type, - entity.name, - false, - ); - - fields[fieldName] = { - type: new GraphQLNonNull(fieldType), - description: primaryAttribute.description, - }; - } - } else { - fields[typeName] = { - type: new GraphQLNonNull(type), - }; - } - - return fields; - }, - }); - - return entityMutationOutputType; -}; - -const extractIdFromNodeId = (graphRegistry, sourceEntityName, nodeId) => { - let instanceId; - - if (nodeId) { - const { type, id } = fromGlobalId(nodeId); - - instanceId = id; - - const entity = graphRegistry.types[type] - ? graphRegistry.types[type].entity - : null; - - if (!entity || entity.name !== sourceEntityName) { - throw new Error('Incompatible nodeId used with this mutation'); - } - } - - return instanceId; -}; +import { + generateOperationInstanceInput, + generateOperationInput, + generateOperationOutput, + generateOperationInstanceNestedInput, + generateOperationNestedInput, + generateOperationByPrimaryAttributeInput, + extractIdFromNodeId, +} from './operation'; export const generateMutations = graphRegistry => { const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const mutations = {}; - generateInstanceUniquenessInputs(graphRegistry); + // generateInstanceUniquenessInputs(graphRegistry); _.forEach(graphRegistry.types, ({ type, entity }, typeName) => { if (!entity.getMutations) { @@ -587,7 +32,7 @@ export const generateMutations = graphRegistry => { } entityMutations.map(entityMutation => { - const mutationName = protocolConfiguration.generateMutationTypeName( + const mutationName = protocolConfiguration.generateOperationTypeName( entity, entityMutation, ); @@ -595,19 +40,19 @@ export const generateMutations = graphRegistry => { let entityMutationInstanceInputType; if (entityMutation.attributes && entityMutation.attributes.length) { - entityMutationInstanceInputType = generateMutationInstanceInput( + entityMutationInstanceInputType = generateOperationInstanceInput( entity, entityMutation, ); } - const mutationInputType = generateMutationInput( + const mutationInputType = generateOperationInput( entity, typeName, entityMutation, entityMutationInstanceInputType, ); - const mutationOutputType = generateMutationOutput( + const mutationOutputType = generateOperationOutput( entity, typeName, type, @@ -639,7 +84,7 @@ export const generateMutations = graphRegistry => { }; if (entityMutation.isTypeCreate || entityMutation.isTypeUpdate) { - const mutationNestedName = protocolConfiguration.generateMutationNestedTypeName( + const mutationNestedName = protocolConfiguration.generateOperationNestedTypeName( entity, entityMutation, ); @@ -647,14 +92,14 @@ export const generateMutations = graphRegistry => { let entityMutationInstanceNestedInputType; if (entityMutation.attributes && entityMutation.attributes.length) { - entityMutationInstanceNestedInputType = generateMutationInstanceNestedInput( + entityMutationInstanceNestedInputType = generateOperationInstanceNestedInput( entity, entityMutation, graphRegistry, ); } - const mutationInputNestedType = generateMutationNestedInput( + const mutationInputNestedType = generateOperationNestedInput( entity, typeName, entityMutation, @@ -690,14 +135,14 @@ export const generateMutations = graphRegistry => { if (primaryAttribute) { const fieldName = primaryAttribute.gqlFieldName; - const mutationByPrimaryAttributeInputType = generateMutationByPrimaryAttributeInput( + const mutationByPrimaryAttributeInputType = generateOperationByPrimaryAttributeInput( entity, typeName, entityMutation, entityMutationInstanceInputType, primaryAttribute, ); - const mutationByPrimaryAttributeName = protocolConfiguration.generateMutationByPrimaryAttributeTypeName( + const mutationByPrimaryAttributeName = protocolConfiguration.generateOperationByPrimaryAttributeTypeName( entity, entityMutation, primaryAttribute, diff --git a/src/graphqlProtocol/operation.ts b/src/graphqlProtocol/operation.ts new file mode 100644 index 00000000..d1446440 --- /dev/null +++ b/src/graphqlProtocol/operation.ts @@ -0,0 +1,608 @@ +import { + GraphQLString, + GraphQLID, + GraphQLNonNull, + GraphQLInputObjectType, + GraphQLObjectType, + GraphQLInt, + GraphQLInputFieldConfigMap, + GraphQLFieldConfigMap, + GraphQLNullableType, +} from 'graphql'; +import { fromGlobalId } from 'graphql-relay'; +import * as _ from 'lodash'; + +import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; +import { getEntityUniquenessAttributes } from './helper'; +import { isEntity } from '../engine/entity/Entity'; +import { Mutation, isMutation } from '../engine/mutation/Mutation'; +import { Subscription } from '..'; +import { isSubscription } from '../engine/subscription/Subscription'; + +const i18nInputFieldTypesCache = {}; + +const generateI18nInputFieldType = ( + entity, + entityOperation: Mutation | Subscription, + attribute, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const i18nFieldTypeName = protocolConfiguration.generateOperationI18nAttributeInputTypeName( + entity, + entityOperation, + attribute, + ); + + if (i18nInputFieldTypesCache[i18nFieldTypeName]) { + return i18nInputFieldTypesCache[i18nFieldTypeName]; + } + + const attributeType = attribute.type; + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + const languages = protocolConfiguration + .getParentConfiguration() + .getLanguages(); + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + attributeType, + entity.name, + true, + ); + + const i18nFieldType = new GraphQLInputObjectType({ + name: i18nFieldTypeName, + description: `**\`${entityOperation.name}\`** operation translations input type for **\`${typeNamePascalCase}.${attribute.gqlFieldName}\`**`, + + fields: () => { + const i18nFields = {}; + + languages.map((language, langIdx) => { + const type = + langIdx === 0 && attribute.required && !entityOperation.ignoreRequired + ? new GraphQLNonNull(fieldType) + : fieldType; + + i18nFields[language] = { + type, + }; + }); + + return i18nFields; + }, + }); + + i18nInputFieldTypesCache[i18nFieldTypeName] = i18nFieldType; + + return i18nFieldType; +}; + +export const generateOperationInstanceInput = (entity, entityOperation) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + + const entityOperationInstanceInputType = new GraphQLInputObjectType({ + name: protocolConfiguration.generateOperationInstanceInputTypeName( + entity, + entityOperation, + ), + description: `**\`${entityOperation.name}\`** operation input type for **\`${typeNamePascalCase}\`**`, + + fields: () => { + const fields: GraphQLInputFieldConfigMap = {}; + + const entityAttributes = entity.getAttributes(); + + _.forEach(entityOperation.attributes, attributeName => { + const attribute = entityAttributes[attributeName]; + + let attributeType = attribute.type; + + // it's a reference + if (isEntity(attributeType)) { + const targetEntity = attributeType; + const primaryAttribute = targetEntity.getPrimaryAttribute(); + attributeType = primaryAttribute.type; + } + + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + attributeType, + entity.name, + true, + ); + + fields[attribute.gqlFieldName] = { + type: + attribute.required && + !entityOperation.ignoreRequired && + !attribute.i18n && + !attribute.defaultValue + ? new GraphQLNonNull(fieldType) + : fieldType, + }; + + if (attribute.i18n) { + const i18nFieldType = generateI18nInputFieldType( + entity, + entityOperation, + attribute, + ); + + fields[attribute.gqlFieldNameI18n] = { + type: i18nFieldType, + }; + } + }); + + return fields; + }, + }); + + return entityOperationInstanceInputType; +}; + +export const generateOperationInput = ( + entity, + typeName: string, + entityOperation: Mutation | Subscription, + entityOperationInstanceInputType, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + + const entityOperationInputType = new GraphQLInputObjectType({ + name: protocolConfiguration.generateOperationInputTypeName( + entity, + entityOperation, + ), + description: `Operation input type for **\`${typeNamePascalCase}\`**`, + + fields: () => { + const fields: GraphQLInputFieldConfigMap = {}; + if (isMutation(entityOperation)) { + fields.clientMutationId = { + type: GraphQLString, + }; + } else if (isSubscription(entityOperation)) { + fields.clientSubscriptionId = { + type: GraphQLString, + }; + } + + if (entityOperation.needsInstance) { + fields.nodeId = { + type: new GraphQLNonNull(GraphQLID), + }; + } + + if (entityOperationInstanceInputType) { + fields[typeName] = { + type: new GraphQLNonNull(entityOperationInstanceInputType), + }; + } + + return fields; + }, + }); + + return entityOperationInputType; +}; + +export const generateOperationByPrimaryAttributeInput = ( + entity, + typeName: string, + entityOperation: Mutation | Subscription, + entityOperationInstanceInputType, + primaryAttribute, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const fieldName = primaryAttribute.gqlFieldName; + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + primaryAttribute.type, + entity.name, + true, + ); + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + + const entityOperationInputType = new GraphQLInputObjectType({ + name: protocolConfiguration.generateOperationByPrimaryAttributeInputTypeName( + entity, + entityOperation, + primaryAttribute, + ), + description: `Operation input type for **\`${typeNamePascalCase}\`** using the **\`${fieldName}\`**`, + + fields: () => { + const fields: GraphQLInputFieldConfigMap = {}; + if (isMutation(entityOperation)) { + fields.clientMutationId = { + type: GraphQLString, + }; + } else if (isSubscription(entityOperation)) { + fields.clientSubscriptionId = { + type: GraphQLString, + }; + } + + if (entityOperation.needsInstance) { + fields[fieldName] = { + type: new GraphQLNonNull(fieldType), + }; + } + + if (entityOperationInstanceInputType) { + fields[typeName] = { + type: new GraphQLNonNull(entityOperationInstanceInputType), + }; + } + + return fields; + }, + }); + + return entityOperationInputType; +}; + +export const generateInstanceUniquenessInput = ( + entity, + uniquenessAttributes, + graphRegistry, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + + // todo watch out for duplicate ! + const entityInstanceInputType = new GraphQLInputObjectType({ + name: protocolConfiguration.generateInstanceUniquenessInputTypeName( + entity, + uniquenessAttributes.uniquenessName, + ), + description: `Input type for **\`${typeNamePascalCase}\`** using data uniqueness (${uniquenessAttributes.attributes}) to resolve the ID`, + + fields: () => { + const fields: GraphQLInputFieldConfigMap = {}; + + const entityAttributes = entity.getAttributes(); + + _.forEach(uniquenessAttributes.attributes, attributeName => { + const attribute = entityAttributes[attributeName]; + + let attributeType = attribute.type; + + if (isEntity(attributeType)) { + const targetEntity = attributeType; + const primaryAttribute = targetEntity.getPrimaryAttribute(); + const targetTypeName = targetEntity.graphql.typeName; + + attributeType = primaryAttribute.type; + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + attributeType, + entity.name, + true, + ); + + const uniquenessAttributesList = getEntityUniquenessAttributes( + targetEntity, + ); + + if (uniquenessAttributesList.length === 0) { + fields[attribute.gqlFieldName] = { + type: attribute.required + ? new GraphQLNonNull(fieldType) + : fieldType, + }; + } else { + fields[attribute.gqlFieldName] = { + type: fieldType, + }; + + const registryType = graphRegistry.types[targetTypeName]; + registryType.instanceUniquenessInputs = + registryType.instanceUniquenessInputs || {}; + + uniquenessAttributesList.map(({ uniquenessName }) => { + const fieldName = protocolConfiguration.generateUniquenessAttributesFieldName( + entity, + attribute, + uniquenessName, + ); + fields[fieldName] = { + type: registryType.instanceUniquenessInputs[uniquenessName], + }; + }); + } + } else { + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + attributeType, + entity.name, + true, + ); + + fields[attribute.gqlFieldName] = { + type: new GraphQLNonNull(fieldType), + }; + } + }); + + return fields; + }, + }); + + return entityInstanceInputType; +}; + +export const generateInstanceUniquenessInputs = graphRegistry => { + _.forEach(graphRegistry.types, ({ entity }, typeName) => { + const uniquenessAttributesList = getEntityUniquenessAttributes(entity); + + const registryType = graphRegistry.types[typeName]; + registryType.instanceUniquenessInputs = + registryType.instanceUniquenessInputs || {}; + + uniquenessAttributesList.map(uniquenessAttributes => { + const instanceUniquenessInput = generateInstanceUniquenessInput( + entity, + uniquenessAttributes, + graphRegistry, + ); + // watching out for duplicate + if ( + !registryType.instanceUniquenessInputs[ + uniquenessAttributes.uniquenessName + ] + ) { + registryType.instanceUniquenessInputs[ + uniquenessAttributes.uniquenessName + ] = instanceUniquenessInput; + } + }); + }); +}; + +export const generateOperationInstanceNestedInput = ( + entity, + entityOperation: Mutation | Subscription, + graphRegistry, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + + const entityOperationInstanceInputType = new GraphQLInputObjectType({ + name: protocolConfiguration.generateOperationInstanceNestedInputTypeName( + entity, + entityOperation, + ), + description: `**\`${entityOperation.name}\`** operation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, + + fields: () => { + const fields: GraphQLInputFieldConfigMap = {}; + + const entityAttributes = entity.getAttributes(); + + _.forEach(entityOperation.attributes, attributeName => { + const attribute = entityAttributes[attributeName]; + + let attributeType = attribute.type; + + if (isEntity(attributeType)) { + const targetEntity = attributeType; + const primaryAttribute = targetEntity.getPrimaryAttribute(); + const targetTypeName = targetEntity.graphql.typeName; + + attributeType = primaryAttribute.type; + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + attributeType, + entity.name, + true, + ); + + const uniquenessAttributesList = getEntityUniquenessAttributes( + targetEntity, + ); + + if (uniquenessAttributesList.length === 0) { + fields[attribute.gqlFieldName] = { + type: + attribute.required && + !entityOperation.ignoreRequired && + !attribute.defaultValue + ? new GraphQLNonNull(fieldType) + : fieldType, + }; + } else { + fields[attribute.gqlFieldName] = { + type: fieldType, + }; + + const registryType = graphRegistry.types[targetTypeName]; + registryType.instanceUniquenessInputs = + registryType.instanceUniquenessInputs || {}; + + uniquenessAttributesList.map(({ uniquenessName }) => { + const fieldName = protocolConfiguration.generateUniquenessAttributesFieldName( + entity, + attribute, + uniquenessName, + ); + fields[fieldName] = { + type: registryType.instanceUniquenessInputs[uniquenessName], + }; + }); + } + } else { + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + attributeType, + entity.name, + true, + ); + + fields[attribute.gqlFieldName] = { + type: + attribute.required && + !entityOperation.ignoreRequired && + !attribute.i18n && + !attribute.defaultValue + ? new GraphQLNonNull(fieldType) + : fieldType, + }; + + if (attribute.i18n) { + const i18nFieldType = generateI18nInputFieldType( + entity, + entityOperation, + attribute, + ); + + fields[attribute.gqlFieldNameI18n] = { + type: i18nFieldType, + }; + } + } + }); + + return fields; + }, + }); + + return entityOperationInstanceInputType; +}; + +export const generateOperationNestedInput = ( + entity, + typeName: string, + entityOperation: Mutation | Subscription, + entityOperationInstanceUniquenessInputType, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + + const entityOperationInputType = new GraphQLInputObjectType({ + name: protocolConfiguration.generateOperationNestedInputTypeName( + entity, + entityOperation, + ), + description: `Operation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, + + fields: () => { + const fields: GraphQLInputFieldConfigMap = {}; + if (isMutation(entityOperation)) { + fields.clientMutationId = { + type: GraphQLString, + }; + } else if (isSubscription(entityOperation)) { + fields.clientSubscriptionId = { + type: GraphQLString, + }; + } + + if (entityOperation.needsInstance) { + fields.nodeId = { + type: new GraphQLNonNull(GraphQLID), + }; + } + + if (entityOperationInstanceUniquenessInputType) { + fields[typeName] = { + type: new GraphQLNonNull(entityOperationInstanceUniquenessInputType), + }; + } + + return fields; + }, + }); + + return entityOperationInputType; +}; + +export const generateOperationOutput = ( + entity, + typeName: string, + type: GraphQLNullableType, + entityOperation: Mutation | Subscription, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + const typeNamePascalCase = entity.graphql.typeNamePascalCase; + + const entityOperationOutputType = new GraphQLObjectType({ + name: protocolConfiguration.generateOperationOutputTypeName( + entity, + entityOperation, + ), + description: `Operation output type for **\`${typeNamePascalCase}\`**`, + + fields: () => { + const fields: GraphQLFieldConfigMap = {}; + if (isMutation(entityOperation)) { + fields.clientMutationId = { + type: GraphQLString, + }; + } else if (isSubscription(entityOperation)) { + fields.clientSubscriptionId = { + type: GraphQLString, + }; + } + + if (entityOperation.isTypeDelete) { + fields.deleteRowCount = { + type: new GraphQLNonNull(GraphQLInt), + description: 'Number of deleted rows', + }; + + const primaryAttribute = entity.getPrimaryAttribute(); + + if (primaryAttribute) { + const fieldName = primaryAttribute.gqlFieldName; + const fieldType = ProtocolGraphQL.convertToProtocolDataType( + primaryAttribute.type, + entity.name, + false, + ); + + fields[fieldName] = { + type: new GraphQLNonNull(fieldType), + description: primaryAttribute.description, + }; + } + } else { + fields[typeName] = { + type: new GraphQLNonNull(type), + }; + } + + return fields; + }, + }); + + return entityOperationOutputType; +}; + +export const extractIdFromNodeId = ( + graphRegistry, + sourceEntityName, + nodeId, +) => { + let instanceId; + + if (nodeId) { + const { type, id } = fromGlobalId(nodeId); + + instanceId = id; + + const entity = graphRegistry.types[type] + ? graphRegistry.types[type].entity + : null; + + if (!entity || entity.name !== sourceEntityName) { + throw new Error('Incompatible nodeId used with this mutation'); + } + } + + return instanceId; +}; diff --git a/src/graphqlProtocol/subscription.ts b/src/graphqlProtocol/subscription.ts index 70a070a7..8471b149 100644 --- a/src/graphqlProtocol/subscription.ts +++ b/src/graphqlProtocol/subscription.ts @@ -1,588 +1,27 @@ -import { - GraphQLString, - GraphQLID, - GraphQLNonNull, - GraphQLInputObjectType, - GraphQLObjectType, - GraphQLInt, - GraphQLInputFieldConfigMap, - GraphQLFieldConfigMap, -} from 'graphql'; -import { fromGlobalId } from 'graphql-relay'; +import { GraphQLNonNull } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; -import { getEntityUniquenessAttributes } from './helper'; import { getSubscriptionResolver, getSubscriptionPayloadResolver, } from './resolver'; -import { isEntity } from '../engine/entity/Entity'; - -const i18nInputFieldTypesCache = {}; - -const generateI18nInputFieldType = (entity, entitySubscription, attribute) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const i18nFieldTypeName = protocolConfiguration.generateSubscriptionI18nAttributeInputTypeName( - entity, - entitySubscription, - attribute, - ); - - if (i18nInputFieldTypesCache[i18nFieldTypeName]) { - return i18nInputFieldTypesCache[i18nFieldTypeName]; - } - - const attributeType = attribute.type; - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - const languages = protocolConfiguration - .getParentConfiguration() - .getLanguages(); - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - const i18nFieldType = new GraphQLInputObjectType({ - name: i18nFieldTypeName, - description: `**\`${entitySubscription.name}\`** subscription translations input type for **\`${typeNamePascalCase}.${attribute.gqlFieldName}\`**`, - - fields: () => { - const i18nFields = {}; - - languages.map((language, langIdx) => { - const type = - langIdx === 0 && - attribute.required && - !entitySubscription.ignoreRequired - ? new GraphQLNonNull(fieldType) - : fieldType; - - i18nFields[language] = { - type, - }; - }); - - return i18nFields; - }, - }); - - i18nInputFieldTypesCache[i18nFieldTypeName] = i18nFieldType; - - return i18nFieldType; -}; - -export const generateSubscriptionInstanceInput = ( - entity, - entitySubscription, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entitySubscriptionInstanceInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateSubscriptionInstanceInputTypeName( - entity, - entitySubscription, - ), - description: `**\`${entitySubscription.name}\`** subscription input type for **\`${typeNamePascalCase}\`**`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = {}; - - const entityAttributes = entity.getAttributes(); - - _.forEach(entitySubscription.attributes, attributeName => { - const attribute = entityAttributes[attributeName]; - - let attributeType = attribute.type; - - // it's a reference - if (isEntity(attributeType)) { - const targetEntity = attributeType; - const primaryAttribute = targetEntity.getPrimaryAttribute(); - attributeType = primaryAttribute.type; - } - - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - fields[attribute.gqlFieldName] = { - type: - attribute.required && - !entitySubscription.ignoreRequired && - !attribute.i18n && - !attribute.defaultValue - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - - if (attribute.i18n) { - const i18nFieldType = generateI18nInputFieldType( - entity, - entitySubscription, - attribute, - ); - - fields[attribute.gqlFieldNameI18n] = { - type: i18nFieldType, - }; - } - }); - - return fields; - }, - }); - - return entitySubscriptionInstanceInputType; -}; - -export const generateSubscriptionInput = ( - entity, - typeName, - entitySubscription, - entitySubscriptionInstanceInputType, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entitySubscriptionInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateSubscriptionInputTypeName( - entity, - entitySubscription, - ), - description: `Subscription input type for **\`${typeNamePascalCase}\`**`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = { - clientSubscriptionId: { - type: GraphQLString, - }, - }; - - if (entitySubscription.needsInstance) { - fields.nodeId = { - type: new GraphQLNonNull(GraphQLID), - }; - } - - if (entitySubscriptionInstanceInputType) { - fields[typeName] = { - type: new GraphQLNonNull(entitySubscriptionInstanceInputType), - }; - } - - return fields; - }, - }); - - return entitySubscriptionInputType; -}; - -export const generateSubscriptionByPrimaryAttributeInput = ( - entity, - typeName, - entitySubscription, - entitySubscriptionInstanceInputType, - primaryAttribute, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const fieldName = primaryAttribute.gqlFieldName; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - primaryAttribute.type, - entity.name, - true, - ); - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entitySubscriptionInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateMutationByPrimaryAttributeInputTypeName( - entity, - entitySubscription, - primaryAttribute, - ), - description: `Subscription input type for **\`${typeNamePascalCase}\`** using the **\`${fieldName}\`**`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = { - clientSubscriptionId: { - type: GraphQLString, - }, - }; - - if (entitySubscription.needsInstance) { - fields[fieldName] = { - type: new GraphQLNonNull(fieldType), - }; - } - - if (entitySubscriptionInstanceInputType) { - fields[typeName] = { - type: new GraphQLNonNull(entitySubscriptionInstanceInputType), - }; - } - - return fields; - }, - }); - - return entitySubscriptionInputType; -}; - -export const generateInstanceUniquenessInput = ( - entity, - uniquenessAttributes, - graphRegistry, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entityInstanceInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateInstanceUniquenessInputTypeName( - entity, - uniquenessAttributes.uniquenessName, - ), - description: `Input type for **\`${typeNamePascalCase}\`** using data uniqueness (${uniquenessAttributes.attributes}) to resolve the ID`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = {}; - - const entityAttributes = entity.getAttributes(); - - _.forEach(uniquenessAttributes.attributes, attributeName => { - const attribute = entityAttributes[attributeName]; - - let attributeType = attribute.type; - - if (isEntity(attributeType)) { - const targetEntity = attributeType; - const primaryAttribute = targetEntity.getPrimaryAttribute(); - const targetTypeName = targetEntity.graphql.typeName; - - attributeType = primaryAttribute.type; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - const uniquenessAttributesList = getEntityUniquenessAttributes( - targetEntity, - ); - - if (uniquenessAttributesList.length === 0) { - fields[attribute.gqlFieldName] = { - type: attribute.required - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - } else { - fields[attribute.gqlFieldName] = { - type: fieldType, - }; - - const registryType = graphRegistry.types[targetTypeName]; - registryType.instanceUniquenessInputs = - registryType.instanceUniquenessInputs || {}; - - uniquenessAttributesList.map(({ uniquenessName }) => { - const fieldName = protocolConfiguration.generateUniquenessAttributesFieldName( - entity, - attribute, - uniquenessName, - ); - fields[fieldName] = { - type: registryType.instanceUniquenessInputs[uniquenessName], - }; - }); - } - } else { - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - fields[attribute.gqlFieldName] = { - type: new GraphQLNonNull(fieldType), - }; - } - }); - - return fields; - }, - }); - - return entityInstanceInputType; -}; - -export const generateInstanceUniquenessInputs = graphRegistry => { - _.forEach(graphRegistry.types, ({ entity }, typeName) => { - const uniquenessAttributesList = getEntityUniquenessAttributes(entity); - - const registryType = graphRegistry.types[typeName]; - registryType.instanceUniquenessInputs = - registryType.instanceUniquenessInputs || {}; - - uniquenessAttributesList.map(uniquenessAttributes => { - const instanceUniquenessInput = generateInstanceUniquenessInput( - entity, - uniquenessAttributes, - graphRegistry, - ); - registryType.instanceUniquenessInputs[ - uniquenessAttributes.uniquenessName - ] = instanceUniquenessInput; - }); - }); -}; - -export const generateSubscriptionInstanceNestedInput = ( - entity, - entitySubscription, - graphRegistry, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entitySubscriptionInstanceInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateSubscriptionInstanceNestedInputTypeName( - entity, - entitySubscription, - ), - description: `**\`${entitySubscription.name}\`** subscription input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = {}; - - const entityAttributes = entity.getAttributes(); - - _.forEach(entitySubscription.attributes, attributeName => { - const attribute = entityAttributes[attributeName]; - - let attributeType = attribute.type; - - if (isEntity(attributeType)) { - const targetEntity = attributeType; - const primaryAttribute = targetEntity.getPrimaryAttribute(); - const targetTypeName = targetEntity.graphql.typeName; - - attributeType = primaryAttribute.type; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - const uniquenessAttributesList = getEntityUniquenessAttributes( - targetEntity, - ); - - if (uniquenessAttributesList.length === 0) { - fields[attribute.gqlFieldName] = { - type: - attribute.required && - !entitySubscription.ignoreRequired && - !attribute.defaultValue - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - } else { - fields[attribute.gqlFieldName] = { - type: fieldType, - }; - - const registryType = graphRegistry.types[targetTypeName]; - registryType.instanceUniquenessInputs = - registryType.instanceUniquenessInputs || {}; - - uniquenessAttributesList.map(({ uniquenessName }) => { - const fieldName = protocolConfiguration.generateUniquenessAttributesFieldName( - entity, - attribute, - uniquenessName, - ); - fields[fieldName] = { - type: registryType.instanceUniquenessInputs[uniquenessName], - }; - }); - } - } else { - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - attributeType, - entity.name, - true, - ); - - fields[attribute.gqlFieldName] = { - type: - attribute.required && - !entitySubscription.ignoreRequired && - !attribute.i18n && - !attribute.defaultValue - ? new GraphQLNonNull(fieldType) - : fieldType, - }; - - if (attribute.i18n) { - const i18nFieldType = generateI18nInputFieldType( - entity, - entitySubscription, - attribute, - ); - - fields[attribute.gqlFieldNameI18n] = { - type: i18nFieldType, - }; - } - } - }); - - return fields; - }, - }); - - return entitySubscriptionInstanceInputType; -}; - -export const generateSubscriptionNestedInput = ( - entity, - typeName, - entitySubscription, - entitySubscriptionInstanceUniquenessInputType, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entitySubscriptionInputType = new GraphQLInputObjectType({ - name: protocolConfiguration.generateSubscriptionNestedInputTypeName( - entity, - entitySubscription, - ), - description: `Mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, - - fields: () => { - const fields: GraphQLInputFieldConfigMap = { - clientSubscriptionId: { - type: GraphQLString, - }, - }; - - if (entitySubscription.needsInstance) { - fields.nodeId = { - type: new GraphQLNonNull(GraphQLID), - }; - } - - if (entitySubscriptionInstanceUniquenessInputType) { - fields[typeName] = { - type: new GraphQLNonNull( - entitySubscriptionInstanceUniquenessInputType, - ), - }; - } - - return fields; - }, - }); - - return entitySubscriptionInputType; -}; - -export const generateSubscriptionOutput = ( - entity, - typeName, - type, - entitySubscription, -) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - - const typeNamePascalCase = entity.graphql.typeNamePascalCase; - - const entitySubscriptionOutputType = new GraphQLObjectType({ - name: protocolConfiguration.generateSubscriptionOutputTypeName( - entity, - entitySubscription, - ), - description: `Subscription output type for **\`${typeNamePascalCase}\`**`, - - fields: () => { - const fields: GraphQLFieldConfigMap = { - clientSubscriptionId: { - type: GraphQLString, - }, - }; - - if (entitySubscription.isTypeDelete) { - fields.deleteRowCount = { - type: new GraphQLNonNull(GraphQLInt), - description: 'Number of deleted rows', - }; - - const primaryAttribute = entity.getPrimaryAttribute(); - - if (primaryAttribute) { - const fieldName = primaryAttribute.gqlFieldName; - const fieldType = ProtocolGraphQL.convertToProtocolDataType( - primaryAttribute.type, - entity.name, - false, - ); - - fields[fieldName] = { - type: new GraphQLNonNull(fieldType), - description: primaryAttribute.description, - }; - } - } else { - fields[typeName] = { - type: new GraphQLNonNull(type), - }; - } - - return fields; - }, - }); - - return entitySubscriptionOutputType; -}; - -const extractIdFromNodeId = (graphRegistry, sourceEntityName, nodeId) => { - let instanceId; - - if (nodeId) { - const { type, id } = fromGlobalId(nodeId); - - instanceId = id; - - const entity = graphRegistry.types[type] - ? graphRegistry.types[type].entity - : null; - - if (!entity || entity.name !== sourceEntityName) { - throw new Error('Incompatible nodeId used with this mutation'); - } - } - - return instanceId; -}; +import { + generateOperationInstanceInput, + generateOperationInput, + generateOperationOutput, + generateOperationInstanceNestedInput, + generateOperationNestedInput, + generateOperationByPrimaryAttributeInput, + extractIdFromNodeId, +} from './operation'; export const generateSubscriptions = graphRegistry => { const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const subscriptions = {}; - generateInstanceUniquenessInputs(graphRegistry); + // generateInstanceUniquenessInputs(graphRegistry); _.forEach(graphRegistry.types, ({ type, entity }, typeName) => { if (!entity.getSubscriptions) { @@ -598,7 +37,7 @@ export const generateSubscriptions = graphRegistry => { } entitySubscriptions.map(entitySubscription => { - const subscriptionName = protocolConfiguration.generateSubscriptionTypeName( + const subscriptionName = protocolConfiguration.generateOperationTypeName( entity, entitySubscription, ); @@ -609,19 +48,19 @@ export const generateSubscriptions = graphRegistry => { entitySubscription.attributes && entitySubscription.attributes.length ) { - entitySubscriptionInstanceInputType = generateSubscriptionInstanceInput( + entitySubscriptionInstanceInputType = generateOperationInstanceInput( entity, entitySubscription, ); } - const subscriptionInputType = generateSubscriptionInput( + const subscriptionInputType = generateOperationInput( entity, typeName, entitySubscription, entitySubscriptionInstanceInputType, ); - const subscriptionOutputType = generateSubscriptionOutput( + const subscriptionOutputType = generateOperationOutput( entity, typeName, type, @@ -653,7 +92,7 @@ export const generateSubscriptions = graphRegistry => { }; if (entitySubscription.isTypeCreate || entitySubscription.isTypeUpdate) { - const subscriptionNestedName = protocolConfiguration.generateSubscriptionNestedTypeName( + const subscriptionNestedName = protocolConfiguration.generateOperationNestedTypeName( entity, entitySubscription, ); @@ -664,14 +103,14 @@ export const generateSubscriptions = graphRegistry => { entitySubscription.attributes && entitySubscription.attributes.length ) { - entitySubscriptionInstanceNestedInputType = generateSubscriptionInstanceNestedInput( + entitySubscriptionInstanceNestedInputType = generateOperationInstanceNestedInput( entity, entitySubscription, graphRegistry, ); } - const subscriptionInputNestedType = generateSubscriptionNestedInput( + const subscriptionInputNestedType = generateOperationNestedInput( entity, typeName, entitySubscription, @@ -711,14 +150,14 @@ export const generateSubscriptions = graphRegistry => { if (primaryAttribute) { const fieldName = primaryAttribute.gqlFieldName; - const subscriptionByPrimaryAttributeInputType = generateSubscriptionByPrimaryAttributeInput( + const subscriptionByPrimaryAttributeInputType = generateOperationByPrimaryAttributeInput( entity, typeName, entitySubscription, entitySubscriptionInstanceInputType, primaryAttribute, ); - const subscriptionByPrimaryAttributeName = protocolConfiguration.generateSubscriptionByPrimaryAttributeTypeName( + const subscriptionByPrimaryAttributeName = protocolConfiguration.generateOperationByPrimaryAttributeTypeName( entity, entitySubscription, primaryAttribute,