Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/EvilLord666/ReportGenerator

A small cross-database tool for building excel documents (reports) based on data from database that extacts via View or Stored Procedures with parametres, ordering e.t.c.
https://github.com/EvilLord666/ReportGenerator

cross-database database database-reporting di-service etl etl-automation excel excel-export excel-to-sql generator reportgenerator reporting-engine reporting-tool reports smart-reporting sql-to-excel statement stored-procedures

Last synced: 3 months ago
JSON representation

A small cross-database tool for building excel documents (reports) based on data from database that extacts via View or Stored Procedures with parametres, ordering e.t.c.

Awesome Lists containing this project

README

        

# ReportGenerator
## 1 Overview
A small tool (library) for generating reports (plain dataset) from ***Stored Procedures*** or ***Views*** following databases:
* MS SQL (SQL Server)
* MySQL
* Postgres

These reports could be generated in ***MS Excel*** or ***CSV*** formats with templates files (typically Headers only).
Logic of data extracting depends on parameters (variables) Stored procedures or Views (**WHERE** parameters, **ORDER BY** and **GROUP BY** parameters).

Report generator core passes parameters for data filtering in View or Variables for Stored Procedures, parameters are taking from:
* 1) ExecutionConfig (.xml file)
* 2) in runtime (as instance of ExecutionConfig class).

There are two ways for getting data:

- from stored procedure (passing variables)
- from view (passing where clauses, ordering and grouping conditions)

In both 2 ways there are a possibility to manipulate data selection by setting parameters (for stored procedure) and automatic sql generation for filtering
View data. It should be noted that there is a configuration of View and StoredProcedure in xml.

### 1.1 Configuration
For Stored Procedure Configuration we must set StoredProcedure

Name to stored procedure name

And also if we have aparameters we should specify collection of StoredProcedureParameters like, ParameterType is a integer value which is specific for databaseEngine :

