Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Squidex/squidex
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianStehle committed Jun 22, 2019
2 parents b4f3a7a + fc172c8 commit 252a19e
Show file tree
Hide file tree
Showing 17 changed files with 232 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,9 @@ public async Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, HashSet<Guid
{
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>());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,14 @@ public async Task<IResultList<IContentEntity>> QueryAsync(ISchemaEntity schema,
{
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,25 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using GraphQL;
using Microsoft.Extensions.Caching.Memory;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;

namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
public sealed class CachingGraphQLService : CachingProviderBase, IGraphQLService
{
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10);
private readonly IContentQueryService contentQuery;
private readonly IGraphQLUrlGenerator urlGenerator;
private readonly ISemanticLog log;
private readonly IAssetQueryService assetQuery;
private readonly IAppProvider appProvider;

public CachingGraphQLService(
IMemoryCache cache,
IAppProvider appProvider,
IAssetQueryService assetQuery,
IContentQueryService contentQuery,
IGraphQLUrlGenerator urlGenerator,
ISemanticLog log)
private readonly IDependencyResolver resolver;

public CachingGraphQLService(IMemoryCache cache, IDependencyResolver resolver)
: base(cache)
{
Guard.NotNull(appProvider, nameof(appProvider));
Guard.NotNull(assetQuery, nameof(assetQuery));
Guard.NotNull(contentQuery, nameof(contentQuery));
Guard.NotNull(urlGenerator, nameof(urlGenerator));
Guard.NotNull(log, nameof(log));

this.appProvider = appProvider;
this.assetQuery = assetQuery;
this.contentQuery = contentQuery;
this.urlGenerator = urlGenerator;
this.log = log;
Guard.NotNull(resolver, nameof(resolver));

this.resolver = resolver;
}

public async Task<(bool HasError, object Response)> QueryAsync(QueryContext context, params GraphQLQuery[] queries)
Expand All @@ -54,7 +36,7 @@ public CachingGraphQLService(

var model = await GetModelAsync(context.App);

var ctx = new GraphQLExecutionContext(context, assetQuery, contentQuery, urlGenerator);
var ctx = new GraphQLExecutionContext(context, resolver);

var result = await Task.WhenAll(queries.Select(q => QueryInternalAsync(model, ctx, q)));

Expand All @@ -68,7 +50,7 @@ public CachingGraphQLService(

var model = await GetModelAsync(context.App);

var ctx = new GraphQLExecutionContext(context, assetQuery, contentQuery, urlGenerator);
var ctx = new GraphQLExecutionContext(context, resolver);

var result = await QueryInternalAsync(model, ctx, query);

Expand All @@ -82,7 +64,7 @@ public CachingGraphQLService(
return (false, new { data = new object() });
}

var result = await model.ExecuteAsync(ctx, query, log);
var result = await model.ExecuteAsync(ctx, query);

if (result.Errors?.Any() == true)
{
Expand All @@ -102,9 +84,13 @@ private Task<GraphQLModel> GetModelAsync(IAppEntity app)
{
entry.AbsoluteExpirationRelativeToNow = CacheDuration;
var allSchemas = await appProvider.GetSchemasAsync(app.Id);
var allSchemas = await resolver.Resolve<IAppProvider>().GetSchemasAsync(app.Id);
return new GraphQLModel(app, allSchemas, contentQuery.DefaultPageSizeGraphQl, assetQuery.DefaultPageSizeGraphQl, urlGenerator);
return new GraphQLModel(app,
allSchemas,
resolver.Resolve<IContentQueryService>().DefaultPageSizeGraphQl,
resolver.Resolve<IAssetQueryService>().DefaultPageSizeGraphQl,
resolver.Resolve<IGraphQLUrlGenerator>());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,114 @@

using System;
using System.Collections.Generic;
using System.Linq;
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;

namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
public sealed class GraphQLExecutionContext : QueryExecutionContext
{
private static readonly List<IAssetEntity> EmptyAssets = new List<IAssetEntity>();
private static readonly List<IContentEntity> EmptyContents = new List<IContentEntity>();
private readonly IDataLoaderContextAccessor dataLoaderContextAccessor;
private readonly IDependencyResolver resolver;

public IGraphQLUrlGenerator UrlGenerator { get; }

public GraphQLExecutionContext(QueryContext context,
IAssetQueryService assetQuery,
IContentQueryService contentQuery,
IGraphQLUrlGenerator urlGenerator)
: base(context, assetQuery, contentQuery)
public ISemanticLog Log { get; }

public GraphQLExecutionContext(QueryContext context, IDependencyResolver resolver)
: base(context,
resolver.Resolve<IAssetQueryService>(),
resolver.Resolve<IContentQueryService>())
{
UrlGenerator = resolver.Resolve<IGraphQLUrlGenerator>();

dataLoaderContextAccessor = resolver.Resolve<IDataLoaderContextAccessor>();

this.resolver = resolver;
}

public void Setup(ExecutionOptions execution)
{
var loader = resolver.Resolve<DataLoaderDocumentListener>();

var logger = LoggingMiddleware.Create(resolver.Resolve<ISemanticLog>());

execution.Listeners.Add(loader);
execution.FieldMiddleware.Use(logger);

execution.UserContext = this;
}

public override Task<IAssetEntity> FindAssetAsync(Guid id)
{
UrlGenerator = urlGenerator;
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 Task<IReadOnlyList<IAssetEntity>> GetReferencedAssetsAsync(IJsonValue value)
public async Task<IReadOnlyList<IAssetEntity>> GetReferencedAssetsAsync(IJsonValue value)
{
var ids = ParseIds(value);

return GetReferencedAssetsAsync(ids);
if (ids == null)
{
return EmptyAssets;
}

var dataLoader = GetAssetsLoader();

return await dataLoader.LoadManyAsync(ids);
}

public Task<IReadOnlyList<IContentEntity>> GetReferencedContentsAsync(Guid schemaId, IJsonValue value)
public async Task<IReadOnlyList<IContentEntity>> GetReferencedContentsAsync(Guid schemaId, IJsonValue value)
{
var ids = ParseIds(value);

return GetReferencedContentsAsync(schemaId, ids);
if (ids == null)
{
return EmptyContents;
}

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);
});
}

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 result.ToDictionary(x => x.Id);
});
}

private static ICollection<Guid> ParseIds(IJsonValue value)
Expand All @@ -58,7 +135,7 @@ private static ICollection<Guid> ParseIds(IJsonValue value)
}
catch
{
return new List<Guid>();
return null;
}
}
}
Expand Down
22 changes: 9 additions & 13 deletions src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Utils;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
using GraphQLSchema = GraphQL.Types.Schema;

