diff --git a/CHANGELOG.md b/CHANGELOG.md index 626cfa3..4e782bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Represents the **NuGet** versions. +## v2.3.15 +- *Fixed:* Updated `CoreEx` to version `3.8.0`. +- *Fixed:* Updated `OnRamp` to version `2.0.0` which necessitated internal change from `Newtonsoft.Json` (now deprecated) to `System.Text.Json`; additionally, the `DataParser` was refactored accordingly. + ## v2.3.14 - *Fixed:* All related package dependencies updated to latest. diff --git a/Common.targets b/Common.targets index 992fac6..aad69b9 100644 --- a/Common.targets +++ b/Common.targets @@ -1,6 +1,6 @@ - 2.3.14 + 2.3.15 preview Avanade Avanade diff --git a/src/DbEx.MySql/DbEx.MySql.csproj b/src/DbEx.MySql/DbEx.MySql.csproj index ae0cea3..dfe9a9d 100644 --- a/src/DbEx.MySql/DbEx.MySql.csproj +++ b/src/DbEx.MySql/DbEx.MySql.csproj @@ -39,7 +39,7 @@ - + diff --git a/src/DbEx.SqlServer/DbEx.SqlServer.csproj b/src/DbEx.SqlServer/DbEx.SqlServer.csproj index b7016d2..7084a7e 100644 --- a/src/DbEx.SqlServer/DbEx.SqlServer.csproj +++ b/src/DbEx.SqlServer/DbEx.SqlServer.csproj @@ -30,7 +30,7 @@ - + diff --git a/src/DbEx/Console/MigrationConsoleBase.cs b/src/DbEx/Console/MigrationConsoleBase.cs index 3684f24..d4bd033 100644 --- a/src/DbEx/Console/MigrationConsoleBase.cs +++ b/src/DbEx/Console/MigrationConsoleBase.cs @@ -27,6 +27,7 @@ namespace DbEx.Console /// The underlying command line parsing is provided by . public abstract class MigrationConsoleBase { + private static readonly string[] memberNames = ["args"]; private const string EntryAssemblyOnlyOptionName = "entry-assembly-only"; private const string AcceptPromptsOptionName = "accept-prompts"; private CommandArgument? _commandArg; @@ -62,7 +63,7 @@ public abstract class MigrationConsoleBase /// /// Gets the console (command line) options. /// - protected Dictionary ConsoleOptions { get; } = new(); + protected Dictionary ConsoleOptions { get; } = []; /// /// Indicates whether to bypass standard execution of , , and . @@ -161,7 +162,7 @@ public async Task RunAsync(string[] args, CancellationToken cancellationTok return vr; if (_additionalArgs.Values.Count > 0 && !(Args.MigrationCommand.HasFlag(MigrationCommand.CodeGen) || Args.MigrationCommand.HasFlag(MigrationCommand.Script) || Args.MigrationCommand.HasFlag(MigrationCommand.Execute))) - return new ValidationResult($"Additional arguments can only be specified when the command is '{nameof(MigrationCommand.CodeGen)}', '{nameof(MigrationCommand.Script)}' or '{nameof(MigrationCommand.Execute)}'.", new string[] { "args" }); + return new ValidationResult($"Additional arguments can only be specified when the command is '{nameof(MigrationCommand.CodeGen)}', '{nameof(MigrationCommand.Script)}' or '{nameof(MigrationCommand.Execute)}'.", memberNames); if (Args.MigrationCommand.HasFlag(MigrationCommand.CodeGen) || Args.MigrationCommand.HasFlag(MigrationCommand.Script)) { @@ -178,7 +179,7 @@ public async Task RunAsync(string[] args, CancellationToken cancellationTok if (string.IsNullOrEmpty(_additionalArgs.Values[i])) continue; - Args.ExecuteStatements ??= new List(); + Args.ExecuteStatements ??= []; Args.ExecuteStatements.Add(_additionalArgs.Values[i]!); } } @@ -404,7 +405,7 @@ public static void WriteStandardizedArgs(DatabaseMigrationBase migrator, Action< migrator.Args.Logger.LogInformation("{Content}", $"Command = {migrator.Args.MigrationCommand}"); migrator.Args.Logger.LogInformation("{Content}", $"Provider = {migrator.Provider}"); - migrator.Args.Logger.LogInformation("{Content}", $"SchemaOrder = {string.Join(", ", migrator.Args.SchemaOrder.ToArray())}"); + migrator.Args.Logger.LogInformation("{Content}", $"SchemaOrder = {string.Join(", ", [.. migrator.Args.SchemaOrder])}"); migrator.Args.Logger.LogInformation("{Content}", $"OutDir = {migrator.Args.OutputDirectory?.FullName}"); additional?.Invoke(migrator.Args.Logger); diff --git a/src/DbEx/Console/MigrationConsoleBaseT.cs b/src/DbEx/Console/MigrationConsoleBaseT.cs index 680fa0d..c0f39b2 100644 --- a/src/DbEx/Console/MigrationConsoleBaseT.cs +++ b/src/DbEx/Console/MigrationConsoleBaseT.cs @@ -55,7 +55,7 @@ public TSelf Assemblies(params Type[] types) list.Add(t.Assembly); } - Args.AddAssembly(list.ToArray()); + Args.AddAssembly([.. list]); return (TSelf)this; } diff --git a/src/DbEx/DatabaseExtensions.cs b/src/DbEx/DatabaseExtensions.cs index 82706f7..52c2d6d 100644 --- a/src/DbEx/DatabaseExtensions.cs +++ b/src/DbEx/DatabaseExtensions.cs @@ -42,7 +42,7 @@ public static async Task> SelectSchemaAsync(this IDatabase d var refDataPredicate = new Func(t => t.Columns.Any(c => c.Name == refDataCodeColumn && !c.IsPrimaryKey && c.DotNetType == "string") && t.Columns.Any(c => c.Name == refDataTextColumn && !c.IsPrimaryKey && c.DotNetType == "string")); // Get all the tables and their columns. - using var sr = DatabaseMigrationBase.GetRequiredResourcesStreamReader("SelectTableAndColumns.sql", new Assembly[] { typeof(DatabaseExtensions).Assembly }); + using var sr = DatabaseMigrationBase.GetRequiredResourcesStreamReader("SelectTableAndColumns.sql", [typeof(DatabaseExtensions).Assembly]); #if NET7_0_OR_GREATER await database.SqlStatement(await sr.ReadToEndAsync(cancellationToken).ConfigureAwait(false)).SelectQueryAsync(dr => #else @@ -84,7 +84,7 @@ public static async Task> SelectSchemaAsync(this IDatabase d } // Configure all the single column primary and unique constraints. - using var sr2 = DatabaseMigrationBase.GetRequiredResourcesStreamReader("SelectTablePrimaryKey.sql", new Assembly[] { typeof(DatabaseExtensions).Assembly }); + using var sr2 = DatabaseMigrationBase.GetRequiredResourcesStreamReader("SelectTablePrimaryKey.sql", [typeof(DatabaseExtensions).Assembly]); #if NET7_0_OR_GREATER var pks = await database.SqlStatement(await sr2.ReadToEndAsync(cancellationToken).ConfigureAwait(false)).SelectQueryAsync(dr => new #else diff --git a/src/DbEx/DbEx.csproj b/src/DbEx/DbEx.csproj index 7a48d90..b8897f5 100644 --- a/src/DbEx/DbEx.csproj +++ b/src/DbEx/DbEx.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/src/DbEx/DbSchema/DbTableSchema.cs b/src/DbEx/DbSchema/DbTableSchema.cs index 6ff3a04..b705fc4 100644 --- a/src/DbEx/DbSchema/DbTableSchema.cs +++ b/src/DbEx/DbSchema/DbTableSchema.cs @@ -176,17 +176,17 @@ public DbTableSchema(DbTableSchema table) /// /// Gets or sets the list. /// - public List Columns { get; private set; } = new List(); + public List Columns { get; private set; } = []; /// /// Gets the primary key list. /// - public List PrimaryKeyColumns => Columns?.Where(x => x.IsPrimaryKey).ToList() ?? new List(); + public List PrimaryKeyColumns => Columns?.Where(x => x.IsPrimaryKey).ToList() ?? []; /// /// Gets the standard list (i.e. not primary key, not created audit, not updated audit, not tenant-id, not row-version, not is-deleted). /// - public List StandardColumns => Columns?.Where(x => !x.IsPrimaryKey && !x.IsCreatedAudit && !x.IsUpdatedAudit && !x.IsTenantId && !x.IsRowVersion && !x.IsIsDeleted).ToList() ?? new List(); + public List StandardColumns => Columns?.Where(x => !x.IsPrimaryKey && !x.IsCreatedAudit && !x.IsUpdatedAudit && !x.IsTenantId && !x.IsRowVersion && !x.IsIsDeleted).ToList() ?? []; /// /// Gets the tenant idenfifier (if any). diff --git a/src/DbEx/Migration/Data/DataConfig.cs b/src/DbEx/Migration/Data/DataConfig.cs index 10f90c1..a6f82e5 100644 --- a/src/DbEx/Migration/Data/DataConfig.cs +++ b/src/DbEx/Migration/Data/DataConfig.cs @@ -1,25 +1,30 @@ // Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/DbEx +using System.Text.Json.Serialization; + namespace DbEx.Migration.Data { /// - /// Respresents the data configuration. + /// Represents the data configuration. /// public class DataConfig { /// /// Gets or sets the pre-condition SQL. /// + [JsonPropertyName("preConditionSql")] public string? PreConditionSql { get; set; } /// /// Gets or sets the pre-SQL. /// + [JsonPropertyName("preSql")] public string? PreSql { get; set; } /// /// Gets or sets the post-SQL. /// + [JsonPropertyName("postSql")] public string? PostSql { get; set; } } } \ No newline at end of file diff --git a/src/DbEx/Migration/Data/DataParser.cs b/src/DbEx/Migration/Data/DataParser.cs index 7eab3a8..8f8cf67 100644 --- a/src/DbEx/Migration/Data/DataParser.cs +++ b/src/DbEx/Migration/Data/DataParser.cs @@ -2,14 +2,15 @@ using DbEx.DbSchema; using HandlebarsDotNet; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; +using YamlDotNet.Core.Events; using YamlDotNet.Serialization; namespace DbEx.Migration.Data @@ -19,6 +20,36 @@ namespace DbEx.Migration.Data /// public class DataParser { + private class YamlNodeTypeResolver : INodeTypeResolver + { + private static readonly string[] boolValues = ["true", "false"]; + + /// + bool INodeTypeResolver.Resolve(NodeEvent? nodeEvent, ref Type currentType) + { + if (nodeEvent is Scalar scalar && scalar.Style == YamlDotNet.Core.ScalarStyle.Plain) + { + if (decimal.TryParse(scalar.Value, out _)) + { + if (scalar.Value.Length > 1 && scalar.Value.StartsWith('0')) // Valid JSON does not support a number that starts with a zero. + currentType = typeof(string); + else + currentType = typeof(decimal); + + return true; + } + + if (boolValues.Contains(scalar.Value)) + { + currentType = typeof(bool); + return true; + } + } + + return false; + } + } + /// /// Initializes a new instance of the class. /// @@ -79,9 +110,9 @@ public Task> ParseYamlAsync(Stream s, CancellationToken cancella /// The resulting list. public Task> ParseYamlAsync(TextReader tr, CancellationToken cancellationToken = default) { - var yaml = new DeserializerBuilder().Build().Deserialize(tr)!; + var yaml = new DeserializerBuilder().WithNodeTypeResolver(new YamlNodeTypeResolver()).Build().Deserialize(tr)!; var json = new SerializerBuilder().JsonCompatible().Build().Serialize(yaml); - return ParseJsonAsync(JObject.Parse(json), cancellationToken); + return ParseJsonAsync(json, cancellationToken); } /// @@ -104,8 +135,8 @@ public Task> ParseJsonAsync(string json, CancellationToken cance /// The resulting list. public Task> ParseJsonAsync(Stream s, CancellationToken cancellationToken = default) { - using var sr = new StreamReader(s); - return ParseJsonAsync(sr, cancellationToken); + using var jd = JsonDocument.Parse(s); + return ParseJsonAsync(jd, cancellationToken); } /// @@ -116,14 +147,14 @@ public Task> ParseJsonAsync(Stream s, CancellationToken cancella /// The resulting list. public Task> ParseJsonAsync(TextReader tr, CancellationToken cancellationToken = default) { - using var jr = new JsonTextReader(tr); - return ParseJsonAsync(JObject.Load(jr), cancellationToken); + using var jd = JsonDocument.Parse(tr.ReadToEnd()); + return ParseJsonAsync(jd, cancellationToken); } /// - /// Reads and parses the database using the specified . + /// Reads and parses the database using the specified . /// - private async Task> ParseJsonAsync(JObject json, CancellationToken cancellationToken) + private async Task> ParseJsonAsync(JsonDocument json, CancellationToken cancellationToken) { // Further update/manipulate the schema. if (Args.DbSchemaUpdaterAsync != null) @@ -134,19 +165,22 @@ private async Task> ParseJsonAsync(JObject json, CancellationTok DataConfig? dataConfig = null; // Loop through all the schemas. - foreach (var js in json.Children()) + foreach (var js in json.RootElement.EnumerateObject()) { // Check for data configuration as identified by the * schema - which is a special key notation. if (js.Name == "*") { - dataConfig = js.Children().FirstOrDefault()?.ToObject(); + if (js.Value.ValueKind != JsonValueKind.Object) + throw new DataParserException("Data configuration ('*' schema) is invalid; must be an object."); + + dataConfig = js.Value.Deserialize(); continue; } // Loop through the collection of tables. - foreach (var jto in GetChildObjects(js)) + foreach (var jto in js.Value.EnumerateArray()) { - foreach (var jt in jto.Children()) + foreach (var jt in jto.EnumerateObject()) { await ParseTableJsonAsync(tables, null, js.Name, jt, cancellationToken).ConfigureAwait(false); } @@ -168,10 +202,10 @@ private async Task> ParseJsonAsync(JObject json, CancellationTok /// /// Reads and parses the table data. /// - private async Task ParseTableJsonAsync(List tables, DataRow? parent, string schema, JProperty jt, CancellationToken cancellationToken) + private async Task ParseTableJsonAsync(List tables, DataRow? parent, string schema, JsonProperty jp, CancellationToken cancellationToken) { // Get existing or create new table. - var sdt = new DataTable(this, DatabaseSchemaConfig.SupportsSchema ? schema : string.Empty, jt.Name); + var sdt = new DataTable(this, DatabaseSchemaConfig.SupportsSchema ? schema : string.Empty, jp.Name); var prev = tables.SingleOrDefault(x => x.Schema == sdt.Schema && x.Name == sdt.Name); if (prev is null) tables.Add(sdt); @@ -179,30 +213,32 @@ private async Task ParseTableJsonAsync(List tables, DataRow? parent, sdt = prev; // Loop through the collection of rows. - foreach (var jro in GetChildObjects(jt)) + foreach (var jro in jp.Value.EnumerateArray()) { var row = new DataRow(sdt); - foreach (var jr in jro.Children()) + foreach (var jr in jro.EnumerateObject()) { - if (jr.Value.Type == JTokenType.Object) - { - throw new DataParserException($"Table '{sdt.Schema}.{sdt.Name}' has unsupported '{jr.Name}' column value; must not be an object: {jr.Value}."); - } - else if (jr.Value.Type == JTokenType.Array) - { - // Try parsing as a further described nested table configuration; i.e. representing a relationship. - await ParseTableJsonAsync(tables, row, sdt.Schema, jr, cancellationToken).ConfigureAwait(false); - } - else + switch (jr.Value.ValueKind) { - if (sdt.IsRefData && jro.Children().Count() == 1) - { - row.AddColumn(Args.RefDataCodeColumnName ?? DatabaseSchemaConfig.RefDataCodeColumnName, GetColumnValue(jr.Name)); - row.AddColumn(Args.RefDataTextColumnName ?? DatabaseSchemaConfig.RefDataTextColumnName, GetColumnValue(jr.Value)); - } - else - row.AddColumn(jr.Name, GetColumnValue(jr.Value)); + case JsonValueKind.Object: + throw new DataParserException($"Table '{sdt.Schema}.{sdt.Name}' has unsupported '{jr.Name}' column value; must not be an object: {jr.Value}."); + + case JsonValueKind.Array: + // Try parsing as a further described nested table configuration; i.e. representing a relationship. + await ParseTableJsonAsync(tables, row, sdt.Schema, jr, cancellationToken).ConfigureAwait(false); + break; + + default: + if (sdt.IsRefData && jro.EnumerateObject().Count() == 1) + { + row.AddColumn(Args.RefDataCodeColumnName ?? DatabaseSchemaConfig.RefDataCodeColumnName, jr.Name); + row.AddColumn(Args.RefDataTextColumnName ?? DatabaseSchemaConfig.RefDataTextColumnName, jr.Value.GetString()); + } + else + row.AddColumn(jr.Name, GetColumnValue(jr.Value)); + + break; } } @@ -220,38 +256,77 @@ private async Task ParseTableJsonAsync(List tables, DataRow? parent, sdt.AddRow(row); } + //// Loop through the collection of rows. + //foreach (var jro in GetChildObjects(jp)) + //{ + // var row = new DataRow(sdt); + + // foreach (var jr in jro.Children()) + // { + // if (jr.Value.Type == JTokenType.Object) + // { + // throw new DataParserException($"Table '{sdt.Schema}.{sdt.Name}' has unsupported '{jr.Name}' column value; must not be an object: {jr.Value}."); + // } + // else if (jr.Value.Type == JTokenType.Array) + // { + // // Try parsing as a further described nested table configuration; i.e. representing a relationship. + // await ParseTableJsonAsync(tables, row, sdt.Schema, jr, cancellationToken).ConfigureAwait(false); + // } + // else + // { + // if (sdt.IsRefData && jro.Children().Count() == 1) + // { + // row.AddColumn(Args.RefDataCodeColumnName ?? DatabaseSchemaConfig.RefDataCodeColumnName, GetColumnValue(jr.Name)); + // row.AddColumn(Args.RefDataTextColumnName ?? DatabaseSchemaConfig.RefDataTextColumnName, GetColumnValue(jr.Value)); + // } + // else + // row.AddColumn(jr.Name, GetColumnValue(jr.Value)); + // } + // } + + // // Where specified within a hierarchy attempt to be fancy and auto-update from the parent's primary key where same name. + // if (parent is not null) + // { + // foreach (var pktc in parent.Table.DbTable.PrimaryKeyColumns) + // { + // var pkc = parent.Columns.SingleOrDefault(x => x.Name == pktc.Name); + // if (pkc is not null && row.Table.DbTable.Columns.Any(x => x.Name == pktc.Name) && row.Columns.SingleOrDefault(x => x.Name == pktc.Name) is null) + // row.AddColumn(pkc.Name, pkc.Value); + // } + // } + + // sdt.AddRow(row); + //} + if (sdt.Columns.Count > 0) await sdt.PrepareAsync(cancellationToken).ConfigureAwait(false); } - /// - /// Gets the child objects. - /// - private static IEnumerable GetChildObjects(JToken j) - { - foreach (var jc in j.Children()) - { - return jc.Children(); - } + ///// + ///// Gets the child objects. + ///// + //private static IEnumerable GetChildObjects(JToken j) + //{ + // foreach (var jc in j.Children()) + // { + // return jc.Children(); + // } - return Array.Empty(); - } + // return Array.Empty(); + //} /// /// Gets the column value. /// - private object? GetColumnValue(JToken j) + private object? GetColumnValue(JsonElement j) { - return j.Type switch + return j.ValueKind switch { - JTokenType.Boolean => j.Value(), - JTokenType.Date => j.Value(), - JTokenType.Float => j.Value(), - JTokenType.Guid => j.Value(), - JTokenType.Integer => j.Value(), - JTokenType.TimeSpan => j.Value(), - JTokenType.Uri => j.Value(), - JTokenType.String => GetRuntimeParameterValue(j.Value()), + JsonValueKind.Null => null, + JsonValueKind.True => true, + JsonValueKind.False => false, + JsonValueKind.Number => j.GetDecimal(), + JsonValueKind.String => j.TryGetDateTime(out var dt) ? dt : GetRuntimeParameterValue(j.GetString()), _ => null }; } @@ -265,7 +340,7 @@ private static IEnumerable GetChildObjects(JToken j) return value; // Get runtime value when formatted like: ^(DateTime.UtcNow) - if (value.StartsWith("^(") && value.EndsWith(")")) + if (value.StartsWith("^(") && value.EndsWith(')')) { var key = value[2..^1]; @@ -340,7 +415,7 @@ private static (object? value, string? message) GetSystemPropertyValue(string pa var part = parts[0]; if (part.EndsWith("()")) { - var mi = type.GetMethod(part[0..^2], Array.Empty()); + var mi = type.GetMethod(part[0..^2], []); if (mi == null || mi.GetParameters().Length != 0) return (null, $"Runtime value parameter '{param}' is invalid; specified method '{part}' is invalid."); diff --git a/src/DbEx/Migration/Data/DataParserArgs.cs b/src/DbEx/Migration/Data/DataParserArgs.cs index 1d754bc..ee5235c 100644 --- a/src/DbEx/Migration/Data/DataParserArgs.cs +++ b/src/DbEx/Migration/Data/DataParserArgs.cs @@ -116,7 +116,7 @@ public class DataParserArgs /// Gets or sets the reference data column defaults dictionary. /// /// The list should contain the column name and function that returns the default value (the input to the function is the corresponding row count as specified). - public Dictionary> RefDataColumnDefaults { get; } = new Dictionary>(); + public Dictionary> RefDataColumnDefaults { get; } = []; /// /// Adds a reference data column default to the . @@ -134,7 +134,7 @@ public DataParserArgs RefDataColumnDefault(string column, Func @de /// Gets or sets the column defaults collection. /// /// The list should contain the column name and function that returns the default value (the input to the function is the corresponding row count as specified). - public DataParserColumnDefaultCollection ColumnDefaults { get; } = new DataParserColumnDefaultCollection(); + public DataParserColumnDefaultCollection ColumnDefaults { get; } = []; /// /// Adds a to the . @@ -153,7 +153,7 @@ public DataParserArgs ColumnDefault(string schema, string table, string column, /// /// Gets the runtime parameters. /// - public Dictionary Parameters { get; } = new Dictionary(); + public Dictionary Parameters { get; } = []; /// /// Adds a parameter to the where it does not already exist; unless is selected then it will add or override. @@ -179,7 +179,7 @@ public DataParserArgs Parameter(string key, object? value, bool overrideExisting /// /// Gets the . /// - public DataParserTableNameMappings TableNameMappings { get; } = new DataParserTableNameMappings(); + public DataParserTableNameMappings TableNameMappings { get; } = []; /// /// Copy and replace from . diff --git a/src/DbEx/Migration/Data/DataParserTableNameMappings.cs b/src/DbEx/Migration/Data/DataParserTableNameMappings.cs index 813147d..b8bcb4d 100644 --- a/src/DbEx/Migration/Data/DataParserTableNameMappings.cs +++ b/src/DbEx/Migration/Data/DataParserTableNameMappings.cs @@ -11,7 +11,7 @@ namespace DbEx.Migration.Data /// public class DataParserTableNameMappings : IEnumerable? ColumnMappings)>> { - private readonly Dictionary<(string, string), (string, string, Dictionary?)> _dict = new(); + private readonly Dictionary<(string, string), (string, string, Dictionary?)> _dict = []; /// /// Adds a schema, table and column(s) mapping. diff --git a/src/DbEx/Migration/Data/DataRow.cs b/src/DbEx/Migration/Data/DataRow.cs index 3704429..81b0f0f 100644 --- a/src/DbEx/Migration/Data/DataRow.cs +++ b/src/DbEx/Migration/Data/DataRow.cs @@ -25,7 +25,7 @@ public class DataRow /// /// Gets the columns. /// - public List Columns { get; } = new List(); + public List Columns { get; } = []; /// /// Gets the insert columns. diff --git a/src/DbEx/Migration/Data/DataTable.cs b/src/DbEx/Migration/Data/DataTable.cs index b30ef63..50d1bcb 100644 --- a/src/DbEx/Migration/Data/DataTable.cs +++ b/src/DbEx/Migration/Data/DataTable.cs @@ -114,7 +114,7 @@ internal DataTable(DataParser parser, string schema, string name) /// /// Gets the columns. /// - public List Columns { get; } = new List(); + public List Columns { get; } = []; /// /// Gets the insert columns. @@ -144,7 +144,7 @@ internal DataTable(DataParser parser, string schema, string name) /// /// Gets the rows. /// - public List Rows { get; } = new List(); + public List Rows { get; } = []; /// /// Gets the column name mappings (from the where specified). diff --git a/src/DbEx/Migration/DatabaseMigrationBase.cs b/src/DbEx/Migration/DatabaseMigrationBase.cs index 5e84d02..91dfb71 100644 --- a/src/DbEx/Migration/DatabaseMigrationBase.cs +++ b/src/DbEx/Migration/DatabaseMigrationBase.cs @@ -58,7 +58,7 @@ protected DatabaseMigrationBase(MigrationArgsBase args) Args.OutputDirectory ??= new DirectoryInfo(CodeGenConsole.GetBaseExeDirectory()); Journal = new DatabaseJournal(this); - SchemaObjectTypes = Array.Empty(); + SchemaObjectTypes = []; } /// @@ -173,7 +173,7 @@ public virtual async Task MigrateAsync(CancellationToken cancellationToken // Where only executing SQL statement, then execute and get out of here! if (Args.MigrationCommand.HasFlag(MigrationCommand.Execute)) - return await ExecuteSqlStatementsAsync(Args.ExecuteStatements?.ToArray() ?? Array.Empty(), cancellationToken).ConfigureAwait(false); + return await ExecuteSqlStatementsAsync(Args.ExecuteStatements?.ToArray() ?? [], cancellationToken).ConfigureAwait(false); /* The remaining commands are executed in sequence as defined (where selected) to enable multiple in the correct run order. */ @@ -829,7 +829,7 @@ private IEnumerable GetNamespacesWithSuffix(string suffix, bool reverse list.Add($"{ns}.{suffix}"); } - return list.Count == 0 ? new string[] { "(none)" } : list.ToArray(); + return list.Count == 0 ? new string[] { "(none)" } : [.. list]; } /// diff --git a/src/DbEx/Migration/MigrationArgsBase.cs b/src/DbEx/Migration/MigrationArgsBase.cs index 7f18cbd..9bc7f0c 100644 --- a/src/DbEx/Migration/MigrationArgsBase.cs +++ b/src/DbEx/Migration/MigrationArgsBase.cs @@ -43,7 +43,7 @@ public abstract class MigrationArgsBase : OnRamp.CodeGeneratorDbArgsBase /// /// Gets the list to use to probe for assembly resource (in defined sequence); will automatically add this (DbEx) assembly also (therefore no need to explicitly specify). /// - public List Assemblies { get; } = new List { typeof(MigrationArgs).Assembly }; + public List Assemblies { get; } = [typeof(MigrationArgs).Assembly]; /// /// Gets the reversed in order for probe-based sequencing. @@ -55,7 +55,7 @@ public abstract class MigrationArgsBase : OnRamp.CodeGeneratorDbArgsBase /// /// The following parameter names are reserved for a specific internal purpose: , and . /// and can support additional command-line arguments; these are automatically added as 'ParamN' where 'N' is the zero-based index; e.g. 'Param0'. - public Dictionary Parameters { get; } = new Dictionary(); + public Dictionary Parameters { get; } = []; /// /// Gets or sets the to optionally log the underlying database migration progress. @@ -70,7 +70,7 @@ public abstract class MigrationArgsBase : OnRamp.CodeGeneratorDbArgsBase /// /// Gets the schema priority list (used to specify schema precedence; otherwise equal last). /// - public List SchemaOrder { get; } = new List(); + public List SchemaOrder { get; } = []; /// /// Gets or sets the . @@ -170,7 +170,7 @@ protected void CopyFrom(MigrationArgsBase args) ExecuteStatements = null; else { - ExecuteStatements = new(); + ExecuteStatements = []; ExecuteStatements.AddRange(args.ExecuteStatements); } } diff --git a/src/DbEx/Migration/StringLogger.cs b/src/DbEx/Migration/StringLogger.cs index 2a6923c..afe8692 100644 --- a/src/DbEx/Migration/StringLogger.cs +++ b/src/DbEx/Migration/StringLogger.cs @@ -12,14 +12,10 @@ namespace DbEx.Migration internal class StringLogger : ILogger { private readonly StringBuilder _stringBuilder = new(); - private readonly IExternalScopeProvider _scopeProvider = new LoggerExternalScopeProvider(); + private readonly LoggerExternalScopeProvider _scopeProvider = new(); /// -#if NET7_0_OR_GREATER public IDisposable BeginScope(TState state) where TState : notnull => _scopeProvider.Push(state); -#else - public IDisposable BeginScope(TState state) => _scopeProvider.Push(state); -#endif /// public bool IsEnabled(LogLevel logLevel) => true; diff --git a/tests/DbEx.Test.OutboxConsole/Config/RootConfig.cs b/tests/DbEx.Test.OutboxConsole/Config/RootConfig.cs index f097820..06fb226 100644 --- a/tests/DbEx.Test.OutboxConsole/Config/RootConfig.cs +++ b/tests/DbEx.Test.OutboxConsole/Config/RootConfig.cs @@ -1,20 +1,20 @@ -using Newtonsoft.Json; -using OnRamp.Config; +using OnRamp.Config; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace DbEx.Test.OutboxConsole.Config { - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + [CodeGenClass("CodeGen")] public sealed class RootConfig : ConfigRootBase { - [JsonProperty("namespaceOutbox", DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonPropertyName("namespaceOutbox")] [CodeGenProperty("Namespace", Title = "The Namespace (root) for the Outbox-related .NET artefacts.")] public string? NamespaceOutbox { get; set; } /// /// Gets or sets the schema name of the event outbox table. /// - [JsonProperty("outboxSchema", DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonPropertyName("outboxSchema")] [CodeGenProperty("Outbox", Title = "The schema name of the event outbox table.", Description = "Defaults to `Outbox` (literal).")] public string? OutboxSchema { get; set; } @@ -22,7 +22,7 @@ public sealed class RootConfig : ConfigRootBase /// /// Gets or sets the name of the event outbox table. /// - [JsonProperty("outboxTable", DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonPropertyName("outboxTable")] [CodeGenProperty("Outbox", Title = "The name of the event outbox table.", Description = "Defaults to `EventOutbox` (literal).")] public string? OutboxTable { get; set; } @@ -30,7 +30,7 @@ public sealed class RootConfig : ConfigRootBase /// /// Gets or sets the stored procedure name for the event outbox enqueue. /// - [JsonProperty("outboxEnqueueStoredProcedure", DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonPropertyName("outboxEnqueueStoredProcedure")] [CodeGenProperty("Outbox", Title = "The stored procedure name for the event outbox enqueue.", Description = "Defaults to `spEventOutboxEnqueue` (literal).")] public string? OutboxEnqueueStoredProcedure { get; set; } @@ -38,7 +38,7 @@ public sealed class RootConfig : ConfigRootBase /// /// Gets or sets the stored procedure name for the event outbox dequeue. /// - [JsonProperty("outboxDequeueStoredProcedure", DefaultValueHandling = DefaultValueHandling.Ignore)] + [JsonPropertyName("outboxDequeueStoredProcedure")] [CodeGenProperty("Outbox", Title = "The stored procedure name for the event outbox dequeue.", Description = "Defaults to `spEventOutboxDequeue` (literal).")] public string? OutboxDequeueStoredProcedure { get; set; } diff --git a/tests/DbEx.Test/SqlServerMigrationTest.cs b/tests/DbEx.Test/SqlServerMigrationTest.cs index 7fdbb71..beed77a 100644 --- a/tests/DbEx.Test/SqlServerMigrationTest.cs +++ b/tests/DbEx.Test/SqlServerMigrationTest.cs @@ -64,10 +64,10 @@ public async Task A120_MigrateAll_With_Log_Output() var l = UnitTest.GetLogger(); var a = new MigrationArgs(MigrationCommand.DropAndAll, cs) { Logger = l }.AddAssembly(typeof(Error.TestError)); using var m = new SqlServerMigration(a); - var r = await m.MigrateAndLogAsync().ConfigureAwait(false); + var (Success, Output) = await m.MigrateAndLogAsync().ConfigureAwait(false); - Assert.IsFalse(r.Success); - Assert.IsTrue(r.Output.Length > 0); + Assert.IsFalse(Success); + Assert.IsTrue(Output.Length > 0); } [Test] @@ -254,7 +254,7 @@ public async Task B120_Execute_Console_Batch_Error() } [Test] - public async Task B120_Execute_Console_Batch_Success() + public async Task B130_Execute_Console_Batch_Success() { var c = await CreateConsoleDb().ConfigureAwait(false); var a = new MigrationArgs(MigrationCommand.Execute, c.cs) { Logger = c.l }.AddAssembly(typeof(Console.Program).Assembly);