/// <summary> /// Add any methods marked with GraphQLMutationAttribute in the given type to the schema. Names are added as lowerCaseCamel` /// </summary> /// <param name="mutationClassInstance"></param> /// <typeparam name="TType"></typeparam> public void AddMutationFrom <TType>(TType mutationClassInstance) { foreach (var method in mutationClassInstance.GetType().GetMethods()) { if (method.GetCustomAttribute(typeof(GraphQLMutationAttribute)) is GraphQLMutationAttribute attribute) { var isAsync = method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null; string name = SchemaGenerator.ToCamelCaseStartsLower(method.Name); //== JT: Allow user to customize the schema-first casing. var n = (System.ComponentModel.DisplayNameAttribute)method.GetCustomAttribute(typeof(System.ComponentModel.DisplayNameAttribute), false); if (n != null) { name = n.DisplayName; } //== var claims = method.GetCustomAttributes(typeof(GraphQLAuthorizeAttribute)).Cast <GraphQLAuthorizeAttribute>(); var requiredClaims = new RequiredClaims(claims); var actualReturnType = GetTypeFromMutationReturn(isAsync ? method.ReturnType.GetGenericArguments()[0] : method.ReturnType); var typeName = GetSchemaTypeNameForDotnetType(actualReturnType); var returnType = new GqlTypeInfo(() => GetReturnType(typeName), actualReturnType); var mutationType = new MutationType(this, name, returnType, mutationClassInstance, method, attribute.Description, requiredClaims, isAsync, SchemaFieldNamer); mutations[name] = mutationType; } } }
internal Field(string name, LambdaExpression resolve, string description, GqlTypeInfo returnType, RequiredClaims authorizeClaims) { Name = name; Description = description; AuthorizeClaims = authorizeClaims; ReturnType = returnType ?? throw new ArgumentNullException(nameof(returnType), "retypeType can not be null"); if (resolve != null) { if (resolve.Body.NodeType == ExpressionType.Call && ((MethodCallExpression)resolve.Body).Method.DeclaringType == typeof(ArgumentHelper) && ((MethodCallExpression)resolve.Body).Method.Name == "WithService") { // they are wanting services injected var call = (MethodCallExpression)resolve.Body; var lambdaExpression = (LambdaExpression)((UnaryExpression)call.Arguments.First()).Operand; Resolve = lambdaExpression.Body; Services = lambdaExpression.Parameters.Select(p => p.Type).ToList(); } else { Resolve = resolve.Body; } FieldParam = resolve.Parameters.First(); if (resolve.Body.NodeType == ExpressionType.MemberAccess) { ReturnType.TypeNotNullable = GraphQLNotNullAttribute.IsMemberMarkedNotNull(((MemberExpression)resolve.Body).Member) || ReturnType.TypeNotNullable; ReturnType.ElementTypeNullable = GraphQLElementTypeNullable.IsMemberElementMarkedNullable(((MemberExpression)resolve.Body).Member) || ReturnType.ElementTypeNullable; } } }
public MutationType(ISchemaProvider schema, string methodName, GqlTypeInfo returnType, object mutationClassInstance, MethodInfo method, string description, RequiredClaims authorizeClaims, bool isAsync) { Description = description; ReturnType = returnType; this.mutationClassInstance = mutationClassInstance; this.method = method; Name = methodName; AuthorizeClaims = authorizeClaims; this.isAsync = isAsync; argInstanceType = method.GetParameters() .FirstOrDefault(p => p.GetCustomAttribute(typeof(MutationArgumentsAttribute)) != null || p.ParameterType.GetTypeInfo().GetCustomAttribute(typeof(MutationArgumentsAttribute)) != null)?.ParameterType; if (argInstanceType != null) { foreach (var item in argInstanceType.GetProperties()) { if (GraphQLIgnoreAttribute.ShouldIgnoreMemberFromInput(item)) { continue; } argumentTypes.Add(SchemaGenerator.ToCamelCaseStartsLower(item.Name), ArgType.FromProperty(schema, item)); } foreach (var item in argInstanceType.GetFields()) { if (GraphQLIgnoreAttribute.ShouldIgnoreMemberFromInput(item)) { continue; } argumentTypes.Add(SchemaGenerator.ToCamelCaseStartsLower(item.Name), ArgType.FromField(schema, item)); } } }
/// <summary> /// Add a mapping from a Dotnet type to a GQL schema type. Make sure you have added the GQL type /// in the schema as a Scalar type or full type /// </summary> /// <param name="gqlType">The GQL schema type in full form. E.g. [Int!]!, [Int], Int, etc.</param> /// <typeparam name="TFrom"></typeparam> public void AddTypeMapping <TFrom>(string gqlType) { var typeInfo = GqlTypeInfo.FromGqlType(this, typeof(TFrom), gqlType); // add mapping customTypeMappings.Add(typeof(TFrom), typeInfo); SetupIntrospectionTypesAndField(); }
public MutationType(ISchemaProvider schema, string methodName, GqlTypeInfo returnType, object mutationClassInstance, MethodInfo method, string description, RequiredClaims authorizeClaims, bool isAsync, Func <MemberInfo, string> fieldNamer) { Description = description; ReturnType = returnType; this.mutationClassInstance = mutationClassInstance; this.method = method; Name = methodName; AuthorizeClaims = authorizeClaims; this.isAsync = isAsync; argInstanceType = method.GetParameters() .FirstOrDefault(p => p.GetCustomAttribute(typeof(MutationArgumentsAttribute)) != null || p.ParameterType.GetTypeInfo().GetCustomAttribute(typeof(MutationArgumentsAttribute)) != null)?.ParameterType; if (argInstanceType != null) { foreach (var item in argInstanceType.GetProperties()) { if (GraphQLIgnoreAttribute.ShouldIgnoreMemberFromInput(item)) { continue; } argumentTypes.Add(fieldNamer(item), ArgType.FromProperty(schema, item)); } foreach (var item in argInstanceType.GetFields()) { if (GraphQLIgnoreAttribute.ShouldIgnoreMemberFromInput(item)) { continue; } argumentTypes.Add(fieldNamer(item), ArgType.FromField(schema, item)); } } //== JT: Start Here else { /*== JT * When parameters are the standard System Types like; Int, String, etc or using the EntityGraphQL.Schema.RequiredField, * loop through the parameters and NOT the object's properties * NOTE: some parameters might be Services * EX: public ReturnModel RemoveById(DataContext context, RequiredField<int> id) */ // !! Forcing a single parameter ONLY. Anything more than that should require a POCO !! ParameterInfo item = method.GetParameters() .FirstOrDefault(p => p.ParameterType.Namespace.StartsWith("EntityGraphQL.Schema") || p.ParameterType.Namespace.StartsWith("System")); if (item.ParameterType.Name == "Nullable`1") { Type argType = item.ParameterType.GetGenericArguments()[0]; argInstanceType = argType; } else { argInstanceType = item.ParameterType; } //TODO: see if able to use the "fieldNamer()" function argumentTypes.Add(SchemaGenerator.ToCamelCaseStartsLower(item.Name), ArgType.FromParameter(schema, item)); } //== }
public static GqlTypeInfo FromGqlType(ISchemaProvider schema, Type dotnetType, string gqlType) { var strippedType = gqlType.Trim('!').Trim('[').Trim(']').Trim('!'); var typeInfo = new GqlTypeInfo(() => schema.Type(strippedType), dotnetType) { TypeNotNullable = gqlType.EndsWith("!"), IsList = gqlType.Contains("["), }; typeInfo.ElementTypeNullable = !(typeInfo.IsList && gqlType.Trim('!').Trim('[').Trim(']').EndsWith("!")); return(typeInfo); }
private static TypeElement BuildType(ISchemaProvider schema, GqlTypeInfo typeInfo, Type clrType, bool isInput = false) { // Is collection of objects? var type = new TypeElement(); if (clrType.IsEnumerableOrArray()) { type.Kind = "LIST"; type.Name = null; type.OfType = BuildType(schema, typeInfo, clrType.GetEnumerableOrArrayType(), isInput); } else if (clrType.Name == "EntityQueryType`1") { type.Kind = "SCALAR"; type.Name = "String"; type.OfType = null; } else if (clrType.GetTypeInfo().IsEnum) { type.Kind = "ENUM"; type.Name = typeInfo.SchemaType.Name; type.OfType = null; } else { type.Kind = typeInfo.SchemaType.IsScalar ? "SCALAR" : "OBJECT"; type.OfType = null; if (type.Kind == "OBJECT" && isInput) { type.Kind = "INPUT_OBJECT"; //== JT: !! INPUT_OBJECT names MUST use camelCase to avoid collision to OBJECT types !! type.Name = SchemaGenerator.ToCamelCaseStartsLower(typeInfo.SchemaType.Name); } else { type.Name = typeInfo.SchemaType.Name; } //== } if (typeInfo.TypeNotNullable) { return(new TypeElement { Kind = "NON_NULL", Name = null, OfType = type }); } return(type); }
private static TypeElement BuildType(ISchemaProvider schema, GqlTypeInfo typeInfo, Type clrType, bool isInput = false) { // Is collection of objects? var type = new TypeElement(); if (clrType.IsEnumerableOrArray()) { type.Kind = "LIST"; type.Name = null; type.OfType = BuildType(schema, typeInfo, clrType.GetEnumerableOrArrayType(), isInput); } else if (clrType.Name == "EntityQueryType`1") { type.Kind = "SCALAR"; type.Name = "String"; type.OfType = null; } else if (clrType.GetTypeInfo().IsEnum) { type.Kind = "ENUM"; type.Name = typeInfo.SchemaType.Name; type.OfType = null; } else { type.Kind = typeInfo.SchemaType.IsScalar ? "SCALAR" : "OBJECT"; type.OfType = null; if (type.Kind == "OBJECT" && isInput) { type.Kind = "INPUT_OBJECT"; } type.Name = typeInfo.SchemaType.Name; } if (typeInfo.TypeNotNullable) { return(new TypeElement { Kind = "NON_NULL", Name = null, OfType = type }); } return(type); }
/// <summary> /// Add any methods marked with GraphQLMutationAttribute in the given type to the schema. Names are added as lowerCaseCamel` /// </summary> /// <param name="mutationClassInstance"></param> /// <typeparam name="TType"></typeparam> public void AddMutationFrom <TType>(TType mutationClassInstance) { foreach (var method in mutationClassInstance.GetType().GetMethods()) { if (method.GetCustomAttribute(typeof(GraphQLMutationAttribute)) is GraphQLMutationAttribute attribute) { var isAsync = method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null; string name = SchemaFieldNamer(method.Name); var claims = method.GetCustomAttributes(typeof(GraphQLAuthorizeAttribute)).Cast <GraphQLAuthorizeAttribute>(); var requiredClaims = new RequiredClaims(claims); var actualReturnType = GetTypeFromMutationReturn(isAsync ? method.ReturnType.GetGenericArguments()[0] : method.ReturnType); var typeName = GetSchemaTypeNameForDotnetType(actualReturnType); var returnType = new GqlTypeInfo(() => GetReturnType(typeName), actualReturnType); var mutationType = new MutationType(this, name, returnType, mutationClassInstance, method, attribute.Description, requiredClaims, isAsync, SchemaFieldNamer); mutations[name] = mutationType; } } }
public Field(ISchemaProvider schema, string name, LambdaExpression resolve, string description, object argTypes, GqlTypeInfo returnType, RequiredClaims claims) : this(name, resolve, description, returnType, claims) { ArgumentTypesObject = argTypes; allArguments = argTypes.GetType().GetProperties().ToDictionary(p => p.Name, p => ArgType.FromProperty(schema, p)); argTypes.GetType().GetFields().ToDictionary(p => p.Name, p => ArgType.FromField(schema, p)).ToList().ForEach(kvp => allArguments.Add(kvp.Key, kvp.Value)); }