Skip to content

Commit

Permalink
Fixes part removal in where if the index has multiple aliases (#3217)
Browse files Browse the repository at this point in the history
Tests and fixes for #3207
  • Loading branch information
carlwoodhouse authored and Jetski5822 committed Feb 20, 2019
1 parent e5de4bf commit 3f2f432
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using GraphQL.Resolvers;
Expand Down Expand Up @@ -108,11 +109,14 @@ private async Task<IQuery<ContentItem>> FilterWhereArguments(
// Add all provided table alias to the current predicate query
var providers = context.ServiceProvider.GetServices<IIndexAliasProvider>();
var indexes = new Dictionary<string, IndexAlias>(StringComparer.OrdinalIgnoreCase);
var indexAliases = new List<string>();

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))
{
Expand All @@ -122,7 +126,7 @@ private async Task<IQuery<ContentItem>> FilterWhereArguments(
}

var expressions = Expression.Conjunction();
BuildWhereExpressions(where, expressions, null, indexes);
BuildWhereExpressions(where, expressions, null, indexAliases);

var whereSqlClause = expressions.ToSqlString(predicateQuery);
query = query.Where(whereSqlClause);
Expand Down Expand Up @@ -202,25 +206,25 @@ private static IQuery<ContentItem, ContentItemIndex> FilterVersion(IQuery<Conten
return query;
}

private void BuildWhereExpressions(JToken where, Junction expressions, string tableAlias, Dictionary<string, IndexAlias> indexes)
private void BuildWhereExpressions(JToken where, Junction expressions, string tableAlias, IEnumerable<string> indexAliases)
{
if (where is JArray array)
{
foreach (var child in array.Children())
{
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<string, IndexAlias> indexes)
private void BuildExpressionsInternal(JObject where, Junction expressions, string tableAlias, IEnumerable<string> indexAliases)
{
foreach (var entry in where.Properties())
{
Expand All @@ -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}";
Expand All @@ -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
{
Expand Down
73 changes: 70 additions & 3 deletions test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,50 @@ public async Task ShouldFilterOnMultipleIndexesOnSameAlias()
Assert.False(animals.First().As<Animal>().IsHappy);
}
}

[Fact]
public async Task ShouldFilterPartsWithoutAPrefixWhenThePartHasNoPrefix()
{
_store.RegisterIndexes<AnimalIndexProvider>();

using (var services = new FakeServiceCollection())
{
services.Populate(new ServiceCollection());
services.Services.AddScoped(x => _store.CreateSession());
services.Services.AddScoped<IIndexProvider, ContentItemIndexProvider>();
services.Services.AddScoped<IIndexProvider, AnimalIndexProvider>();
services.Services.AddScoped<IIndexAliasProvider, MultipleAliasIndexProvider>();
services.Build();

var retrunType = new ListGraphType<StringGraphType>();
retrunType.ResolvedType = new StringGraphType() { Name = "Animal" };

var context = new ResolveFieldContext
{
Arguments = new Dictionary<string, object>(),
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<ISession>();
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<IEnumerable<ContentItem>>)type.Resolver).Resolve(context);

Assert.Single(dogs);
Assert.Equal("doug", dogs.First().As<AnimalPart>().Name);
}
}
}

public class Animal : ContentPart
Expand All @@ -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; }
Expand All @@ -208,7 +254,9 @@ public override void Describe(DescribeContext<ContentItem> context)
{
return new AnimalIndex
{
Name = contentItem.As<Animal>().Name
Name = contentItem.As<Animal>() != null ?
contentItem.As<Animal>().Name
: contentItem.As<AnimalPart>().Name
};
});
}
Expand All @@ -227,10 +275,23 @@ public override void Describe(DescribeContext<ContentItem> context)
context.For<AnimalTraitsIndex>()
.Map(contentItem =>
{
var animal = contentItem.As<Animal>();

if (animal != null)
{
return new AnimalTraitsIndex
{
IsHappy = contentItem.As<Animal>().IsHappy,
IsScary = contentItem.As<Animal>().IsScary
};
}

var animalPartSuffix = contentItem.As<AnimalPart>();

return new AnimalTraitsIndex
{
IsHappy = contentItem.As<Animal>().IsHappy,
IsScary = contentItem.As<Animal>().IsScary
IsHappy = animalPartSuffix.IsHappy,
IsScary = animalPartSuffix.IsScary
};
});
}
Expand All @@ -252,6 +313,12 @@ public class MultipleAliasIndexProvider : IIndexAliasProvider
Alias = "dogs",
Index = nameof(AnimalIndex),
With = q => q.With<AnimalIndex>()
},
new IndexAlias
{
Alias = nameof(AnimalPart),
Index = nameof(AnimalIndex),
With = q => q.With<AnimalIndex>()
}
};

Expand Down

0 comments on commit 3f2f432

Please sign in to comment.