public void Item_WithAttribute_AndAttributeIsAnInvalidName_ThrowsException() { Assert.Throws <GraphTypeDeclarationException>(() => { GraphTypeNames.ParseName <AttributedClassInvalidName>(TypeKind.OBJECT); }); }
public void GenericItem_WithAttribute_ThrowsException() { Assert.Throws <GraphTypeDeclarationException>(() => { var name = GraphTypeNames.ParseName <GenericClassWithAttribute <int, string> >(TypeKind.OBJECT); }); }
/// <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))); }
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); }
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); }
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; } }
/// <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))); }
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); }
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); } } }
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); }
/// <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))); }
/// <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); }
public void Item_WithAttribute_ReturnsAttributeDefinedName() { var name = GraphTypeNames.ParseName <AttributedClass>(TypeKind.OBJECT); Assert.AreEqual("AlternateName", name); }
/// <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)); } }
public void Item_WithNoAttribute_ReturnsNameOfClass() { var name = GraphTypeNames.ParseName <NoAttributeClass>(TypeKind.OBJECT); Assert.AreEqual(nameof(NoAttributeClass), name); }