Skip to content

Commit c654c49

Browse files
authored
Merge pull request #91 from jbogard/support-ignore-table-with-schema
Adding support for including and excluding schemas with tables across all databases
2 parents 8ac9587 + bd2216b commit c654c49

18 files changed

+2759
-409
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,6 @@ FakesAssemblies/
204204
tools/roundhouse/output/
205205

206206
*.orig
207+
208+
# Informix files
209+
informix-server/wl*

Respawn.DatabaseTests/InformixTests.cs

Lines changed: 329 additions & 332 deletions
Large diffs are not rendered by default.

Respawn.DatabaseTests/MySqlTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Threading.Tasks;
22
using MySql.Data.MySqlClient;
3+
using Respawn.Graph;
34
using Xunit;
45
using Xunit.Abstractions;
56

@@ -260,7 +261,7 @@ public async Task ShouldIgnoreTables()
260261
var checkpoint = new Checkpoint
261262
{
262263
DbAdapter = DbAdapter.MySql,
263-
TablesToIgnore = new[] { "Foo" },
264+
TablesToIgnore = new Table[] { "Foo" },
264265
SchemasToInclude = new[] { "MySqlTests" }
265266
};
266267
await checkpoint.Reset(_connection);
@@ -283,7 +284,7 @@ public async Task ShouldIncludeTables()
283284
var checkpoint = new Checkpoint
284285
{
285286
DbAdapter = DbAdapter.MySql,
286-
TablesToInclude = new[] { "Foo" },
287+
TablesToInclude = new Table[] { "Foo" },
287288
SchemasToInclude = new[] { "MySqlTests" }
288289
};
289290
await checkpoint.Reset(_connection);

Respawn.DatabaseTests/PostgresTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Linq;
22
using System.Threading.Tasks;
3+
using Respawn.Graph;
34
using Xunit;
45
using Xunit.Abstractions;
56

@@ -88,7 +89,7 @@ public async Task ShouldIgnoreTables()
8889
var checkpoint = new Checkpoint
8990
{
9091
DbAdapter = DbAdapter.Postgres,
91-
TablesToIgnore = new[] { "foo" }
92+
TablesToIgnore = new Table[] { "foo" }
9293
};
9394
await checkpoint.Reset(_connection);
9495

@@ -111,7 +112,7 @@ public async Task ShouldIncludeTables()
111112
var checkpoint = new Checkpoint
112113
{
113114
DbAdapter = DbAdapter.Postgres,
114-
TablesToInclude = new[] { "foo" }
115+
TablesToInclude = new Table[] { "foo" }
115116
};
116117
await checkpoint.Reset(_connection);
117118

Respawn.DatabaseTests/Respawn.DatabaseTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="All" />
1414
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
1515
<PackageReference Include="Microsoft.Data.SqlClient" Version="4.0.0" />
16-
<!--<PackageReference Include="Oracle.ManagedDataAccess" Version="21.5.0" />-->
16+
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="3.21.50" />
1717
</ItemGroup>
1818
<ItemGroup>
1919
<ProjectReference Include="..\Respawn\Respawn.csproj" />

Respawn.DatabaseTests/SqlServerTests.cs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Threading.Tasks;
22
using Microsoft.Data.SqlClient;
3+
using Respawn.Graph;
34
using Xunit;
45
using Xunit.Abstractions;
56

@@ -251,7 +252,7 @@ public async Task ShouldIgnoreTables()
251252

252253
var checkpoint = new Checkpoint
253254
{
254-
TablesToIgnore = new[] { "Foo" }
255+
TablesToIgnore = new Table[] { "Foo" }
255256
};
256257
try
257258
{
@@ -261,12 +262,57 @@ public async Task ShouldIgnoreTables()
261262
{
262263
_output.WriteLine(checkpoint.DeleteSql);
263264
throw;
264-
}
265-
265+
}
266+
267+
_output.WriteLine(checkpoint.DeleteSql);
266268
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM Foo").ShouldBe(100);
267269
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM Bar").ShouldBe(0);
268270
}
269271

