-
-
Notifications
You must be signed in to change notification settings - Fork 916
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
Introduce optional IGraphTypeFactory #3913
Introduce optional IGraphTypeFactory #3913
Conversation
6ee7329
to
951b33a
Compare
My initial thought is that this is a breaking change, since non-generic graph types are not typically registered within DI. So any existing users that don't use the GraphQL builder methods would have a broken build. We could fix that by using Second, we have tests to ensure that graph types are only pulled from DI once when the schema is built. This allows use of Third, tests don't yet pass. However, it looks like the ApiTests need to run and a single test is failing due to the added registrations in I really don't think we should include the "case-insensitive" implementation. First, case-insensitivity is specifically against the GraphQL spec, and we should not be 'encouraging' such design. I'd rather include it as a sample in the Q&A. Further, the implementation here, although named "case-insensitive" really only allows for constant-case and upper-case. These are multiple ways of spelling, not a difference in case. So "JohnDoe" becomes either "JOHNDOE" or "JOHN_DOE". You can't use "johndoe" or "johnDoe" or "john_doe". I'd like input from other of the maintainers here. If there are other solutions to this issue, I'd like to discuss/review them as well. |
My mistake. I see you convert the input to uppercase. I'd suggest you just use a case-insensitive comparer in the dictionary constructors. |
src/GraphQL/Types/Scalars/Enumeration/CaseInsensitiveEnumValues.cs
Outdated
Show resolved
Hide resolved
src/GraphQL/Types/Scalars/Enumeration/CaseInsensitiveEnumValues.cs
Outdated
Show resolved
Hide resolved
src/GraphQL/Types/Scalars/Enumeration/CaseInsensitiveEnumValues.cs
Outdated
Show resolved
Hide resolved
src/GraphQL/Types/Scalars/Enumeration/CaseInsensitiveEnumValues.cs
Outdated
Show resolved
Hide resolved
src/GraphQL/Types/Scalars/Enumeration/CaseInsensitiveEnumValues.cs
Outdated
Show resolved
Hide resolved
@Shane32 I have removed the public |
Codecov ReportAttention:
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #3913 +/- ##
==========================================
- Coverage 84.22% 84.21% -0.01%
==========================================
Files 421 422 +1
Lines 19532 19542 +10
Branches 3047 3051 +4
==========================================
+ Hits 16451 16458 +7
Misses 2366 2366
- Partials 715 718 +3 ☔ View full report in Codecov by Sentry. |
I like this a lot better. The name But how about this for the interface: public interface IGraphTypeFactory
{
// add xml comments here stating that the supported types are ObjectGraphType, EnumerationGraphType, FieldType, etc
object CreateInstance(Type type);
}
public static GraphTypeFactoryExtensions
{
public static T CreateInstance<T>(this IGraphTypeFactory factory)
where T : class
=> (T)factory.CreateInstance(typeof(T));
} This design makes it so there is only one instance of |
Also with |
@Shane32 I like it better to have one Factory Service per GraphType. This way it is possible to customize only specific GraphType implementations. Otherwise I would need a single factory to support all GraphTypes. |
Well you can use inheritance: public MyFactory : DefaultGraphTypeFactory
{
public object CreateInstance(Type type)
{
if (type == typeof(EnumerationGraphType))
return new MyEnumGraphType();
return base.CreateInstance(type);
}
} although honestly this isn't much different: public MyFactory : IGraphTypeFactory
{
public object CreateInstance(Type type)
=> type == typeof(EnumerationGraphType) ? new MyEnumGraphType() : Activator.CreateInstance(type);
} |
Yes it is not impossible to find ways, but if possible I would like to avoid coupling between different Factory implementations. |
@gao-artur any comments here? |
Looks good 👌 |
@gao-artur any thoughts on |
In general, a single factory makes more sense for me, but I understand @PSanetra's logic. |
I just feel that this is not a good design pattern. Are there other examples of this design pattern in practice? As a single |
@Shane32 I think a good example of this pattern is the |
/// <summary> | ||
/// A generic factory to create instances of specific TGraphType implementations from parameterless constructors. | ||
/// </summary> | ||
public class GenericGraphTypeFactory<TGraphType> : IGraphTypeFactory<TGraphType> where TGraphType : IGraphType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, DefaultGraphTypeFactory
is a better name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. It also matches DefaultServiceProvider
and DefaultNameConverter
and stuff
I think I'll take @PSanetra's side. Although a generic factory interface is a less common approach than the generic method, it looks "cleaner". It also allows replacing the default behavior only for types you are interested in ( services.AddSingleton(typeof(IGraphTypeFactory<>), typeof(MyFactory<>))() public class MyFactory<TGraphType> : BaseFactory, IGraphTypeFactory<TGraphType>
where TGraphType : IGraphType
{
public TGraphType Create() => Create<TGraphType>();
}
public class BaseFactory
{
// Put here whatever logic you want to share
protected TGraphType Create<TGraphType>()
where TGraphType : IGraphType
=> Activator.CreateInstance<TGraphType>();
} |
Sounds good. I’ll review again tonight |
Let's make the changes @gao-artur suggested and then merge. |
d06122c
to
d858eeb
Compare
@gao-artur @Shane32 Alright I have applied the suggested changes and squashed the commits. |
…mentations in schema-first approach using dependency injection
d858eeb
to
d5b5471
Compare
@Shane32 @gao-artur Thank you for merging! Do you have an ETA when this change might be released? Is it possible to get a pre-release containing this change? |
When reasonable, I usually issue a release when asked; I can do it now. You can get prerelease versions from the GitHub Package Registry. Unfortunately it requires authentication so it's a bit of a pain to use. See https://github.com/graphql-dotnet/graphql-dotnet/pkgs/nuget/GraphQL . Version 7.6.2-preview-980 would be the latest 7.x version (newer than 7.7). |
This PR implements two features:
Fixes #3105