csharp/aadreja/vega/Vega/Helper.cs

Helper.cs
/*
 Description: Vega - Fastest ORM with enterprise features
 Author: Ritesh Sutaria
 Date: 9-Dec-2017
 Home Page: https://github.com/aadreja/vega
            http://www.vegaorm.com
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;

namespace Vega
{
    /// 
    /// Vega extension and helper methods 
    /// 
    public static clast Helper
    {
        
        #region constructor

        static Helper()
        {
            mTypeHash = new Hashtable
            {
                [typeof(sbyte)] = OpCodes.Ldind_I1,
                [typeof(byte)] = OpCodes.Ldind_U1,
                [typeof(char)] = OpCodes.Ldind_U2,
                [typeof(short)] = OpCodes.Ldind_I2,
                [typeof(ushort)] = OpCodes.Ldind_U2,
                [typeof(int)] = OpCodes.Ldind_I4,
                [typeof(uint)] = OpCodes.Ldind_U4,
                [typeof(long)] = OpCodes.Ldind_I8,
                [typeof(ulong)] = OpCodes.Ldind_I8,
                [typeof(bool)] = OpCodes.Ldind_I1,
                [typeof(double)] = OpCodes.Ldind_R8,
                [typeof(float)] = OpCodes.Ldind_R4
            };
        }

        #endregion

        #region type extension

        #region idbcommand extension

        /// 
        /// Adds out parameter to the command
        /// 
        /// IDbCommand object
        /// Name of parameter
        /// DbType of parameter
        public static void AddOutParameter(this IDbCommand cmd,
                                   string name,
                                   DbType dbType)
        {
            AddParameter(cmd, name, dbType, ParameterDirection.Output, name, DataRowVersion.Default, null);
        }

        /// 
        /// Adds In parameter to the command
        /// 
        /// IDbCommand object
        /// Name of parameter
        /// DbType of parameter
        /// Value of parameter
        public static void AddInParameter(this IDbCommand cmd,
                                   string name,
                                   DbType dbType,
                                   object value)
        {
            AddParameter(cmd, name, dbType, ParameterDirection.Input, String.Empty, DataRowVersion.Default, value);
        }

        /// 
        /// Adds Parameter to the command
        /// 
        /// IDbCommand object
        /// Name of parameter
        /// DbType of parameter
        /// Director: In or Out
        /// Name of the source column for loading or returning the System.Data.IDataParameter.Value.
        /// System.Data.DataRowVersion to use when loading System.Data.IDataParameter.Value
        /// Value of parameter
        public static void AddParameter(this IDbCommand cmd,
                                 string name,
                                 DbType dbType,
                                 ParameterDirection direction,
                                 string sourceColumn,
                                 DataRowVersion sourceVersion,
                                 object value)
        {
            AddParameter(cmd, name, dbType, 0, direction, false, 0, 0, sourceColumn, sourceVersion, value);
        }

        /// 
        /// Adds Parameter to the command
        /// 
        /// IDbCommand object
        /// Name of parameter
        /// DbType of parameter
        /// Director: In or Out
        /// Name of the source column for loading or returning the System.Data.IDataParameter.Value.
        /// System.Data.DataRowVersion to use when loading System.Data.IDataParameter.Value
        /// Size of column
        /// Is Null values allowed
        /// For Numeric data size e.g. Decimal(10)
        /// For Numeric data scale size e.g. Decimal(10,2)
        /// Value of parameter
        public static void AddParameter(this IDbCommand cmd,
                                         string name,
                                         DbType dbType,
                                         int size,
                                         ParameterDirection direction,
                                         bool nullable,
                                         byte precision,
                                         byte scale,
                                         string sourceColumn,
                                         DataRowVersion sourceVersion,
                                         object value)
        {
            if (cmd == null) throw new ArgumentNullException("command");

            IDbDataParameter parameter = cmd.CreateParameter();

            parameter.ParameterName = name;
            parameter.DbType = dbType;
            parameter.Size = size;
            parameter.Direction = direction;
            //parameter.IsNullable = nullable; //TODO
            parameter.Precision = precision;
            parameter.Scale = scale;
            parameter.SourceColumn = sourceColumn;
            parameter.SourceVersion = sourceVersion;
            parameter.Value = value.ToParameterValue();

            cmd.Parameters.Add(parameter);
        }

        #endregion

        #region object extension 

        /// 
        /// Box Parameter Value to type as per database
        /// 
        /// object of value
        /// boxed value
        internal static object ToParameterValue(this object value)
        {
            if (value == null)
            {
                return DBNull.Value;
            }

            //TODO: not all needs mindatetime to be stored as null
            //if (value is DateTime && (DateTime)value == DateTime.MinValue) return DBNull.Value;

            if (value is Guid) if (Equals(value, Guid.Empty)) return DBNull.Value; else return value;
            else if (value.GetType().IsEnum) return Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
            else return value;
        }

        /// 
        /// Change escaped characters in XML and retuns XML format string
        /// 
        /// Value to convert
        /// dbtype of column
        /// xml string
        internal static string ToXMLValue(this object value, DbType dbType)
        {
            if (value == null) return string.Empty;

            string strValue = (dbType == DbType.DateTime || 
                dbType == DbType.Date) ? strValue = ((DateTime)value).ToSQLDateTime() : value.ToString();            

            //replace special characters in XML //" ' & < >
            strValue = strValue.Replace("'", "'").Replace("\"", """).Replace("&", "&").Replace("", ">");

            return strValue;
        }

        /// 
        /// Checks whether value is number returns true if number else false
        /// 
        /// any object
        /// true or false
        public static bool IsNumber(this object value)
        {
            return value is sbyte
                    || value is byte
                    || value is short
                    || value is ushort
                    || value is int
                    || value is uint
                    || value is long
                    || value is ulong
                    || value is float
                    || value is double
                    || value is decimal;
        }

        /// 
        /// Checks whether value is of AnonymousType
        /// 
        /// any object
        /// true or false
        public static bool IsAnonymousType(this object value)
        {
            if (value == null)
                return false;

            Type type = value.GetType();

            return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
               && type.IsGenericType && type.Name.Contains("AnonymousType")
               && (type.Name.StartsWith("", StringComparison.OrdinalIgnoreCase) ||
                   type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase))
               && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
        }

        #endregion

        #region datetime extension

        /// 
        /// From SQL format datetime (yyyy-MM-dd) to datetime
        /// 
        /// String date
        /// 
        public static DateTime FromSQLDateTime(this string pDate)
        {
            DateTime.TryParse(pDate, out DateTime result);
            return result;
        }

        /// 
        /// To SQL format datetime (yyyy-MM-dd HH:mm:ss)
        /// 
        /// DateTime
        /// 
        public static string ToSQLDateTime(this DateTime pDate)
        {
            return pDate.ToString("yyyy-MM-dd HH:mm:ss");
        }

        /// 
        /// To SQL format datetime (yyyy-MM-dd HH:mm:ss)
        /// 
        /// DateTime Nullable
        /// 
        public static string ToSQLDateTime(this DateTime? pDate)
        {
            if (pDate == null) return string.Empty;
            else return ToSQLDateTime((DateTime)pDate);
        }

        /// 
        /// From SQL format datetime (yyyy-MM-dd) to datetime
        /// 
        /// String date
        /// 
        public static DateTime FromSQLDate(this string pDate)
        {
            DateTime.TryParse(pDate, out DateTime result);
            return result;
        }

        /// 
        /// To SQL format date (yyyy-MM-dd)
        /// 
        /// DateTime
        /// 
        public static string ToSQLDate(this DateTime pDate)
        {
            return pDate.ToString("yyyy-MM-dd");
        }

        /// 
        /// To SQL format date (yyyy-MM-dd)
        /// 
        /// Nullable DateTime
        /// 
        public static string ToSQLDate(this DateTime? pDate)
        {
            if (pDate == null) return string.Empty;
            else return ToSQLDate((DateTime)pDate);
        }

        #endregion

        #region string & stringbuilder extension

        internal static string RemoveLastComma(this string pString)
        {
            if (pString[pString.Length - 1] == ',')
            {
                pString = pString.Remove(pString.Length - 1, 1);
            }
            return pString;
        }

        internal static StringBuilder RemoveLastComma(this StringBuilder pString)
        {
            if (pString[pString.Length - 1] == ',')
            {
                pString.Remove(pString.Length - 1, 1);
            }
            return pString;
        }

        #endregion

        #endregion

        #region converters

        internal static R Parse(this object value)
        {
            if (value == null || value is DBNull) return default(R);
            if (value is R) return (R)value;

            Type type = typeof(R);
            if (type.IsEnum)
            {
                value = Convert.ChangeType(value, Enum.GetUnderlyingType(type), CultureInfo.InvariantCulture);
                return (R)Enum.ToObject(type, value);
            }
            else
            {
                return (R)Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
            }
        }

        internal static object ConvertTo(this object value, Type type)
        {
            var converter = TypeDescriptor.GetConverter(type);

            return converter.ConvertFrom(value);
        }

        internal static object ConvertTo(this string value, Type type)
        {
            var converter = TypeDescriptor.GetConverter(type);

            return converter.ConvertFromString(value);
        }

        internal static object GetDateTimeOrDatabaseDateTimeSQL(DateTime? dateTime, Database db, bool overRideCreatedUpdatedOn)
        {
            if(!overRideCreatedUpdatedOn || dateTime == null || dateTime == default(DateTime))
                return db.CURRENTDATETIMESQL;
            else
                return dateTime;
        }

        #endregion

        #region Configuration Helper Methods

        ///// 
        ///// Reads value from AppSettings sections from App.Config or Web.Config file
        ///// 
        ///// String value indicating Key.
        ///// if found returns value of the specified key from the .config files, otherwise returns Empty string.
        //public static string GetAppSetting(String pKey)
        //{
        //    if (ConfigurationManager.AppSettings[pKey] != null)
        //        return ConfigurationManager.AppSettings[pKey].ToString();
        //    else
        //        return string.Empty;
        //}

        ///// 
        ///// Reads value from ConnectionStrings sections from App.Config or Web.Config file
        ///// 
        ///// String value indicating Key.
        ///// if found returns value of the specified key from the .config files, otherwise returns Empty string.
        //public static string GetConnectionString(String pKey)
        //{
        //    if (ConfigurationManager.ConnectionStrings[pKey] != null)
        //        return ConfigurationManager.ConnectionStrings[pKey].ToString();
        //    else
        //        return string.Empty;
        //}

        #endregion

        #region Emit Helper

        //https://www.codeproject.com/Articles/9927/Fast-Dynamic-Property-Access-with-C

        static Hashtable mTypeHash;

        internal static Func CreateGetProperty(Type ensatyType, string propertyName)
        {
            MethodInfo mi = ensatyType.GetProperty(propertyName).GetMethod;

            if (mi == null) return null; //no get property

            Type[] args = new Type[] { typeof(object) };

            DynamicMethod method = new DynamicMethod("Get_" + ensatyType.Name + "_" + propertyName, typeof(object), args, ensatyType.Module, true);
            ILGenerator getIL = method.GetILGenerator();

            getIL.DeclareLocal(typeof(object));
            getIL.Emit(OpCodes.Ldarg_0); //Load the first argument

            //(target object)
            //Cast to the source type
            getIL.Emit(OpCodes.Castclast, ensatyType);

            //Get the property value
            getIL.EmitCall(OpCodes.Call, mi, null);
            if (mi.ReturnType.IsValueType)
            {
                getIL.Emit(OpCodes.Box, mi.ReturnType);
                //Box if necessary
            }
            getIL.Emit(OpCodes.Stloc_0); //Store it

            getIL.Emit(OpCodes.Ldloc_0);
            getIL.Emit(OpCodes.Ret);

            var funcType = System.Linq.Expressions.Expression.GetFuncType(typeof(object), typeof(object));
            return (Func)method.CreateDelegate(funcType);
        }

        internal static Action CreateSetProperty(Type ensatyType, string propertyName)
        {
            MethodInfo mi = ensatyType.GetProperty(propertyName).SetMethod;

            if (mi == null) return null; //no set property

            Type[] args = new Type[] { typeof(object), typeof(object) };

            DynamicMethod method = new DynamicMethod("Set_" + ensatyType.Name + "_" + propertyName, null, args, ensatyType.Module, true);
            ILGenerator setIL = method.GetILGenerator();

            Type paramType = mi.GetParameters()[0].ParameterType;

            //setIL.DeclareLocal(typeof(object));
            setIL.Emit(OpCodes.Ldarg_0); //Load the first argument [Ensaty]
                                            //(target object)
                                            //Cast to the source type
            setIL.Emit(OpCodes.Castclast, ensatyType);
            setIL.Emit(OpCodes.Ldarg_1); //Load the second argument [Value]
                                            //(value object)
            if (paramType.IsValueType)
            {
                setIL.Emit(OpCodes.Unbox, paramType); //Unbox it 
                if (mTypeHash[paramType] != null) //and load
                {
                    OpCode load = (OpCode)mTypeHash[paramType];
                    setIL.Emit(load);
                }
                else
                {
                    setIL.Emit(OpCodes.Ldobj, paramType);
                }
            }
            else
            {
                setIL.Emit(OpCodes.Castclast, paramType); //Cast clast
            }

            setIL.EmitCall(OpCodes.Callvirt, mi, null); //Set the property value
            setIL.Emit(OpCodes.Ret);

            var actionType = System.Linq.Expressions.Expression.GetActionType(typeof(object), typeof(object));
            return (Action)method.CreateDelegate(actionType);
        }

        #endregion

    }

}