#pragma warning disable IDE0003
Expand Down Expand Up @@ -136,9 +135,9 @@ public IFieldPartitioning ResolvePartition(Partitioning key)
return partitionResolver(key);
}

public (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field)
public (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field, string fieldName)
{
return field.Accept(new QueryGraphTypeVisitor(schema, GetContentType, this, assetListType));
return field.Accept(new QueryGraphTypeVisitor(schema, GetContentType, this, assetListType, fieldName));
}

public IGraphType GetAssetType()
Expand Down Expand Up @@ -172,20 +171,17 @@ public IGraphType GetContentType(Guid schemaId)
return contentTypes.GetOrAdd(schema, s => new ContentGraphType());
}

public async Task<(object Data, object[] Errors)> ExecuteAsync(GraphQLExecutionContext context, GraphQLQuery query, ISemanticLog log)
public async Task<(object Data, object[] Errors)> ExecuteAsync(GraphQLExecutionContext context, GraphQLQuery query)
{
Guard.NotNull(context, nameof(context));

var inputs = query.Variables?.ToInputs();

var result = await new DocumentExecuter().ExecuteAsync(options =>
var result = await new DocumentExecuter().ExecuteAsync(execution =>
{
options.FieldMiddleware.Use(LoggingMiddleware.Create(log));
options.OperationName = query.OperationName;
options.UserContext = context;
options.Schema = graphQLSchema;
options.Inputs = inputs;
options.Query = query.Query;
context.Setup(execution);
execution.Schema = graphQLSchema;
execution.Inputs = query.Variables?.ToInputs();
execution.Query = query.Query;
}).ConfigureAwait(false);

return (result.Data, result.Errors?.Select(x => (object)new { x.Message, x.Locations }).ToArray());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ public interface IGraphModel

IGraphType GetContentDataType(Guid schemaId);

(IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field);
(IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field, string fieldName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void Initialize(IGraphModel model, ISchemaEntity schema)

foreach (var (field, fieldName, typeName) in schema.SchemaDef.Fields.SafeFields())
{
var (resolvedType, valueResolver) = model.GetGraphType(schema, field);
var (resolvedType, valueResolver) = model.GetGraphType(schema, field, fieldName);

if (valueResolver != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -37,5 +39,12 @@ private static string SafeString(this string value, int index)

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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
{
public sealed class NestedGraphType : ObjectGraphType<JsonObject>
{
public NestedGraphType(IGraphModel model, ISchemaEntity schema, IArrayField field)
public NestedGraphType(IGraphModel model, ISchemaEntity schema, IArrayField field, string fieldName)
{
var schemaType = schema.TypeName();
var schemaName = schema.DisplayName();

var fieldName = field.DisplayName();
var fieldDisplayName = field.DisplayName();

Name = $"{schemaType}{fieldName}ChildDto";

foreach (var (nestedField, nestedName, _) in field.Fields.SafeFields())
{
var fieldInfo = model.GetGraphType(schema, nestedField);
var fieldInfo = model.GetGraphType(schema, nestedField, nestedName);

if (fieldInfo.ResolveType != null)
{
Expand All @@ -38,12 +38,12 @@ public NestedGraphType(IGraphModel model, ISchemaEntity schema, IArrayField fiel
Name = nestedName,
Resolver = resolver,
ResolvedType = fieldInfo.ResolveType,
Description = $"The {fieldName}/{nestedField.DisplayName()} nested field."
Description = $"The {fieldDisplayName}/{nestedField.DisplayName()} nested field."
});
}
}

Description = $"The structure of the {schemaName}.{fieldName} nested schema.";
Description = $"The structure of the {schemaName}.{fieldDisplayName} nested schema.";
}

private static FuncFieldResolver<object> ValueResolver(NestedField nestedField, (IGraphType ResolveType, ValueResolver Resolver) fieldInfo)
Expand Down
Loading

0 comments on commit 252a19e

Please sign in to comment.