1- using System . Linq . Expressions ;
2- using System . Reflection ;
1+ using InstantAPIs . Repositories ;
2+ using System . Linq . Expressions ;
33
44namespace Microsoft . AspNetCore . Builder ;
55
6- public class InstantAPIsBuilder < TContext >
7- where TContext : DbContext
6+ public class InstantAPIsBuilder < TContext >
7+ where TContext : class
88{
9+ private readonly InstantAPIsOptions _instantApiOptions ;
10+ private readonly IContextHelper < TContext > _contextFactory ;
11+ private readonly HashSet < InstantAPIsOptions . ITable > _tables = new HashSet < InstantAPIsOptions . ITable > ( ) ;
12+ private readonly IList < string > _excludedTables = new List < string > ( ) ;
913
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 ( ) ;
14- private readonly List < string > _ExcludedTables = new ( ) ;
15- private const string DEFAULT_URI = "/api/" ;
14+ public InstantAPIsBuilder ( InstantAPIsOptions instantApiOptions , IContextHelper < TContext > contextFactory )
15+ {
16+ _instantApiOptions = instantApiOptions ;
17+ _contextFactory = contextFactory ;
18+ }
1619
17- public InstantAPIsBuilder ( TContext theContext )
20+ private IEnumerable < InstantAPIsOptions . ITable > DiscoverTables ( )
1821 {
19- this . _TheContext = theContext ;
22+ return _contextFactory != null
23+ ? _contextFactory . DiscoverFromContext ( _instantApiOptions . DefaultUri )
24+ : Array . Empty < InstantAPIsOptions . ITable > ( ) ;
2025 }
2126
2227 #region Table Inclusion/Exclusion
@@ -27,14 +32,13 @@ public InstantAPIsBuilder(TContext theContext)
2732 /// <param name="setSelector">Select the EntityFramework DbSet to include - Required</param>
2833 /// <param name="methodsToGenerate">A flags enumerable indicating the methods to generate. By default ALL are generated</param>
2934 /// <returns>Configuration builder with this configuration applied</returns>
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 >
35+ public InstantAPIsBuilder < TContext > IncludeTable < TSet , TEntity , TKey > ( Expression < Func < TContext , TSet > > setSelector ,
36+ InstantAPIsOptions . TableOptions < TEntity , TKey > config , ApiMethodsToGenerate methodsToGenerate = ApiMethodsToGenerate . All ,
37+ string baseUrl = "" )
38+ where TSet : class
3339 where TEntity : class
3440 {
35-
36- var theSetType = setSelector . Compile ( ) ( _TheContext ) . GetType ( ) . BaseType ;
37- var property = _ContextType . GetProperties ( ) . First ( p => p . PropertyType == theSetType ) ;
41+ var propertyName = _contextFactory . NameTable ( setSelector ) ;
3842
3943 if ( ! string . IsNullOrEmpty ( baseUrl ) )
4044 {
@@ -50,17 +54,16 @@ public InstantAPIsBuilder<TContext> IncludeTable<TSet, TEntity, TKey>(Expression
5054 }
5155 else
5256 {
53- baseUrl = string . Concat ( DEFAULT_URI , property . Name ) ;
57+ baseUrl = string . Concat ( _instantApiOptions . DefaultUri . ToString ( ) , "/" , propertyName ) ;
5458 }
5559
56- var tableApiMapping = new InstantAPIsOptions . Table < TContext , TSet , TEntity , TKey > ( property . Name , new Uri ( baseUrl , UriKind . Relative ) , setSelector , config )
57- {
58- ApiMethodsToGenerate = methodsToGenerate
60+ var tableApiMapping = new InstantAPIsOptions . Table < TContext , TSet , TEntity , TKey > ( propertyName , new Uri ( baseUrl , UriKind . Relative ) , setSelector , config )
61+ {
62+ ApiMethodsToGenerate = methodsToGenerate
5963 } ;
60- _IncludedTables . Add ( tableApiMapping ) ;
6164
62- if ( _ExcludedTables . Contains ( tableApiMapping . Name ) ) _ExcludedTables . Remove ( tableApiMapping . Name ) ;
63- _IncludedTables . Add ( tableApiMapping ) ;
65+ _tables . RemoveWhere ( x => x . Name == tableApiMapping . Name ) ;
66+ _tables . Add ( tableApiMapping ) ;
6467
6568 return this ;
6669
@@ -69,106 +72,39 @@ public InstantAPIsBuilder<TContext> IncludeTable<TSet, TEntity, TKey>(Expression
6972 /// <summary>
7073 /// Exclude individual tables from the API generation. Exclusion takes priority over inclusion
7174 /// </summary>
72- /// <param name="entitySelector ">Select the entity to exclude from generation</param>
75+ /// <param name="setSelector ">Select the entity to exclude from generation</param>
7376 /// <returns>Configuration builder with this configuraiton applied</returns>
74- public InstantAPIsBuilder < TContext > ExcludeTable < T > ( Func < TContext , DbSet < T > > entitySelector ) where T : class
77+ public InstantAPIsBuilder < TContext > ExcludeTable < TSet > ( Expression < Func < TContext , TSet > > setSelector ) where TSet : class
7578 {
76-
77- var theSetType = entitySelector ( _TheContext ) . GetType ( ) . BaseType ;
78- var property = _ContextType . GetProperties ( ) . First ( p => p . PropertyType == theSetType ) ;
79-
80- if ( _IncludedTables . Select ( t => t . Name ) . Contains ( property . Name ) ) _IncludedTables . Remove ( _IncludedTables . First ( t => t . Name == property . Name ) ) ;
81- _ExcludedTables . Add ( property . Name ) ;
79+ var propertyName = _contextFactory . NameTable ( setSelector ) ;
80+ _excludedTables . Add ( propertyName ) ;
8281
8382 return this ;
84-
8583 }
8684
8785 private void BuildTables ( )
8886 {
89- var tables = WebApplicationExtensions . GetDbTablesForContext < TContext > ( ) . ToArray ( ) ;
90- InstantAPIsOptions . ITable [ ] ? outTables ;
91-
92- // Add the Included tables
93- if ( _IncludedTables . Any ( ) )
94- {
95- outTables = tables . Where ( t => _IncludedTables . Any ( i => i . Name . Equals ( t . Name , StringComparison . InvariantCultureIgnoreCase ) ) )
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 ( ) ;
106- } else {
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 ( ) ;
111- }
112-
113- // Exit now if no tables were excluded
114- if ( ! _ExcludedTables . Any ( ) )
87+ if ( ! _tables . Any ( ) )
11588 {
116- _Config . UnionWith ( outTables ) ;
117- return ;
89+ var discoveredTables = DiscoverTables ( ) ;
90+ foreach ( var discoveredTable in discoveredTables )
91+ {
92+ _tables . Add ( discoveredTable ) ;
93+ }
11894 }
11995
120- // Remove the Excluded tables
121- outTables = outTables . Where ( t => ! _ExcludedTables . Any ( e => e . Equals ( t . Name , StringComparison . InvariantCultureIgnoreCase ) ) ) . ToArray ( ) ;
122-
123- if ( outTables == null || ! outTables . Any ( ) ) throw new ArgumentException ( "All tables were excluded from this configuration" ) ;
96+ _tables . RemoveWhere ( t => _excludedTables . Any ( e => t . Name . Equals ( e , StringComparison . InvariantCultureIgnoreCase ) ) ) ;
12497
125- _Config . UnionWith ( outTables ) ;
126-
127- }
128-
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 ;
98+ if ( ! _tables . Any ( ) ) throw new ArgumentException ( "All tables were excluded from this configuration" ) ;
14199 }
142100
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- }
164101 #endregion
165102
166- internal HashSet < InstantAPIsOptions . ITable > Build ( )
103+ internal IEnumerable < InstantAPIsOptions . ITable > Build ( )
167104 {
168-
169105 BuildTables ( ) ;
170106
171- return _Config ;
107+ return _tables ;
172108 }
173109
174- }
110+ }
0 commit comments