[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/DirectSQL/DirectSQL/refs/heads/main/DirectSQL/SqlResult.cs [Back]  [Original]

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Data;
using System.Dynamic;
using System.Threading.Tasks;

namespace DirectSQL
{
    /// 
    /// Object to get result of SQL
    /// 
    /// This stands for cursor in RDB
    /// Type of DataReader
    /// Type of DbCommand
    /// Type of Transaction
    /// Type of Connection
    /// Type of DataParameter
    public class SqlResult:EnumerableObject,IDisposable
        where R : IDataReader 
        where CMD : IDbCommand 
        where T : IDbTransaction 
        where C : IDbConnection 
        where P : IDataParameter, new()
    {
        private R _reader;
        private CMD _command;

        private ImmutableArray _resultFields = emptyFields;
        private static readonly ImmutableArray emptyFields = new ImmutableArray();

        private ExpandoObject _resultValues;
        private (String name, Object value)[] _resultTuples;

        private readonly IEnumerable _innerEnumerator;

        /// 
        /// variable not to execute not needed initialization
        /// 
        private bool _allowInitialize;

        /// 
        /// Reader in ADO.NET
        /// 
        public IDataReader Reader
        {
            get
            {
                return _reader;
            }
        }

        /// 
        /// Command in ADO.NET
        /// 
        public IDbCommand Command
        {
            get
            {
                return _command;
            }
        }

        /// 
        /// Sql
        /// 
        /// CommandText of command
        public String Sql
        {
            get
            {
                return _command.CommandText;
            }
        }

        /// 
        /// Fields in result
        /// 
        public ImmutableArray ResultFields
        {
            get
            {
                InitResultFields();
                return _resultFields;
            }
        }

        /// 
        /// Result values as dynamic object
        /// 
        /// 
        /// Each column in result has a field in dynamic object.
        /// 
        public dynamic ResultValues
        {
            get
            {
                InitResultValues();
                return _resultValues;
            }
        }

        /// 
        /// Result object of type T
        /// 
        /// Type of result object
        /// convert from dynamic to T
        /// result object
        /// dynamic object is same as ResultValues
        public TP ResultObject(Func convert){
            return convert(ResultValues);
        }

        /// 
        /// Return enumerable of SqlResult
        /// 
        /// Type of object to be enumerated
        /// Convert from dynamic to T
        /// Object which enumerate result of SqlResult
        public IEnumerable AsEnumerable(Func convert)
        {
            return new Enumerable(this, convert);
        }

        /// 
        /// Return enumerable of SqlResult as dynamic
        /// 
        /// Object which enumerate result of SqlResult
        public IEnumerable AsEnumerable()
        {
            return new Enumerable(this, (obj => obj ));
        }        

        /// 
        /// Result values as an array of tuples
        /// 
        /// 
        /// Each tuple has name and value.
        /// Name is name of column and 
        /// value is value of column
        /// in result row
        /// 
        public (String name,Object value)[] ResultTuples
        {
            get
            {
                InitResultTuples();
                return _resultTuples;
            }
        }

        private SqlResult ( 
            String sql, 
            P[] parameters, 
            C connection, 
            IDbTransaction transaction)
        {
            _command = (CMD) connection.CreateCommand();

            _command.CommandText = sql;

            foreach(var param in parameters){
                _command.Parameters.Add(param);
            }

            if(transaction != 
                   DefaultTransaction.defaultTransaction) {
                _command.Transaction = (T)transaction;
            }

            _allowInitialize = true;

            _innerEnumerator = AsEnumerable();
        }

        internal SqlResult ( 
            String sql, 
            P[] parameters, 
            C connection, 
            T transaction) : this( sql, parameters, connection, (IDbTransaction) transaction)
        {
        }

        internal SqlResult ( 
            String sql, 
            P[] parameters, 
            C connection) : 
            this( 
                sql, 
                parameters, 
                connection, 
                DefaultTransaction.defaultTransaction)
        {
        }        

        /// 
        /// Move cursor to next
        /// 
        /// New row has values or not
        public bool Next()
        {
            _resultValues = null;
            _resultTuples = null;

            _allowInitialize = true;

            return _reader.Read();
        }

        internal void Init()
        {
            if (_allowInitialize)
            {
                if (_reader != null)
                    _reader.Close();

                _reader = (R) _command.ExecuteReader();
                _allowInitialize = false;

                _resultValues = null;
                _resultTuples = null;
                _resultFields = emptyFields;
            }
        }

        private void InitResultFields()
        {
            if (_resultFields != emptyFields)
                return; //Already initialized. No need to init again.

            List list = new List();
            for(int i = 0; i < _reader.FieldCount; i ++)
            {
                list.Add(_reader.GetName(i));
            }

            _resultFields = ImmutableArray.ToImmutableArray(list);
        }

        private void InitResultValues()
        {
            if (_resultValues != null)
                return;
            _resultValues = CreateResultValue(_reader, ResultFields);
        }

        private static ExpandoObject CreateResultValue(
            R reader, 
            ImmutableArray fields)
        {
            var values = new ExpandoObject();

            for (int i = 0; i < reader.FieldCount; i++)
            {
                values.TryAdd(fields[i], reader.GetValue(i));
            }

            return values;
        }

        private void InitResultTuples()
        {
            if (_resultTuples != null)
                return;
            _resultTuples = CreateResultTuples(_reader, ResultFields);
        }

        private static (string, object)[] CreateResultTuples(
            R reader, 
            ImmutableArray resultFields)
        {
            var array = new (String, object)[resultFields.Length];
            for(int i = 0; i < resultFields.Length; i ++)
            {
                array[i] = (resultFields[i], reader.GetValue(i));
            }
            return array;
        }

        internal void Close()
        {
            if (_reader != null)
                _reader.Close();

            if ( _command != null )
                _command.Dispose();
        }

        /// 
        /// Dispose resources.
        /// 
        public void Dispose()
        {
            Close();
        }

        public static dynamic[] LoadSqlResult(
            String sql,
            P[] parameters,
            C connection, 
            T transaction)
        {
            var list = new List();

            Database.Query(
                sql,
                parameters,
                connection,
                transaction,
                (result) => {
                    while (result.Next())
                    {
                        list.Add(result.ResultValues);
                    }
                });

            return list.ToArray();
        }

        public static dynamic[] LoadSqlResult(
            String sql,
            (String name, object value)[] parameters,
            C connection, 
            T transaction)
        {
            return LoadSqlResult(
                sql,
                Database.ConvertToDbParameter(parameters),
                connection,
                transaction
            );
        }

        public static dynamic[] LoadSqlResult(
            String sql,
            C connection,
            T transaction)
        {
            return LoadSqlResult(
                sql, 
                new (String, object)[0], 
                connection, 
                transaction
            );
        }
        
        public static async Task LoadSqlResultAsync(
            String sql,
            C connection,
            T transaction)
        {
            return await LoadSqlResultAsync(
                sql, 
                new (String, object)[0], 
                connection, 
                transaction);
        }

        public static async Task LoadSqlResultAsync(
            String sql,
            (String name, object value)[] parameters,
            C connection,
            T transaction)
        {
            return await LoadSqlResultAsync(
                sql,
                Database.ConvertToDbParameter(parameters),
                connection,
                transaction
            );
        }

         public static async Task LoadSqlResultAsync(
            String sql,
            P[] parameters,
            C connection,
            T transaction)
        {
            Task task = Task.Run(() =>
            {
                var list = new List();

                Database.Query(
                    sql,
                    parameters,
                    connection,
                    transaction,
                    (result) =>
                    {
                        while (result.Next())
                        {
                            list.Add(result.ResultValues);
                        }
                    });

                return list.ToArray();
            });

            return await task;
        }

        public override IEnumerator GetEnumerator()
        {
            return _innerEnumerator.GetEnumerator();
        }

        private class Enumerable : IEnumerable 
        {
            private readonly SqlResult _sqlResult;
            private readonly Func _convert;

            internal Enumerable(
                SqlResult sqlResult,
                Func converter)
            {                
                _sqlResult = sqlResult;
                _convert = converter;
            }

            public IEnumerator GetEnumerator()
            {
                _sqlResult.Init();
                return new Enumerator(_sqlResult, _convert);
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }

        private class Enumerator : IEnumerator, IEnumerator 
        {
            private SqlResult _sqlResult;
            private readonly Func _convert;

            internal Enumerator(
                SqlResult sqlResult, 
                Func converter)
            {
                _sqlResult = sqlResult;
                _convert = converter;
            }

            public TP Current => _sqlResult.ResultObject(_convert);

            object IEnumerator.Current => _sqlResult.ResultObject(_convert);

            public void Dispose()
            {
                _sqlResult = null;
            }

            public bool MoveNext()
            {
                return _sqlResult.Next();
            }

            public void Reset()
            {
                _sqlResult.Init();
            }
        }
    }
}

Web Proxy Viewer  |  New URL  |  Original Page