graphql-dotnet / graphql-dotnet

GraphQL for .NET

Home Page:https://graphql-dotnet.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Ensure input object fields default don't conflict with source members default

gao-artur opened this issue · comments

In the sample you provided, it would be more likely that the field would be required and have a default value of an empty list.

Then, to avoid confusion, we must have an analyzer to ensure "legal" defaults are applied on graph and source types. Please correct me if this table is wrong:

Graph type field Source type member default
Nullable without default Nothing or null
Nullable with default Nothing or same as on graph
Not nullable without default Nothing
Not nullable with default Nothing or same as on graph

If we create such an analyzer, then we can implement this note:

We could set ALL undefined properties to their default values, not just init-only ones, making reflection, source-generated and dynamically-compiled versions simpler.

Because there won't be runtime surprises for the developer.

Originally posted by @gao-artur in #3804 (comment)

A simpler alternative here might just be to have the analyzer:

  1. Locate graph input fields on CLR types, either by matching by name or lambda
  2. If they (a) exist in the constructor, or (b) are init-only or required and have a default value, display a warning that the value will be overwritten when etc etc
  3. If they are read-only (fields) or have no public setter (properties), and there is no corresponding value in the constructor, display an error that the value cannot be written to. (separate rule?)

But of course more analysis would not hurt either 😄

Keep in mind that this rule should apply to all properties of CLR types consumed by AutoRegisteringInputObjectGraphType<T> also. (It does not by default auto-generate graph fields for CLR fields.)

  1. If they are read-only (fields) or have no public setter (properties), and there is no corresponding value in the constructor, display an error that the value cannot be written to. (separate rule?)

Already exists: GQL007. Need to extend it to AutoRegisteringInputObjectGraphType.

FYI, I can only produce diagnostics on the graph fields but not the source type members because there is no guarantee that the source type's source code is available or located in the project where the analyzer is referenced. In the AutoRegisteringInputObjectGraphType<T> case, all the warnings will be reported on the <T>.

TODO for me: fix the it's doesn't message as part of this story.

warning GQL007: The field 'FirstName' can't be mapped to the property 'Name' of the type 'MySourceType' because it's doesn't have a public setter. This field will be ignored during the input deserialization.

@Shane32 I'm extending InputGraphTypeAnalyzer to support AutoRegisteringInputObjectGraphType<T>. What attributes should I consider except NameAttribute and IgnoreAttribute?

Well, it shouldn't need to consider any auto-generated properties for 'CanNotMatchInputFieldToTheSourceField' or 'CanNotSetSourceField' diagnostics because the auto-registering type will not add any properties that do not match the requirements. For example, it's going to skip private properties because they can't be set.

Any fields manually added in the constructor of a derived class could be checked with the same code as InputObjectGraphType<T>.

The 'CanNotResolveInputSourceTypeConstructor' error, which I assume considers the selected constructor and ensures that properties are mapped for it, it will need to scan TSourceType for properties which don't have [Ignore] and match the other criteria (public settable property) and include the names of those properties as potential constructor candidates. The [Name] attribute should not be considered, as ToObject will use the name of the property and not the [Name] to match onto the constructor argument.

Any fields manually added in the constructor of a derived class could be checked with the same code as InputObjectGraphType

What may be the reason for defining additional fields in the constructor? All the legal properties and fields on the source type will be added automatically. So, how will the added fields be mapped to the source type?

The 'CanNotResolveInputSourceTypeConstructor' error, which I assume considers the selected constructor and ensures that properties are mapped for it

This diagnostic verifies the source type has an available constructor, and there is no ambiguity about what constructor to use during the parsing.

it will need to scan TSourceType for properties which don't have

This will need a new rule.

What may be the reason for defining additional fields in the constructor? All the legal properties and fields on the source type will be added automatically. So, how will the added fields be mapped to the source type?

Good point

Ok so then is there anything for the analyzer to do at this time?

The #3865 extends the GQL010 to handle the AutoRegisteringInputObjectGraphType.
If I'm not mistaken, the auto registration will add whatever is "settable". So if we have a contractor parameter called email and a public get-only property UserName, it will add a field called email and ignore the UserName. So, no need to add another rule to match constructor parameters and properties, right?

It doesn’t automatically add properties for constructor parameters unless there is a corresponding readonly property - see #3782 . Adding support for ctor parameters without a matching property would change a whole bunch of code.

I think you mean this note

Any attributes such as [Id] must be applied to the property, not the constructor parameter.

Ok, I'll add a rule for that.