From 9ced46dbd2890d6c0c8949e16666530277a63494 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 1 May 2024 13:50:07 -0700 Subject: [PATCH 01/20] Supported Types tests no longer need to resetdbstate after each db row. This caused HUGE test execution times. --- .../GraphQLSupportedTypesTests/DabField.cs | 22 +++++++++ .../GraphQLSupportedTypesTestsBase.cs | 46 ++++++++++--------- .../MsSqlGQLSupportedTypesTests.cs | 9 ++-- .../MySqlGQLSupportedTypesTests.cs | 14 +++--- .../PostgreSqlGQLSupportedTypesTests.cs | 8 ++-- 5 files changed, 62 insertions(+), 37 deletions(-) create mode 100644 src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs new file mode 100644 index 0000000000..c5fae1ad6c --- /dev/null +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Azure.DataApiBuilder.Service.Tests.SqlTests.GraphQLSupportedTypesTests +{ + public class DabField + { + public string Alias { get; set; } + public string BackingColumnName { get; set; } + public DabField(string alias, string backingColumnName) + { + Alias = alias; + BackingColumnName = backingColumnName; + } + + public DabField(string backingColumnName) + { + Alias = backingColumnName; + BackingColumnName = backingColumnName; + } + } +} diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index 0f121f21c1..5d262f144f 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -99,7 +99,7 @@ public async Task QueryTypeColumn(string type, int id) string graphQLQueryName = "supportedType_by_pk"; string gqlQuery = "{ supportedType_by_pk(typeid: " + id + ") { " + field + " } }"; - string dbQuery = MakeQueryOnTypeTable(new List { field }, id); + string dbQuery = MakeQueryOnTypeTable(new List { new(field) }, id); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false); string expected = await GetDatabaseResultAsync(dbQuery); @@ -173,7 +173,7 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper } }"; - string dbQuery = MakeQueryOnTypeTable(new List { field }, filterValue: sqlValue, filterOperator: queryOperator, filterField: field, orderBy: field, limit: "100"); + string dbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, filterValue: sqlValue, filterOperator: queryOperator, filterField: field, orderBy: field, limit: "100"); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false); string expected = await GetDatabaseResultAsync(dbQuery); @@ -369,16 +369,18 @@ public async Task InsertIntoTypeColumn(string type, string value) string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "createSupportedType"; - string gqlQuery = "mutation{ createSupportedType (item: {" + field + ": " + value + " }){ " + field + " } }"; - - string dbQuery = MakeQueryOnTypeTable(new List { field }, id: 5001); + string gqlQuery = "mutation{ createSupportedType (item: {" + field + ": " + value + " }){ typeid, " + field + " } }"; JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: true); - string expected = await GetDatabaseResultAsync(dbQuery); + Assert.IsTrue( + condition: actual.GetProperty("typeid").TryGetInt32(out int insertedRecordId), + message: "Error: GraphQL mutation result indicates issue during record creation."); + string expectedResultDbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, id: insertedRecordId); + string expectedResult = await GetDatabaseResultAsync(expectedResultDbQuery); - PerformTestEqualsForExtendedTypes(type, expected, actual.ToString()); + PerformTestEqualsForExtendedTypes(type, expectedResult, actual.ToString()); - await ResetDbStateAsync(); + ////await ResetDbStateAsync(); } /// @@ -431,16 +433,16 @@ public async Task InsertIntoTypeColumnWithArgument(string type, object value) string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "createSupportedType"; - string gqlQuery = "mutation($param: " + TypeNameToGraphQLType(type) + "){ createSupportedType (item: {" + field + ": $param }){ " + field + " } }"; - - string dbQuery = MakeQueryOnTypeTable(new List { field }, id: 5001); + string gqlQuery = "mutation($param: " + TypeNameToGraphQLType(type) + "){ createSupportedType (item: {" + field + ": $param }){ typeid, " + field + " } }"; JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: true, new() { { "param", value } }); - string expected = await GetDatabaseResultAsync(dbQuery); - - PerformTestEqualsForExtendedTypes(type, expected, actual.ToString()); + Assert.IsTrue( + condition: actual.GetProperty("typeid").TryGetInt32(out int insertedRecordId), + message: "Error: GraphQL mutation result indicates issue during record creation."); + string expectedResultDbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, id: insertedRecordId); + string expectedResult = await GetDatabaseResultAsync(expectedResultDbQuery); - await ResetDbStateAsync(); + PerformTestEqualsForExtendedTypes(type, expectedResult, actual.ToString()); } [DataTestMethod] @@ -494,16 +496,16 @@ public async Task UpdateTypeColumn(string type, string value) string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "updateSupportedType"; - string gqlQuery = "mutation{ updateSupportedType (typeid: 1, item: {" + field + ": " + value + " }){ " + field + " } }"; + string gqlQuery = "mutation{ updateSupportedType (typeid: 1, item: {" + field + ": " + value + " }){ type " + field + " } }"; - string dbQuery = MakeQueryOnTypeTable(new List { field }, id: 1); + string dbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, id: 1); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: true); string expected = await GetDatabaseResultAsync(dbQuery); PerformTestEqualsForExtendedTypes(type, expected, actual.ToString()); - await ResetDbStateAsync(); + //await ResetDbStateAsync(); } [DataTestMethod] @@ -531,14 +533,14 @@ public async Task UpdateTypeColumnWithArgument(string type, object value) string graphQLQueryName = "updateSupportedType"; string gqlQuery = "mutation($param: " + TypeNameToGraphQLType(type) + "){ updateSupportedType (typeid: 1, item: {" + field + ": $param }){ " + field + " } }"; - string dbQuery = MakeQueryOnTypeTable(new List { field }, id: 1); + string dbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, id: 1); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: true, new() { { "param", value } }); string expected = await GetDatabaseResultAsync(dbQuery); PerformTestEqualsForExtendedTypes(type, expected, actual.ToString()); - await ResetDbStateAsync(); + //await ResetDbStateAsync(); } #endregion @@ -824,14 +826,14 @@ private static string TypeNameToGraphQLType(string typeName) } protected abstract string MakeQueryOnTypeTable( - List queriedColumns, + List queryFields, string filterValue = "1", string filterOperator = "=", string filterField = "1", string orderBy = "id", string limit = "1"); - protected abstract string MakeQueryOnTypeTable(List columnsToQuery, int id); + protected abstract string MakeQueryOnTypeTable(List queryFields, int id); protected virtual bool IsSupportedType(string type) { return true; diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs index aab48628bd..35b5ebc669 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -21,13 +22,13 @@ public static async Task SetupAsync(TestContext context) await InitializeTestFixture(); } - protected override string MakeQueryOnTypeTable(List columnsToQuery, int id) + protected override string MakeQueryOnTypeTable(List queryFields, int id) { - return MakeQueryOnTypeTable(columnsToQuery, filterValue: id.ToString(), filterField: "id"); + return MakeQueryOnTypeTable(queryFields, filterValue: id.ToString(), filterField: "id"); } protected override string MakeQueryOnTypeTable( - List queriedColumns, + List queryFields, string filterValue = "1", string filterOperator = "=", string filterField = "1", @@ -36,7 +37,7 @@ protected override string MakeQueryOnTypeTable( { string format = limit.Equals("1") ? "WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES" : "INCLUDE_NULL_VALUES"; return @" - SELECT TOP " + limit + " " + string.Join(", ", queriedColumns) + @" + SELECT TOP " + limit + " " + string.Join(", ", queryFields.Select(field => $"{field.BackingColumnName} AS {field.Alias}")) + @" FROM type_table AS [table0] WHERE " + filterField + " " + filterOperator + " " + filterValue + @" ORDER BY " + orderBy + @" asc diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs index 36f47fcb43..29f51bcc03 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs @@ -24,27 +24,27 @@ public static async Task SetupAsync(TestContext context) await InitializeTestFixture(); } - protected override string MakeQueryOnTypeTable(List columnsToQuery, int id) + protected override string MakeQueryOnTypeTable(List queryFields, int id) { - return MakeQueryOnTypeTable(columnsToQuery, filterValue: id.ToString(), filterField: "id"); + return MakeQueryOnTypeTable(queryFields, filterValue: id.ToString(), filterField: "id"); } protected override string MakeQueryOnTypeTable( - List queriedColumns, + List queryFields, string filterValue = "1", string filterOperator = "=", string filterField = "1", string orderBy = "id", string limit = "1") { - string columnsToQuery = string.Join(", ", queriedColumns.Select(c => $"\"{c}\" , {ProperlyFormatTypeTableColumn(c)}")); - string formattedSelect = limit.Equals("1") ? "SELECT JSON_OBJECT(" + columnsToQuery + @") AS `data`" : - "SELECT COALESCE(JSON_ARRAYAGG(JSON_OBJECT(" + columnsToQuery + @")), '[]') AS `data`"; + string jsonResultProperties = string.Join(", ", queryFields.Select(field => $"\"{field.Alias}\" , {ProperlyFormatTypeTableColumn(field.BackingColumnName)}")); + string formattedSelect = limit.Equals("1") ? "SELECT JSON_OBJECT(" + jsonResultProperties + @") AS `data`" : + "SELECT COALESCE(JSON_ARRAYAGG(JSON_OBJECT(" + jsonResultProperties + @")), '[]') AS `data`"; return @" " + formattedSelect + @" FROM ( - SELECT " + string.Join(", ", queriedColumns) + @" + SELECT " + string.Join(", ", queryFields.Select(field => field.BackingColumnName)) + @" FROM type_table AS `table0` WHERE " + filterField + " " + filterOperator + " " + filterValue + @" ORDER BY " + orderBy + @" asc diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index 79e5684b83..97d759ffd4 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -24,13 +24,13 @@ public static async Task SetupAsync(TestContext context) await InitializeTestFixture(); } - protected override string MakeQueryOnTypeTable(List columnsToQuery, int id) + protected override string MakeQueryOnTypeTable(List queryFields, int id) { - return MakeQueryOnTypeTable(columnsToQuery, filterValue: id.ToString(), filterField: "id"); + return MakeQueryOnTypeTable(queryFields, filterValue: id.ToString(), filterField: "id"); } protected override string MakeQueryOnTypeTable( - List queriedColumns, + List queryFields, string filterValue = "1", string filterOperator = "=", string filterField = "1", @@ -42,7 +42,7 @@ protected override string MakeQueryOnTypeTable( return @" " + formattedSelect + @" FROM - (SELECT " + string.Join(", ", queriedColumns.Select(c => ProperlyFormatTypeTableColumn(c) + $" AS {c}")) + @" + (SELECT " + string.Join(", ", queryFields.Select(field => ProperlyFormatTypeTableColumn(field.BackingColumnName) + $" AS {field.Alias}")) + @" FROM public.type_table AS table0 WHERE " + filterField + " " + filterOperator + " " + filterValue + @" ORDER BY " + orderBy + @" asc From 97b04d6d92542f56b680cb317699330af335c9cc Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 1 May 2024 14:50:04 -0700 Subject: [PATCH 02/20] fix test input. (figure out why this wasn't failing before) i didn't change engine code. --- .../GraphQLSupportedTypesTestsBase.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index 5d262f144f..ded2aeba8b 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -314,7 +314,7 @@ public async Task TestTimeTypePrecisionCheck(string gqlValue, int count) [DataRow(INT_TYPE, "0")] [DataRow(INT_TYPE, "-9999")] [DataRow(INT_TYPE, "null")] - [DataRow(UUID_TYPE, "3a1483a5-9ac2-4998-bcf3-78a28078c6ac")] + [DataRow(UUID_TYPE, "\"3a1483a5-9ac2-4998-bcf3-78a28078c6ac\"")] [DataRow(UUID_TYPE, "null")] [DataRow(LONG_TYPE, "0")] [DataRow(LONG_TYPE, "9000000000000000000")] @@ -379,8 +379,6 @@ public async Task InsertIntoTypeColumn(string type, string value) string expectedResult = await GetDatabaseResultAsync(expectedResultDbQuery); PerformTestEqualsForExtendedTypes(type, expectedResult, actual.ToString()); - - ////await ResetDbStateAsync(); } /// From 91f5f4ce641107adb4bfa8fa2ec373ce843afcf2 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 2 May 2024 14:13:23 -0700 Subject: [PATCH 03/20] ensure typeid in selection set for more tests so that graphql actual results can be correctly compared to db results. --- .../GraphQLSupportedTypesTestsBase.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index ded2aeba8b..42d1e6f698 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -97,9 +97,11 @@ public async Task QueryTypeColumn(string type, int id) string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "supportedType_by_pk"; - string gqlQuery = "{ supportedType_by_pk(typeid: " + id + ") { " + field + " } }"; + string gqlQuery = "{ supportedType_by_pk(typeid: " + id + ") { typeid, " + field + " } }"; - string dbQuery = MakeQueryOnTypeTable(new List { new(field) }, id); + string dbQuery = MakeQueryOnTypeTable( + queryFields: new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, + id: id); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false); string expected = await GetDatabaseResultAsync(dbQuery); @@ -168,12 +170,18 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper string gqlQuery = @"{ supportedTypes(first: 100 orderBy: { " + field + ": ASC } filter: { " + field + ": {" + filterOperator + ": " + gqlValue + @"} }) { items { - " + field + @" + typeid, " + field + @" } } }"; - string dbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, filterValue: sqlValue, filterOperator: queryOperator, filterField: field, orderBy: field, limit: "100"); + string dbQuery = MakeQueryOnTypeTable( + queryFields: new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, + filterValue: sqlValue, + filterOperator: queryOperator, + filterField: field, + orderBy: field, + limit: "100"); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false); string expected = await GetDatabaseResultAsync(dbQuery); @@ -289,7 +297,7 @@ public async Task TestTimeTypePrecisionCheck(string gqlValue, int count) string gqlQuery = @"{ supportedTypes(first: 100 orderBy: { " + "time_types" + ": ASC } filter: { " + "time_types" + ": {" + "eq" + ": " + gqlValue + @"} }) { items { - " + "time_types" + @" + typeid, " + "time_types" + @" } } }"; @@ -400,7 +408,7 @@ public async Task InsertInvalidTimeIntoTimeTypeColumn(string type, string value) string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "createSupportedType"; - string gqlQuery = "mutation{ createSupportedType (item: {" + field + ": " + value + " }){ " + field + " } }"; + string gqlQuery = "mutation{ createSupportedType (item: {" + field + ": " + value + " }){ typeid, " + field + " } }"; JsonElement response = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: true); string responseMessage = Regex.Unescape(JsonSerializer.Serialize(response)); @@ -494,7 +502,7 @@ public async Task UpdateTypeColumn(string type, string value) string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "updateSupportedType"; - string gqlQuery = "mutation{ updateSupportedType (typeid: 1, item: {" + field + ": " + value + " }){ type " + field + " } }"; + string gqlQuery = "mutation{ updateSupportedType (typeid: 1, item: {" + field + ": " + value + " }){ typeid " + field + " } }"; string dbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, id: 1); @@ -529,7 +537,7 @@ public async Task UpdateTypeColumnWithArgument(string type, object value) string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "updateSupportedType"; - string gqlQuery = "mutation($param: " + TypeNameToGraphQLType(type) + "){ updateSupportedType (typeid: 1, item: {" + field + ": $param }){ " + field + " } }"; + string gqlQuery = "mutation($param: " + TypeNameToGraphQLType(type) + "){ updateSupportedType (typeid: 1, item: {" + field + ": $param }){ typeid, " + field + " } }"; string dbQuery = MakeQueryOnTypeTable(new List { new(alias: "typeid", backingColumnName: "id"), new(backingColumnName: field) }, id: 1); From 343d205a96ff99291275f46270c81ddeb8ca1566 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 7 Jun 2024 17:35:38 -0700 Subject: [PATCH 04/20] Fix MySql Supported Types tests and add new test methods which are more readable . also add comments to describe how mysql datetime data type has certain restrictions and accommodate how GraphQL (Hotchocolate) resolves user supplied datetimeoffset and sends to database and how dab then processes and returns the database response. --- .../BaseSqlQueryStructure.cs | 6 +- .../GraphQLSupportedTypesTestsBase.cs | 21 +++-- .../MsSqlGQLSupportedTypesTests.cs | 5 ++ .../MySqlGQLSupportedTypesTests.cs | 86 +++++++++++++++++++ .../PostgreSqlGQLSupportedTypesTests.cs | 5 ++ 5 files changed, 113 insertions(+), 10 deletions(-) diff --git a/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs b/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs index 4bd1aca768..881f41a42e 100644 --- a/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs +++ b/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs @@ -439,7 +439,11 @@ protected static object ParseParamAsSystemType(string param, Type systemType) "Double" => double.Parse(param), "Decimal" => decimal.Parse(param), "Boolean" => bool.Parse(param), - "DateTime" => DateTimeOffset.Parse(param, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal).DateTime, + // When GraphQL input specifies TZ offset "12-31-2024T12:00:00+03:00" and DAB has resolved + // the ColumnDefinition.SystemType to DateTime, DAB convert the value to UTC to: + // - Match assumption that values without timezone offset are "assumed universal." + // - Avoid storing a value in the database that the user did not intend: "12-31-2024T12:00:00" + "DateTime" => DateTimeOffset.Parse(param, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal).UtcDateTime, "DateTimeOffset" => DateTimeOffset.Parse(param, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal), "Date" => DateOnly.Parse(param), "Guid" => Guid.Parse(param), diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index 58913cad96..3370ecb546 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -307,8 +307,8 @@ public async Task TestTimeTypePrecisionCheck(string gqlValue, int count) } /// - /// The method constructs a GraphQL query to insert the value into the database table - /// and then executes the query and compares the expected result with the actual result to verify if different types are supported. + /// This test executes a GraphQL insert mutation for each data row's {value} of GraphQL data type {type} + /// to validate that the DAB engine supports inserting different types into the database. /// [DataTestMethod] [DataRow(BYTE_TYPE, "255")] @@ -353,9 +353,9 @@ public async Task TestTimeTypePrecisionCheck(string gqlValue, int count) [DataRow(TIME_TYPE, "\"23:59\"")] [DataRow(TIME_TYPE, "null")] [DataRow(DATETIME_TYPE, "\"1753-01-01 00:00:00.000\"")] - [DataRow(DATETIME_TYPE, "\"9999-12-31 23:59:59.997\"")] - [DataRow(DATETIME_TYPE, "\"9999-12-31T23:59:59.997\"")] - [DataRow(DATETIME_TYPE, "\"9999-12-31 23:59:59.997Z\"")] + [DataRow(DATETIME_TYPE, "\"9999-12-31 23:59:59.499\"")] + [DataRow(DATETIME_TYPE, "\"9999-12-31T23:59:59.499\"")] + [DataRow(DATETIME_TYPE, "\"9999-12-31 23:59:59.499Z\"")] [DataRow(DATETIME_TYPE, "null")] [DataRow(SMALLDATETIME_TYPE, "\"1900-01-01\"")] [DataRow(SMALLDATETIME_TYPE, "\"2079-06-06\"")] @@ -377,10 +377,10 @@ public async Task InsertIntoTypeColumn(string type, string value) } string field = $"{type.ToLowerInvariant()}_types"; - string graphQLQueryName = "createSupportedType"; - string gqlQuery = "mutation{ createSupportedType (item: {" + field + ": " + value + " }){ typeid, " + field + " } }"; + string graphQLMutationName = "createSupportedType"; + string gqlMutation = "mutation{ createSupportedType (item: {" + field + ": " + value + " }){ typeid, " + field + " } }"; - JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: true); + JsonElement actual = await ExecuteGraphQLRequestAsync(gqlMutation, graphQLMutationName, isAuthenticated: true); Assert.IsTrue( condition: actual.GetProperty("typeid").TryGetInt32(out int insertedRecordId), message: "Error: GraphQL mutation result indicates issue during record creation."); @@ -390,6 +390,8 @@ public async Task InsertIntoTypeColumn(string type, string value) PerformTestEqualsForExtendedTypes(type, expectedResult, actual.ToString()); } + public abstract Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult); + /// /// Test case for invalid time, such as negative values or hours>24 or minutes/seconds>60. /// @@ -573,7 +575,7 @@ public async Task UpdateTypeColumnWithArgument(string type, object value) /// Utility function to do special comparisons for some of the extended types /// if json compare doesn't suffice /// - private static void PerformTestEqualsForExtendedTypes(string type, string expected, string actual) + public static void PerformTestEqualsForExtendedTypes(string type, string expected, string actual) { switch (type) { @@ -858,6 +860,7 @@ protected abstract string MakeQueryOnTypeTable( string limit = "1"); protected abstract string MakeQueryOnTypeTable(List queryFields, int id); + protected virtual bool IsSupportedType(string type) { return true; diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs index 35b5ebc669..7d283d9a82 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs @@ -22,6 +22,11 @@ public static async Task SetupAsync(TestContext context) await InitializeTestFixture(); } + public override Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) + { + throw new System.NotImplementedException(); + } + protected override string MakeQueryOnTypeTable(List queryFields, int id) { return MakeQueryOnTypeTable(queryFields, filterValue: id.ToString(), filterField: "id"); diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs index 29f51bcc03..add9ef7c2a 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedDateTimeTypes; @@ -24,6 +26,90 @@ public static async Task SetupAsync(TestContext context) await InitializeTestFixture(); } + /// + /// Validates that GraphQL mutation input for: + /// GraphQL Field Name (Type): datetime_types (DateTime) + /// MySQL Field Name (Type): datetime_types (datetime) + /// succeeds when the input is a valid DateTime string as described by MySQL documentation. + /// The field under test is of MySQL type datetime, with no fractional second precision. + /// MySQL converts the supplied datetime value to UTC before storing it in the database. + /// + /// + /// The DATETIME type is used for values that contain both date and time parts. + /// MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD hh:mm:ss' format. + /// The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'. + /// + /// + /// Inserting a TIME, DATE, or TIMESTAMP value with a fractional seconds part into a column + /// of the same type but having fewer fractional digits results in rounding. + /// + /// + /// - The (time zone) offset is not displayed when selecting a datetime value, + /// even if one was used when inserting it. + /// - The date and time parts can be separated by T rather than a space. + /// For example, '2012-12-31 11:30:45' '2012-12-31T11:30:45' are equivalent. + /// + /// + /// UTC offset should be formatted as Z and not +00:00 and lower case z and t should be converted to Z and T. + /// + /// Unescaped string used as value for GraphQL input field datetime_types + /// Expected result the HotChocolate returns from resolving database response. + // Date and time + [DataRow("1000-01-01 00:00:00", "1000-01-01T00:00:00.000Z", DisplayName = "Datetime value separated by space.")] + [DataRow("9999-12-31T23:59:59", "9999-12-31T23:59:59.000Z", DisplayName = "Datetime value separated by T.")] + [DataRow("9999-12-31 23:59:59Z", "9999-12-31T23:59:59.000Z", DisplayName = "Datetime value specified with UTC offset Z as resolved by HotChocolate.")] + [DataRow("9999-12-31 23:59:59+00:00", "9999-12-31T23:59:59.000Z", DisplayName = "Datetime value specified with UTC offset with no datetime change when stored in db.")] + [DataRow("9999-12-31 23:59:59+03:00", "9999-12-31T20:59:59.000Z", DisplayName = "Timezone offset UTC+03:00 accepted by MySQL because UTC value is in supported datetime range.")] + [DataRow("9999-12-31 20:59:59-03:00", "9999-12-31T23:59:59.000Z", DisplayName = "Timezone offset UTC-03:00 accepted by MySQL because UTC value is in supported datetime range.")] + // Fractional seconds rounded up/down when mysql column datetime doesn't specify fractional seconds + // e.g. column not defined as datetime({1-6}) + [DataRow("9999-12-31 23:59:59.499999", "9999-12-31T23:59:59.000Z", DisplayName = "Fractional seconds rounded down because fractional seconds are passed to column with datatype datetime(0).")] + [DataRow("2024-12-31 23:59:59.999999", "2025-01-01T00:00:00.000Z", DisplayName = "Fractional seconds rounded up because fractional seconds are passed to column with datatype datetime(0).")] + // Only date + [DataRow("9999-12-31", "9999-12-31T00:00:00.000Z", DisplayName = "Max date for datetime column stored with zeroed out time.")] + [DataRow("1000-01-01", "1000-01-01T00:00:00.000Z", DisplayName = "Min date for datetime column stored with zeroed out time.")] + [DataTestMethod] + public override async Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) + { + // Arrange + const string DATETIME_FIELD = "datetime_types"; + string graphQLMutationName = "createSupportedType"; + string gqlMutation = "mutation{ createSupportedType (item: {" + DATETIME_FIELD + ": \"" + dateTimeGraphQLInput + "\" }){ typeid, " + DATETIME_FIELD + " } }"; + + // Act + JsonElement actual = await ExecuteGraphQLRequestAsync(gqlMutation, graphQLMutationName, isAuthenticated: true); + + // Assert + Assert.IsTrue( + condition: actual.GetProperty("typeid").TryGetInt32(out _), + message: "Error: GraphQL mutation result indicates issue during record creation because primary key 'typeid' was not resolved."); + + Assert.AreEqual( + expected: expectedResult, + actual: actual.GetProperty(DATETIME_FIELD).GetString(), + message: "get back towork jr"); + } + + /// + /// For MySQL, values passed to columns with datatype datetime(0) (no fractional seconds) that only include time + /// are auto-populated with the current date. + /// Based on the supplied time (assumed to be UTC), gets the current date. This calculation must fetch + /// DateTime.UtcNow, otherwise the test machine's timezone will be used and result in an unexpected date. + /// + /// Unescaped string used as value for GraphQL input field datetime_types + /// Expected result the HotChocolate returns from resolving database response. + [DataRow("23:59:59.499999", "23:59:59.000Z", DisplayName = "hh:mm::ss.ffffff for datetime column stored with zeroed out date and rounded down fractional seconds.")] + [DataRow("23:59:59", "23:59:59.000Z", DisplayName = "hh:mm:ss for datetime column stored with zeroed out date.")] + [DataRow("23:59", "23:59:00.000Z", DisplayName = "hh:mm for datetime column stored with zeroed out date and seconds.")] + [DataTestMethod] + public async Task InsertMutationInput_DateTimeTypes_TimeOnly_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) + { + // Arrange + //expectedResult = DateTime.Parse(dateTimeGraphQLInput).ToString("yyyy-MM-ddT") + expectedResult; + expectedResult = DateTime.UtcNow.ToString("yyyy-MM-ddT") + expectedResult; + await InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(dateTimeGraphQLInput, expectedResult); + } + protected override string MakeQueryOnTypeTable(List queryFields, int id) { return MakeQueryOnTypeTable(queryFields, filterValue: id.ToString(), filterField: "id"); diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index 97d759ffd4..04615e6992 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -88,5 +88,10 @@ private static string ProperlyFormatTypeTableColumn(string columnName) { Assert.Inconclusive("Test skipped for PostgreSql."); } + + public override Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) + { + throw new System.NotImplementedException(); + } } } From c75840f945b13c25ef8c8bf9a3ab5bdeb9b9564e Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 7 Jun 2024 18:14:57 -0700 Subject: [PATCH 05/20] Fix broken graphql test that was somehow showing as green but was actualy failing. --- .../GraphQLSupportedTypesTestsBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index 3370ecb546..dafc065462 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -436,8 +436,8 @@ public async Task InsertInvalidTimeIntoTimeTypeColumn(string type, string value) [DataRow(BOOLEAN_TYPE, true)] [DataRow(DATETIMEOFFSET_TYPE, "1999-01-08 10:23:54+8:00")] [DataRow(DATETIME_TYPE, "1999-01-08 10:23:54")] - [DataRow(TIME_TYPE, "\"23:59:59.9999999\"")] - [DataRow(TIME_TYPE, "null")] + [DataRow(LOCALTIME_TYPE, "\"23:59:59.9999999\"")] + [DataRow(LOCALTIME_TYPE, "null")] [DataRow(BYTEARRAY_TYPE, "V2hhdGNodSBkb2luZyBkZWNvZGluZyBvdXIgdGVzdCBiYXNlNjQgc3RyaW5ncz8=")] [DataRow(UUID_TYPE, "3a1483a5-9ac2-4998-bcf3-78a28078c6ac")] public async Task InsertIntoTypeColumnWithArgument(string type, object value) From 8543e2c75bd77002773121eb8186d3dc4fbca310 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 7 Jun 2024 18:35:38 -0700 Subject: [PATCH 06/20] fix localtime/time tests with bad values. --- .../GraphQLSupportedTypesTestsBase.cs | 20 +++++++++---------- .../MySqlGQLSupportedTypesTests.cs | 2 ++ .../PostgreSqlGQLSupportedTypesTests.cs | 2 ++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index dafc065462..e5f9d629d5 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -168,7 +168,7 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper string field = $"{type.ToLowerInvariant()}_types"; string graphQLQueryName = "supportedTypes"; string gqlQuery = @"{ - supportedTypes(first: 100 orderBy: { " + field + ": ASC } filter: { " + field + ": {" + filterOperator + ": " + gqlValue + @"} }) { + supportedTypes(first: 100 orderBy: { typeid: ASC } filter: { " + field + ": {" + filterOperator + ": " + gqlValue + @"} }) { items { typeid, " + field + @" } @@ -180,7 +180,7 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper filterValue: sqlValue, filterOperator: queryOperator, filterField: field, - orderBy: field, + orderBy: "typeid", limit: "100"); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false); @@ -223,7 +223,7 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper DisplayName = "datetime type filter and orderby test with neq operator and specific value '1999-01-08 10:23:54'.")] [DataRow(DATETIMEOFFSET_TYPE, "neq", "'1999-01-08 10:23:54.9999999-14:00'", "\"1999-01-08 10:23:54.9999999-14:00\"", "!=", DisplayName = "datetimeoffset type filter and orderby test with neq operator")] - [DataRow(DATETIMEOFFSET_TYPE, "lt", "'9999-12-31 23:59:59.9999999'", "\"9999-12-31 23:59:59.9999999\"", "<", + [DataRow(DATETIMEOFFSET_TYPE, "lt", "'9999-12-31 23:59:59.9999999'", "\"9999-12-31 23:59:59.9999999Z\"", "<", DisplayName = "datetimeoffset type filter and orderby test with lt operator and max value for datetimeoffset.")] [DataRow(DATETIMEOFFSET_TYPE, "eq", "'1999-01-08 10:23:54.9999999-14:00'", "\"1999-01-08 10:23:54.9999999-14:00\"", "=", DisplayName = "datetimeoffset type filter and orderby test with eq operator")] @@ -436,8 +436,8 @@ public async Task InsertInvalidTimeIntoTimeTypeColumn(string type, string value) [DataRow(BOOLEAN_TYPE, true)] [DataRow(DATETIMEOFFSET_TYPE, "1999-01-08 10:23:54+8:00")] [DataRow(DATETIME_TYPE, "1999-01-08 10:23:54")] - [DataRow(LOCALTIME_TYPE, "\"23:59:59.9999999\"")] - [DataRow(LOCALTIME_TYPE, "null")] + [DataRow(TIME_TYPE, "23:59:59")] + [DataRow(TIME_TYPE, "null")] [DataRow(BYTEARRAY_TYPE, "V2hhdGNodSBkb2luZyBkZWNvZGluZyBvdXIgdGVzdCBiYXNlNjQgc3RyaW5ncz8=")] [DataRow(UUID_TYPE, "3a1483a5-9ac2-4998-bcf3-78a28078c6ac")] public async Task InsertIntoTypeColumnWithArgument(string type, object value) @@ -843,12 +843,12 @@ private static void AssertOnFields(string field, string actualElement, string ex /// private static string TypeNameToGraphQLType(string typeName) { - if (typeName is DATETIMEOFFSET_TYPE) + return typeName switch { - return DATETIME_TYPE; - } - - return typeName; + DATETIMEOFFSET_TYPE => DATETIME_TYPE, + TIME_TYPE => LOCALTIME_TYPE, + _ => typeName + }; } protected abstract string MakeQueryOnTypeTable( diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs index add9ef7c2a..34e17a4bda 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; +using HotChocolate.Types.NodaTime; using Microsoft.VisualStudio.TestTools.UnitTesting; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedDateTimeTypes; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedHotChocolateTypes; @@ -149,6 +150,7 @@ protected override bool IsSupportedType(string type) DATETIME2_TYPE => false, DATETIMEOFFSET_TYPE => false, TIME_TYPE => false, + LOCALTIME_TYPE => false, _ => true }; } diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index 04615e6992..11975f61da 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using HotChocolate.Types.NodaTime; using Microsoft.VisualStudio.TestTools.UnitTesting; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedDateTimeTypes; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedHotChocolateTypes; @@ -60,6 +61,7 @@ protected override bool IsSupportedType(string type) DATETIME2_TYPE => false, DATETIMEOFFSET_TYPE => false, TIME_TYPE => false, + LOCALTIME_TYPE => false, _ => true }; } From bfe523d6fca93a351692106d69575509a0622aa2 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 7 Jun 2024 18:37:51 -0700 Subject: [PATCH 07/20] more mssql time test fixes. removed null for LocalTime, not compatible. --- .../GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index e5f9d629d5..c98e289336 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -437,7 +437,6 @@ public async Task InsertInvalidTimeIntoTimeTypeColumn(string type, string value) [DataRow(DATETIMEOFFSET_TYPE, "1999-01-08 10:23:54+8:00")] [DataRow(DATETIME_TYPE, "1999-01-08 10:23:54")] [DataRow(TIME_TYPE, "23:59:59")] - [DataRow(TIME_TYPE, "null")] [DataRow(BYTEARRAY_TYPE, "V2hhdGNodSBkb2luZyBkZWNvZGluZyBvdXIgdGVzdCBiYXNlNjQgc3RyaW5ncz8=")] [DataRow(UUID_TYPE, "3a1483a5-9ac2-4998-bcf3-78a28078c6ac")] public async Task InsertIntoTypeColumnWithArgument(string type, object value) From 96f877b365ae74273a65ec54d8eccf4bd800afa0 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 13 Jun 2024 16:16:59 -0700 Subject: [PATCH 08/20] Fix TestTimeTypePrecisionCheck test and fix PG single_type test with lte .33 because expected value query isn't parameterized and doesn't capture the proper data type. real data type must be used as real '0.33'. to get expected value. --- .../GraphQLSupportedTypesTestsBase.cs | 48 +++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index c98e289336..6730ae2bf8 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -139,7 +139,7 @@ public async Task QueryTypeColumn(string type, int id) [DataRow(SINGLE_TYPE, "gt", "-9.3", "-9.3", ">")] [DataRow(SINGLE_TYPE, "gte", "-9.2", "-9.2", ">=")] [DataRow(SINGLE_TYPE, "lt", ".33", "0.33", "<")] - [DataRow(SINGLE_TYPE, "lte", ".33", "0.33", "<=")] + [DataRow(SINGLE_TYPE, "lte", "real '.33'", "0.33", "<=")] [DataRow(SINGLE_TYPE, "neq", "9.2", "9.2", "!=")] [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] [DataRow(FLOAT_TYPE, "gt", "-9.2", "-9.2", ">")] @@ -180,7 +180,7 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper filterValue: sqlValue, filterOperator: queryOperator, filterField: field, - orderBy: "typeid", + orderBy: "id", limit: "100"); JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false); @@ -279,31 +279,63 @@ public async Task QueryTypeColumnFilterAndOrderByLocalTime(string type, string f } /// + /// (MSSQL Test, which supports time type with 7 decimal precision) /// Validates that LocalTime values with X precision are handled correctly: precision of 7 decimal places used with eq (=) will /// not return result with only 3 decimal places i.e. 10:23:54.999 != 10:23:54.9999999 - /// In the Database only one row exist with value 23:59:59.9999999 + /// In the Database only one row exists with value 23:59:59.9999999 /// [DataTestMethod] - [DataRow("\"23:59:59.9999999\"", 1, DisplayName = "TimeType Precision Check with 7 decimal places")] - [DataRow("\"23:59:59.999\"", 0, DisplayName = "TimeType Precision Check with 3 decimal places")] - public async Task TestTimeTypePrecisionCheck(string gqlValue, int count) + [DataRow("23:59:59.9999999", DisplayName = "TimeType Precision Check with 7 decimal places")] + [DataRow("23:59:59.999", DisplayName = "TimeType Precision Check with 3 decimal places")] + public async Task TestTimeTypePrecisionCheck(string gqlInput) { + // Arrange if (!IsSupportedType(TIME_TYPE)) { Assert.Inconclusive("Type not supported"); } + string graphQLMutationName = "createSupportedType"; + string gqlMutation = "mutation{ createSupportedType (item: { time_types: \"" + gqlInput + "\"}){ typeid, time_types } }"; + JsonElement testScopedInsertedRecord = await ExecuteGraphQLRequestAsync(gqlMutation, graphQLMutationName, isAuthenticated: true); + + if (!testScopedInsertedRecord.TryGetProperty("typeid", out JsonElement typeid)) + { + Assert.Fail(message: "Failed to insert test record."); + } + + int insertedRecordId = typeid.GetInt32(); + string graphQLQueryName = "supportedTypes"; + string idFilter = @"typeid: { eq: " + typeid.GetInt32() + " }"; string gqlQuery = @"{ - supportedTypes(first: 100 orderBy: { " + "time_types" + ": ASC } filter: { " + "time_types" + ": {" + "eq" + ": " + gqlValue + @"} }) { + supportedTypes( + orderBy: { " + "time_types" + @": ASC } + filter: { " + "time_types" + ": {" + "eq" + ": \"" + gqlInput + "\"}," + idFilter + @"}) { items { typeid, " + "time_types" + @" } } }"; + // Act - Execute query with filter on time_types, expect to get back time_types with 7 decimal places. JsonElement gqlResponse = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false); - Assert.AreEqual(count, gqlResponse.GetProperty("items").GetArrayLength()); + + // Assert + // Validate that the filter returned a result. + bool receivedResultWithFilter = gqlResponse.TryGetProperty("items", out JsonElement items) && items.GetArrayLength() > 0; + Assert.AreEqual(expected: true, actual: receivedResultWithFilter, message: "Unexpected results and result count."); + + // Validate that the filter returned the value inserted during setup. + JsonElement firstItem = items[0]; + JsonElement typeId = firstItem.GetProperty("typeid"); + int actualTypeIdInResponse = typeId.GetInt32(); + Assert.AreEqual(expected: insertedRecordId, actual: actualTypeIdInResponse, message: "typeid mismatch, filter didn't work"); + + // Validate that the filter returned the value with expected time_types precision. + JsonElement timeValue = firstItem.GetProperty("time_types"); + string actualTimeValue = timeValue.GetString(); + Assert.AreEqual(expected: gqlInput, actual: actualTimeValue, message: "returned time value unexpected."); } /// From 7fb3574e9c24f109c35a9de64b6486ad1823941a Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 14 Jun 2024 17:27:36 -0700 Subject: [PATCH 09/20] Updated DabField comments. Updated DateTime conversion to UTC comments. Removed commented out resetDbStateAsync(). fixed test input to include UTC offset because SqlClient assumes input without offset specifier is current timezone and not UTC. Tracking via bug #2265, but offset specified so that tests pass locally for Redmond devs. --- .../BaseSqlQueryStructure.cs | 11 ++-- .../GraphQLSupportedTypesTests/DabField.cs | 50 +++++++++++++------ .../GraphQLSupportedTypesTestsBase.cs | 9 ++-- .../MySqlGQLSupportedTypesTests.cs | 1 - .../PostgreSqlGQLSupportedTypesTests.cs | 1 - 5 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs b/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs index 881f41a42e..d7d900d4f9 100644 --- a/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs +++ b/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs @@ -439,10 +439,13 @@ protected static object ParseParamAsSystemType(string param, Type systemType) "Double" => double.Parse(param), "Decimal" => decimal.Parse(param), "Boolean" => bool.Parse(param), - // When GraphQL input specifies TZ offset "12-31-2024T12:00:00+03:00" and DAB has resolved - // the ColumnDefinition.SystemType to DateTime, DAB convert the value to UTC to: - // - Match assumption that values without timezone offset are "assumed universal." - // - Avoid storing a value in the database that the user did not intend: "12-31-2024T12:00:00" + // When GraphQL input specifies a TZ offset "12-31-2024T12:00:00+03:00" + // and DAB has resolved the ColumnDefinition.SystemType to DateTime, + // DAB converts the input to UTC because: + // - DAB assumes that values without timezone offset are UTC. + // - DAB shouldn't store values in the backend database which the user did not intend + // - e.g. Storing this value for the original example would be incorrect: "12-31-2024T12:00:00" + // - The correct value to store would be "12-31-2024T09:00:00" (UTC) "DateTime" => DateTimeOffset.Parse(param, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal).UtcDateTime, "DateTimeOffset" => DateTimeOffset.Parse(param, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal), "Date" => DateOnly.Parse(param), diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs index c5fae1ad6c..53b6c0c8c8 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs @@ -1,22 +1,44 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Azure.DataApiBuilder.Service.Tests.SqlTests.GraphQLSupportedTypesTests +namespace Azure.DataApiBuilder.Service.Tests.SqlTests.GraphQLSupportedTypesTests; + +/// +/// Encapsulates field name metadata which is used when +/// creating database queries to validate test results +/// in the GraphQLSupportedTypesTestBase. +/// +public class DabField { - public class DabField + /// + /// Mapped (aliased) column name defined in DAB runtime config. + /// + public string Alias { get; set; } + + /// + /// Database column name. + /// + public string BackingColumnName { get; set; } + + /// + /// Creates a new DabField instance with both alias and backing column name. + /// + /// Mapped (aliased) column name defined in DAB runtime config. + /// + public DabField(string alias, string backingColumnName) { - public string Alias { get; set; } - public string BackingColumnName { get; set; } - public DabField(string alias, string backingColumnName) - { - Alias = alias; - BackingColumnName = backingColumnName; - } + Alias = alias; + BackingColumnName = backingColumnName; + } - public DabField(string backingColumnName) - { - Alias = backingColumnName; - BackingColumnName = backingColumnName; - } + /// + /// Creates a new DabField instance with only the backing column name + /// where the alias is the same as the backing column name. + /// + /// Database column name. + public DabField(string backingColumnName) + { + Alias = backingColumnName; + BackingColumnName = backingColumnName; } } diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index 8cf9a5bfe2..08eb3a0f8d 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -224,7 +224,7 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper [DataRow(DATETIMEOFFSET_TYPE, "neq", "'1999-01-08 10:23:54.9999999-14:00'", "\"1999-01-08 10:23:54.9999999-14:00\"", "!=", DisplayName = "datetimeoffset type filter and orderby test with neq operator")] [DataRow(DATETIMEOFFSET_TYPE, "lt", "'9999-12-31 23:59:59.9999999'", "\"9999-12-31 23:59:59.9999999Z\"", "<", - DisplayName = "datetimeoffset type filter and orderby test with lt operator and max value for datetimeoffset.")] + DisplayName = "datetimeoffset type filter and orderby test with lt operator and max value (with UTC offset specified) for datetimeoffset.")] [DataRow(DATETIMEOFFSET_TYPE, "eq", "'1999-01-08 10:23:54.9999999-14:00'", "\"1999-01-08 10:23:54.9999999-14:00\"", "=", DisplayName = "datetimeoffset type filter and orderby test with eq operator")] [DataRow(DATE_TYPE, "eq", "'1999-01-08'", "\"1999-01-08\"", "=", @@ -253,7 +253,8 @@ public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOper DisplayName = "datetime2 type filter and orderby test with neq operator")] public async Task QueryTypeColumnFilterAndOrderByDateTime(string type, string filterOperator, string sqlValue, string gqlValue, string queryOperator) { - // In MySQL, the DATETIME data type supports a range from '1000-01-01 00:00:00.0000000' to '9999-12-31 23:59:59.0000000' + // In MySQL, the DATETIME data type supports a range from '1000-01-01 00:00:00.0000000' to '9999-12-31 23:59:59.499999' + // https://dev.mysql.com/doc/refman/8.4/en/datetime.html if (DatabaseEngine is TestCategory.MYSQL && sqlValue is "'9999-12-31 23:59:59.9999999'") { sqlValue = "'9999-12-31 23:59:59.0000000'"; @@ -554,8 +555,6 @@ public async Task UpdateTypeColumn(string type, string value) string expected = await GetDatabaseResultAsync(dbQuery); PerformTestEqualsForExtendedTypes(type, expected, actual.ToString()); - - //await ResetDbStateAsync(); } [DataTestMethod] @@ -596,8 +595,6 @@ public async Task UpdateTypeColumnWithArgument(string type, object value) string expected = await GetDatabaseResultAsync(dbQuery); PerformTestEqualsForExtendedTypes(type, expected, actual.ToString()); - - //await ResetDbStateAsync(); } #endregion diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs index 34e17a4bda..1406ee555e 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; -using HotChocolate.Types.NodaTime; using Microsoft.VisualStudio.TestTools.UnitTesting; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedDateTimeTypes; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedHotChocolateTypes; diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index 11975f61da..45d8ef35a0 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using HotChocolate.Types.NodaTime; using Microsoft.VisualStudio.TestTools.UnitTesting; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedDateTimeTypes; using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedHotChocolateTypes; From b304dc4af57ab6a700141636727f4f1a7cf70c1e Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 14 Jun 2024 17:53:52 -0700 Subject: [PATCH 10/20] Removed commented code. Updated Single_type graphql tests to accommodate pg differences with 'real' conversion. --- .../GraphQLSupportedTypesTestsBase.cs | 8 ----- .../MsSqlGQLSupportedTypesTests.cs | 25 ++++++++++++++-- .../MySqlGQLSupportedTypesTests.cs | 30 +++++++++++++++++-- .../PostgreSqlGQLSupportedTypesTests.cs | 30 +++++++++++++++---- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index 08eb3a0f8d..9be5bc930b 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -136,12 +136,6 @@ public async Task QueryTypeColumn(string type, int id) [DataRow(LONG_TYPE, "eq", "-1", "-1", "=")] [DataRow(STRING_TYPE, "neq", "'foo'", "\"foo\"", "!=")] [DataRow(STRING_TYPE, "eq", "'lksa;jdflasdf;alsdflksdfkldj'", "\"lksa;jdflasdf;alsdflksdfkldj\"", "=")] - [DataRow(SINGLE_TYPE, "gt", "-9.3", "-9.3", ">")] - [DataRow(SINGLE_TYPE, "gte", "-9.2", "-9.2", ">=")] - [DataRow(SINGLE_TYPE, "lt", ".33", "0.33", "<")] - [DataRow(SINGLE_TYPE, "lte", "real '.33'", "0.33", "<=")] - [DataRow(SINGLE_TYPE, "neq", "9.2", "9.2", "!=")] - [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] [DataRow(FLOAT_TYPE, "gt", "-9.2", "-9.2", ">")] [DataRow(FLOAT_TYPE, "gte", "-9.2", "-9.2", ">=")] [DataRow(FLOAT_TYPE, "lt", ".33", "0.33", "<")] @@ -423,8 +417,6 @@ public async Task InsertIntoTypeColumn(string type, string value) PerformTestEqualsForExtendedTypes(type, expectedResult, actual.ToString()); } - public abstract Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult); - /// /// Test case for invalid time, such as negative values or hours>24 or minutes/seconds>60. /// diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs index 7d283d9a82..b9bca0dc1e 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; +using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedHotChocolateTypes; namespace Azure.DataApiBuilder.Service.Tests.SqlTests.GraphQLSupportedTypesTests { @@ -22,9 +23,29 @@ public static async Task SetupAsync(TestContext context) await InitializeTestFixture(); } - public override Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) + /// + /// MSSQL Single Type Tests. + /// + /// GraphQL Type + /// Comparison operator: gt, lt, gte, lte, etc. + /// Value to be set in "expected value" sql query. + /// GraphQL input value supplied. + /// Query operator for "expected value" sql query. + [DataRow(SINGLE_TYPE, "gt", "-9.3", "-9.3", ">")] + [DataRow(SINGLE_TYPE, "gte", "-9.'", "-9.2", ">=")] + [DataRow(SINGLE_TYPE, "lt", ".33", "0.33", "<")] + [DataRow(SINGLE_TYPE, "lte", ".33", "0.33", "<=")] + [DataRow(SINGLE_TYPE, "neq", "9.2", "9.2", "!=")] + [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] + [DataTestMethod] + public async Task MSSQL_real_graphql_single_filter_expectedValues( + string type, + string filterOperator, + string sqlValue, + string gqlValue, + string queryOperator) { - throw new System.NotImplementedException(); + await QueryTypeColumnFilterAndOrderBy(type, filterOperator, sqlValue, gqlValue, queryOperator); } protected override string MakeQueryOnTypeTable(List queryFields, int id) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs index 1406ee555e..0099282c91 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs @@ -69,7 +69,7 @@ public static async Task SetupAsync(TestContext context) [DataRow("9999-12-31", "9999-12-31T00:00:00.000Z", DisplayName = "Max date for datetime column stored with zeroed out time.")] [DataRow("1000-01-01", "1000-01-01T00:00:00.000Z", DisplayName = "Min date for datetime column stored with zeroed out time.")] [DataTestMethod] - public override async Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) + public async Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) { // Arrange const string DATETIME_FIELD = "datetime_types"; @@ -87,7 +87,7 @@ public override async Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsE Assert.AreEqual( expected: expectedResult, actual: actual.GetProperty(DATETIME_FIELD).GetString(), - message: "get back towork jr"); + message: "Unexpected datetime value."); } /// @@ -105,11 +105,35 @@ public override async Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsE public async Task InsertMutationInput_DateTimeTypes_TimeOnly_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) { // Arrange - //expectedResult = DateTime.Parse(dateTimeGraphQLInput).ToString("yyyy-MM-ddT") + expectedResult; expectedResult = DateTime.UtcNow.ToString("yyyy-MM-ddT") + expectedResult; await InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(dateTimeGraphQLInput, expectedResult); } + /// + /// MySql Single Type Tests. + /// + /// GraphQL Type + /// Comparison operator: gt, lt, gte, lte, etc. + /// Value to be set in "expected value" sql query. + /// GraphQL input value supplied. + /// Query operator for "expected value" sql query. + [DataRow(SINGLE_TYPE, "gt", "-9.3", "-9.3", ">")] + [DataRow(SINGLE_TYPE, "gte", "-9.'", "-9.2", ">=")] + [DataRow(SINGLE_TYPE, "lt", ".33", "0.33", "<")] + [DataRow(SINGLE_TYPE, "lte", ".33", "0.33", "<=")] + [DataRow(SINGLE_TYPE, "neq", "9.2", "9.2", "!=")] + [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] + [DataTestMethod] + public async Task MySql_real_graphql_single_filter_expectedValues( + string type, + string filterOperator, + string sqlValue, + string gqlValue, + string queryOperator) + { + await QueryTypeColumnFilterAndOrderBy(type, filterOperator, sqlValue, gqlValue, queryOperator); + } + protected override string MakeQueryOnTypeTable(List queryFields, int id) { return MakeQueryOnTypeTable(queryFields, filterValue: id.ToString(), filterField: "id"); diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index 45d8ef35a0..fa7e225078 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -24,6 +24,31 @@ public static async Task SetupAsync(TestContext context) await InitializeTestFixture(); } + /// + /// Postgres requires conversion of 0.33 to 'real' type otherwise precision is lost. + /// + /// GraphQL Type + /// Comparison operator: gt, lt, gte, lte, etc. + /// Value to be set in "expected value" sql query. + /// GraphQL input value supplied. + /// Query operator for "expected value" sql query. + [DataRow(SINGLE_TYPE, "gt", "real '-9.3'", "-9.3", ">")] + [DataRow(SINGLE_TYPE, "gte", "real '-9.2'", "-9.2", ">=")] + [DataRow(SINGLE_TYPE, "lt", "real '.33'", "0.33", "<")] + [DataRow(SINGLE_TYPE, "lte", "real '.33'", "0.33", "<=")] + [DataRow(SINGLE_TYPE, "neq", "real '9.2'", "9.2", "!=")] + [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] + [DataTestMethod] + public async Task PG_real_graphql_single_filter_expectedValues( + string type, + string filterOperator, + string sqlValue, + string gqlValue, + string queryOperator) + { + await QueryTypeColumnFilterAndOrderBy(type, filterOperator, sqlValue, gqlValue, queryOperator); + } + protected override string MakeQueryOnTypeTable(List queryFields, int id) { return MakeQueryOnTypeTable(queryFields, filterValue: id.ToString(), filterField: "id"); @@ -89,10 +114,5 @@ private static string ProperlyFormatTypeTableColumn(string columnName) { Assert.Inconclusive("Test skipped for PostgreSql."); } - - public override Task InsertMutationInput_DateTimeTypes_ValidRange_ReturnsExpectedValues(string dateTimeGraphQLInput, string expectedResult) - { - throw new System.NotImplementedException(); - } } } From 98004ac856658f6e51e54c563941306fb739d7ec Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 14 Jun 2024 17:54:11 -0700 Subject: [PATCH 11/20] Formatting --- .../PostgreSqlGQLSupportedTypesTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index fa7e225078..e20640486c 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -40,10 +40,10 @@ public static async Task SetupAsync(TestContext context) [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] [DataTestMethod] public async Task PG_real_graphql_single_filter_expectedValues( - string type, - string filterOperator, + string type, + string filterOperator, string sqlValue, - string gqlValue, + string gqlValue, string queryOperator) { await QueryTypeColumnFilterAndOrderBy(type, filterOperator, sqlValue, gqlValue, queryOperator); From 2bf92798ad0cbf32792c18ca21e5f18079f3ba56 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 14 Jun 2024 18:00:07 -0700 Subject: [PATCH 12/20] fix test input --- .../GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs | 2 +- .../GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs index b9bca0dc1e..0b25a38423 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs @@ -32,7 +32,7 @@ public static async Task SetupAsync(TestContext context) /// GraphQL input value supplied. /// Query operator for "expected value" sql query. [DataRow(SINGLE_TYPE, "gt", "-9.3", "-9.3", ">")] - [DataRow(SINGLE_TYPE, "gte", "-9.'", "-9.2", ">=")] + [DataRow(SINGLE_TYPE, "gte", "-9.", "-9.2", ">=")] [DataRow(SINGLE_TYPE, "lt", ".33", "0.33", "<")] [DataRow(SINGLE_TYPE, "lte", ".33", "0.33", "<=")] [DataRow(SINGLE_TYPE, "neq", "9.2", "9.2", "!=")] diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs index 0099282c91..f7fda4cdca 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs @@ -118,7 +118,7 @@ public async Task InsertMutationInput_DateTimeTypes_TimeOnly_ValidRange_ReturnsE /// GraphQL input value supplied. /// Query operator for "expected value" sql query. [DataRow(SINGLE_TYPE, "gt", "-9.3", "-9.3", ">")] - [DataRow(SINGLE_TYPE, "gte", "-9.'", "-9.2", ">=")] + [DataRow(SINGLE_TYPE, "gte", "-9.2", "-9.2", ">=")] [DataRow(SINGLE_TYPE, "lt", ".33", "0.33", "<")] [DataRow(SINGLE_TYPE, "lte", ".33", "0.33", "<=")] [DataRow(SINGLE_TYPE, "neq", "9.2", "9.2", "!=")] From 6f7921b049c5efa9fa0ab48bf5670590cfe5ea7f Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 14 Jun 2024 18:09:18 -0700 Subject: [PATCH 13/20] fix test --- .../GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs index 0b25a38423..66832b958c 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MsSqlGQLSupportedTypesTests.cs @@ -32,7 +32,7 @@ public static async Task SetupAsync(TestContext context) /// GraphQL input value supplied. /// Query operator for "expected value" sql query. [DataRow(SINGLE_TYPE, "gt", "-9.3", "-9.3", ">")] - [DataRow(SINGLE_TYPE, "gte", "-9.", "-9.2", ">=")] + [DataRow(SINGLE_TYPE, "gte", "-9.2", "-9.2", ">=")] [DataRow(SINGLE_TYPE, "lt", ".33", "0.33", "<")] [DataRow(SINGLE_TYPE, "lte", ".33", "0.33", "<=")] [DataRow(SINGLE_TYPE, "neq", "9.2", "9.2", "!=")] From 674c4d7ce601986c48a4cab6130f27abd3a6f152 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 19 Jun 2024 16:12:13 -0700 Subject: [PATCH 14/20] update type -> graphqldatatype for specificity per pr feedback. --- .../MySqlGQLSupportedTypesTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs index f7fda4cdca..04ce926ad6 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs @@ -112,7 +112,7 @@ public async Task InsertMutationInput_DateTimeTypes_TimeOnly_ValidRange_ReturnsE /// /// MySql Single Type Tests. /// - /// GraphQL Type + /// GraphQL Data Type /// Comparison operator: gt, lt, gte, lte, etc. /// Value to be set in "expected value" sql query. /// GraphQL input value supplied. @@ -125,13 +125,13 @@ public async Task InsertMutationInput_DateTimeTypes_TimeOnly_ValidRange_ReturnsE [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] [DataTestMethod] public async Task MySql_real_graphql_single_filter_expectedValues( - string type, + string graphqlDataType, string filterOperator, string sqlValue, string gqlValue, string queryOperator) { - await QueryTypeColumnFilterAndOrderBy(type, filterOperator, sqlValue, gqlValue, queryOperator); + await QueryTypeColumnFilterAndOrderBy(graphqlDataType, filterOperator, sqlValue, gqlValue, queryOperator); } protected override string MakeQueryOnTypeTable(List queryFields, int id) From 7cf81095869c8be9bdae6d6044148c39a3afb601 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar <102276754+abhishekkumams@users.noreply.github.com> Date: Thu, 4 Jul 2024 16:24:51 +0530 Subject: [PATCH 15/20] Update src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs Co-authored-by: Aniruddh Munde --- .../SqlTests/GraphQLSupportedTypesTests/DabField.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs index 53b6c0c8c8..344b659041 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/DabField.cs @@ -24,7 +24,7 @@ public class DabField /// Creates a new DabField instance with both alias and backing column name. /// /// Mapped (aliased) column name defined in DAB runtime config. - /// + /// Database column name. public DabField(string alias, string backingColumnName) { Alias = alias; From 8351553c1d37032fd2a39d53d8ddf6669adee7b1 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar <102276754+abhishekkumams@users.noreply.github.com> Date: Thu, 4 Jul 2024 16:25:05 +0530 Subject: [PATCH 16/20] Update src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs Co-authored-by: Aniruddh Munde --- .../GraphQLSupportedTypesTestsBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index 9be5bc930b..c7f1023ac1 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -251,7 +251,7 @@ public async Task QueryTypeColumnFilterAndOrderByDateTime(string type, string fi // https://dev.mysql.com/doc/refman/8.4/en/datetime.html if (DatabaseEngine is TestCategory.MYSQL && sqlValue is "'9999-12-31 23:59:59.9999999'") { - sqlValue = "'9999-12-31 23:59:59.0000000'"; + sqlValue = "'9999-12-31 23:59:59.499999"; gqlValue = "\"9999-12-31 23:59:59.0000000\""; } From 597bb0b24a1b4fe9231936c8eeedfed44dd23441 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Jul 2024 17:26:07 +0530 Subject: [PATCH 17/20] fixing nits --- .../GraphQLSupportedTypesTestsBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs index c7f1023ac1..1ad5bbc93e 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs @@ -595,7 +595,7 @@ public async Task UpdateTypeColumnWithArgument(string type, object value) /// Utility function to do special comparisons for some of the extended types /// if json compare doesn't suffice /// - public static void PerformTestEqualsForExtendedTypes(string type, string expected, string actual) + protected static void PerformTestEqualsForExtendedTypes(string type, string expected, string actual) { switch (type) { From d97cbef1971f00f06b57b122fe2632486b7c1441 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Jul 2024 17:42:01 +0530 Subject: [PATCH 18/20] test type conversion to real in postgres --- .../PostgreSqlGQLSupportedTypesTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index e20640486c..e3c5adfb72 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -25,6 +25,7 @@ public static async Task SetupAsync(TestContext context) } /// + /// Postgres Single Type Test. /// Postgres requires conversion of 0.33 to 'real' type otherwise precision is lost. /// /// GraphQL Type @@ -35,8 +36,8 @@ public static async Task SetupAsync(TestContext context) [DataRow(SINGLE_TYPE, "gt", "real '-9.3'", "-9.3", ">")] [DataRow(SINGLE_TYPE, "gte", "real '-9.2'", "-9.2", ">=")] [DataRow(SINGLE_TYPE, "lt", "real '.33'", "0.33", "<")] - [DataRow(SINGLE_TYPE, "lte", "real '.33'", "0.33", "<=")] - [DataRow(SINGLE_TYPE, "neq", "real '9.2'", "9.2", "!=")] + [DataRow(SINGLE_TYPE, "lte", "'.33'", "0.33", "<=")] + [DataRow(SINGLE_TYPE, "neq", "'9.2'", "9.2", "!=")] [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] [DataTestMethod] public async Task PG_real_graphql_single_filter_expectedValues( From aa7aacab3201cc00c5a0dbb7c869c51a338c78f5 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Jul 2024 19:01:36 +0530 Subject: [PATCH 19/20] fixing nits --- .../PostgreSqlGQLSupportedTypesTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index e3c5adfb72..2c5f8bb3ec 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -36,9 +36,9 @@ public static async Task SetupAsync(TestContext context) [DataRow(SINGLE_TYPE, "gt", "real '-9.3'", "-9.3", ">")] [DataRow(SINGLE_TYPE, "gte", "real '-9.2'", "-9.2", ">=")] [DataRow(SINGLE_TYPE, "lt", "real '.33'", "0.33", "<")] - [DataRow(SINGLE_TYPE, "lte", "'.33'", "0.33", "<=")] - [DataRow(SINGLE_TYPE, "neq", "'9.2'", "9.2", "!=")] - [DataRow(SINGLE_TYPE, "eq", "'0.33'", "0.33", "=")] + [DataRow(SINGLE_TYPE, "lte", "real '.33'", "0.33", "<=")] + [DataRow(SINGLE_TYPE, "neq", "real '9.2'", "9.2", "!=")] + [DataRow(SINGLE_TYPE, "eq", "real '0.33'", "0.33", "=")] [DataTestMethod] public async Task PG_real_graphql_single_filter_expectedValues( string type, From af9e89c8d3d73f00e4fe08140fe68497d5bc40cb Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Jul 2024 19:02:11 +0530 Subject: [PATCH 20/20] fixing nits --- .../PostgreSqlGQLSupportedTypesTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs index 2c5f8bb3ec..dc1e8e7d51 100644 --- a/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs +++ b/src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/PostgreSqlGQLSupportedTypesTests.cs @@ -26,7 +26,7 @@ public static async Task SetupAsync(TestContext context) /// /// Postgres Single Type Test. - /// Postgres requires conversion of 0.33 to 'real' type otherwise precision is lost. + /// Postgres requires conversion of a float value, ex: 0.33 to 'real' type otherwise precision is lost. /// /// GraphQL Type /// Comparison operator: gt, lt, gte, lte, etc.