Skip to content

Commit 5d5068c

Browse files
[CherryPick]: Fix for guid filter in GraphQL (0.8) (#1659)
- Cherry picks PR #1644 to 0.8 release as a bug fix patch. --------- Co-authored-by: Ayush Agarwal <[email protected]>
1 parent 3fef26a commit 5d5068c

File tree

14 files changed

+94
-40
lines changed

14 files changed

+94
-40
lines changed

src/Core/Services/ResolverMiddleware.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ protected static bool IsInnerObject(IMiddlewareContext context)
261261
SINGLE_TYPE => ((FloatValueNode)value).ToSingle(),
262262
FLOAT_TYPE => ((FloatValueNode)value).ToDouble(),
263263
DECIMAL_TYPE => ((FloatValueNode)value).ToDecimal(),
264+
// If we reach here, we can be sure that the value will not be null.
265+
UUID_TYPE => Guid.TryParse(value.Value!.ToString(), out Guid guidValue) ? guidValue : value.Value,
264266
_ => value.Value
265267
};
266268
}

src/Service.GraphQLBuilder/GraphQLTypes/SupportedTypes.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
namespace Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes
55
{
66
/// <summary>
7-
/// Only used to group the supported type names under a class with a relevant name
7+
/// Only used to group the supported type names under a class with a relevant name.
8+
/// The type names mentioned here are Hotchocolate scalar built in types.
9+
/// The corresponding SQL type name may be different for e.g. UUID maps to Guid as the SQL type.
810
/// </summary>
911
public static class SupportedTypes
1012
{
13+
public const string UUID_TYPE = "UUID";
1114
public const string BYTE_TYPE = "Byte";
1215
public const string SHORT_TYPE = "Short";
1316
public const string INT_TYPE = "Int";
@@ -20,6 +23,5 @@ public static class SupportedTypes
2023
public const string DATETIME_TYPE = "DateTime";
2124
public const string DATETIME_NONUTC_TYPE = "DateTimeNonUTC";
2225
public const string BYTEARRAY_TYPE = "ByteArray";
23-
public const string GUID_TYPE = "Guid";
2426
}
2527
}

src/Service.GraphQLBuilder/GraphQLUtils.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public static bool IsBuiltInType(ITypeNode typeNode)
4242
HashSet<string> inBuiltTypes = new()
4343
{
4444
"ID",
45+
UUID_TYPE,
4546
BYTE_TYPE,
4647
SHORT_TYPE,
4748
INT_TYPE,

src/Service.GraphQLBuilder/Queries/StandardQueryInputs.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public static InputObjectTypeDefinitionNode StringInputType() =>
169169
new InputValueDefinitionNode(null, new NameNode("endsWith"), new StringValueNode("Ends With"), new StringType().ToTypeNode(), null, new List<DirectiveNode>()),
170170
new InputValueDefinitionNode(null, new NameNode("neq"), new StringValueNode("Not Equals"), new StringType().ToTypeNode(), null, new List<DirectiveNode>()),
171171
new InputValueDefinitionNode(null, new NameNode("caseInsensitive"), new StringValueNode("Case Insensitive"), new BooleanType().ToTypeNode(), new BooleanValueNode(false), new List<DirectiveNode>()),
172-
new InputValueDefinitionNode(null, new NameNode("isNull"), new StringValueNode("Not null test"), new BooleanType().ToTypeNode(), null, new List<DirectiveNode>())
172+
new InputValueDefinitionNode(null, new NameNode("isNull"), new StringValueNode("Is null test"), new BooleanType().ToTypeNode(), null, new List<DirectiveNode>())
173173
}
174174
);
175175

