Skip to content

Commit

Permalink
Enabling multiple data providers
Browse files Browse the repository at this point in the history
- added an interface with factory
- included ef core provider
- included json provider
- did some code reorganisation/move/rename
  • Loading branch information
Dries Verbeke committed Mar 18, 2022
1 parent be6d708 commit 2c0d002
Show file tree
Hide file tree
Showing 34 changed files with 890 additions and 681 deletions.
8 changes: 1 addition & 7 deletions Fritz.InstantAPIs/ApiMethodsToGenerate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,9 @@ public enum ApiMethodsToGenerate
All = 31
}

public record TableApiMapping(
string TableName,
ApiMethodsToGenerate MethodsToGenerate = ApiMethodsToGenerate.All,
string BaseUrl = ""
);

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ApiMethodAttribute : Attribute
{
{
public ApiMethodsToGenerate MethodsToGenerate { get; set; }
public ApiMethodAttribute(ApiMethodsToGenerate apiMethodsToGenerate)
{
Expand Down
113 changes: 113 additions & 0 deletions Fritz.InstantAPIs/InstantAPIsBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using Fritz.InstantAPIs.Repositories;
using System.Linq.Expressions;

namespace Microsoft.AspNetCore.Builder;

public class InstantAPIsBuilder<TContext>
where TContext : class
{

private Type _ContextType = typeof(TContext);

private readonly InstantAPIsOptions _instantApiOptions;
private readonly IContextHelper<TContext> _contextFactory;
private readonly HashSet<InstantAPIsOptions.ITable> _tables = new HashSet<InstantAPIsOptions.ITable>();
private readonly IList<string> _excludedTables = new List<string>();

public InstantAPIsBuilder(InstantAPIsOptions instantApiOptions, IContextHelper<TContext> contextFactory)
{
_instantApiOptions = instantApiOptions;
_contextFactory = contextFactory;
}

private IEnumerable<InstantAPIsOptions.ITable> DiscoverTables()
{
return _contextFactory != null
? _contextFactory.DiscoverFromContext(_instantApiOptions.DefaultUri)
: Array.Empty<InstantAPIsOptions.ITable>();
}

#region Table Inclusion/Exclusion

/// <summary>
/// Specify individual tables to include in the API generation with the methods requested
/// </summary>
/// <param name="setSelector">Select the EntityFramework DbSet to include - Required</param>
/// <param name="methodsToGenerate">A flags enumerable indicating the methods to generate. By default ALL are generated</param>
/// <returns>Configuration builder with this configuration applied</returns>
public InstantAPIsBuilder<TContext> IncludeTable<TSet, TEntity, TKey>(Expression<Func<TContext, TSet>> setSelector,
InstantAPIsOptions.TableOptions<TEntity, TKey> config, ApiMethodsToGenerate methodsToGenerate = ApiMethodsToGenerate.All,
string baseUrl = "")
where TSet : class
where TEntity : class
{
var propertyName = _contextFactory.NameTable(setSelector);

if (!string.IsNullOrEmpty(baseUrl))
{
try
{
var testUri = new Uri(baseUrl, UriKind.RelativeOrAbsolute);
baseUrl = testUri.IsAbsoluteUri ? testUri.LocalPath : baseUrl;
}
catch
{
throw new ArgumentException(nameof(baseUrl), "Not a valid Uri");
}
}
else
{
baseUrl = string.Concat(_instantApiOptions.DefaultUri.ToString(), "/", propertyName);
}

var tableApiMapping = new InstantAPIsOptions.Table<TContext, TSet, TEntity, TKey>(propertyName, new Uri(baseUrl, UriKind.Relative), setSelector, config)
{
ApiMethodsToGenerate = methodsToGenerate
};

_tables.RemoveWhere(x => x.Name == tableApiMapping.Name);
_tables.Add(tableApiMapping);

return this;

}

/// <summary>
/// Exclude individual tables from the API generation. Exclusion takes priority over inclusion
/// </summary>
/// <param name="setSelector">Select the entity to exclude from generation</param>
/// <returns>Configuration builder with this configuraiton applied</returns>
public InstantAPIsBuilder<TContext> ExcludeTable<TSet>(Expression<Func<TContext, TSet>> setSelector) where TSet : class
{
var propertyName = _contextFactory.NameTable(setSelector);
_excludedTables.Add(propertyName);

return this;
}

private void BuildTables()
{
if (!_tables.Any())
{
var discoveredTables = DiscoverTables();
foreach (var discoveredTable in discoveredTables)
{
_tables.Add(discoveredTable);
}
}

_tables.RemoveWhere(t => _excludedTables.Any(e => t.Name.Equals(e, StringComparison.InvariantCultureIgnoreCase)));

if (!_tables.Any()) throw new ArgumentException("All tables were excluded from this configuration");
}

#endregion

internal IEnumerable<InstantAPIsOptions.ITable> Build()
{
BuildTables();

return _tables;
}

}
137 changes: 0 additions & 137 deletions Fritz.InstantAPIs/InstantAPIsConfig.cs

This file was deleted.

72 changes: 72 additions & 0 deletions Fritz.InstantAPIs/InstantAPIsOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Linq.Expressions;

namespace Fritz.InstantAPIs;

public enum EnableSwagger
{
None,
DevelopmentOnly,
Always
}

public class InstantAPIsOptions
{
public Uri DefaultUri = new Uri("/api", UriKind.Relative);

public EnableSwagger? EnableSwagger { get; set; }
public Action<SwaggerGenOptions>? Swagger { get; set; }

public IEnumerable<ITable> Tables { get; internal set; } = new HashSet<ITable>();

internal class Table<TContext, TSet, TEntity, TKey>
: ITable
where TContext : class
where TSet : class
where TEntity : class
{
public Table(string name, Uri baseUrl, Expression<Func<TContext, TSet>> entitySelector, TableOptions<TEntity, TKey> config)
{
Name = name;
BaseUrl = baseUrl;
EntitySelector = entitySelector;
Config = config;

RepoType = typeof(TContext);
InstanceType = typeof(TEntity);
}

public string Name { get; }
public Type RepoType { get; }
public Type InstanceType { get; }
public Uri BaseUrl { get; set; }
public ApiMethodsToGenerate ApiMethodsToGenerate { get; set; } = ApiMethodsToGenerate.All;

public Expression<Func<TContext, TSet>> EntitySelector { get; }
public TableOptions<TEntity, TKey> Config { get; }

public object EntitySelectorObject => EntitySelector;
public object ConfigObject => Config;
}

public interface ITable
{
public string Name { get; }
public Type RepoType { get; }
public Type InstanceType { get; }
public Uri BaseUrl { get; set; }
public ApiMethodsToGenerate ApiMethodsToGenerate { get; set; }

public object EntitySelectorObject { get; }
public object ConfigObject { get; }

}


public record TableOptions<TEntity, TKey>()
{
public Expression<Func<TEntity, TKey>>? KeySelector { get; set; }

public Expression<Func<TEntity, TKey>>? OrderBy { get; set; }
}
}
24 changes: 19 additions & 5 deletions Fritz.InstantAPIs/InstantAPIsServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace Microsoft.Extensions.DependencyInjection;
using Fritz.InstantAPIs.Repositories;
using Fritz.InstantAPIs.Repositories.Json;

namespace Microsoft.Extensions.DependencyInjection;

public static class InstantAPIsServiceCollectionExtensions
{
public static IServiceCollection AddInstantAPIs(this IServiceCollection services, Action<InstantAPIsServiceOptions>? setupAction = null)
public static IServiceCollection AddInstantAPIs(this IServiceCollection services, Action<InstantAPIsOptions>? setupAction = null)
{
var options = new InstantAPIsServiceOptions();
var options = new InstantAPIsOptions();

// Get the service options
setupAction?.Invoke(options);
Expand All @@ -22,11 +25,22 @@ public static IServiceCollection AddInstantAPIs(this IServiceCollection services
}

// Register the required options so that it can be accessed by InstantAPIs middleware
services.Configure<InstantAPIsServiceOptions>(config =>
services.Configure<InstantAPIsOptions>(config =>
{
config.EnableSwagger = options.EnableSwagger;
});

return services;
services.AddSingleton(typeof(IRepositoryHelperFactory<,,,>), typeof(RepositoryHelperFactory<,,,>));
services.AddSingleton(typeof(IContextHelper<>), typeof(ContextHelper<>));

// ef core specific
services.AddSingleton<IRepositoryHelperFactory, EfCoreRepositoryHelperFactory>();
services.AddSingleton<IContextHelper, EfCoreContextHelper>();

// json specific
services.AddSingleton<IRepositoryHelperFactory, JsonRepositoryHelperFactory>();
services.AddSingleton<IContextHelper, JsonContextHelper>();

return services;
}
}
Loading

0 comments on commit 2c0d002

Please sign in to comment.