Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.3.10 #44

Merged
merged 2 commits into from
Aug 29, 2023
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

Represents the **NuGet** versions.

## v2.3.10
- *Fixed:* `DbTableSchema`, `DbColumnSchema` and `DataParserArgs` now correctly support the full range of by-convention properties (e.g. `RowVersion`, `TenantId` and `IsDeleted`). Both the `SqlServerSchemaConfig` and `MySqlSchemaConfig` updated to default names as appropriate. Additional properties added to `Db*Schema` to support additional code-generation scenarios, etc.

## v2.3.9
- *Fixed:* The YAML-based `MigrationCommand.Data` logic previously set the `CreatedBy`, `CreatedDate`, `UpdatedBy` and `UpdatedDate` (or specified equivalent) regardless of whether the data was being inserted or merged (insert/update). This has been corrected such that the appropriate values are only set for the specific type of operation being performed; i.e. `Created*`-only or `Updated*`-only.
- *Fixed:* Enabled additional command-line arguments to be passed for `MigrationCommand.CodeGen` to enable inherited usage flexibility. Removed `MigrationArgsBase.ScriptName` and `MigrationArgsBase.ScriptArguments` and included within existing `MigrationArgsBase.Parameters` as singular dictionary of key/value pairs (simplification).
Expand Down
2 changes: 1 addition & 1 deletion Common.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>2.3.9</Version>
<Version>2.3.10</Version>
<LangVersion>preview</LangVersion>
<Authors>Avanade</Authors>
<Company>Avanade</Company>
Expand Down
18 changes: 18 additions & 0 deletions src/DbEx.MySql/MySqlSchemaConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ public MySqlSchemaConfig(string databaseName) : base(databaseName, false) { }
/// <remarks>Value is '<c>updated_by</c>'.</remarks>
public override string UpdatedByColumnName => "updated_by";

/// <inheritdoc/>
/// <remarks>Value is '<c>tenant_id</c>'.</remarks>
public override string TenantIdColumnName => "tenant_id";

/// <inheritdoc/>
/// <remarks>Value is '<c>row_version</c>'.</remarks>
public override string RowVersionColumnName => "row_version";

/// <inheritdoc/>
/// <remarks>Value is '<c>is_deleted</c>'.</remarks>
public override string IsDeletedColumnName => "is_deleted";

/// <inheritdoc/>
/// <remarks>Value is '<c>code</c>'.</remarks>
public override string RefDataCodeColumnName => "code";
Expand All @@ -68,10 +80,16 @@ public override void PrepareDataParserArgs(DataParserArgs dataParserArgs)
dataParserArgs.RefDataColumnDefaults.TryAdd("sort_order", i => i);
}

dataParserArgs.IdColumnNameSuffix ??= IdColumnNameSuffix;
dataParserArgs.CreatedByColumnName ??= CreatedByColumnName;
dataParserArgs.CreatedDateColumnName ??= CreatedDateColumnName;
dataParserArgs.UpdatedByColumnName ??= UpdatedByColumnName;
dataParserArgs.UpdatedDateColumnName ??= UpdatedDateColumnName;
dataParserArgs.TenantIdColumnName ??= TenantIdColumnName;
dataParserArgs.RowVersionColumnName ??= RowVersionColumnName;
dataParserArgs.IsDeletedColumnName ??= IsDeletedColumnName;
dataParserArgs.RefDataCodeColumnName ??= RefDataCodeColumnName;
dataParserArgs.RefDataTextColumnName ??= RefDataTextColumnName;
}

/// <inheritdoc/>
Expand Down
18 changes: 18 additions & 0 deletions src/DbEx.SqlServer/SqlServerSchemaConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ public SqlServerSchemaConfig(string databaseName) : base(databaseName) { }
/// <remarks>Value is '<c>UpdatedBy</c>'.</remarks>
public override string UpdatedByColumnName => "UpdatedBy";

/// <inheritdoc/>
/// <remarks>Value is '<c>TenantId</c>'.</remarks>
public override string TenantIdColumnName => "TenantId";

/// <inheritdoc/>
/// <remarks>Value is '<c>RowVersion</c>'.</remarks>
public override string RowVersionColumnName => "RowVersion";

