Browse Source

More optimizations.

pull/378/head
Sebastian 7 years ago
parent
commit
af6c3808a9
  1. 7
      src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs
  2. 9
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs
  3. 59
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
  4. 9
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs
  5. 4
      src/Squidex.Domain.Apps.Entities/Contents/QueryExecutionContext.cs
  6. 5
      src/Squidex.Domain.Apps.Entities/Q.cs
  7. 48
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs

7
src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs

@ -119,12 +119,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{
var find = Collection.Find(x => ids.Contains(x.Id)).SortByDescending(x => x.LastModified);
var assetItems = find.ToListAsync();
var assetCount = find.CountDocumentsAsync();
var assetItems = await find.ToListAsync();
await Task.WhenAll(assetItems, assetCount);
return ResultList.Create(assetCount.Result, assetItems.Result.OfType<IAssetEntity>());
return ResultList.Create(assetItems.Count, assetItems.OfType<IAssetEntity>());
}
}

9
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs

@ -137,17 +137,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
{
var find = Collection.Find(FilterFactory.IdsBySchema(schema.Id, ids, status));
var contentItems = find.WithoutDraft(includeDraft).ToListAsync();
var contentCount = find.CountDocumentsAsync();
await Task.WhenAll(contentItems, contentCount);
var contentItems = await find.WithoutDraft(includeDraft).ToListAsync();
foreach (var entity in contentItems.Result)
foreach (var entity in contentItems)
{
entity.ParseData(schema.SchemaDef, serializer);
}
return ResultList.Create<IContentEntity>(contentCount.Result, contentItems.Result);
return ResultList.Create<IContentEntity>(contentItems.Count, contentItems);
}
public async Task<IContentEntity> FindContentAsync(ISchemaEntity schema, Guid id, Status[] status, bool includeDraft)

59
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs

@ -12,6 +12,7 @@ using System.Threading.Tasks;
using GraphQL;
using GraphQL.DataLoader;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Log;
@ -52,6 +53,20 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
execution.UserContext = this;
}
public override Task<IAssetEntity> FindAssetAsync(Guid id)
{
var dataLoader = GetAssetsLoader();
return dataLoader.LoadAsync(id);
}
public override Task<IContentEntity> FindContentAsync(Guid schemaId, Guid id)
{
var dataLoader = GetContentsLoader(schemaId);
return dataLoader.LoadAsync(id);
}
public async Task<IReadOnlyList<IAssetEntity>> GetReferencedAssetsAsync(IJsonValue value)
{
var ids = ParseIds(value);
@ -61,18 +76,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
return EmptyAssets;
}
var dataLoader =
dataLoaderContextAccessor.Context.GetOrAddBatchLoader<Guid, IAssetEntity>("Assets",
async batch =>
{
var result = await GetReferencedAssetsAsync(new List<Guid>(batch));
return result.ToDictionary(x => x.Id);
});
var dataLoader = GetAssetsLoader();
var assets = await Task.WhenAll(ids.Select(x => dataLoader.LoadAsync(x)));
return assets.Where(x => x != null).ToList();
return await dataLoader.LoadManyAsync(ids);
}
public async Task<IReadOnlyList<IContentEntity>> GetReferencedContentsAsync(Guid schemaId, IJsonValue value)
@ -84,18 +90,31 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
return EmptyContents;
}
var dataLoader =
dataLoaderContextAccessor.Context.GetOrAddBatchLoader<Guid, IContentEntity>($"Schema_{schemaId}",
async batch =>
{
var result = await GetReferencedContentsAsync(schemaId, new List<Guid>(batch));
var dataLoader = GetContentsLoader(schemaId);
return await dataLoader.LoadManyAsync(ids);
}
private IDataLoader<Guid, IAssetEntity> GetAssetsLoader()
{
return dataLoaderContextAccessor.Context.GetOrAddBatchLoader<Guid, IAssetEntity>("Assets",
async batch =>
{
var result = await GetReferencedAssetsAsync(new List<Guid>(batch));
return result.ToDictionary(x => x.Id);
});
return result.ToDictionary(x => x.Id);
});
}
var contents = await Task.WhenAll(ids.Select(x => dataLoader.LoadAsync(x)));
private IDataLoader<Guid, IContentEntity> GetContentsLoader(Guid schemaId)
{
return dataLoaderContextAccessor.Context.GetOrAddBatchLoader<Guid, IContentEntity>($"Schema_{schemaId}",
async batch =>
{
var result = await GetReferencedContentsAsync(schemaId, new List<Guid>(batch));
return contents.Where(x => x != null).ToList();
return result.ToDictionary(x => x.Id);
});
}
private static ICollection<Guid> ParseIds(IJsonValue value)

9
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs

