2021-11-19 16:11:12 +01:00
|
|
|
namespace zero.Routing;
|
2021-11-10 11:52:49 +01:00
|
|
|
|
2021-12-01 15:54:11 +01:00
|
|
|
public abstract class ZeroRouteProvider<T> : ZeroRouteProvider, IRouteProvider<T> where T : ISupportsRouting
|
2021-10-05 15:50:12 +02:00
|
|
|
{
|
2021-11-10 11:52:49 +01:00
|
|
|
public ZeroRouteProvider(string alias) : base(alias) { }
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public override bool CanHandle(Type type) => typeof(T).IsAssignableFrom(type);
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual Task<Route> Create(RoutingContext context, T model) => base.Create(context, model);
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public sealed override Task<Route> Create(RoutingContext context, ISupportsRouting model) => Create(context, (T)model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual string Key(T model) => model.Hash;
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public sealed override string Key(ISupportsRouting model) => Key((T)model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual Task<bool> IsRouteStale(RoutingContext context, T previous, T current) => Task.FromResult(true);
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public sealed override Task<bool> IsRouteStale(RoutingContext context, ISupportsRouting previous, ISupportsRouting current) => IsRouteStale(context, (T)previous, (T)current);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual string Id(T model) => base.Id(model);
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public sealed override string Id(ISupportsRouting model) => base.Id(model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual async Task<Route> Find(RoutingContext context, T model) => await context.Session.LoadAsync<Route>(Id(model));
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public sealed override Task<Route> Find(RoutingContext context, ISupportsRouting model) => Find(context, (T)model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual async Task<Dictionary<T, Route>> Find(RoutingContext context, params T[] models)
|
2021-10-05 15:50:12 +02:00
|
|
|
{
|
2021-11-10 11:52:49 +01:00
|
|
|
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)
|
2021-11-08 15:49:36 +01:00
|
|
|
{
|
2021-11-10 11:52:49 +01:00
|
|
|
result.Add(model, routes.GetValueOrDefault(id));
|
2021-11-08 15:49:36 +01:00
|
|
|
}
|
2021-10-05 15:50:12 +02:00
|
|
|
|
2021-11-10 11:52:49 +01:00
|
|
|
return result;
|
2021-11-04 15:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
2021-11-10 11:52:49 +01:00
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public sealed override async Task<Dictionary<ISupportsRouting, Route>> Find(RoutingContext context, params ISupportsRouting[] models)
|
2021-11-04 15:51:54 +01:00
|
|
|
{
|
2021-12-01 15:54:11 +01:00
|
|
|
return (await Find(context, models.Select(x => (T)x).ToArray())).ToDictionary(x => (ISupportsRouting)x.Key, x => x.Value);
|
2021-11-04 15:51:54 +01:00
|
|
|
}
|
2021-10-05 15:50:12 +02:00
|
|
|
}
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
public abstract class ZeroRouteProvider : IRouteProvider
|
|
|
|
|
{
|
|
|
|
|
protected static string ID_PARAM = "id";
|
|
|
|
|
|
|
|
|
|
protected PageRouteResolverHelper PageResolver { get; set; } = new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ZeroRouteProvider(string alias)
|
|
|
|
|
{
|
|
|
|
|
Alias = alias;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual string Alias { get; protected set; }
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public uint Priority { get; protected set; } = 0;
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual bool CanHandle(Type type) => false;
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public virtual Task<Route> Create(RoutingContext context, ISupportsRouting model) => Task.FromResult(new Route()
|
2021-11-10 11:52:49 +01:00
|
|
|
{
|
|
|
|
|
Id = Id(model),
|
|
|
|
|
ProviderAlias = Alias,
|
|
|
|
|
ReferenceId = model.Id
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public virtual string Key(ISupportsRouting model) => model.Hash;
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual IAsyncEnumerable<Route> Seed(RoutingContext context) => AsyncEnumerable.Empty<Route>();
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public virtual IAsyncEnumerable<Route> SeedOnUpdate<T>(RoutingContext context, T model) where T : ISupportsRouting => AsyncEnumerable.Empty<Route>();
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public virtual Task<IRouteModel> Model(RoutingContext context, RouteResponse response) => Task.FromResult((IRouteModel)new RouteModel() { Route = response.Route });
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public virtual Task<bool> IsRouteStale(RoutingContext context, ISupportsRouting previous, ISupportsRouting current) => Task.FromResult(true);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public virtual string Id(ISupportsRouting model) => "routes." + Alias + "." + Key(model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2022-01-07 12:47:37 +01:00
|
|
|
public virtual IRouteEndpoint Map(RoutingContext context, IRouteModel route)
|
2021-11-10 11:52:49 +01:00
|
|
|
{
|
2021-11-26 12:31:33 +01:00
|
|
|
RoutingOptions options = context.Context.Options.For<RoutingOptions>();
|
|
|
|
|
|
2022-01-07 12:47:37 +01:00
|
|
|
IEnumerable<Func<IRouteModel, IRouteEndpoint>> resolvers = options.EndpointResolvers.GetAll(route.GetType());
|
2021-11-10 11:52:49 +01:00
|
|
|
|
2022-01-07 12:47:37 +01:00
|
|
|
foreach (Func<IRouteModel, IRouteEndpoint> resolver in resolvers.Reverse())
|
2021-11-10 11:52:49 +01:00
|
|
|
{
|
2022-01-07 12:47:37 +01:00
|
|
|
IRouteEndpoint endpoint = resolver(route);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
if (endpoint != null)
|
|
|
|
|
{
|
|
|
|
|
return endpoint;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-26 12:31:33 +01:00
|
|
|
return options.DefaultEndpoint;
|
2021-11-10 11:52:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public virtual async Task<Route> Find(RoutingContext context, ISupportsRouting model) => await context.Session.LoadAsync<Route>(Id(model));
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2021-12-01 15:54:11 +01:00
|
|
|
public virtual async Task<Dictionary<ISupportsRouting, Route>> Find(RoutingContext context, params ISupportsRouting[] models)
|
2021-11-10 11:52:49 +01:00
|
|
|
{
|
2021-12-01 15:54:11 +01:00
|
|
|
Dictionary<string, ISupportsRouting> idMap = models.ToDistinctDictionary(x => Id(x), x => x);
|
2021-11-10 11:52:49 +01:00
|
|
|
Dictionary<string, Route> routes = await context.Session.LoadAsync<Route>(idMap.Select(x => x.Key));
|
2021-12-01 15:54:11 +01:00
|
|
|
Dictionary<ISupportsRouting, Route> result = new();
|
2021-11-10 11:52:49 +01:00
|
|
|
|
2021-12-01 15:54:11 +01:00
|
|
|
foreach ((string id, ISupportsRouting model) in idMap)
|
2021-11-10 11:52:49 +01:00
|
|
|
{
|
|
|
|
|
result.Add(model, routes.GetValueOrDefault(id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-12-01 15:54:11 +01:00
|
|
|
public interface IRouteProvider<T> : IRouteProvider where T : ISupportsRouting
|
2021-11-10 11:52:49 +01:00
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Generate unique route key for a model
|
|
|
|
|
/// </summary>
|
|
|
|
|
string Key(T model);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Generate unique ID for a model
|
|
|
|
|
/// </summary>
|
|
|
|
|
string Id(T model);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create route entity from a model
|
|
|
|
|
/// </summary>
|
|
|
|
|
Task<Route> Create(RoutingContext context, T model);
|
|
|
|
|
|
|
|
|
|
/// <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);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Find a persisted route for an entity
|
|
|
|
|
/// </summary>
|
|
|
|
|
Task<Route> Find(RoutingContext context, T model);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public interface IRouteProvider
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Alias of this route provider
|
|
|
|
|
/// </summary>
|
|
|
|
|
string Alias { get; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Providers with higher priority will run before other providers when seeding
|
|
|
|
|
/// </summary>
|
|
|
|
|
uint Priority { 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>
|
2021-12-01 15:54:11 +01:00
|
|
|
string Key(ISupportsRouting model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Generate unique ID for a model
|
|
|
|
|
/// </summary>
|
2021-12-01 15:54:11 +01:00
|
|
|
string Id(ISupportsRouting model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create route entity from a model
|
|
|
|
|
/// </summary>
|
2021-12-01 15:54:11 +01:00
|
|
|
Task<Route> Create(RoutingContext context, ISupportsRouting model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get all models which should be provided and handled by this instance
|
|
|
|
|
/// </summary>
|
|
|
|
|
IAsyncEnumerable<Route> Seed(RoutingContext context);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get all models which should be updated when an entity changes
|
|
|
|
|
/// </summary>
|
2021-12-01 15:54:11 +01:00
|
|
|
IAsyncEnumerable<Route> SeedOnUpdate<T>(RoutingContext context, T model) where T : ISupportsRouting;
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Converts a route to a model which is passed to the endpoint
|
|
|
|
|
/// </summary>
|
|
|
|
|
Task<IRouteModel> Model(RoutingContext context, RouteResponse response);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Determines whether the route for previous is stale and needs to be refreshed
|
|
|
|
|
/// based on comparison with the previous version
|
|
|
|
|
/// </summary>
|
2021-12-01 15:54:11 +01:00
|
|
|
Task<bool> IsRouteStale(RoutingContext context, ISupportsRouting previous, ISupportsRouting current);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Map a route model to an endpoint
|
|
|
|
|
/// </summary>
|
2022-01-07 12:47:37 +01:00
|
|
|
IRouteEndpoint Map(RoutingContext context, IRouteModel route);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Find a persisted route for an entity
|
|
|
|
|
/// </summary>
|
2021-12-01 15:54:11 +01:00
|
|
|
Task<Route> Find(RoutingContext context, ISupportsRouting model);
|
2021-11-10 11:52:49 +01:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Find persisted routes for entities
|
|
|
|
|
/// </summary>
|
2021-12-01 15:54:11 +01:00
|
|
|
Task<Dictionary<ISupportsRouting, Route>> Find(RoutingContext context, params ISupportsRouting[] models);
|
2021-11-10 11:52:49 +01:00
|
|
|
}
|