Skip to content

Commit ffdd0e6

Browse files
Merge pull request #133 from dotnetprojects/add-primary-key
Added CopyDataFromTableToTable
2 parents e4a2721 + ecc9ae5 commit ffdd0e6

15 files changed

+423
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System.Collections.Generic;
2+
using System.Data;
3+
using DotNetProjects.Migrator.Framework;
4+
using Migrator.Tests.Providers.Base;
5+
using Migrator.Tests.Providers.Generic.Models;
6+
using NUnit.Framework;
7+
8+
namespace Migrator.Tests.Providers.Generic;
9+
10+
public abstract class Generic_CopyDataFromTableToTableBase : TransformationProviderBase
11+
{
12+
[Test]
13+
public void CopyDataFromTableToTable_Success()
14+
{
15+
// Arrange
16+
const string tableNameSource = "SourceTable";
17+
const string columnName1Source = "SourceColumn1";
18+
const string columnName2Source = "SourceColumn2";
19+
const string columnName3Source = "SourceColumn3";
20+
21+
const string tableNameTarget = "TargetTable";
22+
const string columnName1Target = "TargetColumn1";
23+
const string columnName2Target = "TargetColumn2";
24+
const string columnName3Target = "TargetColumn3";
25+
26+
Provider.AddTable(tableNameSource,
27+
new Column(columnName1Source, DbType.Int32),
28+
new Column(columnName2Source, DbType.String),
29+
new Column(columnName3Source, DbType.Int32)
30+
);
31+
32+
Provider.AddTable(tableNameTarget,
33+
new Column(columnName1Target, DbType.Int32),
34+
new Column(columnName2Target, DbType.String),
35+
new Column(columnName3Target, DbType.Int32)
36+
);
37+
38+
Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source], [2, "Hello2", 22]);
39+
Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source], [1, "Hello1", 11]);
40+
41+
// Act
42+
Provider.CopyDataFromTableToTable(
43+
tableNameSource,
44+
[columnName1Source, columnName2Source, columnName3Source],
45+
tableNameTarget,
46+
[columnName1Target, columnName2Target, columnName3Target],
47+
[columnName1Source]);
48+
49+
// Assert
50+
List<CopyDataFromTableToTableModel> targetRows = [];
51+
using (var cmd = Provider.CreateCommand())
52+
using (var reader = Provider.Select(cmd, tableNameTarget, [columnName1Target, columnName2Target, columnName3Target]))
53+
{
54+
while (reader.Read())
55+
{
56+
targetRows.Add(new CopyDataFromTableToTableModel
57+
{
58+
Column1 = reader.GetInt32(0),
59+
Column2 = reader.GetString(1),
60+
Column3 = reader.GetInt32(2),
61+
});
62+
}
63+
}
64+
65+
List<CopyDataFromTableToTableModel> expectedTargetRows = [
66+
new CopyDataFromTableToTableModel{ Column1 = 1, Column2 = "Hello1", Column3 = 11 },
67+
new CopyDataFromTableToTableModel{ Column1 = 2, Column2 = "Hello2", Column3 = 22 },
68+
];
69+
70+
Assert.That(targetRows, Is.EquivalentTo(expectedTargetRows).Using<CopyDataFromTableToTableModel>((x, y) =>
71+
x.Column1 == y.Column1 &&
72+
x.Column2 == y.Column2 &&
73+
x.Column3 == y.Column3));
74+
}
75+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Migrator.Tests.Providers.Generic.Models;
2+
3+
public class CopyDataFromTableToTableModel
4+
{
5+
public int Column1 { get; set; }
6+
public string Column2 { get; set; }
7+
public int Column3 { get; set; }
8+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Threading.Tasks;
2+
using Migrator.Tests.Providers.Generic;
3+
using NUnit.Framework;
4+
5+
namespace Migrator.Tests.Providers.OracleProvider;
6+
7+
[TestFixture]
8+
[Category("Oracle")]
9+
public class OracleTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase
10+
{
11+
[SetUp]
12+
public async Task SetUpAsync()
13+
{
14+
await BeginOracleTransactionAsync();
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Threading.Tasks;
2+
using Migrator.Tests.Providers.Generic;
3+
using NUnit.Framework;
4+
5+
namespace Migrator.Tests.Providers.PostgreSQL;
6+
7+
[TestFixture]
8+
[Category("Postgre")]
9+
public class PostgreSQLTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase
10+
{
11+
[SetUp]
12+
public async Task SetUpAsync()
13+
{
14+
await BeginPostgreSQLTransactionAsync();
15+
}
16+
}

src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,22 @@ public void ChangeColumn_DateTimeToDateTime2_Success()
3535
Assert.That(columnBefore.Type == DbType.DateTime);
3636
Assert.That(columnAfter.Type == DbType.DateTime2);
3737
}
38+
39+
[Test, Ignore("This issue is not yet fixed. See https://github.com/dotnetprojects/Migrator.NET/issues/132")]
40+
public void ChangeColumn_WithUniqueThenReChangeToNonUnique_UniqueConstraintShouldBeRemoved()
41+
{
42+
// Arrange
43+
const string tableName = "TestTable";
44+
const string columnName = "TestColumn";
45+
46+
Provider.AddTable(tableName, new Column(columnName, DbType.Int32, ColumnProperty.NotNull));
47+
48+
// Act
49+
Provider.ChangeColumn(tableName, new Column(columnName, DbType.Int32, ColumnProperty.NotNull | ColumnProperty.Unique));
50+
Provider.ChangeColumn(tableName, new Column(columnName, DbType.Int32, ColumnProperty.NotNull));
51+
52+
// Assert
53+
var indexes = Provider.GetIndexes(tableName);
54+
Assert.That(indexes, Is.Empty);
55+
}
3856
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Threading.Tasks;
2+
using Migrator.Tests.Providers.Generic;
3+
using NUnit.Framework;
4+
5+
namespace Migrator.Tests.Providers.SQLServer;
6+
7+
[TestFixture]
8+
[Category("SqlServer")]
9+
public class SQLServerTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase
10+
{
11+
[SetUp]
12+
public async Task SetUpAsync()
13+
{
14+
await BeginSQLServerTransactionAsync();
15+
}
16+
}

src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds()
4343
Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (2, 3)");
4444

4545
// Assert
46+
var createScriptAfter = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName);
47+
Assert.That(createScriptAfter, Does.Contain("Color2 TEXT NULL UNIQUE"));
48+
4649
using var command = Provider.GetCommand();
4750
using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}");
4851
reader.Read();
@@ -65,4 +68,26 @@ public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds()
6568
Assert.That(indexAfter.Name, Is.EqualTo(indexName));
6669
CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 });
6770
}
71+
72+
[Test]
73+
public void ChangeColumn_StringFromNullToNotNull_StillNotNull()
74+
{
75+
// Arrange
76+
const string testTableName = "MyDefaultTestTable";
77+
const string propertyName1 = "Color1";
78+
const string propertyName2 = "Color2";
79+
80+
Provider.AddTable(testTableName,
81+
new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey),
82+
new Column(propertyName2, DbType.String, 100, ColumnProperty.Null)
83+
);
84+
85+
// Act
86+
Provider.ChangeColumn(table: testTableName, new Column(propertyName2, DbType.String, ColumnProperty.NotNull));
87+
88+
89+
// Assert
90+
var createScriptAfter = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName);
91+
Assert.That(createScriptAfter, Does.Contain("Color2 TEXT NOT NULL"));
92+
}
6893
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Threading.Tasks;
2+
using Migrator.Tests.Providers.Generic;
3+
using NUnit.Framework;
4+
5+
namespace Migrator.Tests.Providers.SQLite;
6+
7+
[TestFixture]
8+
[Category("SQLite")]
9+
public class SQLiteTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase
10+
{
11+
[SetUp]
12+
public async Task SetUpAsync()
13+
{
14+
await BeginSQLiteTransactionAsync();
15+
}
16+
}

