Skip to content

Commit

Permalink
Merge pull request #91 from jbogard/support-ignore-table-with-schema
Browse files Browse the repository at this point in the history
Adding support for including and excluding schemas with tables across all databases
  • Loading branch information
jbogard authored Jan 13, 2022
2 parents 8ac9587 + bd2216b commit c654c49
Show file tree
Hide file tree
Showing 18 changed files with 2,759 additions and 409 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,6 @@ FakesAssemblies/
tools/roundhouse/output/

*.orig

# Informix files
informix-server/wl*
661 changes: 329 additions & 332 deletions Respawn.DatabaseTests/InformixTests.cs

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions Respawn.DatabaseTests/MySqlTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using Respawn.Graph;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -260,7 +261,7 @@ public async Task ShouldIgnoreTables()
var checkpoint = new Checkpoint
{
DbAdapter = DbAdapter.MySql,
TablesToIgnore = new[] { "Foo" },
TablesToIgnore = new Table[] { "Foo" },
SchemasToInclude = new[] { "MySqlTests" }
};
await checkpoint.Reset(_connection);
Expand All @@ -283,7 +284,7 @@ public async Task ShouldIncludeTables()
var checkpoint = new Checkpoint
{
DbAdapter = DbAdapter.MySql,
TablesToInclude = new[] { "Foo" },
TablesToInclude = new Table[] { "Foo" },
SchemasToInclude = new[] { "MySqlTests" }
};
await checkpoint.Reset(_connection);
Expand Down
5 changes: 3 additions & 2 deletions Respawn.DatabaseTests/PostgresTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using System.Threading.Tasks;
using Respawn.Graph;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -88,7 +89,7 @@ public async Task ShouldIgnoreTables()
var checkpoint = new Checkpoint
{
DbAdapter = DbAdapter.Postgres,
TablesToIgnore = new[] { "foo" }
TablesToIgnore = new Table[] { "foo" }
};
await checkpoint.Reset(_connection);

Expand All @@ -111,7 +112,7 @@ public async Task ShouldIncludeTables()
var checkpoint = new Checkpoint
{
DbAdapter = DbAdapter.Postgres,
TablesToInclude = new[] { "foo" }
TablesToInclude = new Table[] { "foo" }
};
await checkpoint.Reset(_connection);

Expand Down
2 changes: 1 addition & 1 deletion Respawn.DatabaseTests/Respawn.DatabaseTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="All" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="4.0.0" />
<!--<PackageReference Include="Oracle.ManagedDataAccess" Version="21.5.0" />-->
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="3.21.50" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Respawn\Respawn.csproj" />
Expand Down
54 changes: 50 additions & 4 deletions Respawn.DatabaseTests/SqlServerTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using Respawn.Graph;
using Xunit;
using Xunit.Abstractions;

Expand Down Expand Up @@ -251,7 +252,7 @@ public async Task ShouldIgnoreTables()

var checkpoint = new Checkpoint
{
TablesToIgnore = new[] { "Foo" }
TablesToIgnore = new Table[] { "Foo" }
};
try
{
Expand All @@ -261,12 +262,57 @@ public async Task ShouldIgnoreTables()
{
_output.WriteLine(checkpoint.DeleteSql);
throw;
}

}

_output.WriteLine(checkpoint.DeleteSql);
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM Foo").ShouldBe(100);
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM Bar").ShouldBe(0);
}

[Fact]
public async Task ShouldIgnoreTablesWithSchema()
{
await _database.ExecuteAsync("drop schema if exists A");
await _database.ExecuteAsync("drop schema if exists B");
await _database.ExecuteAsync("create schema A");
await _database.ExecuteAsync("create schema B");
await _database.ExecuteAsync("create table A.Foo (Value [int])");
await _database.ExecuteAsync("create table A.FooWithBrackets (Value [int])");
await _database.ExecuteAsync("create table B.Bar (Value [int])");
await _database.ExecuteAsync("create table B.Foo (Value [int])");

for (var i = 0; i < 100; i++)
{
await _database.ExecuteAsync("INSERT A.Foo VALUES (" + i + ")");
await _database.ExecuteAsync("INSERT A.FooWithBrackets VALUES (" + i + ")");
await _database.ExecuteAsync("INSERT B.Bar VALUES (" + i + ")");
await _database.ExecuteAsync("INSERT B.Foo VALUES (" + i + ")");
}

var checkpoint = new Checkpoint
{
TablesToIgnore = new[]
{
new Table("A", "Foo"),
new Table("A", "FooWithBrackets")
}
};
try
{
await checkpoint.Reset(_connection);
}
catch
{
_output.WriteLine(checkpoint.DeleteSql);
throw;
}

_database.ExecuteScalar<int>("SELECT COUNT(1) FROM A.Foo").ShouldBe(100);
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM A.FooWithBrackets").ShouldBe(100);
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM B.Bar").ShouldBe(0);
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM B.Foo").ShouldBe(0);
}

