Skip to content

Commit

Permalink
refactored config and upgrader
Browse files Browse the repository at this point in the history
  • Loading branch information
jweathers committed Jun 17, 2024
1 parent c646793 commit 5d16927
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 50 deletions.
147 changes: 104 additions & 43 deletions src/Config.cs
Original file line number Diff line number Diff line change
@@ -1,80 +1,141 @@
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using DbUp;
using DbUp.Builder;
using DbUp.Engine;
using DbUp.ScriptProviders;

namespace dbup.dotnet.tool;
public enum DatabaseProvider
{
sqlserver,
postgresql,
mysql,
sqlite
}
public enum TransactionConfiguration
{
Single,
PerScript,
None
}
public record class ScriptConfiguration
(
string Folder,
bool Recursive,
bool RunAlways,
string Filter,
bool MatchFullPath,
int Order = 100,
string Encoding = "utf-8"
)
{
}


public record class NamingConfiguration(
internal record class NamingConfiguration(
bool UseOnlyFileName,
bool IncludeBaseFolderName,
string Prefix
);
public record class JournalConfiguration(
internal record class JournalConfiguration(
string Schema,
string Table
);
public record class Configuration(
internal record class LogConfiguration(
LogTarget? LogTo,
bool? LogScriptOutput
);
internal record class Configuration(
DatabaseProvider Provider,
string ConnectionString,
TimeSpan ConnectionTimeout,
bool DisableVars,
TransactionConfiguration Transaction,
ScriptConfiguration[] Scripts,
ScriptConfiguration Script,
NamingConfiguration? Naming,
JournalConfiguration? JournalTo,
Dictionary<string,string>? Variables
){
public static Configuration CreateFromFile(FileInfo configFile)
Dictionary<string, string>? Variables,
bool DisableVars,
LogConfiguration? Log
)
{
internal static Configuration CreateFromFile(FileInfo configFile)
{
using var configReader = (configFile.Exists)?configFile.OpenText():throw new FileNotFoundException($"Could not find the config file at path: {configFile.FullName}");
using var configReader = (configFile.Exists) ? configFile.OpenText() : throw new FileNotFoundException($"Could not find the config file at path: {configFile.FullName}");
var ser = new YamlDotNet.Serialization.Deserializer();
return ser.Deserialize<Configuration>(configReader);
}
}

public static class DatabaseProviderExtensions
internal static class DatabaseProviderExtensions
{
public static bool TryValidateConnectionString(this DatabaseProvider provider, string connectionString)
internal static bool TryValidateConnectionString(this DatabaseProvider provider, string connectionString)
{
return false;
}
}

public static class ScriptConfigurationExtensions

internal static class ConfigurationExtensions
{
public static FileSystemScriptOptions AsFileSystemScriptOptions(this ScriptConfiguration scriptConfiguration)

internal static readonly Dictionary<DatabaseProvider,Func<string,UpgradeEngineBuilder>> databaseProviderFactory = new Dictionary<DatabaseProvider, Func<string,UpgradeEngineBuilder>>(){
{DatabaseProvider.mysql,(cnstr)=>DeployChanges.To.MySqlDatabase(cnstr)},
{DatabaseProvider.postgresql,(cnstr)=>DeployChanges.To.PostgresqlDatabase(cnstr)},
{DatabaseProvider.sqlserver,(cnstr)=>DeployChanges.To.SqlDatabase(cnstr)}
};

private static UpgradeEngineBuilder CreateBuilderFromProvider(this Configuration configuration, string connectionString)=>databaseProviderFactory[configuration.Provider](connectionString);
static readonly Dictionary<TransactionConfiguration, Action<UpgradeEngineBuilder>> transactionConfigActions = new Dictionary<TransactionConfiguration, Action<UpgradeEngineBuilder>>{
{TransactionConfiguration.None,e=>e.WithoutTransaction()},
{TransactionConfiguration.PerScript,e=>e.WithTransactionPerScript()},
{TransactionConfiguration.Single,e=>e.WithTransaction()}
};
internal static Configuration ConfigureTransactions(this Configuration configuration, UpgradeEngineBuilder upgradeEngineBuilder)
{
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(upgradeEngineBuilder);
transactionConfigActions[configuration.Transaction](upgradeEngineBuilder);
return configuration;
}

internal static Configuration ConfigureScripts(this Configuration configuration, UpgradeEngineBuilder upgradeEngineBuilder)
{
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(upgradeEngineBuilder);
upgradeEngineBuilder.WithScripts(configuration.Script.AsFileSystemScriptProvider());
return configuration;
}
internal static Configuration ConfigureVariables(this Configuration configuration, UpgradeEngineBuilder upgradeEngineBuilder)
{
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(upgradeEngineBuilder);
if ((configuration.Variables?.Count ?? 0) > 0)
{
upgradeEngineBuilder.WithVariables(configuration.Variables);
}
if (configuration.DisableVars)
{
upgradeEngineBuilder.WithVariablesDisabled();
}
else
{
upgradeEngineBuilder.WithVariablesEnabled();
}
return configuration;
}


static readonly Dictionary<LogTarget,Action<UpgradeEngineBuilder>> logConfigurationActions = new Dictionary<LogTarget, Action<UpgradeEngineBuilder>>(){
{LogTarget.Autodetect,b=>b.LogToAutodetectedLog()},
{LogTarget.Console,b=>b.LogToConsole()},
{LogTarget.Nowhere,b=>b.LogToNowhere()},
{LogTarget.Trace,b=>b.LogToTrace()}
};
internal static Configuration ConfigureLogging(this Configuration configuration, UpgradeEngineBuilder upgradeEngineBuilder)
{
return new FileSystemScriptOptions(){
Encoding=Encoding.GetEncoding(scriptConfiguration.Encoding),
Filter=scriptConfiguration.Filter,
IncludeSubDirectories=scriptConfiguration.Recursive,
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(upgradeEngineBuilder);
if(configuration.Log?.LogScriptOutput ?? false)
{
upgradeEngineBuilder.LogScriptOutput();
}
if(configuration.Log?.LogTo is not null)
{
logConfigurationActions[configuration.Log.LogTo.Value](upgradeEngineBuilder);
}
return configuration;
}

internal static UpgradeEngineBuilder CreateBuilder(this Configuration configuration, string connectionString)
{
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNullOrWhiteSpace(connectionString);
var builder = configuration.CreateBuilderFromProvider(connectionString);
configuration.ConfigureVariables(builder).ConfigureLogging(builder).ConfigureTransactions(builder).ConfigureScripts(builder);
return builder;
}
}

public enum LogTarget
{
Autodetect,
Nowhere,
Console,
Trace
}
9 changes: 9 additions & 0 deletions src/DatabaseProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace dbup.dotnet.tool;

public enum DatabaseProvider
{
sqlserver,
postgresql,
mysql,
sqlite
}
18 changes: 11 additions & 7 deletions src/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.CommandLine;
using DbUp;
using DbUp.Builder;
using DbUp.Engine;
using DbUp.ScriptProviders;
using Microsoft.VisualBasic;

Expand Down Expand Up @@ -29,18 +31,20 @@ static void Main(string[] args)
rootCommand.AddCommand(upgradeCommand);
rootCommand.Invoke(args);
}
static Task HandleUpgrade(string ConnectionString,FileInfo configFile)

static Task HandleUpgrade(string connectionString,FileInfo configFile)
{
ArgumentNullException.ThrowIfNullOrWhiteSpace(connectionString);
ArgumentNullException.ThrowIfNull(configFile);
var config = Configuration.CreateFromFile(configFile);
if(!config.Provider.TryValidateConnectionString(ConnectionString)) throw new Exception($"Invalid connection string for provider {config.Provider}");

var upgrader = new DbUp.Builder.UpgradeEngineBuilder();
var fileScriptOptions = new FileSystemScriptOptions();

var scriptProvider = new FileSystemScriptProvider(config.Scripts.First().Folder)

var upgrader = config.CreateBuilder(connectionString);
upgrader.Build().PerformUpgrade();
return Task.CompletedTask;
}



static Configuration LoadConfig(FileInfo configFile)
{
using var configReader = (configFile.Exists)?configFile.OpenText():throw new FileNotFoundException($"Could not find the config file at path: {configFile.FullName}");
Expand Down
73 changes: 73 additions & 0 deletions src/ScriptConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Text;
using System.Text.RegularExpressions;
using DbUp.Engine;
using DbUp.ScriptProviders;

namespace dbup.dotnet.tool;

internal record class ScriptConfiguration
(
string Path,
string[]? Extensions,
bool? IncludeSubDirectories,
string? Encoding,
string? Filter,
bool? UseOnlyFilenameForScriptName,
int? RunGroupOrder,
DbUp.Support.ScriptType? ScriptType
)
{
public static implicit operator FileSystemScriptProvider(ScriptConfiguration scriptConfiguration)=>scriptConfiguration?.AsFileSystemScriptProvider();
}


internal static class ScriptConfigurationExtensions
{
internal static FileSystemScriptProvider AsFileSystemScriptProvider(this ScriptConfiguration scriptConfiguration)
{
ArgumentNullException.ThrowIfNull(scriptConfiguration);
ArgumentNullException.ThrowIfNullOrWhiteSpace(scriptConfiguration.Path);
if(!Path.Exists(scriptConfiguration.Path)) throw new ArgumentOutOfRangeException(nameof(scriptConfiguration.Path), $"Path not found. {scriptConfiguration.Path}");

var options = new FileSystemScriptOptions();

if ((scriptConfiguration.Extensions?.Length ?? 0) > 0)
{
options.Extensions=new string[scriptConfiguration.Extensions.Length];
Array.Copy(scriptConfiguration.Extensions, options.Extensions, options.Extensions.Length);
}

if(!string.IsNullOrWhiteSpace(scriptConfiguration.Encoding))
{
options.Encoding= Encoding.GetEncoding(scriptConfiguration.Encoding);
}

if(!string.IsNullOrWhiteSpace(scriptConfiguration.Filter))
{
options.Filter=(v1)=>Regex.IsMatch(v1,scriptConfiguration.Filter);
}

if(scriptConfiguration.IncludeSubDirectories.HasValue)
{
options.IncludeSubDirectories=scriptConfiguration.IncludeSubDirectories.Value;
}

if(scriptConfiguration.UseOnlyFilenameForScriptName.HasValue)
{
options.UseOnlyFilenameForScriptName=scriptConfiguration.UseOnlyFilenameForScriptName.Value;
}

SqlScriptOptions? sqlScriptOptions=new SqlScriptOptions();
if(scriptConfiguration.RunGroupOrder.HasValue)
{
sqlScriptOptions.RunGroupOrder=scriptConfiguration.RunGroupOrder.Value;
}
if(scriptConfiguration.ScriptType.HasValue)
{
sqlScriptOptions.ScriptType=scriptConfiguration.ScriptType.Value;

}

return new FileSystemScriptProvider(scriptConfiguration.Path,options,sqlScriptOptions);
}
}
8 changes: 8 additions & 0 deletions src/TransactionConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace dbup.dotnet.tool;

public enum TransactionConfiguration
{
Single,
PerScript,
None
}

0 comments on commit 5d16927

Please sign in to comment.