Esempio n. 1
0
 public void Item_WithAttribute_AndAttributeIsAnInvalidName_ThrowsException()
 {
     Assert.Throws <GraphTypeDeclarationException>(() =>
     {
         GraphTypeNames.ParseName <AttributedClassInvalidName>(TypeKind.OBJECT);
     });
 }
Esempio n. 2
0
 public void GenericItem_WithAttribute_ThrowsException()
 {
     Assert.Throws <GraphTypeDeclarationException>(() =>
     {
         var name = GraphTypeNames.ParseName <GenericClassWithAttribute <int, string> >(TypeKind.OBJECT);
     });
 }
Esempio n. 3
0
        /// <summary>
        /// Parses the item definition.
        /// </summary>
        protected override void ParseTemplateDefinition()
        {
            if (!this.ObjectType.IsEnum)
            {
                return;
            }

            _name            = GraphTypeNames.ParseName(this.ObjectType, TypeKind.ENUM);
            this.Description = this.ObjectType.SingleAttributeOrDefault <DescriptionAttribute>()?.Description?.Trim();
            this.Route       = this.GenerateFieldPath();

            // parse the enum values for later injection
            foreach (var value in Enum.GetValues(this.ObjectType))
            {
                var fi = this.ObjectType.GetField(value.ToString());
                if (fi.SingleAttributeOrDefault <GraphSkipAttribute>() != null)
                {
                    continue;
                }

                var description = fi.SingleAttributeOrDefault <DescriptionAttribute>()?.Description ?? null;
                var enumAttrib  = fi.SingleAttributeOrDefault <GraphEnumValueAttribute>();

                var valueName = enumAttrib?.Name?.Trim() ?? Constants.Routing.ENUM_VALUE_META_NAME;
                if (valueName.Length == 0)
                {
                    valueName = Constants.Routing.ENUM_VALUE_META_NAME;
                }
                valueName = valueName.Replace(Constants.Routing.ENUM_VALUE_META_NAME, value.ToString());

                var deprecated = fi.SingleAttributeOrDefault <DeprecatedAttribute>();
                _values.Add(new GraphEnumOption(this.ObjectType, valueName, description, enumAttrib != null, deprecated != null, deprecated?.Reason));
            }
        }
        /// <summary>
        /// When overridden in a child class, this metyhod builds the route that will be assigned to this method
        /// using the implementation rules of the concrete type.
        /// </summary>
        /// <returns>GraphRoutePath.</returns>
        protected override GraphFieldPath GenerateFieldPath()
        {
            // a standard graph object cannot contain any route pathing or nesting like controllers can
            // before creating hte route, ensure that the declared name, by itself, is valid for graphql
            var graphName = GraphTypeNames.ParseName(this.ObjectType, TypeKind.INPUT_OBJECT);

            return(new GraphFieldPath(GraphFieldPath.Join(GraphCollection.Types, graphName)));
        }
Esempio n. 5
0
        public void Item_WithNoAttribute_StoredAsInputAndNormal_ReturnsNameOfClass()
        {
            var name      = GraphTypeNames.ParseName <NoAttributeClass>(TypeKind.OBJECT);
            var inputName = GraphTypeNames.ParseName <NoAttributeClass>(TypeKind.INPUT_OBJECT);

            Assert.AreEqual(nameof(NoAttributeClass), name);
            Assert.AreEqual($"Input_{nameof(NoAttributeClass)}", inputName);
        }
Esempio n. 6
0
        public void Item_ForceAssign_NewName_ReturnsNewName()
        {
            var name = GraphTypeNames.ParseName <NoAttributeClassForNewName>(TypeKind.OBJECT);

            Assert.AreEqual(nameof(NoAttributeClassForNewName), name);

            GraphTypeNames.AssignName(typeof(NoAttributeClassForNewName), TypeKind.OBJECT, "NewName123");
            name = GraphTypeNames.ParseName <NoAttributeClassForNewName>(TypeKind.OBJECT);
            Assert.AreEqual("NewName123", name);
        }
