Summary

Class:CBAM.SQL.PostgreSQL.Implementation.TypeRegistryImpl
Assembly:CBAM.SQL.PostgreSQL.Implementation
File(s):/repo-dir/contents/Source/Code/CBAM.SQL.PostgreSQL.Implementation/TypeRegistry.cs
Covered lines:76
Uncovered lines:3
Coverable lines:79
Total lines:163
Line coverage:96.2%
Branch coverage:77.7%

Coverage History

Metrics

MethodCyclomatic complexity NPath complexity Sequence coverage Branch coverage
.ctor(...)101%0%
AddTypeFunctionalitiesAsync()801%1%
TryGetTypeInfo(...)101%0%
TryGetTypeInfo(...)600.667%0.667%
TryFindByParent(...)101%0%
ReadTypeDataFromServer()801%1%
>c/<<ReadTypeDataFromServer()1301%0.385%
AssignTypeData(...)1001%1%

File(s)

/repo-dir/contents/Source/Code/CBAM.SQL.PostgreSQL.Implementation/TypeRegistry.cs

#LineLine coverage
 1using CBAM.SQL.Implementation;
 2using System;
 3using System.Collections.Generic;
 4using System.Linq;
 5using System.Reflection;
 6using System.Text;
 7using System.Threading.Tasks;
 8using UtilPack;
 9using TStaticTypeCacheValue = System.Collections.Generic.IDictionary<System.String, CBAM.SQL.PostgreSQL.PgSQLTypeDatabas
 10using TypeInfo = System.ValueTuple<CBAM.SQL.PostgreSQL.PgSQLTypeFunctionality, CBAM.SQL.PostgreSQL.PgSQLTypeDatabaseData
 11using TypeInfoWithCLRType = System.ValueTuple<System.Type, CBAM.SQL.PostgreSQL.PgSQLTypeFunctionality, CBAM.SQL.PostgreS
 12
 13namespace CBAM.SQL.PostgreSQL.Implementation
 14{
 15   using SQLConnectionFunctionality = Func<String, IAsyncEnumerable<SQLStatementExecutionResult>>; // Abstractions.Conne
 16
 17   internal class TypeRegistryImpl : TypeRegistry
 18   {
 19      private const Char ARRAY_PREFIX = '_';
 20
 21      private readonly IDictionary<Int32, TypeFunctionalityInformation> _typeInfos;
 22      private readonly IDictionary<Type, TypeFunctionalityInformation> _typeInfosByCLRType;
 23
 24      private readonly SQLConnectionVendorFunctionality _vendorFunctionality;
 25      private readonly SQLConnectionFunctionality _connectionFunctionality;
 26
 2427      public TypeRegistryImpl(
 2428         SQLConnectionVendorFunctionality vendorFunctionality,
 2429         SQLConnectionFunctionality connectionFunctionality
 2430         )
 31      {
 2432         this._vendorFunctionality = ArgumentValidator.ValidateNotNull( nameof( vendorFunctionality ), vendorFunctionali
 2433         this._connectionFunctionality = ArgumentValidator.ValidateNotNull( nameof( connectionFunctionality ), connectio
 34
 2435         this._typeInfos = new Dictionary<Int32, TypeFunctionalityInformation>();
 2436         this._typeInfosByCLRType = new Dictionary<Type, TypeFunctionalityInformation>();
 2437      }
 38
 39      public async ValueTask<Int32> AddTypeFunctionalitiesAsync( params (String DBTypeName, Type CLRType, Func<PgSQLType
 40      {
 341         var retVal = 0;
 342         if ( functionalities != null )
 43         {
 1544            var dic = functionalities.ToDictionary_Overwrite( tuple => tuple.DBTypeName, tuple => tuple );
 345            retVal = dic.Count;
 346            this.AssignTypeData(
 347               await this.ReadTypeDataFromServer( dic.Keys ),
 1548               typeName => dic[typeName].CLRType,
 949               tuple => dic[tuple.DBTypeName].FunctionalityCreator( tuple.BoundData )
 350               );
 351         }
 52
 353         return retVal;
 354      }
 55
 56      public TypeFunctionalityInformation TryGetTypeInfo( Int32 typeID )
 57      {
 44458         this._typeInfos.TryGetValue( typeID, out var retVal );
 44659         return retVal;
 60      }
 61
 62      public TypeFunctionalityInformation TryGetTypeInfo( Type clrType )
 63      {
 64         TypeFunctionalityInformation retVal;
 4965         if ( clrType != null )
 66         {
 67            KeyValuePair<Type, TypeFunctionalityInformation> kvp;
 5368            if ( !this._typeInfosByCLRType.TryGetValue( clrType, out retVal ) )
 69            {
 170               if ( ( kvp = this.TryFindByParent( clrType ) ).Value != null )
 71               {
 172                  retVal = kvp.Value;
 173               }
 74               else
 75               {
 076                  retVal = default;
 77               }
 78            }
 079         }
 80         else
 81         {
 082            retVal = default;
 83         }
 5484         return retVal;
 85      }
 86
 87      private KeyValuePair<Type, TypeFunctionalityInformation> TryFindByParent( Type clrType )
 88      {
 189         var child = clrType
 190#if !NET40 && !NET45
 191         .GetTypeInfo()
 192#endif
 193         ;
 3694         return this._typeInfosByCLRType.FirstOrDefault( kvp => kvp.Key
 3695#if !NET40 && !NET45
 3696         .GetTypeInfo()
 3697#endif
 3698         .IsAssignableFrom( child )
 199         );
 100      }
 101
 102      public async ValueTask<TStaticTypeCacheValue> ReadTypeDataFromServer(
 103         IEnumerable<String> typeNames
 104         )
 105      {
 4106         return await this._connectionFunctionality(
 4107               "SELECT typname, oid, typdelim, typelem\n" +
 4108               "FROM pg_type\n" +
 4109               "WHERE typname IN (" + String.Join( ", ", typeNames.Select( typename =>
 4110               {
 33111                  typename = this._vendorFunctionality.EscapeLiteral( typename );
 33112                  return "'" + typename + "', '" + ARRAY_PREFIX + typename + "'";
 4113               } ) ) + ")\n"
 4114            ).IncludeDataRowsOnly()
 61115            .Select( async row => new PgSQLTypeDatabaseData(
 61116               // We need to get all values as strings, since we might not have type mapping yet (we might be building i
 61117               await row.GetValueAsync<String>( 0 ),
 61118               Int32.Parse( await row.GetValueAsync<String>( 1 ) ),
 61119               await row.GetValueAsync<String>( 2 ),
 61120               Int32.Parse( await row.GetValueAsync<String>( 3 )
 61121               ) ) )
 118122            .ToDictionaryAsync( type => type.TypeName, type => type );
 4123      }
 124
 125      public void AssignTypeData(
 126         TStaticTypeCacheValue typeData,
 127         Func<String, Type> clrTypeExtractor,
 128         Func<(String DBTypeName, PgSQLTypeDatabaseData BoundData), TypeFunctionalityCreationResult> funcExtractor
 129         )
 130      {
 2238131         foreach ( var kvp in typeData )
 132         {
 1092133            var typeName = kvp.Key;
 1092134            var boundData = kvp.Value;
 135            PgSQLTypeFunctionality thisFunc;
 136            Boolean isDefaultForThisCLRType;
 137            Type clrType;
 1092138            if ( typeName[0] == ARRAY_PREFIX )
 139            {
 534140               clrType = clrTypeExtractor( typeName.Substring( 1 ) );
 534141               thisFunc = new PgSQLTypeFunctionalityForArrays( this, ref clrType, kvp.Value.ElementTypeID );
 534142               clrType = clrType.MakeArrayType();
 534143               isDefaultForThisCLRType = true;
 534144            }
 145            else
 146            {
 558147               clrType = clrTypeExtractor( typeName );
 558148               var result = funcExtractor( (typeName, boundData) );
 558149               (thisFunc, isDefaultForThisCLRType) = (result.TypeFunctionality, result.IsDefaultForCLRType);
 150            }
 1092151            if ( thisFunc != null )
 152            {
 1092153               var typeInfo = new TypeFunctionalityInformation( clrType, thisFunc, boundData );
 1092154               this._typeInfos[boundData.TypeID] = typeInfo;
 1092155               if ( isDefaultForThisCLRType || !this._typeInfosByCLRType.ContainsKey( clrType ) )
 156               {
 1020157                  this._typeInfosByCLRType[clrType] = typeInfo;
 158               }
 159            }
 160         }
 27161      }
 162   }
 163}