Skip to content

Commit 2e60ed5

Browse files
authored
Merge pull request #30 from SubSonic-Core/dev/29-asynchronous-support
Dev/29 asynchronous support
2 parents 2a89718 + 11e070e commit 2e60ed5

File tree

70 files changed

+1683
-207
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1683
-207
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Ignore Visual Studio temporary files, build results, and
1+
## Ignore Visual Studio temporary files, build results, and
22
## files generated by popular Visual Studio add-ons.
33

44
# Ignore local web.config as it is built-in automatically
@@ -252,3 +252,5 @@ _Pvt_Extensions
252252
/.vscode/launch.json
253253

254254
# Ignore local nuget sources to force server sources
255+
SubSonic/MyKey.PublicKeyOnly.snk
256+
SubSonic/temp.txt

SubSonic.Extensions.SqlServer/SubSonic.Extensions.SqlServer.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
<PackageLicenseFile>LICENSE.MD</PackageLicenseFile>
1616
<PackageProjectUrl>https://github.com/kccarter76/SubSonic-Core/projects/1</PackageProjectUrl>
1717
<RepositoryUrl>https://github.com/kccarter76/SubSonic-Core/tree/master/SubSonic.Extensions.Test</RepositoryUrl>
18-
<Version>4.1.0-alpha.1</Version>
18+
<Version>4.1.0-alpha.2</Version>
1919
<NeutralLanguage>en</NeutralLanguage>
20+
<SignAssembly>true</SignAssembly>
21+
<DelaySign>false</DelaySign>
22+
<AssemblyOriginatorKeyFile>SubSonicStrongName.snk</AssemblyOriginatorKeyFile>
2023
</PropertyGroup>
2124

2225
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
596 Bytes
Binary file not shown.

SubSonic.Extensions.Test/Data/Procedures/DeleteRealEstateProperty.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace SubSonic.Extensions.Test
88
{
9-
[DbStoredProcedure(nameof(DeleteRealEstateProperty))]
9+
[DbStoredProcedure(nameof(DeleteRealEstateProperty), IsNonQuery = true)]
1010
public class DeleteRealEstateProperty
1111
: DbSubSonicCommandQueryProcedure<Models.RealEstateProperty>
1212
{

SubSonic.Extensions.Test/Extensions/UnitTestingExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public static DataTable ToDataTable<TEntity>(this IEnumerable<TEntity> source)
177177
}
178178
}
179179