SQL Server - SqlDbType (https://msdn.microsoft.com/ru-ru/library/system.data.sqldbtype(v=vs.110).aspx)

MySQL Server - MySqlDbType (https://dev.mysql.com/doc/dev/connector-net/8.0/html/T_MySql_Data_MySqlClient_MySqlDbType.htm)

Postgres - NpgsqlDbType (https://www.npgsql.org/doc/api/NpgsqlTypes.NpgsqlDbType.html)
`
Example of config for SQL server (examples of config could be found in ReportGenerator.Core.Tests/ExampleConfig)
```xml


StoredProcedure
GetSitizensByCityAndDateOfBirth


12
City
N'Yekaterinburg



8
PostalCode
620000



4
DateOfBirth
'2018-01-01'

```
For View Configuration is a little similar as DataSource we must note View:

View

Name is a name of View

But here we should also specify parameters for rows selection (WHERE, ORDER BY and GROUP BY parameters). All of them are represented with only one type - DbQueryParameter.

DbQueryParameter consist of following:

-collection of JoinCondition (works only for WHERE parameters) - is way of how parameters joined in WHERE statement by logical AND or logical OR, or maybe AND/OR with inversion - AND NOT Condition ... OR NOT Condition (see example below). Should be ommited for first parameter in WHERE statement.

-parameter Name make sense for every type of parameter (WHERE, ORDER BY and GROUP BY)

-comparison operator (make sense only for WHERE parameters) - is any valid SQL condition operator like >, <, =, IS, IS NOT, IN, BETWEEN, LIKE and so on...

-parameter value works for WHERE (value for comparison) and ORDER BY (ASC or DESC), THESE are DEFAULT values, they OF COURSE could be set during the runtime

Example:

```xml

View
CitizensView



FirstName
N'Michael'
=



And
Not

City
N'Yekaterinburg'
=



Between

Age
18 AND 60



In

District
(N'D1', N'A3', N'A5', N'C7')



Or

Region
N'Sverdlovskaya oblast'
!=




FirstName
ASC


LastName
DESC




District


```

## 2 Example of usage
Top interface is - IReportGeneratorManager.
For all functionality were written Unit tests with xUnit (sucks), full example could be found in unit test project (ReportGenerator.Core.Tests/ReportsGenerator/TestExcelReportGeneratorManager):

```csharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using ReportGenerator.Core.Database;
using ReportGenerator.Core.Database.Managers;
using ReportGenerator.Core.Database.Utils;
using ReportGenerator.Core.Helpers;
using ReportGenerator.Core.ReportsGenerator;
using Xunit;

namespace ReportGenerator.Core.Tests.ReportsGenerator
{
public class TestExcelReportGeneratorManager
{
[Fact]
public void TestGenerateReportSqlServer()
{
_testSqlServerDbName = TestSqlServerDatabasePattern + "_" + DateTime.Now.Millisecond.ToString();
SetUpSqlServerTestData();
// executing extraction ...
object[] parameters = ExcelReportGeneratorHelper.CreateParameters(1, 2, 3);
ILoggerFactory loggerFactory = new LoggerFactory();
IReportGeneratorManager manager = new ExcelReportGeneratorManager(loggerFactory, DbEngine.SqlServer,
TestSqlServerHost, _testSqlServerDbName);
Task result = manager.GenerateAsync(TestExcelTemplate, SqlServerDataExecutionConfig, ReportFile, parameters);
result.Wait();
Assert.True(result.Result > 0);
TearDownSqlServerTestData();
}

[Fact]
public void TestGenerateReportSqLite()
{
SetUpSqLiteTestData();
object[] parameters = ExcelReportGeneratorHelper.CreateParameters(1, 2, 3);
ILoggerFactory loggerFactory = new LoggerFactory();
loggerFactory.AddConsole();
loggerFactory.AddDebug();
IReportGeneratorManager manager = new ExcelReportGeneratorManager(loggerFactory, DbEngine.SqLite, _connectionString);
Task result = manager.GenerateAsync(TestExcelTemplate, SqLiteDataExecutionConfig, ReportFile, parameters);
result.Wait();
Assert.True(result.Result > 0);
TearDownSqLiteTestData();
}

[Fact]
public void TestGenerateReportPostgres()
{
SetUpPostgresSqlTestData();
object[] parameters = ExcelReportGeneratorHelper.CreateParameters(1, 2, 3);
ILoggerFactory loggerFactory = new LoggerFactory();
loggerFactory.AddConsole();
loggerFactory.AddDebug();
IReportGeneratorManager manager = new ExcelReportGeneratorManager(loggerFactory, DbEngine.PostgresSql, _connectionString);
Task result = manager.GenerateAsync(TestExcelTemplate, PostgresSqlViewDataExecutionConfig, ReportFile, parameters);
result.Wait();
Assert.True(result.Result > 0);
TearDownPostgresSqlTestData();
}

[Fact]
public void TestGenerateReportMySql()
{
SetUpMySqlTestData();
object[] parameters = ExcelReportGeneratorHelper.CreateParameters(1, 2, 3);
ILoggerFactory loggerFactory = new LoggerFactory();
loggerFactory.AddConsole();
loggerFactory.AddDebug();
IReportGeneratorManager manager = new ExcelReportGeneratorManager(loggerFactory, DbEngine.MySql, _connectionString);
Task result = manager.GenerateAsync(TestExcelTemplate, MySqlDataExecutionConfig, ReportFile, parameters);
result.Wait();
Assert.True(result.Result > 0);
TearDownMySqlTestData();
}

private void SetUpSqlServerTestData()
{
_dbManager = new CommonDbManager(DbEngine.SqlServer, _loggerFactory.CreateLogger());
IDictionary connectionStringParams = new Dictionary()
{
{DbParametersKeys.HostKey, TestSqlServerHost},
{DbParametersKeys.DatabaseKey, _testSqlServerDbName},
{DbParametersKeys.UseIntegratedSecurityKey, "true"},
{DbParametersKeys.UseTrustedConnectionKey, "true"}
};
_connectionString = ConnectionStringBuilder.Build(DbEngine.SqlServer, connectionStringParams);
_dbManager.CreateDatabase(_connectionString, true);
//
string createDatabaseStatement = File.ReadAllText(Path.GetFullPath(SqlServerCreateDatabaseScript));
string insertDataStatement = File.ReadAllText(Path.GetFullPath(SqlServerInsertDataScript));
_dbManager.ExecuteNonQueryAsync(_connectionString, createDatabaseStatement).Wait();
_dbManager.ExecuteNonQueryAsync(_connectionString, insertDataStatement).Wait();
}

private void TearDownSqlServerTestData()
{
_dbManager.DropDatabase(_connectionString);
}

private void SetUpSqLiteTestData()
{
_dbManager = new CommonDbManager(DbEngine.SqLite, _loggerFactory.CreateLogger());
IDictionary connectionStringParams = new Dictionary()
{
{DbParametersKeys.DatabaseKey, TestSqLiteDatabase},
{DbParametersKeys.DatabaseEngineVersion, "3"}
};
_connectionString = ConnectionStringBuilder.Build(DbEngine.SqLite, connectionStringParams);
_dbManager.CreateDatabase(_connectionString, true);
string createDatabaseStatement = File.ReadAllText(Path.GetFullPath(SqLiteCreateDatabaseScript));
string insertDataStatement = File.ReadAllText(Path.GetFullPath(SqLiteInsertDataScript));
_dbManager.ExecuteNonQueryAsync(_connectionString, createDatabaseStatement).Wait();
_dbManager.ExecuteNonQueryAsync(_connectionString, insertDataStatement).Wait();
}

private void TearDownSqLiteTestData()
{
_dbManager.DropDatabase(_connectionString);
}

private void SetUpMySqlTestData()
{
_dbManager = new CommonDbManager(DbEngine.MySql, _loggerFactory.CreateLogger());
IDictionary connectionStringParams = new Dictionary()
{
{DbParametersKeys.HostKey, TestMySqlHost},
{DbParametersKeys.DatabaseKey, TestMySqlDatabase},
// {DbParametersKeys.UseIntegratedSecurityKey, "true"} // is not working ...
{DbParametersKeys.LoginKey, "root"},
{DbParametersKeys.PasswordKey, "123"}
};
_connectionString = ConnectionStringBuilder.Build(DbEngine.MySql, connectionStringParams);
_dbManager.CreateDatabase(_connectionString, true);
string createDatabaseStatement = File.ReadAllText(Path.GetFullPath(MySqlCreateDatabaseScript));
string insertDataStatement = File.ReadAllText(Path.GetFullPath(MySqlInsertDataScript));
_dbManager.ExecuteNonQueryAsync(_connectionString, createDatabaseStatement).Wait();
_dbManager.ExecuteNonQueryAsync(_connectionString, insertDataStatement).Wait();
}

private void TearDownMySqlTestData()
{
_dbManager.DropDatabase(_connectionString);
}

private void SetUpPostgresSqlTestData()
{
_dbManager = new CommonDbManager(DbEngine.PostgresSql, _loggerFactory.CreateLogger());
IDictionary connectionStringParams = new Dictionary()
{
{DbParametersKeys.HostKey, TestPostgresSqlHost},
{DbParametersKeys.DatabaseKey, TestPostgresSqlDatabase},
// {DbParametersKeys.UseIntegratedSecurityKey, "true"} // is not working ...
{DbParametersKeys.LoginKey, "postgres"},
{DbParametersKeys.PasswordKey, "123"}
};
_connectionString = ConnectionStringBuilder.Build(DbEngine.PostgresSql, connectionStringParams);
_dbManager.CreateDatabase(_connectionString, true);
string createDatabaseStatement = File.ReadAllText(Path.GetFullPath(PostgresSqlCreateDatabaseScript));
string insertDataStatement = File.ReadAllText(Path.GetFullPath(PostgresSqlInsertDataScript));
_dbManager.ExecuteNonQueryAsync(_connectionString, createDatabaseStatement).Wait();
_dbManager.ExecuteNonQueryAsync(_connectionString, insertDataStatement).Wait();
}

private void TearDownPostgresSqlTestData()
{
_dbManager.DropDatabase(_connectionString);
}

private const string TestExcelTemplate = @"..\..\..\TestExcelTemplates\CitizensTemplate.xlsx";
private const string ReportFile = @".\Report.xlsx";
private const string SqlServerDataExecutionConfig = @"..\..\..\ExampleConfig\sqlServerDataExtractionParams.xml";
private const string SqLiteDataExecutionConfig = @"..\..\..\ExampleConfig\sqLiteDataExtractionParams.xml";
private const string MySqlDataExecutionConfig = @"..\..\..\ExampleConfig\mySql_testReport4_StoredProcedure.xml";
private const string PostgresSqlViewDataExecutionConfig = @"..\..\..\ExampleConfig\postgresViewDataExtractionParams.xml";
private const string PostgresSqlStoredProcedureDataExecutionConfig = @"..\..\..\ExampleConfig\postgresStoredProcDataExtractionParams.xml";

private const string TestSqlServerHost = @"(localdb)\mssqllocaldb";
private const string TestSqlServerDatabasePattern = "ReportGeneratorTestDb";
private const string TestSqLiteDatabase = "ReportGeneratorTestDb.sqlite";
private const string TestMySqlHost = "localhost";
private const string TestMySqlDatabase = "ReportGeneratorTestDb";
private const string TestPostgresSqlHost = "localhost";
private const string TestPostgresSqlDatabase = "ReportGeneratorTestDb";

private const string SqlServerCreateDatabaseScript = @"..\..\..\DbScripts\SqlServerCreateDb.sql";
private const string SqlServerInsertDataScript = @"..\..\..\DbScripts\SqlServerCreateData.sql";
private const string SqLiteCreateDatabaseScript = @"..\..\..\DbScripts\SqLiteCreateDb.sql";
private const string SqLiteInsertDataScript = @"..\..\..\DbScripts\SqLiteCreateData.sql";
private const string MySqlCreateDatabaseScript = @"..\..\..\DbScripts\MySqlCreateDb.sql";
private const string MySqlInsertDataScript = @"..\..\..\DbScripts\MySqlCreateData.sql";
private const string PostgresSqlCreateDatabaseScript = @"..\..\..\DbScripts\PostgresSqlCreateDb.sql";
private const string PostgresSqlInsertDataScript = @"..\..\..\DbScripts\PostgresSqlCreateData.sql";

private string _testSqlServerDbName;
private string _connectionString;
private readonly ILoggerFactory _loggerFactory = new LoggerFactory();
private IDbManager _dbManager;
}
}
`

## 3 Service for Dependency injection

Here is example of how to use ReportGenerator with dependency injection:
`csharp
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ReportGenerator.Core.Database;
using ReportGenerator.Core.Database.Managers;
using ReportGenerator.Core.Database.Utils;
using ReportGenerator.Core.Extensions;
using ReportGenerator.Core.ReportsGenerator;
using Xunit;

namespace ReportGenerator.Core.Tests.Extensions
{
public class ServiceCollectionExtensionsTests : IDisposable
{
public ServiceCollectionExtensionsTests()
{
_testDbName = TestDatabasePattern + "_" + DateTime.Now.ToString("YYYYMMDDHHmmss");
_dbManager = new CommonDbManager(DbEngine.SqlServer, _loggerFactory.CreateLogger());
IDictionary connectionStringParams = new Dictionary()
{
{DbParametersKeys.HostKey, Server},
{DbParametersKeys.DatabaseKey, _testDbName},
{DbParametersKeys.UseIntegratedSecurityKey, "true"},
{DbParametersKeys.UseTrustedConnectionKey, "true"}
};
_connectionString = ConnectionStringBuilder.Build(DbEngine.SqlServer, connectionStringParams);
_dbManager.CreateDatabase(_connectionString, true);
_services = new ServiceCollection();
_services.AddScoped(_ => new LoggerFactory());
_services.AddReportGenerator(DbEngine.SqlServer, _connectionString);
}

public void Dispose()
{
_dbManager.DropDatabase(_connectionString);
}

[Fact]
public void TestServiceInstantiationViaProvider()
{
IServiceProvider serviceProvider = _services.BuildServiceProvider();
IReportGeneratorManager reportGenerator = serviceProvider.GetService();

Assert.NotNull(reportGenerator);
}

private const string Server = @"(localdb)\mssqllocaldb";
private const string TestDatabasePattern = "ReportGeneratorTestDb";

private readonly IServiceCollection _services;
private readonly string _testDbName;
private readonly string _connectionString;
private IDbManager _dbManager;
private readonly ILoggerFactory _loggerFactory = new LoggerFactory();
}
}
```
## 4 GUI

A Full Web application (NET Core) with usage Report Generator as DI service will be implemented in this project:
https://github.com/Wissance/ReportGeneratorWebGui it is also allow to use Web API for ReportsGeneration

# 5 Nuget Package
Nuget package is available on nuget.org : https://www.nuget.org/packages/ReportsGenerator/
There are some strange troubles with import of version 1.1.0 and 1.1.1 they are **Broken and unlisted**. **ACTUAL NUGET PACKAGE IS 1.1.2**