@@ -197,13 +197,32 @@ public static InputObjectTypeDefinitionNode ByteArrayInputType() =>
197197
new StringValueNode("Input type for adding ByteArray filters"),
198198
new List<DirectiveNode>(),
199199
new List<InputValueDefinitionNode> {
200-
new InputValueDefinitionNode(null, new NameNode("isNull"), new StringValueNode("Not null test"), new BooleanType().ToTypeNode(), null, new List<DirectiveNode>())
200+
new InputValueDefinitionNode(null, new NameNode("isNull"), new StringValueNode("Is null test"), new BooleanType().ToTypeNode(), null, new List<DirectiveNode>())
201+
}
202+
);
203+
204+
public static InputObjectTypeDefinitionNode UuidInputType() =>
205+
new(
206+
location: null,
207+
new NameNode("UuidFilterInput"),
208+
new StringValueNode("Input type for adding Uuid filters"),
209+
new List<DirectiveNode>(),
210+
new List<InputValueDefinitionNode> {
211+
new InputValueDefinitionNode(null, new NameNode("eq"), new StringValueNode("Equals"), new UuidType().ToTypeNode(), null, new List<DirectiveNode>()),
212+
new InputValueDefinitionNode(null, new NameNode("contains"), new StringValueNode("Contains"), new UuidType().ToTypeNode(), null, new List<DirectiveNode>()),
213+
new InputValueDefinitionNode(null, new NameNode("notContains"), new StringValueNode("Not Contains"), new UuidType().ToTypeNode(), null, new List<DirectiveNode>()),
214+
new InputValueDefinitionNode(null, new NameNode("startsWith"), new StringValueNode("Starts With"), new UuidType().ToTypeNode(), null, new List<DirectiveNode>()),
215+
new InputValueDefinitionNode(null, new NameNode("endsWith"), new StringValueNode("Ends With"), new UuidType().ToTypeNode(), null, new List<DirectiveNode>()),
216+
new InputValueDefinitionNode(null, new NameNode("neq"), new StringValueNode("Not Equals"), new UuidType().ToTypeNode(), null, new List<DirectiveNode>()),
217+
new InputValueDefinitionNode(null, new NameNode("caseInsensitive"), new StringValueNode("Case Insensitive"), new BooleanType().ToTypeNode(), new BooleanValueNode(false), new List<DirectiveNode>()),
218+
new InputValueDefinitionNode(null, new NameNode("isNull"), new StringValueNode("Is null test"), new BooleanType().ToTypeNode(), null, new List<DirectiveNode>())
201219
}
202220
);
203221

