예제 #1
0
        public void BasicTest()
        {
            TestFileSystem fileSystem = new TestFileSystem();

            fileSystem.AddFile("A\\table1.cs", TestTable1Text);

            var generated = ExistingCodeExplorer
                            .EnumerateTableDescriptorsModelAttributes("A", fileSystem)
                            .ParseAttribute(true)
                            .CreateAnalysis()
                            .Select(meta => ModelClassGenerator.Generate(meta, "Org", "", true, ModelType.ImmutableClass, fileSystem, out _).SyntaxTree)
                            .ToList();

            var trees = new List <SyntaxTree>();

            foreach (var syntaxTree in generated)
            {
                trees.Add(CSharpSyntaxTree.ParseText(syntaxTree.ToString()));
            }

            trees.Add(CSharpSyntaxTree.ParseText(TestTable1Text));

            var compilation = CSharpCompilation.Create("SqModels",
                                                       trees,
                                                       options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, nullableContextOptions: NullableContextOptions.Enable));

            compilation = compilation.AddReferences(
                MetadataReference.CreateFromFile(Assembly.Load("netstandard, Version=2.0.0.0").Location),
                MetadataReference.CreateFromFile(typeof(object).Assembly.GetAssemblyLocation()),
                MetadataReference.CreateFromFile(Assembly
                                                 .Load("System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
                                                 .Location),
                MetadataReference.CreateFromFile(typeof(SqQueryBuilder).Assembly.GetAssemblyLocation()));

            MemoryStream ms = new MemoryStream();

            var emitResult = compilation.Emit(ms);

            if (!emitResult.Success)
            {
                Diagnostic first = emitResult.Diagnostics.First();

                var sourceCode = first.Location.SourceTree?.ToString();
                var s          = sourceCode?.Substring(first.Location.SourceSpan.Start, first.Location.SourceSpan.Length);
                Console.WriteLine(sourceCode);
                Assert.Fail(first.GetMessage() + (string.IsNullOrEmpty(s)?null:$" \"{s}\""));
            }

            var assembly = Assembly.Load(ms.ToArray());

            var allTypes = assembly.GetTypes();

            Assert.AreEqual(21, allTypes.Length);
        }
예제 #2
0
        public static async Task RunGenTablesOptions(GenTablesOptions options)
        {
            ILogger logger = new DefaultLogger(Console.Out, options.Verbosity);

            logger.LogMinimal("Table proxy classes generation is running...");

            string directory = EnsureDirectory(options.OutputDir, logger, "Output", true);

            if (string.IsNullOrEmpty(options.ConnectionString))
            {
                throw new SqExpressCodeGenException("Connection string cannot be empty");
            }
            logger.LogNormal("Checking existing code...");
            IReadOnlyDictionary <TableRef, ClassDeclarationSyntax> existingCode = ExistingCodeExplorer.FindTableDescriptors(directory);

            if (logger.IsNormalOrHigher)
            {
                logger.LogNormal(existingCode.Count > 0
                ? $"Found {existingCode.Count} already existing table descriptor classes."
                : "No table descriptor classes found.");
            }

            var sqlManager = CreateDbManager(options);

            logger.LogNormal("Connecting to database...");

            var connectionTest = await sqlManager.TryOpenConnection();

            if (!string.IsNullOrEmpty(connectionTest))
            {
                throw new SqExpressCodeGenException(connectionTest);
            }

            logger.LogNormal("Success!");

            var tables = await sqlManager.SelectTables();

            if (logger.IsNormalOrHigher)
            {
                logger.LogNormal(tables.Count > 0
                    ? $"Found {tables.Count} tables."
                    : "No tables found in the database.");

                if (logger.IsDetailed)
                {
                    foreach (var tableModel in tables)
                    {
                        Console.WriteLine($"{tableModel.DbName} ({tableModel.Name})");
                        foreach (var tableModelColumn in tableModel.Columns)
                        {
                            Console.WriteLine($"- {tableModelColumn.DbName.Name} {tableModelColumn.ColumnType.GetType().Name}{(tableModelColumn.Pk.HasValue ? " (PK)":null)}{(tableModelColumn.Fk != null ? $" (FK: {string.Join(';', tableModelColumn.Fk.Select(f=>f.ToString()))})" : null)}");
                        }
                    }
                }
            }

            logger.LogNormal("Code generation...");
            IReadOnlyDictionary <TableRef, TableModel> tableMap = tables.ToDictionary(t => t.DbName);

            var tableClassGenerator = new TableClassGenerator(tableMap, options.Namespace, existingCode);

            foreach (var table in tables)
            {
                string filePath = Path.Combine(directory, $"{table.Name}.cs");

                if (logger.IsDetailed)
                {
                    logger.LogDetailed($"{table.DbName} to \"{filePath}\".");
                }

                var text = tableClassGenerator.Generate(table, out var existing).ToFullString();
                await File.WriteAllTextAsync(filePath, text);

                if (logger.IsDetailed)
                {
                    logger.LogDetailed(existing ? "Existing file updated." : "New file created.");
                }
            }

            var allTablePath = Path.Combine(directory, "AllTables.cs");

            if (logger.IsDetailed)
            {
                logger.LogDetailed($"AllTables to \"{allTablePath}\".");
            }

            await File.WriteAllTextAsync(allTablePath, TableListClassGenerator.Generate(allTablePath, tables, options.Namespace, options.TableClassPrefix).ToFullString());

            logger.LogMinimal("Table proxy classes generation successfully completed!");
        }