Esempio n. 7
0
        public void GenericItem_WithNoAttribute_StoresMultipleNamesCorrectly()
        {
            var name = GraphTypeNames.ParseName <GenericClass <int, string> >(TypeKind.OBJECT);

            Assert.AreEqual("GenericClass_int_string_", name);

            name = GraphTypeNames.ParseName <GenericClass <int, int> >(TypeKind.OBJECT);
            Assert.AreEqual("GenericClass_int_int_", name);

            name = GraphTypeNames.ParseName <GenericClass <int, string> >(TypeKind.OBJECT);
            Assert.AreEqual("GenericClass_int_string_", name);
        }
        /// <summary>
        /// Parses the template contents according to the rules of the template.
        /// </summary>
        public virtual void Parse()
        {
            this.DeclaredArgumentType = this.Parameter.ParameterType;
            this.ObjectType           = GraphValidation.EliminateWrappersFromCoreType(this.Parameter.ParameterType);

            // set the name
            _fieldDeclaration = this.Parameter.SingleAttributeOrDefault <FromGraphQLAttribute>();
            string name = null;

            if (_fieldDeclaration != null)
            {
                name = _fieldDeclaration?.ArgumentName?.Trim();
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                name = Constants.Routing.PARAMETER_META_NAME;
            }

            name       = name.Replace(Constants.Routing.PARAMETER_META_NAME, this.Parameter.Name);
            this.Route = new GraphArgumentFieldPath(this.Parent.Route, name);

            this.Description = this.Parameter.SingleAttributeOrDefault <DescriptionAttribute>()?.Description?.Trim();

            if (this.Parameter.HasDefaultValue && this.Parameter.DefaultValue != null)
            {
                // enums will present their default value as a raw int
                if (this.ObjectType.IsEnum)
                {
                    this.DefaultValue = Enum.ToObject(this.ObjectType, this.Parameter.DefaultValue);
                }
                else
                {
                    this.DefaultValue = this.Parameter.DefaultValue;
                }
            }

            // set appropriate meta data about this parameter for inclusion in the type system
            this.TypeExpression = GraphValidation.GenerateTypeExpression(this.DeclaredArgumentType, this);
            this.TypeExpression = this.TypeExpression.CloneTo(GraphTypeNames.ParseName(this.ObjectType, TypeKind.INPUT_OBJECT));

            // when this argument accepts the same data type as the data returned by its owners target source type
            // i.e. if the source data supplied to the field for resolution is the same as this argument
            // then assume this argument is to contain the source data
            // since the source data will be an OBJECT type (not INPUT_OBJECT) there is no way the user could have supplied it
            if (this.IsSourceDataArgument())
            {
                this.ArgumentModifiers = this.ArgumentModifiers
                                         | GraphArgumentModifiers.ParentFieldResult
                                         | GraphArgumentModifiers.Internal;
            }
        }
Esempio n. 9
0
        /// <summary>
        /// When overridden in a child class, this method builds the route that will be assigned to this method
        /// using the implementation rules of the concrete type.
        /// </summary>
        /// <returns>GraphRoutePath.</returns>
        protected override GraphFieldPath GenerateFieldPath()
        {
            // extract the parent name from the global meta data about the type being extended
            var parentName = GraphTypeNames.ParseName(_typeAttrib.TypeToExtend, TypeKind.OBJECT);

            // an object method cannot contain any route pathing or nesting like controller methods can
            // before creating hte route, ensure that the declared name, by itself, is valid for graphql
            var graphName = _typeAttrib.Template?.Trim() ?? Constants.Routing.ACTION_METHOD_META_NAME;

            graphName = graphName.Replace(Constants.Routing.ACTION_METHOD_META_NAME, this.Method.Name).Trim();

            return(new GraphFieldPath(GraphFieldPath.Join(GraphCollection.Types, parentName, graphName)));
        }
