Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b802963

Browse filesBrowse files
Bug: Records as OBJECT types, [GraphType] on structs (#137)
* Fixed an issue where records could not be used as objects in some cases
1 parent 90cca98 commit b802963
Copy full SHA for b802963

File tree

Expand file treeCollapse file tree

19 files changed

+236
-9
lines changed
Filter options
Expand file treeCollapse file tree

19 files changed

+236
-9
lines changed

‎src/graphql-aspnet/Attributes/GraphTypeAttribute.cs

Copy file name to clipboardExpand all lines: src/graphql-aspnet/Attributes/GraphTypeAttribute.cs
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace GraphQL.AspNet.Attributes
1919
/// item should be treated as a graph type and included in a schema. This attribute is
2020
/// optional depending on your schema configuration and naming preferences.
2121
/// </summary>
22-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum)]
22+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct)]
2323
public class GraphTypeAttribute : GraphAttributeBase
2424
{
2525
private TemplateDeclarationRequirements _templateDeclarationRequirements = TemplateDeclarationRequirements.None;

‎src/graphql-aspnet/Common/Extensions/TypeExtensions.cs

Copy file name to clipboardExpand all lines: src/graphql-aspnet/Common/Extensions/TypeExtensions.cs
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace GraphQL.AspNet.Common.Extensions
1515
using System.ComponentModel.DataAnnotations;
1616
using System.Linq;
1717
using System.Reflection;
18+
using GraphQL.AspNet.Schemas.TypeSystem.Introspection;
1819

1920
/// <summary>
2021
/// Extension methods for working with .NET <see cref="Type"/>
@@ -506,5 +507,19 @@ public static bool IsStruct(this Type type)
506507
return type.IsValueType && !type.IsPrimitive && !type.IsEnum && !type.IsArray && !type.IsInterface
507508
&& !type.IsAbstract;
508509
}
510+
511+
/// <summary>
512+
/// Determines whether the specified type represents a record declared in
513+
/// source code.
514+
/// </summary>
515+
/// <param name="type">The type to inspect.</param>
516+
/// <returns><c>true</c> if the specified type is record; otherwise, <c>false</c>.</returns>
517+
public static bool IsRecord(this Type type)
518+
{
519+
if (type == null)
520+
return false;
521+
522+
return type.GetMethods().Any(m => m.Name == "<Clone>$");
523+
}
509524
}
510525
}

‎src/graphql-aspnet/Constants.cs

Copy file name to clipboardExpand all lines: src/graphql-aspnet/Constants.cs
+13-2Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,25 @@ public static class Messaging
108108
/// <value>The known ignored field names.</value>
109109
public static ISet<string> IgnoredFieldNames { get; } = new HashSet<string>()
110110
{
111-
// object declared methods that might be exposed
112-
// also methods internally declared by structs that might be exposed
111+
// object methods that might be exposed
112+
// also methods internally declared by structs or records that might be exposed
113113
"Deconstruct",
114114
nameof(object.ToString),
115115
nameof(object.GetHashCode),
116116
nameof(object.GetType),
117117
};
118118

119+
/// <summary>
120+
/// Gets a set of field names (property or method) that are never parsed by the templating engine
121+
/// for any reason when parsing a record.
122+
/// </summary>
123+
/// <value>The known ignored field names.</value>
124+
public static ISet<string> IgnoredRecordFieldNames { get; } = new HashSet<string>()
125+
{
126+
"Equals",
127+
"<Clone>$",
128+
};
129+
119130
/// <summary>
120131
/// A collection of common suffixes that are semantically handled or removed from naming.
121132
/// </summary>

‎src/graphql-aspnet/Internal/TypeTemplates/NonLeafGraphTypeTemplateBase.cs

Copy file name to clipboardExpand all lines: src/graphql-aspnet/Internal/TypeTemplates/NonLeafGraphTypeTemplateBase.cs
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ protected virtual bool CouldBeGraphField(MemberInfo memberInfo)
188188
if (Constants.IgnoredFieldNames.Contains(memberInfo.Name))
189189
return false;
190190