/// <inheritdoc/>
/// <remarks>Value is '<c>IsDeleted</c>'.</remarks>
public override string IsDeletedColumnName => "IsDeleted";

/// <inheritdoc/>
/// <remarks>Value is '<c>Code</c>'.</remarks>
public override string RefDataCodeColumnName => "Code";
Expand All @@ -68,10 +80,16 @@ public override void PrepareDataParserArgs(DataParserArgs dataParserArgs)
dataParserArgs.RefDataColumnDefaults.TryAdd("SortOrder", i => i);
}

dataParserArgs.IdColumnNameSuffix ??= IdColumnNameSuffix;
dataParserArgs.CreatedByColumnName ??= CreatedByColumnName;
dataParserArgs.CreatedDateColumnName ??= CreatedDateColumnName;
dataParserArgs.UpdatedByColumnName ??= UpdatedByColumnName;
dataParserArgs.UpdatedDateColumnName ??= UpdatedDateColumnName;
dataParserArgs.TenantIdColumnName ??= TenantIdColumnName;
dataParserArgs.RowVersionColumnName ??= RowVersionColumnName;
dataParserArgs.IsDeletedColumnName ??= IsDeletedColumnName;
dataParserArgs.RefDataCodeColumnName ??= RefDataCodeColumnName;
dataParserArgs.RefDataTextColumnName ??= RefDataTextColumnName;
}

/// <inheritdoc/>
Expand Down
43 changes: 38 additions & 5 deletions src/DbEx/DatabaseExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using OnRamp.Utility;

namespace DbEx
{
Expand All @@ -31,9 +34,11 @@ public static async Task<List<DbTableSchema>> SelectSchemaAsync(this IDatabase d
var tables = new List<DbTableSchema>();
DbTableSchema? table = null;

var idColumnNameSuffix = dataParserArgs?.IdColumnNameSuffix ?? databaseSchemaConfig.IdColumnNameSuffix;
var refDataCodeColumn = dataParserArgs?.RefDataCodeColumnName ?? databaseSchemaConfig.RefDataCodeColumnName;
var refDataTextColumn = dataParserArgs?.RefDataTextColumnName ?? databaseSchemaConfig.RefDataTextColumnName;
dataParserArgs ??= new DataParserArgs();
databaseSchemaConfig.PrepareDataParserArgs(dataParserArgs);
var idColumnNameSuffix = dataParserArgs?.IdColumnNameSuffix!;
var refDataCodeColumn = dataParserArgs?.RefDataCodeColumnName!;
var refDataTextColumn = dataParserArgs?.RefDataTextColumnName!;
var refDataPredicate = new Func<DbTableSchema, bool>(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.
Expand All @@ -56,8 +61,11 @@ await database.SqlStatement(await sr.ReadToEndAsync().ConfigureAwait(false)).Sel
tables.Add(table = dt);

var dc = databaseSchemaConfig.CreateColumnFromInformationSchema(table, dr);
dc.IsCreatedAudit = dc.Name == (dataParserArgs?.CreatedByColumnName ?? databaseSchemaConfig.CreatedByColumnName) || dc.Name == (dataParserArgs?.CreatedDateColumnName ?? databaseSchemaConfig.CreatedDateColumnName);
dc.IsUpdatedAudit = dc.Name == (dataParserArgs?.UpdatedByColumnName ?? databaseSchemaConfig.UpdatedByColumnName) || dc.Name == (dataParserArgs?.UpdatedDateColumnName ?? databaseSchemaConfig.UpdatedDateColumnName);
dc.IsCreatedAudit = dc.Name == dataParserArgs?.CreatedByColumnName || dc.Name == dataParserArgs?.CreatedDateColumnName;
dc.IsUpdatedAudit = dc.Name == dataParserArgs?.UpdatedByColumnName || dc.Name == dataParserArgs?.UpdatedDateColumnName;
dc.IsTenantId = dc.Name == dataParserArgs?.TenantIdColumnName;
dc.IsRowVersion = dc.Name == dataParserArgs?.RowVersionColumnName;
dc.IsIsDeleted = dc.Name == dataParserArgs?.IsDeletedColumnName;

table.Columns.Add(dc);
return 0;
Expand Down Expand Up @@ -153,6 +161,31 @@ from c in t.Columns
}
}

// Attempt to infer if a reference data column where not explicitly specified.
var sb = new StringBuilder();

foreach (var t in tables)
{
foreach (var c in t.Columns.Where(x => !x.IsPrimaryKey))
{
if (c.IsForeignRefData)
{
c.IsRefData = true;
continue;
}

sb.Clear();
c.Name.Split(new char[] { '_', '-' }, StringSplitOptions.RemoveEmptyEntries).ForEach(part => sb.Append(StringConverter.ToPascalCase(part)));
var words = Regex.Split(sb.ToString(), DbTableSchema.WordSplitPattern).Where(x => !string.IsNullOrEmpty(x));
if (words.Count() > 1 && new string[] { "Id", "Code" }.Contains(words.Last(), StringComparer.InvariantCultureIgnoreCase))
{
var name = string.Join(string.Empty, words.Take(words.Count() - 1));
if (tables.Any(x => x.Name == name && x.Schema == t.Schema && x.IsRefData))
c.IsRefData = true;
}
}
}

return tables;
}
}
Expand Down
19 changes: 15 additions & 4 deletions src/DbEx/DatabaseSchemaConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,33 @@ protected DatabaseSchemaConfig(string databaseName, bool supportsSchema = true)
/// <summary>
/// Gets the name of the <see cref="IChangeLogAudit.CreatedDate"/> column (where it exists).
/// </summary>
/// <remarks>Defaults to '<c>CreatedDate</c>'.</remarks>
public abstract string CreatedDateColumnName { get; }