Esempio n. 10
0
        public void Item_EnumParsesToEnumName_RegardlessOfTypeKind()
        {
            var nameSet = new HashSet <string>();

            foreach (var typeKind in Enum.GetValues(typeof(TypeKind)).Cast <TypeKind>())
            {
                var name = GraphTypeNames.ParseName(typeof(EnumNameTest), typeKind);
                if (!nameSet.Contains(name))
                {
                    nameSet.Add(name);
                }

                Assert.AreEqual(1, nameSet.Count);
            }
        }
        /// <summary>
        /// Inspects the given type and, in accordance with the rules of this maker, will
        /// generate a complete set of necessary graph types required to support it.
        /// </summary>
        /// <param name="concreteType">The concrete type to incorporate into the schema.</param>
        /// <returns>GraphTypeCreationResult.</returns>
        public virtual GraphTypeCreationResult CreateGraphType(Type concreteType)
        {
            if (concreteType == null)
            {
                return(null);
            }

            var template = GraphQLProviders.TemplateProvider.ParseType(concreteType, TypeKind.OBJECT) as IObjectGraphTypeTemplate;

            if (template == null)
            {
                return(null);
            }

            var result    = new GraphTypeCreationResult();
            var formatter = _schema.Configuration.DeclarationOptions.GraphNamingFormatter;

            var fieldSet   = new List <IGraphField>();
            var fieldMaker = GraphQLProviders.GraphTypeMakerProvider.CreateFieldMaker(_schema);

            foreach (var fieldTemplate in ObjectGraphTypeMaker.GatherFieldTemplates(template, _schema))
            {
                var fieldResult = fieldMaker.CreateField(fieldTemplate);
                fieldSet.Add(fieldResult.Field);

                result.MergeDependents(fieldResult);
            }

            var objectType = new ObjectGraphType(
                formatter.FormatGraphTypeName(template.Name),
                concreteType,
                fieldSet)
            {
                Description = template.Description,
                Publish     = template.Publish,
            };

            // add in declared interfaces by name
            foreach (var iface in template.DeclaredInterfaces)
            {
                objectType.InterfaceNames.Add(formatter.FormatGraphTypeName(GraphTypeNames.ParseName(iface, TypeKind.OBJECT)));
            }

            result.GraphType    = objectType;
            result.ConcreteType = concreteType;
            return(result);
        }
Esempio n. 12
0
        public void Item_ScalarParsesToScalarName_Always()
        {
            foreach (var scalar in GraphQLProviders.ScalarProvider)
            {
                var nameSet      = new HashSet <string>();
                var concreteType = GraphQLProviders.ScalarProvider.RetrieveConcreteType(scalar.Name);
                foreach (var typeKind in Enum.GetValues(typeof(TypeKind)).Cast <TypeKind>())
                {
                    var name = GraphTypeNames.ParseName(concreteType, typeKind);
                    if (!nameSet.Contains(name))
                    {
                        nameSet.Add(name);
                    }

                    Assert.AreEqual(1, nameSet.Count);
                }
            }
        }
Esempio n. 13
0
        public void Parse_FieldAndDependencies_SetCorrectly()
        {
            var server = new TestServerBuilder().Build();

            var template = TemplateHelper.CreateGraphTypeTemplate <ComplexInputObject>(TypeKind.INPUT_OBJECT) as IInputObjectGraphTypeTemplate;

            var typeResult = this.MakeGraphType(typeof(ComplexInputObject), TypeKind.INPUT_OBJECT);
            var graphType  = typeResult.GraphType as IInputObjectGraphType;

            Assert.IsNotNull(graphType);

            var inputGraphTypeName = GraphTypeNames.ParseName(typeof(OneMarkedProperty), TypeKind.INPUT_OBJECT);

            Assert.AreEqual(2, graphType.Fields.Count);

            var field = graphType.Fields.FirstOrDefault(x => x.TypeExpression.TypeName == inputGraphTypeName);

            Assert.IsNotNull(field);

            // string, OneMarkedProperty
            Assert.AreEqual(2, typeResult.DependentTypes.Count());
            Assert.IsTrue(typeResult.DependentTypes.Any(x => x.Type == typeof(OneMarkedProperty) && x.ExpectedKind == TypeKind.INPUT_OBJECT));
            Assert.IsTrue(typeResult.DependentTypes.Any(x => x.Type == typeof(string) && x.ExpectedKind == TypeKind.SCALAR));
        }
        /// <summary>
        /// Creates a union graph type from the given proxy.
        /// </summary>
        /// <param name="proxy">The proxy to convert to a union.</param>
        /// <param name="ownerKind">The typekind of the <see cref="IGraphType"/> that sponsors this union.</param>
        /// <returns>IUnionGraphType.</returns>
        public IUnionGraphType CreateGraphType(IGraphUnionProxy proxy, TypeKind ownerKind)
        {
            if (proxy == null)
            {
                return(null);
            }

            var formatter = _schema.Configuration.DeclarationOptions.GraphNamingFormatter;
            var name      = formatter.FormatGraphTypeName(proxy.Name);
            var union     = new UnionGraphType(name, proxy)
            {
                Description = proxy.Description,
                Publish     = proxy.Publish,
            };

            foreach (var type in proxy.Types)
            {
                union.AddPossibleGraphType(
                    formatter.FormatGraphTypeName(GraphTypeNames.ParseName(type, ownerKind)),
                    type);
            }

            return(union);
        }
