Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling multiple data providers #57

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TargetFramework>netstandard2.0</TargetFramework>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
</ItemGroup>
</Project>
6 changes: 0 additions & 6 deletions InstantAPIs/ApiMethodsToGenerate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ 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
{
Expand Down
110 changes: 110 additions & 0 deletions InstantAPIs/InstantAPIsBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using InstantAPIs.Repositories;
using System.Linq.Expressions;

namespace Microsoft.AspNetCore.Builder;

public class InstantAPIsBuilder<TContext>
where TContext : class
{
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 InstantAPIs/InstantAPIsConfig.cs

This file was deleted.

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

namespace 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
{
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 Expression<Func<TContext, TSet>> EntitySelector { get; }
public TableOptions<TEntity, TKey> Config { get; }

public ApiMethodsToGenerate ApiMethodsToGenerate { get; set; } = ApiMethodsToGenerate.All;

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; }
}
}
Loading