Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict list types in GetGraphTypeFromType #3099

Merged
merged 12 commits into from
Apr 25, 2022
Merged

Conversation

Shane32
Copy link
Member

@Shane32 Shane32 commented Apr 24, 2022

I keep running into this problem in my code: GetGraphTypeFromType takes classes that inherit or implement a list or dictionary type and assign it a graph type mapping of the KeyValuePair rather than the object as a whole.

For example:

private MyInfoClass : Dictionary<string, object>
{
    public string Name => this["Name"];
}

var type = GetGraphTypeFromType(typeof(MyInfoClass), true, TypeMappingMode.OutputType);
//expected:
type == typeof(GraphQLClrOutputGraphType<MyInfoClass>)
//actual:
type == typeof(ListGraphType<GraphQLClrOutputGraphType<KeyValuePair<string, object>>>);

My workaround is currently as follows:

  1. Apply the patch in this PR to a custom version of the GetGraphTypeFromType method
  2. Create a class derived from TypeInformation and override ConstructGraphType to use the new method
  3. Create a class dervied from AutoRegisteringObjectGraphType and override GetTypeInformation to use the new class
  4. Register the new class within DI to be used when AutoRegisteringObjectGraphType is requested.

My suggested fix is to only detect explicit enumerable types that we have already predefined in the TypeInformation class:

  • IEnumerable
  • IEnumerable<>
  • IList<>
  • List<>
  • ICollection<>
  • IReadOnlyCollection<>
  • IReadOnlyList<>
  • HashSet<>
  • ISet<>

Any derived types from those types will not be detected as a list. This is a breaking change, and if someone is relying on the prior behavior, they will need to cast their custom return type to a detected list type. For example:

public class People : List<Person>
{
}

var type = GetGraphTypeFromType(typeof(People), true, TypeMappingMode.OutputType);
//previously:
type == typeof(ListGraphType<GraphQLClrOutputGraphType<Person>>)
//now:
type == typeof(GraphQLClrOutputGraphType<People>)

//breaking change affects uses like this:
Field(x => x.People); //where People is of type People not of type List<Person>

My workaround (described above) contains almost 200 lines of code to fix this problem (mostly copied from the main library). I suggest we fix it in the main library. However, it is a breaking change and there may be existing code that relies on the current behavior. As much as I would like to see it in 5.1 for my own needs, I suggest this be a change for 6.0. I can live with my existing workaround.

An alternative option would be to make this a global option. Even though I generally discourage global options, this really seems like a pain point (for me) that we can get rid of rather easily.

@Shane32 Shane32 added the BREAKING Breaking changes in either public API or runtime behavior label Apr 24, 2022
@Shane32 Shane32 requested a review from sungam3r April 24, 2022 21:29
@Shane32 Shane32 self-assigned this Apr 24, 2022
@Shane32
Copy link
Member Author

Shane32 commented Apr 24, 2022

Unfortunately my patch is required in multiple private libraries - ugh!

@sungam3r
Copy link
Member

As much as I would like to see it in 5.1 for my own needs, I suggest this be a change for 6.0.

Let's keep it in 5.x.x timeline but with new global option that by default preserves old behavior. This option may be deprecated in v6.

@codecov-commenter
Copy link

Codecov Report

Merging #3099 (8f19a5c) into master (23361a7) will decrease coverage by 0.09%.
The diff coverage is 14.28%.

@@            Coverage Diff             @@
##           master    #3099      +/-   ##
==========================================
- Coverage   84.40%   84.30%   -0.10%     
==========================================
  Files         361      362       +1     
  Lines       15853    15884      +31     
  Branches     2578     2580       +2     
==========================================
+ Hits        13380    13391      +11     
- Misses       1859     1876      +17     
- Partials      614      617       +3     
Impacted Files Coverage Δ
src/GraphQL/TypeExtensions.cs 79.56% <0.00%> (-6.82%) ⬇️
src/GraphQL/GlobalSwitches.cs 100.00% <100.00%> (ø)
src/GraphQL/Types/TypeInformation.cs 95.65% <100.00%> (ø)
src/GraphQL/Types/Schema.cs 78.99% <0.00%> (-0.92%) ⬇️
src/GraphQL/IConfigureAutoSchema.cs 100.00% <0.00%> (ø)
src/GraphQL/Types/AutoSchema.cs 100.00% <0.00%> (ø)
src/GraphQL/GraphQLBuilderExtensions.cs 96.00% <0.00%> (+0.06%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1ccf984...8f19a5c. Read the comment docs.

@Shane32
Copy link
Member Author

Shane32 commented Apr 25, 2022

@sungam3r I added more details to the xml comment for the global switch if you want to review it.

@Shane32 Shane32 merged commit 01bf0ac into master Apr 25, 2022
@Shane32 Shane32 deleted the restrict_list_types branch April 25, 2022 15:08
@Shane32 Shane32 added this to the 5.1 milestone Apr 25, 2022
@Shane32 Shane32 added enhancement New feature or request and removed BREAKING Breaking changes in either public API or runtime behavior labels Apr 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants