Skip to content

Commit

Permalink
sp_rename columns
Browse files Browse the repository at this point in the history
  • Loading branch information
AMagistroni committed Oct 5, 2021
1 parent f22f876 commit 362c280
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 26 deletions.
11 changes: 6 additions & 5 deletions SqlSchemaCompare.Core/Common/TSqlResultProcessDbObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ public class OperationOnDbObject
{
public DbObject DbObject { get; init; }
public Operation Operation { get; init; }
public string Parameter { get; init; }
}
public List<OperationOnDbObject> OperationsOnDbObject { get; private set; } = new();
public void AddOperation<T>(DbObject dbObjects, Operation operation) where T : DbObject
public List<OperationOnDbObject> OperationsOnDbObject { get; } = new();
public void AddOperation<T>(DbObject dbObjects, Operation operation, string parameter = null) where T : DbObject
{
OperationsOnDbObject.Add(new OperationOnDbObject { DbObject = dbObjects, Operation = operation } );
OperationsOnDbObject.Add(new OperationOnDbObject { DbObject = dbObjects, Operation = operation, Parameter = parameter } );
}
public void AddOperation<T>(IList<T> dbObjects, Operation operation) where T : DbObject
{
dbObjects.ToList().ForEach(x => AddOperation<T>(x, operation));
}
}

public IEnumerable<DbObject> GetDbObject(DbObjectType dbObjectType, Operation operation)
{
return OperationsOnDbObject.Where(x => x.DbObject.DbObjectType == dbObjectType && x.Operation == operation).Select(x => x.DbObject);
Expand Down
3 changes: 3 additions & 0 deletions SqlSchemaCompare.Core/DbStructures/DbObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public abstract class DbObject
public abstract DbObjectType DbObjectType { get; }
public string Schema { get; init; }
public string Name { get; init; }
public string NameCaseInsensitive => Name.ToLower();
public string Sql { get; set; }
public string ParentName { get; init; }

Expand Down Expand Up @@ -47,5 +48,7 @@ public string Identifier
return string.IsNullOrEmpty(Schema) ? Name : $"{Schema}.{Name}";
}
}

public string IdentifierCaseInsensitive => Identifier.ToLower();
}
}
3 changes: 2 additions & 1 deletion SqlSchemaCompare.Core/DbStructures/Operation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public enum Operation
Alter,
Drop,
Enabled,
Disabled
Disabled,
Rename
}
}
20 changes: 20 additions & 0 deletions SqlSchemaCompare.Core/TSql/CaseInsensitiveComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using SqlSchemaCompare.Core.DbStructures;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace SqlSchemaCompare.Core.TSql
{
public class CaseInsensitiveComparer : IEqualityComparer<DbObject>
{
public bool Equals(DbObject x, DbObject y)
{
return string.Equals(x.Sql, y.Sql, StringComparison.OrdinalIgnoreCase);
}

public int GetHashCode([DisallowNull] DbObject obj)
{
return obj.GetHashCode();
}
}
}
14 changes: 12 additions & 2 deletions SqlSchemaCompare.Core/TSql/TSqlSchemaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public string Build(DbObject dbObject, Operation operation, ResultProcessDbObjec
DbObjectType.TableDefaultContraint => BuildTableConstraint(dbObject as TableConstraint, operation, resultProcessDbObject),
DbObjectType.TablePrimaryKeyContraint => BuildTableConstraint(dbObject as TableConstraint, operation, resultProcessDbObject),
DbObjectType.TableForeignKeyContraint => BuildTableConstraint(dbObject as TableConstraint, operation, resultProcessDbObject),
DbObjectType.Column => BuildColumn(dbObject as Table.Column, operation),
DbObjectType.Column => BuildColumn(dbObject as Table.Column, operation, resultProcessDbObject),
DbObjectType.View => BuildView(dbObject as View, operation),
DbObjectType.StoreProcedure => BuildGenericDbObjects("PROCEDURE", dbObject as StoreProcedure, operation),
DbObjectType.Function => BuildGenericDbObjects("FUNCTION", dbObject as Function, operation),
Expand Down Expand Up @@ -97,7 +97,7 @@ private string BuildMember(Member member, Operation operation)
};
}

