Files
mixtape/zero.Core/Routing/ZeroRouteProvider.cs
T

232 lines
7.5 KiB
C#
Raw Normal View History

2021-11-04 15:51:54 +01:00
using System;
using System.Collections.Generic;
using System.Linq;
2021-10-05 15:50:12 +02:00
using System.Threading.Tasks;
using zero.Core.Entities;
2021-11-07 13:51:45 +01:00
using zero.Core.Extensions;
2021-10-05 15:50:12 +02:00
namespace zero.Core.Routing
{
2021-11-06 16:27:04 +01:00
public abstract class ZeroRouteProvider<T> : ZeroRouteProvider, IRouteProvider<T> where T : IZeroRouteEntity
2021-10-05 15:50:12 +02:00
{
2021-11-04 15:51:54 +01:00
public ZeroRouteProvider(string alias) : base(alias) { }
2021-10-05 15:50:12 +02:00
2021-11-04 15:51:54 +01:00
/// <inheritdoc />
public override bool CanHandle(Type type) => typeof(T).IsAssignableFrom(type);
2021-10-06 11:47:39 +02:00
2021-11-04 15:51:54 +01:00
/// <inheritdoc />
public abstract Task<Route> Create(RoutingContext context, T model);
2021-10-05 15:50:12 +02:00
2021-11-04 15:51:54 +01:00
/// <inheritdoc />
public sealed override Task<Route> Create(RoutingContext context, IZeroRouteEntity model) => Create(context, (T)model);
/// <inheritdoc />
public virtual string Key(T model) => model.Hash;
/// <inheritdoc />
public sealed override string Key(IZeroRouteEntity model) => Key((T)model);
/// <inheritdoc />
2021-11-05 13:46:07 +01:00
public virtual Task<bool> IsRouteStale(RoutingContext context, T previous, T current) => Task.FromResult(true);
2021-11-04 15:51:54 +01:00
/// <inheritdoc />
2021-11-05 13:46:07 +01:00
public sealed override Task<bool> IsRouteStale(RoutingContext context, IZeroRouteEntity previous, IZeroRouteEntity current) => IsRouteStale(context, (T)previous, (T)current);
/// <inheritdoc />
public virtual string Id(T model) => base.Id(model);
/// <inheritdoc />
public sealed override string Id(IZeroRouteEntity model) => base.Id(model);
2021-11-06 16:27:04 +01:00
/// <inheritdoc />
public virtual async Task<Route> Find(RoutingContext context, T model) => await context.Session.LoadAsync<Route>(Id(model));
/// <inheritdoc />
public sealed override Task<Route> Find(RoutingContext context, IZeroRouteEntity model) => Find(context, (T)model);
2021-11-07 13:51:45 +01:00
/// <inheritdoc />
public virtual async Task<Dictionary<T, Route>> Find(RoutingContext context, params T[] models)
{
Dictionary<string, T> idMap = models.ToDistinctDictionary(x => Id(x), x => x);
Dictionary<string, Route> routes = await context.Session.LoadAsync<Route>(idMap.Select(x => x.Key));
Dictionary<T, Route> result = new();
foreach ((string id, T model) in idMap)
{
result.Add(model, routes.GetValueOrDefault(id));
}
return result;
}
/// <inheritdoc />
public sealed override async Task<Dictionary<IZeroRouteEntity, Route>> Find(RoutingContext context, params IZeroRouteEntity[] models)
{
return (await Find(context, models.Select(x => (T)x).ToArray())).ToDictionary(x => (IZeroRouteEntity)x.Key, x => x.Value);
}
2021-11-04 15:51:54 +01:00
}
2021-11-06 16:27:04 +01:00
public abstract class ZeroRouteProvider : IRouteProvider
2021-11-04 15:51:54 +01:00
{
2021-11-05 13:46:07 +01:00
protected static string ID_PARAM = "id";
protected PageRouteResolverHelper PageResolver { get; set; } = new();
2021-11-04 15:51:54 +01:00
public ZeroRouteProvider(string alias)
{
Alias = alias;
}
public virtual string Alias { get; protected set; }
/// <inheritdoc />
public virtual bool CanHandle(Type type) => false;
/// <inheritdoc />
public abstract Task<Route> Create(RoutingContext context, IZeroRouteEntity model);
/// <inheritdoc />
public virtual string Key(IZeroRouteEntity model) => model.Hash;
/// <inheritdoc />
public virtual IAsyncEnumerable<Route> Seed(RoutingContext context) => AsyncEnumerable.Empty<Route>();
/// <inheritdoc />
2021-11-05 13:46:07 +01:00
public virtual Task<IRouteModel> Model(RoutingContext context, Route route) => Task.FromResult((IRouteModel)new RouteModel() { Route = route });
/// <inheritdoc />
public virtual Task<bool> IsRouteStale(RoutingContext context, IZeroRouteEntity previous, IZeroRouteEntity current) => Task.FromResult(true);
/// <inheritdoc />
public virtual string Id(IZeroRouteEntity model) => "routes." + Alias + "." + Key(model);
2021-11-06 16:27:04 +01:00
/// <inheritdoc />
public virtual RouteEndpoint Map(RoutingContext context, IRouteModel route)
{
IEnumerable<Func<IRouteModel, RouteEndpoint>> resolvers = context.Context.Options.Routing.EndpointResolvers.GetAll(route.GetType());
foreach (Func<IRouteModel, RouteEndpoint> resolver in resolvers.Reverse())
{
RouteEndpoint endpoint = resolver(route);
if (endpoint != null)
{
return endpoint;
}
}
return context.Context.Options.Routing.DefaultEndpoint;
}
2021-11-07 13:51:45 +01:00
/// <inheritdoc />
2021-11-06 16:27:04 +01:00
public virtual async Task<Route> Find(RoutingContext context, IZeroRouteEntity model) => await context.Session.LoadAsync<Route>(Id(model));
2021-11-07 13:51:45 +01:00
/// <inheritdoc />
public virtual async Task<Dictionary<IZeroRouteEntity, Route>> Find(RoutingContext context, params IZeroRouteEntity[] models)
{
Dictionary<string, IZeroRouteEntity> idMap = models.ToDistinctDictionary(x => Id(x), x => x);
Dictionary<string, Route> routes = await context.Session.LoadAsync<Route>(idMap.Select(x => x.Key));
Dictionary<IZeroRouteEntity, Route> result = new();
foreach ((string id, IZeroRouteEntity model) in idMap)
{
result.Add(model, routes.GetValueOrDefault(id));
}
return result;
}
2021-11-04 15:51:54 +01:00
}
2021-11-06 16:27:04 +01:00
public interface IRouteProvider<T> : IRouteProvider where T : IZeroRouteEntity
2021-11-04 15:51:54 +01:00
{
2021-10-05 15:50:12 +02:00
/// <summary>
2021-11-04 15:51:54 +01:00
/// Generate unique route key for a model
2021-10-05 15:50:12 +02:00
/// </summary>
2021-11-04 15:51:54 +01:00
string Key(T model);
2021-10-05 15:50:12 +02:00
2021-11-05 13:46:07 +01:00
/// <summary>
/// Generate unique ID for a model
/// </summary>
string Id(T model);
2021-10-05 15:50:12 +02:00
/// <summary>
/// Create route entity from a model
/// </summary>
2021-11-04 15:51:54 +01:00
Task<Route> Create(RoutingContext context, T model);
2021-10-06 11:47:39 +02:00
2021-11-05 13:46:07 +01:00
/// <summary>
/// Determines whether the route for previous is stale and needs to be refreshed
/// based on comparison with the previous version
/// </summary>
Task<bool> IsRouteStale(RoutingContext context, T previous, T current);
2021-11-06 16:27:04 +01:00
/// <summary>
/// Find a persisted route for an entity
/// </summary>
Task<Route> Find(RoutingContext context, T model);
2021-11-04 15:51:54 +01:00
}
2021-11-06 16:27:04 +01:00
public interface IRouteProvider
2021-11-04 15:51:54 +01:00
{
/// <summary>
/// Alias of this route provider
/// </summary>
string Alias { get; }
/// <summary>
/// Whether this provider can handle a certain entity type
/// </summary>
bool CanHandle(Type type);
/// <summary>
/// Generate unique route key for a model
/// </summary>
string Key(IZeroRouteEntity model);
2021-11-05 13:46:07 +01:00
/// <summary>
/// Generate unique ID for a model
/// </summary>
string Id(IZeroRouteEntity model);
2021-11-04 15:51:54 +01:00
/// <summary>
/// Create route entity from a model
/// </summary>
Task<Route> Create(RoutingContext context, IZeroRouteEntity model);
2021-10-05 15:50:12 +02:00
/// <summary>
/// Get all models which should be provided and handled by this instance
/// </summary>
2021-11-04 15:51:54 +01:00
IAsyncEnumerable<Route> Seed(RoutingContext context);
2021-10-05 15:50:12 +02:00
/// <summary>
2021-11-04 15:51:54 +01:00
/// Converts a route to a model which is passed to the endpoint
2021-10-05 15:50:12 +02:00
/// </summary>
2021-11-05 13:46:07 +01:00
Task<IRouteModel> Model(RoutingContext context, Route route);
/// <summary>
/// Determines whether the route for previous is stale and needs to be refreshed
/// based on comparison with the previous version
/// </summary>
Task<bool> IsRouteStale(RoutingContext context, IZeroRouteEntity previous, IZeroRouteEntity current);
2021-11-06 16:27:04 +01:00
/// <summary>
/// Map a route model to an endpoint
/// </summary>
RouteEndpoint Map(RoutingContext context, IRouteModel route);
/// <summary>
/// Find a persisted route for an entity
/// </summary>
Task<Route> Find(RoutingContext context, IZeroRouteEntity model);
2021-11-07 13:51:45 +01:00
/// <summary>
/// Find persisted routes for entities
/// </summary>
Task<Dictionary<IZeroRouteEntity, Route>> Find(RoutingContext context, params IZeroRouteEntity[] models);
2021-10-05 15:50:12 +02:00
}
2021-11-04 15:51:54 +01:00
2021-10-05 15:50:12 +02:00
}