Skip to content

Commit 758f901

Browse files
Add an extension method ExecuteScript() to execute a SQL script.
1 parent 7622a25 commit 758f901

File tree

5 files changed

+213
-5
lines changed

5 files changed

+213
-5
lines changed

src/Directory.Build.props

+19-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,25 @@
1111
<PackageReadmeFile>README.md</PackageReadmeFile>
1212
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1313
<PackageReleaseNotes>
14-
1.0.1
15-
- Fix the documentation
16-
17-
1.0.0
18-
- Initial version
14+
2.1.0
15+
- PosInformatique.Testing.Databases.SqlServer target the .NET Standard 2.0 platform.
16+
- PosInformatique.Testing.Databases.SqlServer.Dac target the .NET Core 6.0 and .NET Framework 4.6.2
17+
- PosInformatique.Testing.Databases.SqlServer.EntityFramework target the .NET Core 6.0
18+
- Reduce the dependencies to Entity Framework 6.0
19+
- Reduce the dependencies of DACfx to a more earlier version.
20+
- Add new method SqlServerDatabase.ExecuteScript() to execute T-SQL script.
21+
22+
2.0.0
23+
- Add SqlServerDatabaseComparer class to perform comparison between two databases.
24+
- Add new PosInformatique.Testing.Databases.SqlServer.Dac NuGet package which contains DAC package tools.
25+
- Add new SqlServer.CreateDatabaseAsync() extension method to create a database from a DbContext.
26+
- Reduce dependencies version of the Entity Framework Core and SQL Server Client NuGet packages.
27+
28+
1.0.1
29+
- Fix the documentation
30+
31+
1.0.0
32+
- Initial version
1933
</PackageReleaseNotes>
2034
</PropertyGroup>
2135

src/Testing.Databases.SqlServer/SqlServerDatabaseExtensions.cs

+34
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,40 @@ [sys].[identity_columns] AS [ic]
130130
database.ExecuteNonQuery("EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all'");
131131
}
132132