180-
public static void AddCommandBehavior<TResult>(this DbProviderFactory factory, string command, Func<DbCommand, TResult> result)
180+
public static void AddCommandBehavior(this DbProviderFactory factory, string command, Func<DbCommand, object> result)
181181
{
182182
if (factory is null)
183183
{

SubSonic.Extensions.Test/MockDbClient/IMockCommandExecution.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5+
using System.Threading;
6+
using System.Threading.Tasks;
57

68
namespace SubSonic.Extensions.Test.MockDbClient
79
{
810
using Syntax;
11+
912
interface IMockCommandExecution
1013
{
1114
int ExecuteNonQuery(MockDbCommand cmd);
1215
object ExecuteScalar(MockDbCommand cmd);
1316
MockDbDataReaderCollection ExecuteDataReader(MockDbCommand cmd);
17+
Task<MockDbDataReaderCollection> ExecuteDataReaderAsync(MockDbCommand cmd, CancellationToken cancellationToken);
1418
}
1519
}

SubSonic.Extensions.Test/MockDbClient/MockDBErrors.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

SubSonic.Extensions.Test/MockDbClient/MockDBErrors.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,7 @@
126126
<data name="MissingDbParameter" xml:space="preserve">
127127
<value>Missing expected db parameter.</value>
128128
</data>
129+
<data name="ResultSetIsNotDataTable" xml:space="preserve">
130+
<value>The return is not of type DataTable.</value>
131+
</data>
129132
</root>

SubSonic.Extensions.Test/MockDbClient/MockDbClientFactory.cs

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.Text;
55
using System.Data;
66
using System.Data.Common;
7+
using System.Threading;
8+
using System.Threading.Tasks;
79

810
namespace SubSonic.Extensions.Test.MockDbClient
911
{
@@ -91,21 +93,88 @@ private MockCommandBehavior FindBehavior(MockDbCommand cmd)
9193

9294
int IMockCommandExecution.ExecuteNonQuery(MockDbCommand cmd)
9395
{
94-
return GetReturnValue<int>(cmd);
96+
if (GetReturnValue<int>(cmd) is int @return)
97+
{
98+
return @return;
99+
}
100+
101+
throw Error.InvalidOperation();
95102
}
96103

97104
object IMockCommandExecution.ExecuteScalar(MockDbCommand cmd)
98105
{
99106
return GetReturnValue<object>(cmd);
100107
}
101108

109+
async Task<MockDbDataReaderCollection> IMockCommandExecution.ExecuteDataReaderAsync(MockDbCommand cmd, CancellationToken cancellationToken)
110+
{
111+
string[] commands = cmd.CommandText.Split(';');
112+
113+
if (commands.Length == 1)
114+
{ // command contains one select command
115+
object value = GetReturnValue<DataTable>(cmd);
116+
117+
if (value is DataTable result)
118+
{
119+
return new MockDbDataReaderCollection(result.CreateDataReader());
120+
}
121+
else if (value is null)
122+
{
123+
return new MockDbDataReaderCollection();
124+
}
125+
else
126+
{
127+
throw Error.InvalidOperation(MockDBErrors.ResultSetIsNotDataTable);
128+
}
129+
}
130+
else
131+
{
132+
using (DataSet data = new DataSet())
133+
{
134+
foreach (string sql in commands)
135+
{
136+
cancellationToken.ThrowIfCancellationRequested();
137+
138+
#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities
139+
#pragma warning disable CA2000 // Dispose objects before losing scope
140+
if (GetReturnValue<DataTable>(new MockDbCommand(this, cmd.Parameters) { CommandText = sql.Trim("\r\n".ToCharArray()) }) is DataTable result)
141+
{
142+
data.Tables.Add(result);
143+
}
144+
#pragma warning restore CA2000 // Dispose objects before losing scope
145+
#pragma warning restore CA2100 // Review SQL queries for security vulnerabilities
146+
}
147+
148+
if (data.Tables.Count == 0)
149+
{
150+
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Could not find behavior for command '{0}'", cmd.CommandText));
151+
}
152+
153+
return new MockDbDataReaderCollection(data.CreateDataReader());
154+
}
155+
}
156+
}
157+
102158
MockDbDataReaderCollection IMockCommandExecution.ExecuteDataReader(MockDbCommand cmd)
103159
{
104160
string[] commands = cmd.CommandText.Split(';');
105161

106162
if (commands.Length == 1)
107163
{ // command contains one select command
108-
return new MockDbDataReaderCollection(GetReturnValue<DataTable>(cmd).IsNotNull(x => x.CreateDataReader()));
164+
object value = GetReturnValue<DataTable>(cmd);
165+
166+
if (value is DataTable result)
167+
{
168+
return new MockDbDataReaderCollection(result.CreateDataReader());
169+
}
170+
else if (value is null)
171+
{
172+
return new MockDbDataReaderCollection();
173+
}
174+
else
175+
{
176+
throw Error.InvalidOperation(MockDBErrors.ResultSetIsNotDataTable);
177+
}
109178
}
110179
else
111180
{
@@ -115,8 +184,7 @@ MockDbDataReaderCollection IMockCommandExecution.ExecuteDataReader(MockDbCommand
115184
{
116185
#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities
117186
#pragma warning disable CA2000 // Dispose objects before losing scope
118-
DataTable result = GetReturnValue<DataTable>(new MockDbCommand(this, cmd.Parameters) { CommandText = sql.Trim("\r\n".ToCharArray()) });
119-
if (!(result is null))
187+
if (GetReturnValue<DataTable>(new MockDbCommand(this, cmd.Parameters) { CommandText = sql.Trim("\r\n".ToCharArray()) }) is DataTable result)
120188
{
121189
data.Tables.Add(result);
122190
}
@@ -134,7 +202,7 @@ MockDbDataReaderCollection IMockCommandExecution.ExecuteDataReader(MockDbCommand
134202
}
135203
}
136204

137-
public TReturn GetReturnValue<TReturn>(MockDbCommand cmd)
205+
public object GetReturnValue<TReturn>(MockDbCommand cmd)
138206
{
139207
if (cmd is null)
140208
{
@@ -150,7 +218,7 @@ public TReturn GetReturnValue<TReturn>(MockDbCommand cmd)
150218

151219
object value = behavior.ReturnValue;
152220

153-
if (value is Func<DbCommand, TReturn> func)
221+
if (value is Func<DbCommand, object> func)
154222
{
155223
return func(cmd);
156224
}

SubSonic.Extensions.Test/MockDbClient/MockDbCommand.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,26 @@ protected override DbDataReader ExecuteDbDataReader(System.Data.CommandBehavior
120120
}
121121
}
122122

123-
protected override Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
123+
protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
124124
{
125+
try
126+
{
127+
if (this.Connection.State == ConnectionState.Open)
128+
{
129+
Prepare();
125130

126-
return Task.Run(() => ExecuteDbDataReader(behavior), cancellationToken);
131+
return await _exec.ExecuteDataReaderAsync(this, cancellationToken)
132+
.ConfigureAwait(false);
133+
}
134+
else
135+
{
136+
throw new InvalidOperationException(MockDBErrors.ConnectionStateNotOpen);
137+
}
138+
}
139+
catch (Exception ex)
140+
{
141+
throw new MockDBException(ex.Message, ex);
142+
}
127143
}
128144

129145
public override int ExecuteNonQuery()

0 commit comments

Comments
 (0)