Schema

Specification

Schema is defined by ISchema-interface.

using System;
using System.Collections.Generic;
using System.Linq;
using Tanka.GraphQL.TypeSystem.ValueSerialization;
using Tanka.GraphQL.ValueResolution;

namespace Tanka.GraphQL.TypeSystem
{
    public interface ISchema : IHasDirectives, IType
    {
        ObjectType? Subscription { get; }

        ObjectType Query { get; }

        ObjectType? Mutation { get; }

        INamedType GetNamedType(string name);

        IField GetField(string type, string name);

        IEnumerable<KeyValuePair<string, IField>> GetFields(string type);

        IQueryable<T> QueryTypes<T>(Predicate<T>? filter = null) where T : INamedType;

        DirectiveType GetDirectiveType(string name);

        IQueryable<DirectiveType> QueryDirectiveTypes(Predicate<DirectiveType> filter = null);

        IEnumerable<KeyValuePair<string, InputObjectField>> GetInputFields(string type);

        InputObjectField GetInputField(string type, string name);

        IEnumerable<ObjectType> GetPossibleTypes(IAbstractType abstractType);

        Resolver GetResolver(string type, string fieldName);

        Subscriber GetSubscriber(string type, string fieldName);

        IValueConverter GetValueConverter(string type);
    }
}

Rarely accessing the actual implemention class GraphSchema is required

Schema is immutable and cannot be changed directly once created. To create Schema instance you need to provide query root object at minimum. Optionally mutation and subscription roots can be also provided.

Basics

Built by SchemaBuilder

        public SchemaFacts()
        {
            Schema = new SchemaBuilder()
                .InputObject("input", out var input)
                .Connections(connect => connect
                    .InputField(input, "id", ScalarType.ID))
                .Query(out var query)
                .Connections(connect => connect
                    .Field(query, "name", ScalarType.String))
                .Build();
        }

Query root is ObjectType


        [Fact]
        public void Roots_Query()
        {
            /* Given */
            /* When */
            /* Then */
            Assert.NotNull(Schema.Query);
            Assert.IsType<ObjectType>(Schema.Query);
        }

Mutation is optional


        [Fact]
        public void Roots_Mutation()
        {
            /* Given */
            /* When */
            /* Then */
            Assert.Null(Schema.Mutation);
        }

Subscription is optional


        [Fact]
        public void Roots_Subscription()
        {
            /* Given */
            /* When */
            /* Then */
            Assert.Null(Schema.Subscription);
        }

Querying types

Query named types


        [Fact]
        public void GetNamedType()
        {
            /* Given */
            var namedTypeName = Schema.Query.Name;

            /* When */
            var namedType = Schema.GetNamedType(namedTypeName);

            /* Then */
            Assert.NotNull(namedType);
            Assert.IsAssignableFrom<INamedType>(namedType);
        }


        [Fact]
        public void QueryNamedTypes()
        {
            /* Given */
            bool TypesWithoutDescription(ObjectType type)
            {
                return string.IsNullOrEmpty(type.Description);
            }

            /* When */
            var undocumentedTypes = Schema.QueryTypes<ObjectType>(TypesWithoutDescription);

            /* Then */
            Assert.NotNull(undocumentedTypes);
            Assert.Single(undocumentedTypes, type => type.Name == "Query");
        }

Query directives


        [Fact]
        public void GetDirective()
        {
            /* Given */
            var directiveTypeName = DirectiveType.Include.Name;

            /* When */
            var directiveType = Schema.GetDirectiveType(directiveTypeName);

            /* Then */
            Assert.NotNull(directiveType);
            Assert.IsType<DirectiveType>(directiveType);
        }


        [Fact]
        public void QueryDirectives()
        {
            /* Given */
            bool AppliesToField(DirectiveType type)
            {
                return type.Locations.Contains(DirectiveLocation.FIELD);
            }

            /* When */
            var directives = Schema.QueryDirectiveTypes(AppliesToField)
                .ToList();

            /* Then */
            foreach (var directiveType in directives) 
                Assert.Contains(DirectiveLocation.FIELD, directiveType.Locations);
        }

Query fields


        [Fact]
        public void GetField()
        {
            /* Given */
            var namedTypeName = Schema.Query.Name;

            /* When */
            var field = Schema.GetField(namedTypeName, "name");

            /* Then */
            Assert.NotNull(field);
            Assert.Same(ScalarType.String, field.Type);
        }


        [Fact]
        public void GetFields()
        {
            /* Given */
            var namedTypeName = Schema.Query.Name;

            /* When */
            var fields = Schema.GetFields(namedTypeName);

            /* Then */
            Assert.Single(
                fields,
                kv => kv.Key == "name" && (ScalarType) kv.Value.Type == ScalarType.String);
        }

Query input fields


        [Fact]
        public void GetInputField()
        {
            /* Given */
            var inputTypeName = "input";

            /* When */
            var field = Schema.GetInputField(inputTypeName, "id");

            /* Then */
            Assert.NotNull(field);
            Assert.Same(ScalarType.ID, field.Type);
        }


        [Fact]
        public void GetInputFields()
        {
            /* Given */
            var inputTypeName = "input";

            /* When */
            var fields = Schema.GetInputFields(inputTypeName);

            /* Then */
            Assert.Single(
                fields,
                kv => kv.Key == "id" && (ScalarType) kv.Value.Type == ScalarType.ID);
        }

Defaults

By default Skip and Include directives are included


        [Fact]
        public void Included_directives()
        {
            /* Given */ 
            /* When */
            var directives = Schema.QueryDirectiveTypes();

            /* Then */
            Assert.Single(directives, DirectiveType.Include);
            Assert.Single(directives, DirectiveType.Skip);
        }

By default all standard ScalarTypes are included


        [Fact]
        public void Included_scalars()
        {
            /* Given */
            /* When */
            var scalars = Schema.QueryTypes<ScalarType>()
                .ToList();

            /* Then */
            foreach (var scalar in ScalarType.Standard)
            {
                Assert.Contains(scalar.Type, scalars);
            }
        }