@ -7,6 +7,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GraphQL.DataLoader;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
@ -37,5 +39,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
return value;
}
public static async Task<IReadOnlyList<T>> LoadManyAsync<TKey, T>(this IDataLoader<TKey, T> dataLoader, ICollection<TKey> keys) where T : class
{
var contents = await Task.WhenAll(keys.Select(x => dataLoader.LoadAsync(x)));
return contents.Where(x => x != null).ToList();
}
}
}

4
src/Squidex.Domain.Apps.Entities/Contents/QueryExecutionContext.cs

@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
this.context = context;
}
public async Task<IAssetEntity> FindAssetAsync(Guid id)
public virtual async Task<IAssetEntity> FindAssetAsync(Guid id)
{
var asset = cachedAssets.GetOrDefault(id);
@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return asset;
}
public async Task<IContentEntity> FindContentAsync(Guid schemaId, Guid id)
public virtual async Task<IContentEntity> FindContentAsync(Guid schemaId, Guid id)
{
var content = cachedContents.GetOrDefault(id);

5
src/Squidex.Domain.Apps.Entities/Q.cs

@ -25,6 +25,11 @@ namespace Squidex.Domain.Apps.Entities
return Clone(c => c.ODataQuery = odataQuery);
}
public Q WithIds(params Guid[] ids)
{
return Clone(c => c.Ids = ids.ToList());
}
public Q WithIds(IEnumerable<Guid> ids)
{
return Clone(c => c.Ids = ids.ToList());

48
tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs

@ -212,8 +212,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", assetId.ToString());
A.CallTo(() => assetQuery.FindAssetAsync(MatchsAssetContext(), assetId))
.Returns(asset);
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), MatchId(assetId)))
.Returns(ResultList.Create(1, asset));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query });
@ -544,8 +544,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", contentId.ToString());
A.CallTo(() => contentQuery.FindContentAsync(MatchsContentContext(), schemaId.ToString(), contentId, EtagVersion.Any))
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), MatchId(contentId)))
.Returns(ResultList.Create(1, content));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query });
@ -635,8 +635,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", contentId.ToString());
A.CallTo(() => contentQuery.FindContentAsync(MatchsContentContext(), schemaId.ToString(), contentId, EtagVersion.Any))
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), MatchId(contentId)))
.Returns(ResultList.Create(1, content));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query });
@ -730,12 +730,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", contentId.ToString());
A.CallTo(() => contentQuery.FindContentAsync(MatchsContentContext(), schemaId.ToString(), contentId, EtagVersion.Any))
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), A<Q>.Ignored))
.Returns(ResultList.Create(0, contentRef));
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), MatchId(contentId)))
.Returns(ResultList.Create(1, content));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query });
var expected = new
@ -788,8 +788,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", contentId.ToString());
A.CallTo(() => contentQuery.FindContentAsync(MatchsContentContext(), schemaId.ToString(), contentId, EtagVersion.Any))
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), MatchId(contentId)))
.Returns(ResultList.Create(1, content));
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), A<Q>.Ignored))
.Returns(ResultList.Create(0, assetRef));
@ -844,10 +844,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", assetId2.ToString());
A.CallTo(() => assetQuery.FindAssetAsync(MatchsAssetContext(), assetId1))
.Returns(asset1);
A.CallTo(() => assetQuery.FindAssetAsync(MatchsAssetContext(), assetId2))
.Returns(asset2);
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), MatchId(assetId1)))
.Returns(ResultList.Create(0, asset1));
A.CallTo(() => assetQuery.QueryAsync(MatchsAssetContext(), MatchId(assetId2)))
.Returns(ResultList.Create(0, asset2));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query1 }, new GraphQLQuery { Query = query2 });
@ -902,8 +903,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", contentId.ToString());
A.CallTo(() => contentQuery.FindContentAsync(MatchsContentContext(), schemaId.ToString(), contentId, EtagVersion.Any))
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), MatchId(contentId)))
.Returns(ResultList.Create(1, content));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query });
@ -940,8 +941,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", contentId.ToString());
A.CallTo(() => contentQuery.FindContentAsync(MatchsContentContext(), schemaId.ToString(), contentId, EtagVersion.Any))
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), MatchId(contentId)))
.Returns(ResultList.Create(1, content));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query });
@ -986,8 +987,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
}".Replace("<ID>", contentId.ToString());
A.CallTo(() => contentQuery.FindContentAsync(MatchsContentContext(), schemaId.ToString(), contentId, EtagVersion.Any))
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(MatchsContentContext(), schemaId.ToString(), MatchId(contentId)))
.Returns(ResultList.Create(1, content));
var result = await sut.QueryAsync(context, new GraphQLQuery { Query = query });
@ -1005,6 +1006,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
AssertResult(expected, result);
}
private static Q MatchId(Guid contentId)
{
return A<Q>.That.Matches(x => x.Ids.Count == 1 && x.Ids[0] == contentId);
}
private QueryContext MatchsAssetContext()
{
return A<QueryContext>.That.Matches(x => x.App == app && x.User == user);

Loading…
Cancel
Save