133+
/// <summary>
134+
/// Execute an T-SQL script on the <paramref name="database"/>.
135+
/// </summary>
136+
/// <param name="database"><see cref="SqlServerDatabase"/> where the <paramref name="script"/> will be executed.</param>
137+
/// <param name="script">T-SQL script to execute.</param>
138+
public static void ExecuteScript(this SqlServerDatabase database, string script)
139+
{
140+
using var stringReader = new StringReader(script);
141+
142+
ExecuteScript(database, stringReader);
143+
}
144+
145+
/// <summary>
146+
/// Execute an T-SQL script on the <paramref name="database"/>.
147+
/// </summary>
148+
/// <param name="database"><see cref="SqlServerDatabase"/> where the <paramref name="script"/> will be executed.</param>
149+
/// <param name="script"><see cref="StringReader"/> which contains the T-SQL script to execute.</param>
150+
public static void ExecuteScript(this SqlServerDatabase database, StringReader script)
151+
{
152+
var parser = new SqlServerScriptParser(script);
153+
154+
var block = parser.ReadNextBlock();
155+
156+
while (block is not null)
157+
{
158+
for (var i = 0; i < block.Count; i++)
159+
{
160+
database.ExecuteNonQuery(block.Code);
161+
}
162+
163+
block = parser.ReadNextBlock();
164+
}
165+
}
166+
133167
private sealed class SqlInsertStatementBuilder
134168
{
135169
private readonly string tableName;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="SqlServerScriptBlock.cs" company="P.O.S Informatique">
3+
// Copyright (c) P.O.S Informatique. All rights reserved.
4+
// </copyright>
5+
//-----------------------------------------------------------------------
6+
7+
namespace PosInformatique.Testing.Databases.SqlServer
8+
{
9+
internal class SqlServerScriptBlock
10+
{
11+
public SqlServerScriptBlock(string code, int count)
12+
{
13+
this.Code = code;
14+
this.Count = count;
15+
}
16+
17+
public string Code { get; }
18+
19+
public int Count { get; }
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="SqlServerScriptParser.cs" company="P.O.S Informatique">
3+
// Copyright (c) P.O.S Informatique. All rights reserved.
4+
// </copyright>
5+
//-----------------------------------------------------------------------
6+
7+
namespace PosInformatique.Testing.Databases.SqlServer
8+
{
9+
using System.Globalization;
10+
using System.Text;
11+
12+
internal sealed class SqlServerScriptParser
13+
{
14+
private readonly TextReader script;
15+
16+
private bool isEndOfScript;
17+
18+
public SqlServerScriptParser(TextReader script)
19+
{
20+
this.script = script;
21+
}
22+
23+
public SqlServerScriptBlock? ReadNextBlock()
24+
{
25+
if (this.isEndOfScript)
26+
{
27+
return null;
28+
}
29+
30+
var codeBuilder = new StringBuilder();
31+
32+
var count = 1;
33+
34+
while (true)
35+
{
36+
var line = this.script.ReadLine();
37+
38+
if (line is null)
39+
{
40+
// End of the script reach.
41+
this.isEndOfScript = true;
42+
break;
43+
}
44+
45+
line = line.Trim();
46+
47+
if (line.StartsWith("GO"))
48+
{
49+
// Parse the number after the "GO".
50+
var textAfterGo = line.Substring(2).Trim();
51+
52+
if (textAfterGo != string.Empty)
53+
{
54+
count = Convert.ToInt32(textAfterGo, CultureInfo.InvariantCulture);
55+
}
56+
57+
// If no code parsed, we continue to parse the block.
58+
if (codeBuilder.Length == 0)
59+
{
60+
continue;
61+
}
62+
63+
// Else, we stop the read of the script.
64+
break;
65+
}
66+
67+
codeBuilder.AppendLine(line);
68+
}
69+
70+
return new SqlServerScriptBlock(codeBuilder.ToString(), count);
71+
}
72+
}
73+
}

tests/Testing.Databases.SqlServer.Tests/SqlServerDatabaseExtensionsTest.cs

+66
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,71 @@ Binary VARBINARY(MAX) NULL,
9090
table.Rows[1]["Boolean"].As<bool>().Should().Be(false);
9191
table.Rows[1]["BooleanNull"].Should().Be(DBNull.Value);
9292
}
93+
94+
[Fact]
95+
public void ExecuteScript_String()
96+
{
97+
var server = new SqlServer(ConnectionString);
98+
99+
var database = server.CreateEmptyDatabase("SqlServerDatabaseExtensionsTest");
100+
101+
database.ExecuteScript(@"
102+
CREATE TABLE TableTest
103+
(
104+
Id INT NOT NULL
105+
)
106+
107+
GO
108+
GO
109+
110+
INSERT INTO [TableTest] ([Id]) VALUES (0)
111+
112+
GO
113+
UPDATE [TableTest]
114+
SET [Id] = [Id] + 1
115+
116+
GO 10
117+
118+
");
119+
120+
var table = database.ExecuteQuery("SELECT * FROM [TableTest]");
121+
122+
table.Rows.Should().HaveCount(1);
123+
124+
table.Rows[0]["Id"].Should().Be(10);
125+
}
126+
127+
[Fact]
128+
public void ExecuteScript_StringReader()
129+
{
130+
var server = new SqlServer(ConnectionString);
131+
132+
var database = server.CreateEmptyDatabase("SqlServerDatabaseExtensionsTest");
133+
134+
database.ExecuteScript(new StringReader(@"
135+
CREATE TABLE TableTest
136+
(
137+
Id INT NOT NULL
138+
)
139+
140+
GO
141+
GO
142+
143+
INSERT INTO [TableTest] ([Id]) VALUES (0)
144+
145+
GO
146+
UPDATE [TableTest]
147+
SET [Id] = [Id] + 1
148+
149+
GO 10
150+
151+
"));
152+
153+
var table = database.ExecuteQuery("SELECT * FROM [TableTest]");
154+
155+
table.Rows.Should().HaveCount(1);
156+
157+
table.Rows[0]["Id"].Should().Be(10);
158+
}
93159
}
94160
}

0 commit comments

Comments
 (0)