204222
public static Dictionary<string, InputObjectTypeDefinitionNode> InputTypes = new()
205223
{
206224
{ "ID", IdInputType() },
225+
{ UUID_TYPE, UuidInputType() },
207226
{ BYTE_TYPE, ByteInputType() },
208227
{ SHORT_TYPE, ShortInputType() },
209228
{ INT_TYPE, IntInputType() },

src/Service.GraphQLBuilder/Sql/SchemaConverter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ public static string GetGraphQLTypeFromSystemType(Type type)
219219
return type.Name switch
220220
{
221221
"String" => STRING_TYPE,
222-
"Guid" => STRING_TYPE,
222+
"Guid" => UUID_TYPE,
223223
"Byte" => BYTE_TYPE,
224224
"Int16" => SHORT_TYPE,
225225
"Int32" => INT_TYPE,
@@ -255,7 +255,7 @@ public static IValueNode CreateValueNodeFromDbObjectMetadata(object metadataValu
255255
short value => new ObjectValueNode(new ObjectFieldNode(SHORT_TYPE, new IntValueNode(value))),
256256
int value => new ObjectValueNode(new ObjectFieldNode(INT_TYPE, value)),
257257
long value => new ObjectValueNode(new ObjectFieldNode(LONG_TYPE, new IntValueNode(value))),
258-
Guid value => new ObjectValueNode(new ObjectFieldNode(GUID_TYPE, value.ToString())),
258+
Guid value => new ObjectValueNode(new ObjectFieldNode(UUID_TYPE, new UuidType().ParseValue(value))),
259259
string value => new ObjectValueNode(new ObjectFieldNode(STRING_TYPE, value)),
260260
bool value => new ObjectValueNode(new ObjectFieldNode(BOOLEAN_TYPE, value)),
261261
float value => new ObjectValueNode(new ObjectFieldNode(SINGLE_TYPE, new SingleType().ParseValue(value))),

src/Service.Tests/DatabaseSchema-MsSql.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ CREATE TABLE type_table(
163163
datetimeoffset_types datetimeoffset,
164164
smalldatetime_types smalldatetime,
165165
bytearray_types varbinary(max),
166-
guid_types uniqueidentifier DEFAULT newid()
166+
uuid_types uniqueidentifier DEFAULT newid()
167167
);
168168

169169
CREATE TABLE trees (
@@ -414,6 +414,7 @@ VALUES
414414
'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',
415415
0xFFFFFFFF),
416416
(5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
417+
INSERT INTO type_table(id, uuid_types) values(10, 'D1D021A8-47B4-4AE4-B718-98E89C41A161');
417418
SET IDENTITY_INSERT type_table OFF
418419

419420
SET IDENTITY_INSERT sales ON

src/Service.Tests/DatabaseSchema-PostgreSql.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ CREATE TABLE type_table(
143143
boolean_types boolean,
144144
datetime_types timestamp,
145145
bytearray_types bytea,
146-
guid_types uuid DEFAULT gen_random_uuid ()
146+
uuid_types uuid DEFAULT gen_random_uuid ()
147147
);
148148

149149
CREATE TABLE trees (
@@ -328,6 +328,7 @@ INSERT INTO type_table(id, short_types, int_types, long_types, string_types, sin
328328
(3, -32768, -2147483648, -9223372036854775808, '', -3.4E38, -1.7E308, 2.929292E-19, true, '1753-01-01 00:00:00.000', '\x00000000'),
329329
(4, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9998-12-31 23:59:59.997', '\xFFFFFFFF'),
330330
(5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
331+
INSERT INTO type_table(id, uuid_types) values(10, 'D1D021A8-47B4-4AE4-B718-98E89C41A161');
331332
INSERT INTO trees("treeId", species, region, height) VALUES (1, 'Tsuga terophylla', 'Pacific Northwest', '30m'), (2, 'Pseudotsuga menziesii', 'Pacific Northwest', '40m');
332333
INSERT INTO fungi(speciesid, region) VALUES (1, 'northeast'), (2, 'southwest');
333334
INSERT INTO notebooks(id, noteBookName, color, ownerName) VALUES (1, 'Notebook1', 'red', 'Sean'), (2, 'Notebook2', 'green', 'Ani'), (3, 'Notebook3', 'blue', 'Jarupat'), (4, 'Notebook4', 'yellow', 'Aaron');

src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public void MultipleColumnsAllMapped()
229229
[DataRow(typeof(DateTime), DATETIME_TYPE)]
230230
[DataRow(typeof(DateTimeOffset), DATETIME_TYPE)]
231231
[DataRow(typeof(byte[]), BYTEARRAY_TYPE)]
232-
[DataRow(typeof(Guid), STRING_TYPE)]
232+
[DataRow(typeof(Guid), UUID_TYPE)]
233233
public void SystemTypeMapsToCorrectGraphQLType(Type systemType, string graphQLType)
234234
{
235235
SourceDefinition table = new();

src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/GraphQLSupportedTypesTestsBase.cs

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ public abstract class GraphQLSupportedTypesTestBase : SqlTestBase
6464
[DataRow(BYTEARRAY_TYPE, 2)]
6565
[DataRow(BYTEARRAY_TYPE, 3)]
6666
[DataRow(BYTEARRAY_TYPE, 4)]
67-
[DataRow(GUID_TYPE, 1)]
68-
[DataRow(GUID_TYPE, 2)]
69-
[DataRow(GUID_TYPE, 3)]
70-
[DataRow(GUID_TYPE, 4)]
67+
[DataRow(UUID_TYPE, 1)]
68+
[DataRow(UUID_TYPE, 2)]
69+
[DataRow(UUID_TYPE, 3)]
70+
[DataRow(UUID_TYPE, 4)]
7171
public async Task QueryTypeColumn(string type, int id)
7272
{
7373
if (!IsSupportedType(type))
@@ -134,6 +134,8 @@ public async Task QueryTypeColumn(string type, int id)
134134
[DataRow(DECIMAL_TYPE, "eq", "-9.292929", "-9.292929", "=")]
135135
[DataRow(BOOLEAN_TYPE, "neq", "\'false\'", "false", "!=")]
136136
[DataRow(BOOLEAN_TYPE, "eq", "\'false\'", "false", "=")]
137+
[DataRow(UUID_TYPE, "eq", "'D1D021A8-47B4-4AE4-B718-98E89C41A161'", "\"D1D021A8-47B4-4AE4-B718-98E89C41A161\"", "=")]
138+
[DataRow(UUID_TYPE, "neq", "'D1D021A8-47B4-4AE4-B718-98E89C41A161'", "\"D1D021A8-47B4-4AE4-B718-98E89C41A161\"", "!=")]
137139
public async Task QueryTypeColumnFilterAndOrderBy(string type, string filterOperator, string sqlValue, string gqlValue, string queryOperator)
138140
{
139141
if (!IsSupportedType(type))
@@ -340,8 +342,8 @@ public async Task InsertIntoTypeColumnWithArgument(string type, object value)
340342
[DataRow(BYTEARRAY_TYPE, "\"U3RyaW5neQ==\"")]
341343
[DataRow(BYTEARRAY_TYPE, "\"V2hhdGNodSBkb2luZyBkZWNvZGluZyBvdXIgdGVzdCBiYXNlNjQgc3RyaW5ncz8=\"")]
342344
[DataRow(BYTEARRAY_TYPE, "null")]
343-
[DataRow(GUID_TYPE, "\"3a1483a5-9ac2-4998-bcf3-78a28078c6ac\"")]
344-
[DataRow(GUID_TYPE, "null")]
345+
[DataRow(UUID_TYPE, "\"3a1483a5-9ac2-4998-bcf3-78a28078c6ac\"")]
346+
[DataRow(UUID_TYPE, "null")]
345347
public async Task UpdateTypeColumn(string type, string value)
346348
{
347349
if (!IsSupportedType(type))
@@ -382,8 +384,8 @@ public async Task UpdateTypeColumn(string type, string value)
382384
[DataRow(DATETIME_TYPE, "1999-01-08 10:23:54")]
383385
[DataRow(DATETIME_NONUTC_TYPE, "1999-01-08 10:23:54+8:00")]
384386
[DataRow(BYTEARRAY_TYPE, "V2hhdGNodSBkb2luZyBkZWNvZGluZyBvdXIgdGVzdCBiYXNlNjQgc3RyaW5ncz8=")]
385-
[DataRow(GUID_TYPE, "3a1483a5-9ac2-4998-bcf3-78a28078c6ac")]
386-
[DataRow(GUID_TYPE, null)]
387+
[DataRow(UUID_TYPE, "3a1483a5-9ac2-4998-bcf3-78a28078c6ac")]
388+
[DataRow(UUID_TYPE, null)]
387389
public async Task UpdateTypeColumnWithArgument(string type, object value)
388390
{
389391
if (!IsSupportedType(type))
@@ -400,7 +402,7 @@ public async Task UpdateTypeColumnWithArgument(string type, object value)
400402

401403
string field = $"{type.ToLowerInvariant()}_types";
402404
string graphQLQueryName = "updateSupportedType";
403-
string gqlQuery = "mutation($param: " + TypeNameToGraphQLType(type) + "){ updateSupportedType (typeid: 1, item: {" + field + ": $param }){ " + field + " } }";
405+
string gqlQuery = "mutation($param: " + type + "){ updateSupportedType (typeid: 1, item: {" + field + ": $param }){ " + field + " } }";
404406

405407
string dbQuery = MakeQueryOnTypeTable(new List<string> { field }, id: 1);
406408

@@ -428,12 +430,45 @@ private static void PerformTestEqualsForExtendedTypes(string type, string expect
428430
{
429431
CompareDateTimeResults(actual.ToString(), expected);
430432
}
433+
else if (type == UUID_TYPE)
434+
{
435+
CompareUuidResults(actual.ToString(), expected);
436+
}
431437
else
432438
{
433439
SqlTestHelper.PerformTestEqualJsonStrings(expected, actual.ToString());
434440
}
435441
}
436442

443+
private static void CompareUuidResults(string actual, string expected)
444+
{
445+
string fieldName = "uuid_types";
446+
447+
using JsonDocument actualJsonDoc = JsonDocument.Parse(actual);
448+
using JsonDocument expectedJsonDoc = JsonDocument.Parse(expected);
449+
450+
if (actualJsonDoc.RootElement.ValueKind is JsonValueKind.Array)
451+
{
452+
ValidateArrayResults(actualJsonDoc, expectedJsonDoc, fieldName);
453+
return;
454+
}
455+
456+
string actualUuidString = actualJsonDoc.RootElement.GetProperty(fieldName).ToString();
457+
string expectedUuidString = expectedJsonDoc.RootElement.GetProperty(fieldName).ToString();
458+
459+
// handles cases when one of the values is null
460+
if (string.IsNullOrEmpty(actualUuidString) || string.IsNullOrEmpty(expectedUuidString))
461+
{
462+
Assert.AreEqual(expectedUuidString, actualUuidString);
463+
}
464+
else
465+
{
466+
Guid actualGuidValue = Guid.Parse(actualUuidString);
467+
Guid expectedGuidValue = Guid.Parse(expectedUuidString);
468+
Assert.AreEqual(actualGuidValue, expectedGuidValue);
469+
}
470+
}
471+
437472
/// <summary>
438473
/// HotChocolate will parse large floats to exponential notation
439474
/// while the db will return the number fully printed out. Because
@@ -530,6 +565,12 @@ private static void ValidateArrayResults(JsonDocument actualJsonDoc, JsonDocumen
530565
DateTime expectedDateTime = DateTime.Parse(expectedValue.ToString(), CultureInfo.InvariantCulture, DateTimeStyles.None);
531566
Assert.AreEqual(expectedDateTime, actualDateTime);
532567
}
568+
else if (fieldName.StartsWith(UUID_TYPE.ToLower()))
569+
{
570+
Guid actualGuidValue = Guid.Parse(actualValue.ToString());
571+
Guid expectedGuidValue = Guid.Parse(expectedValue.ToString());
572+
Assert.AreEqual(expectedGuidValue, actualGuidValue);
573+
}
533574
else if (fieldName.StartsWith(SINGLE_TYPE.ToLower()))
534575
{
535576
Assert.AreEqual(expectedValue.GetSingle(), actualValue.GetSingle());
@@ -541,20 +582,6 @@ private static void ValidateArrayResults(JsonDocument actualJsonDoc, JsonDocumen
541582
}
542583
}
543584

544-
/// <summary>
545-
/// Needed to map the type name to a graphql type in argument tests
546-
/// where the argument type need to be specified.
547-
/// </summary>
548-
private static string TypeNameToGraphQLType(string typeName)
549-
{
550-
if (typeName is GUID_TYPE)
551-
{
552-
return STRING_TYPE;
553-
}
554-
555-
return typeName;
556-
}
557-
558585
protected abstract string MakeQueryOnTypeTable(
559586
List<string> queriedColumns,
560587
string filterValue = "1",

src/Service.Tests/SqlTests/GraphQLSupportedTypesTests/MySqlGQLSupportedTypesTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ protected override bool IsSupportedType(string type)
5656
{
5757
return type switch
5858
{
59-
GUID_TYPE => false,
59+
UUID_TYPE => false,
6060
_ => true
6161
};
6262
}

src/Service.Tests/SqlTests/RestApiTests/Insert/MsSqlInsertApiTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class MsSqlInsertApiTests : InsertApiTestBase
3232
"InsertOneInSupportedTypes",
3333
$"SELECT [id] as [typeid], [byte_types], [short_types], [int_types], [long_types],string_types, [single_types], [float_types], " +
3434
$"[decimal_types], [boolean_types], [date_types], [datetime_types], [datetime2_types], [datetimeoffset_types], [smalldatetime_types], " +
35-
$"[bytearray_types], LOWER([guid_types]) as [guid_types] FROM { _integrationTypeTable } " +
35+
$"[bytearray_types], LOWER([uuid_types]) as [uuid_types] FROM { _integrationTypeTable } " +
3636
$"WHERE [id] = { STARTING_ID_FOR_TEST_INSERTS } AND [bytearray_types] is NULL " +
3737
$"FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER"
3838
},

src/Service.Tests/SqlTests/RestApiTests/Insert/PostgreSqlInsertApiTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ SELECT to_jsonb(subq) AS data
3434
SELECT to_jsonb(subq) AS data
3535
FROM (
3636
SELECT id as typeid, short_types, int_types, long_types, string_types, single_types,
37-
float_types, decimal_types, boolean_types, datetime_types, bytearray_types, guid_types
37+
float_types, decimal_types, boolean_types, datetime_types, bytearray_types, uuid_types
3838
FROM " + _integrationTypeTable + @"
3939
WHERE id = " + STARTING_ID_FOR_TEST_INSERTS + @"
4040
) AS subq

0 commit comments

Comments
 (0)