src/Migrator/Framework/ITransformationProvider.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,16 @@ public interface ITransformationProvider : IDisposable
343343
/// <returns></returns>
344344
bool ConstraintExists(string table, string name);
345345

346+
/// <summary>
347+
/// Copies data from source table to target table using INSERT INTO...SELECT..FROM
348+
/// </summary>
349+
/// <param name="sourceTableName"></param>
350+
/// <param name="sourceColumnNames"></param>
351+
/// <param name="targetTableName"></param>
352+
/// <param name="targetColumnNames"></param>
353+
/// <param name="orderBySourceColumns">Sort source by these columns. <paramref name="sourceColumnNames"/> must contain the <paramref name="orderBySourceColumns"/>.
354+
void CopyDataFromTableToTable(string sourceTableName, List<string> sourceColumnNames, string targetTableName, List<string> targetColumnNames, List<string> orderBySourceColumns);
355+
346356
/// <summary>
347357
/// Check to see if a primary key constraint exists on the table
348358
/// </summary>

src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,59 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter,
818818
}
819819
}
820820

821+
public override void CopyDataFromTableToTable(string sourceTableName, List<string> sourceColumnNames, string targetTableName, List<string> targetColumnNames, List<string> orderBySourceColumns)
822+
{
823+
orderBySourceColumns ??= [];
824+
825+
if (!TableExists(sourceTableName))
826+
{
827+
throw new Exception($"Source table '{QuoteTableNameIfRequired(sourceTableName)}' does not exist");
828+
}
829+
830+
if (!TableExists(targetTableName))
831+
{
832+
throw new Exception($"Target table '{QuoteTableNameIfRequired(targetTableName)}' does not exist");
833+
}
834+
835+
var sourceColumnsConcatenated = sourceColumnNames.Concat(orderBySourceColumns);
836+
837+
foreach (var column in sourceColumnsConcatenated)
838+
{
839+
if (!ColumnExists(sourceTableName, column))
840+
{
841+
throw new Exception($"Column {column} in source table does not exist.");
842+
}
843+
}
844+
845+
foreach (var column in targetColumnNames)
846+
{
847+
if (!ColumnExists(targetTableName, column))
848+
{
849+
throw new Exception($"Column {column} in target table does not exist.");
850+
}
851+
}
852+
853+
if (!orderBySourceColumns.All(x => sourceColumnNames.Contains(x)))
854+
{
855+
throw new Exception($"All columns in {nameof(orderBySourceColumns)} must be in {nameof(sourceColumnNames)}");
856+
}
857+
858+
var sourceTableNameQuoted = QuoteTableNameIfRequired(sourceTableName);
859+
var targetTableNameQuoted = QuoteTableNameIfRequired(targetTableName);
860+
861+
var sourceColumnNamesQuoted = sourceColumnNames.Select(QuoteColumnNameIfRequired).ToList();
862+
var targetColumnNamesQuoted = targetColumnNames.Select(QuoteColumnNameIfRequired).ToList();
863+
var orderBySourceColumnsQuoted = orderBySourceColumns.Select(QuoteColumnNameIfRequired).ToList();
864+
865+
var sourceColumnsJoined = string.Join(", ", sourceColumnNamesQuoted);
866+
var targetColumnsJoined = string.Join(", ", targetColumnNamesQuoted);
867+
var orderBySourceColumnsJoined = string.Join(", ", orderBySourceColumnsQuoted);
868+
869+
870+
var sql = $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted} ORDER BY {orderBySourceColumnsJoined}";
871+
ExecuteNonQuery(sql);
872+
}
873+
821874
public override void RemoveColumnDefaultValue(string table, string column)
822875
{
823876
var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column);

0 commit comments

Comments
 (0)