1- namespace Microsoft . AspNetCore . Builder ;
1+ using System . Linq . Expressions ;
2+ using System . Reflection ;
23
3- public class InstantAPIsBuilder < D > where D : DbContext
4+ namespace Microsoft . AspNetCore . Builder ;
5+
6+ public class InstantAPIsBuilder < TContext >
7+ where TContext : DbContext
48{
59
6- private HashSet < InstantAPIsOptions . Table > _Config = new ( ) ;
7- private Type _ContextType = typeof ( D ) ;
8- private D _TheContext ;
9- private readonly HashSet < InstantAPIsOptions . Table > _IncludedTables = new ( ) ;
10+ private HashSet < InstantAPIsOptions . ITable > _Config = new ( ) ;
11+ private Type _ContextType = typeof ( TContext ) ;
12+ private TContext _TheContext ;
13+ private readonly HashSet < InstantAPIsOptions . ITable > _IncludedTables = new ( ) ;
1014 private readonly List < string > _ExcludedTables = new ( ) ;
1115 private const string DEFAULT_URI = "/api/" ;
1216
13- public InstantAPIsBuilder ( D theContext )
17+ public InstantAPIsBuilder ( TContext theContext )
1418 {
1519 this . _TheContext = theContext ;
1620 }
@@ -20,13 +24,16 @@ public InstantAPIsBuilder(D theContext)
2024 /// <summary>
2125 /// Specify individual tables to include in the API generation with the methods requested
2226 /// </summary>
23- /// <param name="entitySelector ">Select the EntityFramework DbSet to include - Required</param>
27+ /// <param name="setSelector ">Select the EntityFramework DbSet to include - Required</param>
2428 /// <param name="methodsToGenerate">A flags enumerable indicating the methods to generate. By default ALL are generated</param>
2529 /// <returns>Configuration builder with this configuration applied</returns>
26- public InstantAPIsBuilder < D > IncludeTable < T > ( Func < D , DbSet < T > > entitySelector , ApiMethodsToGenerate methodsToGenerate = ApiMethodsToGenerate . All , string baseUrl = "" ) where T : class
30+ public InstantAPIsBuilder < TContext > IncludeTable < TSet , TEntity , TKey > ( Expression < Func < TContext , TSet > > setSelector ,
31+ InstantAPIsOptions . TableOptions < TEntity , TKey > config , ApiMethodsToGenerate methodsToGenerate = ApiMethodsToGenerate . All , string baseUrl = "" )
32+ where TSet : DbSet < TEntity >
33+ where TEntity : class
2734 {
2835
29- var theSetType = entitySelector ( _TheContext ) . GetType ( ) . BaseType ;
36+ var theSetType = setSelector . Compile ( ) ( _TheContext ) . GetType ( ) . BaseType ;
3037 var property = _ContextType . GetProperties ( ) . First ( p => p . PropertyType == theSetType ) ;
3138
3239 if ( ! string . IsNullOrEmpty ( baseUrl ) )
@@ -46,7 +53,10 @@ public InstantAPIsBuilder<D> IncludeTable<T>(Func<D, DbSet<T>> entitySelector, A
4653 baseUrl = string . Concat ( DEFAULT_URI , property . Name ) ;
4754 }
4855
49- var tableApiMapping = new InstantAPIsOptions . Table ( property . Name , new Uri ( baseUrl ) , typeof ( T ) ) { ApiMethodsToGenerate = methodsToGenerate } ;
56+ var tableApiMapping = new InstantAPIsOptions . Table < TContext , TSet , TEntity , TKey > ( property . Name , new Uri ( baseUrl , UriKind . Relative ) , setSelector , config )
57+ {
58+ ApiMethodsToGenerate = methodsToGenerate
59+ } ;
5060 _IncludedTables . Add ( tableApiMapping ) ;
5161
5262 if ( _ExcludedTables . Contains ( tableApiMapping . Name ) ) _ExcludedTables . Remove ( tableApiMapping . Name ) ;
@@ -61,7 +71,7 @@ public InstantAPIsBuilder<D> IncludeTable<T>(Func<D, DbSet<T>> entitySelector, A
6171 /// </summary>
6272 /// <param name="entitySelector">Select the entity to exclude from generation</param>
6373 /// <returns>Configuration builder with this configuraiton applied</returns>
64- public InstantAPIsBuilder < D > ExcludeTable < T > ( Func < D , DbSet < T > > entitySelector ) where T : class
74+ public InstantAPIsBuilder < TContext > ExcludeTable < T > ( Func < TContext , DbSet < T > > entitySelector ) where T : class
6575 {
6676
6777 var theSetType = entitySelector ( _TheContext ) . GetType ( ) . BaseType ;
@@ -76,20 +86,28 @@ public InstantAPIsBuilder<D> ExcludeTable<T>(Func<D, DbSet<T>> entitySelector) w
7686
7787 private void BuildTables ( )
7888 {
79-
80- var tables = WebApplicationExtensions . GetDbTablesForContext < D > ( ) . ToArray ( ) ;
81- InstantAPIsOptions . Table [ ] ? outTables ;
89+ var tables = WebApplicationExtensions . GetDbTablesForContext < TContext > ( ) . ToArray ( ) ;
90+ InstantAPIsOptions . ITable [ ] ? outTables ;
8291
8392 // Add the Included tables
8493 if ( _IncludedTables . Any ( ) )
8594 {
8695 outTables = tables . Where ( t => _IncludedTables . Any ( i => i . Name . Equals ( t . Name , StringComparison . InvariantCultureIgnoreCase ) ) )
87- . Select ( t => new InstantAPIsOptions . Table ( t . Name , new Uri ( _IncludedTables . First ( i => i . Name . Equals ( t . Name , StringComparison . InvariantCultureIgnoreCase ) ) . BaseUrl . ToString ( ) , UriKind . Relative ) , t . InstanceType )
88- {
89- ApiMethodsToGenerate = _IncludedTables . First ( i => i . Name . Equals ( t . Name , StringComparison . InvariantCultureIgnoreCase ) ) . ApiMethodsToGenerate
90- } ) . ToArray ( ) ;
96+ . Select ( t => {
97+ var table = CreateTable ( t . Name , new Uri ( _IncludedTables . First ( i => i . Name . Equals ( t . Name , StringComparison . InvariantCultureIgnoreCase ) ) . BaseUrl . ToString ( ) , UriKind . Relative ) , typeof ( TContext ) , typeof ( DbSet < > ) . MakeGenericType ( t . InstanceType ) , t . InstanceType ) ;
98+ if ( table != null )
99+ {
100+ table . ApiMethodsToGenerate = _IncludedTables . First ( i => i . Name . Equals ( t . Name , StringComparison . InvariantCultureIgnoreCase ) ) . ApiMethodsToGenerate ;
101+ }
102+ return table ;
103+ } )
104+ . Where ( x => x != null ) . OfType < InstantAPIsOptions . ITable > ( )
105+ . ToArray ( ) ;
91106 } else {
92- outTables = tables . Select ( t => new InstantAPIsOptions . Table ( t . Name , new Uri ( DEFAULT_URI + t . Name , uriKind : UriKind . Relative ) , t . InstanceType ) ) . ToArray ( ) ;
107+ outTables = tables
108+ . Select ( t => CreateTable ( t . Name , new Uri ( DEFAULT_URI + t . Name , uriKind : UriKind . Relative ) , typeof ( TContext ) , typeof ( DbSet < > ) . MakeGenericType ( t . InstanceType ) , t . InstanceType ) )
109+ . Where ( x => x != null ) . OfType < InstantAPIsOptions . ITable > ( )
110+ . ToArray ( ) ;
93111 }
94112
95113 // Exit now if no tables were excluded
@@ -108,9 +126,44 @@ private void BuildTables()
108126
109127 }
110128
111- #endregion
129+ public static InstantAPIsOptions . ITable ? CreateTable ( string name , Uri baseUrl , Type contextType , Type setType , Type entityType )
130+ {
131+ var keyProperty = entityType . GetProperties ( ) . Where ( x => "id" . Equals ( x . Name , StringComparison . InvariantCultureIgnoreCase ) ) . FirstOrDefault ( ) ;
132+ if ( keyProperty == null ) return null ;
133+
134+ var genericMethod = typeof ( InstantAPIsBuilder < > ) . MakeGenericType ( contextType ) . GetMethod ( nameof ( CreateTableGeneric ) , BindingFlags . NonPublic | BindingFlags . Static )
135+ ?? throw new Exception ( "Missing method" ) ;
136+ var concreteMethod = genericMethod . MakeGenericMethod ( contextType , setType , entityType , keyProperty . PropertyType ) ;
137+
138+ var entitySelector = CreateExpression ( contextType , name , setType ) ;
139+ var keySelector = CreateExpression ( entityType , keyProperty . Name , keyProperty . PropertyType ) ;
140+ return concreteMethod . Invoke ( null , new object ? [ ] { name , baseUrl , entitySelector , keySelector , null } ) as InstantAPIsOptions . ITable ;
141+ }
142+
143+ private static object CreateExpression ( Type memberOwnerType , string property , Type returnType )
144+ {
145+ var parameterExpression = Expression . Parameter ( memberOwnerType , "x" ) ;
146+ var propertyExpression = Expression . Property ( parameterExpression , property ) ;
147+ //var block = Expression.Block(propertyExpression, returnExpression);
148+ return Expression . Lambda ( typeof ( Func < , > ) . MakeGenericType ( memberOwnerType , returnType ) , propertyExpression , parameterExpression ) ;
149+ }
150+
151+ private static InstantAPIsOptions . ITable CreateTableGeneric < TContextStatic , TSet , TEntity , TKey > ( string name , Uri baseUrl ,
152+ Expression < Func < TContextStatic , TSet > > entitySelector , Expression < Func < TEntity , TKey > > ? keySelector , Expression < Func < TEntity , TKey > > ? orderBy )
153+ where TContextStatic : class
154+ where TSet : class
155+ where TEntity : class
156+ {
157+ return new InstantAPIsOptions . Table < TContextStatic , TSet , TEntity , TKey > ( name , baseUrl , entitySelector ,
158+ new InstantAPIsOptions . TableOptions < TEntity , TKey > ( )
159+ {
160+ KeySelector = keySelector ,
161+ OrderBy = orderBy
162+ } ) ;
163+ }
164+ #endregion
112165
113- internal HashSet < InstantAPIsOptions . Table > Build ( )
166+ internal HashSet < InstantAPIsOptions . ITable > Build ( )
114167 {
115168
116169 BuildTables ( ) ;
0 commit comments