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

Adding support for including and excluding schemas with tables across all databases #91

Merged
merged 1 commit into from
Jan 13, 2022
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 .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