Files
mixtape/zero.Core/Routing/AbtractRouteProvider.cs
T
2021-02-23 15:50:33 +01:00

155 lines
4.3 KiB
C#

using Raven.Client.Documents;
using Raven.Client.Documents.Session;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using zero.Core.Entities;
using zero.Core.Options;
namespace zero.Core.Routing
{
public abstract class AbtractRouteProvider<T> : IRouteProvider<T>
{
public virtual string Alias { get; protected set; }
public virtual Type[] AffectedTypes { get; protected set; }
public const string ID_PREFIX = "routes.";
public const char SLASH = '/';
protected IZeroOptions Options { get; set; }
public AbtractRouteProvider(string alias, IZeroOptions options)
{
Alias = alias;
Options = options;
AffectedTypes = new Type[1] { typeof(T) };
}
/// <summary>
/// Map a route to an MVC endpoint
/// </summary>
public virtual RouteProviderEndpoint MapEndpoint(IResolvedRoute route)
{
IEnumerable<Func<IResolvedRoute, RouteProviderEndpoint>> resolvers = Options.Routing.EndpointResolvers.GetAll(route.GetType());
foreach (Func<IResolvedRoute, RouteProviderEndpoint> resolver in resolvers.Reverse())
{
RouteProviderEndpoint endpoint = resolver(route);
if (endpoint != null)
{
return endpoint;
}
}
return Options.Routing.DefaultEndpoint;
}
/// <inheritdoc />
public virtual async Task<IRoute> GetRoute(IAsyncDocumentSession session, T model)
{
return await session.LoadAsync<IRoute>(GetRouteId(model));
}
/// <inheritdoc />
public virtual async Task<IRoute> GetRoute(IAsyncDocumentSession session, object model)
{
if (!(model is T))
{
return null;
}
return await GetRoute(session, (T)model);
}
/// <inheritdoc />
public virtual Task<IResolvedRoute> ResolveRoute(IAsyncDocumentSession session, IRoute route)
{
DefaultResolvedRoute resolved = new DefaultResolvedRoute() { Route = route };
return Task.FromResult((IResolvedRoute)resolved);
}
/// <inheritdoc />
public abstract Task<IList<IRoute>> GetAllRoutes(IAsyncDocumentSession session);
/// <inheritdoc />
public abstract string GetRouteId(T model);
/// <inheritdoc />
public string GetRouteId(object model)
{
if (!(model is T))
{
throw new ArgumentException($"Parameter has to be of type {typeof(T)}", nameof(model));
}
return GetRouteId((T)model);
}
protected async Task<IPage> ResolvePage(IAsyncDocumentSession session)
{
IEnumerable<Expression<Func<IPage, bool>>> resolvers = Options.Routing.PageResolvers.GetAll(typeof(T));
foreach (Expression<Func<IPage, bool>> resolver in resolvers.Reverse())
{
IPage page = await session.Query<IPage>().FirstOrDefaultAsync(resolver);
if (page != null)
{
return page;
}
}
return null;
}
protected async Task<IEnumerable<IPage>> ResolvePages(IAsyncDocumentSession session)
{
List<IPage> pages = new();
IEnumerable<Expression<Func<IPage, bool>>> resolvers = Options.Routing.PageResolvers.GetAll(typeof(T));
foreach (Expression<Func<IPage, bool>> resolver in resolvers.Reverse())
{
pages.AddRange(await session.Query<IPage>().Where(resolver).ToListAsync());
}
return pages;
}
protected async Task<IRoute> ResolvePageRoute(IAsyncDocumentSession session)
{
IPage page = await ResolvePage(session);
// WARNING: we are assuming that the route id is built from the page hash but this could be altered with PageRouteProvier.GetRouteId.
// we cannot use a dependency on this provider here as we are working from the abstract route provider which is the base of the PageRouteProvider itself,
// and therefore a circular dependency.
return page == null ? null : await session.LoadAsync<IRoute>(ID_PREFIX + page.Hash);
}
protected async Task<IEnumerable<IRoute>> ResolvePageRoutes(IAsyncDocumentSession session)
{
List<IRoute> routes = new();
IEnumerable<IPage> pages = await ResolvePages(session);
string[] ids = pages.Select(x => ID_PREFIX + x.Hash).ToArray();
return ids.Length < 1 ? routes : (await session.LoadAsync<IRoute>(ids)).Select(x => x.Value);
}
}
}