<commit_before>namespace ReamQuery
{
    using System;
    using System.Linq;
    using Microsoft.EntityFrameworkCore.Scaffolding.Internal;
    using ReamQuery.Services;
    using Microsoft.EntityFrameworkCore.Scaffolding;
    using System.Threading.Tasks;
    using ReamQuery.Models;
    using System.Text;
    using System.Text.RegularExpressions;
    using ReamQuery.Helpers;
    using NLog;

    public abstract class BaseSchemaService
    {
        private static Logger Logger = LogManager.GetCurrentClassLogger();
        
        private string _tempFolder;

        protected InMemoryFileService InMemoryFiles;
        protected ReverseEngineeringGenerator Generator;
        protected IScaffoldingModelFactory ScaffoldingModelFactory;
        public BaseSchemaService() 
        {
            // todo figure out something better
            _tempFolder = Environment.GetEnvironmentVariable("TEMP");
            if (string.IsNullOrEmpty(_tempFolder)) 
            {
                _tempFolder = "/tmp";
            }
        }
        public async Task<SchemaResult> GetSchemaSource(string connectionString, string assemblyNamespace, bool withUsings = true) 
        {
            var programName = "Ctx";
            // append guid to create unique output location
            var outputPath = System.IO.Path.Combine(_tempFolder, Guid.NewGuid().ToIdentifierWithPrefix("folder"));
            var conf = new ReverseEngineeringConfiguration 
            {
                ConnectionString = connectionString,
                ContextClassName = programName,
                ProjectPath = "na",
                ProjectRootNamespace = assemblyNamespace,
                OutputPath = outputPath
            };
            ReverseEngineerFiles resFiles = null; 
            try 
            {
                resFiles = await Generator.GenerateAsync(conf);
            }
            catch (System.Exception exn) when (exn.ExpectedError())
            {
                Logger.Debug("Known error {0}", exn.Message);
                return new SchemaResult { Code = exn.StatusCode(), Message = exn.Message };
            }
            var output = new StringBuilder();
            var dbCtx = CreateContext(InMemoryFiles.RetrieveFileContents(outputPath, programName + ".cs"), isLibrary: withUsings);
            var ctx = dbCtx.Item1;
            if (!withUsings)
            {
                ctx = ctx.SkipLines(3);
            }
            else
            {
                output.Append(_refs);
            }
            // remove the entity generated warning about injected connection strings
            ctx = Regex.Replace(ctx, @"#warning.*", "");
            output.Append(ctx);
            Logger.Info("ContextFile.Count {0}", resFiles.ContextFile.Count());
            foreach(var fpath in resFiles.EntityTypeFiles)
            {
                output.Append(InMemoryFiles.RetrieveFileContents(outputPath, System.IO.Path.GetFileName(fpath)).SkipLines(4));
            }
            
            return new SchemaResult 
            {
                Schema = output.ToString(),<commit_msg>Avoid racecondition in EF<commit_after>namespace ReamQuery
{
    using System;
    using System.Linq;
    using Microsoft.EntityFrameworkCore.Scaffolding.Internal;
    using ReamQuery.Services;
    using Microsoft.EntityFrameworkCore.Scaffolding;
    using System.Threading.Tasks;
    using ReamQuery.Models;
    using System.Text;
    using System.Text.RegularExpressions;
    using ReamQuery.Helpers;
    using NLog;

    public abstract class BaseSchemaService
    {
        private static Logger Logger = LogManager.GetCurrentClassLogger();
        private object _lock = new object();
        
        private string _tempFolder;

        protected InMemoryFileService InMemoryFiles;
        protected ReverseEngineeringGenerator Generator;
        protected IScaffoldingModelFactory ScaffoldingModelFactory;
        public BaseSchemaService() 
        {
            // todo figure out something better
            _tempFolder = Environment.GetEnvironmentVariable("TEMP");
            if (string.IsNullOrEmpty(_tempFolder)) 
            {
                _tempFolder = "/tmp";
            }
        }
        public async Task<SchemaResult> GetSchemaSource(string connectionString, string assemblyNamespace, bool withUsings = true) 
        {
            var programName = "Ctx";
            // append guid to create unique output location
            var outputPath = System.IO.Path.Combine(_tempFolder, Guid.NewGuid().ToIdentifierWithPrefix("folder"));
            var conf = new ReverseEngineeringConfiguration 
            {
                ConnectionString = connectionString,
                ContextClassName = programName,
                ProjectPath = "na",
                ProjectRootNamespace = assemblyNamespace,
                OutputPath = outputPath
            };
            ReverseEngineerFiles resFiles = null; 
            try 
            {
                // todo there's a race condition in here when fx both template and execute are called at once, 
                // which seems to trigger something in EF, instead of this lock, do some sync in SchemaSource. 
                lock(_lock) {
                    var resFilesTask = Generator.GenerateAsync(conf);
                    resFilesTask.Wait();
                    resFiles = resFilesTask.Result;
                }
            }
            catch (System.Exception exn) when (exn.ExpectedError())
            {
                Logger.Debug("Known error {0}", exn.Message);
                return new SchemaResult { Code = exn.StatusCode(), Message = exn.Message };
            }
            var output = new StringBuilder();
            var dbCtx = CreateContext(InMemoryFiles.RetrieveFileContents(outputPath, programName + ".cs"), isLibrary: withUsings);
            var ctx = dbCtx.Item1;
            if (!withUsings)
            {
                ctx = ctx.SkipLines(3);
            }
            else
            {
                output.Append(_refs);
            }
            // remove the entity generated warning about injected connection strings
            ctx = Regex.Replace(ctx, @"#warning.*", "");
            output.Append(ctx);
            Logger.Info("ContextFile.Count {0}", resFiles.ContextFile.Count());
            foreach(var fpath in resFiles.EntityTypeFiles)
            {
                output.Append(InMemoryFiles.RetrieveFileContents(outputPath, System.IO.Path.GetFileName(fpath)).SkipLines(4));
            }
            
            return new SchemaResult 
            {
                Schema = output.ToString(),
{'fraction_non_alphanumeric': 0.07805907172995781, 'fraction_numerical': 0.0015069318866787222, 'mean_word_length': 1.857081360309944, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '6195753', 'n_tokens_mistral': 1581, 'n_tokens_neox': 1529, 'n_words': 376}