private static ObjectTypeDefinitionNode CreateObjectTypeDefinitionForTableOrView()

in src/Service.GraphQLBuilder/Sql/SchemaConverter.cs [151:229]


        private static ObjectTypeDefinitionNode CreateObjectTypeDefinitionForTableOrView(
            string entityName,
            DatabaseObject databaseObject,
            Entity configEntity,
            RuntimeEntities entities,
            IEnumerable<string> rolesAllowedForEntity,
            IDictionary<string, IEnumerable<string>> rolesAllowedForFields)
        {
            Dictionary<string, FieldDefinitionNode> fieldDefinitionNodes = new();
            SourceDefinition sourceDefinition = databaseObject.SourceDefinition;
            foreach ((string columnName, ColumnDefinition column) in sourceDefinition.Columns)
            {
                List<DirectiveNode> directives = new();
                if (sourceDefinition.PrimaryKey.Contains(columnName))
                {
                    directives.Add(new DirectiveNode(PrimaryKeyDirectiveType.DirectiveName, new ArgumentNode("databaseType", column.SystemType.Name)));
                }

                if (column.IsReadOnly)
                {
                    directives.Add(new DirectiveNode(AutoGeneratedDirectiveType.DirectiveName));
                }

                if (column.DefaultValue is not null)
                {
                    IValueNode arg = CreateValueNodeFromDbObjectMetadata(column.DefaultValue);

                    directives.Add(new DirectiveNode(DefaultValueDirectiveType.DirectiveName, new ArgumentNode("value", arg)));
                }

                // A field is added to the ObjectTypeDefinition when:
                // 1. The entity is a linking entity. A linking entity is not exposed by DAB for query/mutation but the fields are required to generate
                // object definitions of directional linking entities from source to target.
                // 2. The entity is not a linking entity and there is atleast one role allowed to access the field.
                if (rolesAllowedForFields.TryGetValue(key: columnName, out IEnumerable<string>? roles) || configEntity.IsLinkingEntity)
                {
                    // Roles will not be null here if TryGetValue evaluates to true, so here we check if there are any roles to process.
                    // This check is bypassed for linking entities for the same reason explained above.
                    if (configEntity.IsLinkingEntity || roles is not null && roles.Count() > 0)
                    {
                        FieldDefinitionNode field = GenerateFieldForColumn(configEntity, columnName, column, directives, roles);
                        fieldDefinitionNodes.Add(columnName, field);
                    }
                }
            }

            // A linking entity is not exposed in the runtime config file but is used by DAB to support multiple mutations on entities with M:N relationship.
            // Hence we don't need to process relationships for the linking entity itself.
            if (!configEntity.IsLinkingEntity)
            {
                // For an entity exposed in the config, process the relationships (if there are any)
                // sequentially and generate fields for them - to be added to the entity's ObjectTypeDefinition at the end.
                if (configEntity.Relationships is not null)
                {
                    foreach ((string relationshipName, EntityRelationship relationship) in configEntity.Relationships)
                    {
                        FieldDefinitionNode relationshipField = GenerateFieldForRelationship(
                            entityName,
                            databaseObject,
                            entities,
                            relationshipName,
                            relationship);
                        fieldDefinitionNodes.Add(relationshipField.Name.Value, relationshipField);
                    }
                }
            }

            // Top-level object type definition name should be singular.
            // The singularPlural.Singular value is used, and if not configured,
            // the top-level entity name value is used. No singularization occurs
            // if the top-level entity name is already plural.
            return new ObjectTypeDefinitionNode(
                location: null,
                name: new(value: GetDefinedSingularName(entityName, configEntity)),
                description: null,
                directives: GenerateObjectTypeDirectivesForEntity(entityName, configEntity, rolesAllowedForEntity),
                new List<NamedTypeNode>(),
                fieldDefinitionNodes.Values.ToImmutableList());
        }