private static InputObjectTypeDefinitionNode GenerateCreateInputTypeForRelationalDb()

in src/Service.GraphQLBuilder/Mutations/CreateMutationBuilder.cs [35:160]


        private static InputObjectTypeDefinitionNode GenerateCreateInputTypeForRelationalDb(
            Dictionary<NameNode, InputObjectTypeDefinitionNode> inputs,
            ObjectTypeDefinitionNode objectTypeDefinitionNode,
            string entityName,
            NameNode name,
            NameNode baseEntityName,
            IEnumerable<HotChocolate.Language.IHasName> definitions,
            DatabaseType databaseType,
            RuntimeEntities entities,
            bool IsMultipleCreateOperationEnabled)
        {
            NameNode inputName = GenerateInputTypeName(name.Value);

            if (inputs.ContainsKey(inputName))
            {
                return inputs[inputName];
            }

            // The input fields for a create object will be a combination of:
            // 1. Scalar input fields corresponding to columns which belong to the table.
            // 2. Complex input fields corresponding to related (target) entities (table backed entities, for now)
            // which are defined in the runtime config.
            List<InputValueDefinitionNode> inputFields = new();

            // 1. Scalar input fields.
            IEnumerable<InputValueDefinitionNode> scalarInputFields = objectTypeDefinitionNode.Fields
                .Where(field => IsBuiltInType(field.Type) && !IsAutoGeneratedField(field))
                .Select(field =>
                {
                    return GenerateScalarInputType(name, field, IsMultipleCreateOperationEnabled);
                });

            // Add scalar input fields to list of input fields for current input type.
            inputFields.AddRange(scalarInputFields);

            // Create input object for this entity.
            InputObjectTypeDefinitionNode input =
                new(
                    location: null,
                    inputName,
                    new StringValueNode($"Input type for creating {name}"),
                    new List<DirectiveNode>(),
                    inputFields
                );

            // Add input object to the dictionary of entities for which input object has already been created.
            // This input object currently holds only scalar fields.
            // The complex fields (for related entities) would be added later when we return from recursion.
            // Adding the input object to the dictionary ensures that we don't go into infinite recursion and return whenever
            // we find that the input object has already been created for the entity.
            inputs.Add(input.Name, input);

            // Generate fields for related entities when
            // 1. Multiple mutation operations are supported for the database type.
            // 2. Multiple mutation operations are enabled.
            if (IsMultipleCreateOperationEnabled)
            {
                // 2. Complex input fields.
                // Evaluate input objects for related entities.
                IEnumerable<InputValueDefinitionNode> complexInputFields =
                    objectTypeDefinitionNode.Fields
                    .Where(field => !IsBuiltInType(field.Type) && IsComplexFieldAllowedForCreateInputInRelationalDb(field, definitions))
                    .Select(field =>
                    {
                        string typeName = RelationshipDirectiveType.Target(field);
                        HotChocolate.Language.IHasName? def = definitions.FirstOrDefault(d => d.Name.Value.Equals(typeName));

                        if (def is null)
                        {
                            throw new DataApiBuilderException(
                                message: $"The type {typeName} is not a known GraphQL type, and cannot be used in this schema.",
                                statusCode: HttpStatusCode.ServiceUnavailable,
                                subStatusCode: DataApiBuilderException.SubStatusCodes.ErrorInInitialization);
                        }

                        if (!entities.TryGetValue(entityName, out Entity? entity) || entity.Relationships is null)
                        {
                            throw new DataApiBuilderException(
                                message: $"Could not find entity metadata for entity: {entityName}.",
                                statusCode: HttpStatusCode.ServiceUnavailable,
                                subStatusCode: DataApiBuilderException.SubStatusCodes.ErrorInInitialization);
                        }

                        string targetEntityName = entity.Relationships[field.Name.Value].TargetEntity;
                        if (IsMToNRelationship(entity, field.Name.Value))
                        {
                            // The field can represent a related entity with M:N relationship with the parent.
                            NameNode baseObjectTypeNameForField = new(typeName);
                            typeName = GenerateLinkingNodeName(baseEntityName.Value, typeName);
                            def = (ObjectTypeDefinitionNode)definitions.FirstOrDefault(d => d.Name.Value.Equals(typeName))!;

                            // Get entity definition for this ObjectTypeDefinitionNode.
                            // Recurse for evaluating input objects for related entities.
                            return GenerateComplexInputTypeForRelationalDb(
                                entityName: targetEntityName,
                                inputs: inputs,
                                definitions: definitions,
                                field: field,
                                typeName: typeName,
                                targetObjectTypeName: baseObjectTypeNameForField,
                                objectTypeDefinitionNode: (ObjectTypeDefinitionNode)def,
                                databaseType: databaseType,
                                entities: entities,
                                IsMultipleCreateOperationEnabled: IsMultipleCreateOperationEnabled);
                        }

                        // Get entity definition for this ObjectTypeDefinitionNode.
                        // Recurse for evaluating input objects for related entities.
                        return GenerateComplexInputTypeForRelationalDb(
                            entityName: targetEntityName,
                            inputs: inputs,
                            definitions: definitions,
                            field: field,
                            typeName: typeName,
                            targetObjectTypeName: new(typeName),
                            objectTypeDefinitionNode: (ObjectTypeDefinitionNode)def,
                            databaseType: databaseType,
                            entities: entities,
                            IsMultipleCreateOperationEnabled: IsMultipleCreateOperationEnabled);
                    });
                // Append relationship fields to the input fields.
                inputFields.AddRange(complexInputFields);
            }

            return input;
        }