Skip to content

Commit

Permalink
Add order by and filter tests for missing SQL Types to GQL (#1557)
Browse files Browse the repository at this point in the history
## Why make this change?

Closes #1533
Our test coverage was missing order by and filter tests for a most of
the SQL Types we support in GQL. We add those tests. Adding `DateTime`
support for PostgreSql will take additional work. Those tests are
bypassed for now.

## What is this change?

Adds testing for `order by` and `filter` for all the DB types within
GQL, with the exception of `DateTime` for `PostgreSql`.

## How was this tested?

Ran against our test suite.

## Sample Request(s)

The valid GQL is included within the test cases. These can be copied if
you wish to run manually.
  • Loading branch information
aaronburtle authored Jul 24, 2023
1 parent f260f28 commit ebe4ef4
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/Service.Tests/DatabaseSchema-MsSql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ VALUES
'0001-01-01', '1753-01-01 00:00:00.000', '0001-01-01 00:00:00.0000000', '0001-01-01 00:00:00.0000000+0:00', '1900-01-01 00:00:00',
0x00000000),
(4, 255, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, 1,
'9999-12-31', '9999-12-31 23:59:59', '9999-12-31 23:59:59.9999999', '9999-12-31 23:59:59.9999999+14:00', '2079-06-06',
'9998-12-31', '9998-12-31 23:59:59', '9998-12-31 23:59:59.9999999', '9998-12-31 23:59:59.9999999+00:00', '2079-06-06',
0xFFFFFFFF),
(5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
SET IDENTITY_INSERT type_table OFF
Expand Down
2 changes: 1 addition & 1 deletion src/Service.Tests/DatabaseSchema-MySql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ INSERT INTO type_table(id, byte_types, short_types, int_types, long_types, strin
(1, 1, 1, 1, 1, '', 0.33, 0.33, 0.333333, true, '1999-01-08 10:23:54', 0xABCDEF0123),
(2, 0, -1, -1, -1, 'lksa;jdflasdf;alsdflksdfkldj', -9.2, -9.2, -9.292929, false, '1999-01-08 10:23:00', 0x98AB7511AABB1234),
(3, 0, -32768, -2147483648, -9223372036854775808, '', -3.4E38, -1.7E308, 2.929292E-19, true, '1753-01-01 00:00:00.000', 0x00000000),
(4, 255, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9999-12-31 23:59:59', 0xFFFFFFFF),
(4, 255, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9998-12-31 23:59:59', 0xFFFFFFFF),
(5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO trees(treeId, species, region, height) VALUES (1, 'Tsuga terophylla', 'Pacific Northwest', '30m'), (2, 'Pseudotsuga menziesii', 'Pacific Northwest', '40m');
INSERT INTO fungi(speciesid, region) VALUES (1, 'northeast'), (2, 'southwest');
Expand Down
2 changes: 1 addition & 1 deletion src/Service.Tests/DatabaseSchema-PostgreSql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ INSERT INTO type_table(id, short_types, int_types, long_types, string_types, sin
(1, 1, 1, 1, '', 0.33, 0.33, 0.333333, true, '1999-01-08 10:23:54', '\xABCDEF0123'),
(2, -1, -1, -1, 'lksa;jdflasdf;alsdflksdfkldj', -9.2, -9.2, -9.292929, false, '19990108 10:23:00', '\x98AB7511AABB1234'),
(3, -32768, -2147483648, -9223372036854775808, '', -3.4E38, -1.7E308, 2.929292E-19, true, '1753-01-01 00:00:00.000', '\x00000000'),
(4, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9999-12-31 23:59:59.997', '\xFFFFFFFF'),
(4, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9998-12-31 23:59:59.997', '\xFFFFFFFF'),
(5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO trees("treeId", species, region, height) VALUES (1, 'Tsuga terophylla', 'Pacific Northwest', '30m'), (2, 'Pseudotsuga menziesii', 'Pacific Northwest', '40m');
INSERT INTO fungi(speciesid, region) VALUES (1, 'northeast'), (2, 'southwest');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ public static async Task SetupAsync(TestContext context)
[DataRow("boolean_types", "false", "true", 2, 4,
DisplayName = "Test after token for boolean values.")]
[DataRow("date_types", "\"0001-01-01\"",
"\"9999-12-31\"", 3, 4,
"\"9998-12-31\"", 3, 4,
DisplayName = "Test after token for date values.")]
[DataRow("datetime_types", "\"1753-01-01T00:00:00.000\"",
"\"9999-12-31T23:59:59\"", 3, 4,
"\"9998-12-31T23:59:59\"", 3, 4,
DisplayName = "Test after token for datetime values.")]
[DataRow("datetime2_types", "\"0001-01-01 00:00:00.0000000\"",
"\"9999-12-31T23:59:59.9999999\"", 3, 4,
"\"9998-12-31T23:59:59.9999999\"", 3, 4,
DisplayName = "Test after token for datetime2 values.")]
[DataRow("datetimeoffset_types", "\"0001-01-01 00:00:00.0000000+0:00\"",
"\"9999-12-31T23:59:59.9999999+14:00\"", 3, 4,
"\"9998-12-31T23:59:59.9999999+00:00\"", 3, 4,
DisplayName = "Test after token for datetimeoffset values.")]
[DataRow("smalldatetime_types", "\"1900-01-01 00:00:00\"",
"\"2079-06-06T00:00:00\"", 3, 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static async Task SetupAsync(TestContext context)
[DataRow("boolean_types", "false", "true", 2, 4,
DisplayName = "Test after token for boolean values.")]
[DataRow("datetime_types", "\"1753-01-01T00:00:00.000\"",
"\"9999-12-31 23:59:59.000000\"", 3, 4,
"\"9998-12-31 23:59:59.000000\"", 3, 4,
DisplayName = "Test after token for datetime values.")]
[DataRow("bytearray_types", "\"AAAAAA==\"", "\"/////w==\"", 3, 4,
DisplayName = "Test after token for bytearray values.")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static async Task SetupAsync(TestContext context)
[DataRow("boolean_types", "false", "true", 2, 4,
DisplayName = "Test after token for boolean values.")]
[DataRow("datetime_types", "\"1753-01-01T00:00:00.000\"",
"\"9999-12-31T23:59:59.997\"", 3, 4,
"\"9998-12-31T23:59:59.997\"", 3, 4,
DisplayName = "Test after token for datetime values.")]
[DataRow("bytearray_types", "\"AAAAAA==\"", "\"/////w==\"", 3, 4,
DisplayName = "Test after token for bytearray values.")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -86,6 +87,115 @@ public async Task QueryTypeColumn(string type, int id)
PerformTestEqualsForExtendedTypes(type, expected, actual.ToString());
}

[DataTestMethod]
[DataRow(BYTE_TYPE, "gt", "0", "0", ">")]
[DataRow(BYTE_TYPE, "gte", "0", "0", ">=")]
[DataRow(BYTE_TYPE, "lt", "1", "1", "<")]
[DataRow(BYTE_TYPE, "lte", "1", "1", "<=")]
[DataRow(BYTE_TYPE, "neq", "0", "0", "!=")]
[DataRow(BYTE_TYPE, "eq", "1", "1", "=")]
[DataRow(SHORT_TYPE, "gt", "-1", "-1", ">")]
[DataRow(SHORT_TYPE, "gte", "-1", "-1", ">=")]
[DataRow(SHORT_TYPE, "lt", "1", "1", "<")]
[DataRow(SHORT_TYPE, "lte", "1", "1", "<=")]
[DataRow(SHORT_TYPE, "neq", "1", "1", "!=")]
[DataRow(SHORT_TYPE, "eq", "-1", "-1", "=")]
[DataRow(INT_TYPE, "gt", "-1", "-1", ">")]
[DataRow(INT_TYPE, "gte", "2147483647", "2147483647", " >= ")]
[DataRow(INT_TYPE, "lt", "1", "1", "<")]
[DataRow(INT_TYPE, "lte", "-2147483648", "-2147483648", " <= ")]
[DataRow(INT_TYPE, "neq", "1", "1", "!=")]
[DataRow(INT_TYPE, "eq", "-1", "-1", "=")]
[DataRow(LONG_TYPE, "gt", "-1", "-1", ">")]
[DataRow(LONG_TYPE, "gte", "9223372036854775807", "9223372036854775807", " >= ")]
[DataRow(LONG_TYPE, "lt", "1", "1", "<")]
[DataRow(LONG_TYPE, "lte", "-9223372036854775808", "-9223372036854775808", " <= ")]
[DataRow(LONG_TYPE, "neq", "1", "1", "!=")]
[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", ".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", "<")]
[DataRow(FLOAT_TYPE, "lte", ".33", "0.33", "<=")]
[DataRow(FLOAT_TYPE, "neq", "-9.2", "-9.2", "!=")]
[DataRow(FLOAT_TYPE, "eq", "-9.2", "-9.2", "=")]
[DataRow(DECIMAL_TYPE, "gt", "-9.292929", "-9.292929", " > ")]
[DataRow(DECIMAL_TYPE, "gte", "-9.292929", "-9.292929", " >= ")]
[DataRow(DECIMAL_TYPE, "lt", "0.333333", "0.333333", "<")]
[DataRow(DECIMAL_TYPE, "lte", "0.333333", "0.333333", " <= ")]
[DataRow(DECIMAL_TYPE, "neq", "0.0", "0.0", "!=")]
[DataRow(DECIMAL_TYPE, "eq", "-9.292929", "-9.292929", "=")]
[DataRow(BOOLEAN_TYPE, "neq", "\'false\'", "false", "!=")]
[DataRow(BOOLEAN_TYPE, "eq", "\'false\'", "false", "=")]
public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOperator, string sqlValue, string gqlValue, string queryOperator)
{
if (!IsSupportedType(type))
{
Assert.Inconclusive("Type not supported");
}

string field = $"{type.ToLowerInvariant()}_types";
string graphQLQueryName = "supportedTypes";
string gqlQuery = @"{
supportedTypes(first: 100 orderBy: { " + field + ": ASC } filter: { " + field + ": {" + filterOperator + ": " + gqlValue + @"} }) {
items {
" + field + @"
}
}
}";

string dbQuery = MakeQueryOnTypeTable(new List<string> { field }, filterValue: sqlValue, filterOperator: queryOperator, filterField: field, orderBy: field, limit: "100");

JsonElement actual = await ExecuteGraphQLRequestAsync(gqlQuery, graphQLQueryName, isAuthenticated: false);
string expected = await GetDatabaseResultAsync(dbQuery);

PerformTestEqualsForExtendedTypes(type, expected, actual.GetProperty("items").ToString());
}

/// <summary>
/// Separate test case for DateTime to allow overwrite for postgreSql.
/// Year 9998 used in test and data within test tables to avoid out of
/// date range error within GQL.
/// </summary>
[DataTestMethod]
[DataRow(DATETIME_TYPE, "gt", "\'1999-01-08\'", "\"1999-01-08\"", " > ")]
[DataRow(DATETIME_TYPE, "gte", "\'1999-01-08\'", "\"1999-01-08\"", " >= ")]
[DataRow(DATETIME_TYPE, "lt", "\'0001-01-01\'", "\"0001-01-01\"", " < ")]
[DataRow(DATETIME_TYPE, "lte", "\'0001-01-01\'", "\"0001-01-01\"", " <= ")]
[DataRow(DATETIME_TYPE, "neq", "\'0001-01-01\'", "\"0001-01-01\"", "!=")]
[DataRow(DATETIME_TYPE, "eq", "\'0001-01-01\'", "\"0001-01-01T01:01:01\"", "=")]
[DataRow(DATETIME_TYPE, "gt", "\'1999-01-08 10:23:00\'", "\"1999-01-08 10:23:00\"", " > ")]
[DataRow(DATETIME_TYPE, "gte", "\'1999-01-08 10:23:00\'", "\"1999-01-08 10:23:00\"", " >= ")]
[DataRow(DATETIME_TYPE, "lt", "\'9998-12-31 23:59:59\'", "\"9998-12-31 23:59:59\"", " < ")]
[DataRow(DATETIME_TYPE, "lte", "\'9998-12-31 23:59:59\'", "\"9998-12-31 23:59:59\"", " <= ")]
[DataRow(DATETIME_TYPE, "neq", "\'1999-01-08 10:23:00\'", "\"1999-01-08 10:23:00\"", "!=")]
[DataRow(DATETIME_TYPE, "eq", "\'1999-01-08 10:23:00\'", "\"1999-01-08 10:23:00\"", "=")]
[DataRow(DATETIME_TYPE, "gt", "\'1999-01-08 10:23:00.9999999\'", "\"1999-01-08 10:23:00.9999999\"", " > ")]
[DataRow(DATETIME_TYPE, "gte", "\'1999-01-08 10:23:00.9999999\'", "\"1999-01-08 10:23:00.9999999\"", " >= ")]
[DataRow(DATETIME_TYPE, "lt", "\'9998-12-31 23:59:59.9999999\'", "\"9998-12-31 23:59:59.9999999\"", " < ")]
[DataRow(DATETIME_TYPE, "lte", "\'9998-12-31 23:59:59.9999999\'", "\"9998-12-31 23:59:59.9999999\"", " <= ")]
[DataRow(DATETIME_TYPE, "neq", "\'1999-01-08 10:23:00.9999999\'", "\"1999-01-08 10:23:00.9999999\"", "!=")]
[DataRow(DATETIME_TYPE, "eq", "\'1999-01-08 10:23:00.9999999\'", "\"1999-01-08 10:23:00.9999999\"", "=")]
[DataRow(DATETIME_TYPE, "neq", "\'1999-01-08 10:23:54.9999999-14:00\'", "\"1999-01-08 10:23:54.9999999-14:00\"", "!=")]
[DataRow(DATETIME_TYPE, "eq", "\'1999-01-08 10:23:54.9999999-14:00\'", "\"1999-01-08 10:23:54.9999999-14:00\"", "=")]
[DataRow(DATETIME_TYPE, "gt", "\'1999-01-08 10:22:00\'", "\"1999-01-08 10:22:00\"", " > ")]
[DataRow(DATETIME_TYPE, "gte", "\'1999-01-08 10:23:54\'", "\"1999-01-08 10:23:54\"", " >= ")]
[DataRow(DATETIME_TYPE, "lt", "\'2079-06-06\'", "\"2079-06-06\"", " < ")]
[DataRow(DATETIME_TYPE, "lte", "\'2079-06-06\'", "\"2079-06-06\"", " <= ")]
[DataRow(DATETIME_TYPE, "neq", "\'1999-01-08 10:23:54\'", "\"1999-01-08 10:23:54\"", "!=")]
[DataRow(DATETIME_TYPE, "eq", "\'1999-01-08 10:23:54\'", "\"1999-01-08 10:23:54\"", "=")]
public async Task QueryTypeColumnFilterAndOrderByDateTime(string type, string filterOperator, string sqlValue, string gqlValue, string queryOperator)
{
await QueryTypeColumnFilterAndOrderBy(type, filterOperator, sqlValue, gqlValue, queryOperator);
}

[DataTestMethod]
[DataRow(BYTE_TYPE, "255")]
[DataRow(BYTE_TYPE, "0")]
Expand Down Expand Up @@ -337,8 +447,16 @@ private static void CompareFloatResults(string floatType, string actual, string
using JsonDocument actualJsonDoc = JsonDocument.Parse(actual);
using JsonDocument expectedJsonDoc = JsonDocument.Parse(expected);

string actualFloat = actualJsonDoc.RootElement.GetProperty(fieldName).ToString();
string expectedFloat = expectedJsonDoc.RootElement.GetProperty(fieldName).ToString();
if (actualJsonDoc.RootElement.ValueKind is JsonValueKind.Array)
{
ValidateArrayResults(actualJsonDoc, expectedJsonDoc, fieldName);
return;
}

string actualFloat;
string expectedFloat;
actualFloat = actualJsonDoc.RootElement.GetProperty(fieldName).ToString();
expectedFloat = expectedJsonDoc.RootElement.GetProperty(fieldName).ToString();

// handles cases when one of the values is null
if (string.IsNullOrEmpty(actualFloat) || string.IsNullOrEmpty(expectedFloat))
Expand Down Expand Up @@ -375,6 +493,12 @@ private static void CompareDateTimeResults(string actual, string expected)
using JsonDocument actualJsonDoc = JsonDocument.Parse(actual);
using JsonDocument expectedJsonDoc = JsonDocument.Parse(expected);

if (actualJsonDoc.RootElement.ValueKind is JsonValueKind.Array)
{
ValidateArrayResults(actualJsonDoc, expectedJsonDoc, fieldName);
return;
}

string actualDateTime = actualJsonDoc.RootElement.GetProperty(fieldName).ToString();
string expectedDateTime = expectedJsonDoc.RootElement.GetProperty(fieldName).ToString();

Expand All @@ -389,6 +513,34 @@ private static void CompareDateTimeResults(string actual, string expected)
}
}

private static void ValidateArrayResults(JsonDocument actualJsonDoc, JsonDocument expectedJsonDoc, string fieldName)
{
JsonElement.ArrayEnumerator actualEnumerater = actualJsonDoc.RootElement.EnumerateArray();
foreach (JsonElement expectedElement in expectedJsonDoc.RootElement.EnumerateArray())
{
actualEnumerater.MoveNext();
JsonElement actualElement = actualEnumerater.Current;
actualElement.TryGetProperty(fieldName, out JsonElement actualValue);
expectedElement.TryGetProperty(fieldName, out JsonElement expectedValue);

if (fieldName.StartsWith(DATETIME_TYPE.ToLower()))
{
// MySql returns a format that will not directly parse into DateTime type so we use string here for parsing
DateTime actualDateTime = DateTime.Parse(actualValue.ToString(), CultureInfo.InvariantCulture, DateTimeStyles.None);
DateTime expectedDateTime = DateTime.Parse(expectedValue.ToString(), CultureInfo.InvariantCulture, DateTimeStyles.None);
Assert.AreEqual(expectedDateTime, actualDateTime);
}
else if (fieldName.StartsWith(SINGLE_TYPE.ToLower()))
{
Assert.AreEqual(expectedValue.GetSingle(), actualValue.GetSingle());
}
else
{
Assert.AreEqual(expectedValue.GetDouble(), actualValue.GetDouble());
}
}
}

/// <summary>
/// Needed to map the type name to a graphql type in argument tests
/// where the argument type need to be specified.
Expand All @@ -403,6 +555,14 @@ private static string TypeNameToGraphQLType(string typeName)
return typeName;
}

protected abstract string MakeQueryOnTypeTable(
List<string> queriedColumns,
string filterValue = "1",
string filterOperator = "=",
string filterField = "1",
string orderBy = "id",
string limit = "1");

protected abstract string MakeQueryOnTypeTable(List<string> columnsToQuery, int id);
protected virtual bool IsSupportedType(string type)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,28 @@ public static async Task SetupAsync(TestContext context)
await InitializeTestFixture(context);
}

protected override string MakeQueryOnTypeTable(List<string> queriedColumns, int id)
protected override string MakeQueryOnTypeTable(List<string> columnsToQuery, int id)
{
return MakeQueryOnTypeTable(columnsToQuery, filterValue: id.ToString(), filterField: "id");
}

protected override string MakeQueryOnTypeTable(
List<string> queriedColumns,
string filterValue = "1",
string filterOperator = "=",
string filterField = "1",
string orderBy = "id",
string limit = "1")
{
string format = limit.Equals("1") ? "WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES" : "INCLUDE_NULL_VALUES";
return @"
SELECT TOP 1 " + string.Join(", ", queriedColumns) + @"
SELECT TOP " + limit + " " + string.Join(", ", queriedColumns) + @"
FROM type_table AS [table0]
WHERE id = " + id + @"
ORDER BY id asc
WHERE " + filterField + " " + filterOperator + " " + filterValue + @"
ORDER BY " + orderBy + @" asc
FOR JSON PATH,
WITHOUT_ARRAY_WRAPPER,
INCLUDE_NULL_VALUES
" + format + @"
";
}
}
Expand Down
Loading

0 comments on commit ebe4ef4

Please sign in to comment.