Esempio n. 15
0
        /// <summary>
        /// When overridden in a child class, this method builds the unique graph route that will be assigned to this instance
        /// using the implementation rules of the concrete type.
        /// </summary>
        /// <returns>GraphRoutePath.</returns>
        protected override GraphFieldPath GenerateFieldPath()
        {
            var name = GraphTypeNames.ParseName(this.ObjectType, TypeKind.DIRECTIVE);

            return(new GraphFieldPath(GraphFieldPath.Join(GraphCollection.Directives, name)));
        }
Esempio n. 16
0
        /// <summary>
        /// When overridden in a child class this method builds out the template according to its own individual requirements.
        /// </summary>
        protected override void ParseTemplateDefinition()
        {
            _fieldDeclaration = this.SingleAttributeOfTypeOrDefault <GraphFieldAttribute>();

            // ------------------------------------
            // Common Metadata
            // ------------------------------------
            this.Route       = this.GenerateFieldPath();
            this.Mode        = _fieldDeclaration?.ExecutionMode ?? FieldResolutionMode.PerSourceItem;
            this.Complexity  = _fieldDeclaration?.Complexity;
            this.Description = this.SingleAttributeOfTypeOrDefault <DescriptionAttribute>()?.Description;
            var depreciated = this.SingleAttributeOfTypeOrDefault <DeprecatedAttribute>();

            if (depreciated != null)
            {
                this.IsDeprecated      = true;
                this.DeprecationReason = depreciated.Reason?.Trim();
            }

            var objectType     = GraphValidation.EliminateWrappersFromCoreType(this.DeclaredReturnType);
            var typeExpression = GraphValidation.GenerateTypeExpression(this.DeclaredReturnType, this);

            typeExpression = typeExpression.CloneTo(GraphTypeNames.ParseName(objectType, this.Parent.Kind));

            // ------------------------------------
            // Gather Possible Types and/or union definition
            // ------------------------------------
            this.BuildUnionProxyInstance();
            if (this.UnionProxy != null)
            {
                this.PossibleTypes = new List <Type>(this.UnionProxy.Types);
            }
            else
            {
                this.PossibleTypes = new List <Type>();

                // the possible types attribte is optional but expects taht the concrete types are added
                // to the schema else where lest a runtime exception occurs of a missing graph type.
                var typesAttrib = this.SingleAttributeOfTypeOrDefault <PossibleTypesAttribute>();
                if (typesAttrib != null)
                {
                    foreach (var type in typesAttrib.PossibleTypes)
                    {
                        this.PossibleTypes.Add(type);
                    }
                }

                // add any types decalred on the primary field declaration
                if (_fieldDeclaration != null)
                {
                    foreach (var type in _fieldDeclaration.Types)
                    {
                        var strippedType = GraphValidation.EliminateWrappersFromCoreType(type);
                        if (strippedType != null)
                        {
                            this.PossibleTypes.Add(strippedType);
                        }
                    }
                }

                if (objectType != null && !Validation.IsCastable <IGraphActionResult>(objectType) && GraphValidation.IsValidGraphType(objectType))
                {
                    this.PossibleTypes.Insert(0, objectType);
                }
            }

            this.PossibleTypes = this.PossibleTypes.Distinct().ToList();

            // ------------------------------------
            // Adjust the action result to the actual return type this field returns
            // ------------------------------------
            if (Validation.IsCastable <IGraphActionResult>(objectType))
            {
                if (this.UnionProxy != null)
                {
                    // if a union was decalred preserve whatever modifer elements
                    // were decalred but alter the return type to object (a known common element among all members of the union)
                    objectType = typeof(object);
                }
                else if (_fieldDeclaration != null && _fieldDeclaration.Types.Count > 0)
                {
                    objectType     = _fieldDeclaration.Types[0];
                    typeExpression = GraphValidation.GenerateTypeExpression(objectType, this)
                                     .CloneTo(GraphTypeNames.ParseName(objectType, this.Parent.Kind));
                    objectType = GraphValidation.EliminateWrappersFromCoreType(objectType);
                }
                else if (this.PossibleTypes.Count > 0)
                {
                    objectType     = this.PossibleTypes[0];
                    typeExpression = GraphValidation.GenerateTypeExpression(objectType, this)
                                     .CloneTo(GraphTypeNames.ParseName(objectType, this.Parent.Kind));
                    objectType = GraphValidation.EliminateWrappersFromCoreType(objectType);
                }
                else
                {
                    objectType = typeof(object);
                }
            }

            this.ObjectType = objectType;

            if (this.UnionProxy != null)
            {
                this.TypeExpression = typeExpression.CloneTo(this.UnionProxy.Name);
            }
            else
            {
                this.TypeExpression = typeExpression;
            }

            // ------------------------------------
            // Async Requirements
            // ------------------------------------
            this.IsAsyncField = Validation.IsCastable <Task>(this.DeclaredReturnType);

            // ------------------------------------
            // Security Policies
            // ------------------------------------
            _securityPolicies = FieldSecurityGroup.FromAttributeCollection(this.AttributeProvider);
        }
