From 1d4c524a4eefa7e113868677d7b0eec817019cb2 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 16 Sep 2024 16:56:40 -0700 Subject: [PATCH 01/22] Upgrade GraphQL to 8.0.2 --- Directory.Packages.props | 26 +++++-------------- .../GraphQLMiddleware.cs | 18 ++++++++----- .../MaxNumberOfResultsValidationRule.cs | 8 +++++- .../RequiresPermissionValidationRule.cs | 8 +++++- .../ContentPickerFieldQueryObjectType.cs | 4 +-- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 4d01810be52..81444d17547 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,15 +1,12 @@ - true true - 2.3.0 - @@ -25,10 +22,10 @@ - - - - + + + + @@ -45,7 +42,6 @@ - - @@ -91,12 +86,10 @@ - - + - @@ -110,7 +103,6 @@ └─ System.Text.RegularExpressions (v4.3.0) --> - - - 8.0.8 8.0.8 - - @@ -157,11 +145,9 @@ - - - + \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs index 60bdace4489..fdd3ff1e67c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs @@ -151,13 +151,19 @@ private async Task ExecuteAsync(HttpContext context) options.Variables = request.Variables; options.UserContext = _settings.BuildUserContext?.Invoke(context); options.ValidationRules = DocumentValidator.CoreRules - .Concat(context.RequestServices.GetServices()) - .Append(new ComplexityValidationRule(new ComplexityConfiguration + .Concat(context.RequestServices.GetServices()) + .Append(new ComplexityValidationRule(new ComplexityOptions + { + MaxDepth = _settings.MaxDepth, + MaxComplexity = _settings.MaxComplexity, + DefaultComplexityImpactDelegate = (ctx) => { - MaxDepth = _settings.MaxDepth, - MaxComplexity = _settings.MaxComplexity, - FieldImpact = _settings.FieldImpact - })); + return new FieldComplexityResult() + { + FieldImpact = _settings.FieldImpact ?? 0, + }; + } + })); options.Listeners.Add(dataLoaderDocumentListener); options.RequestServices = context.RequestServices; }); diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs index a429869af6f..af4d3baaedf 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs @@ -25,7 +25,7 @@ public MaxNumberOfResultsValidationRule( _logger = logger; } - public ValueTask ValidateAsync(ValidationContext validationContext) + public ValueTask GetPreNodeVisitorAsync(ValidationContext validationContext) { return ValueTask.FromResult((INodeVisitor)new NodeVisitors( new MatchingNodeVisitor((arg, visitorContext) => @@ -68,4 +68,10 @@ public ValueTask ValidateAsync(ValidationContext validationContext } }))); } + + public ValueTask GetVariableVisitorAsync(ValidationContext context) + => ValueTask.FromResult(null); + + public ValueTask GetPostNodeVisitorAsync(ValidationContext context) + => ValueTask.FromResult(null); } diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs index ba3183d2447..d1c061f9e70 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs @@ -23,7 +23,7 @@ public RequiresPermissionValidationRule( S = localizer; } - public async ValueTask ValidateAsync(ValidationContext validationContext) + public async ValueTask GetPreNodeVisitorAsync(ValidationContext validationContext) { // shouldn't we access UserContext from validation-context inside MatchingNodeVisitor actions? var userContext = (GraphQLUserContext)validationContext.UserContext; @@ -121,4 +121,10 @@ private void AddPermissionValidationError(ValidationContext validationContext, A S["Authorization is required to access the node. {0}", nodeName], node)); } + + public ValueTask GetVariableVisitorAsync(ValidationContext context) + => ValueTask.FromResult(null); + + public ValueTask GetPostNodeVisitorAsync(ValidationContext context) + => ValueTask.FromResult(null); } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/ContentPickerFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/ContentPickerFieldQueryObjectType.cs index af2371a288a..df80bd7e94f 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/ContentPickerFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/ContentPickerFieldQueryObjectType.cs @@ -1,4 +1,4 @@ -using GraphQL.DataLoader; +using GraphQL; using GraphQL.Types; using OrchardCore.Apis.GraphQL; using OrchardCore.ContentFields.Fields; @@ -29,7 +29,7 @@ public ContentPickerFieldQueryObjectType() { var contentItemLoader = x.GetOrAddPublishedContentItemByIdDataLoader(); - return (contentItemLoader.LoadAsync(x.Page(x.Source.ContentItemIds))).Then(itemResultSet => + return contentItemLoader.LoadAsync(x.Page(x.Source.ContentItemIds)).Then(itemResultSet => { return itemResultSet.SelectMany(x => x); }); From 2b428fe98bcb226cc6c566bb3c8839d85667a50a Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Mon, 16 Sep 2024 17:02:46 -0700 Subject: [PATCH 02/22] spaces --- Directory.Packages.props | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 81444d17547..56d9abc24d7 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,12 +1,15 @@ + true true + 2.3.0 + @@ -86,10 +89,12 @@ + + @@ -121,12 +126,14 @@ --> + 8.0.8 8.0.8 + + - \ No newline at end of file + + From 2258a8650dfe34094b2d91b465e780cbfc1a75be Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 18 Sep 2024 11:48:26 -0700 Subject: [PATCH 03/22] use DefaultObjectImpact --- .../OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs index fdd3ff1e67c..3f4ab760043 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs @@ -156,13 +156,7 @@ private async Task ExecuteAsync(HttpContext context) { MaxDepth = _settings.MaxDepth, MaxComplexity = _settings.MaxComplexity, - DefaultComplexityImpactDelegate = (ctx) => - { - return new FieldComplexityResult() - { - FieldImpact = _settings.FieldImpact ?? 0, - }; - } + DefaultObjectImpact = _settings.FieldImpact ?? 0, })); options.Listeners.Add(dataLoaderDocumentListener); options.RequestServices = context.RequestServices; From 1a3f3d66922d307f2bc9057164c11a4bc0994f3c Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 18 Sep 2024 14:16:33 -0700 Subject: [PATCH 04/22] don't resolve services from ISchema --- .../GraphQL/Fields/ContentFieldsProvider.cs | 7 +++--- .../Types/DynamicContentTypeBuilder.cs | 5 +++- .../Types/DynamicContentTypeQueryBuilder.cs | 3 ++- .../DynamicContentTypeWhereInputBuilder.cs | 3 ++- .../Queries/Types/DynamicPartGraphType.cs | 24 +++++++++---------- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index 57da8bc0e8b..6522a92afb6 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -127,7 +127,8 @@ public FieldType GetField(ISchema schema, ContentPartFieldDefinition field, stri }; } - public bool HasField(ISchema schema, ContentPartFieldDefinition field) => _contentFieldTypeMappings.ContainsKey(field.FieldDefinition.Name); + public bool HasField(ISchema schema, ContentPartFieldDefinition field) + => _contentFieldTypeMappings.ContainsKey(field.FieldDefinition.Name); public FieldTypeIndexDescriptor GetFieldIndex(ContentPartFieldDefinition field) { @@ -145,8 +146,8 @@ public FieldTypeIndexDescriptor GetFieldIndex(ContentPartFieldDefinition field) }; } - public bool HasFieldIndex(ContentPartFieldDefinition field) => - _contentFieldTypeMappings.TryGetValue(field.FieldDefinition.Name, out var fieldTypeDescriptor) && + public bool HasFieldIndex(ContentPartFieldDefinition field) + => _contentFieldTypeMappings.TryGetValue(field.FieldDefinition.Name, out var fieldTypeDescriptor) && fieldTypeDescriptor.IndexType != null && !string.IsNullOrWhiteSpace(fieldTypeDescriptor.Index); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index 53ba0a1476a..3c2dede23e3 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -13,15 +13,18 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public abstract class DynamicContentTypeBuilder : IContentTypeBuilder { protected readonly IHttpContextAccessor _httpContextAccessor; + private readonly IEnumerable _contentFieldProviders; protected readonly GraphQLContentOptions _contentOptions; protected readonly IStringLocalizer S; private readonly Dictionary _dynamicPartFields; protected DynamicContentTypeBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, + IEnumerable contentFieldProviders, IStringLocalizer localizer) { _httpContextAccessor = httpContextAccessor; + _contentFieldProviders = contentFieldProviders; _contentOptions = contentOptionsAccessor.Value; _dynamicPartFields = []; @@ -184,7 +187,7 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe Name = partFieldName, Description = S["Represents a {0}.", part.PartDefinition.Name], Type = typeof(DynamicPartGraphType), - ResolvedType = new DynamicPartGraphType(part), + ResolvedType = new DynamicPartGraphType(part, _contentFieldProviders), Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs index 6a74496498b..9d6b62ed982 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs @@ -11,8 +11,9 @@ public class DynamicContentTypeQueryBuilder : DynamicContentTypeBuilder { public DynamicContentTypeQueryBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, + IEnumerable contentFieldProviders, IStringLocalizer localizer) - : base(httpContextAccessor, contentOptionsAccessor, localizer) { } + : base(httpContextAccessor, contentOptionsAccessor, contentFieldProviders, localizer) { } public override void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs index ff1836b04ce..e256d29a5bb 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs @@ -11,8 +11,9 @@ public class DynamicContentTypeWhereInputBuilder : DynamicContentTypeBuilder { public DynamicContentTypeWhereInputBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, + IEnumerable contentFieldProviders, IStringLocalizer localizer) - : base(httpContextAccessor, contentOptionsAccessor, localizer) { } + : base(httpContextAccessor, contentOptionsAccessor, contentFieldProviders, localizer) { } public override void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index 123c5b861f2..1740c9d49f6 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -1,5 +1,4 @@ using GraphQL.Types; -using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement.Metadata.Models; namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; @@ -7,29 +6,28 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public sealed class DynamicPartGraphType : ObjectGraphType { private ContentTypePartDefinition _part; + private readonly IEnumerable _contentFieldProviders; - public DynamicPartGraphType(ContentTypePartDefinition part) + public DynamicPartGraphType( + ContentTypePartDefinition part, + IEnumerable contentFieldProviders) { Name = part.Name; _part = part; + _contentFieldProviders = contentFieldProviders; } public override void Initialize(ISchema schema) { - if (schema is IServiceProvider serviceProvider) + foreach (var field in _part.PartDefinition.Fields) { - var contentFieldProviders = serviceProvider.GetServices().ToList(); - - foreach (var field in _part.PartDefinition.Fields) + foreach (var fieldProvider in _contentFieldProviders) { - foreach (var fieldProvider in contentFieldProviders) + var fieldType = fieldProvider.GetField(schema, field, _part.Name); + if (fieldType != null) { - var fieldType = fieldProvider.GetField(schema, field, _part.Name); - if (fieldType != null) - { - AddField(fieldType); - break; - } + AddField(fieldType); + break; } } } From 44a1340b00d0b763e76f8e9fb395185e4912106d Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 18 Sep 2024 14:23:44 -0700 Subject: [PATCH 05/22] DynamicPartGraphType should define fields in the constructor --- .../Types/DynamicContentTypeBuilder.cs | 2 +- .../Queries/Types/DynamicPartGraphType.cs | 27 ++++++------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index 3c2dede23e3..dfe9089776d 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -187,7 +187,7 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe Name = partFieldName, Description = S["Represents a {0}.", part.PartDefinition.Name], Type = typeof(DynamicPartGraphType), - ResolvedType = new DynamicPartGraphType(part, _contentFieldProviders), + ResolvedType = new DynamicPartGraphType(part, _contentFieldProviders, schema), Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index 1740c9d49f6..b5c2544effe 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -5,36 +5,25 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public sealed class DynamicPartGraphType : ObjectGraphType { - private ContentTypePartDefinition _part; - private readonly IEnumerable _contentFieldProviders; - public DynamicPartGraphType( ContentTypePartDefinition part, - IEnumerable contentFieldProviders) + IEnumerable contentFieldProviders, + ISchema schema) { Name = part.Name; - _part = part; - _contentFieldProviders = contentFieldProviders; - } - public override void Initialize(ISchema schema) - { - foreach (var field in _part.PartDefinition.Fields) + foreach (var field in part.PartDefinition.Fields) { - foreach (var fieldProvider in _contentFieldProviders) + foreach (var fieldProvider in contentFieldProviders) { - var fieldType = fieldProvider.GetField(schema, field, _part.Name); - if (fieldType != null) + var fieldType = fieldProvider.GetField(schema, field, part.Name); + if (fieldType == null) { - AddField(fieldType); break; } + + AddField(fieldType); } } - - // Part is not required here anymore, do not keep it alive. - _part = null; - - base.Initialize(schema); } } From ca7d97eabc196474dccf338bebc7c8a0c79f2b34 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 18 Sep 2024 14:35:12 -0700 Subject: [PATCH 06/22] cleanup --- .../Queries/Types/DynamicContentTypeBuilder.cs | 5 +++-- .../ServiceCollectionExtensions.cs | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index dfe9089776d..b85fdf6e29d 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -13,9 +13,10 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public abstract class DynamicContentTypeBuilder : IContentTypeBuilder { protected readonly IHttpContextAccessor _httpContextAccessor; - private readonly IEnumerable _contentFieldProviders; + protected readonly IEnumerable _contentFieldProviders; protected readonly GraphQLContentOptions _contentOptions; protected readonly IStringLocalizer S; + private readonly Dictionary _dynamicPartFields; protected DynamicContentTypeBuilder(IHttpContextAccessor httpContextAccessor, @@ -41,7 +42,7 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe } var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; - var contentFieldProviders = serviceProvider.GetServices().ToList(); + var contentFieldProviders = serviceProvider.GetServices().ToArray(); foreach (var part in contentTypeDefinition.Parts) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/ServiceCollectionExtensions.cs index 7727a8f484d..f59ab7ee9bd 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/ServiceCollectionExtensions.cs @@ -22,7 +22,6 @@ public static IServiceCollection AddContentGraphQL(this IServiceCollection servi services.AddPermissionProvider(); - services.AddTransient(); services.AddScoped(); services.AddScoped(); From 6698d69a093ccf6cd9b0774b29839b635c4db19f Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 18 Sep 2024 16:03:12 -0700 Subject: [PATCH 07/22] Adding ResolvedType --- .../GraphQL/Fields/ContentFieldsProvider.cs | 21 ++++++- .../GraphQL/SiteLayersQuery.cs | 3 +- .../GraphQL/SiteCulturesQuery.cs | 3 +- .../GraphQL/MenuItemContentTypeBuilder.cs | 5 +- .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 4 +- .../GraphQL/ElasticQueryFieldTypeProvider.cs | 2 + .../GraphQL/LuceneQueryFieldTypeProvider.cs | 2 + .../Queries/WhereInputObjectGraphType.cs | 55 +++++++++++++++++-- .../Queries/ContentItemQuery.cs | 1 + .../Types/DynamicContentTypeBuilder.cs | 9 +-- .../Types/DynamicContentTypeQueryBuilder.cs | 3 +- .../DynamicContentTypeWhereInputBuilder.cs | 3 +- .../Queries/Types/TypedContentTypeBuilder.cs | 16 +++--- .../GraphQL/UserType.cs | 2 +- .../GraphQL/ContentItemsFieldTypeTests.cs | 38 +++++++++---- 15 files changed, 123 insertions(+), 44 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index 6522a92afb6..7de66c9c9c4 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -20,10 +20,11 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Boolean field", FieldType = typeof(BooleanGraphType), + ResolvedType = new BooleanGraphType(), UnderlyingType = typeof(BooleanField), FieldAccessor = field => ((BooleanField)field).Value, IndexType = typeof(BooleanFieldIndex), - Index = nameof(BooleanFieldIndex.Boolean) + Index = nameof(BooleanFieldIndex.Boolean), } }, { @@ -32,10 +33,11 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Date field", FieldType = typeof(DateGraphType), + ResolvedType = new DateGraphType(), UnderlyingType = typeof(DateField), FieldAccessor = field => ((DateField)field).Value, IndexType = typeof(DateFieldIndex), - Index = nameof(DateFieldIndex.Date) + Index = nameof(DateFieldIndex.Date), } }, { @@ -44,10 +46,11 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Date & time field", FieldType = typeof(DateTimeGraphType), + ResolvedType = new DateTimeGraphType(), UnderlyingType = typeof(DateTimeField), FieldAccessor = field => ((DateTimeField)field).Value, IndexType = typeof(DateTimeFieldIndex), - Index = nameof(DateTimeFieldIndex.DateTime) + Index = nameof(DateTimeFieldIndex.DateTime), } }, { @@ -56,6 +59,7 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Numeric field", FieldType = typeof(DecimalGraphType), + ResolvedType = new DecimalGraphType(), UnderlyingType = typeof(NumericField), FieldAccessor = field => ((NumericField)field).Value, IndexType = typeof(NumericFieldIndex), @@ -68,6 +72,7 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Text field", FieldType = typeof(StringGraphType), + ResolvedType = new StringGraphType(), UnderlyingType = typeof(TextField), FieldAccessor = field => ((TextField)field).Text, IndexType = typeof(TextFieldIndex), @@ -80,6 +85,7 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Time field", FieldType = typeof(TimeSpanGraphType), + ResolvedType = new TimeSpanGraphType(), UnderlyingType = typeof(TimeField), FieldAccessor = field => ((TimeField)field).Value, IndexType = typeof(TimeFieldIndex), @@ -92,6 +98,7 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Multi text field", FieldType = typeof(ListGraphType), + ResolvedType = new ListGraphType(), UnderlyingType = typeof(MultiTextField), FieldAccessor = field => ((MultiTextField)field).Values, } @@ -110,6 +117,7 @@ public FieldType GetField(ISchema schema, ContentPartFieldDefinition field, stri Name = customFieldName ?? field.Name, Description = fieldDescriptor.Description, Type = fieldDescriptor.FieldType, + ResolvedType = fieldDescriptor.ResolvedType, Resolver = new FuncFieldResolver(context => { // Check if part has been collapsed by trying to get the parent part. @@ -154,10 +162,17 @@ public bool HasFieldIndex(ContentPartFieldDefinition field) private sealed class FieldTypeDescriptor { public string Description { get; set; } + public Type FieldType { get; set; } + public Type UnderlyingType { get; set; } + + public required IGraphType ResolvedType { get; set; } + public Func FieldAccessor { get; set; } + public string Index { get; set; } + public Type IndexType { get; set; } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs index 1421bb17dc2..1fd58874af2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs @@ -38,7 +38,8 @@ public Task BuildAsync(ISchema schema) Name = "SiteLayers", Description = S["Site layers define the rules and zone placement for widgets."], Type = typeof(ListGraphType), - Resolver = new LockedAsyncFieldResolver>(ResolveAsync) + ResolvedType = new ListGraphType(), + Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; schema.Query.AddField(field); diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs index 1fb5ba5d14a..365ebf6aef8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs @@ -46,7 +46,8 @@ public Task BuildAsync(ISchema schema) Name = "SiteCultures", Description = S["The active cultures configured for the site."], Type = typeof(ListGraphType), - Resolver = new LockedAsyncFieldResolver>(ResolveAsync) + ResolvedType = new ListGraphType(), + Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; schema.Query.AddField(field); diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs index 6c2a72c5fee..bd00f13f2de 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs @@ -18,9 +18,10 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentItemType.AddField(new FieldType { - Type = typeof(MenuItemsListQueryObjectType), Name = nameof(MenuItemsListPart).ToFieldName(), - Resolver = new FuncFieldResolver(context => context.Source.As()) + Type = typeof(MenuItemsListQueryObjectType), + ResolvedType = new MenuItemsListQueryObjectType(), + Resolver = new FuncFieldResolver(context => context.Source.As()), }); contentItemType.Interface(); diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index f0f7572fa78..f029c3e2c5e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -117,6 +117,7 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc Name = nameLower, Description = description, Type = typeof(StringGraphType), + ResolvedType = new StringGraphType(), Resolver = new FuncFieldResolver(context => { var source = context.Source; @@ -131,8 +132,9 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc var field = new FieldType() { Name = nameLower, - Description = description, Type = typeof(IntGraphType), + ResolvedType = new IntGraphType(), + Description = description, Resolver = new FuncFieldResolver(context => { var source = context.Source; diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs index 492dcccb0e6..aad37ed411d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs @@ -112,6 +112,7 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc Name = nameLower, Description = description, Type = typeof(StringGraphType), + ResolvedType = new StringGraphType(), Resolver = new FuncFieldResolver(context => { var source = context.Source; @@ -128,6 +129,7 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc Name = nameLower, Description = description, Type = typeof(IntGraphType), + ResolvedType = new IntGraphType(), Resolver = new FuncFieldResolver(context => { var source = context.Source; diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs index 63b4e630c38..d215e4d032b 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs @@ -114,6 +114,7 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc Name = nameLower, Description = description, Type = typeof(StringGraphType), + ResolvedType = new StringGraphType(), Resolver = new FuncFieldResolver(context => { var source = context.Source; @@ -130,6 +131,7 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc Name = nameLower, Description = description, Type = typeof(IntGraphType), + ResolvedType = new IntGraphType(), Resolver = new FuncFieldResolver(context => { var source = context.Source; diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs index 7d28ba1b445..fea6daffd67 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs @@ -94,26 +94,31 @@ public virtual void AddScalarFilterFields(Type graphType, string fieldName, stri private void AddEqualityFilters(Type graphType, string fieldName, string description) { - AddFilterFields(graphType, EqualityOperators, fieldName, description); + AddFilterFields(graphType, CreateGraphType(graphType), EqualityOperators, fieldName, description); } private void AddStringFilters(Type graphType, string fieldName, string description) { - AddFilterFields(graphType, StringComparisonOperators, fieldName, description); + AddFilterFields(graphType, CreateGraphType(graphType), StringComparisonOperators, fieldName, description); } private void AddNonStringFilters(Type graphType, string fieldName, string description) { - AddFilterFields(graphType, NonStringValueComparisonOperators, fieldName, description); + AddFilterFields(graphType, CreateGraphType(graphType), NonStringValueComparisonOperators, fieldName, description); } private void AddMultiValueFilters(Type graphType, string fieldName, string description) { var wrappedType = typeof(ListGraphType<>).MakeGenericType(graphType); - AddFilterFields(wrappedType, MultiValueComparisonOperators, fieldName, description); + AddFilterFields(wrappedType, CreateGraphType(graphType), MultiValueComparisonOperators, fieldName, description); } - private void AddFilterFields(Type graphType, IDictionary filters, string fieldName, string description) + private void AddFilterFields( + Type graphType, + IGraphType resolvedType, + IDictionary filters, + string fieldName, + string description) { foreach (var filter in filters) { @@ -121,8 +126,46 @@ private void AddFilterFields(Type graphType, IDictionary filters { Name = fieldName + filter.Key, Description = $"{description} {filter.Value}", - Type = graphType + Type = graphType, + ResolvedType = resolvedType, }); } } + + private readonly Dictionary graphTypes = new(); + + private IGraphType CreateGraphType(Type type) + { + if (type.IsGenericType) + { + var genericDef = type.GetGenericTypeDefinition(); + if (genericDef == typeof(ListGraphType<>)) + { + var innerType = type.GetGenericArguments()[0]; + + return new ListGraphType(CreateGraphType(innerType)); + } + + if (genericDef == typeof(NonNullGraphType<>)) + { + var innerType = type.GetGenericArguments()[0]; + + return new NonNullGraphType(CreateGraphType(innerType)); + } + } + + if (typeof(ScalarGraphType).IsAssignableFrom(type)) + { + if (!graphTypes.TryGetValue(type, out var graphType)) + { + graphType = (IGraphType)Activator.CreateInstance(type); + + graphTypes[type] = graphType; + } + + return graphType; + } + + throw new InvalidOperationException($"{type.Name} is not a valid {nameof(ScalarGraphType)}."); + } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs index 29408e222f8..9f44fc5c7df 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs @@ -31,6 +31,7 @@ public Task BuildAsync(ISchema schema) Name = "ContentItem", Description = S["Content items are instances of content types, just like objects are instances of classes."], Type = typeof(ContentItemInterface), + // ResolvedType = new NonNullGraphType(), Arguments = new QueryArguments( new QueryArgument> { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index b85fdf6e29d..ded835e4fd0 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -13,19 +13,17 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public abstract class DynamicContentTypeBuilder : IContentTypeBuilder { protected readonly IHttpContextAccessor _httpContextAccessor; - protected readonly IEnumerable _contentFieldProviders; protected readonly GraphQLContentOptions _contentOptions; protected readonly IStringLocalizer S; private readonly Dictionary _dynamicPartFields; - protected DynamicContentTypeBuilder(IHttpContextAccessor httpContextAccessor, + protected DynamicContentTypeBuilder( + IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, - IEnumerable contentFieldProviders, IStringLocalizer localizer) { _httpContextAccessor = httpContextAccessor; - _contentFieldProviders = contentFieldProviders; _contentOptions = contentOptionsAccessor.Value; _dynamicPartFields = []; @@ -40,7 +38,6 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe { return; } - var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; var contentFieldProviders = serviceProvider.GetServices().ToArray(); @@ -188,7 +185,7 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe Name = partFieldName, Description = S["Represents a {0}.", part.PartDefinition.Name], Type = typeof(DynamicPartGraphType), - ResolvedType = new DynamicPartGraphType(part, _contentFieldProviders, schema), + ResolvedType = new DynamicPartGraphType(part, contentFieldProviders, schema), Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs index 9d6b62ed982..6a74496498b 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs @@ -11,9 +11,8 @@ public class DynamicContentTypeQueryBuilder : DynamicContentTypeBuilder { public DynamicContentTypeQueryBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, - IEnumerable contentFieldProviders, IStringLocalizer localizer) - : base(httpContextAccessor, contentOptionsAccessor, contentFieldProviders, localizer) { } + : base(httpContextAccessor, contentOptionsAccessor, localizer) { } public override void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs index e256d29a5bb..ff1836b04ce 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs @@ -11,9 +11,8 @@ public class DynamicContentTypeWhereInputBuilder : DynamicContentTypeBuilder { public DynamicContentTypeWhereInputBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, - IEnumerable contentFieldProviders, IStringLocalizer localizer) - : base(httpContextAccessor, contentOptionsAccessor, contentFieldProviders, localizer) { } + : base(httpContextAccessor, contentOptionsAccessor, localizer) { } public override void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 561939d0066..e3bda7c2e72 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -100,14 +100,14 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition Description = queryGraphType.Description, }; contentItemType.Field(partFieldName, queryGraphType.GetType()) - .Description(queryGraphType.Description) - .Resolve(context => - { - var nameToResolve = partName; - var typeToResolve = context.FieldDefinition.ResolvedType.GetType().BaseType.GetGenericArguments().First(); - - return context.Source.Get(typeToResolve, nameToResolve); - }); + .Description(queryGraphType.Description) + .Resolve(context => + { + var nameToResolve = partName; + var typeToResolve = context.FieldDefinition.ResolvedType.GetType().BaseType.GetGenericArguments().First(); + + return context.Source.Get(typeToResolve, nameToResolve); + }); } } diff --git a/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs b/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs index a1276989049..981e5fb0c56 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs @@ -8,7 +8,7 @@ namespace OrchardCore.Users.GraphQL; public class UserType : ObjectGraphType { - protected readonly IStringLocalizer S; + protected readonly IStringLocalizer S; public UserType(IStringLocalizer localizer) { diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs index cafc2c3cb14..904d0a88885 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs @@ -414,15 +414,19 @@ private static ResolveFieldContext CreateAnimalFieldContext(IServiceProvider ser FieldDefinition = new FieldType { Name = "Inputs", - ResolvedType = new ListGraphType(new StringGraphType() { Name = "Animal" }), - Arguments = [ - new QueryArgument - { - Name = "where", - Description = "filters the animals", - ResolvedType = where - } - ] + ResolvedType = new ListGraphType(new StringGraphType() + { + Name = "Animal", + }), + Arguments = + [ + new QueryArgument + { + Name = "where", + Description = "filters the animals", + ResolvedType = where + } + ] }, RequestServices = services }; @@ -435,7 +439,12 @@ public AnimalPartWhereInput(string fieldName) { Name = "Test"; Description = "Foo"; - var fieldType = new FieldType { Name = fieldName, Type = typeof(StringGraphType) }; + var fieldType = new FieldType + { + Name = fieldName, + Type = typeof(StringGraphType), + ResolvedType = new StringGraphType(), + }; fieldType.Metadata["PartName"] = "AnimalPart"; AddField(fieldType); } @@ -447,7 +456,12 @@ public AnimalPartCollapsedWhereInput() { Name = "Test"; Description = "Foo"; - var fieldType = new FieldType { Name = "Name", Type = typeof(StringGraphType) }; + var fieldType = new FieldType + { + Name = "Name", + Type = typeof(StringGraphType), + ResolvedType = new StringGraphType(), + }; fieldType.Metadata["PartName"] = "AnimalPart"; fieldType.Metadata["PartCollapsed"] = true; AddField(fieldType); @@ -457,7 +471,9 @@ public AnimalPartCollapsedWhereInput() public class Animal : ContentPart { public string Name { get; set; } + public bool IsHappy { get; set; } + public bool IsScary { get; set; } } From 1bdb795f894292217fcb0814a03728a222e724c9 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Tue, 19 Nov 2024 16:20:37 -0800 Subject: [PATCH 08/22] attempt to register. --- .../Services/SchemaService.cs | 41 +++++++++++++++---- .../GraphQL/Fields/ContentFieldsProvider.cs | 2 +- .../GraphQL/MenuItemsListQueryObjectType.cs | 1 - .../ServiceCollectionExtensions.cs | 3 +- .../Queries/ContentItemQuery.cs | 4 +- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 3b8f0e9c8b0..5ed49b80416 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -61,19 +61,42 @@ public async Task GetSchemaAsync() var schema = new Schema(new SelfActivatingServiceProvider(_serviceProvider)) { - Query = new ObjectGraphType { Name = "Query" }, - Mutation = new ObjectGraphType { Name = "Mutation" }, - Subscription = new ObjectGraphType { Name = "Subscription" }, + Query = new ObjectGraphType + { + Name = "Query", + }, + Mutation = new ObjectGraphType + { + Name = "Mutation", + }, + Subscription = new ObjectGraphType + { + Name = "Subscription", + }, NameConverter = new OrchardFieldNameConverter(), }; + // Keep track of registered types to avoid duplicates. + var registeredTypes = new HashSet(); + foreach (var type in serviceProvider.GetServices()) { + if (!registeredTypes.Add(type.Name)) + { + continue; + } + schema.RegisterType(type); } foreach (var type in serviceProvider.GetServices()) { + // Only register if it's not already registered + if (!registeredTypes.Add(type.Name)) + { + continue; + } + schema.RegisterType(type); } @@ -90,28 +113,32 @@ public async Task GetSchemaAsync() await builder.BuildAsync(schema); } - // Clean Query, Mutation and Subscription if they have no fields // to prevent GraphQL configuration errors. - if (schema.Query.Fields.Count == 0) + if (schema.Query?.Fields != null && schema.Query.Fields.Count == 0) { schema.Query = null; } - if (schema.Mutation.Fields.Count == 0) + if (schema.Mutation?.Fields != null && schema.Mutation.Fields.Count == 0) { schema.Mutation = null; } - if (schema.Subscription.Fields.Count == 0) + if (schema.Subscription?.Fields != null && schema.Subscription.Fields.Count == 0) { schema.Subscription = null; } schema.Initialize(); + return _schema = schema; } + catch (Exception) + { + throw; + } finally { _schemaGenerationSemaphore.Release(); diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index 7de66c9c9c4..fda1a866837 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -150,7 +150,7 @@ public FieldTypeIndexDescriptor GetFieldIndex(ContentPartFieldDefinition field) return new FieldTypeIndexDescriptor { Index = fieldDescriptor.Index, - IndexType = fieldDescriptor.IndexType + IndexType = fieldDescriptor.IndexType, }; } diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs index 15627321436..2030c2c94ce 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs @@ -12,6 +12,5 @@ public MenuItemsListQueryObjectType() Field>("menuItems") .Description("The menu items.") .Resolve(context => context.Source.MenuItems); - } } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs index ca5a2c72663..9bda0fc3201 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs @@ -1,5 +1,6 @@ using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace OrchardCore.Apis; @@ -30,7 +31,7 @@ public static void AddObjectGraphType(this IServiceCollectio where TInput : class where TInputType : ObjectGraphType { - services.AddTransient(); + services.TryAddSingleton(); services.AddTransient, TInputType>(s => s.GetRequiredService()); services.AddTransient(s => s.GetRequiredService()); } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs index 9f44fc5c7df..690b08de896 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs @@ -31,12 +31,12 @@ public Task BuildAsync(ISchema schema) Name = "ContentItem", Description = S["Content items are instances of content types, just like objects are instances of classes."], Type = typeof(ContentItemInterface), - // ResolvedType = new NonNullGraphType(), + ResolvedType = new NonNullGraphType(), Arguments = new QueryArguments( new QueryArgument> { Name = "contentItemId", - Description = S["Content item id"] + Description = S["Content item id"], } ), Resolver = new FuncFieldResolver(ResolveAsync) From ecf72102140e6e9ae2a1026c8e992b30281e98d9 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 20 Nov 2024 07:57:13 -0800 Subject: [PATCH 09/22] fix more issues --- .../Services/SchemaService.cs | 3 +- .../GraphQL/LayerQueryObjectType.cs | 13 ++++-- .../GraphQL/SiteLayersQuery.cs | 7 ++- .../GraphQL/MediaAssetQuery.cs | 1 + .../GraphQL/MenuItemContentTypeBuilder.cs | 1 - .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 2 +- .../Options/GraphQLContentPartOption.cs | 1 + .../Queries/ContentItemQuery.cs | 2 +- .../Queries/ContentItemsFieldType.cs | 38 ++++++++++++--- .../Queries/ContentTypeQuery.cs | 5 +- .../Queries/Types/ContentItemType.cs | 46 ++++++++++++++----- .../Queries/Types/TypedContentTypeBuilder.cs | 16 +++---- 12 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 5ed49b80416..783f9409e45 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -135,8 +135,9 @@ public async Task GetSchemaAsync() return _schema = schema; } - catch (Exception) + catch (Exception e) { + var t = e; throw; } finally diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs index a12f83eecda..58593fcf4e4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs @@ -18,11 +18,16 @@ public LayerQueryObjectType() { Name = "Layer"; - Field(layer => layer.Name).Description("The name of the layer."); + Field(layer => layer.Name) + .Description("The name of the layer."); + Field, IEnumerable>("layerrule") .Description("The rule that activates the layer.") .Resolve(ctx => ctx.Source.LayerRule.Conditions); - Field(layer => layer.Description).Description("The description of the layer."); + + Field(layer => layer.Description) + .Description("The description of the layer."); + Field, IEnumerable>("widgets") .Description("The widgets for this layer.") .Argument("status", "publication status of the widgets") @@ -50,8 +55,8 @@ async ValueTask> GetWidgetsForLayerAsync(IResolveFieldC } } - private static Expression> GetVersionFilter(PublicationStatusEnum status) => - status switch + private static Expression> GetVersionFilter(PublicationStatusEnum status) + => status switch { PublicationStatusEnum.Published => x => x.Published, PublicationStatusEnum.Draft => x => x.Latest && !x.Published, diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs index 1fd58874af2..baffe120f4d 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs @@ -24,7 +24,8 @@ public SiteLayersQuery( _graphQLContentOptions = graphQLContentOptions.Value; } - public Task GetIdentifierAsync() => Task.FromResult(string.Empty); + public Task GetIdentifierAsync() + => Task.FromResult(string.Empty); public Task BuildAsync(ISchema schema) { @@ -38,7 +39,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteLayers", Description = S["Site layers define the rules and zone placement for widgets."], Type = typeof(ListGraphType), - ResolvedType = new ListGraphType(), + ResolvedType = new LayerQueryObjectType(), Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; @@ -50,7 +51,9 @@ public Task BuildAsync(ISchema schema) private async ValueTask> ResolveAsync(IResolveFieldContext resolveContext) { var layerService = resolveContext.RequestServices.GetService(); + var allLayers = await layerService.GetLayersAsync(); + return allLayers.Layers; } } diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs index 71c98579da2..3a45718b221 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs @@ -37,6 +37,7 @@ public Task BuildAsync(ISchema schema) Name = "MediaAssets", Description = S["Media assets are items that are part of your media library."], Type = typeof(ListGraphType), + ResolvedType = new MediaAssetObjectType(), Arguments = new QueryArguments( new QueryArgument { diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs index bd00f13f2de..41f1577f630 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs @@ -20,7 +20,6 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition { Name = nameof(MenuItemsListPart).ToFieldName(), Type = typeof(MenuItemsListQueryObjectType), - ResolvedType = new MenuItemsListQueryObjectType(), Resolver = new FuncFieldResolver(context => context.Source.As()), }); diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index f029c3e2c5e..2c01bc06ced 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -100,7 +100,7 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc var typeType = new ObjectGraphType { - Name = fieldTypeName + Name = fieldTypeName, }; foreach (var child in properties) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentPartOption.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentPartOption.cs index ce1e54f80c8..d933310c67d 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentPartOption.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentPartOption.cs @@ -19,5 +19,6 @@ public GraphQLContentPartOption(string contentPartName) public string Name { get; } public bool Collapse { get; set; } + public bool Hidden { get; set; } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs index 690b08de896..ec16e3c3378 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs @@ -31,7 +31,7 @@ public Task BuildAsync(ISchema schema) Name = "ContentItem", Description = S["Content items are instances of content types, just like objects are instances of classes."], Type = typeof(ContentItemInterface), - ResolvedType = new NonNullGraphType(), + ResolvedType = new ObjectGraphType(), Arguments = new QueryArguments( new QueryArgument> { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index 37b3346a80c..437a6d0a6c8 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -40,16 +40,42 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions); - + ResolvedType = new ContentItemType(optionsAccessor); var whereInput = new ContentItemWhereInput(contentItemName, optionsAccessor); var orderByInput = new ContentItemOrderByInput(contentItemName); Arguments = new QueryArguments( - new QueryArgument { Name = "where", Description = "filters the content items", ResolvedType = whereInput }, - new QueryArgument { Name = "orderBy", Description = "sort order", ResolvedType = orderByInput }, - new QueryArgument { Name = "first", Description = "the first n content items", ResolvedType = new IntGraphType() }, - new QueryArgument { Name = "skip", Description = "the number of content items to skip", ResolvedType = new IntGraphType() }, - new QueryArgument { Name = "status", Description = "publication status of the content item", ResolvedType = new PublicationStatusGraphType(), DefaultValue = PublicationStatusEnum.Published } + new QueryArgument + { + Name = "where", + Description = "filters the content items", + ResolvedType = whereInput, + }, + new QueryArgument + { + Name = "orderBy", + Description = "sort order", + ResolvedType = orderByInput, + }, + new QueryArgument + { + Name = "first", + Description = "the first n content items", + ResolvedType = new IntGraphType(), + }, + new QueryArgument + { + Name = "skip", + Description = "the number of content items to skip", + ResolvedType = new IntGraphType(), + }, + new QueryArgument + { + Name = "status", + Description = "publication status of the content item", + ResolvedType = new PublicationStatusGraphType(), + DefaultValue = PublicationStatusEnum.Published, + } ); Resolver = new LockedAsyncFieldResolver>(ResolveAsync); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs index 874ff2e4ef0..59c445b469b 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs @@ -19,6 +19,7 @@ public class ContentTypeQuery : ISchemaBuilder private readonly IHttpContextAccessor _httpContextAccessor; private readonly IOptions _contentOptionsAccessor; private readonly IOptions _settingsAccessor; + protected readonly IStringLocalizer S; public ContentTypeQuery(IHttpContextAccessor httpContextAccessor, @@ -55,14 +56,14 @@ public async Task BuildAsync(ISchema schema) var typeType = new ContentItemType(_contentOptionsAccessor) { Name = typeDefinition.Name, - Description = S["Represents a {0}.", typeDefinition.DisplayName] + Description = S["Represents a {0}.", typeDefinition.DisplayName], }; var query = new ContentItemsFieldType(typeDefinition.Name, schema, _contentOptionsAccessor, _settingsAccessor) { Name = typeDefinition.Name, Description = S["Represents a {0}.", typeDefinition.DisplayName], - ResolvedType = new ListGraphType(typeType) + ResolvedType = typeType, }; query.RequirePermission(CommonPermissions.ExecuteGraphQL); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs index a721ad1e18f..0759739590a 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs @@ -22,17 +22,41 @@ public ContentItemType(IOptions optionsAccessor) Name = "ContentItemType"; - Field(ci => ci.ContentItemId).Description("Content item id"); - Field(ci => ci.ContentItemVersionId, nullable: true).Description("The content item version id"); - Field(ci => ci.ContentType).Description("Type of content"); - Field(ci => ci.DisplayText, nullable: true).Description("The display text of the content item"); - Field(ci => ci.Published).Description("Is the published version"); - Field(ci => ci.Latest).Description("Is the latest version"); - Field("modifiedUtc").Resolve(ci => ci.Source.ModifiedUtc).Description("The date and time of modification"); - Field("publishedUtc").Resolve(ci => ci.Source.PublishedUtc).Description("The date and time of publication"); - Field("createdUtc").Resolve(ci => ci.Source.CreatedUtc).Description("The date and time of creation"); - Field(ci => ci.Owner, nullable: true).Description("The owner of the content item"); - Field(ci => ci.Author).Description("The author of the content item"); + Field(ci => ci.ContentItemId) + .Description("Content item id"); + + Field(ci => ci.ContentItemVersionId, nullable: true) + .Description("The content item version id"); + + Field(ci => ci.ContentType) + .Description("Type of content"); + + Field(ci => ci.DisplayText, nullable: true) + .Description("The display text of the content item"); + + Field(ci => ci.Published) + .Description("Is the published version"); + + Field(ci => ci.Latest) + .Description("Is the latest version"); + + Field("modifiedUtc") + .Resolve(ci => ci.Source.ModifiedUtc) + .Description("The date and time of modification"); + + Field("publishedUtc") + .Resolve(ci => ci.Source.PublishedUtc) + .Description("The date and time of publication"); + + Field("createdUtc") + .Resolve(ci => ci.Source.CreatedUtc) + .Description("The date and time of creation"); + + Field(ci => ci.Owner, nullable: true) + .Description("The owner of the content item"); + + Field(ci => ci.Author) + .Description("The author of the content item"); Field("render") .ResolveLockedAsync(RenderShapeAsync); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index e3bda7c2e72..1c0a6c7c3e4 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -14,7 +14,8 @@ public class TypedContentTypeBuilder : IContentTypeBuilder private readonly IHttpContextAccessor _httpContextAccessor; private readonly GraphQLContentOptions _contentOptions; - public TypedContentTypeBuilder(IHttpContextAccessor httpContextAccessor, + public TypedContentTypeBuilder( + IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor) { _httpContextAccessor = httpContextAccessor; @@ -64,11 +65,13 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition continue; } - var partType = typeActivator.GetTypeActivator(part.PartDefinition.Name).Type; + var partActivator = typeActivator.GetTypeActivator(part.PartDefinition.Name); + var partType = partActivator.Type; var rolledUpField = new FieldType { Name = field.Name, Type = field.Type, + // ResolvedType = instance.CreateInstance(), Description = field.Description, DeprecationReason = field.DeprecationReason, Arguments = field.Arguments, @@ -93,13 +96,8 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition } else { - var field = new FieldType - { - Name = partFieldName, - Type = queryGraphType.GetType(), - Description = queryGraphType.Description, - }; - contentItemType.Field(partFieldName, queryGraphType.GetType()) + contentItemType + .Field(partFieldName, queryGraphType.GetType()) .Description(queryGraphType.Description) .Resolve(context => { From d0f317a22018de8a1073c1a9c10d701fd4a35306 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 20 Nov 2024 08:05:16 -0800 Subject: [PATCH 10/22] simplify the schema service --- .../Services/SchemaService.cs | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 783f9409e45..88dd113b175 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using GraphQL; using GraphQL.MicrosoftDI; using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; @@ -76,29 +77,8 @@ public async Task GetSchemaAsync() NameConverter = new OrchardFieldNameConverter(), }; - // Keep track of registered types to avoid duplicates. - var registeredTypes = new HashSet(); - - foreach (var type in serviceProvider.GetServices()) - { - if (!registeredTypes.Add(type.Name)) - { - continue; - } - - schema.RegisterType(type); - } - - foreach (var type in serviceProvider.GetServices()) - { - // Only register if it's not already registered - if (!registeredTypes.Add(type.Name)) - { - continue; - } - - schema.RegisterType(type); - } + schema.RegisterTypes(serviceProvider.GetServices().ToArray()); + schema.RegisterTypes(serviceProvider.GetServices().ToArray()); foreach (var builder in _schemaBuilders) { From ce76ac2b5440df61b7b6706d6016de25687486f4 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Wed, 20 Nov 2024 08:16:07 -0800 Subject: [PATCH 11/22] cleanup --- .../GraphQL/SiteCulturesQuery.cs | 5 +++-- .../GraphQL/MenuItemContentTypeBuilder.cs | 10 +++------- .../ServiceCollectionExtensions.cs | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs index 365ebf6aef8..37be0f5a8c2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs @@ -31,7 +31,8 @@ public SiteCulturesQuery( _graphQLContentOptions = graphQLContentOptions.Value; } - public Task GetIdentifierAsync() => Task.FromResult(string.Empty); + public Task GetIdentifierAsync() + => Task.FromResult(string.Empty); /// public Task BuildAsync(ISchema schema) @@ -46,7 +47,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteCultures", Description = S["The active cultures configured for the site."], Type = typeof(ListGraphType), - ResolvedType = new ListGraphType(), + ResolvedType = new CultureQueryObjectType(), Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs index 41f1577f630..ae3715b6a68 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs @@ -1,4 +1,3 @@ -using GraphQL.Resolvers; using GraphQL.Types; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.GraphQL.Queries.Types; @@ -16,12 +15,9 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition return; } - contentItemType.AddField(new FieldType - { - Name = nameof(MenuItemsListPart).ToFieldName(), - Type = typeof(MenuItemsListQueryObjectType), - Resolver = new FuncFieldResolver(context => context.Source.As()), - }); + contentItemType + .Field(nameof(MenuItemsListPart).ToFieldName()) + .Resolve(context => context.Source.As()); contentItemType.Interface(); } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs index 9bda0fc3201..3c13ea5e2c4 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs @@ -16,7 +16,7 @@ public static void AddInputObjectGraphType(this IServiceCo where TObject : class where TObjectType : InputObjectGraphType { - services.AddTransient(); + services.TryAddTransient(); services.AddTransient, TObjectType>(s => s.GetRequiredService()); services.AddTransient(s => s.GetRequiredService()); } @@ -31,7 +31,7 @@ public static void AddObjectGraphType(this IServiceCollectio where TInput : class where TInputType : ObjectGraphType { - services.TryAddSingleton(); + services.TryAddTransient(); services.AddTransient, TInputType>(s => s.GetRequiredService()); services.AddTransient(s => s.GetRequiredService()); } From 534024455b71bc095aea53f00572649f7d2fda96 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 08:27:41 -0800 Subject: [PATCH 12/22] Fix Schema validations --- .../GraphQL/FlowMetadataContentTypeBuilder.cs | 4 +++ .../GraphQL/SiteLayersQuery.cs | 11 ++++--- .../GraphQL/SiteCulturesQuery.cs | 2 +- .../GraphQL/MediaAssetQuery.cs | 2 +- .../GraphQL/MenuItemContentTypeBuilder.cs | 4 +++ .../Queries/ContentItemQuery.cs | 5 +-- .../Queries/ContentItemsFieldType.cs | 2 +- .../Queries/PublicationStatusGraphType.cs | 1 - .../DynamicContentFieldsIndexAliasProvider.cs | 1 - .../Types/DynamicContentTypeBuilder.cs | 2 +- .../Types/DynamicContentTypeQueryBuilder.cs | 4 ++- .../Queries/Types/DynamicPartGraphType.cs | 32 +++++++++++++------ .../Queries/Types/IContentTypeBuilder.cs | 3 +- .../Queries/Types/TypedContentTypeBuilder.cs | 4 +++ 14 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs index 25119a26ccc..f3414b3d8a5 100644 --- a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs @@ -18,4 +18,8 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentItemType.Field("metadata") .Resolve(context => context.Source.As()); } + + public void Clear() + { + } } diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs index baffe120f4d..6ae12890905 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs @@ -13,15 +13,16 @@ namespace OrchardCore.Layers.GraphQL; public class SiteLayersQuery : ISchemaBuilder { - protected readonly IStringLocalizer S; private readonly GraphQLContentOptions _graphQLContentOptions; + protected readonly IStringLocalizer S; + public SiteLayersQuery( - IStringLocalizer localizer, - IOptions graphQLContentOptions) + IOptions graphQLContentOptions, + IStringLocalizer localizer) { - S = localizer; _graphQLContentOptions = graphQLContentOptions.Value; + S = localizer; } public Task GetIdentifierAsync() @@ -39,7 +40,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteLayers", Description = S["Site layers define the rules and zone placement for widgets."], Type = typeof(ListGraphType), - ResolvedType = new LayerQueryObjectType(), + // ResolvedType = new LayerQueryObjectType(), Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs index 37be0f5a8c2..0891e752555 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs @@ -47,7 +47,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteCultures", Description = S["The active cultures configured for the site."], Type = typeof(ListGraphType), - ResolvedType = new CultureQueryObjectType(), + // ResolvedType = new CultureQueryObjectType(), Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs index 3a45718b221..2f6799c0e81 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs @@ -37,7 +37,7 @@ public Task BuildAsync(ISchema schema) Name = "MediaAssets", Description = S["Media assets are items that are part of your media library."], Type = typeof(ListGraphType), - ResolvedType = new MediaAssetObjectType(), + // ResolvedType = new MediaAssetObjectType(), Arguments = new QueryArguments( new QueryArgument { diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs index ae3715b6a68..98dac63c2d9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs @@ -21,4 +21,8 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentItemType.Interface(); } + + public void Clear() + { + } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs index ec16e3c3378..978cd2192eb 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs @@ -12,6 +12,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries; public class ContentItemQuery : ISchemaBuilder { private readonly IHttpContextAccessor _httpContextAccessor; + protected readonly IStringLocalizer S; public ContentItemQuery(IHttpContextAccessor httpContextAccessor, @@ -22,7 +23,8 @@ public ContentItemQuery(IHttpContextAccessor httpContextAccessor, S = localizer; } - public Task GetIdentifierAsync() => Task.FromResult(string.Empty); + public Task GetIdentifierAsync() + => Task.FromResult(string.Empty); public Task BuildAsync(ISchema schema) { @@ -31,7 +33,6 @@ public Task BuildAsync(ISchema schema) Name = "ContentItem", Description = S["Content items are instances of content types, just like objects are instances of classes."], Type = typeof(ContentItemInterface), - ResolvedType = new ObjectGraphType(), Arguments = new QueryArguments( new QueryArgument> { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index 437a6d0a6c8..678c2508e6c 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -40,7 +40,7 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions); - ResolvedType = new ContentItemType(optionsAccessor); + // ResolvedType = new ContentItemType(optionsAccessor); var whereInput = new ContentItemWhereInput(contentItemName, optionsAccessor); var orderByInput = new ContentItemOrderByInput(contentItemName); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs index 8dcefd2e92d..9c24cadc0f4 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs @@ -4,7 +4,6 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries; public class PublicationStatusGraphType : EnumerationGraphType { - public PublicationStatusGraphType() { Name = "Status"; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs index e693a5595a0..4ca0fcdd83e 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs @@ -16,7 +16,6 @@ public class DynamicContentFieldsIndexAliasProvider : IIndexAliasProvider, ICont private readonly IMemoryCache _memoryCache; private readonly GraphQLContentOptions _contentOptions; - public DynamicContentFieldsIndexAliasProvider( IEnumerable contentFieldProviders, IOptions contentOptionsAccessor, diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index ded835e4fd0..6bee71820a6 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -185,7 +185,7 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe Name = partFieldName, Description = S["Represents a {0}.", part.PartDefinition.Name], Type = typeof(DynamicPartGraphType), - ResolvedType = new DynamicPartGraphType(part, contentFieldProviders, schema), + ResolvedType = new DynamicPartGraphType(part), Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs index 6a74496498b..fa45133c246 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs @@ -12,7 +12,9 @@ public class DynamicContentTypeQueryBuilder : DynamicContentTypeBuilder public DynamicContentTypeQueryBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, IStringLocalizer localizer) - : base(httpContextAccessor, contentOptionsAccessor, localizer) { } + : base(httpContextAccessor, contentOptionsAccessor, localizer) + { + } public override void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index b5c2544effe..87ff2cd8642 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -1,29 +1,41 @@ using GraphQL.Types; +using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement.Metadata.Models; namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public sealed class DynamicPartGraphType : ObjectGraphType { + private readonly ContentTypePartDefinition _part; + public DynamicPartGraphType( - ContentTypePartDefinition part, - IEnumerable contentFieldProviders, - ISchema schema) + ContentTypePartDefinition part) { Name = part.Name; + _part = part; + } - foreach (var field in part.PartDefinition.Fields) + public override void Initialize(ISchema schema) + { + if (schema is IServiceProvider serviceProvider) { - foreach (var fieldProvider in contentFieldProviders) + var contentFieldProviders = serviceProvider.GetServices(); + + foreach (var field in _part.PartDefinition.Fields) { - var fieldType = fieldProvider.GetField(schema, field, part.Name); - if (fieldType == null) + foreach (var fieldProvider in contentFieldProviders) { - break; - } + var fieldType = fieldProvider.GetField(schema, field, _part.Name); + if (fieldType == null) + { + break; + } - AddField(fieldType); + AddField(fieldType); + } } } + + base.Initialize(schema); } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentTypeBuilder.cs index 4964df7604e..599ab80114a 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentTypeBuilder.cs @@ -6,5 +6,6 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public interface IContentTypeBuilder { void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition contentTypeDefinition, ContentItemType contentItemType); - void Clear() { } + + void Clear(); } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 1c0a6c7c3e4..160bb52d1e1 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -141,4 +141,8 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition } } } + + public void Clear() + { + } } From fcae801c75304289d8d4a8ef978b69799b8c008e Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 09:01:50 -0800 Subject: [PATCH 13/22] cleanup --- .../Services/SchemaService.cs | 11 +++-------- .../OrchardCore.Layers/GraphQL/SiteLayersQuery.cs | 1 - .../GraphQL/SiteCulturesQuery.cs | 1 - .../OrchardCore.Media/GraphQL/MediaAssetQuery.cs | 1 - .../Queries/ContentItemQuery.cs | 1 - .../Queries/ContentTypeQuery.cs | 3 ++- .../Queries/Types/DynamicPartGraphType.cs | 6 +++--- 7 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 88dd113b175..89cc7736cdc 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -96,17 +96,17 @@ public async Task GetSchemaAsync() // Clean Query, Mutation and Subscription if they have no fields // to prevent GraphQL configuration errors. - if (schema.Query?.Fields != null && schema.Query.Fields.Count == 0) + if (schema.Query?.Fields is null || schema.Query.Fields.Count == 0) { schema.Query = null; } - if (schema.Mutation?.Fields != null && schema.Mutation.Fields.Count == 0) + if (schema.Mutation?.Fields is null || schema.Mutation.Fields.Count == 0) { schema.Mutation = null; } - if (schema.Subscription?.Fields != null && schema.Subscription.Fields.Count == 0) + if (schema.Subscription?.Fields is null || schema.Subscription.Fields.Count == 0) { schema.Subscription = null; } @@ -115,11 +115,6 @@ public async Task GetSchemaAsync() return _schema = schema; } - catch (Exception e) - { - var t = e; - throw; - } finally { _schemaGenerationSemaphore.Release(); diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs index 6ae12890905..41e2b6ca70f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs @@ -40,7 +40,6 @@ public Task BuildAsync(ISchema schema) Name = "SiteLayers", Description = S["Site layers define the rules and zone placement for widgets."], Type = typeof(ListGraphType), - // ResolvedType = new LayerQueryObjectType(), Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs index 0891e752555..b8ffc1a4a3e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs @@ -47,7 +47,6 @@ public Task BuildAsync(ISchema schema) Name = "SiteCultures", Description = S["The active cultures configured for the site."], Type = typeof(ListGraphType), - // ResolvedType = new CultureQueryObjectType(), Resolver = new LockedAsyncFieldResolver>(ResolveAsync), }; diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs index 2f6799c0e81..71c98579da2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs @@ -37,7 +37,6 @@ public Task BuildAsync(ISchema schema) Name = "MediaAssets", Description = S["Media assets are items that are part of your media library."], Type = typeof(ListGraphType), - // ResolvedType = new MediaAssetObjectType(), Arguments = new QueryArguments( new QueryArgument { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs index 978cd2192eb..c583e5ae436 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs @@ -19,7 +19,6 @@ public ContentItemQuery(IHttpContextAccessor httpContextAccessor, IStringLocalizer localizer) { _httpContextAccessor = httpContextAccessor; - S = localizer; } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs index 59c445b469b..bcacfadd474 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs @@ -36,6 +36,7 @@ public ContentTypeQuery(IHttpContextAccessor httpContextAccessor, public Task GetIdentifierAsync() { var contentDefinitionManager = _httpContextAccessor.HttpContext.RequestServices.GetService(); + return contentDefinitionManager.GetIdentifierAsync(); } @@ -63,7 +64,7 @@ public async Task BuildAsync(ISchema schema) { Name = typeDefinition.Name, Description = S["Represents a {0}.", typeDefinition.DisplayName], - ResolvedType = typeType, + ResolvedType = new ListGraphType(typeType), }; query.RequirePermission(CommonPermissions.ExecuteGraphQL); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index 87ff2cd8642..0a0c3cf78d1 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -26,12 +26,12 @@ public override void Initialize(ISchema schema) foreach (var fieldProvider in contentFieldProviders) { var fieldType = fieldProvider.GetField(schema, field, _part.Name); - if (fieldType == null) + if (fieldType != null) { + AddField(fieldType); + break; } - - AddField(fieldType); } } } From 3b0c7ea6683cf451b2cb0e9b5a1420c3dc28ece6 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 09:21:30 -0800 Subject: [PATCH 14/22] seal classes, and document the changes. --- mkdocs.yml | 1 + .../Services/SchemaService.cs | 6 +++-- .../GraphQL/SiteLayersQuery.cs | 4 +-- .../GraphQL/SiteCulturesQuery.cs | 5 ++-- .../GraphQL/MediaAssetQuery.cs | 5 ++-- .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 2 +- .../GraphQL/ElasticQueryFieldTypeProvider.cs | 6 +++-- .../GraphQL/LuceneQueryFieldTypeProvider.cs | 2 +- .../GraphQL/CurrentUserQuery.cs | 4 ++- .../GraphQLFieldNameAttribute.cs | 1 + .../GraphQLSettings.cs | 8 +++++- .../GraphQLUserContext.cs | 1 + .../Queries/ContentItemFilters.cs | 5 ++-- .../Queries/ContentItemQuery.cs | 4 +-- .../Queries/ContentTypeQuery.cs | 4 +-- .../Queries/PublicationStatusGraphType.cs | 2 +- .../Queries/Types/ContentItemInterface.cs | 2 +- .../Queries/Types/ContentItemOrderByInput.cs | 2 +- .../Queries/Types/ContentItemType.cs | 2 +- .../Queries/Types/ContentItemWhereInput.cs | 2 +- .../DynamicContentFieldsIndexAliasProvider.cs | 2 +- .../Types/DynamicContentTypeBuilder.cs | 1 + .../Types/DynamicContentTypeQueryBuilder.cs | 2 +- .../DynamicContentTypeWhereInputBuilder.cs | 5 ++-- .../Queries/Types/FieldTypeIndexDescriptor.cs | 8 ++++++ .../Queries/Types/IContentFieldProvider.cs | 6 ----- .../Queries/Types/TypedContentTypeBuilder.cs | 2 +- src/docs/releases/3.0.0.md | 25 +++++++++++++++++++ 28 files changed, 83 insertions(+), 36 deletions(-) create mode 100644 src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/FieldTypeIndexDescriptor.cs create mode 100644 src/docs/releases/3.0.0.md diff --git a/mkdocs.yml b/mkdocs.yml index d22589e4125..daaf0c1f4b1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,6 +56,7 @@ validation: not_in_nav: | samples/ releases/2.1.0.md + releases/3.0.0.md # Extensions markdown_extensions: diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 89cc7736cdc..cd4c82e3333 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -7,7 +7,7 @@ namespace OrchardCore.Apis.GraphQL.Services; -public class SchemaService : ISchemaFactory +public sealed class SchemaService : ISchemaFactory { private readonly IEnumerable _schemaBuilders; private readonly IServiceProvider _serviceProvider; @@ -16,7 +16,9 @@ public class SchemaService : ISchemaFactory private ISchema _schema; - public SchemaService(IEnumerable schemaBuilders, IServiceProvider serviceProvider) + public SchemaService( + IEnumerable schemaBuilders, + IServiceProvider serviceProvider) { _schemaBuilders = schemaBuilders; _serviceProvider = serviceProvider; diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs index 41e2b6ca70f..1e4e60cdd45 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs @@ -11,11 +11,11 @@ namespace OrchardCore.Layers.GraphQL; -public class SiteLayersQuery : ISchemaBuilder +public sealed class SiteLayersQuery : ISchemaBuilder { private readonly GraphQLContentOptions _graphQLContentOptions; - protected readonly IStringLocalizer S; + internal readonly IStringLocalizer S; public SiteLayersQuery( IOptions graphQLContentOptions, diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs index b8ffc1a4a3e..347eee587d7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs @@ -12,11 +12,12 @@ namespace OrchardCore.Localization.GraphQL; /// /// Represents a site cultures for Graph QL. /// -public class SiteCulturesQuery : ISchemaBuilder +public sealed class SiteCulturesQuery : ISchemaBuilder { - protected readonly IStringLocalizer S; private readonly GraphQLContentOptions _graphQLContentOptions; + internal readonly IStringLocalizer S; + /// /// Creates a new instance of the . /// diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs index 71c98579da2..12a6ba384cb 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs @@ -10,11 +10,12 @@ namespace OrchardCore.Media.GraphQL; -public class MediaAssetQuery : ISchemaBuilder +public sealed class MediaAssetQuery : ISchemaBuilder { - protected readonly IStringLocalizer S; private readonly GraphQLContentOptions _graphQLContentOptions; + protected internal IStringLocalizer S; + public MediaAssetQuery( IStringLocalizer localizer, IOptions graphQLContentOptions) diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index 2c01bc06ced..99abce9600a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -18,7 +18,7 @@ namespace OrchardCore.Queries.Sql.GraphQL.Queries; /// This implementation of registers /// all SQL Queries as GraphQL queries. /// -public class SqlQueryFieldTypeProvider : ISchemaBuilder +public sealed class SqlQueryFieldTypeProvider : ISchemaBuilder { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger _logger; diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs index aad37ed411d..11440892e85 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs @@ -16,12 +16,14 @@ namespace OrchardCore.Search.Elasticsearch.GraphQL.Queries; -public class ElasticQueryFieldTypeProvider : ISchemaBuilder +public sealed class ElasticQueryFieldTypeProvider : ISchemaBuilder { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger _logger; - public ElasticQueryFieldTypeProvider(IHttpContextAccessor httpContextAccessor, ILogger logger) + public ElasticQueryFieldTypeProvider( + IHttpContextAccessor httpContextAccessor, + ILogger logger) { _httpContextAccessor = httpContextAccessor; _logger = logger; diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs index d215e4d032b..c7b5cb68591 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs @@ -15,7 +15,7 @@ namespace OrchardCore.Queries.Lucene.GraphQL.Queries; -public class LuceneQueryFieldTypeProvider : ISchemaBuilder +public sealed class LuceneQueryFieldTypeProvider : ISchemaBuilder { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger _logger; diff --git a/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs b/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs index 5f108547a0d..b1198136f22 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs @@ -16,7 +16,8 @@ namespace OrchardCore.Users.GraphQL; internal sealed class CurrentUserQuery : ISchemaBuilder { private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IStringLocalizer S; + + internal readonly IStringLocalizer S; public CurrentUserQuery( IHttpContextAccessor httpContextAccessor, @@ -50,6 +51,7 @@ public Task BuildAsync(ISchema schema) public Task GetIdentifierAsync() { var contentDefinitionManager = _httpContextAccessor.HttpContext.RequestServices.GetRequiredService(); + return contentDefinitionManager.GetIdentifierAsync(); } } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLFieldNameAttribute.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLFieldNameAttribute.cs index ce557684395..5c457989358 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLFieldNameAttribute.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLFieldNameAttribute.cs @@ -10,5 +10,6 @@ public GraphQLFieldNameAttribute(string field, string mapped) } public string Field { get; } + public string Mapped { get; } } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLSettings.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLSettings.cs index 69313c2b434..2a48c5b0586 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLSettings.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLSettings.cs @@ -5,15 +5,21 @@ namespace OrchardCore.Apis.GraphQL; public class GraphQLSettings { public PathString Path { get; set; } = "/api/graphql"; + public Func> BuildUserContext { get; set; } public bool ExposeExceptions { get; set; } public int? MaxDepth { get; set; } + public int? MaxComplexity { get; set; } + public double? FieldImpact { get; set; } + public int DefaultNumberOfResults { get; set; } + public int MaxNumberOfResults { get; set; } + public MaxNumberOfResultsValidationMode MaxNumberOfResultsValidationMode { get; set; } } @@ -21,5 +27,5 @@ public enum MaxNumberOfResultsValidationMode { Default, Enabled, - Disabled + Disabled, } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLUserContext.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLUserContext.cs index 4816a009504..41e297c5e47 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLUserContext.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/GraphQLUserContext.cs @@ -5,5 +5,6 @@ namespace OrchardCore.Apis.GraphQL; public class GraphQLUserContext : Dictionary { public ClaimsPrincipal User { get; set; } + public SemaphoreSlim ExecutionContextLock { get; } = new SemaphoreSlim(1, 1); } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemFilters.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemFilters.cs index 7a5c3fef8a8..3308fb41b8f 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemFilters.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemFilters.cs @@ -11,13 +11,14 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries; -public class ContentItemFilters : GraphQLFilter +public sealed class ContentItemFilters : GraphQLFilter { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IContentDefinitionManager _contentDefinitionManager; private readonly IAuthorizationService _authorizationService; - public ContentItemFilters(IHttpContextAccessor httpContextAccessor, + public ContentItemFilters( + IHttpContextAccessor httpContextAccessor, IContentDefinitionManager contentDefinitionManager, IAuthorizationService authorizationService) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs index c583e5ae436..19f8203cbd5 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs @@ -9,11 +9,11 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries; -public class ContentItemQuery : ISchemaBuilder +public sealed class ContentItemQuery : ISchemaBuilder { private readonly IHttpContextAccessor _httpContextAccessor; - protected readonly IStringLocalizer S; + internal readonly IStringLocalizer S; public ContentItemQuery(IHttpContextAccessor httpContextAccessor, IStringLocalizer localizer) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs index bcacfadd474..f99d9125630 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs @@ -14,13 +14,13 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries; /// /// Registers all Content Types as queries. /// -public class ContentTypeQuery : ISchemaBuilder +public sealed class ContentTypeQuery : ISchemaBuilder { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IOptions _contentOptionsAccessor; private readonly IOptions _settingsAccessor; - protected readonly IStringLocalizer S; + internal readonly IStringLocalizer S; public ContentTypeQuery(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs index 9c24cadc0f4..de831b8fa23 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs @@ -2,7 +2,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries; -public class PublicationStatusGraphType : EnumerationGraphType +public sealed class PublicationStatusGraphType : EnumerationGraphType { public PublicationStatusGraphType() { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs index 1cbd102f448..f5fc4ccfd20 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs @@ -4,7 +4,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; -public class ContentItemInterface : InterfaceGraphType +public sealed class ContentItemInterface : InterfaceGraphType { private readonly GraphQLContentOptions _options; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs index 79326ee323c..e61cd619e24 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs @@ -2,7 +2,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; -public class ContentItemOrderByInput : InputObjectGraphType +public sealed class ContentItemOrderByInput : InputObjectGraphType { public ContentItemOrderByInput(string contentItemName) { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs index 0759739590a..93e72619446 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs @@ -12,7 +12,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; -public class ContentItemType : ObjectGraphType +public sealed class ContentItemType : ObjectGraphType { private readonly GraphQLContentOptions _options; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemWhereInput.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemWhereInput.cs index 8cb51e3026a..e3015d46d7d 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemWhereInput.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemWhereInput.cs @@ -9,7 +9,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; [GraphQLFieldName("Or", "OR")] [GraphQLFieldName("And", "AND")] [GraphQLFieldName("Not", "NOT")] -public class ContentItemWhereInput : WhereInputObjectGraphType +public sealed class ContentItemWhereInput : WhereInputObjectGraphType { private readonly IOptions _optionsAccessor; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs index 4ca0fcdd83e..9b109a4d622 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentFieldsIndexAliasProvider.cs @@ -7,7 +7,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; -public class DynamicContentFieldsIndexAliasProvider : IIndexAliasProvider, IContentDefinitionEventHandler +public sealed class DynamicContentFieldsIndexAliasProvider : IIndexAliasProvider, IContentDefinitionEventHandler { private static readonly string _cacheKey = nameof(DynamicContentFieldsIndexAliasProvider); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index 6bee71820a6..eea40af6d93 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -14,6 +14,7 @@ public abstract class DynamicContentTypeBuilder : IContentTypeBuilder { protected readonly IHttpContextAccessor _httpContextAccessor; protected readonly GraphQLContentOptions _contentOptions; + protected readonly IStringLocalizer S; private readonly Dictionary _dynamicPartFields; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs index fa45133c246..6745d84e075 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeQueryBuilder.cs @@ -7,7 +7,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; -public class DynamicContentTypeQueryBuilder : DynamicContentTypeBuilder +public sealed class DynamicContentTypeQueryBuilder : DynamicContentTypeBuilder { public DynamicContentTypeQueryBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs index ff1836b04ce..c2fa5081c66 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeWhereInputBuilder.cs @@ -7,9 +7,10 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; -public class DynamicContentTypeWhereInputBuilder : DynamicContentTypeBuilder +public sealed class DynamicContentTypeWhereInputBuilder : DynamicContentTypeBuilder { - public DynamicContentTypeWhereInputBuilder(IHttpContextAccessor httpContextAccessor, + public DynamicContentTypeWhereInputBuilder( + IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor, IStringLocalizer localizer) : base(httpContextAccessor, contentOptionsAccessor, localizer) { } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/FieldTypeIndexDescriptor.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/FieldTypeIndexDescriptor.cs new file mode 100644 index 00000000000..fdca6d51baa --- /dev/null +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/FieldTypeIndexDescriptor.cs @@ -0,0 +1,8 @@ +namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; + +public sealed class FieldTypeIndexDescriptor +{ + public required string Index { get; set; } + + public required Type IndexType { get; set; } +} diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs index a1f0bc2fea1..1f691702c9e 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/IContentFieldProvider.cs @@ -13,9 +13,3 @@ public interface IContentFieldProvider bool HasFieldIndex(ContentPartFieldDefinition field); } - -public sealed class FieldTypeIndexDescriptor -{ - public required string Index { get; set; } - public required Type IndexType { get; set; } -} diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 160bb52d1e1..9ee8bc39c3f 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -9,7 +9,7 @@ namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; -public class TypedContentTypeBuilder : IContentTypeBuilder +public sealed class TypedContentTypeBuilder : IContentTypeBuilder { private readonly IHttpContextAccessor _httpContextAccessor; private readonly GraphQLContentOptions _contentOptions; diff --git a/src/docs/releases/3.0.0.md b/src/docs/releases/3.0.0.md new file mode 100644 index 00000000000..0718c3c0d1e --- /dev/null +++ b/src/docs/releases/3.0.0.md @@ -0,0 +1,25 @@ +# Orchard Core 3.0.0 + +Release date: Not yet released + +## Breaking Changes + +### GraphQL Module + +#### GraphQL Library Upgrade + +The `GraphQL` libraries have been upgraded from version 7 to version 8. Below are important changes and considerations for your implementation: + +1. **Removal of Default Implementation**: + The `IContentTypeBuilder` interface previously included a default implementation for the `Clear()` method. This implementation has been removed. If you have a custom implementation of `IContentTypeBuilder`, you must now provide your own `Clear()` method. The method can remain empty if no specific actions are needed. + +2. **Sealed Classes**: + Several classes have been marked as sealed to prevent further inheritance. This change is intended to enhance stability and maintainability. The following classes are now sealed: + + - All implementations of `InputObjectGraphType` + - All implementations of `ObjectGraphType<>` + - All implementations of `WhereInputObjectGraphType` + - All implementations of `DynamicContentTypeBuilder` + - All implementations of `IContentTypeBuilder` + - All implementations of `GraphQLFilter` + - All implementations of `ISchemaBuilder` From b37c1c4df1ca44548e3bcbd7183f0926d71efc34 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 09:30:36 -0800 Subject: [PATCH 15/22] finalize --- .../Queries/ContentItemsFieldType.cs | 1 - .../Types/DynamicContentTypeBuilder.cs | 2 +- .../Queries/Types/DynamicPartGraphType.cs | 30 ++++++------------- .../Queries/Types/TypedContentTypeBuilder.cs | 1 - .../GraphQL/UserType.cs | 24 ++++++++++----- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index 678c2508e6c..850c09bdd92 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -40,7 +40,6 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions); - // ResolvedType = new ContentItemType(optionsAccessor); var whereInput = new ContentItemWhereInput(contentItemName, optionsAccessor); var orderByInput = new ContentItemOrderByInput(contentItemName); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index eea40af6d93..b5318838856 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -186,7 +186,7 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe Name = partFieldName, Description = S["Represents a {0}.", part.PartDefinition.Name], Type = typeof(DynamicPartGraphType), - ResolvedType = new DynamicPartGraphType(part), + ResolvedType = new DynamicPartGraphType(part, schema, contentFieldProviders), Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index 0a0c3cf78d1..a5862d75560 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -1,41 +1,29 @@ using GraphQL.Types; -using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement.Metadata.Models; namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public sealed class DynamicPartGraphType : ObjectGraphType { - private readonly ContentTypePartDefinition _part; - public DynamicPartGraphType( - ContentTypePartDefinition part) + ContentTypePartDefinition part, + ISchema schema, + IEnumerable contentFieldProviders) { Name = part.Name; - _part = part; - } - public override void Initialize(ISchema schema) - { - if (schema is IServiceProvider serviceProvider) + foreach (var field in part.PartDefinition.Fields) { - var contentFieldProviders = serviceProvider.GetServices(); - - foreach (var field in _part.PartDefinition.Fields) + foreach (var fieldProvider in contentFieldProviders) { - foreach (var fieldProvider in contentFieldProviders) + var fieldType = fieldProvider.GetField(schema, field, part.Name); + if (fieldType != null) { - var fieldType = fieldProvider.GetField(schema, field, _part.Name); - if (fieldType != null) - { - AddField(fieldType); + AddField(fieldType); - break; - } + break; } } } - - base.Initialize(schema); } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 9ee8bc39c3f..0ee612716ba 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -71,7 +71,6 @@ public void Build(ISchema schema, FieldType contentQuery, ContentTypeDefinition { Name = field.Name, Type = field.Type, - // ResolvedType = instance.CreateInstance(), Description = field.Description, DeprecationReason = field.DeprecationReason, Arguments = field.Arguments, diff --git a/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs b/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs index 981e5fb0c56..ab0e672d154 100644 --- a/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs +++ b/src/OrchardCore/OrchardCore.Users.Core/GraphQL/UserType.cs @@ -6,9 +6,9 @@ namespace OrchardCore.Users.GraphQL; -public class UserType : ObjectGraphType +public sealed class UserType : ObjectGraphType { - protected readonly IStringLocalizer S; + internal readonly IStringLocalizer S; public UserType(IStringLocalizer localizer) { @@ -17,17 +17,27 @@ public UserType(IStringLocalizer localizer) Name = "User"; Description = S["Represents a user."]; - Field(u => u.UserId).Description(S["The id of the user."]); - Field(u => u.UserName).Description(S["The name of the user."]); - Field(u => u.Email, nullable: true).Description(S["The email of the user."]); - Field(u => u.PhoneNumber, nullable: true).Description(S["The phone number of the user."]); + Field(u => u.UserId) + .Description(S["The id of the user."]); + + Field(u => u.UserName) + .Description(S["The name of the user."]); + + Field(u => u.Email, nullable: true) + .Description(S["The email of the user."]); + + Field(u => u.PhoneNumber, nullable: true) + .Description(S["The phone number of the user."]); } public override void Initialize(ISchema schema) { // Add custom user settings by reusing previously registered content types with the // stereotype "CustomUserSettings". - foreach (var contentItemType in schema.AdditionalTypeInstances.Where(t => t.Metadata.TryGetValue("Stereotype", out var stereotype) && stereotype as string == "CustomUserSettings")) + var contentItemTypes = schema.AdditionalTypeInstances + .Where(t => t.Metadata.TryGetValue("Stereotype", out var stereotype) && (stereotype as string) == "CustomUserSettings"); + + foreach (var contentItemType in contentItemTypes) { Field(contentItemType.Name, contentItemType) .Description(S["Custom user settings of {0}.", contentItemType.Name]) From ad5e58c3d9e42229c9edda4b2935b4c0eedd9af1 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 09:35:13 -0800 Subject: [PATCH 16/22] fix build --- .../OrchardCore.Media/GraphQL/MediaAssetQuery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs index 12a6ba384cb..4bd5fdc9b7a 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs @@ -14,7 +14,7 @@ public sealed class MediaAssetQuery : ISchemaBuilder { private readonly GraphQLContentOptions _graphQLContentOptions; - protected internal IStringLocalizer S; + internal IStringLocalizer S; public MediaAssetQuery( IStringLocalizer localizer, From 185f8ada34177667bfb66a2ed3c034385e82dda4 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 10:40:44 -0800 Subject: [PATCH 17/22] Fix tests --- .../GraphQL/Fields/ContentFieldsProvider.cs | 21 ++---------- .../GraphQL/Fields/FieldTypeDescriptor.cs | 24 ++++++++++++++ .../Queries/IFilterInputObjectGraphType.cs | 10 ++++++ .../Queries/WhereInputObjectGraphType.cs | 7 ---- .../Options/GraphQLContentOptions.cs | 2 +- .../Types/DynamicContentTypeBuilder.cs | 4 +-- .../Queries/Types/DynamicPartGraphType.cs | 32 ++++++++++++------- 7 files changed, 60 insertions(+), 40 deletions(-) create mode 100644 src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs create mode 100644 src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/IFilterInputObjectGraphType.cs diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index fda1a866837..a6f96a1dc6a 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -10,7 +10,7 @@ namespace OrchardCore.ContentFields.GraphQL.Fields; -public class ContentFieldsProvider : IContentFieldProvider +public partial class ContentFieldsProvider : IContentFieldProvider { private static readonly FrozenDictionary _contentFieldTypeMappings = new Dictionary() { @@ -114,7 +114,7 @@ public FieldType GetField(ISchema schema, ContentPartFieldDefinition field, stri return new FieldType { - Name = customFieldName ?? field.Name, + Name = customFieldName ?? schema.NameConverter.NameForField(field.Name, null), Description = fieldDescriptor.Description, Type = fieldDescriptor.FieldType, ResolvedType = fieldDescriptor.ResolvedType, @@ -158,21 +158,4 @@ public bool HasFieldIndex(ContentPartFieldDefinition field) => _contentFieldTypeMappings.TryGetValue(field.FieldDefinition.Name, out var fieldTypeDescriptor) && fieldTypeDescriptor.IndexType != null && !string.IsNullOrWhiteSpace(fieldTypeDescriptor.Index); - - private sealed class FieldTypeDescriptor - { - public string Description { get; set; } - - public Type FieldType { get; set; } - - public Type UnderlyingType { get; set; } - - public required IGraphType ResolvedType { get; set; } - - public Func FieldAccessor { get; set; } - - public string Index { get; set; } - - public Type IndexType { get; set; } - } } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs new file mode 100644 index 00000000000..3b4bd5e9e60 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs @@ -0,0 +1,24 @@ +using GraphQL.Types; +using OrchardCore.ContentManagement; + +namespace OrchardCore.ContentFields.GraphQL.Fields; + +public partial class ContentFieldsProvider +{ + internal sealed class FieldTypeDescriptor + { + public string Description { get; set; } + + public Type FieldType { get; set; } + + public Type UnderlyingType { get; set; } + + public required IGraphType ResolvedType { get; set; } + + public Func FieldAccessor { get; set; } + + public string Index { get; set; } + + public Type IndexType { get; set; } + } +} diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/IFilterInputObjectGraphType.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/IFilterInputObjectGraphType.cs new file mode 100644 index 00000000000..6e5b8a39b5d --- /dev/null +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/IFilterInputObjectGraphType.cs @@ -0,0 +1,10 @@ +using GraphQL.Types; + +namespace OrchardCore.Apis.GraphQL.Queries; + +public interface IFilterInputObjectGraphType : IInputObjectGraphType +{ + void AddScalarFilterFields(string fieldName, string description); + + void AddScalarFilterFields(Type graphType, string fieldName, string description); +} diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs index fea6daffd67..45c1fb45a49 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs @@ -3,13 +3,6 @@ namespace OrchardCore.Apis.GraphQL.Queries; -public interface IFilterInputObjectGraphType : IInputObjectGraphType -{ - void AddScalarFilterFields(string fieldName, string description); - - void AddScalarFilterFields(Type graphType, string fieldName, string description); -} - public class WhereInputObjectGraphType : WhereInputObjectGraphType, IFilterInputObjectGraphType { } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs index 420676967fc..961836ad20f 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Options/GraphQLContentOptions.cs @@ -157,7 +157,7 @@ public bool IsHiddenByDefault(string contentType) { ArgumentException.ThrowIfNullOrEmpty(contentType); - var contentTypeOption = ContentTypeOptions.FirstOrDefault(ctp => ctp.ContentType == contentType); + var contentTypeOption = ContentTypeOptions.FirstOrDefault(ctp => ctp.ContentType.Equals(contentType, StringComparison.OrdinalIgnoreCase)); return contentTypeOption?.Hidden ?? false; } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index b5318838856..72529c27741 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -186,14 +186,14 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe Name = partFieldName, Description = S["Represents a {0}.", part.PartDefinition.Name], Type = typeof(DynamicPartGraphType), - ResolvedType = new DynamicPartGraphType(part, schema, contentFieldProviders), + ResolvedType = new DynamicPartGraphType(part), Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; var typeToResolve = context.FieldDefinition.ResolvedType.GetType().BaseType.GetGenericArguments().First(); return context.Source.Get(typeToResolve, nameToResolve); - }) + }), }; objectGraphType.AddField(field); diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index a5862d75560..faa7e0e6569 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -1,29 +1,39 @@ using GraphQL.Types; +using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement.Metadata.Models; namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public sealed class DynamicPartGraphType : ObjectGraphType { - public DynamicPartGraphType( - ContentTypePartDefinition part, - ISchema schema, - IEnumerable contentFieldProviders) + private readonly ContentTypePartDefinition _part; + + public DynamicPartGraphType(ContentTypePartDefinition part) { Name = part.Name; + _part = part; + } - foreach (var field in part.PartDefinition.Fields) + public override void Initialize(ISchema schema) + { + if (schema is IServiceProvider serviceProvider) { - foreach (var fieldProvider in contentFieldProviders) + var contentFieldProviders = serviceProvider.GetServices().ToList(); + + foreach (var field in _part.PartDefinition.Fields) { - var fieldType = fieldProvider.GetField(schema, field, part.Name); - if (fieldType != null) + foreach (var fieldProvider in contentFieldProviders) { - AddField(fieldType); - - break; + var fieldType = fieldProvider.GetField(schema, field, _part.Name); + if (fieldType != null) + { + AddField(fieldType); + break; + } } } } + + base.Initialize(schema); } } From 06e70fd12e985b2c3920d8c8f503a6337aad317a Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 10:44:02 -0800 Subject: [PATCH 18/22] don't use partial --- .../GraphQL/Fields/ContentFieldsProvider.cs | 2 +- .../GraphQL/Fields/FieldTypeDescriptor.cs | 21 ++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index a6f96a1dc6a..f4426b0b13f 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -10,7 +10,7 @@ namespace OrchardCore.ContentFields.GraphQL.Fields; -public partial class ContentFieldsProvider : IContentFieldProvider +public class ContentFieldsProvider : IContentFieldProvider { private static readonly FrozenDictionary _contentFieldTypeMappings = new Dictionary() { diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs index 3b4bd5e9e60..493b9fa7ea2 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs @@ -1,24 +1,21 @@ -using GraphQL.Types; +using GraphQL.Types; using OrchardCore.ContentManagement; namespace OrchardCore.ContentFields.GraphQL.Fields; -public partial class ContentFieldsProvider +internal sealed class FieldTypeDescriptor { - internal sealed class FieldTypeDescriptor - { - public string Description { get; set; } + public string Description { get; set; } - public Type FieldType { get; set; } + public Type FieldType { get; set; } - public Type UnderlyingType { get; set; } + public Type UnderlyingType { get; set; } - public required IGraphType ResolvedType { get; set; } + public required IGraphType ResolvedType { get; set; } - public Func FieldAccessor { get; set; } + public Func FieldAccessor { get; set; } - public string Index { get; set; } + public string Index { get; set; } - public Type IndexType { get; set; } - } + public Type IndexType { get; set; } } From 744fb91e282cd1ba6c16f57cfd496b4a28a8c0cd Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 11:18:36 -0800 Subject: [PATCH 19/22] Use latest packages --- Directory.Packages.props | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d01bfe6f082..92a42970662 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -25,10 +25,10 @@ - - - - + + + + @@ -87,7 +87,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -139,14 +139,14 @@ - + - + - + @@ -174,7 +174,7 @@ - + From f00f520d546e2089ee2c822c9bf577cf2b50cf22 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 21 Nov 2024 12:18:43 -0800 Subject: [PATCH 20/22] Fix warning --- .../GraphQL/Fields/ContentFieldsProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index f4426b0b13f..19e70683f44 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -98,7 +98,7 @@ public class ContentFieldsProvider : IContentFieldProvider { Description = "Multi text field", FieldType = typeof(ListGraphType), - ResolvedType = new ListGraphType(), + ResolvedType = new ListGraphType(new StringGraphType()), UnderlyingType = typeof(MultiTextField), FieldAccessor = field => ((MultiTextField)field).Values, } From 2e25e4aed6d3be1aef4db6089a785966f2211627 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Fri, 22 Nov 2024 09:35:59 -0800 Subject: [PATCH 21/22] address feedback --- .../Services/SchemaService.cs | 6 ++-- .../GraphQL/Fields/ContentFieldsProvider.cs | 17 ++++++++++ .../GraphQL/Fields/FieldTypeDescriptor.cs | 21 ------------- .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 2 -- .../Queries/WhereInputObjectGraphType.cs | 10 +++--- .../Types/DynamicContentTypeBuilder.cs | 2 +- .../Queries/Types/DynamicPartGraphType.cs | 31 ++++++------------- 7 files changed, 35 insertions(+), 54 deletions(-) delete mode 100644 src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index cd4c82e3333..bc13d9055f5 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -98,17 +98,17 @@ public async Task GetSchemaAsync() // Clean Query, Mutation and Subscription if they have no fields // to prevent GraphQL configuration errors. - if (schema.Query?.Fields is null || schema.Query.Fields.Count == 0) + if (schema.Query.Fields.Count == 0) { schema.Query = null; } - if (schema.Mutation?.Fields is null || schema.Mutation.Fields.Count == 0) + if (schema.Mutation.Fields.Count == 0) { schema.Mutation = null; } - if (schema.Subscription?.Fields is null || schema.Subscription.Fields.Count == 0) + if (schema.Subscription.Fields.Count == 0) { schema.Subscription = null; } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index 19e70683f44..6954860e83b 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -158,4 +158,21 @@ public bool HasFieldIndex(ContentPartFieldDefinition field) => _contentFieldTypeMappings.TryGetValue(field.FieldDefinition.Name, out var fieldTypeDescriptor) && fieldTypeDescriptor.IndexType != null && !string.IsNullOrWhiteSpace(fieldTypeDescriptor.Index); + + private sealed class FieldTypeDescriptor + { + public string Description { get; set; } + + public Type FieldType { get; set; } + + public Type UnderlyingType { get; set; } + + public required IGraphType ResolvedType { get; set; } + + public Func FieldAccessor { get; set; } + + public string Index { get; set; } + + public Type IndexType { get; set; } + } } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs deleted file mode 100644 index 493b9fa7ea2..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/FieldTypeDescriptor.cs +++ /dev/null @@ -1,21 +0,0 @@ -using GraphQL.Types; -using OrchardCore.ContentManagement; - -namespace OrchardCore.ContentFields.GraphQL.Fields; - -internal sealed class FieldTypeDescriptor -{ - public string Description { get; set; } - - public Type FieldType { get; set; } - - public Type UnderlyingType { get; set; } - - public required IGraphType ResolvedType { get; set; } - - public Func FieldAccessor { get; set; } - - public string Index { get; set; } - - public Type IndexType { get; set; } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index 99abce9600a..98d9893d656 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -117,7 +117,6 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc Name = nameLower, Description = description, Type = typeof(StringGraphType), - ResolvedType = new StringGraphType(), Resolver = new FuncFieldResolver(context => { var source = context.Source; @@ -133,7 +132,6 @@ private static FieldType BuildSchemaBasedFieldType(Query query, JsonNode querySc { Name = nameLower, Type = typeof(IntGraphType), - ResolvedType = new IntGraphType(), Description = description, Resolver = new FuncFieldResolver(context => { diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs index 45c1fb45a49..2778dde9b9c 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs @@ -87,27 +87,26 @@ public virtual void AddScalarFilterFields(Type graphType, string fieldName, stri private void AddEqualityFilters(Type graphType, string fieldName, string description) { - AddFilterFields(graphType, CreateGraphType(graphType), EqualityOperators, fieldName, description); + AddFilterFields(CreateGraphType(graphType), EqualityOperators, fieldName, description); } private void AddStringFilters(Type graphType, string fieldName, string description) { - AddFilterFields(graphType, CreateGraphType(graphType), StringComparisonOperators, fieldName, description); + AddFilterFields(CreateGraphType(graphType), StringComparisonOperators, fieldName, description); } private void AddNonStringFilters(Type graphType, string fieldName, string description) { - AddFilterFields(graphType, CreateGraphType(graphType), NonStringValueComparisonOperators, fieldName, description); + AddFilterFields(CreateGraphType(graphType), NonStringValueComparisonOperators, fieldName, description); } private void AddMultiValueFilters(Type graphType, string fieldName, string description) { var wrappedType = typeof(ListGraphType<>).MakeGenericType(graphType); - AddFilterFields(wrappedType, CreateGraphType(graphType), MultiValueComparisonOperators, fieldName, description); + AddFilterFields(CreateGraphType(graphType), MultiValueComparisonOperators, fieldName, description); } private void AddFilterFields( - Type graphType, IGraphType resolvedType, IDictionary filters, string fieldName, @@ -119,7 +118,6 @@ private void AddFilterFields( { Name = fieldName + filter.Key, Description = $"{description} {filter.Value}", - Type = graphType, ResolvedType = resolvedType, }); } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs index 72529c27741..026b8fa76e3 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicContentTypeBuilder.cs @@ -186,7 +186,7 @@ protected void BuildInternal(ISchema schema, ContentTypeDefinition contentTypeDe Name = partFieldName, Description = S["Represents a {0}.", part.PartDefinition.Name], Type = typeof(DynamicPartGraphType), - ResolvedType = new DynamicPartGraphType(part), + ResolvedType = new DynamicPartGraphType(part, schema, contentFieldProviders), Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs index faa7e0e6569..3f8d21195fe 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/DynamicPartGraphType.cs @@ -1,39 +1,28 @@ using GraphQL.Types; -using Microsoft.Extensions.DependencyInjection; using OrchardCore.ContentManagement.Metadata.Models; namespace OrchardCore.ContentManagement.GraphQL.Queries.Types; public sealed class DynamicPartGraphType : ObjectGraphType { - private readonly ContentTypePartDefinition _part; - - public DynamicPartGraphType(ContentTypePartDefinition part) + public DynamicPartGraphType( + ContentTypePartDefinition part, + ISchema schema, + IEnumerable contentFieldProviders) { Name = part.Name; - _part = part; - } - public override void Initialize(ISchema schema) - { - if (schema is IServiceProvider serviceProvider) + foreach (var field in part.PartDefinition.Fields) { - var contentFieldProviders = serviceProvider.GetServices().ToList(); - - foreach (var field in _part.PartDefinition.Fields) + foreach (var fieldProvider in contentFieldProviders) { - foreach (var fieldProvider in contentFieldProviders) + var fieldType = fieldProvider.GetField(schema, field, part.Name); + if (fieldType != null) { - var fieldType = fieldProvider.GetField(schema, field, _part.Name); - if (fieldType != null) - { - AddField(fieldType); - break; - } + AddField(fieldType); + break; } } } - - base.Initialize(schema); } } From 38c538ccb6d956040778fac9805c20351f2d6f22 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Fri, 22 Nov 2024 09:52:16 -0800 Subject: [PATCH 22/22] fix warning --- .../Queries/WhereInputObjectGraphType.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs index 2778dde9b9c..c084f6af265 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Queries/WhereInputObjectGraphType.cs @@ -102,7 +102,6 @@ private void AddNonStringFilters(Type graphType, string fieldName, string descri private void AddMultiValueFilters(Type graphType, string fieldName, string description) { - var wrappedType = typeof(ListGraphType<>).MakeGenericType(graphType); AddFilterFields(CreateGraphType(graphType), MultiValueComparisonOperators, fieldName, description); }