From ec28d407890a685eada7c8d7c93e004cef533dca Mon Sep 17 00:00:00 2001 From: Ayush Agarwal Date: Tue, 14 Feb 2023 11:34:55 +0530 Subject: [PATCH 1/5] Encapsulating multiple dictionaries parsed from DbDataReader into class --- src/Service/Models/DbOperationResultRow.cs | 30 ++++++++++ src/Service/Resolvers/IQueryExecutor.cs | 20 +++---- src/Service/Resolvers/QueryExecutor.cs | 58 +++++++++---------- src/Service/Resolvers/SqlMutationEngine.cs | 41 ++++++------- .../MetadataProviders/SqlMetadataProvider.cs | 7 ++- 5 files changed, 89 insertions(+), 67 deletions(-) create mode 100644 src/Service/Models/DbOperationResultRow.cs diff --git a/src/Service/Models/DbOperationResultRow.cs b/src/Service/Models/DbOperationResultRow.cs new file mode 100644 index 0000000000..c406f5215f --- /dev/null +++ b/src/Service/Models/DbOperationResultRow.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Generic; + +namespace Azure.DataApiBuilder.Service.Models +{ + /// + /// Represents a single row read from DbDataReader. + /// + public class DbOperationResultRow + { + public DbOperationResultRow( + Dictionary row, + Dictionary propertiesOfResult){ + this.Row = row; + this.PropertiesOfResult = propertiesOfResult; + } + + /// + /// A dictionary representing the row in ColumnName: Value format, empty if no row was found. + /// + public Dictionary Row { get; set; } + + /// + /// A dictionary of properties of the DbDataReader like RecordsAffected, HasRows. + /// + public Dictionary PropertiesOfResult { get; set; } + } +} diff --git a/src/Service/Resolvers/IQueryExecutor.cs b/src/Service/Resolvers/IQueryExecutor.cs index b967ff5f84..52e8d7aab2 100644 --- a/src/Service/Resolvers/IQueryExecutor.cs +++ b/src/Service/Resolvers/IQueryExecutor.cs @@ -6,6 +6,7 @@ using System.Data.Common; using System.Text.Json.Nodes; using System.Threading.Tasks; +using Azure.DataApiBuilder.Service.Models; using Microsoft.AspNetCore.Http; namespace Azure.DataApiBuilder.Service.Resolvers @@ -30,7 +31,7 @@ public interface IQueryExecutor public Task ExecuteQueryAsync( string sqltext, IDictionary parameters, - Func?, Task>? dataReaderHandler, + Func?, Task>? dataReaderHandler, HttpContext? httpContext = null, List? args = null); @@ -41,7 +42,7 @@ public interface IQueryExecutor /// A DbDataReader. /// List of string arguments if any. /// A JsonArray with each element corresponding to the row (ColumnName : columnValue) in the dbDataReader. - public Task GetJsonArrayAsync( + public Task GetJsonArrayAsync( DbDataReader dbDataReader, List? args = null); @@ -62,10 +63,8 @@ public interface IQueryExecutor /// /// A DbDataReader /// List of columns to extract. Extracts all if unspecified. - /// A tuple of 2 dictionaries: - /// 1. A dictionary representing the row in ColumnName: Value format, null if no row was found - /// 2. A dictionary of properties of the Db Data Reader like RecordsAffected, HasRows. - public Task?, Dictionary>?> ExtractRowFromDbDataReader( + /// Single row read from DbDataReader. + public Task ExtractRowFromDbDataReader( DbDataReader dbDataReader, List? args = null); @@ -76,11 +75,10 @@ public interface IQueryExecutor /// /// A DbDataReader. /// The arguments to this handler - args[0] = primary key in pretty format, args[1] = entity name. - /// A tuple of 2 dictionaries: - /// 1. A dictionary representing the row in ColumnName: Value format. - /// 2. A dictionary of properties of the DbDataReader like RecordsAffected, HasRows. - /// If the first result set is being returned, has the property "IsFirstResultSet" set to true in this dictionary. - public Task?, Dictionary>?> GetMultipleResultSetsIfAnyAsync( + /// Single row read from DbDataReader. + /// If the first result set is being returned, DbOperationResultRow.PropertiesOfResult dictionary has + /// the property "IsFirstResultSet" set to true. + public Task GetMultipleResultSetsIfAnyAsync( DbDataReader dbDataReader, List? args = null); diff --git a/src/Service/Resolvers/QueryExecutor.cs b/src/Service/Resolvers/QueryExecutor.cs index e506826484..424fb1cd61 100644 --- a/src/Service/Resolvers/QueryExecutor.cs +++ b/src/Service/Resolvers/QueryExecutor.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Azure.DataApiBuilder.Service.Configurations; using Azure.DataApiBuilder.Service.Exceptions; +using Azure.DataApiBuilder.Service.Models; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Polly; @@ -62,7 +63,7 @@ public QueryExecutor(DbExceptionParser dbExceptionParser, public virtual async Task ExecuteQueryAsync( string sqltext, IDictionary parameters, - Func?, Task>? dataReaderHandler, + Func?, Task>? dataReaderHandler, HttpContext? httpContext = null, List? args = null) { @@ -134,7 +135,7 @@ await ExecuteQueryAgainstDbAsync(conn, TConnection conn, string sqltext, IDictionary parameters, - Func?, Task>? dataReaderHandler, + Func?, Task>? dataReaderHandler, HttpContext? httpContext, List? args = null) { @@ -208,12 +209,12 @@ public async Task ReadAsync(DbDataReader reader) } /// - public async Task?, Dictionary>?> + public async Task ExtractRowFromDbDataReader(DbDataReader dbDataReader, List? args = null) { - Dictionary row = new(); - - Dictionary propertiesOfResult = GetResultProperties(dbDataReader).Result ?? new(); + DbOperationResultRow dbOperationResultRow = new( + row: new(), + propertiesOfResult: GetResultProperties(dbDataReader).Result ?? new()); if (await ReadAsync(dbDataReader)) { @@ -221,7 +222,7 @@ public async Task ReadAsync(DbDataReader reader) { DataTable? schemaTable = dbDataReader.GetSchemaTable(); - if (schemaTable != null) + if (schemaTable is not null) { foreach (DataRow schemaRow in schemaTable.Rows) { @@ -235,43 +236,37 @@ public async Task ReadAsync(DbDataReader reader) int colIndex = dbDataReader.GetOrdinal(columnName); if (!dbDataReader.IsDBNull(colIndex)) { - row.Add(columnName, dbDataReader[columnName]); + dbOperationResultRow.Row.Add(columnName, dbDataReader[columnName]); } else { - row.Add(columnName, value: null); + dbOperationResultRow.Row.Add(columnName, value: null); } } } } } - // no row was read - if (row.Count == 0) - { - return new Tuple?, Dictionary>(null, propertiesOfResult); - } - - return new Tuple?, Dictionary>(row, propertiesOfResult); + return dbOperationResultRow; } /// /// This function is a DbDataReader handler of type Func?, Task> /// The parameter args is not used but is added to conform to the signature of the DbDataReader handler /// function argument of ExecuteQueryAsync. - public async Task GetJsonArrayAsync( + public async Task GetJsonArrayAsync( DbDataReader dbDataReader, List? args = null) { - Tuple?, Dictionary>? resultRowAndProperties; + DbOperationResultRow dbOperationResultRow = await ExtractRowFromDbDataReader(dbDataReader); JsonArray resultArray = new(); - while ((resultRowAndProperties = await ExtractRowFromDbDataReader(dbDataReader)) is not null && - resultRowAndProperties.Item1 is not null) + while (dbOperationResultRow.Row.Count > 0) { JsonElement result = - JsonSerializer.Deserialize(JsonSerializer.Serialize(resultRowAndProperties.Item1)); + JsonSerializer.Deserialize(JsonSerializer.Serialize(dbOperationResultRow.Row)); resultArray.Add(result); + dbOperationResultRow = await ExtractRowFromDbDataReader(dbDataReader); } return resultArray; @@ -306,21 +301,20 @@ public async Task ReadAsync(DbDataReader reader) /// /// This function is a DbDataReader handler of type /// Func?, Task> - public async Task?, Dictionary>?> GetMultipleResultSetsIfAnyAsync( + public async Task GetMultipleResultSetsIfAnyAsync( DbDataReader dbDataReader, List? args = null) { - Tuple?, Dictionary>? resultRecordWithProperties + DbOperationResultRow dbOperationResultRow = await ExtractRowFromDbDataReader(dbDataReader); /// Processes a second result set from DbDataReader if it exists. /// In MsSQL upsert: /// result set #1: result of the UPDATE operation. /// result set #2: result of the INSERT operation. - if (resultRecordWithProperties is not null && resultRecordWithProperties.Item1 is not null) + if (dbOperationResultRow.Row.Count > 0) { - resultRecordWithProperties.Item2.Add(SqlMutationEngine.IS_FIRST_RESULT_SET, true); - return new Tuple?, Dictionary> - (resultRecordWithProperties.Item1, resultRecordWithProperties.Item2); + dbOperationResultRow.PropertiesOfResult.Add(SqlMutationEngine.IS_FIRST_RESULT_SET, true); + return dbOperationResultRow; } else if (await dbDataReader.NextResultAsync()) { @@ -345,7 +339,7 @@ public async Task ReadAsync(DbDataReader reader) } } - return null; + return dbOperationResultRow; } /// @@ -355,9 +349,11 @@ public async Task ReadAsync(DbDataReader reader) DbDataReader dbDataReader, List? columnNames = null) { - Dictionary? propertiesOfResult = new(); - propertiesOfResult.Add(nameof(dbDataReader.RecordsAffected), dbDataReader.RecordsAffected); - propertiesOfResult.Add(nameof(dbDataReader.HasRows), dbDataReader.HasRows); + Dictionary propertiesOfResult = new() + { + { nameof(dbDataReader.RecordsAffected), dbDataReader.RecordsAffected }, + { nameof(dbDataReader.HasRows), dbDataReader.HasRows } + }; return Task.FromResult((Dictionary?)propertiesOfResult); } diff --git a/src/Service/Resolvers/SqlMutationEngine.cs b/src/Service/Resolvers/SqlMutationEngine.cs index fd7bee2843..069dfeb516 100644 --- a/src/Service/Resolvers/SqlMutationEngine.cs +++ b/src/Service/Resolvers/SqlMutationEngine.cs @@ -117,14 +117,14 @@ await PerformDeleteOperation( } else { - Tuple?, Dictionary>? resultRowAndProperties = + DbOperationResultRow? mutationResult = await PerformMutationOperation( entityName, mutationOperation, parameters, context); - if (resultRowAndProperties is not null && resultRowAndProperties.Item1 is not null + if (mutationResult is not null && mutationResult.Row.Count > 0 && !context.Selection.Type.IsScalarType()) { // Because the GraphQL mutation result set columns were exposed (mapped) column names, @@ -133,7 +133,7 @@ await PerformMutationOperation( // represent database column names. result = await _queryEngine.ExecuteAsync( context, - GetBackingColumnsFromCollection(entityName, resultRowAndProperties.Item1)); + GetBackingColumnsFromCollection(entityName, mutationResult.Row)); } } @@ -287,18 +287,17 @@ await PerformDeleteOperation( } else if (context.OperationType is Config.Operation.Upsert || context.OperationType is Config.Operation.UpsertIncremental) { - Tuple?, Dictionary>? resultRowAndProperties = + DbOperationResultRow? upsertOperationResult = await PerformUpsertOperation( parameters, context); - if (resultRowAndProperties is not null && - resultRowAndProperties.Item1 is not null) + if (upsertOperationResult is not null && upsertOperationResult.Row.Count > 0) { - Dictionary resultRow = resultRowAndProperties.Item1; + Dictionary resultRow = upsertOperationResult.Row; bool isFirstResultSet = false; - if (resultRowAndProperties.Item2.TryGetValue(IS_FIRST_RESULT_SET, out object? isFirstResultSetValue)) + if (upsertOperationResult.PropertiesOfResult.TryGetValue(IS_FIRST_RESULT_SET, out object? isFirstResultSetValue)) { isFirstResultSet = Convert.ToBoolean(isFirstResultSetValue); } @@ -320,7 +319,7 @@ await PerformUpsertOperation( } else { - Tuple?, Dictionary>? resultRowAndProperties = + DbOperationResultRow? mutationResult = await PerformMutationOperation( context.EntityName, context.OperationType, @@ -328,14 +327,14 @@ await PerformMutationOperation( if (context.OperationType is Config.Operation.Insert) { - if (resultRowAndProperties is null || resultRowAndProperties.Item1 is null) + if (mutationResult is null || mutationResult.Row.Count == 0) { // this case should not happen, we throw an exception // which will be returned as an Unexpected Internal Server Error throw new Exception(); } - Dictionary resultRow = resultRowAndProperties.Item1; + Dictionary resultRow = mutationResult.Row; string primaryKeyRoute = ConstructPrimaryKeyRoute(context, resultRow); // location will be updated in rest controller where httpcontext is available return new CreatedResult(location: primaryKeyRoute, OkMutationResponse(resultRow).Value); @@ -344,9 +343,7 @@ await PerformMutationOperation( if (context.OperationType is Config.Operation.Update || context.OperationType is Config.Operation.UpdateIncremental) { // Nothing to update means we throw Exception - if (resultRowAndProperties is null || - resultRowAndProperties.Item1 is null || - resultRowAndProperties.Item1.Count == 0) + if (mutationResult is null || mutationResult.Row.Count == 0) { throw new DataApiBuilderException(message: "No Update could be performed, record not found", statusCode: HttpStatusCode.PreconditionFailed, @@ -354,7 +351,7 @@ resultRowAndProperties.Item1 is null || } // Valid REST updates return OkObjectResult - return OkMutationResponse(resultRowAndProperties.Item1); + return OkMutationResponse(mutationResult.Row); } } @@ -416,7 +413,7 @@ private static OkObjectResult OkMutationResponse(JsonElement jsonResult) /// A tuple of 2 dictionaries: /// 1. A dictionary representing the row in ColumnName: Value format, null if no row is mutated. /// 2. A dictionary of properties of the Db Data Reader like RecordsAffected, HasRows. - private async Task?, Dictionary>?> + private async Task PerformMutationOperation( string entityName, Config.Operation operationType, @@ -493,7 +490,7 @@ private static OkObjectResult OkMutationResponse(JsonElement jsonResult) throw new NotSupportedException($"Unexpected mutation operation \" {operationType}\" requested."); } - Tuple?, Dictionary>? resultRecord = null; + DbOperationResultRow? dbOperationResultRow; if (context is not null && !context.Selection.Type.IsScalarType()) { @@ -517,7 +514,7 @@ private static OkObjectResult OkMutationResponse(JsonElement jsonResult) // which would fail to get the mutated entry from the db // When no exposed column names were resolved, it is safe to provide // backing column names (sourceDefinition.Primary) as a list of arguments. - resultRecord = + dbOperationResultRow = await _queryExecutor.ExecuteQueryAsync( queryString, queryParameters, @@ -525,7 +522,7 @@ await _queryExecutor.ExecuteQueryAsync( _httpContextAccessor.HttpContext!, primaryKeyExposedColumnNames.Count > 0 ? primaryKeyExposedColumnNames : sourceDefinition.PrimaryKey); - if (resultRecord is not null && resultRecord.Item1 is null) + if (dbOperationResultRow is not null && dbOperationResultRow.Row.Count == 0) { string searchedPK; if (primaryKeyExposedColumnNames.Count > 0) @@ -547,7 +544,7 @@ await _queryExecutor.ExecuteQueryAsync( { // This is the scenario for all REST mutation operations covered by this function // and the case when the Selection Type is a scalar for GraphQL. - resultRecord = + dbOperationResultRow = await _queryExecutor.ExecuteQueryAsync( queryString, queryParameters, @@ -555,7 +552,7 @@ await _queryExecutor.ExecuteQueryAsync( _httpContextAccessor.HttpContext!); } - return resultRecord; + return dbOperationResultRow; } /// @@ -608,7 +605,7 @@ private async Task?> /// A tuple of 2 dictionaries: /// 1. A dictionary representing the row in ColumnName: Value format, null if no row was found /// 2. A dictionary of properties of the Db Data Reader like RecordsAffected, HasRows. - private async Task?, Dictionary>?> + private async Task PerformUpsertOperation( IDictionary parameters, RestRequestContext context) diff --git a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs index dc0d0f636c..a4b441ed90 100644 --- a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs +++ b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs @@ -15,6 +15,7 @@ using Azure.DataApiBuilder.Config; using Azure.DataApiBuilder.Service.Configurations; using Azure.DataApiBuilder.Service.Exceptions; +using Azure.DataApiBuilder.Service.Models; using Azure.DataApiBuilder.Service.Parsers; using Azure.DataApiBuilder.Service.Resolvers; using Microsoft.Extensions.Logging; @@ -1364,13 +1365,13 @@ private async Task?> // 1. the first row extracted from the result // 2. Dictionary of the DbDataReader properties like RecordsAffected, HasRows. // This function only requires the result row i.e. Item1 from the tuple. - Tuple?, Dictionary>? foreignKeyInfoWithProperties = + DbOperationResultRow foreignKeyInfoWithProperties = await QueryExecutor.ExtractRowFromDbDataReader(reader); Dictionary pairToFkDefinition = new(); - while (foreignKeyInfoWithProperties is not null && foreignKeyInfoWithProperties.Item1 is not null) + while (foreignKeyInfoWithProperties.Row.Count > 0) { - Dictionary foreignKeyInfo = foreignKeyInfoWithProperties.Item1; + Dictionary foreignKeyInfo = foreignKeyInfoWithProperties.Row; string referencingSchemaName = (string)foreignKeyInfo[$"Referencing{nameof(DatabaseObject.SchemaName)}"]!; string referencingTableName = (string)foreignKeyInfo[$"Referencing{nameof(SourceDefinition)}"]!; From 144d75619acbc4e96fe152a0619af078c01218b1 Mon Sep 17 00:00:00 2001 From: Ayush Agarwal Date: Tue, 14 Feb 2023 12:10:32 +0530 Subject: [PATCH 2/5] fix formatting --- src/Service/Models/DbOperationResultRow.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Service/Models/DbOperationResultRow.cs b/src/Service/Models/DbOperationResultRow.cs index c406f5215f..bc8d3a1436 100644 --- a/src/Service/Models/DbOperationResultRow.cs +++ b/src/Service/Models/DbOperationResultRow.cs @@ -12,7 +12,8 @@ public class DbOperationResultRow { public DbOperationResultRow( Dictionary row, - Dictionary propertiesOfResult){ + Dictionary propertiesOfResult) + { this.Row = row; this.PropertiesOfResult = propertiesOfResult; } From 2afd8c4fcb7c0204c23d77363f581331663615d0 Mon Sep 17 00:00:00 2001 From: Ayush Agarwal Date: Wed, 15 Feb 2023 13:48:43 +0530 Subject: [PATCH 3/5] addressing review comments --- src/Service/Models/DbOperationResultRow.cs | 4 ++-- src/Service/Resolvers/SqlMutationEngine.cs | 8 ++------ .../Services/MetadataProviders/SqlMetadataProvider.cs | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Service/Models/DbOperationResultRow.cs b/src/Service/Models/DbOperationResultRow.cs index bc8d3a1436..d82fe35f60 100644 --- a/src/Service/Models/DbOperationResultRow.cs +++ b/src/Service/Models/DbOperationResultRow.cs @@ -21,11 +21,11 @@ public DbOperationResultRow( /// /// A dictionary representing the row in ColumnName: Value format, empty if no row was found. /// - public Dictionary Row { get; set; } + public Dictionary Row { get; private set; } /// /// A dictionary of properties of the DbDataReader like RecordsAffected, HasRows. /// - public Dictionary PropertiesOfResult { get; set; } + public Dictionary PropertiesOfResult { get; private set; } } } diff --git a/src/Service/Resolvers/SqlMutationEngine.cs b/src/Service/Resolvers/SqlMutationEngine.cs index 069dfeb516..337b77d6b4 100644 --- a/src/Service/Resolvers/SqlMutationEngine.cs +++ b/src/Service/Resolvers/SqlMutationEngine.cs @@ -410,9 +410,7 @@ private static OkObjectResult OkMutationResponse(JsonElement jsonResult) /// This cannot be Delete, Upsert or UpsertIncremental since those operations have dedicated functions. /// The parameters of the mutation query. /// In the case of GraphQL, the HotChocolate library's middleware context. - /// A tuple of 2 dictionaries: - /// 1. A dictionary representing the row in ColumnName: Value format, null if no row is mutated. - /// 2. A dictionary of properties of the Db Data Reader like RecordsAffected, HasRows. + /// Single row read from DbDataReader. private async Task PerformMutationOperation( string entityName, @@ -602,9 +600,7 @@ private async Task?> /// /// The parameters for the mutation query. /// The REST request context. - /// A tuple of 2 dictionaries: - /// 1. A dictionary representing the row in ColumnName: Value format, null if no row was found - /// 2. A dictionary of properties of the Db Data Reader like RecordsAffected, HasRows. + /// Single row read from DbDataReader. private async Task PerformUpsertOperation( IDictionary parameters, diff --git a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs index a4b441ed90..8eeacefde6 100644 --- a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs +++ b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs @@ -1361,10 +1361,10 @@ private static void ValidateAllFkHaveBeenInferred( private async Task?> SummarizeFkMetadata(DbDataReader reader, List? args = null) { - // Gets a tuple of 2 dictionaries: + // Gets a single row read from DbDataReader which contains 2 dictionaries: // 1. the first row extracted from the result // 2. Dictionary of the DbDataReader properties like RecordsAffected, HasRows. - // This function only requires the result row i.e. Item1 from the tuple. + // This function only requires the result row i.e.the first dictionary. DbOperationResultRow foreignKeyInfoWithProperties = await QueryExecutor.ExtractRowFromDbDataReader(reader); From dff673970d46dd38c5f8abe3d6197917e9f06320 Mon Sep 17 00:00:00 2001 From: Ayush Agarwal Date: Thu, 16 Feb 2023 11:34:11 +0530 Subject: [PATCH 4/5] addressing review comments --- src/Service/Models/DbOperationResultRow.cs | 16 ++++++------- src/Service/Resolvers/IQueryExecutor.cs | 2 +- src/Service/Resolvers/QueryExecutor.cs | 20 ++++++++-------- src/Service/Resolvers/SqlMutationEngine.cs | 24 +++++++++---------- .../MetadataProviders/SqlMetadataProvider.cs | 6 ++--- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/Service/Models/DbOperationResultRow.cs b/src/Service/Models/DbOperationResultRow.cs index d82fe35f60..1e21aaea8c 100644 --- a/src/Service/Models/DbOperationResultRow.cs +++ b/src/Service/Models/DbOperationResultRow.cs @@ -11,21 +11,21 @@ namespace Azure.DataApiBuilder.Service.Models public class DbOperationResultRow { public DbOperationResultRow( - Dictionary row, - Dictionary propertiesOfResult) + Dictionary columns, + Dictionary resultProperties) { - this.Row = row; - this.PropertiesOfResult = propertiesOfResult; + this.Columns = columns; + this.ResultProperties = resultProperties; } /// - /// A dictionary representing the row in ColumnName: Value format, empty if no row was found. + /// Represents a result set row in ColumnName: Value format, empty if no row was found. /// - public Dictionary Row { get; private set; } + public Dictionary Columns { get; private set; } /// - /// A dictionary of properties of the DbDataReader like RecordsAffected, HasRows. + /// Represents DbDataReader properties such as RecordsAffected and HasRows. /// - public Dictionary PropertiesOfResult { get; private set; } + public Dictionary ResultProperties { get; private set; } } } diff --git a/src/Service/Resolvers/IQueryExecutor.cs b/src/Service/Resolvers/IQueryExecutor.cs index 52e8d7aab2..9713609de1 100644 --- a/src/Service/Resolvers/IQueryExecutor.cs +++ b/src/Service/Resolvers/IQueryExecutor.cs @@ -76,7 +76,7 @@ public Task ExtractRowFromDbDataReader( /// A DbDataReader. /// The arguments to this handler - args[0] = primary key in pretty format, args[1] = entity name. /// Single row read from DbDataReader. - /// If the first result set is being returned, DbOperationResultRow.PropertiesOfResult dictionary has + /// If the first result set is being returned, DbOperationResultRow.ResultProperties dictionary has /// the property "IsFirstResultSet" set to true. public Task GetMultipleResultSetsIfAnyAsync( DbDataReader dbDataReader, diff --git a/src/Service/Resolvers/QueryExecutor.cs b/src/Service/Resolvers/QueryExecutor.cs index 424fb1cd61..af557efb88 100644 --- a/src/Service/Resolvers/QueryExecutor.cs +++ b/src/Service/Resolvers/QueryExecutor.cs @@ -213,8 +213,8 @@ public async Task ExtractRowFromDbDataReader(DbDataReader dbDataReader, List? args = null) { DbOperationResultRow dbOperationResultRow = new( - row: new(), - propertiesOfResult: GetResultProperties(dbDataReader).Result ?? new()); + columns: new(), + resultProperties: GetResultProperties(dbDataReader).Result ?? new()); if (await ReadAsync(dbDataReader)) { @@ -236,11 +236,11 @@ public async Task int colIndex = dbDataReader.GetOrdinal(columnName); if (!dbDataReader.IsDBNull(colIndex)) { - dbOperationResultRow.Row.Add(columnName, dbDataReader[columnName]); + dbOperationResultRow.Columns.Add(columnName, dbDataReader[columnName]); } else { - dbOperationResultRow.Row.Add(columnName, value: null); + dbOperationResultRow.Columns.Add(columnName, value: null); } } } @@ -261,10 +261,10 @@ public async Task GetJsonArrayAsync( DbOperationResultRow dbOperationResultRow = await ExtractRowFromDbDataReader(dbDataReader); JsonArray resultArray = new(); - while (dbOperationResultRow.Row.Count > 0) + while (dbOperationResultRow.Columns.Count > 0) { JsonElement result = - JsonSerializer.Deserialize(JsonSerializer.Serialize(dbOperationResultRow.Row)); + JsonSerializer.Deserialize(JsonSerializer.Serialize(dbOperationResultRow.Columns)); resultArray.Add(result); dbOperationResultRow = await ExtractRowFromDbDataReader(dbDataReader); } @@ -311,9 +311,9 @@ DbOperationResultRow dbOperationResultRow /// In MsSQL upsert: /// result set #1: result of the UPDATE operation. /// result set #2: result of the INSERT operation. - if (dbOperationResultRow.Row.Count > 0) + if (dbOperationResultRow.Columns.Count > 0) { - dbOperationResultRow.PropertiesOfResult.Add(SqlMutationEngine.IS_FIRST_RESULT_SET, true); + dbOperationResultRow.ResultProperties.Add(SqlMutationEngine.IS_FIRST_RESULT_SET, true); return dbOperationResultRow; } else if (await dbDataReader.NextResultAsync()) @@ -349,12 +349,12 @@ DbOperationResultRow dbOperationResultRow DbDataReader dbDataReader, List? columnNames = null) { - Dictionary propertiesOfResult = new() + Dictionary resultProperties = new() { { nameof(dbDataReader.RecordsAffected), dbDataReader.RecordsAffected }, { nameof(dbDataReader.HasRows), dbDataReader.HasRows } }; - return Task.FromResult((Dictionary?)propertiesOfResult); + return Task.FromResult((Dictionary?)resultProperties); } private async Task GetJsonStringFromDbReader(DbDataReader dbDataReader) diff --git a/src/Service/Resolvers/SqlMutationEngine.cs b/src/Service/Resolvers/SqlMutationEngine.cs index 337b77d6b4..6301f3ea6a 100644 --- a/src/Service/Resolvers/SqlMutationEngine.cs +++ b/src/Service/Resolvers/SqlMutationEngine.cs @@ -124,7 +124,7 @@ await PerformMutationOperation( parameters, context); - if (mutationResult is not null && mutationResult.Row.Count > 0 + if (mutationResult is not null && mutationResult.Columns.Count > 0 && !context.Selection.Type.IsScalarType()) { // Because the GraphQL mutation result set columns were exposed (mapped) column names, @@ -133,7 +133,7 @@ await PerformMutationOperation( // represent database column names. result = await _queryEngine.ExecuteAsync( context, - GetBackingColumnsFromCollection(entityName, mutationResult.Row)); + GetBackingColumnsFromCollection(entityName, mutationResult.Columns)); } } @@ -292,12 +292,12 @@ await PerformUpsertOperation( parameters, context); - if (upsertOperationResult is not null && upsertOperationResult.Row.Count > 0) + if (upsertOperationResult is not null && upsertOperationResult.Columns.Count > 0) { - Dictionary resultRow = upsertOperationResult.Row; + Dictionary resultRow = upsertOperationResult.Columns; bool isFirstResultSet = false; - if (upsertOperationResult.PropertiesOfResult.TryGetValue(IS_FIRST_RESULT_SET, out object? isFirstResultSetValue)) + if (upsertOperationResult.ResultProperties.TryGetValue(IS_FIRST_RESULT_SET, out object? isFirstResultSetValue)) { isFirstResultSet = Convert.ToBoolean(isFirstResultSetValue); } @@ -327,23 +327,23 @@ await PerformMutationOperation( if (context.OperationType is Config.Operation.Insert) { - if (mutationResult is null || mutationResult.Row.Count == 0) + if (mutationResult is null || mutationResult.Columns.Count == 0) { // this case should not happen, we throw an exception // which will be returned as an Unexpected Internal Server Error throw new Exception(); } - Dictionary resultRow = mutationResult.Row; - string primaryKeyRoute = ConstructPrimaryKeyRoute(context, resultRow); + Dictionary resultColumns = mutationResult.Columns; + string primaryKeyRoute = ConstructPrimaryKeyRoute(context, resultColumns); // location will be updated in rest controller where httpcontext is available - return new CreatedResult(location: primaryKeyRoute, OkMutationResponse(resultRow).Value); + return new CreatedResult(location: primaryKeyRoute, OkMutationResponse(resultColumns).Value); } if (context.OperationType is Config.Operation.Update || context.OperationType is Config.Operation.UpdateIncremental) { // Nothing to update means we throw Exception - if (mutationResult is null || mutationResult.Row.Count == 0) + if (mutationResult is null || mutationResult.Columns.Count == 0) { throw new DataApiBuilderException(message: "No Update could be performed, record not found", statusCode: HttpStatusCode.PreconditionFailed, @@ -351,7 +351,7 @@ await PerformMutationOperation( } // Valid REST updates return OkObjectResult - return OkMutationResponse(mutationResult.Row); + return OkMutationResponse(mutationResult.Columns); } } @@ -520,7 +520,7 @@ await _queryExecutor.ExecuteQueryAsync( _httpContextAccessor.HttpContext!, primaryKeyExposedColumnNames.Count > 0 ? primaryKeyExposedColumnNames : sourceDefinition.PrimaryKey); - if (dbOperationResultRow is not null && dbOperationResultRow.Row.Count == 0) + if (dbOperationResultRow is not null && dbOperationResultRow.Columns.Count == 0) { string searchedPK; if (primaryKeyExposedColumnNames.Count > 0) diff --git a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs index 8eeacefde6..663d816572 100644 --- a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs +++ b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs @@ -1364,14 +1364,14 @@ private async Task?> // Gets a single row read from DbDataReader which contains 2 dictionaries: // 1. the first row extracted from the result // 2. Dictionary of the DbDataReader properties like RecordsAffected, HasRows. - // This function only requires the result row i.e.the first dictionary. + // This function only requires the DbOperationResultRow.Columns property. DbOperationResultRow foreignKeyInfoWithProperties = await QueryExecutor.ExtractRowFromDbDataReader(reader); Dictionary pairToFkDefinition = new(); - while (foreignKeyInfoWithProperties.Row.Count > 0) + while (foreignKeyInfoWithProperties.Columns.Count > 0) { - Dictionary foreignKeyInfo = foreignKeyInfoWithProperties.Row; + Dictionary foreignKeyInfo = foreignKeyInfoWithProperties.Columns; string referencingSchemaName = (string)foreignKeyInfo[$"Referencing{nameof(DatabaseObject.SchemaName)}"]!; string referencingTableName = (string)foreignKeyInfo[$"Referencing{nameof(SourceDefinition)}"]!; From e17e3c477db6808a37c58d12727ba393c5cbe23a Mon Sep 17 00:00:00 2001 From: Ayush Agarwal Date: Thu, 16 Feb 2023 23:00:15 +0530 Subject: [PATCH 5/5] addressing review comments --- src/Service/Resolvers/IQueryExecutor.cs | 2 +- src/Service/Resolvers/QueryExecutor.cs | 4 ++-- src/Service/Resolvers/SqlMutationEngine.cs | 5 ++--- .../Services/MetadataProviders/SqlMetadataProvider.cs | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Service/Resolvers/IQueryExecutor.cs b/src/Service/Resolvers/IQueryExecutor.cs index 9713609de1..2a9934b7f6 100644 --- a/src/Service/Resolvers/IQueryExecutor.cs +++ b/src/Service/Resolvers/IQueryExecutor.cs @@ -88,7 +88,7 @@ public Task GetMultipleResultSetsIfAnyAsync( /// A DbDataReader. /// List of string arguments if any. /// A dictionary of properties of the DbDataReader like RecordsAffected, HasRows. - public Task?> GetResultProperties( + public Task> GetResultProperties( DbDataReader dbDataReader, List? args = null); diff --git a/src/Service/Resolvers/QueryExecutor.cs b/src/Service/Resolvers/QueryExecutor.cs index c45d5ffe32..24938bbe3a 100644 --- a/src/Service/Resolvers/QueryExecutor.cs +++ b/src/Service/Resolvers/QueryExecutor.cs @@ -345,7 +345,7 @@ DbOperationResultRow dbOperationResultRow /// /// This function is a DbDataReader handler of type /// Func?, Task> - public Task?> GetResultProperties( + public Task> GetResultProperties( DbDataReader dbDataReader, List? columnNames = null) { @@ -354,7 +354,7 @@ DbOperationResultRow dbOperationResultRow { nameof(dbDataReader.RecordsAffected), dbDataReader.RecordsAffected }, { nameof(dbDataReader.HasRows), dbDataReader.HasRows } }; - return Task.FromResult((Dictionary?)resultProperties); + return Task.FromResult(resultProperties); } private async Task GetJsonStringFromDbReader(DbDataReader dbDataReader) diff --git a/src/Service/Resolvers/SqlMutationEngine.cs b/src/Service/Resolvers/SqlMutationEngine.cs index 6301f3ea6a..48c98e0ef6 100644 --- a/src/Service/Resolvers/SqlMutationEngine.cs +++ b/src/Service/Resolvers/SqlMutationEngine.cs @@ -334,10 +334,9 @@ await PerformMutationOperation( throw new Exception(); } - Dictionary resultColumns = mutationResult.Columns; - string primaryKeyRoute = ConstructPrimaryKeyRoute(context, resultColumns); + string primaryKeyRoute = ConstructPrimaryKeyRoute(context, mutationResult.Columns); // location will be updated in rest controller where httpcontext is available - return new CreatedResult(location: primaryKeyRoute, OkMutationResponse(resultColumns).Value); + return new CreatedResult(location: primaryKeyRoute, OkMutationResponse(mutationResult.Columns).Value); } if (context.OperationType is Config.Operation.Update || context.OperationType is Config.Operation.UpdateIncremental) diff --git a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs index 663d816572..f6ea00e193 100644 --- a/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs +++ b/src/Service/Services/MetadataProviders/SqlMetadataProvider.cs @@ -1362,8 +1362,8 @@ private async Task?> SummarizeFkMetadata(DbDataReader reader, List? args = null) { // Gets a single row read from DbDataReader which contains 2 dictionaries: - // 1. the first row extracted from the result - // 2. Dictionary of the DbDataReader properties like RecordsAffected, HasRows. + // 1. The columns of the first row extracted from the result + // 2. DbDataReader properties like RecordsAffected, HasRows. // This function only requires the DbOperationResultRow.Columns property. DbOperationResultRow foreignKeyInfoWithProperties = await QueryExecutor.ExtractRowFromDbDataReader(reader);