Refactor services and configuration handling for improved clarity and performance

This commit is contained in:
Giuliano Paschoalino 2025-07-15 15:58:49 -03:00
parent 4bb348cb7f
commit d18b736e36
7 changed files with 34 additions and 41 deletions

8
Pipefy.code-workspace Normal file
View File

@ -0,0 +1,8 @@
{
"folders": [
{
"path": "."
}
],
"settings": {}
}

View File

@ -9,6 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@ -22,7 +22,7 @@ class Program
var serviceCollection = new ServiceCollection(); var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IConfigurationService, ConfigurationService>(); serviceCollection.AddSingleton<IConfigurationService, ConfigurationService>();
serviceCollection.AddSingleton<IPipefyApiService>(provider => { serviceCollection.AddSingleton<IPipefyApiService>(provider => {
var config = provider.GetRequiredService<IConfigurationService>().LoadAppSettings(); var config = provider.GetRequiredService<IConfigurationService>().GetAppSettings();
return new PipefyApiService(config.PIPEFY_API_URL, config.PIPEFY_API_TOKEN); return new PipefyApiService(config.PIPEFY_API_URL, config.PIPEFY_API_TOKEN);
}); });
serviceCollection.AddSingleton<IDatabaseService, DatabaseService>(); serviceCollection.AddSingleton<IDatabaseService, DatabaseService>();
@ -31,7 +31,7 @@ class Program
var serviceProvider = serviceCollection.BuildServiceProvider(); var serviceProvider = serviceCollection.BuildServiceProvider();
var configService = serviceProvider.GetRequiredService<IConfigurationService>(); var configService = serviceProvider.GetRequiredService<IConfigurationService>();
var AppSettings = configService.LoadAppSettings(); var AppSettings = configService.GetAppSettings();
if (AppSettings is null){ Environment.Exit(1); } if (AppSettings is null){ Environment.Exit(1); }
Console.Clear(); Console.Clear();
@ -53,6 +53,7 @@ class Program
List<ClasseEmpresas> databaseData = databaseService.GetDataFromDatabase(AppSettings.DB_PATH); List<ClasseEmpresas> databaseData = databaseService.GetDataFromDatabase(AppSettings.DB_PATH);
var businessLogic = serviceProvider.GetRequiredService<IBusinessLogicService>(); var businessLogic = serviceProvider.GetRequiredService<IBusinessLogicService>();
List<ClasseEmpresas> recordsMissingInJson = businessLogic.CompareData(databaseData, jsonList, jsonListGestores); List<ClasseEmpresas> recordsMissingInJson = businessLogic.CompareData(databaseData, jsonList, jsonListGestores);
recordsMissingInJson.AddRange(businessLogic.CompareData(jsonList, databaseData, jsonListGestores));
if (recordsMissingInJson.Count != 0 && recordsMissingInJson != null) if (recordsMissingInJson.Count != 0 && recordsMissingInJson != null)
{ {
await pipefyApi.CreateRecordsAsync(AppSettings.PIPEFY_TABLE_ID, recordsMissingInJson); await pipefyApi.CreateRecordsAsync(AppSettings.PIPEFY_TABLE_ID, recordsMissingInJson);

View File

@ -20,6 +20,7 @@ This document outlines a step-by-step plan to refactor the Pipefy project to com
- `Models/`: For data models (move from `data.cs`). - `Models/`: For data models (move from `data.cs`).
- `Mappers/`: For mapping logic between API/DB and domain models (optional, if mapping grows). - `Mappers/`: For mapping logic between API/DB and domain models (optional, if mapping grows).
- [ ] Integrate ORM (e.g., Entity Framework Core) to abstract DB access and ease future DB changes. (Next step) - [ ] Integrate ORM (e.g., Entity Framework Core) to abstract DB access and ease future DB changes. (Next step)
- Note: Current structure is well-separated; ORM will further improve OCP and testability.
- [x] Move or create files as needed for separation of concerns. - [x] Move or create files as needed for separation of concerns.
## 3. Single Responsibility Principle (SRP) ## 3. Single Responsibility Principle (SRP)
@ -29,17 +30,21 @@ This document outlines a step-by-step plan to refactor the Pipefy project to com
- [x] Extract data mapping logic into `IDataMapper` and `DataMapper`. - [x] Extract data mapping logic into `IDataMapper` and `DataMapper`.
- [x] Extract business logic (comparison, orchestration) into `IBusinessLogicService` and `BusinessLogicService`. - [x] Extract business logic (comparison, orchestration) into `IBusinessLogicService` and `BusinessLogicService`.
- [x] Remove static business/data methods from `Program.cs` and ensure all logic is in services. - [x] Remove static business/data methods from `Program.cs` and ensure all logic is in services.
- Note: All main responsibilities are separated. Consider splitting services further if logic grows (e.g., separate API read/write, config providers).
## 4. Open/Closed Principle (OCP) ## 4. Open/Closed Principle (OCP)
- [x] Define interfaces for each service (already done: IConfigurationService, IPipefyApiService, IDatabaseService, IDataMapper, IBusinessLogicService). - [x] Define interfaces for each service (already done: IConfigurationService, IPipefyApiService, IDatabaseService, IDataMapper, IBusinessLogicService).
- [x] Ensure new data sources or logic can be added by implementing new classes, not modifying existing ones (all main logic is now behind interfaces and DI). - [x] Ensure new data sources or logic can be added by implementing new classes, not modifying existing ones (all main logic is now behind interfaces and DI).
- Note: Future data sources or logic can be added via new classes.
## 5. Liskov Substitution Principle (LSP) ## 5. Liskov Substitution Principle (LSP)
- [ ] Ensure all service implementations can be replaced by their interfaces without breaking functionality. - [ ] Ensure all service implementations can be replaced by their interfaces without breaking functionality.
- Note: Add/expand unit tests to verify all service implementations can be swapped without breaking consumers. Ensure interfaces do not expose implementation-specific details.
## 6. Interface Segregation Principle (ISP) ## 6. Interface Segregation Principle (ISP)
- [ ] Keep interfaces focused and small. - [ ] Keep interfaces focused and small.
- [ ] Split large interfaces if needed. - [ ] Split large interfaces if needed.
- Note: Review interfaces for granularity. Split any that grow too large or have unrelated methods.
## 7. Dependency Inversion Principle (DIP) ## 7. Dependency Inversion Principle (DIP)
- [x] Refactor `Program.cs` to depend on abstractions (interfaces), not concrete classes. - [x] Refactor `Program.cs` to depend on abstractions (interfaces), not concrete classes.
@ -48,10 +53,12 @@ This document outlines a step-by-step plan to refactor the Pipefy project to com
## 8. Testing ## 8. Testing
- [ ] Add or update unit tests for each service. - [ ] Add or update unit tests for each service.
- [ ] Ensure business logic is testable in isolation. - [ ] Ensure business logic is testable in isolation.
- Note: Prioritize unit tests for business logic and service interfaces. Use mocks/fakes to test substitutability and isolation.
## 9. Documentation ## 9. Documentation
- [ ] Update this plan as you progress. - [ ] Update this plan as you progress.
- [ ] Document new structure and usage in a `README.md` or similar file. - [ ] Document new structure and usage in a `README.md` or similar file.
- Note: Document service responsibilities and interface contracts. Add XML comments to public APIs.
--- ---
@ -61,4 +68,4 @@ This document outlines a step-by-step plan to refactor the Pipefy project to com
--- ---
_Last updated: May 16, 2025_ _Last updated: May 19, 2025_

View File

@ -17,14 +17,5 @@ namespace Pipefy.Services
{ {
return _configuration.GetSection("AppSettings").Get<AppSettings>()!; return _configuration.GetSection("AppSettings").Get<AppSettings>()!;
} }
public AppSettings LoadAppSettings()
{
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false);
IConfiguration configuration = configurationBuilder.Build();
return configuration.GetSection("AppSettings").Get<AppSettings>()!;
}
} }
} }

