public async Task BasicTest() { using var dbManager = new DbManager(new DbManagerTest(), new SqlConnection("Initial Catalog=TestDatabase;"), new GenTablesOptions(ConnectionType.MsSql, "fake", "Tab", "", "MyTables", verbosity: Verbosity.Quite)); var tables = await dbManager.SelectTables(); Assert.AreEqual(2, tables.Count); var tableMap = tables.ToDictionary(t => t.DbName); IReadOnlyDictionary <TableRef, ClassDeclarationSyntax> existingCode = new Dictionary <TableRef, ClassDeclarationSyntax>(); var generator = new TableClassGenerator(tableMap, "MyCompany.MyProject.Tables", existingCode); var trees = tables.Select(t => CSharpSyntaxTree.Create(generator.Generate(t, out _))).ToList(); var compilation = CSharpCompilation.Create("Tables", trees, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); 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) { Assert.Fail(emitResult.Diagnostics.FirstOrDefault()?.GetMessage()); } var assembly = Assembly.Load(ms.ToArray()); var allTypes = assembly.GetTypes(); var table1 = (TableBase)Activator.CreateInstance(allTypes.Find(t => t.Name == tables[0].Name)); Assert.NotNull(table1); var table2 = (TableBase)Activator.CreateInstance(allTypes.Find(t => t.Name == tables[1].Name)); Assert.NotNull(table2); string table1ExpectedSql = "CREATE TABLE [dbo].[TableZ]([Id] int NOT NULL IDENTITY (1, 1) DEFAULT (0),[ValueA] [nvarchar](255) NOT NULL DEFAULT (''),[Value_A] decimal(2,6),CONSTRAINT [PK_dbo_TableZ] PRIMARY KEY ([Id]));"; Assert.AreEqual(table1ExpectedSql, TSqlExporter.Default.ToSql(table1.Script.Create())); string table2ExpectedSql = "CREATE TABLE [dbo].[TableA]([Id] int NOT NULL IDENTITY (1, 1) DEFAULT (0),[Value] datetime NOT NULL DEFAULT (GETUTCDATE()),CONSTRAINT [PK_dbo_TableA] PRIMARY KEY ([Id]),CONSTRAINT [FK_dbo__TableA_to_dbo__TableZ] FOREIGN KEY ([Id]) REFERENCES [dbo].[TableZ]([Id]),INDEX [IX_dbo_TableA_Value_DESC] UNIQUE([Value] DESC));"; Assert.AreEqual(table2ExpectedSql, TSqlExporter.Default.ToSql(table2.Script.Create())); }
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!"); }