예제 #3
0
        private static async Task RunGenModelsOptions(GenModelsOptions options)
        {
            ILogger logger = new DefaultLogger(Console.Out, options.Verbosity);

            logger.LogMinimal("Model classes generation is running...");

            string inDirectory  = EnsureDirectory(options.InputDir, logger, "Input", false);
            string outDirectory = EnsureDirectory(options.OutputDir, logger, "Output", true);

            var analysis = ExistingCodeExplorer
                           .EnumerateTableDescriptorsModelAttributes(inDirectory)
                           .ParseAttribute(options.NullRefTypes)
                           .CreateAnalysis();

            if (analysis.Count < 1)
            {
                logger.LogNormal("No model attributes detected in the input directory.");
            }
            else
            {
                logger.LogNormal($"Found {analysis.Count} models in the input directory.");
            }

            if (logger.IsDetailed)
            {
                foreach (var model in analysis)
                {
                    logger.LogDetailed(model.Name);
                    foreach (var property in model.Properties)
                    {
                        logger.LogDetailed(
                            $" -{property.Type} {property.Name}");
                        foreach (var col in property.Column)
                        {
                            logger.LogDetailed(
                                $"   ={(property.CastType != null ? $"({property.CastType})" : null)}{col.TableRef.TableTypeName}.{col.ColumnName}");
                        }
                    }
                }
            }

            logger.LogNormal("Code generation...");

            foreach (var meta in analysis)
            {
                string path = Path.Combine(outDirectory, $"{meta.Name}.cs");
                if (logger.IsDetailed)
                {
                    logger.LogDetailed(path);
                }
                await File.WriteAllTextAsync(path, ModelClassGenerator.Generate(meta, options.Namespace, path, out var existing).ToFullString());

                if (logger.IsDetailed)
                {
                    logger.LogDetailed(existing ? "Existing file updated." : "New file created.");
                }
            }


            logger.LogMinimal("Model classes generation successfully completed!");
        }
예제 #4
0
        private static async Task RunGenModelsOptions(GenModelsOptions options)
        {
            ILogger logger = new DefaultLogger(Console.Out, options.Verbosity);

            logger.LogMinimal("Model classes generation is running...");

            string inDirectory  = EnsureDirectory(options.InputDir, logger, "Input", false);
            string outDirectory = EnsureDirectory(options.OutputDir, logger, "Output", true);

            var analysis = ExistingCodeExplorer
                           .EnumerateTableDescriptorsModelAttributes(inDirectory, DefaultFileSystem.Instance)
                           .ParseAttribute(options.NullRefTypes)
                           .CreateAnalysis();

            if (analysis.Count < 1)
            {
                logger.LogNormal("No model attributes detected in the input directory.");
            }
            else
            {
                logger.LogNormal($"Found {analysis.Count} models in the input directory.");
            }

            if (logger.IsDetailed)
            {
                foreach (var model in analysis)
                {
                    logger.LogDetailed(model.Name);
                    foreach (var property in model.Properties)
                    {
                        logger.LogDetailed(
                            $" -{property.Type} {property.Name}");
                        foreach (var col in property.Column)
                        {
                            logger.LogDetailed(
                                $"   ={(property.CastType != null ? $"({property.CastType})" : null)}{col.TableRef.TableTypeName}.{col.ColumnName}");
                        }
                    }
                }
            }

            logger.LogNormal("Code generation...");

            foreach (var meta in analysis)
            {
                string path = Path.Combine(outDirectory, $"{meta.Name}.cs");
                if (logger.IsDetailed)
                {
                    logger.LogDetailed(path);
                }
                await File.WriteAllTextAsync(path, ModelClassGenerator.Generate(meta, options.Namespace, path, options.RwClasses, options.ModelType, DefaultFileSystem.Instance, out var existing).ToFullString());

                if (logger.IsDetailed)
                {
                    logger.LogDetailed(existing ? "Existing file updated." : "New file created.");
                }
            }

            if (options.CleanOutput)
            {
                var modelFiles = analysis.Select(meta => $"{meta.Name}.cs").ToHashSet(StringComparer.InvariantCultureIgnoreCase);

                var toRemove = Directory.EnumerateFiles(outDirectory).Where(p => !modelFiles.Contains(Path.GetFileName(p))).ToList();

                foreach (var delPath in toRemove)
                {
                    File.Delete(delPath);
                    if (logger.IsNormalOrHigher)
                    {
                        logger.LogNormal($"File {Path.GetFileName(delPath)} has been removed since it does not contain any model class");
                    }
                }
            }


            logger.LogMinimal("Model classes generation successfully completed!");
        }