Esempio n. 17
0
        public void Item_WithAttribute_ReturnsAttributeDefinedName()
        {
            var name = GraphTypeNames.ParseName <AttributedClass>(TypeKind.OBJECT);

            Assert.AreEqual("AlternateName", name);
        }
Esempio n. 18
0
        /// <summary>
        /// Parses the item definition.
        /// </summary>
        protected override void ParseTemplateDefinition()
        {
            if (!this.ObjectType.IsEnum)
            {
                return;
            }

            _name            = GraphTypeNames.ParseName(this.ObjectType, TypeKind.ENUM);
            this.Description = this.ObjectType.SingleAttributeOrDefault <DescriptionAttribute>()?.Description?.Trim();
            this.Route       = this.GenerateFieldPath();

            // parse the enum values for later injection
            var labels         = Enum.GetNames(this.ObjectType);
            var typeIsUnsigned = this.ObjectType.IsEnumOfUnsignedNumericType();

            foreach (var label in labels)
            {
                var fi = this.ObjectType.GetField(label);

                var value = fi.GetValue(null);

                // we must have unique labels to values
                // (no enums with duplicate values)
                // to prevent potential ambiguity in down stream
                // requests
                //
                // for instance, if an enum existed such that:
                // enum SomeEnum
                // {
                //    Value1 = 1,
                //    Value2 = 1,
                // }
                //
                // then the operation
                // var enumValue = (SomeEnum)1;
                //
                // is indeterminate as to which is the appropriate
                // label to apply to the value for conversion
                // into the coorisponding enum graph type
                // and ultimately serialization
                // to a requestor
                string numericAsString;
                if (typeIsUnsigned)
                {
                    numericAsString = Convert.ToUInt64(value).ToString();
                }
                else
                {
                    numericAsString = Convert.ToInt64(value).ToString();
                }

                if (!_valuesTolabels.ContainsKey(numericAsString))
                {
                    _valuesTolabels.Add(numericAsString, new List <string>());
                }

                _valuesTolabels[numericAsString].Add(label);
                if (_valuesTolabels[numericAsString].Count != 1)
                {
                    continue;
                }

                if (fi.SingleAttributeOrDefault <GraphSkipAttribute>() != null)
                {
                    continue;
                }

                var description = fi.SingleAttributeOrDefault <DescriptionAttribute>()?.Description ?? null;
                var enumAttrib  = fi.SingleAttributeOrDefault <GraphEnumValueAttribute>();

                var valueName = enumAttrib?.Name?.Trim() ?? Constants.Routing.ENUM_VALUE_META_NAME;
                if (valueName.Length == 0)
                {
                    valueName = Constants.Routing.ENUM_VALUE_META_NAME;
                }

                valueName = valueName.Replace(Constants.Routing.ENUM_VALUE_META_NAME, label);

                var deprecated = fi.SingleAttributeOrDefault <DeprecatedAttribute>();
                _values.Add(new GraphEnumOption(this.ObjectType, valueName, description, enumAttrib != null, deprecated != null, deprecated?.Reason));
            }
        }
Esempio n. 19
0
        public void Item_WithNoAttribute_ReturnsNameOfClass()
        {
            var name = GraphTypeNames.ParseName <NoAttributeClass>(TypeKind.OBJECT);

            Assert.AreEqual(nameof(NoAttributeClass), name);
        }