<commit_before>﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Text;

namespace TddBuddy.SpeedySqlLocalDb.Attribute
{
    public sealed class SharedSpeedyLocalDb : System.Attribute, IDisposable
    {        
        private readonly Type _dbContextType;
        private readonly Type[] _dbContextTypeArgs;
        private readonly ISpeedySqlLocalDb _speedyInstance;
        private readonly ContextVariables _contextVariables;

        private static Type[] nullTypeArgs = new Type[0];

        public SharedSpeedyLocalDb(Type dbContextType) : this(dbContextType, nullTypeArgs){}

        public SharedSpeedyLocalDb(Type dbContextType, params Type[] dbContextTypeArgs)
        {
            if (!dbContextType.IsSubclassOf(typeof(DbContext)))
            {
                throw new Exception($"{nameof(dbContextType)} must be a subclass of DbContext");
            }

            _dbContextType = dbContextType;
            _dbContextTypeArgs = dbContextTypeArgs;
            _contextVariables = new ContextVariables();
            _speedyInstance = new SpeedySqlLocalDb(_contextVariables);
            BootstrapDatabaseForEfMigrations();
            CleanUpOldDatabases();
        }

        public void Dispose()
        {
            DetachDatabase();
        }

        // todo : TEST THIS
        private void CleanUpOldDatabases()
        {
            var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            var masterLocalDb = @"Microsoft\Microsoft SQL Server Local DB\Instances\MSSQLLocalDb\master.mdf";
            var connectionString = $"Data Source={_contextVariables.LocalDbName};AttachDBFileName={appDataPath}\\{masterLocalDb};Initial Catalog=master;Integrated Security=True;";
            using (var connection = new SqlConnection(connectionString))
            {
                var cleanCmd = CreateCleanupCommand();

                using (var cmd = connection.CreateCommand())
                {
                    RemoveDatabases(connection, cleanCmd, cmd);
                }
            }
        }

        private void RemoveDatabases(SqlConnection connection, string cleanCmd, SqlCommand cmd)
        {
            try
            {
                connection.Open();
                cmd.CommandText = cleanCmd;
                cmd.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                // could be a pathing issue to DB or other sillyness
                Console.Write($"Failed attempting to clean up old connections - {e.Message}");
            }
        }

        private string CreateCleanupCommand()
        {
            var cleanCmd = new StringBuilder();
            cleanCmd.AppendLine("declare @tmp table(cmd nvarchar(1024));");
            cleanCmd.AppendLine(
                $"insert into @tmp(cmd) select 'drop database ' + name from sys.databases where name like '{_contextVariables.Prefix}%' and is_cleanly_shutdown = 1;");
            cleanCmd.AppendLine("declare @cmd nvarchar(1024);");
            cleanCmd.AppendLine("while exists(select * from @tmp)");
            cleanCmd.AppendLine("begin");
            cleanCmd.AppendLine("select top 1 @cmd = cmd from @tmp;");
            cleanCmd.AppendLine("delete from @tmp where cmd = @cmd;");
            cleanCmd.AppendLine("begin try");
            cleanCmd.AppendLine("exec(@cmd);");
            cleanCmd.AppendLine("end try");
            cleanCmd.AppendLine("begin catch");
            cleanCmd.AppendLine("end catch");
            cleanCmd.AppendLine("end");
            return cleanCmd.ToString();
        }