[Fact]
public async Task ShouldIncludeTables()
{
Expand All @@ -278,7 +324,7 @@ public async Task ShouldIncludeTables()

var checkpoint = new Checkpoint
{
TablesToInclude = new[] { "Foo" }
TablesToInclude = new Table[] { "Foo" }
};
try
{
Expand Down
2 changes: 2 additions & 0 deletions Respawn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\ci.yml = .github\workflows\ci.yml
Directory.Build.props = Directory.Build.props
docker-compose.yml = docker-compose.yml
informix-server\my_post.sh = informix-server\my_post.sh
informix-server\onconfig = informix-server\onconfig
Push.ps1 = Push.ps1
.github\workflows\release.yml = .github\workflows\release.yml
EndProjectSection
Expand Down
4 changes: 2 additions & 2 deletions Respawn/Checkpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class Checkpoint
{
private IList<TemporalTable> _temporalTables = new List<TemporalTable>();

public string[] TablesToIgnore { get; init; } = Array.Empty<string>();
public string[] TablesToInclude { get; init; } = Array.Empty<string>();
public Table[] TablesToIgnore { get; init; } = Array.Empty<Table>();
public Table[] TablesToInclude { get; init; } = Array.Empty<Table>();
public string[] SchemasToInclude { get; init; } = Array.Empty<string>();
public string[] SchemasToExclude { get; init; } = Array.Empty<string>();
public string? DeleteSql { get; private set; }
Expand Down
7 changes: 7 additions & 0 deletions Respawn/Graph/Table.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ namespace Respawn.Graph
{
public class Table : IEquatable<Table>
{
public Table(string name) : this(null, name)
{

}

public Table(string? schema, string name)
{
Schema = schema;
Expand All @@ -21,6 +26,8 @@ public string GetFullName(char quoteIdentifier) =>
? $"{quoteIdentifier}{Name}{quoteIdentifier}"
: $"{quoteIdentifier}{Schema}{quoteIdentifier}.{quoteIdentifier}{Name}{quoteIdentifier}";

public static implicit operator Table(string name) => new(name);

public bool Equals(Table? other)
{
if (ReferenceEquals(null, other)) return false;
Expand Down
113 changes: 107 additions & 6 deletions Respawn/InformixDbAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,61 @@ public string BuildTableCommandText(Checkpoint checkpoint)

if (checkpoint.TablesToIgnore.Any())
{
var args = string.Join(",", checkpoint.TablesToIgnore.Select(t => $"'{t}'"));

commandText += " AND t.tabname NOT IN (" + args + ")";
var tablesToIgnoreGroups = checkpoint.TablesToIgnore
.GroupBy(
t => t.Schema != null,
t => t,
(hasSchema, tables) => new
{
HasSchema = hasSchema,
Tables = tables
})
.ToList();
foreach (var tableGroup in tablesToIgnoreGroups)
{
if (tableGroup.HasSchema)
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));

commandText += " AND t.owner + '.' + t.tabname NOT IN (" + args + ")";
}
else
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));

commandText += " AND t.tabname NOT IN (" + args + ")";
}
}
}
if (checkpoint.TablesToInclude.Any())
{
var tablesToIncludeGroups = checkpoint.TablesToInclude
.GroupBy(
t => t.Schema != null,
t => t,
(hasSchema, tables) => new
{
HasSchema = hasSchema,
Tables = tables
})
.ToList();
foreach (var tableGroup in tablesToIncludeGroups)
{
if (tableGroup.HasSchema)
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));

commandText += " AND t.owner + '.' + t.tabname IN (" + args + ")";
}
else
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));

commandText += " AND t.tabname IN (" + args + ")";
}
}
}

if (checkpoint.SchemasToExclude.Any())
{
var args = string.Join(",", checkpoint.SchemasToExclude.Select(t => $"'{t}'"));
Expand Down Expand Up @@ -54,9 +105,59 @@ INNER JOIN systables T2

if (checkpoint.TablesToIgnore.Any())
{
var args = string.Join(",", checkpoint.TablesToIgnore.Select(t => $"'{t}'"));

commandText += " AND T2.tabname NOT IN (" + args + ")";
var tablesToIgnoreGroups = checkpoint.TablesToIgnore
.GroupBy(
t => t.Schema != null,
t => t,
(hasSchema, tables) => new
{
HasSchema = hasSchema,
Tables = tables
})
.ToList();
foreach (var tableGroup in tablesToIgnoreGroups)
{
if (tableGroup.HasSchema)
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));

commandText += " AND T2.owner + '.' + T2.tabname NOT IN (" + args + ")";
}
else
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));

commandText += " AND T2.tabname NOT IN (" + args + ")";
}
}
}
if (checkpoint.TablesToInclude.Any())
{
var tablesToIncludeGroups = checkpoint.TablesToInclude
.GroupBy(
t => t.Schema != null,
t => t,
(hasSchema, tables) => new
{
HasSchema = hasSchema,
Tables = tables
})
.ToList();
foreach (var tableGroup in tablesToIncludeGroups)
{
if (tableGroup.HasSchema)
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));

commandText += " AND T2.owner + '.' + T2.tabname IN (" + args + ")";
}
else
{
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));

commandText += " AND T2.tabname IN (" + args + ")";
}
}
}
if (checkpoint.SchemasToExclude.Any())
{
Expand Down
Loading

0 comments on commit c654c49

Please sign in to comment.