internal static void Register <TProduct>(ComplexGraphType <TProduct> type, Func <IResolveFieldContext <TProduct>, Object> reviewResolver = null) where TProduct : IProduct { type.Field(p => p.Name).Description("The products name"); type.Field(p => p.Id).Description("The products id").Type(new NonNullGraphType(new IdGraphType())); type.Field(p => p.Stock).Description("The number of products in stock"); type.Field(p => p.Type).Description("The type of product"); type.Field <ListGraphType <ReviewType> >("reviews", resolve: reviewResolver); }
public static void Add(IStatsProvider statsProvider, ComplexGraphType <object> type) { type.Field <ListGraphType <StatType> >("stats", arguments: new QueryArguments { new QueryArgument(typeof(StringGraphType)) { Name = "team1", Description = "Team 1" }, new QueryArgument(typeof(StringGraphType)) { Name = "team2", Description = "Team 2" } }, resolve: context => { var c = context as ResolveFieldContext; var team1 = c.Arguments["team1"].ToString(); var team2 = c.Arguments["team2"].ToString(); return(statsProvider.GetStatsAsync(team1, team2).Result); }); }
public static ComplexGraphType <IPublishedContent> AddUmbracoBuiltInProperties(this ComplexGraphType <IPublishedContent> graphType) { // TODO: set this field name as a reserved property alias graphType.Field <PublishedContentDataGraphType>("_contentData", "Built in published content data.", resolve: context => context.Source).SetDoctypeMetadata(graphType.GetMetadata <string>("documentTypeAlias")); return(graphType); }
static void AddMember <TSource>(ComplexGraphType <TSource> graph, PropertyInfo property) { var(compile, propertyGraphType) = Compile <TSource>(property); var resolver = new SimpleFieldResolver <TSource>(compile); var graphQlField = graph.Field(type: propertyGraphType, name: property.Name); graphQlField.Resolver = resolver; }
public static void SetFields <TSourceType>(ComplexGraphType <TSourceType> type, IEnumerable <PropertyInfo> properties, GraphObjectTypeReflectionOptions <TSourceType> options) { // Default the options if we get a null passed in. if (options == null) { options = new GraphObjectTypeReflectionOptions <TSourceType>(); } //type.Name = typeof(TSourceType).GraphQLName(); // Don't do this, it will then break with Input types. // Helper method that works out if bool isNullable(PropertyInfo propertyInfo) { if (!options.Nullable.HasValue) { return(IsNullableProperty(propertyInfo)); } if (options.NullableProperties?.Any(p => GetPropertyName(p) == propertyInfo.Name) == true) { return(true); } if (options.NonNullableProperties?.Any(p => GetPropertyName(p) == propertyInfo.Name) == true) { return(false); } return(options.Nullable.Value); } foreach (var propertyInfo in properties) { if (options.ExcludedProperties?.Any(p => GetPropertyName(p) == propertyInfo.Name) == true) { continue; } if (options.SkipExisting) { if (type.Fields.Any(p => p.Name == propertyInfo.Name)) { continue; } } type.Field( type: propertyInfo.PropertyType.GetGraphTypeFromType(isNullable(propertyInfo)), name: propertyInfo.Name, description: propertyInfo.Description(), deprecationReason: propertyInfo.ObsoleteMessage() ).DefaultValue = (propertyInfo.GetCustomAttributes(typeof(DefaultValueAttribute), false).FirstOrDefault() as DefaultValueAttribute)?.Value; } }
public static GraphQL.Builders.FieldBuilder <object, IQueryable <TSource> > CustomField <TGraphType, TSource>( this ComplexGraphType <object> graphType, string name, System.Func <GraphQL.IResolveFieldContext <object>, IQueryable <TSource> > resolve) where TSource : class { var builder = graphType.Field <ObjectGraphType <IQueryable <TSource> >, IQueryable <TSource> >(name); builder.Resolve(resolve); return(builder); }
public static FieldType RemoteField <TSourceType>(this ComplexGraphType <TSourceType> self, IEnumerable <Type> types, string remoteMoniker, string typeName, string name, string description = null, QueryArguments arguments = null, Func <ResolveFieldContext <TSourceType>, object> resolve = null, string deprecationReason = null) { var type = types.FirstOrDefault(t => t.GetCustomAttributes(true).Any(a => a is RemoteLiteralGraphTypeMetadataAttribute metadata && metadata.RemoteMoniker == remoteMoniker && metadata.Name == typeName)); if (type == null) { throw new ArgumentException($"Couldn't find a type in {nameof(types)} with remote '{remoteMoniker}' and name '{name}'"); } return(self.Field(type, name, description, arguments, resolve, deprecationReason)); }
public static FieldType AssociationField <TSourceType>( this ComplexGraphType <TSourceType> _this, IGraphTypesCache graphTypesCache, string name, IReadOnlyList <string> allowedTypes, string roleId, GraphDirections graphDirection) { var graphTypes = allowedTypes.Select(ckId => graphTypesCache.GetOrCreate(ckId)); var unionType = new RtEntityAssociationType( $"{_this.Name}_{name}{CommonConstants.GraphQlUnionSuffix}", $"Association {roleId} ({graphDirection}) of entity type {_this.Name}", graphTypesCache, graphTypes, roleId, graphDirection); return(_this.Field(name, null, unionType, resolve: context => context.Source)); }
/// <summary> /// Adds a field that gets an entity by id. /// Example usage: /// <code> /// this.AddSingleField<Order, NodeObjectType<Order>, IdGraphType>("id", context => { /// var id = Guid.Parse(context.GetArgument<string>("id")); /// var order = orderRepository.GetOrderById(id); /// return order; /// }); /// </code> /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <typeparam name="TEntityGraphType">The type of the entity's GraphQL type (i.e. NodeObjectType<Entity>)</typeparam> /// <typeparam name="TId">The type of the id field (i.e. IdGraphType or IntGraphType)</typeparam> /// <param name="type"></param> /// <param name="idName">The name of the id property.</param> /// <param name="resolve">The resolving function that returns a <see cref="TEntity"/>.</param> /// <param name="name">The name of the field.</param> public static FieldType AddSingleField <TEntity, TEntityGraphType, TId>(this ComplexGraphType <object> type, string idName, Func <ResolveFieldContext <object>, object> resolve, string name = null) where TEntity : class, new() where TEntityGraphType : ComplexGraphType <object>, IGraphType <TEntity> where TId : GraphType { // create name if non is given var lowerCaseName = name != null ? name : $"{typeof(TEntity).Name.ToFirstLower()}"; var arguments = new QueryArguments( new QueryArgument <NonNullGraphType <TId> > { Name = idName, Description = $"id of a {lowerCaseName}" }); return(type.Field(typeof(TEntityGraphType).ConvertToVirtualType(), lowerCaseName, $"The {lowerCaseName}", arguments, resolve)); }
public static void AddField(IContainer container, ComplexGraphType <Object> obj, Type type, PropertyInfo propertyInfo, MethodInfo methodInfo) { if (propertyInfo.PropertyType == typeof(IContainer)) { return; } var fieldType = propertyInfo.PropertyType; var fieldName = StringExtensions.PascalCase(propertyInfo.Name); var fieldDescription = ""; var authFieldName = $"{type.FullName}.{propertyInfo.Name}"; Func <ResolveFieldContext <object>, object> contextResolve; if (methodInfo != null) { // Custom mapping of property contextResolve = context => { AuthorizeProperty(container, authFieldName); return(methodInfo.Invoke(obj, GetArgumentsForMethod(methodInfo, container, context))); }; } else { // 1 to 1 mapping of property to source contextResolve = context => { AuthorizeProperty(container, authFieldName); var properties = context.Source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); var sourceProp = properties.FirstOrDefault(p => p.Name == propertyInfo.Name); if (sourceProp == null) { throw new ArgumentException($"No matching source property found for GraphObject. Type: {type.Name} Property: {propertyInfo.Name}"); } return(sourceProp.GetValue(context.Source)); }; } var graphType = TypeLoader.GetGraphType(fieldType); var nonNull = Enumerable.Any(propertyInfo.CustomAttributes, a => a.AttributeType == typeof(RequiredAttribute)); if (nonNull) { graphType = typeof(NonNullGraphType <>).MakeGenericType(graphType); } obj.Field(graphType, fieldName, fieldDescription, null, contextResolve); container.GetInstance <AuthorizationMap>().AddAuthorization(type, propertyInfo); }
public static ComplexGraphType <IPublishedContent> AddUmbracoContentPropeties( this ComplexGraphType <IPublishedContent> graphType, IContentTypeComposition contentType, PublishedItemType publishedItemType) { var publishedContentType = PublishedContentType.Get(publishedItemType, contentType.Alias); foreach (var property in contentType.CompositionPropertyTypes) { //TODO: black/whitelist properties if (property.PropertyEditorAlias == Constants.PropertyEditors.ListViewAlias || property.PropertyEditorAlias == Constants.PropertyEditors.FolderBrowserAlias || property.Alias.StartsWith("umbracoMember")) { continue; } var publishedPropertyType = publishedContentType.GetPropertyType(property.Alias); var resolver = GraphQLValueResolversResolver.Current.FindResolver(publishedPropertyType) ?? new DefaultValueResolver(); var propertyGraphType = resolver.GetGraphQLType(publishedPropertyType); if (property.Mandatory) { propertyGraphType = typeof(NonNullGraphType <>).MakeGenericType(propertyGraphType); } graphType.Field( propertyGraphType, property.Alias.ToCamelCase(), property.Description, resolve: context => { var publishedProperty = context.Source.GetProperty(property.Alias); return(publishedProperty == null ? null : resolver.Resolve(publishedPropertyType, publishedProperty.Value)); } ).SetPermissions(graphType); } return(graphType); }
public static void Add(ITeamsProvider teamsProvider, ComplexGraphType<object> type) { type.Field<ListGraphType<TeamType>>("teams", arguments: new QueryArguments { new QueryArgument(typeof(StringGraphType)) { Name = "search", Description = "Search for teams", DefaultValue = "*" } }, resolve: context => { if (_teams == null) _teams = teamsProvider.GetTeamsAsync().Result; var search = (string)(context as ResolveFieldContext).Arguments["search"]; return search == "*" ? _teams : _teams.Where(t => t.Name.ToLower().Contains(search.ToLower())).OrderBy(t => t.Name).ToList(); }); }
public static void AddFields <T>(ComplexGraphType <T> graph, bool skipMutableFields = false) { bool isInputType = graph is IInputObjectGraphType; foreach (var exposedPropery in typeof(T).GetProperties().Where( p => Attribute.IsDefined(p, typeof(ApiAttribute)))) { if (skipMutableFields) { var mutable = (Attribute.GetCustomAttribute(exposedPropery, typeof(ApiAttribute)) as ApiAttribute).Mutable; if (!mutable) { continue; } } var underlyingType = exposedPropery.PropertyType; var isNullable = Nullable.GetUnderlyingType(underlyingType) != null; if (isNullable) { underlyingType = Nullable.GetUnderlyingType(exposedPropery.PropertyType); } var parameter = Expression.Parameter(typeof(T), "type"); var memberExpression = Expression.Property(parameter, exposedPropery.Name); var fieldExpression = Expression.Lambda(memberExpression, parameter); if (underlyingType.IsEnum) { RegisterEnum(underlyingType); } switch (underlyingType.Name) { case "String": graph.Field((Expression <Func <T, string> >)fieldExpression, isNullable, typeof(StringGraphType)); break; case "Int32": if (isNullable) { graph.Field((Expression <Func <T, int?> >)fieldExpression, isNullable, typeof(IntGraphType)); } else { graph.Field((Expression <Func <T, int> >)fieldExpression, isNullable, typeof(IntGraphType)); } break; case "Int64": case "Long": if (isNullable) { graph.Field((Expression <Func <T, Int64?> >)fieldExpression, isNullable, typeof(LongGraphType)); } else { graph.Field((Expression <Func <T, Int64> >)fieldExpression, isNullable, typeof(LongGraphType)); } break; case "Double": if (isNullable) { graph.Field((Expression <Func <T, double?> >)fieldExpression, isNullable, typeof(FloatGraphType)); } else { graph.Field((Expression <Func <T, double> >)fieldExpression, isNullable, typeof(FloatGraphType)); } break; case "DateTime": if (isNullable) { graph.Field((Expression <Func <T, DateTime?> >)fieldExpression, isNullable, typeof(DateTimeGraphType)); } else { graph.Field((Expression <Func <T, DateTime> >)fieldExpression, isNullable, typeof(DateTimeGraphType)); } break; case "Boolean": if (isNullable) { graph.Field((Expression <Func <T, bool?> >)fieldExpression, isNullable, typeof(BooleanGraphType)); } else { graph.Field((Expression <Func <T, bool> >)fieldExpression, isNullable, typeof(BooleanGraphType)); } break; case "List`1": graph.Field((dynamic)fieldExpression, isNullable, GetListGraphType(underlyingType.GetGenericArguments()[0], isInputType)); break; default: if (underlyingType.IsEnum) { graph.Field((dynamic)fieldExpression, isNullable, GetEnumType(underlyingType, isInputType)); } else // custom type { //graph.Field((dynamic)fieldExpression, isNullable, GetCustomGraphType(underlyingType, isInputType)); graph.Field((dynamic)fieldExpression, !isNullable, isInputType ? GetGraphInputType(exposedPropery.PropertyType, isInputType) : GetGraphType(exposedPropery.PropertyType, isInputType)); } break; } } }
public static ComplexGraphType <IPublishedContent> AddContentDataProperties(this ComplexGraphType <IPublishedContent> graphType) { //TODO: black/whitelist properties graphType.Field <NonNullGraphType <DateGraphType> >("createDate", "Create date of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <StringGraphType> >("creatorName", "Name of the content creator.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <StringGraphType> >("documentTypeAlias", "Document type alias of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <IdGraphType> >("id", "Unique id of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <IntGraphType> >("index", "Index of the content.", resolve: context => context.Source.GetIndex()).SetPermissions(graphType, true); graphType.Field <NonNullGraphType <IntGraphType> >("level", "Level of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <BooleanGraphType> >("isFirst", "Is the content first in the list.", resolve: context => context.Source.IsFirst()).SetPermissions(graphType, true); graphType.Field <NonNullGraphType <BooleanGraphType> >("isLast", "Is the content last in the list.", resolve: context => context.Source.IsLast()).SetPermissions(graphType, true); graphType.Field <NonNullGraphType <BooleanGraphType> >("isVisible", "Is the content visible.", resolve: context => context.Source.IsVisible()).SetPermissions(graphType, true); graphType.Field <NonNullGraphType <StringGraphType> >("name", "Name of the content.").SetPermissions(graphType, true); graphType.Field <PublishedContentGraphType>("parent", "Parent of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <IntGraphType> >("sortOrder", "SortOrder of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <DateGraphType> >("updateDate", "Update date of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <StringGraphType> >("url", "Url of the content.").SetPermissions(graphType, true); graphType.Field <NonNullGraphType <StringGraphType> >("urlAbsolute", "Absolute url of the content.", resolve: context => context.Source.UrlAbsolute()).SetPermissions(graphType, true); graphType.Field <NonNullGraphType <StringGraphType> >("writerName", "Name of the content writer.").SetPermissions(graphType, true); graphType.FilteredConnection <PublishedContentGraphType, IPublishedContent>() .Name("ancestors") .Description("Ancestors of the content.") .Argument <BooleanGraphType>("includeSelf", "include self in list") .Bidirectional() .Resolve(context => (context.GetArgument <bool?>("includeSelf") == true ? context.Source.AncestorsOrSelf() : context.Source.Ancestors()).Filter(context).ToConnection(context) ); graphType.FilteredConnection <PublishedContentGraphType, IPublishedContent>() .Name("siblings") .Description("Siblings of the content.") .Bidirectional() .Resolve(context => context.Source.Siblings().Filter(context).ToConnection(context)); graphType.FilteredConnection <PublishedContentGraphType, IPublishedContent>() .Name("children") .Description("Children of the content.") .Bidirectional() .Resolve(context => context.Source.Children.Filter(context).ToConnection(context)); return(graphType); }
/// <summary> /// Adds a connection field. /// Example usage: /// <code> /// this.AddConnectionField<Order, ObjectType<Order>>(context => /// { /// return new Connection<Order>(orderRepository.GetOrders()); /// }); /// </code> /// </summary> /// <typeparam name="T">The type of the model.</typeparam> /// <typeparam name="TT">The type of the GraphQL type (i.e. ObjectType<Model>)</typeparam> /// <param name="type"></param> /// <param name="resolve">The resolving func that retuns a connection model.</param> /// <param name="name">The name of the field.</param> public static FieldType AddConnectionField <T, TT>(this ComplexGraphType <object> type, Func <ResolveFieldContext <object>, object> resolve, string name = null, QueryArgument[] arguments = null) where T : class where TT : ComplexGraphType <object>, IGraphType <T> { // create name if non is given var lowerCaseName = name != null ? name : $"{typeof(T).Name.ToFirstLower()}s"; // build argument list... first default ones var args = new QueryArguments( new QueryArgument <IdGraphType> { Name = "after" }, new QueryArgument <IntGraphType> { Name = "first" }, new QueryArgument <IdGraphType> { Name = "before" }, new QueryArgument <IntGraphType> { Name = "last" }); // construct order by type // create a class type "additionsType" and add a property for each item in "arguments" // if any custom arguments are set if (arguments != null) { var additionsType = TypeExtensions.CreateAdditionsTypeForType(typeof(T), arguments.Select(a => a.Name).ToArray()); // create a type like OrderByType<T, additionsType> and use it below var orderByType = typeof(OrderByType <,>).MakeGenericType(new[] { typeof(T), additionsType }); args.Add(new QueryArgument(orderByType) { Name = "orderBy" }); } else { args.Add(new QueryArgument <OrderByType <T> > { Name = "orderBy" }); } // ... then add an optional argument for each property of T var properties = typeof(T).GetExactProperies(); foreach (var property in properties.Where(p => p.PropertyType.IsSimpleType())) { var propertyName = property.Name.ToFirstLower(); args.Add(new QueryArgument(property.PropertyType.MapToGraphType()) { Name = propertyName }); } // .. then add custom added arguments if (arguments != null) { args.AddRange(arguments); } // create field return(type.Field <ConnectionType <T, TT> >(lowerCaseName, $"The {lowerCaseName} connection.", args, resolve)); }
/// <summary> /// Creats a field from a given primitive property (like string, double, int etc.). /// </summary> /// <param name="type"></param> /// <param name="property">The property type to create a field for.</param> public static void CreateFieldFromPrimitiveProperty(this ComplexGraphType <object> type, PropertyInfo property) { var propertyName = property.Name.ToFirstLower(); type.Field(property.PropertyType.MapToGraphType(), propertyName); }
/// <summary> /// Adds a list field. /// Example usage: /// <code> /// this.AddListfield<Order, ObjectType<Order>>() /// </code> /// </summary> /// <typeparam name="T">The type of the model.</typeparam> /// <typeparam name="TT">The type of the GraphQL type (i.e. ObjectType<Model>)</typeparam> /// <param name="type"></param> /// <param name="name">The name of the field. When no name is given, it is derived from the model type name.</param> public static FieldType AddListField <T, TT>(this ComplexGraphType <object> type, string name = null) where T : class where TT : ComplexGraphType <object>, IGraphType <T> { var lowerCaseName = name != null ? name : $"{typeof(T).Name.ToFirstLower()}s"; return(type.Field <ListGraphType <TT> >(lowerCaseName)); }
public static FieldBuilder <object, ModelType> IdField <GraphType, ModelType, ParamType>(this ComplexGraphType <object> parent, string fieldName, string paramName, string paramDescription) where GraphType : IGraphType { return(parent.Field <GraphType, ModelType>() .Name(fieldName) .Argument <ParamType>(paramName, paramDescription)); }
public static void AddField(IContainer container, ComplexGraphType <Object> obj, Type type, PropertyInfo propertyInfo, MethodInfo methodInfo) { if (propertyInfo.PropertyType == typeof(IContainer)) { return; } var fieldType = propertyInfo.PropertyType; var fieldName = propertyInfo.Name.ToCamelCase(); var fieldDescription = ""; var authFieldName = $"{type.FullName}.{propertyInfo.Name}"; var sourceType = type.BaseType?.GenericTypeArguments.FirstOrDefault() ?? type; QueryArguments arguments = null; Func <ResolveFieldContext <object>, object> contextResolve; if (methodInfo != null) { arguments = GetPropertyArguments(sourceType, methodInfo); // Custom mapping of property contextResolve = context => { AuthorizeProperty(container, authFieldName); var sourceResolverInfo = container.GetInstance <ResolverInfoManager>().Create(context).First(); var output = methodInfo.Invoke(obj, GetArgumentValues(methodInfo, container, context, sourceResolverInfo)); output = container.GetInstance <ApiSchema>().PropertyFilterManager.Filter(sourceResolverInfo, propertyInfo, authFieldName, output); var baseType = TypeLoader.GetBaseType(output?.GetType(), out var isList); if (output != null && !baseType.IsValueType) { container.GetInstance <ResolverInfoManager>().Create(context, output, sourceResolverInfo); } return(output); }; } else { // 1 to 1 mapping of property to source contextResolve = context => { AuthorizeProperty(container, authFieldName); var properties = context.Source.GetType().GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); var sourceProp = properties.FirstOrDefault(p => p.Name == propertyInfo.Name); if (sourceProp == null) { throw new ArgumentException($"No matching source property found for GraphObject. Type: {type.Name} Property: {propertyInfo.Name}"); } var output = sourceProp.GetValue(context.Source); var sourceResolverInfo = container.GetInstance <ResolverInfoManager>().Create(context).First(); output = container.GetInstance <ApiSchema>().PropertyFilterManager.Filter(sourceResolverInfo, propertyInfo, authFieldName, output); var baseType = TypeLoader.GetBaseType(output?.GetType(), out var isList); if (output != null && !baseType.IsValueType) { container.GetInstance <ResolverInfoManager>().Create(context, output, sourceResolverInfo); } return(output); }; } var graphType = TypeLoader.GetGraphType(fieldType); var nonNull = Enumerable.Any(propertyInfo.CustomAttributes, a => a.AttributeType == typeof(RequiredAttribute)); if (nonNull) { graphType = typeof(NonNullGraphType <>).MakeGenericType(graphType); } var field = obj.Field(graphType, fieldName, fieldDescription, arguments, contextResolve); //field.ResolvedType = (IGraphType)Activator.CreateInstance(graphType); container.GetInstance <AuthorizationMap>().AddAuthorization(type, propertyInfo); }