Skip to content

Commit 12ccbf4

Browse files
ayush3797Ayush Agarwal
and
Ayush Agarwal
authored
Encapsulating multiple dictionaries parsed from DbDataReader handler into a class (#1224)
* Encapsulating multiple dictionaries parsed from DbDataReader into class * fix formatting * addressing review comments * addressing review comments --------- Co-authored-by: Ayush Agarwal <[email protected]>
1 parent 2dd7a96 commit 12ccbf4

File tree

5 files changed

+100
-82
lines changed

5 files changed

+100
-82
lines changed
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Collections.Generic;
5+
6+
namespace Azure.DataApiBuilder.Service.Models
7+
{
8+
/// <summary>
9+
/// Represents a single row read from DbDataReader.
10+
/// </summary>
11+
public class DbOperationResultRow
12+
{
13+
public DbOperationResultRow(
14+
Dictionary<string, object?> columns,
15+
Dictionary<string, object> resultProperties)
16+
{
17+
this.Columns = columns;
18+
this.ResultProperties = resultProperties;
19+
}
20+
21+
/// <summary>
22+
/// Represents a result set row in <c>ColumnName: Value</c> format, empty if no row was found.
23+
/// </summary>
24+
public Dictionary<string, object?> Columns { get; private set; }
25+
26+
/// <summary>
27+
/// Represents DbDataReader properties such as RecordsAffected and HasRows.
28+
/// </summary>
29+
public Dictionary<string, object> ResultProperties { get; private set; }
30+
}
31+
}

src/Service/Resolvers/IQueryExecutor.cs

+10-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Data.Common;
77
using System.Text.Json.Nodes;
88
using System.Threading.Tasks;
9+
using Azure.DataApiBuilder.Service.Models;
910
using Microsoft.AspNetCore.Http;
1011

1112
namespace Azure.DataApiBuilder.Service.Resolvers
@@ -30,7 +31,7 @@ public interface IQueryExecutor
3031
public Task<TResult?> ExecuteQueryAsync<TResult>(
3132
string sqltext,
3233
IDictionary<string, object?> parameters,
33-
Func<DbDataReader, List<string>?, Task<TResult?>>? dataReaderHandler,
34+
Func<DbDataReader, List<string>?, Task<TResult>>? dataReaderHandler,
3435
HttpContext? httpContext = null,
3536
List<string>? args = null);
3637

@@ -41,7 +42,7 @@ public interface IQueryExecutor
4142
/// <param name="dbDataReader">A DbDataReader.</param>
4243
/// <param name="args">List of string arguments if any.</param>
4344
/// <returns>A JsonArray with each element corresponding to the row (ColumnName : columnValue) in the dbDataReader.</returns>
44-
public Task<JsonArray?> GetJsonArrayAsync(
45+
public Task<JsonArray> GetJsonArrayAsync(
4546
DbDataReader dbDataReader,
4647
List<string>? args = null);
4748

@@ -62,10 +63,8 @@ public interface IQueryExecutor
6263
/// </summary>
6364
/// <param name="dbDataReader">A DbDataReader</param>
6465
/// <param name="args">List of columns to extract. Extracts all if unspecified.</param>
65-
/// <returns>A tuple of 2 dictionaries:
66-
/// 1. A dictionary representing the row in <c>ColumnName: Value</c> format, null if no row was found
67-
/// 2. A dictionary of properties of the Db Data Reader like RecordsAffected, HasRows.</returns>
68-
public Task<Tuple<Dictionary<string, object?>?, Dictionary<string, object>>?> ExtractRowFromDbDataReader(
66+
/// <returns>Single row read from DbDataReader.</returns>
67+
public Task<DbOperationResultRow> ExtractRowFromDbDataReader(
6968
DbDataReader dbDataReader,
7069
List<string>? args = null);
7170

@@ -76,11 +75,10 @@ public interface IQueryExecutor
7675
/// </summary>
7776
/// <param name="dbDataReader">A DbDataReader.</param>
7877
/// <param name="args">The arguments to this handler - args[0] = primary key in pretty format, args[1] = entity name.</param>
79-
/// <returns>A tuple of 2 dictionaries:
80-
/// 1. A dictionary representing the row in <c>ColumnName: Value</c> format.
81-
/// 2. A dictionary of properties of the DbDataReader like RecordsAffected, HasRows.
82-
/// If the first result set is being returned, has the property "IsFirstResultSet" set to true in this dictionary.</returns>
83-
public Task<Tuple<Dictionary<string, object?>?, Dictionary<string, object>>?> GetMultipleResultSetsIfAnyAsync(
78+
/// <returns>Single row read from DbDataReader.
79+
/// If the first result set is being returned, DbOperationResultRow.ResultProperties dictionary has
80+
/// the property "IsFirstResultSet" set to true.</returns>
81+
public Task<DbOperationResultRow> GetMultipleResultSetsIfAnyAsync(
8482
DbDataReader dbDataReader,
8583
List<string>? args = null);
8684

@@ -90,7 +88,7 @@ public interface IQueryExecutor
9088
/// <param name="dbDataReader">A DbDataReader.</param>
9189
/// <param name="args">List of string arguments if any.</param>
9290
/// <returns>A dictionary of properties of the DbDataReader like RecordsAffected, HasRows.</returns>
93-
public Task<Dictionary<string, object>?> GetResultProperties(
91+
public Task<Dictionary<string, object>> GetResultProperties(
9492
DbDataReader dbDataReader,
9593
List<string>? args = null);
9694

src/Service/Resolvers/QueryExecutor.cs

+29-33
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Threading.Tasks;
1313
using Azure.DataApiBuilder.Service.Configurations;
1414
using Azure.DataApiBuilder.Service.Exceptions;
15+
using Azure.DataApiBuilder.Service.Models;
1516
using Microsoft.AspNetCore.Http;
1617
using Microsoft.Extensions.Logging;
1718
using Polly;
@@ -62,7 +63,7 @@ public QueryExecutor(DbExceptionParser dbExceptionParser,
6263
public virtual async Task<TResult?> ExecuteQueryAsync<TResult>(
6364
string sqltext,
6465
IDictionary<string, object?> parameters,
65-
Func<DbDataReader, List<string>?, Task<TResult?>>? dataReaderHandler,
66+
Func<DbDataReader, List<string>?, Task<TResult>>? dataReaderHandler,
6667
HttpContext? httpContext = null,
6768
List<string>? args = null)
6869
{
@@ -134,7 +135,7 @@ await ExecuteQueryAgainstDbAsync(conn,
134135
TConnection conn,
135136
string sqltext,
136137
IDictionary<string, object?> parameters,
137-
Func<DbDataReader, List<string>?, Task<TResult?>>? dataReaderHandler,
138+
Func<DbDataReader, List<string>?, Task<TResult>>? dataReaderHandler,
138139
HttpContext? httpContext,
139140
List<string>? args = null)
140141
{
@@ -208,20 +209,20 @@ public async Task<bool> ReadAsync(DbDataReader reader)
208209
}
209210

210211
/// <inheritdoc />
211-
public async Task<Tuple<Dictionary<string, object?>?, Dictionary<string, object>>?>
212+
public async Task<DbOperationResultRow>
212213
ExtractRowFromDbDataReader(DbDataReader dbDataReader, List<string>? args = null)
213214
{
214-
Dictionary<string, object?> row = new();
215-
216-
Dictionary<string, object> propertiesOfResult = GetResultProperties(dbDataReader).Result ?? new();
215+
DbOperationResultRow dbOperationResultRow = new(
216+
columns: new(),
217+
resultProperties: GetResultProperties(dbDataReader).Result ?? new());
217218

218219
if (await ReadAsync(dbDataReader))
219220
{
220221
if (dbDataReader.HasRows)
221222
{
222223
DataTable? schemaTable = dbDataReader.GetSchemaTable();
223224

224-
if (schemaTable != null)
225+
if (schemaTable is not null)
225226
{
226227
foreach (DataRow schemaRow in schemaTable.Rows)
227228
{
@@ -235,43 +236,37 @@ public async Task<bool> ReadAsync(DbDataReader reader)
235236
int colIndex = dbDataReader.GetOrdinal(columnName);
236237
if (!dbDataReader.IsDBNull(colIndex))
237238
{
238-
row.Add(columnName, dbDataReader[columnName]);
239+
dbOperationResultRow.Columns.Add(columnName, dbDataReader[columnName]);
239240
}
240241
else
241242
{
242-
row.Add(columnName, value: null);
243+
dbOperationResultRow.Columns.Add(columnName, value: null);
243244
}
244245
}
245246
}
246247
}
247248
}
248249

249-
// no row was read
250-
if (row.Count == 0)
251-
{
252-
return new Tuple<Dictionary<string, object?>?, Dictionary<string, object>>(null, propertiesOfResult);
253-
}
254-
255-
return new Tuple<Dictionary<string, object?>?, Dictionary<string, object>>(row, propertiesOfResult);
250+
return dbOperationResultRow;
256251
}
257252

258253
/// <inheritdoc />
259254
/// <Note>This function is a DbDataReader handler of type Func<DbDataReader, List<string>?, Task<TResult?>>
260255
/// The parameter args is not used but is added to conform to the signature of the DbDataReader handler
261256
/// function argument of ExecuteQueryAsync.</Note>
262-
public async Task<JsonArray?> GetJsonArrayAsync(
257+
public async Task<JsonArray> GetJsonArrayAsync(
263258
DbDataReader dbDataReader,
264259
List<string>? args = null)
265260
{
266-
Tuple<Dictionary<string, object?>?, Dictionary<string, object>>? resultRowAndProperties;
261+
DbOperationResultRow dbOperationResultRow = await ExtractRowFromDbDataReader(dbDataReader);
267262
JsonArray resultArray = new();
268263

269-
while ((resultRowAndProperties = await ExtractRowFromDbDataReader(dbDataReader)) is not null &&
270-
resultRowAndProperties.Item1 is not null)
264+
while (dbOperationResultRow.Columns.Count > 0)
271265
{
272266
JsonElement result =
273-
JsonSerializer.Deserialize<JsonElement>(JsonSerializer.Serialize(resultRowAndProperties.Item1));
267+
JsonSerializer.Deserialize<JsonElement>(JsonSerializer.Serialize(dbOperationResultRow.Columns));
274268
resultArray.Add(result);
269+
dbOperationResultRow = await ExtractRowFromDbDataReader(dbDataReader);
275270
}
276271

277272
return resultArray;
@@ -306,21 +301,20 @@ public async Task<bool> ReadAsync(DbDataReader reader)
306301
/// <inheritdoc />
307302
/// <Note>This function is a DbDataReader handler of type
308303
/// Func<DbDataReader, List<string>?, Task<TResult?>></Note>
309-
public async Task<Tuple<Dictionary<string, object?>?, Dictionary<string, object>>?> GetMultipleResultSetsIfAnyAsync(
304+
public async Task<DbOperationResultRow> GetMultipleResultSetsIfAnyAsync(
310305
DbDataReader dbDataReader, List<string>? args = null)
311306
{
312-
Tuple<Dictionary<string, object?>?, Dictionary<string, object>>? resultRecordWithProperties
307+
DbOperationResultRow dbOperationResultRow
313308
= await ExtractRowFromDbDataReader(dbDataReader);
314309

315310
/// Processes a second result set from DbDataReader if it exists.
316311
/// In MsSQL upsert:
317312
/// result set #1: result of the UPDATE operation.
318313
/// result set #2: result of the INSERT operation.
319-
if (resultRecordWithProperties is not null && resultRecordWithProperties.Item1 is not null)
314+
if (dbOperationResultRow.Columns.Count > 0)
320315
{
321-
resultRecordWithProperties.Item2.Add(SqlMutationEngine.IS_FIRST_RESULT_SET, true);
322-
return new Tuple<Dictionary<string, object?>?, Dictionary<string, object>>
323-
(resultRecordWithProperties.Item1, resultRecordWithProperties.Item2);
316+
dbOperationResultRow.ResultProperties.Add(SqlMutationEngine.IS_FIRST_RESULT_SET, true);
317+
return dbOperationResultRow;
324318
}
325319
else if (await dbDataReader.NextResultAsync())
326320
{
@@ -345,20 +339,22 @@ public async Task<bool> ReadAsync(DbDataReader reader)
345339
}
346340
}
347341

348-
return null;
342+
return dbOperationResultRow;
349343
}
350344

351345
/// <inheritdoc />
352346
/// <Note>This function is a DbDataReader handler of type
353347
/// Func<DbDataReader, List<string>?, Task<TResult?>></Note>
354-
public Task<Dictionary<string, object>?> GetResultProperties(
348+
public Task<Dictionary<string, object>> GetResultProperties(
355349
DbDataReader dbDataReader,
356350
List<string>? columnNames = null)
357351
{
358-
Dictionary<string, object>? propertiesOfResult = new();
359-
propertiesOfResult.Add(nameof(dbDataReader.RecordsAffected), dbDataReader.RecordsAffected);
360-
propertiesOfResult.Add(nameof(dbDataReader.HasRows), dbDataReader.HasRows);
361-
return Task.FromResult((Dictionary<string, object>?)propertiesOfResult);
352+
Dictionary<string, object> resultProperties = new()
353+
{
354+
{ nameof(dbDataReader.RecordsAffected), dbDataReader.RecordsAffected },
355+
{ nameof(dbDataReader.HasRows), dbDataReader.HasRows }
356+
};
357+
return Task.FromResult(resultProperties);
362358
}
363359

364360
private async Task<string> GetJsonStringFromDbReader(DbDataReader dbDataReader)

0 commit comments

Comments
 (0)