Summary

Class:CBAM.SQL.Implementation.StatementParameterImpl
Assembly:CBAM.SQL.Implementation
File(s):/repo-dir/contents/Source/Code/CBAM.SQL.Implementation/Statement.cs
Covered lines:9
Uncovered lines:0
Coverable lines:9
Total lines:329
Line coverage:100%

Coverage History

Metrics

MethodCyclomatic complexity NPath complexity Sequence coverage Branch coverage
.ctor(...)101%0%

File(s)

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

#LineLine coverage
 1/*
 2 * Copyright 2017 Stanislav Muhametsin. All rights Reserved.
 3 *
 4 * Licensed  under the  Apache License,  Version 2.0  (the "License");
 5 * you may not use  this file  except in  compliance with the License.
 6 * You may obtain a copy of the License at
 7 *
 8 *   http://www.apache.org/licenses/LICENSE-2.0
 9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed  under the  License is distributed on an "AS IS" BASIS,
 12 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 13 * implied.
 14 *
 15 * See the License for the specific language governing permissions and
 16 * limitations under the License.
 17 */
 18using CBAM.SQL.Implementation;
 19using System;
 20using System.Collections.Generic;
 21using System.Linq;
 22using System.Text;
 23using System.Threading;
 24using System.Threading.Tasks;
 25using UtilPack;
 26
 27
 28namespace CBAM.SQL.Implementation
 29{
 30   /// <summary>
 31   /// This class provides default implementation for <see cref="SQLStatementBuilderInformation"/>.
 32   /// </summary>
 33   /// <typeparam name="TParameter">The actual type of parameter, derivable from <see cref="StatementParameter"/>.</type
 34   /// <typeparam name="TList">The type of list holding batch parameters.</typeparam>
 35   public class StatementBuilderInformationImpl<TParameter, TList> : SQLStatementBuilderInformation
 36      where TParameter : StatementParameter
 37      where TList : class,
 38#if NET40
 39      IList<TParameter[]>
 40#else
 41      IReadOnlyList<TParameter[]>
 42#endif
 43   {
 44      /// <summary>
 45      /// This field holds the batch parameter set list.
 46      /// </summary>
 47      protected readonly TList _batchParameters;
 48
 49      /// <summary>
 50      /// This field holds the current parameter set as array of parameters.
 51      /// </summary>
 52      protected readonly TParameter[] _currentParameters;
 53
 54      /// <summary>
 55      /// Creates a new instance of <see cref="StatementBuilderInformationImpl{TParameter, TList}"/>.
 56      /// </summary>
 57      /// <param name="sql">The textual SQL statement.</param>
 58      /// <param name="currentParameters">Current array of parameters. May be <c>null</c>.</param>
 59      /// <param name="batchParams">The batch parameter list.</param>
 60      /// <exception cref="ArgumentNullException">If either of <paramref name="sql"/> or <paramref name="batchParams"/> 
 61      public StatementBuilderInformationImpl(
 62         String sql,
 63         TParameter[] currentParameters,
 64         TList batchParams
 65         )
 66      {
 67         this.SQL = ArgumentValidator.ValidateNotEmpty( nameof( sql ), sql );
 68         this._currentParameters = currentParameters ?? Empty<TParameter>.Array;
 69         this._batchParameters = ArgumentValidator.ValidateNotNull( nameof( batchParams ), batchParams );
 70      }
 71
 72      /// <summary>
 73      /// Implements <see cref="SQLStatementBuilderInformation.SQLParameterCount"/> and gets the amount of parameters in
 74      /// </summary>
 75      /// <value>The amount of parameters in this statement.</value>
 76      /// <remarks>
 77      /// If this returns <c>0</c>, this is not considred a prepared statement, but just simple statement instead.
 78      /// </remarks>
 79      public Int32 SQLParameterCount => this._currentParameters.Length;
 80
 81      /// <summary>
 82      /// Implements <see cref="SQLStatementBuilderInformation.SQL"/> and gets the textual SQL statement of this stateme
 83      /// </summary>
 84      /// <value>The textual SQL statement of this statement builder.</value>
 85      public String SQL { get; }
 86
 87      /// <summary>
 88      /// Implements <see cref="SQLStatementBuilderInformation.BatchParameterCount"/> and gets the amount of batched par
 89      /// </summary>
 90      /// <value>The amount of batched parameter sets.</value>
 91      /// <remarks>
 92      /// Both simple and prepared statements may be batched.
 93      /// </remarks>
 94      public Int32 BatchParameterCount => this._batchParameters.Count;
 95
 96      /// <summary>
 97      /// Implements <see cref="SQLStatementBuilderInformation.GetParameterInfo(int)"/> and returns <see cref="Statement
 98      /// </summary>
 99      /// <param name="parameterIndex">The index of the parameter. Should be <c>0 ≤ <paramref name="parameterIndex"/> &l
 100      /// <returns>The parameter information at given index.</returns>
 101      /// <exception cref="ArgumentException">If <paramref name="parameterIndex"/> is out of bounds.</exception>
 102      /// <seealso cref="StatementParameter"/>
 103      public StatementParameter GetParameterInfo( Int32 parameterIndex )
 104      {
 105         return this._currentParameters.CheckArrayIndexAndReturnOrThrow( parameterIndex, nameof( parameterIndex ) )[para
 106      }
 107
 108      /// <summary>
 109      /// Implements <see cref="SQLStatementBuilderInformation.GetBatchParameterInfo(int, int)"/> and returns <see cref=
 110      /// </summary>
 111      /// <param name="batchIndex">The batch index. Should be <c>0 ≤ <paramref name="batchIndex"/> &lt; <see cref="Batch
 112      /// <param name="parameterIndex">The parameter index. Should be <c>0 ≤ <paramref name="parameterIndex"/> &lt; <see
 113      /// <returns>The parameter information at given batch and parameter indices.</returns>
 114      /// <exception cref="ArgumentException">If either of <paramref name="batchIndex"/> or <paramref name="parameterInd
 115      /// <seealso cref="StatementParameter"/>
 116      public StatementParameter GetBatchParameterInfo( Int32 batchIndex, Int32 parameterIndex )
 117      {
 118         return this._batchParameters
 119            .CheckListIndexAndReturnOrThrow( batchIndex, nameof( batchIndex ) )[batchIndex]
 120            .CheckArrayIndexAndReturnOrThrow( parameterIndex, nameof( parameterIndex ) )[parameterIndex];
 121      }
 122   }
 123
 124   /// <summary>
 125   /// This class implements read-write functionality of <see cref="SQLStatementBuilder"/> by extending <see cref="State
 126   /// </summary>
 127   /// <typeparam name="TParameter">The actual type of parameter, derivable from <see cref="StatementParameter"/>.</type
 128   public abstract class StatementBuilderImpl<TParameter> : StatementBuilderInformationImpl<TParameter, List<TParameter[
 129      where TParameter : StatementParameter
 130   {
 131
 132      /// <summary>
 133      /// Initializes a new instance of <see cref="StatementBuilderImpl{TParameter}"/> with given parameters.
 134      /// </summary>
 135      /// <param name="information">The <see cref="SQLStatementBuilderInformation"/> that will hold the read-only access
 136      /// <param name="currentParams">The current parameter set as array of parameters.</param>
 137      /// <param name="batchParams">The batch parameter set list.</param>
 138      /// <exception cref="ArgumentNullException">If either of <paramref name="information"/> or <paramref name="batchPa
 139      public StatementBuilderImpl(
 140         SQLStatementBuilderInformation information,
 141         TParameter[] currentParams,
 142         List<TParameter[]> batchParams
 143         ) : base( ArgumentValidator.ValidateNotNull( nameof( information ), information ).SQL, currentParams, batchPara
 144      {
 145         this.StatementBuilderInformation = information;
 146      }
 147
 148      /// <summary>
 149      /// Implements <see cref="SQLStatementBuilder.StatementBuilderInformation"/> and gets the read-only <see cref="SQL
 150      /// </summary>
 151      /// <value>The read-only <see cref="SQLStatementBuilderInformation"/> of this statement builder.</value>
 152      public SQLStatementBuilderInformation StatementBuilderInformation { get; }
 153
 154      /// <summary>
 155      /// Implements <see cref="SQLStatementBuilder.AddBatch"/> method and adds current parameter set to list of batched
 156      /// </summary>
 157      /// <exception cref="InvalidOperationException">If there is at least one parameter that has not been set.</excepti
 158      public void AddBatch()
 159      {
 160         Int32 idx;
 161         if ( ( idx = Array.FindIndex( this._currentParameters, p => p == null ) ) >= 0 )
 162         {
 163            throw new InvalidOperationException( $"The parameter at index {idx} has not been set." );
 164         }
 165
 166         //if ( this._batchParameters.Count > 0 )
 167         //{
 168         //   // Must verify batch parameters
 169         //   var prevRow = this._batchParameters[this._batchParameters.Count - 1];
 170         //   for ( var i = 0; i < this._currentParameters.Length; ++i )
 171         //   {
 172         //      var exc = this.VerifyBatchParameters( prevRow[i], this._currentParameters[i] );
 173         //      if ( exc != null )
 174         //      {
 175         //         throw exc;
 176         //      }
 177         //   }
 178         //}
 179
 180         this._batchParameters.Add( this._currentParameters.CreateArrayCopy() );
 181         Array.Clear( this._currentParameters, 0, this._currentParameters.Length );
 182      }
 183
 184      /// <summary>
 185      /// Implements <see cref="SQLStatementBuilder.SetParameterObjectWithType(int, object, Type)"/> and adds given para
 186      /// </summary>
 187      /// <param name="parameterIndex">The index of the parameter. Should be <c>0 ≤ <paramref name="parameterIndex"/> &l
 188      /// <param name="value">The value to set. May be <c>null</c>.</param>
 189      /// <param name="clrType">The type of the value. If value is not <c>null</c> and this parameter is <c>null</c>, th
 190      /// <exception cref="ArgumentNullException">If both <paramref name="value"/> and <paramref name="clrType"/> are <c
 191      /// <exception cref="ArgumentException">If <paramref name="parameterIndex"/> is out of bounds.</exception>
 192      public void SetParameterObjectWithType( Int32 parameterIndex, Object value, Type clrType )
 193      {
 194         if ( clrType == null && value == null )
 195         {
 196            throw new ArgumentNullException( $"Both {nameof( value )} and {nameof( clrType )} were null." );
 197         }
 198         this._currentParameters[parameterIndex] = this.CreateStatementParameter( parameterIndex, value, clrType ?? valu
 199      }
 200
 201      /// <inheritdoc />
 202      public void RemoveAllBatchedParameters()
 203      {
 204         this._batchParameters.Clear();
 205      }
 206
 207      /// <summary>
 208      /// Derived classes should implement this method to return custom instances of <see cref="StatementParameter"/>.
 209      /// </summary>
 210      /// <param name="parameterIndex">The index of the parameter.</param>
 211      /// <param name="value">The value to set.</param>
 212      /// <param name="clrType">The type of the value.</param>
 213      /// <returns>A new instance of <see cref="StatementParameter"/>.</returns>
 214      protected abstract TParameter CreateStatementParameter( Int32 parameterIndex, Object value, Type clrType );
 215
 216   }
 217
 218   /// <summary>
 219   /// This class provides default implementation for <see cref="StatementParameter"/>.
 220   /// </summary>
 221   public class StatementParameterImpl : StatementParameter
 222   {
 223      /// <summary>
 224      /// Creates a new instance of <see cref="StatementParameterImpl"/> with given type and value.
 225      /// </summary>
 226      /// <param name="cilType">The parameter type.</param>
 227      /// <param name="value">The parameter value.</param>
 228      /// <exception cref="ArgumentNullException">If <paramref name="cilType"/> is <c>null</c>.</exception>
 51229      public StatementParameterImpl(
 51230         Type cilType,
 51231         Object value
 51232         )
 233      {
 51234         this.ParameterCILType = ArgumentValidator.ValidateNotNull( nameof( cilType ), cilType );
 53235         this.ParameterValue = value;
 53236      }
 237
 238      /// <summary>
 239      /// Implements <see cref="StatementParameter.ParameterCILType"/> and gets the type of the parameter value.
 240      /// </summary>
 241      /// <value>The type of the parameter value.</value>
 50242      public Type ParameterCILType { get; }
 243
 244      /// <summary>
 245      /// Implements <see cref="StatementParameter.ParameterValue"/> and gets the parameter value.
 246      /// May be <c>null</c>.
 247      /// </summary>
 248      /// <value>The parameter value.</value>
 50249      public Object ParameterValue { get; }
 250
 251      //public Boolean Equals( StatementParameter other )
 252      //{
 253      //   return ReferenceEquals( this, other )
 254      //      || ( other != null
 255      //      && Equals( this.ParameterCILType, other.ParameterCILType )
 256      //      && Equals( this.ParameterValue, other.ParameterValue )
 257      //      );
 258      //}
 259   }
 260
 261   internal static class CBAMExtensions
 262   {
 263
 264
 265      // TODO Collections.Generic.IList<T> does not extend Collections.List...
 266
 267      public static Boolean CheckListIndex<T>( this
 268#if NET40
 269      IList<T>
 270#else
 271      IReadOnlyList<T>
 272#endif
 273         list, Int32 index )
 274      {
 275         return list != null && index >= 0 && index < list.Count;
 276      }
 277
 278      public static void CheckListIndexOrThrow<T>( this
 279#if NET40
 280      IList<T>
 281#else
 282      IReadOnlyList<T>
 283#endif
 284         list, Int32 index, String indexParameterName = null )
 285      {
 286         if ( !list.CheckListIndex( index ) )
 287         {
 288            throw new ArgumentException( String.IsNullOrEmpty( indexParameterName ) ? "list index" : indexParameterName 
 289         }
 290      }
 291
 292
 293      public static
 294#if NET40
 295      IList<T[]>
 296#else
 297      IReadOnlyList<T[]>
 298#endif
 299         CheckListIndexAndReturnOrThrow<T>( this
 300#if NET40
 301      IList<T[]>
 302#else
 303      IReadOnlyList<T[]>
 304#endif
 305         list, Int32 index, String indexParameterName = null )
 306      {
 307         list.CheckListIndexOrThrow( index, indexParameterName );
 308         return list;
 309      }
 310
 311      public static T[] NewArrayOfLength<T>( this Int32 newLength, String msg = null )
 312      {
 313         if ( newLength < 0 )
 314         {
 315            throw new ArgumentException( msg ?? "Invalid array length" );
 316         }
 317         else if ( newLength == 0 )
 318         {
 319            return Empty<T>.Array;
 320         }
 321         else
 322         {
 323            return new T[newLength];
 324         }
 325      }
 326   }
 327}
 328
 329