diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index e75fd9c84a4..449bed64b21 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using GraphQL.Resolvers; @@ -108,11 +109,14 @@ private async Task> FilterWhereArguments( // Add all provided table alias to the current predicate query var providers = context.ServiceProvider.GetServices(); var indexes = new Dictionary(StringComparer.OrdinalIgnoreCase); + var indexAliases = new List(); + foreach (var aliasProvider in providers) { foreach (var alias in aliasProvider.GetAliases()) { predicateQuery.CreateAlias(alias.Alias, alias.Index); + indexAliases.Add(alias.Alias); if (!indexes.ContainsKey(alias.Index)) { @@ -122,7 +126,7 @@ private async Task> FilterWhereArguments( } var expressions = Expression.Conjunction(); - BuildWhereExpressions(where, expressions, null, indexes); + BuildWhereExpressions(where, expressions, null, indexAliases); var whereSqlClause = expressions.ToSqlString(predicateQuery); query = query.Where(whereSqlClause); @@ -202,7 +206,7 @@ private static IQuery FilterVersion(IQuery indexes) + private void BuildWhereExpressions(JToken where, Junction expressions, string tableAlias, IEnumerable indexAliases) { if (where is JArray array) { @@ -210,17 +214,17 @@ private void BuildWhereExpressions(JToken where, Junction expressions, string ta { if (child is JObject whereObject) { - BuildExpressionsInternal(whereObject, expressions, tableAlias, indexes); + BuildExpressionsInternal(whereObject, expressions, tableAlias, indexAliases); } } } else if (where is JObject whereObject) { - BuildExpressionsInternal(whereObject, expressions, tableAlias, indexes); + BuildExpressionsInternal(whereObject, expressions, tableAlias, indexAliases); } } - private void BuildExpressionsInternal(JObject where, Junction expressions, string tableAlias, Dictionary indexes) + private void BuildExpressionsInternal(JObject where, Junction expressions, string tableAlias, IEnumerable indexAliases) { foreach (var entry in where.Properties()) { @@ -232,10 +236,14 @@ private void BuildExpressionsInternal(JObject where, Junction expressions, strin var property = values[0]; if (!string.IsNullOrEmpty(tableAlias)) { - // check if we need to stick a prefix of 'Part' on the alias. - if (indexes != null && indexes.TryGetValue($"{tableAlias}PartIndex", out var indexAlias)) - { - tableAlias = indexAlias.Alias; + // check if we need to stick a suffix of 'Part' on the alias. + if (!tableAlias.EndsWith("Part")) { + + var aliasLookup = indexAliases.FirstOrDefault(x => x.Equals($"{tableAlias}Part", StringComparison.OrdinalIgnoreCase)); + if (aliasLookup != null) + { + tableAlias = aliasLookup; + } } property = $"{tableAlias}.{property}"; @@ -246,24 +254,24 @@ private void BuildExpressionsInternal(JObject where, Junction expressions, strin if (string.Equals(values[0], "or", StringComparison.OrdinalIgnoreCase)) { expression = Expression.Disjunction(); - BuildWhereExpressions(entry.Value, (Junction)expression, tableAlias, indexes); + BuildWhereExpressions(entry.Value, (Junction)expression, tableAlias, indexAliases); } else if (string.Equals(values[0], "and", StringComparison.OrdinalIgnoreCase)) { expression = Expression.Conjunction(); - BuildWhereExpressions(entry.Value, (Junction)expression, tableAlias, indexes); + BuildWhereExpressions(entry.Value, (Junction)expression, tableAlias, indexAliases); } else if (string.Equals(values[0], "not", StringComparison.OrdinalIgnoreCase)) { expression = Expression.Conjunction(); - BuildWhereExpressions(entry.Value, (Junction)expression, tableAlias, indexes); + BuildWhereExpressions(entry.Value, (Junction)expression, tableAlias, indexAliases); expression = Expression.Not(expression); } else if (entry.HasValues && entry.Value.Type == JTokenType.Object) { // Loop through the part's properties, passing the name of the part as the table tableAlias. // This tableAlias can then be used with the table alias to index mappings to join with the correct table. - BuildWhereExpressions(entry.Value, expressions, values[0], indexes); + BuildWhereExpressions(entry.Value, expressions, values[0], indexAliases); } else { diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs index 8d4c671b2a9..af37ebabff0 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs @@ -185,6 +185,50 @@ public async Task ShouldFilterOnMultipleIndexesOnSameAlias() Assert.False(animals.First().As().IsHappy); } } + + [Fact] + public async Task ShouldFilterPartsWithoutAPrefixWhenThePartHasNoPrefix() + { + _store.RegisterIndexes(); + + using (var services = new FakeServiceCollection()) + { + services.Populate(new ServiceCollection()); + services.Services.AddScoped(x => _store.CreateSession()); + services.Services.AddScoped(); + services.Services.AddScoped(); + services.Services.AddScoped(); + services.Build(); + + var retrunType = new ListGraphType(); + retrunType.ResolvedType = new StringGraphType() { Name = "Animal" }; + + var context = new ResolveFieldContext + { + Arguments = new Dictionary(), + UserContext = new GraphQLContext + { + ServiceProvider = services + }, + ReturnType = retrunType + }; + + var ci = new ContentItem { ContentType = "Animal", Published = true, ContentItemId = "1", ContentItemVersionId = "1" }; + ci.Weld(new AnimalPart { Name = "doug" }); + + var session = ((GraphQLContext)context.UserContext).ServiceProvider.GetService(); + session.Save(ci); + await session.CommitAsync(); + + var type = new ContentItemsFieldType("Animal", new Schema()); + + context.Arguments["where"] = JObject.Parse("{ animal: { name: \"doug\" } }"); + var dogs = await ((AsyncFieldResolver>)type.Resolver).Resolve(context); + + Assert.Single(dogs); + Assert.Equal("doug", dogs.First().As().Name); + } + } } public class Animal : ContentPart @@ -194,6 +238,8 @@ public class Animal : ContentPart public bool IsScary { get; set; } } + public class AnimalPart : Animal { }; + public class AnimalIndex : MapIndex { public string Name { get; set; } @@ -208,7 +254,9 @@ public override void Describe(DescribeContext context) { return new AnimalIndex { - Name = contentItem.As().Name + Name = contentItem.As() != null ? + contentItem.As().Name + : contentItem.As().Name }; }); } @@ -227,10 +275,23 @@ public override void Describe(DescribeContext context) context.For() .Map(contentItem => { + var animal = contentItem.As(); + + if (animal != null) + { + return new AnimalTraitsIndex + { + IsHappy = contentItem.As().IsHappy, + IsScary = contentItem.As().IsScary + }; + } + + var animalPartSuffix = contentItem.As(); + return new AnimalTraitsIndex { - IsHappy = contentItem.As().IsHappy, - IsScary = contentItem.As().IsScary + IsHappy = animalPartSuffix.IsHappy, + IsScary = animalPartSuffix.IsScary }; }); } @@ -252,6 +313,12 @@ public class MultipleAliasIndexProvider : IIndexAliasProvider Alias = "dogs", Index = nameof(AnimalIndex), With = q => q.With() + }, + new IndexAlias + { + Alias = nameof(AnimalPart), + Index = nameof(AnimalIndex), + With = q => q.With() } };