Added support for custom repositories
This commit is contained in:
@@ -2,7 +2,13 @@
|
||||
|
||||
namespace HopFrame.Core.Config;
|
||||
|
||||
public class DbContextConfig {
|
||||
public interface ITableGroupConfig {
|
||||
public Type ContextType { get; }
|
||||
public List<TableConfig> Tables { get; }
|
||||
public HopFrameConfig ParentConfig { get; }
|
||||
}
|
||||
|
||||
public class DbContextConfig : ITableGroupConfig {
|
||||
public Type ContextType { get; }
|
||||
public List<TableConfig> Tables { get; } = new();
|
||||
public HopFrameConfig ParentConfig { get; }
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using HopFrame.Core.Callbacks;
|
||||
using System.Linq.Expressions;
|
||||
using HopFrame.Core.Callbacks;
|
||||
using HopFrame.Core.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace HopFrame.Core.Config;
|
||||
|
||||
public class HopFrameConfig {
|
||||
public List<DbContextConfig> Contexts { get; } = new();
|
||||
public List<ITableGroupConfig> Contexts { get; } = new();
|
||||
public bool DisplayUserInfo { get; set; } = true;
|
||||
public string? BasePolicy { get; set; }
|
||||
public string? LoginPageRewrite { get; set; }
|
||||
@@ -48,6 +50,36 @@ public sealed class HopFrameConfigurator(HopFrameConfig config, IServiceCollecti
|
||||
return new DbContextConfigurator<TDbContext>(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a table of the desired type and configures it to use a custom repository
|
||||
/// </summary>
|
||||
/// <param name="keyExpression">The key of the model</param>
|
||||
/// <param name="configurator">The configurator used for configuring the table page</param>
|
||||
/// <typeparam name="TRepository">The repository class that inherits from the <see cref="IHopFrameRepository{TModel,TKey}"/> (needs to be registered as a service)</typeparam>
|
||||
/// <typeparam name="TModel">The model of the table</typeparam>
|
||||
/// <typeparam name="TKey">The type of the primary key</typeparam>
|
||||
public HopFrameConfigurator AddCustomRepository<TRepository, TModel, TKey>(Expression<Func<TModel, TKey>> keyExpression, Action<TableConfigurator<TModel>> configurator) {
|
||||
var context = AddCustomRepository<TRepository, TModel, TKey>(keyExpression);
|
||||
configurator.Invoke(context);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a table of the desired type and configures it to use a custom repository
|
||||
/// </summary>
|
||||
/// <param name="keyExpression">The key of the model</param>
|
||||
/// <typeparam name="TRepository">The repository class that inherits from the <see cref="IHopFrameRepository{TModel,TKey}"/> (needs to be registered as a service)</typeparam>
|
||||
/// <typeparam name="TModel">The model of the table</typeparam>
|
||||
/// <typeparam name="TKey">The type of the primary key</typeparam>
|
||||
/// <returns>The configurator used for configuring the table page</returns>
|
||||
public TableConfigurator<TModel> AddCustomRepository<TRepository, TModel, TKey>(Expression<Func<TModel, TKey>> keyExpression) {
|
||||
var keyProperty = TableConfigurator<TModel>.GetPropertyInfo(keyExpression);
|
||||
var context = new RepositoryGroupConfig(typeof(TRepository), keyProperty, InnerConfig);
|
||||
context.Tables.Add(new TableConfig(context, typeof(TModel), typeof(TRepository).Name, 0));
|
||||
InnerConfig.Contexts.Add(context);
|
||||
return new TableConfigurator<TModel>(context.Tables[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a context is already registered in the HopFrame
|
||||
/// </summary>
|
||||
@@ -64,6 +96,7 @@ public sealed class HopFrameConfigurator(HopFrameConfig config, IServiceCollecti
|
||||
/// <returns>The configurator of the context if it already was defined, null if not</returns>
|
||||
public DbContextConfigurator<TDbContext>? GetDbContext<TDbContext>() where TDbContext : DbContext {
|
||||
var config = InnerConfig.Contexts
|
||||
.OfType<DbContextConfig>()
|
||||
.SingleOrDefault(context => context.ContextType == typeof(TDbContext));
|
||||
if (config is null) return null;
|
||||
|
||||
|
||||
13
src/HopFrame.Core/Config/RepositoryGroupConfig.cs
Normal file
13
src/HopFrame.Core/Config/RepositoryGroupConfig.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace HopFrame.Core.Config;
|
||||
|
||||
public class RepositoryGroupConfig(Type repoType, PropertyInfo keyProperty, HopFrameConfig config) : ITableGroupConfig {
|
||||
public Type ContextType { get; } = repoType;
|
||||
|
||||
public List<TableConfig> Tables { get; } = new();
|
||||
|
||||
public HopFrameConfig ParentConfig { get; } = config;
|
||||
|
||||
public PropertyInfo KeyProperty { get; } = keyProperty;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ public class TableConfig {
|
||||
public string PropertyName { get; }
|
||||
public string DisplayName { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public DbContextConfig ContextConfig { get; }
|
||||
public ITableGroupConfig ContextConfig { get; }
|
||||
public bool Ignored { get; set; }
|
||||
public int Order { get; set; }
|
||||
internal bool Seeded { get; set; }
|
||||
@@ -23,7 +23,7 @@ public class TableConfig {
|
||||
|
||||
public List<PropertyConfig> Properties { get; } = new();
|
||||
|
||||
public TableConfig(DbContextConfig config, Type tableType, string propertyName, int nthTable) {
|
||||
public TableConfig(ITableGroupConfig config, Type tableType, string propertyName, int nthTable) {
|
||||
TableType = tableType;
|
||||
PropertyName = propertyName;
|
||||
ContextConfig = config;
|
||||
|
||||
24
src/HopFrame.Core/Repositories/IHopFrameRepository.cs
Normal file
24
src/HopFrame.Core/Repositories/IHopFrameRepository.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace HopFrame.Core.Repositories;
|
||||
|
||||
public interface IHopFrameRepository<TModel, in TKey> where TModel : class {
|
||||
|
||||
Task<IEnumerable<TModel>> LoadPage(int page, int perPage);
|
||||
|
||||
Task<SearchResult<TModel>> Search(string searchTerm, int page, int perPage);
|
||||
|
||||
Task<int> GetTotalPageCount(int perPage);
|
||||
|
||||
Task CreateItem(TModel item);
|
||||
|
||||
Task EditItem(TModel item);
|
||||
|
||||
Task DeleteItem(TModel item);
|
||||
|
||||
Task<TModel?> GetOne(TKey key);
|
||||
|
||||
}
|
||||
|
||||
public readonly struct SearchResult<TModel>(IEnumerable<TModel> items, int pageCount) {
|
||||
public IEnumerable<TModel> Items { get; init; } = items;
|
||||
public int PageCount { get; init; } = pageCount;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using HopFrame.Core.Config;
|
||||
namespace HopFrame.Core.Services;
|
||||
|
||||
public interface ITableManager {
|
||||
public IQueryable<object> LoadPage(int page, int perPage = 20);
|
||||
public Task<IEnumerable<object>> LoadPage(int page, int perPage = 20);
|
||||
public Task<(IEnumerable<object>, int)> Search(string searchTerm, int page = 0, int perPage = 20);
|
||||
public Task<int> TotalPages(int perPage = 20);
|
||||
public Task DeleteItem(object item);
|
||||
|
||||
@@ -45,11 +45,18 @@ internal sealed class ContextExplorer(HopFrameConfig config, IServiceProvider pr
|
||||
var table = context.Tables.FirstOrDefault(table => table.PropertyName == tablePropertyName);
|
||||
if (table is null) continue;
|
||||
|
||||
var dbContext = provider.GetService(context.ContextType) as DbContext;
|
||||
if (dbContext is null) return null;
|
||||
var repo = provider.GetService(context.ContextType);
|
||||
if (repo is null) return null;
|
||||
|
||||
var type = typeof(TableManager<>).MakeGenericType(table.TableType);
|
||||
return Activator.CreateInstance(type, dbContext, table, this, provider) as ITableManager;
|
||||
if (context is DbContextConfig) {
|
||||
var type = typeof(TableManager<>).MakeGenericType(table.TableType);
|
||||
return Activator.CreateInstance(type, (DbContext)repo, table, this, provider) as ITableManager;
|
||||
}
|
||||
|
||||
if (context is RepositoryGroupConfig repoConfig) {
|
||||
var type = typeof(RepositoryTableManager<,>).MakeGenericType(table.TableType, repoConfig.KeyProperty.PropertyType);
|
||||
return Activator.CreateInstance(type, repo, this, provider) as ITableManager;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -60,11 +67,18 @@ internal sealed class ContextExplorer(HopFrameConfig config, IServiceProvider pr
|
||||
var table = context.Tables.FirstOrDefault(table => table.TableType == tableType);
|
||||
if (table is null) continue;
|
||||
|
||||
var dbContext = provider.GetService(context.ContextType) as DbContext;
|
||||
if (dbContext is null) return null;
|
||||
var repo = provider.GetService(context.ContextType);
|
||||
if (repo is null) return null;
|
||||
|
||||
var type = typeof(TableManager<>).MakeGenericType(table.TableType);
|
||||
return Activator.CreateInstance(type, dbContext, table, this, provider) as ITableManager;
|
||||
if (context is DbContextConfig) {
|
||||
var type = typeof(TableManager<>).MakeGenericType(table.TableType);
|
||||
return Activator.CreateInstance(type, (DbContext)repo, table, this, provider) as ITableManager;
|
||||
}
|
||||
|
||||
if (context is RepositoryGroupConfig repoConfig) {
|
||||
var type = typeof(RepositoryTableManager<,>).MakeGenericType(table.TableType, repoConfig.KeyProperty.PropertyType);
|
||||
return Activator.CreateInstance(type, repo, this, provider) as ITableManager;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -72,6 +86,7 @@ internal sealed class ContextExplorer(HopFrameConfig config, IServiceProvider pr
|
||||
|
||||
private void SeedTableData(TableConfig table) {
|
||||
if (table.Seeded) return;
|
||||
if (table.ContextConfig is not DbContextConfig) return;
|
||||
var dbContext = (provider.GetRequiredService(table.ContextConfig.ContextType) as DbContext)!;
|
||||
var entity = dbContext.Model.FindEntityType(table.TableType)!;
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Repositories;
|
||||
|
||||
namespace HopFrame.Core.Services.Implementations;
|
||||
|
||||
public class RepositoryTableManager<TModel, TKey>(IHopFrameRepository<TModel, TKey> repo, IContextExplorer explorer, IServiceProvider provider) : ITableManager where TModel : class {
|
||||
public async Task<IEnumerable<object>> LoadPage(int page, int perPage = 20) {
|
||||
return await repo.LoadPage(page, perPage);
|
||||
}
|
||||
public async Task<(IEnumerable<object>, int)> Search(string searchTerm, int page = 0, int perPage = 20) {
|
||||
var result = await repo.Search(searchTerm, page, perPage);
|
||||
return (result.Items, result.PageCount);
|
||||
}
|
||||
public Task<int> TotalPages(int perPage = 20) {
|
||||
return repo.GetTotalPageCount(perPage);
|
||||
}
|
||||
public Task DeleteItem(object item) {
|
||||
return repo.DeleteItem((TModel)item);
|
||||
}
|
||||
public Task EditItem(object item) {
|
||||
return repo.EditItem((TModel)item);
|
||||
}
|
||||
public Task AddItem(object item) {
|
||||
return repo.CreateItem((TModel)item);
|
||||
}
|
||||
public Task AddAll(IEnumerable<object> items) {
|
||||
var tasks = items
|
||||
.Select(item => repo.CreateItem((TModel)item))
|
||||
.ToList();
|
||||
|
||||
return Task.WhenAll(tasks);
|
||||
}
|
||||
public async Task<object?> GetOne(object key) {
|
||||
return await repo.GetOne((TKey)key);
|
||||
}
|
||||
public async Task<string> DisplayProperty(object? item, PropertyConfig prop, object? value = null, object? enumerableValue = null) {
|
||||
var manager = new TableManager<TModel>(null!, null!, explorer, provider);
|
||||
return await manager.DisplayProperty(item, prop, value, enumerableValue);
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,13 @@ namespace HopFrame.Core.Services.Implementations;
|
||||
|
||||
internal sealed class TableManager<TModel>(DbContext context, TableConfig config, IContextExplorer explorer, IServiceProvider provider) : ITableManager where TModel : class {
|
||||
|
||||
public IQueryable<object> LoadPage(int page, int perPage = 20) {
|
||||
public async Task<IEnumerable<object>> LoadPage(int page, int perPage = 20) {
|
||||
var table = context.Set<TModel>();
|
||||
var data = IncludeForeignKeys(table);
|
||||
return data
|
||||
return await data
|
||||
.Skip(page * perPage)
|
||||
.Take(perPage);
|
||||
.Take(perPage)
|
||||
.ToArrayAsync();
|
||||
}
|
||||
|
||||
public Task<(IEnumerable<object>, int)> Search(string searchTerm, int page = 0, int perPage = 20) {
|
||||
|
||||
Reference in New Issue
Block a user