        private void BootstrapDatabaseForEfMigrations()
        {
            try
            {
                using (var connectionWrapper = _speedyInstance.CreateSpeedyLocalDbWrapper())
                {
                    var repositoryDbContext = CreateDbContext(connectionWrapper.Connection);
                    // force EF migrations to run and build db
                    repositoryDbContext.Database.ExecuteSqlCommand("select 1");
                    connectionWrapper.CompleteTransaction();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Bootstrap Exception: {e.Message}");
            }
        }


        private DbContext CreateDbContext(DbConnection connection)
        {
            if (_dbContextTypeArgs.Length == 0)<commit_msg>Changed _dbContextType.Length == 0 to == nullTypeArgs as static named instance<commit_after>﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Text;

namespace TddBuddy.SpeedySqlLocalDb.Attribute
{
    public sealed class SharedSpeedyLocalDb : System.Attribute, IDisposable
    {        
        private readonly Type _dbContextType;
        private readonly Type[] _dbContextTypeArgs;
        private readonly ISpeedySqlLocalDb _speedyInstance;
        private readonly ContextVariables _contextVariables;

        private static Type[] nullTypeArgs = new Type[0];

        public SharedSpeedyLocalDb(Type dbContextType) : this(dbContextType, nullTypeArgs){}

        public SharedSpeedyLocalDb(Type dbContextType, params Type[] dbContextTypeArgs)
        {
            if (!dbContextType.IsSubclassOf(typeof(DbContext)))
            {
                throw new Exception($"{nameof(dbContextType)} must be a subclass of DbContext");
            }

            _dbContextType = dbContextType;
            _dbContextTypeArgs = dbContextTypeArgs;
            _contextVariables = new ContextVariables();
            _speedyInstance = new SpeedySqlLocalDb(_contextVariables);
            BootstrapDatabaseForEfMigrations();
            CleanUpOldDatabases();
        }

        public void Dispose()
        {
            DetachDatabase();
        }

        // todo : TEST THIS
        private void CleanUpOldDatabases()
        {
            var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            var masterLocalDb = @"Microsoft\Microsoft SQL Server Local DB\Instances\MSSQLLocalDb\master.mdf";
            var connectionString = $"Data Source={_contextVariables.LocalDbName};AttachDBFileName={appDataPath}\\{masterLocalDb};Initial Catalog=master;Integrated Security=True;";
            using (var connection = new SqlConnection(connectionString))
            {
                var cleanCmd = CreateCleanupCommand();

                using (var cmd = connection.CreateCommand())
                {
                    RemoveDatabases(connection, cleanCmd, cmd);
                }
            }
        }

        private void RemoveDatabases(SqlConnection connection, string cleanCmd, SqlCommand cmd)
        {
            try
            {
                connection.Open();
                cmd.CommandText = cleanCmd;
                cmd.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                // could be a pathing issue to DB or other sillyness
                Console.Write($"Failed attempting to clean up old connections - {e.Message}");
            }
        }

        private string CreateCleanupCommand()
        {
            var cleanCmd = new StringBuilder();
            cleanCmd.AppendLine("declare @tmp table(cmd nvarchar(1024));");
            cleanCmd.AppendLine(
                $"insert into @tmp(cmd) select 'drop database ' + name from sys.databases where name like '{_contextVariables.Prefix}%' and is_cleanly_shutdown = 1;");
            cleanCmd.AppendLine("declare @cmd nvarchar(1024);");
            cleanCmd.AppendLine("while exists(select * from @tmp)");
            cleanCmd.AppendLine("begin");
            cleanCmd.AppendLine("select top 1 @cmd = cmd from @tmp;");
            cleanCmd.AppendLine("delete from @tmp where cmd = @cmd;");
            cleanCmd.AppendLine("begin try");
            cleanCmd.AppendLine("exec(@cmd);");
            cleanCmd.AppendLine("end try");
            cleanCmd.AppendLine("begin catch");
            cleanCmd.AppendLine("end catch");
            cleanCmd.AppendLine("end");
            return cleanCmd.ToString();
        }

        private void BootstrapDatabaseForEfMigrations()
        {
            try
            {
                using (var connectionWrapper = _speedyInstance.CreateSpeedyLocalDbWrapper())
                {
                    var repositoryDbContext = CreateDbContext(connectionWrapper.Connection);
                    // force EF migrations to run and build db
                    repositoryDbContext.Database.ExecuteSqlCommand("select 1");
                    connectionWrapper.CompleteTransaction();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Bootstrap Exception: {e.Message}");
            }
        }


        private DbContext CreateDbContext(DbConnection connection)
        {
            if (_dbContextTypeArgs == nullTypeArgs)
{'fraction_non_alphanumeric': 0.08651623555310953, 'fraction_numerical': 0.0028618602091359385, 'mean_word_length': 2.0582295523392795, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4740265', 'n_tokens_mistral': 2240, 'n_tokens_neox': 2128, 'n_words': 501}