191+
if (memberInfo.DeclaringType?.IsRecord() ?? false)
192+
{
193+
if (Constants.IgnoredRecordFieldNames.Contains(memberInfo.Name))
194+
return false;
195+
}
196+
191197
// when the member declares any known attribute in the library include it
192198
// and allow it to generate validation failures if its not properly constructed
193199
if (memberInfo.SingleAttributeOfTypeOrDefault<GraphFieldAttribute>() != null)

‎src/unit-tests/graphql-aspnet-tests/Common/GraphIdTests.cs

Copy file name to clipboardExpand all lines: src/unit-tests/graphql-aspnet-tests/Common/GraphIdTests.cs
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public void GeneralPropertyCheck()
3131
[Test]
3232
public void EmptyGraphIdCtor_IsEmptyString()
3333
{
34-
GraphId id = new ();
34+
GraphId id = default;
3535
Assert.IsNull(id.Value);
3636
}
3737

+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// *************************************************************
2+
// project: graphql-aspnet
3+
// --
4+
// repo: https://github.com/graphql-aspnet
5+
// docs: https://graphql-aspnet.github.io
6+
// --
7+
// License: MIT
8+
// *************************************************************
9+
10+
namespace GraphQL.AspNet.Tests.Execution
11+
{
12+
using System.Threading.Tasks;
13+
using GraphQL.AspNet.Tests.Execution.TestData.ExecutionPlanTestData;
14+
using GraphQL.AspNet.Tests.Framework;
15+
using GraphQL.AspNet.Tests.Framework.CommonHelpers;
16+
using NUnit.Framework;
17+
18+
[TestFixture]
19+
public class GeneralQueryExecutionTests3
20+
{
21+
[Test]
22+
public async Task Record_asInputObject_RendersObjectCorrectly()
23+
{
24+
var server = new TestServerBuilder()
25+
.AddGraphQL(o =>
26+
{
27+
o.AddType<RecordAsInputObjectController>();
28+
})
29+
.Build();
30+
31+
// totalPeople exists on base controller
32+
// totalEmployees exists on the added EmployeeController
33+
var builder = server.CreateQueryContextBuilder()
34+
.AddQueryText(@"query {
35+
retrieveValue(record: {property1: 23})
36+
}");
37+
38+
var expectedOutput =
39+
@"{
40+
""data"": {
41+
""retrieveValue"" : 23
42+
}
43+
}";
44+
45+
var result = await server.RenderResult(builder);
46+
CommonAssertions.AreEqualJsonStrings(expectedOutput, result);
47+
}
48+
}
49+
}
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// *************************************************************
2+
// project: graphql-aspnet
3+
// --
4+
// repo: https://github.com/graphql-aspnet
5+
// docs: https://graphql-aspnet.github.io
6+
// --
7+
// License: MIT
8+
// *************************************************************
9+
10+
namespace GraphQL.AspNet.Tests.Execution.TestData.ExecutionPlanTestData
11+
{
12+
public record MyRecord
13+
{
14+
public int Property1 { get; set; }
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// *************************************************************
2+
// project: graphql-aspnet
3+
// --
4+
// repo: https://github.com/graphql-aspnet
5+
// docs: https://graphql-aspnet.github.io
6+
// --
7+
// License: MIT
8+
// *************************************************************
9+
10+
namespace GraphQL.AspNet.Tests.Execution.TestData.ExecutionPlanTestData
11+
{
12+
using GraphQL.AspNet.Attributes;
13+
using GraphQL.AspNet.Controllers;
14+
15+
public class RecordAsInputObjectController : GraphController
16+
{
17+
[QueryRoot]
18+
public int RetrieveValue(MyRecord record)
19+
{
20+
return record.Property1;
21+
}
22+
}
23+
}

‎src/unit-tests/graphql-aspnet-tests/Internal/Templating/InputObjectTemplateTests.cs

Copy file name to clipboardExpand all lines: src/unit-tests/graphql-aspnet-tests/Internal/Templating/InputObjectTemplateTests.cs
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,5 +374,23 @@ public void Parse_DuplicatePropertyPaths_ThrowsException()
374374
template.ValidateOrThrow();
375375
});
376376
}
377+
378+
[Test]
379+
public void Parse_OnRecord_YieldsTemplate()
380+
{
381+
var template = new InputObjectGraphTypeTemplate(typeof(InputRecord));
382+
template.Parse();
383+
template.ValidateOrThrow();
384+
385+
Assert.AreEqual(2, template.FieldTemplates.Count);
386+
var field1 = template.FieldTemplates.SingleOrDefault(x => x.Value.Name == "Property1").Value;
387+
var field2 = template.FieldTemplates.SingleOrDefault(x => x.Value.Name == "Property2").Value;
388+
389+
Assert.IsNotNull(field1);
390+
Assert.IsNotNull(field2);
391+
392+
Assert.AreEqual(typeof(int), field1.ObjectType);
393+
Assert.AreEqual(typeof(string), field2.ObjectType);
394+
}
377395
}
378396
}