272+
[Fact]
273+
public async Task ShouldIgnoreTablesWithSchema()
274+
{
275+
await _database.ExecuteAsync("drop schema if exists A");
276+
await _database.ExecuteAsync("drop schema if exists B");
277+
await _database.ExecuteAsync("create schema A");
278+
await _database.ExecuteAsync("create schema B");
279+
await _database.ExecuteAsync("create table A.Foo (Value [int])");
280+
await _database.ExecuteAsync("create table A.FooWithBrackets (Value [int])");
281+
await _database.ExecuteAsync("create table B.Bar (Value [int])");
282+
await _database.ExecuteAsync("create table B.Foo (Value [int])");
283+
284+
for (var i = 0; i < 100; i++)
285+
{
286+
await _database.ExecuteAsync("INSERT A.Foo VALUES (" + i + ")");
287+
await _database.ExecuteAsync("INSERT A.FooWithBrackets VALUES (" + i + ")");
288+
await _database.ExecuteAsync("INSERT B.Bar VALUES (" + i + ")");
289+
await _database.ExecuteAsync("INSERT B.Foo VALUES (" + i + ")");
290+
}
291+
292+
var checkpoint = new Checkpoint
293+
{
294+
TablesToIgnore = new[]
295+
{
296+
new Table("A", "Foo"),
297+
new Table("A", "FooWithBrackets")
298+
}
299+
};
300+
try
301+
{
302+
await checkpoint.Reset(_connection);
303+
}
304+
catch
305+
{
306+
_output.WriteLine(checkpoint.DeleteSql);
307+
throw;
308+
}
309+
310+
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM A.Foo").ShouldBe(100);
311+
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM A.FooWithBrackets").ShouldBe(100);
312+
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM B.Bar").ShouldBe(0);
313+
_database.ExecuteScalar<int>("SELECT COUNT(1) FROM B.Foo").ShouldBe(0);
314+
}
315+
270316
[Fact]
271317
public async Task ShouldIncludeTables()
272318
{
@@ -278,7 +324,7 @@ public async Task ShouldIncludeTables()
278324

279325
var checkpoint = new Checkpoint
280326
{
281-
TablesToInclude = new[] { "Foo" }
327+
TablesToInclude = new Table[] { "Foo" }
282328
};
283329
try
284330
{

Respawn.sln

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1414
.github\workflows\ci.yml = .github\workflows\ci.yml
1515
Directory.Build.props = Directory.Build.props
1616
docker-compose.yml = docker-compose.yml
17+
informix-server\my_post.sh = informix-server\my_post.sh
18+
informix-server\onconfig = informix-server\onconfig
1719
Push.ps1 = Push.ps1
1820
.github\workflows\release.yml = .github\workflows\release.yml
1921
EndProjectSection

Respawn/Checkpoint.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public class Checkpoint
1212
{
1313
private IList<TemporalTable> _temporalTables = new List<TemporalTable>();
1414

15-
public string[] TablesToIgnore { get; init; } = Array.Empty<string>();
16-
public string[] TablesToInclude { get; init; } = Array.Empty<string>();
15+
public Table[] TablesToIgnore { get; init; } = Array.Empty<Table>();
16+
public Table[] TablesToInclude { get; init; } = Array.Empty<Table>();
1717
public string[] SchemasToInclude { get; init; } = Array.Empty<string>();
1818
public string[] SchemasToExclude { get; init; } = Array.Empty<string>();
1919
public string? DeleteSql { get; private set; }

Respawn/Graph/Table.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ namespace Respawn.Graph
55
{
66
public class Table : IEquatable<Table>
77
{
8+
public Table(string name) : this(null, name)
9+
{
10+
11+
}
12+
813
public Table(string? schema, string name)
914
{
1015
Schema = schema;
@@ -21,6 +26,8 @@ public string GetFullName(char quoteIdentifier) =>
2126
? $"{quoteIdentifier}{Name}{quoteIdentifier}"
2227
: $"{quoteIdentifier}{Schema}{quoteIdentifier}.{quoteIdentifier}{Name}{quoteIdentifier}";
2328

29+
public static implicit operator Table(string name) => new(name);
30+
2431
public bool Equals(Table? other)
2532
{
2633
if (ReferenceEquals(null, other)) return false;

Respawn/InformixDbAdapter.cs

Lines changed: 107 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,61 @@ public string BuildTableCommandText(Checkpoint checkpoint)
1818

1919
if (checkpoint.TablesToIgnore.Any())
2020
{
21-
var args = string.Join(",", checkpoint.TablesToIgnore.Select(t => $"'{t}'"));
22-
23-
commandText += " AND t.tabname NOT IN (" + args + ")";
21+
var tablesToIgnoreGroups = checkpoint.TablesToIgnore
22+
.GroupBy(
23+
t => t.Schema != null,
24+
t => t,
25+
(hasSchema, tables) => new
26+
{
27+
HasSchema = hasSchema,
28+
Tables = tables
29+
})
30+
.ToList();
31+
foreach (var tableGroup in tablesToIgnoreGroups)
32+
{
33+
if (tableGroup.HasSchema)
34+
{
35+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));
36+
37+
commandText += " AND t.owner + '.' + t.tabname NOT IN (" + args + ")";
38+
}
39+
else
40+
{
41+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));
42+
43+
commandText += " AND t.tabname NOT IN (" + args + ")";
44+
}
45+
}
46+
}
47+
if (checkpoint.TablesToInclude.Any())
48+
{
49+
var tablesToIncludeGroups = checkpoint.TablesToInclude
50+
.GroupBy(
51+
t => t.Schema != null,
52+
t => t,
53+
(hasSchema, tables) => new
54+
{
55+
HasSchema = hasSchema,
56+
Tables = tables
57+
})
58+
.ToList();
59+
foreach (var tableGroup in tablesToIncludeGroups)
60+
{
61+
if (tableGroup.HasSchema)
62+
{
63+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));
64+
65+
commandText += " AND t.owner + '.' + t.tabname IN (" + args + ")";
66+
}
67+
else
68+
{
69+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));
70+
71+
commandText += " AND t.tabname IN (" + args + ")";
72+
}
73+
}
2474
}
75+
2576
if (checkpoint.SchemasToExclude.Any())
2677
{
2778
var args = string.Join(",", checkpoint.SchemasToExclude.Select(t => $"'{t}'"));
@@ -54,9 +105,59 @@ INNER JOIN systables T2
54105

55106
if (checkpoint.TablesToIgnore.Any())
56107
{
57-
var args = string.Join(",", checkpoint.TablesToIgnore.Select(t => $"'{t}'"));
58-
59-
commandText += " AND T2.tabname NOT IN (" + args + ")";
108+
var tablesToIgnoreGroups = checkpoint.TablesToIgnore
109+
.GroupBy(
110+
t => t.Schema != null,
111+
t => t,
112+
(hasSchema, tables) => new
113+
{
114+
HasSchema = hasSchema,
115+
Tables = tables
116+
})
117+
.ToList();
118+
foreach (var tableGroup in tablesToIgnoreGroups)
119+
{
120+
if (tableGroup.HasSchema)
121+
{
122+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));
123+
124+
commandText += " AND T2.owner + '.' + T2.tabname NOT IN (" + args + ")";
125+
}
126+
else
127+
{
128+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));
129+
130+
commandText += " AND T2.tabname NOT IN (" + args + ")";
131+
}
132+
}
133+
}
134+
if (checkpoint.TablesToInclude.Any())
135+
{
136+
var tablesToIncludeGroups = checkpoint.TablesToInclude
137+
.GroupBy(
138+
t => t.Schema != null,
139+
t => t,
140+
(hasSchema, tables) => new
141+
{
142+
HasSchema = hasSchema,
143+
Tables = tables
144+
})
145+
.ToList();
146+
foreach (var tableGroup in tablesToIncludeGroups)
147+
{
148+
if (tableGroup.HasSchema)
149+
{
150+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Schema}.{table.Name}'"));
151+
152+
commandText += " AND T2.owner + '.' + T2.tabname IN (" + args + ")";
153+
}
154+
else
155+
{
156+
var args = string.Join(",", tableGroup.Tables.Select(table => $"'{table.Name}'"));
157+
158+
commandText += " AND T2.tabname IN (" + args + ")";
159+
}
160+
}
60161
}
61162
if (checkpoint.SchemasToExclude.Any())
62163
{

0 commit comments

Comments
 (0)