private string BuildColumn(Table.Column column, Operation operation)
private string BuildColumn(Table.Column column, Operation operation, ResultProcessDbObject resultProcessDbObject)
{
switch (operation)
{
Expand All @@ -113,11 +113,21 @@ private string BuildColumn(Table.Column column, Operation operation)
return $"ALTER TABLE {column.ParentName} ALTER COLUMN {column.Sql}";
case Operation.Drop:
return $"ALTER TABLE {column.ParentName} DROP COLUMN {column.Name}";
case Operation.Rename:
var dbObject = resultProcessDbObject.OperationsOnDbObject.Single(x => x.Operation == Operation.Rename && x.DbObject.ParentName == column.ParentName);
return $"sp_rename '{column.ParentName}.{dbObject.Parameter}', '{GetStringWithoutBracket(column.Name)}', 'COLUMN'";
default:
throw new NotSupportedException("Alter not supported on schema");
}
}

private string GetStringWithoutBracket(string value)
{
value = value.StartsWith('[') ? value[1..] : value;
value = value.EndsWith(']') ? value[0..^1] : value;
return value;
}

private string BuildUser(User user, Operation operation)
{
switch (operation)
Expand Down
39 changes: 21 additions & 18 deletions SqlSchemaCompare.Core/UpdateSchemaManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using SqlSchemaCompare.Core.Common;
using SqlSchemaCompare.Core.DbStructures;
using SqlSchemaCompare.Core.TSql;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -34,6 +35,7 @@ public UpdateSchemaManager(ISchemaBuilder schemaBuilder)
(DbObjectType.TableForeignKeyContraint, Operation.Drop),
(DbObjectType.TablePrimaryKeyContraint, Operation.Drop),
(DbObjectType.Index, Operation.Drop),
(DbObjectType.Column, Operation.Rename),
(DbObjectType.Column, Operation.Create),
(DbObjectType.Column, Operation.Drop),
(DbObjectType.Column, Operation.Alter),
Expand Down Expand Up @@ -98,15 +100,7 @@ public string UpdateSchema(IEnumerable<DbObject> sourceObjects, IEnumerable<DbOb
{
if (selectedObjectType.Contains(objectToWrite.DbObjectType))
{
var dbObjects = objectToWrite.Operation switch
{
Operation.Alter => resultProcessDbObject.GetDbObject(objectToWrite.DbObjectType, Operation.Alter),
Operation.Create => resultProcessDbObject.GetDbObject(objectToWrite.DbObjectType, Operation.Create),
Operation.Disabled => resultProcessDbObject.GetDbObject(objectToWrite.DbObjectType, Operation.Disabled),
Operation.Enabled => resultProcessDbObject.GetDbObject(objectToWrite.DbObjectType, Operation.Enabled),
Operation.Drop => resultProcessDbObject.GetDbObject(objectToWrite.DbObjectType, Operation.Drop),
_ => throw new System.NotSupportedException(),
};
var dbObjects = resultProcessDbObject.GetDbObject(objectToWrite.DbObjectType, objectToWrite.Operation);

foreach (var dbObject in dbObjects.ToList())
{
Expand Down Expand Up @@ -235,7 +229,7 @@ private void ProcessTable(IEnumerable<DbObject> sourceObjects, IEnumerable<DbObj

resultProcessDbObject.AddOperation(tableOrigin.Indexes, Operation.Create);
resultProcessDbObject.AddOperation<Table>(tableOrigin, Operation.Create);
resultProcessDbObject.AddOperation<TableSet>(tableOrigin.TableSetList, Operation.Create);
resultProcessDbObject.AddOperation(tableOrigin.TableSetList, Operation.Create);
}
else
{
Expand Down Expand Up @@ -272,7 +266,7 @@ private void ProcessTable(IEnumerable<DbObject> sourceObjects, IEnumerable<DbObj
//columns different
ProcessTableColumn(tableOrigin, destinationTable, resultProcessDbObject);
}
resultProcessDbObject.AddOperation<TableSet>(tableOrigin.TableSetList.Except(destinationTable.TableSetList).ToList(), Operation.Create);
resultProcessDbObject.AddOperation(tableOrigin.TableSetList.Except(destinationTable.TableSetList).ToList(), Operation.Create);
}
}
DropDbObject(originDb, destinationDb, resultProcessDbObject);
Expand All @@ -282,24 +276,33 @@ private void ProcessTableColumn(Table table, Table destinationTable, ResultProce
IList<Column> columnsToAdd;
IList<Column> columnsToDrop;
IList<Column> columnsToAlter;
IList<Column> columnsToRename;

var columnsEqualsCaseInsensitive = table.Columns.Select(x => x.NameCaseInsensitive).Intersect(destinationTable.Columns.Select(x => x.NameCaseInsensitive));
columnsToRename = table.Columns.Where(x => columnsEqualsCaseInsensitive.Contains(x.NameCaseInsensitive) && !destinationTable.Columns.Select(x => x.Name).Contains(x.Name)).ToList();
foreach (var column in columnsToRename)
{
resultProcessDbObject.AddOperation<Column>(column, Operation.Rename,
destinationTable.Columns.Single(x => x.IdentifierCaseInsensitive == column.IdentifierCaseInsensitive).Name);
}

columnsToAdd = table.Columns
.Where(x =>
table.Columns
.Select(x => x.Name)
.Except(destinationTable.Columns.Select(x => x.Name))
.Contains(x.Name)).ToList();
.Select(x => x.NameCaseInsensitive)
.Except(destinationTable.Columns.Select(x => x.NameCaseInsensitive))
.Contains(x.NameCaseInsensitive)).ToList();

columnsToDrop = destinationTable.Columns
.Where(x =>
destinationTable.Columns
.Select(x => x.Name)
.Except(table.Columns.Select(x => x.Name))
.Contains(x.Name)).ToList();
.Select(x => x.NameCaseInsensitive)
.Except(table.Columns.Select(x => x.NameCaseInsensitive))
.Contains(x.NameCaseInsensitive)).ToList();

columnsToAlter = table.Columns
.Except(columnsToAdd)
.Where(x => !destinationTable.Columns.Contains(x)).ToList();
.Where(x => !destinationTable.Columns.Contains(x, new CaseInsensitiveComparer())).ToList();

resultProcessDbObject.AddOperation(columnsToAdd, Operation.Create);
resultProcessDbObject.AddOperation(columnsToAlter, Operation.Alter);
Expand Down
21 changes: 21 additions & 0 deletions SqlSchemaCompare.Test/TSql/TSqlTableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,27 @@ ALTER TABLE [schema].[tbl] SET (LOCK_ESCALATION = DISABLE)
ALTER TABLE [schema].[tbl] SET (LOCK_ESCALATION = DISABLE)
GO
");
errors.ShouldBeEmpty();
}

[Fact]
public void ColumnsDifferentCase()
{
const string origin =
@"CREATE TABLE [schema].[tbl] ([col1] INT not null)
GO";

const string destination =
@"CREATE TABLE [schema].[tbl] ([COL1] INT not null)
GO";

(string updateSchema, string errors) = UtilityTest.UpdateSchema(origin, destination, SelectedObjects);

updateSchema.ShouldBe(
@"sp_rename '[schema].[tbl].[COL1]', 'col1', 'COLUMN'
GO
");
errors.ShouldBeEmpty();
}
Expand Down

0 comments on commit 362c280

Please sign in to comment.