/// <summary>
/// Gets the name of the <see cref="IChangeLogAudit.CreatedBy"/> column (where it exists).
/// </summary>
/// <remarks>Defaults to '<c>CreatedBy</c>'.</remarks>
public abstract string CreatedByColumnName { get; }

/// <summary>
/// Gets the name of the <see cref="IChangeLogAudit.UpdatedDate"/> column (where it exists).
/// </summary>
/// <remarks>Defaults to '<c>UpdatedDate</c>'.</remarks>
public abstract string UpdatedDateColumnName { get; }

/// <summary>
/// Gets the name of the <see cref="IChangeLogAudit.UpdatedBy"/> column (where it exists).
/// </summary>
/// <remarks>Defaults to '<c>UpdatedBy</c>'.</remarks>
public abstract string UpdatedByColumnName { get; }

/// <summary>
/// Gets the name of the <see cref="ITenantId.TenantId"/> column (where it exists).
/// </summary>
public abstract string TenantIdColumnName { get; }

/// <summary>
/// Gets the name of the row-version (<see cref="IETag.ETag"/> equivalent) column (where it exists).
/// </summary>
public abstract string RowVersionColumnName { get; }

/// <summary>
/// Gets the default <see cref="IReferenceData.Code"/> column.
/// </summary>
Expand All @@ -75,6 +81,11 @@ protected DatabaseSchemaConfig(string databaseName, bool supportsSchema = true)
/// </summary>
public abstract string RefDataTextColumnName { get; }

/// <summary>
/// Gets the default <see cref="ILogicallyDeleted.IsDeleted"/> column.
/// </summary>
public abstract string IsDeletedColumnName { get; }