View File

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.OleDb; using System.Data.OleDb;
using System.Text; using Dapper;
using Pipefy.Models; using Pipefy.Models;
namespace Pipefy.Services namespace Pipefy.Services
@ -10,38 +10,24 @@ namespace Pipefy.Services
public List<ClasseEmpresas> GetDataFromDatabase(string connSourcePath) public List<ClasseEmpresas> GetDataFromDatabase(string connSourcePath)
{ {
string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + connSourcePath + ";Jet OLEDB:Database Password=gds21;"; string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + connSourcePath + ";Jet OLEDB:Database Password=gds21;";
List<ClasseEmpresas> data = new List<ClasseEmpresas>();
using (OleDbConnection connection = new OleDbConnection(connectionString)) using (OleDbConnection connection = new OleDbConnection(connectionString))
{ {
connection.Open(); connection.Open();
StringBuilder sqlQuery = new StringBuilder(); string sqlQuery = @"SELECT cod_smart_cliente AS c_digo_smart,
sqlQuery.Append("SELECT cod_smart_cliente, \n"); cliente AS nome_da_empresa,
sqlQuery.Append(" cliente, \n"); modalidade,
sqlQuery.Append(" modalidade, \n"); gestao AS gestores
sqlQuery.Append(" gestao \n"); FROM dados_cadastrais
sqlQuery.Append("FROM dados_cadastrais \n"); WHERE cod_smart_unidade LIKE '%001'
sqlQuery.Append("WHERE cod_smart_unidade LIKE \"%001\" \n"); AND unidade_gerenciada;";
sqlQuery.Append(" AND unidade_gerenciada;"); var data = connection.Query<ClasseEmpresas>(sqlQuery).AsList();
using (OleDbCommand command = new OleDbCommand(sqlQuery.ToString(), connection)) // rec_id is not in the DB, set to empty string
foreach (var item in data)
{ {
using (OleDbDataReader reader = command.ExecuteReader()) item.rec_id = string.Empty;
{
while (reader.Read())
{
ClasseEmpresas record = new ClasseEmpresas
{
c_digo_smart = reader["Cod_Smart_cliente"].ToString(),
nome_da_empresa = reader["Cliente"].ToString(),
modalidade = reader["Modalidade"].ToString(),
gestores = reader["Gestao"].ToString(),
rec_id = ""
};
data.Add(record);
}
}
}
} }
return data; return data;
} }
} }
} }
}

View File

@ -5,6 +5,5 @@ namespace Pipefy.Services
public interface IConfigurationService public interface IConfigurationService
{ {
AppSettings GetAppSettings(); AppSettings GetAppSettings();
AppSettings LoadAppSettings();
} }
} }