diff --git a/src/DataMasker.Runner/Program.cs b/src/DataMasker.Runner/Program.cs index e253ec0..8cdd1ff 100644 --- a/src/DataMasker.Runner/Program.cs +++ b/src/DataMasker.Runner/Program.cs @@ -13,165 +13,181 @@ namespace DataMasker.Runner { - internal class Program - { - private static readonly Dictionary _progressBars = new Dictionary(); - - private static Options cliOptions; - - private static void Main( - string[] args) + internal class Program { + private static readonly Dictionary _progressBars = new Dictionary(); - Parser.Default.ParseArguments(args) - .WithParsed( - options => - { - cliOptions = options; - try - { - RuntimeArgumentHandle(); - } - catch (Exception ex) - { - WriteLine(ex.Message); - } - }); - } + private static Options cliOptions; - private static void InitProgressBars() - { - if (cliOptions.NoOutput) - { - return; - } - - _progressBars.Add( - ProgressType.Overall, - new ProgressbarUpdate { ProgressBar = new ProgressBar(PbStyle.SingleLine, 0), LastMessage = "Overall Progress" }); - - _progressBars.Add( - ProgressType.Updating, - new ProgressbarUpdate { ProgressBar = new ProgressBar(PbStyle.SingleLine, 0), LastMessage = "Update Progress" }); + private static void Main( + string[] args) + { - _progressBars.Add( - ProgressType.Masking, - new ProgressbarUpdate { ProgressBar = new ProgressBar(PbStyle.SingleLine, 0), LastMessage = "Masking Progress" }); - } + Parser.Default.ParseArguments(args) + .WithParsed( + options => + { + cliOptions = options; + try + { + RuntimeArgumentHandle(); + } + catch (Exception ex) + { + WriteLine(ex.Message); + } + }); + } + + private static void InitProgressBars() + { + if (cliOptions.NoOutput) + { + return; + } + + _progressBars.Add( + ProgressType.Overall, + new ProgressbarUpdate { ProgressBar = new ProgressBar(PbStyle.SingleLine, 0), LastMessage = "Overall Progress" }); + + _progressBars.Add( + ProgressType.Updating, + new ProgressbarUpdate { ProgressBar = new ProgressBar(PbStyle.SingleLine, 0), LastMessage = "Update Progress" }); + + _progressBars.Add( + ProgressType.Masking, + new ProgressbarUpdate { ProgressBar = new ProgressBar(PbStyle.SingleLine, 0), LastMessage = "Masking Progress" }); + } + + private static void UpdateProgress( + ProgressType progressType, + int current, + int? max = null, + string message = null) + { + if (cliOptions.NoOutput) + { + return; + } - private static void UpdateProgress( - ProgressType progressType, - int current, - int? max = null, - string message = null) - { - if (cliOptions.NoOutput) - { - return; - } + max = max ?? + _progressBars[progressType] + .ProgressBar.Max; - max = max ?? _progressBars[progressType] - .ProgressBar.Max; + .ProgressBar.Max = max.Value; - _progressBars[progressType] - .ProgressBar.Max = max.Value; + message = message ?? + _progressBars[progressType] + .LastMessage; - message = message ?? - _progressBars[progressType] - .LastMessage; + _progressBars[progressType] + .ProgressBar.Refresh(current, message); + } + private static void RuntimeArgumentHandle() + { + if (cliOptions.PrintOptions) + { + WriteLine(); + WriteLine(JsonConvert.SerializeObject(cliOptions, Formatting.Indented)); + WriteLine(); + return; + } + + InitProgressBars(); + Config config = Config.Load(cliOptions.ConfigFile); + if (cliOptions.DryRun != null) + { + config.DataSource.DryRun = cliOptions.DryRun.Value; + } + + if (!string.IsNullOrEmpty(cliOptions.Locale)) + { + config.DataGeneration.Locale = cliOptions.Locale; + } + + if (cliOptions.UpdateBatchSize != null) + { + config.DataSource.UpdateBatchSize = cliOptions.UpdateBatchSize; + } + + Execute(config); + } + + private static void WriteLine( + string message = null) + { + if (!cliOptions.NoOutput) + { + Console.WriteLine(message); + } + } + + private static void Execute( + Config config) + { + WriteLine("Masking Data"); + UpdateProgress(ProgressType.Overall, 0, config.Tables.Count, "Overall Progress"); - _progressBars[progressType] - .ProgressBar.Refresh(current, message); - } - private static void RuntimeArgumentHandle() - { - if (cliOptions.PrintOptions) - { - WriteLine(); - WriteLine(JsonConvert.SerializeObject(cliOptions, Formatting.Indented)); - WriteLine(); - return; - } - - InitProgressBars(); - Config config = Config.Load(cliOptions.ConfigFile); - if (cliOptions.DryRun != null) + var dataProviders = new List { - config.DataSource.DryRun = cliOptions.DryRun.Value; - } + new BogusDataProvider(config.DataGeneration), + new SqlDataProvider(new System.Data.SqlClient.SqlConnection(config.DataSource.GetConnectionString())) + }; - if (!string.IsNullOrEmpty(cliOptions.Locale)) - { - config.DataGeneration.Locale = cliOptions.Locale; - } + //create a data masker + IDataMasker dataMasker = new DataMasker(dataProviders); - if (cliOptions.UpdateBatchSize != null) - { - config.DataSource.UpdateBatchSize = cliOptions.UpdateBatchSize; - } + //grab our dataSource from the config, note: you could just ignore the config.DataSource.Type + //and initialize your own instance + IDataSource dataSource = DataSourceProvider.Provide(config.DataSource.Type, config.DataSource); - Execute(config); - } + for (int i = 0; i < config.Tables.Count; i++) + { + TableConfig tableConfig = config.Tables[i]; - private static void WriteLine( - string message = null) - { - if (!cliOptions.NoOutput) - { - Console.WriteLine(message); - } - } - private static void Execute( - Config config) - { - WriteLine("Masking Data"); - UpdateProgress(ProgressType.Overall, 0, config.Tables.Count, "Overall Progress"); + var rowCount = dataSource.GetCount(tableConfig); + UpdateProgress(ProgressType.Masking, 0, (int)rowCount, "Masking Progress"); + UpdateProgress(ProgressType.Updating, 0, (int)rowCount, "Update Progress"); - var dataProviders = new List - { - new BogusDataProvider(config.DataGeneration), - new SqlDataProvider(new System.Data.SqlClient.SqlConnection(config.DataSource.GetConnectionString())) - }; + IEnumerable> rows = dataSource.GetData(tableConfig); - //create a data masker - IDataMasker dataMasker = new DataMasker(dataProviders); + int rowIndex = 0; - //grab our dataSource from the config, note: you could just ignore the config.DataSource.Type - //and initialize your own instance - IDataSource dataSource = DataSourceProvider.Provide(config.DataSource.Type, config.DataSource); + var maskedRows = rows.Select(row => + { + rowIndex++; - for (int i = 0; i < config.Tables.Count; i++) - { - TableConfig tableConfig = config.Tables[i]; + //update per row, or see below, + //dataSource.UpdateRow(row, tableConfig); + UpdateProgress(ProgressType.Masking, rowIndex); + return dataMasker.Mask(row, tableConfig); + }); - var rowCount = dataSource.GetCount(tableConfig); - UpdateProgress(ProgressType.Masking, 0, (int)rowCount, "Masking Progress"); - UpdateProgress(ProgressType.Updating, 0, (int)rowCount, "Update Progress"); + //update all rows + dataSource.UpdateRows(maskedRows, rowCount, tableConfig, totalUpdated => UpdateProgress(ProgressType.Updating, totalUpdated)); + UpdateProgress(ProgressType.Overall, i + 1); + } - IEnumerable> rows = dataSource.GetData(tableConfig); + ISqlStatementDataSource sqlStatementDataSource = SqlStatementDataProvier.Provide(config.DataSource.Type, config.DataSource); - int rowIndex = 0; + for (int i = 0; i < config.SqlStatements.Count; i++) + { + SqlStatementConfig sqlStatementConfig = config.SqlStatements[i]; - var maskedRows = rows.Select(row => - { - rowIndex++; + //IDataMasker dataMasker = new DataMasker(dataProviders); - //update per row, or see below, - //dataSource.UpdateRow(row, tableConfig); - UpdateProgress(ProgressType.Masking, rowIndex); + var rowCount = config.SqlStatements.Count(); + UpdateProgress(ProgressType.Masking, 0, (int)rowCount, "Masking Progress"); + UpdateProgress(ProgressType.Updating, 0, (int)rowCount, "Update Progress"); + sqlStatementDataSource.Execute(sqlStatementConfig); - return dataMasker.Mask(row, tableConfig); - }); - //update all rows - dataSource.UpdateRows(maskedRows, rowCount, tableConfig, totalUpdated => UpdateProgress(ProgressType.Updating, totalUpdated)); - UpdateProgress(ProgressType.Overall, i + 1); - } + } - WriteLine("Done"); + WriteLine("Done"); + } } - } } diff --git a/src/DataMasker/DataMasker.cs b/src/DataMasker/DataMasker.cs index 633e5c2..627d3cc 100644 --- a/src/DataMasker/DataMasker.cs +++ b/src/DataMasker/DataMasker.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using Bogus.DataSets; +using DataMasker.DataSources; using DataMasker.Interfaces; using DataMasker.Models; @@ -38,13 +39,16 @@ public DataMasker( _dataProviders = dataProviders; } - /// - /// Masks the specified object with new data - /// - /// The object to mask - /// The table configuration. - /// - public IDictionary Mask( + + + + /// + /// Masks the specified object with new data + /// + /// The object to mask + /// The table configuration. + /// + public IDictionary Mask( IDictionary obj, TableConfig tableConfig) { diff --git a/src/DataMasker/DataSourceProvider.cs b/src/DataMasker/DataSourceProvider.cs index 9d2cf57..8282f44 100644 --- a/src/DataMasker/DataSourceProvider.cs +++ b/src/DataMasker/DataSourceProvider.cs @@ -25,5 +25,7 @@ public static IDataSource Provide( throw new ArgumentOutOfRangeException(nameof(dataSourceType), dataSourceType, null); } + + } } diff --git a/src/DataMasker/DataSources/SqlStatementDataSource.cs b/src/DataMasker/DataSources/SqlStatementDataSource.cs new file mode 100644 index 0000000..b20a16e --- /dev/null +++ b/src/DataMasker/DataSources/SqlStatementDataSource.cs @@ -0,0 +1,57 @@ +using System; +using Dapper; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using DataMasker.Interfaces; +using DataMasker.Models; +using DataMasker.Utils; + +namespace DataMasker.DataSources +{ + /// + /// SqlStatementDataSource + /// + /// + public class SqlStatementDataSource : ISqlStatementDataSource + { + private readonly DataSourceConfig _sourceConfig; + + private readonly string _connectionString; + + /// + /// Initializes a new instance of the class. + /// + /// + public SqlStatementDataSource( + DataSourceConfig sourceConfig) + { + _sourceConfig = sourceConfig; + _connectionString = sourceConfig.GetConnectionString(); + } + + + /// + /// Executes sql statement + /// + /// The statement configuration. + /// + public void Execute( + SqlStatementConfig sqlStatementConfig) + { + if (!_sourceConfig.DryRun) + { + using (SqlConnection connection = new SqlConnection(_connectionString)) + { + connection.Open(); + var statementToExecute = sqlStatementConfig.Statement; + connection.Execute(statementToExecute); + + } + } + } + + + } +} diff --git a/src/DataMasker/Interfaces/ISqlStatementDataSource.cs b/src/DataMasker/Interfaces/ISqlStatementDataSource.cs new file mode 100644 index 0000000..d663d78 --- /dev/null +++ b/src/DataMasker/Interfaces/ISqlStatementDataSource.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using DataMasker.Models; + +namespace DataMasker.Interfaces +{ + /// + /// ISqlStatementDataSource + /// + public interface ISqlStatementDataSource + { + /// + /// Gets the data. + /// + /// The statement configuration. + /// + void Execute(SqlStatementConfig sqlStatementConfig); + + } +} diff --git a/src/DataMasker/Models/Config.cs b/src/DataMasker/Models/Config.cs index 510c7c0..ba3c325 100644 --- a/src/DataMasker/Models/Config.cs +++ b/src/DataMasker/Models/Config.cs @@ -25,6 +25,9 @@ private Config() public IList Tables { get; set; } + + public IList SqlStatements { get; set; } + /// /// Gets or sets the generation configuration. /// diff --git a/src/DataMasker/Models/SqlStatementConfig.cs b/src/DataMasker/Models/SqlStatementConfig.cs new file mode 100644 index 0000000..df6a9a8 --- /dev/null +++ b/src/DataMasker/Models/SqlStatementConfig.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.ComponentModel; +using Newtonsoft.Json; + +namespace DataMasker.Models +{ + /// + /// TableConfig + /// + public class SqlStatementConfig + { + /// + /// The name of the sql statement + /// + /// + /// The name. + /// + [JsonRequired] + public string Name { get; set; } + + /// + /// The sql statement to be executed angainst db + /// + /// + /// The sql statement + /// + [JsonRequired] + public string Statement { get; set; } + + } +} diff --git a/src/DataMasker/SqlStatementDataProvier.cs b/src/DataMasker/SqlStatementDataProvier.cs new file mode 100644 index 0000000..91b31e6 --- /dev/null +++ b/src/DataMasker/SqlStatementDataProvier.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataMasker.DataSources; +using DataMasker.Interfaces; +using DataMasker.Models; + +namespace DataMasker +{ + public static class SqlStatementDataProvier + { + public static ISqlStatementDataSource Provide( + DataSourceType dataSourceType, DataSourceConfig dataSourceConfig = null) + { + switch (dataSourceType) + { + + case DataSourceType.SqlServer: + return new SqlStatementDataSource(dataSourceConfig); + + } + + throw new ArgumentOutOfRangeException(nameof(dataSourceType), dataSourceType, null); + } + + + } +}