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