Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using Microsoft.AspNetCore.Mvc;
using Quipu.ParameterizationExtractor.WebApi.Models;
using Quipu.ParameterizationExtractor.WebApi.Services;

namespace Quipu.ParameterizationExtractor.WebApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ExtractionController : ControllerBase
{
private readonly IExtractionService _extractionService;
private readonly ILogger<ExtractionController> _logger;

public ExtractionController(IExtractionService extractionService, ILogger<ExtractionController> logger)
{
_extractionService = extractionService;
_logger = logger;
}

/// <summary>
/// </summary>
[HttpPost("extract")]
public async Task<IActionResult> ExtractAsync([FromBody] ExtractionRequest request, CancellationToken cancellationToken = default)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}

_logger.LogInformation("Received extraction request for config type: {ConfigType}", request.ConfigType);

var result = await _extractionService.ProcessExtractionAsync(request, cancellationToken);

if (!result.Success)
{
return BadRequest(new { error = result.ErrorMessage });
}

return File(result.ZipFileContent!, "application/zip", result.FileName);
}

/// <summary>
/// </summary>
[HttpGet("health")]
public IActionResult Health()
{
return Ok(new { status = "healthy", timestamp = DateTime.UtcNow });
}

/// <summary>
/// </summary>
[HttpGet("formats")]
public IActionResult GetFormats()
{
var formats = new
{
supported_formats = new[] { "DSL", "JSON", "XML" },
examples = new
{
dsl = @"for script ""example"" take from ""Users"" where ""Active = 1"" consider FK for ""Users"" and UniqueColumns ""Id"" build sql with asIs",
json = new
{
scripts = new[]
{
new
{
scriptName = "example",
rootRecords = new[]
{
new { tableName = "Users", where = "Active = 1", processingOrder = 0 }
},
tablesToProcess = new[]
{
new
{
tableName = "Users",
uniqueColumns = new[] { "Id" },
extractStrategy = "FK",
sqlBuildOptions = new[] { "AsIsInserts" }
}
}
}
}
},
xml = @"<Package><Scripts><SourceForScript ScriptName=""example""><RootRecords><RecordsToExtract TableName=""Users"" Where=""Active = 1"" ProcessingOrder=""0"" /></RootRecords><TablesToProcess><TableToExtract TableName=""Users""><UniqueColumns><string>Id</string></UniqueColumns></TableToExtract></TablesToProcess></SourceForScript></Scripts></Package>"
}
};

return Ok(formats);
}
}
}
24 changes: 24 additions & 0 deletions ParameterizationExtractor.WebApi/Models/ApiAppArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Quipu.ParameterizationExtractor.Common;

namespace Quipu.ParameterizationExtractor.WebApi.Models
{
public class ApiAppArgs : IAppArgs
{
public string DBName { get; set; } = string.Empty;
public string ServerName { get; set; } = string.Empty;
public string PathToPackage { get; set; } = string.Empty;
public string ConnectionName { get; set; } = "DefaultConnection";
public string OutputFolder { get; set; } = string.Empty;
public bool Interactive { get; set; } = false;

public static ApiAppArgs Create(string outputFolder, string connectionName = "DefaultConnection")
{
return new ApiAppArgs
{
OutputFolder = outputFolder,
ConnectionName = connectionName,
Interactive = false
};
}
}
}
33 changes: 33 additions & 0 deletions ParameterizationExtractor.WebApi/Models/ExtractionRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.ComponentModel.DataAnnotations;

namespace Quipu.ParameterizationExtractor.WebApi.Models
{
public class ExtractionRequest
{
[Required]
public string ConnectionString { get; set; } = string.Empty;

[Required]
public string Configuration { get; set; } = string.Empty;

[Required]
public ConfigurationType ConfigType { get; set; }

public string? OutputFileName { get; set; }
}

public enum ConfigurationType
{
DSL,
JSON,
XML
}

public class ExtractionResponse
{
public bool Success { get; set; }
public string? ErrorMessage { get; set; }
public byte[]? ZipFileContent { get; set; }
public string? FileName { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Quipu.ParameterizationExtractor.WebApi</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ParameterizationExtractor.Common\ParameterizationExtractor.Common.csproj" />
<ProjectReference Include="..\ParameterizationExtractor.DSL.Connector\ParameterizationExtractor.DSL.Connector.csproj" />
<ProjectReference Include="..\ParameterizationExtractor.DSL\ParameterizationExtractor.DSL.fsproj" />
<ProjectReference Include="..\ParameterizationExtractor.Logic\ParameterizationExtractor.Logic.csproj" />
</ItemGroup>

</Project>
71 changes: 71 additions & 0 deletions ParameterizationExtractor.WebApi/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Microsoft.OpenApi.Models;
using Quipu.ParameterizationExtractor.WebApi.Services;
using Quipu.ParameterizationExtractor.WebApi.Models;
using Quipu.ParameterizationExtractor.Logic.Interfaces;
using Quipu.ParameterizationExtractor.Logic.MSSQL;
using Quipu.ParameterizationExtractor.DSL.Connector;
using Quipu.ParameterizationExtractor;
using Quipu.ParameterizationExtractor.Common;
using Quipu.ParameterizationExtractor.Configs;
using ParameterizationExtractor.Logic.MSSQL;
using Quipu.ParameterizationExtractor.Logic.Configs;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "ParameterizationExtractor API",
Version = "v1",
Description = "REST API for database extraction and SQL script generation"
});
});

builder.Services.AddScoped<IExtractionService, ExtractionService>();
builder.Services.AddScoped<IDSLConnector, FparsecConnector>();
builder.Services.AddScoped<PackageProcessor>();

builder.Services.AddScoped<IFileService, FileService>();
builder.Services.AddScoped<ICanSerializeConfigs, ConfigSerializer>();
builder.Services.AddTransient<ISqlBuilder, MSSqlBuilder>();
builder.Services.AddScoped<ISourceSchema, MSSQLSourceSchema>();
builder.Services.AddScoped<IObjectMetaDataProvider, ObjectMetaDataProvider>();
builder.Services.AddScoped<IUnitOfWorkFactory, UnitOfWorkFactory>();
builder.Services.AddTransient<IDependencyBuilder, DependencyBuilder>();
builder.Services.AddTransient<IMetaDataInitializer, MetaDataInitializer>();
builder.Services.AddScoped<IConnectionStringResolver, ConnectionStringResolver>();

builder.Services.AddScoped<IAppArgs>(provider => new ApiAppArgs());

builder.Services.AddSingleton<IExtractConfiguration>(provider =>
{
var dslConnector = provider.GetRequiredService<IDSLConnector>();
var configSerializer = new ConfigSerializer(dslConnector);
try
{
return configSerializer.GetGlobalConfig();
}
catch
{
return new GlobalExtractConfiguration();
}
});

builder.Services.AddLogging();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();
Loading