/// <summary>
/// Gets the default reference data predicate to determine <see cref="DbTableSchema.IsRefData"/>.
/// </summary>
Expand Down
51 changes: 41 additions & 10 deletions src/DbEx/DbSchema/DbColumnSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class DbColumnSchema
{
private string? _dotNetType;
private string? _dotNetName;
private string? _dotNetCleanedName;
private string? _sqlType;

/// <summary>
Expand Down Expand Up @@ -53,6 +54,11 @@ public DbColumnSchema(DbTableSchema dbTable, string name, string type)
/// </summary>
public ulong? Length { get; set; }

/// <summary>
/// Indicates whether the column has a length greater than zero.
/// </summary>
public bool HasLength => Length != null && Length > 0;

/// <summary>
/// Gets or sets the precision.
/// </summary>
Expand Down Expand Up @@ -119,7 +125,12 @@ public DbColumnSchema(DbTableSchema dbTable, string name, string type)
public string? ForeignColumn { get; set; }

/// <summary>
/// Indicates whether the foreign key is references a reference data table/entity.
/// Indicates whether the column <see cref="IsForeignRefData"/> or the name (after removing '<c>Id</c>' or '<c>Code</c>') matches a reference data table/entity in the same schema (where applicable).
/// </summary>
public bool IsRefData { get; set; }

/// <summary>
/// Indicates whether the foreign key is referencing a reference data table/entity.
/// </summary>
public bool IsForeignRefData { get; set; }

Expand All @@ -138,6 +149,26 @@ public DbColumnSchema(DbTableSchema dbTable, string name, string type)
/// </summary>
public bool IsUpdatedAudit { get; set; }

/// <summary>
/// Indicates whether the column is a row-version column; i.e. name is <c>RowVersion</c>.
/// </summary>
public bool IsRowVersion { get; set; }

/// <summary>
/// Indicates whether the column is a tenant identifier column; i.e. name is <c>TenantId</c>.
/// </summary>
public bool IsTenantId { get; set; }

/// <summary>
/// Indicates whether the column is an is-deleted column; i.e. name is <c>IsDeleted</c>.
/// </summary>
public bool IsIsDeleted { get; set; }

/// <summary>
/// Indicates whether the column <i>may</i> contain JSON content by convention (<see cref="DotNetType"/> is a `<c>string</c>` and the <see cref="Name"/> ends with `<c>Json</c>`) .
/// </summary>
public bool IsJsonContent => DotNetType == "string" && Name.EndsWith("Json", StringComparison.OrdinalIgnoreCase);

/// <summary>
/// Gets the corresponding .NET <see cref="System.Type"/> name.
/// </summary>
Expand All @@ -149,19 +180,14 @@ public DbColumnSchema(DbTableSchema dbTable, string name, string type)
public string DotNetName => _dotNetName ??= DbTableSchema.CreateDotNetName(Name);

/// <summary>
/// Gets the fully defined SQL type.
/// Gets the corresponding .NET name cleaned; by removing any known suffixes where <see cref="IsRefData"/> or <see cref="IsJsonContent"/>
/// </summary>
public string SqlType => _sqlType ??= DbTable?.Config.ToFormattedSqlType(this) ?? throw new InvalidOperationException($"The {nameof(DbTable)} must be set before the {nameof(SqlType)} property can be accessed.");
public string DotNetCleanedName => _dotNetCleanedName ??= DbTableSchema.CreateDotNetName(Name, IsRefData || IsJsonContent);

/// <summary>
/// Prepares the schema by updating the calculated properties: <see cref="DotNetType"/>, <see cref="DotNetName"/> and <see cref="SqlType"/>.
/// Gets the fully defined SQL type.
/// </summary>
public void Prepare()
{
_dotNetType = DbTable.Config.ToDotNetTypeName(this);
_dotNetName = DbTableSchema.CreateDotNetName(Name);
_sqlType = DbTable.Config.ToFormattedSqlType(this);
}
public string SqlType => _sqlType ??= DbTable?.Config.ToFormattedSqlType(this) ?? throw new InvalidOperationException($"The {nameof(DbTable)} must be set before the {nameof(SqlType)} property can be accessed.");

/// <summary>
/// Clones the <see cref="DbColumnSchema"/> creating a new instance.
Expand Down Expand Up @@ -195,11 +221,16 @@ public void CopyFrom(DbColumnSchema column)
ForeignSchema = column.ForeignSchema;
ForeignColumn = column.ForeignColumn;
IsForeignRefData = column.IsForeignRefData;
IsRefData = column.IsRefData;
ForeignRefDataCodeColumn = column.ForeignRefDataCodeColumn;
IsCreatedAudit = column.IsCreatedAudit;
IsUpdatedAudit = column.IsUpdatedAudit;
IsRowVersion = column.IsRowVersion;
IsTenantId = column.IsTenantId;
IsIsDeleted = column.IsIsDeleted;
_dotNetType = column._dotNetType;
_dotNetName = column._dotNetName;
_dotNetCleanedName = column._dotNetCleanedName;
_sqlType = column._sqlType;
}
}
Expand Down
Loading
Loading