‎src/unit-tests/graphql-aspnet-tests/Internal/Templating/ObjectGraphTypeTemplateTests.cs

Copy file name to clipboardExpand all lines: src/unit-tests/graphql-aspnet-tests/Internal/Templating/ObjectGraphTypeTemplateTests.cs
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,5 +431,34 @@ public void Parse_InternalInheritedMembers_AreNotTemplated()
431431
Assert.AreEqual("Method3", fieldTemplate0.Name);
432432
Assert.AreEqual("Field1", fieldTemplate1.Name);
433433
}
434+
435+
[Test]
436+
public void Parse_Struct_WithGraphTypeNameOverride_ParsesCorrectly()
437+
{
438+
var template = new ObjectGraphTypeTemplate(typeof(SimpleScalarStructWithTypeOverride));
439+
template.Parse();
440+
template.ValidateOrThrow();
441+
442+
Assert.IsNotNull(template);
443+
Assert.AreEqual("SomeTypeName", template.Name);
444+
}
445+
446+
[Test]
447+
public void Parse_Record_ParsesCorrectly()
448+
{
449+
var template = new ObjectGraphTypeTemplate(typeof(ObjectRecord));
450+
template.Parse();
451+
template.ValidateOrThrow();
452+
453+
Assert.AreEqual(2, template.FieldTemplates.Count);
454+
var field1 = template.FieldTemplates.SingleOrDefault(x => x.Name == "Property1");
455+
var field2 = template.FieldTemplates.SingleOrDefault(x => x.Name == "Property2");
456+
457+
Assert.IsNotNull(field1);
458+
Assert.IsNotNull(field2);
459+
460+
Assert.AreEqual(typeof(int), field1.ObjectType);
461+
Assert.AreEqual(typeof(string), field2.ObjectType);
462+
}
434463
}
435464
}
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// *************************************************************
2+
// project: graphql-aspnet
3+
// --
4+
// repo: https://github.com/graphql-aspnet
5+
// docs: https://graphql-aspnet.github.io
6+
// --
7+
// License: MIT
8+
// *************************************************************
9+
10+
namespace GraphQL.AspNet.Tests.Internal.Templating.ObjectTypeTests
11+
{
12+
using GraphQL.AspNet.Attributes;
13+
14+
[GraphType]
15+
public record InputRecord
16+
{
17+
public int Property1 { get; set; }
18+
19+
public string Property2 { get; set; }
20+
}
21+
}
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// *************************************************************
2+
// project: graphql-aspnet
3+
// --
4+
// repo: https://github.com/graphql-aspnet
5+
// docs: https://graphql-aspnet.github.io
6+
// --
7+
// License: MIT
8+
// *************************************************************
9+
10+
namespace GraphQL.AspNet.Tests.Internal.Templating.ObjectTypeTests
11+
{
12+
using GraphQL.AspNet.Attributes;
13+
14+
[GraphType]
15+
public record ObjectRecord
16+
{
17+
public int Property1 { get; set; }
18+
19+
public string Property2 { get; set; }
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// *************************************************************
2+
// project: graphql-aspnet
3+
// --
4+
// repo: https://github.com/graphql-aspnet
5+
// docs: https://graphql-aspnet.github.io
6+
// --
7+
// License: MIT
8+
// *************************************************************
9+
10+
namespace GraphQL.AspNet.Tests.Internal.Templating.ObjectTypeTests
11+
{
12+
using GraphQL.AspNet.Attributes;
13+
14+
[GraphType("SomeTypeName")]
15+
public struct SimpleScalarStructWithTypeOverride
16+
{
17+
public int Prop1 { get; set; }
18+
}
19+
}

‎src/unit-tests/graphql-aspnet-tests/ServerExtensions/MutlipartRequests/ConfigTests.cs

Copy file name to clipboardExpand all lines: src/unit-tests/graphql-aspnet-tests/ServerExtensions/MutlipartRequests/ConfigTests.cs
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace GraphQL.AspNet.Tests.ServerExtensions.MutlipartRequests
3030
[TestFixture]
3131
public class ConfigTests
3232
{
33-
private (MultiPartHttpFormPayloadParser<GraphSchema>, HttpContext) CreateTestObject(
33+
private (MultiPartHttpFormPayloadParser<GraphSchema> Parser, HttpContext Context) CreateTestObject(
3434
string operationsField,
3535
string mapField,
3636
IMultipartRequestConfiguration<GraphSchema> config = null,

‎src/unit-tests/graphql-aspnet-tests/ServerExtensions/MutlipartRequests/MultipartRequestGraphQLHttpProcessorTests.cs

Copy file name to clipboardExpand all lines: src/unit-tests/graphql-aspnet-tests/ServerExtensions/MutlipartRequests/MultipartRequestGraphQLHttpProcessorTests.cs
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ namespace GraphQL.AspNet.Tests.ServerExtensions.MutlipartRequests
2222
using GraphQL.AspNet.Interfaces.Logging;
2323
using GraphQL.AspNet.Interfaces.Security;
2424
using GraphQL.AspNet.Schemas;
25-
using GraphQL.AspNet.ServerExtensions.MultipartRequests;
2625
using GraphQL.AspNet.ServerExtensions.MultipartRequests.Configuration;
2726
using GraphQL.AspNet.ServerExtensions.MultipartRequests.Engine;
2827
using GraphQL.AspNet.ServerExtensions.MultipartRequests.Engine.TypeMakers;
@@ -44,7 +43,7 @@ public class MultipartRequestGraphQLHttpProcessorTests
4443
{
4544
private DateTime _staticFailDate = new DateTime(202, 3, 4, 13, 14, 15, DateTimeKind.Utc);
4645

47-
private (HttpContext, MultipartRequestGraphQLHttpProcessor<GraphSchema>) CreateTestObjects(
46+
private (HttpContext Context, MultipartRequestGraphQLHttpProcessor<GraphSchema> Processor) CreateTestObjects(
4847
(string FieldName, string FieldValue)[] fields = null,
4948
(string FieldName, string FileName, string ContentType, string FileContents)[] files = null,
5049
string httpMethod = "POST",

‎src/unit-tests/graphql-aspnet-tests/ServerExtensions/MutlipartRequests/MultipartRequestPayloadAssemblerTests.cs

Copy file name to clipboardExpand all lines: src/unit-tests/graphql-aspnet-tests/ServerExtensions/MutlipartRequests/MultipartRequestPayloadAssemblerTests.cs
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace GraphQL.AspNet.Tests.ServerExtensions.MutlipartRequests
3232
[TestFixture]
3333
public class MultipartRequestPayloadAssemblerTests
3434
{
35-
private (MultiPartHttpFormPayloadParser<GraphSchema>, HttpContext) CreateTestObject(
35+
private (MultiPartHttpFormPayloadParser<GraphSchema> Parser, HttpContext Context) CreateTestObject(
3636
string operationsField,
3737
string mapField,
3838
IMultipartRequestConfiguration<GraphSchema> config = null,

‎src/unit-tests/graphql-aspnet-tests/graphql-aspnet-tests.csproj

Copy file name to clipboardExpand all lines: src/unit-tests/graphql-aspnet-tests/graphql-aspnet-tests.csproj
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
</ItemGroup>
2121

2222
<ItemGroup>
23-
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
23+
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.507" PrivateAssets="All" />
2424
<PackageReference Include="nunit" Version="3.13.3" />
2525
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
2626
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.