public ResourceProperty(IResourceTypeResolver typeResolver, PropertyInfo propertyInfo, ResourceType reflectedType) : base(typeResolver, propertyInfo, reflectedType) { this.resourcePropertyDetails = CreateLazy(() => typeResolver.LoadResourcePropertyDetails(this)); }
protected virtual Func<PomonaContext, PomonaResponse> ResolveGetCollection(Route route, ResourceType resourceType) { var propertyRoute = route as ResourcePropertyRoute; if (propertyRoute != null) return ResolveGetCollectionProperty(propertyRoute, propertyRoute.Property, resourceType); return null; }
public DataSourceCollectionRoute(DataSourceRootRoute parent, ResourceType resultItemType) : base(0, parent) { if (resultItemType == null) throw new ArgumentNullException(nameof(resultItemType)); this.parent = parent; this.resultItemType = resultItemType; ResultType = parent.TypeMapper.FromType(typeof(IEnumerable<>).MakeGenericType(resultItemType)); }
public GetByIdRoute(ResourceType resultItemType, Route parent, HttpMethod allowedMethods) : base(10, parent) { if (resultItemType == null) throw new ArgumentNullException(nameof(resultItemType)); this.resultItemType = resultItemType; AllowedMethods = allowedMethods; IdProperty = this.resultItemType.PrimaryId; if (IdProperty == null) throw new ArgumentException("Resource in collection needs to have a primary id."); }
private RouteAction MatchCollectionNodeRequest(HttpMethod method, ResourceType resourceType) { switch (method) { case HttpMethod.Post: return NameStartsWith(method) ? MatchMethodTakingForm(resourceType) : null; case HttpMethod.Get: return MatchMethodReturningQueryable(resourceType); } return null; }
private static Func<PomonaContext, PomonaResponse> ResolvePatch(Route route, ResourceType resourceItemType) { if (route.IsSingle) { return pr => { var patchedObject = pr.Bind(); var dataSource = GetDataSource(pr.Session); var patchedType = patchedObject.GetType(); return new PomonaResponse(pr, dataSource.Patch(patchedType, patchedObject)); }; } return null; }
protected virtual Func<PomonaContext, PomonaResponse> ResolveGetById(GetByIdRoute route, ResourceType resourceType) { var idProp = route.IdProperty; var idType = idProp.PropertyType; return pr => { var segmentValue = pr.Node.PathSegment.Parse(idType); var segmentExpression = Ex.Const(segmentValue, idType); var whereExpression = pr.Node.Parent .Query() .WhereEx(ex => ex.Apply(idProp.CreateGetterExpression) == segmentExpression); var queryableResult = whereExpression.WrapActionResult(QueryProjection.FirstOrDefault); return new PomonaResponse(pr, queryableResult); }; }
public ResourceTypeDetails(ResourceType type, string uriRelativePath, bool isExposedAsRepository, Type postReturnType, PropertyInfo parentToChildPropertyInfo, PropertyInfo childToParentPropertyInfo) { if (type == null) throw new ArgumentNullException("type"); this.type = type; this.uriRelativePath = uriRelativePath; this.isExposedAsRepository = isExposedAsRepository; this.postReturnType = postReturnType; this.parentToChildPropertyInfo = parentToChildPropertyInfo; this.childToParentPropertyInfo = childToParentPropertyInfo; }
public ResourceNode(ITypeMapper typeMapper, PathNode parent, string name, Func<object> valueFetcher, ResourceType expectedType) : base(typeMapper, parent, name) { this.value = new System.Lazy<object>(valueFetcher); this.expectedType = expectedType; this.type = new System.Lazy<ResourceType>(() => { var localValue = Value; if (Value == null) return expectedType; return (ResourceType)typeMapper.GetClassMapping(localValue.GetType()); }); }
protected virtual Func<PomonaContext, PomonaResponse> ResolveGetCollectionProperty(ResourcePropertyRoute route, ResourceProperty property, ResourceType resourceItemType) { if (this.capabilityResolver.PropertyIsMapped(property.PropertyInfo) || property.GetPropertyFormula() != null) { return pr => { // Check existance of parent here, cannot differentiate between an empty collection and not found. var parent = pr.Node.Parent; if (parent.Route.IsSingle) { if (!parent.Exists) throw new ResourceNotFoundException("Resource not found."); } return new PomonaResponse( parent .Query() .OfTypeIfRequired(pr.Node.Route.InputType) .SelectManyEx(x => x.Apply(property.CreateGetterExpression)) .WrapActionResult(defaultPageSize : property.ExposedAsRepository ? (int?)null : int.MaxValue)); }; } else { return pr => { var parentNode = pr.Node.Parent; if (parentNode.Route.IsSingle) return new PomonaResponse(((IEnumerable)property.GetValue(parentNode.Get())).AsQueryable()); return new PomonaResponse( pr.Node.Parent .Query() .OfTypeIfRequired(pr.Node.Route.InputType) .ToListDetectType() .AsQueryable() .SelectManyEx(x => x.Apply(property.CreateGetterExpression)) .WrapActionResult(defaultPageSize : property.ExposedAsRepository ? (int?)null : int.MaxValue)); }; } }
private static Func<PomonaContext, PomonaResponse> ResolveGetCollection(Route route, ResourceType resourceType) { var dataSourceCollectionRoute = route as DataSourceCollectionRoute; if (dataSourceCollectionRoute != null) { return pr => { Type[] qTypeArgs; var elementType = resourceType.Type; if (pr.AcceptType != null && pr.AcceptType.TryExtractTypeArguments(typeof(IQueryable<>), out qTypeArgs)) elementType = qTypeArgs[0]; var dataSource = GetDataSource(pr.Session); var entity = dataSource.Query(elementType); return new PomonaResponse(pr, entity); }; } return null; }
public ResourceTypeDetails(ResourceType type, string urlRelativePath, bool isExposedAsRepository, Type postReturnType, PropertyInfo parentToChildPropertyInfo, PropertyInfo childToParentPropertyInfo, bool isSingleton, IEnumerable<Type> resourceHandlers, string pluralName) { if (type == null) throw new ArgumentNullException(nameof(type)); this.type = type; UrlRelativePath = urlRelativePath; IsExposedAsRepository = isExposedAsRepository; this.postReturnType = postReturnType; this.parentToChildPropertyInfo = parentToChildPropertyInfo; this.childToParentPropertyInfo = childToParentPropertyInfo; IsSingleton = isSingleton; ResourceHandlers = resourceHandlers; PluralName = pluralName; }
public override ResourceType LoadUriBaseType(ResourceType resourceType) { Type uriBaseType = Filter.GetUriBaseType(resourceType.Type); return uriBaseType != null ? (ResourceType)FromType(uriBaseType) : null; }
public abstract ResourceTypeDetails LoadResourceTypeDetails(ResourceType resourceType);
private void RegisterRoutesFor(ResourceType type) { var path = "/" + type.UriRelativePath; Register(Get, path + "/{remaining*}", x => GetResource()); Register(Get, path, x => GetResource()); Register(Post, path, x => GetResource()); Register(Patch, path + "/{remaining*}", x => GetResource()); Register(Post, path + "/{remaining*}", x => GetResource()); }
private static Func<PomonaContext, PomonaResponse> ResolvePost(Route route, ResourceType resourceItemType) { if (route.NodeType == PathNodeType.Collection) return ResolvePostToCollection(route, resourceItemType); return null; }
private static Func<PomonaContext, PomonaResponse> ResolvePostToCollection(Route route, ResourceType resourceItemType) { if (route.ResultItemType is ResourceType && route.ResultType.IsCollection && route.Root() is DataSourceRootRoute) { return pr => { var form = pr.Bind(resourceItemType); var dataSource = GetDataSource(pr.Session); var entity = dataSource.Post(form.GetType(), form); return new PomonaResponse(pr, entity); }; } return null; }
private RouteAction MatchResourceNodeRequest(HttpMethod httpMethod, ResourceType resourceType) { if (!NameStartsWith(httpMethod)) return null; switch (httpMethod) { case HttpMethod.Delete: return MatchMethodTakingExistingResource(resourceType); case HttpMethod.Patch: return MatchMethodTakingPatchedExistingResource(resourceType); case HttpMethod.Get: return MatchMethodTakingResourceId(resourceType); case HttpMethod.Post: return MatchMethodTakingExistingResourceAndForm(resourceType); } return null; }
private RouteAction MatchMethodTakingResourceId(ResourceType resourceType) { if (MethodInfo.ReturnType != resourceType.Type) return null; var idParam = Parameters.SingleOrDefault(x => x.Type == resourceType.PrimaryId.PropertyType.Type); if (idParam != null) return new HandlerMethodTakingResourceId(this); return null; }
private RouteAction MatchMethodReturningQueryable(ResourceType resourceType) { // Check that the method is called "Get", "Query", "Get<TypeName>s" or "Query<TypeName>s". if (!MethodInfo.Name.Equals("Get") && !MethodInfo.Name.Equals("Query") && !MethodInfo.Name.Equals("Get" + resourceType.PluralName) && !MethodInfo.Name.Equals("Query" + resourceType.PluralName)) return null; // Check that the it takes a parameter of type Parent if the type is a child resource of Parent. if (resourceType.ParentResourceType != null) { var parentParameter = MethodInfo.GetParameters(); if (parentParameter.Length != 1 || parentParameter[0].ParameterType != resourceType.ParentResourceType.Type) return null; } // Check that it returns an IQueryable<Object>. if (!typeof(IQueryable<>).MakeGenericType(resourceType.Type).IsAssignableFrom(MethodInfo.ReturnType)) return null; return new DefaultHandlerMethodInvoker(this); }
private static Func<PomonaContext, PomonaResponse> ResolveGet(Route route, ResourceType resourceType) { if (route.ResultType.IsCollection) return ResolveGetCollection(route, resourceType); return null; }
protected virtual Func<PomonaContext, PomonaResponse> ResolveGetSingle(Route route, ResourceType resourceType) { var getByIdRoute = route as GetByIdRoute; if (getByIdRoute != null && !getByIdRoute.IsRoot) return ResolveGetById(getByIdRoute, resourceType); var propertyRoute = route as ResourcePropertyRoute; if (propertyRoute != null) return ResolveGetSingleProperty(propertyRoute, propertyRoute.Property, resourceType); return null; }
protected virtual Func<PomonaContext, PomonaResponse> ResolveGetSingleProperty(ResourcePropertyRoute route, StructuredProperty property, ResourceType resourceType) { return pr => new PomonaResponse(pr, pr.Node.Parent.Query() .SelectEx(x => x.Apply(property.CreateGetterExpression)) .WrapActionResult(QueryProjection.FirstOrDefault)); }
private static void BuildUriGenerator(ResourceType rt, List<Expression> sbFormatArgs, Expression parentExpression, StringBuilder formatStringBuilder) { if (rt.PrimaryId == null) throw new InvalidOperationException($"{rt.Name} has no Id property or primary key mapping"); var parentToChildProperty = rt.ParentToChildProperty; if (parentToChildProperty != null) { var childToParentProperty = rt.ChildToParentProperty; var nextParentExpr = childToParentProperty.CreateGetterExpression(parentExpression); BuildUriGenerator(rt.ParentResourceType, sbFormatArgs, nextParentExpr, formatStringBuilder); if (formatStringBuilder.Length > 0) formatStringBuilder.Append('/'); formatStringBuilder.AppendFormat("{0}", parentToChildProperty.UriName); if (parentToChildProperty.PropertyType.IsCollection) { formatStringBuilder.AppendFormat("/{{{0}}}", sbFormatArgs.Count); var sbArgsExpr = rt.PrimaryId.CreateGetterExpression(parentExpression); sbFormatArgs.Add(sbArgsExpr); } } else { if (rt.IsSingleton) formatStringBuilder.AppendFormat("{0}", rt.UrlRelativePath); else { var sbArgsExpr = rt.PrimaryId.CreateGetterExpression(parentExpression); formatStringBuilder.AppendFormat("{0}/{{{1}}}", rt.UrlRelativePath, sbFormatArgs.Count); sbFormatArgs.Add(sbArgsExpr); } } }
protected virtual Func<PomonaContext, PomonaResponse> ResolveGet(Route route, ResourceType resourceType) { if (route.ResultType.IsCollection) return ResolveGetCollection(route, resourceType); return ResolveGetSingle(route, resourceType); }
public override ResourceTypeDetails LoadResourceTypeDetails(ResourceType resourceType) { var type = resourceType.Type; var parentToChildProperty = Filter.GetParentToChildProperty(type); var childToParentProperty = Filter.GetChildToParentProperty(type); var isRootResource = parentToChildProperty == null; var relativeResourcePath = isRootResource ? Filter.GetUrlRelativePath(type).TrimStart('/') : null; return new ResourceTypeDetails(resourceType, relativeResourcePath, Filter.TypeIsExposedAsRepository(type), Filter.GetPostReturnType(type), parentToChildProperty, childToParentProperty, Filter.TypeIsSingletonResource(type), Filter.GetResourceHandlers(type), Filter.GetPluralNameForType(type)); }
private static Expression<Action<object, StringBuilder>> BuildUriGenerator(ResourceType rt) { var parameterExpression = Expression.Parameter(typeof(object), "x"); var objParam = Expression.Convert(parameterExpression, rt); var sbParam = Expression.Parameter(typeof(StringBuilder), "sb"); var sbArgs = new List<Expression>(); var formatStringBuilder = new StringBuilder(); BuildUriGenerator(rt, sbArgs, objParam, formatStringBuilder); var sbArgsEncoded = sbArgs.Select( GetUrlPathEncodedExpression); return Expression.Lambda<Action<object, StringBuilder>>(Expression.Call(sbParam, stringBuilderAppendFormatMethod, Expression.Constant(CultureInfo.InvariantCulture), Expression.Constant(formatStringBuilder.ToString()), Expression.NewArrayInit(typeof(object), sbArgsEncoded)), parameterExpression, sbParam); }
private static void BuildUriGenerator(ResourceType rt, List<Expression> sbFormatArgs, Expression parentExpression, StringBuilder formatStringBuilder) { if (rt.ParentToChildProperty != null) { var nextParentExpr = rt.ChildToParentProperty.CreateGetterExpression(parentExpression); BuildUriGenerator(rt.ParentResourceType, sbFormatArgs, nextParentExpr, formatStringBuilder); var sbArgsExpr = rt.PrimaryId.CreateGetterExpression(parentExpression); formatStringBuilder.AppendFormat("/{0}/{{{1}}}", rt.ParentToChildProperty.UriName, sbFormatArgs.Count); sbFormatArgs.Add(sbArgsExpr); } else { var sbArgsExpr = rt.PrimaryId.CreateGetterExpression(parentExpression); formatStringBuilder.AppendFormat("{0}/{{{1}}}", rt.UriRelativePath, sbFormatArgs.Count); sbFormatArgs.Add(sbArgsExpr); } }
private void AddRepositoryFormPostMethod(MethodAttributes methodAttributes, bool isImplementation, ResourceType subType, TypeDefinition repoTypeDef, TypeDefinition baseTypeGenericDef, TypeReference[] baseTypeGenericArgs) { var postReturnTypeRef = this.clientTypeInfoDict[subType.PostReturnType].InterfaceType; var method = new MethodDefinition("Post", methodAttributes, postReturnTypeRef); method.Parameters.Add(new ParameterDefinition("form", 0, this.clientTypeInfoDict[subType].PostFormType)); repoTypeDef.Methods.Add(method); if (isImplementation) { var basePostMethodRef = Import( Import(typeof(ClientRepository<,>)).Resolve().GetMethods() .Single( x => x.Name == "Post" && x.Parameters.Count == 1 && x.Parameters[0].Name == "form") ).MakeHostInstanceGeneric(baseTypeGenericArgs); var ilproc = method.Body.GetILProcessor(); ilproc.Emit(OpCodes.Ldarg_0); ilproc.Emit(OpCodes.Ldarg_1); ilproc.Emit(OpCodes.Callvirt, basePostMethodRef); ilproc.Emit(OpCodes.Castclass, postReturnTypeRef); ilproc.Emit(OpCodes.Ret); } }
private static void BuildUriTemplate(ResourceType rt, StringBuilder sb, string parentPath, bool useJsonNameStyle = false) { if (rt.ParentToChildProperty != null) { BuildUriTemplate(rt.ParentResourceType, sb, string.Format("{0}{1}.", parentPath, useJsonNameStyle ? rt.ChildToParentProperty.Name : rt.ChildToParentProperty.JsonName)); sb.AppendFormat("/{0}/{{{1}{2}}}", rt.ParentToChildProperty.UriName, parentPath, rt.PrimaryId.Name); } else sb.AppendFormat("{0}/{{{1}{2}}}", rt.UriRelativePath, parentPath, rt.PrimaryId.Name); }