Browse Source

Merge branch 'master' of github.com:Squidex/squidex

pull/378/head v2.1.0
Sebastian Stehle 7 years ago
parent
commit
252a19e722
  1. 7
      src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs
  2. 9
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs
  3. 46
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs
  4. 99
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs
  5. 22
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs
  6. 2
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs
  7. 2
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs
  8. 9
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Extensions.cs
  9. 10
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs
  10. 6
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs
  11. 12
      src/Squidex.Domain.Apps.Entities/Contents/QueryExecutionContext.cs
  12. 8
      src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs
  13. 5
      src/Squidex.Domain.Apps.Entities/Q.cs
  14. 10
      src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs
  15. 14
      src/Squidex/Config/Domain/EntitiesServices.cs
  16. 48
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs
  17. 41
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.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)

46
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs

@ -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)
@ -54,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
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)));
@ -68,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
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);
@ -82,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
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)
{
@ -102,9 +84,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
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>());
});
}

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

@ -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)
@ -58,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}
catch
{
return new List<Guid>();
return null;
}
}
}

22
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs

@ -20,7 +20,6 @@ using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types;
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
@ -136,9 +135,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
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()
@ -172,20 +171,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
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());

2
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs

@ -35,6 +35,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
IGraphType GetContentDataType(Guid schemaId);
(IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field);
(IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field, string fieldName);
}
}

2
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs

@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
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)
{

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

10
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs

@ -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)
{
@ -38,12 +38,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
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)

6
src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs

@ -22,13 +22,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
private readonly Func<Guid, IGraphType> schemaResolver;
private readonly IGraphModel model;
private readonly IGraphType assetListType;
private readonly string fieldName;
public QueryGraphTypeVisitor(ISchemaEntity schema, Func<Guid, IGraphType> schemaResolver, IGraphModel model, IGraphType assetListType)
public QueryGraphTypeVisitor(ISchemaEntity schema, Func<Guid, IGraphType> schemaResolver, IGraphModel model, IGraphType assetListType, string fieldName)
{
this.model = model;
this.assetListType = assetListType;
this.schema = schema;
this.schemaResolver = schemaResolver;
this.fieldName = fieldName;
}
public (IGraphType ResolveType, ValueResolver Resolver) Visit(IArrayField field)
@ -93,7 +95,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types
private (IGraphType ResolveType, ValueResolver Resolver) ResolveNested(IArrayField field)
{
var schemaFieldType = new ListGraphType(new NonNullGraphType(new NestedGraphType(model, schema, field)));
var schemaFieldType = new ListGraphType(new NonNullGraphType(new NestedGraphType(model, schema, field, this.fieldName)));
return (schemaFieldType, NoopResolver);
}

12
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);
@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return content;
}
public async Task<IResultList<IAssetEntity>> QueryAssetsAsync(string query)
public virtual async Task<IResultList<IAssetEntity>> QueryAssetsAsync(string query)
{
var assets = await assetQuery.QueryAsync(context, Q.Empty.WithODataQuery(query));
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return assets;
}
public async Task<IResultList<IContentEntity>> QueryContentsAsync(string schemaIdOrName, string query)
public virtual async Task<IResultList<IContentEntity>> QueryContentsAsync(string schemaIdOrName, string query)
{
var result = await contentQuery.QueryAsync(context, schemaIdOrName, Q.Empty.WithODataQuery(query));
@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return result;
}
public async Task<IReadOnlyList<IAssetEntity>> GetReferencedAssetsAsync(ICollection<Guid> ids)
public virtual async Task<IReadOnlyList<IAssetEntity>> GetReferencedAssetsAsync(ICollection<Guid> ids)
{
Guard.NotNull(ids, nameof(ids));
@ -111,7 +111,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return ids.Select(cachedAssets.GetOrDefault).Where(x => x != null).ToList();
}
public async Task<IReadOnlyList<IContentEntity>> GetReferencedContentsAsync(Guid schemaId, ICollection<Guid> ids)
public virtual async Task<IReadOnlyList<IContentEntity>> GetReferencedContentsAsync(Guid schemaId, ICollection<Guid> ids)
{
Guard.NotNull(ids, nameof(ids));

8
src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs

@ -22,17 +22,17 @@ namespace Squidex.Domain.Apps.Entities.Contents
public Instant DueTime { get; }
public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant due)
public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant dueTime)
{
Id = id;
ScheduledBy = scheduledBy;
Status = status;
DueTime = due;
DueTime = dueTime;
}
public static ScheduleJob Build(Status status, RefToken by, Instant due)
public static ScheduleJob Build(Status status, RefToken scheduledBy, Instant dueTime)
{
return new ScheduleJob(Guid.NewGuid(), status, by, due);
return new ScheduleJob(Guid.NewGuid(), status, scheduledBy, dueTime);
}
}
}

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

10
src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs

@ -6,6 +6,7 @@
// ==========================================================================
using System;
using System.ComponentModel.DataAnnotations;
using NodaTime;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Infrastructure;
@ -25,13 +26,14 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models
public Status Status { get; set; }
/// <summary>
/// The user who schedule the content.
/// The target date and time when the content should be scheduled.
/// </summary>
public RefToken ScheduledBy { get; set; }
public Instant DueTime { get; set; }
/// <summary>
/// The target date and time when the content should be scheduled.
/// The user who schedule the content.
/// </summary>
public Instant DueTime { get; set; }
[Required]
public RefToken ScheduledBy { get; set; }
}
}

14
src/Squidex/Config/Domain/EntitiesServices.cs

@ -6,6 +6,8 @@
// ==========================================================================
using System;
using GraphQL;
using GraphQL.DataLoader;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@ -74,6 +76,18 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<AssetUsageTracker>()
.As<IEventConsumer>().As<IAssetUsageTracker>();
services.AddSingletonAs(x => new FuncDependencyResolver(t => x.GetRequiredService(t)))
.As<IDependencyResolver>();
services.AddSingletonAs<DataLoaderContextAccessor>()
.As<IDataLoaderContextAccessor>();
services.AddSingletonAs<DataLoaderDocumentListener>()
.AsSelf();
services.AddSingletonAs<CachingGraphQLService>()
.As<IGraphQLService>();
services.AddSingletonAs<CachingGraphQLService>()
.As<IGraphQLService>();

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

41
tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs

@ -9,6 +9,8 @@ using System;
using System.Collections.Generic;
using System.Security.Claims;
using FakeItEasy;
using GraphQL;
using GraphQL.DataLoader;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
@ -34,7 +36,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
public class GraphQLTestBase
{
protected readonly Schema schemaDef;
protected readonly Guid schemaId = Guid.NewGuid();
protected readonly Guid appId = Guid.NewGuid();
protected readonly string appName = "my-app";
@ -42,8 +43,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
protected readonly IAssetQueryService assetQuery = A.Fake<IAssetQueryService>();
protected readonly ISchemaEntity schema = A.Fake<ISchemaEntity>();
protected readonly IJsonSerializer serializer = TestUtils.CreateSerializer(TypeNameHandling.None);
protected readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
protected readonly IAppProvider appProvider = A.Fake<IAppProvider>();
protected readonly IDependencyResolver dependencyResolver;
protected readonly IAppEntity app = A.Dummy<IAppEntity>();
protected readonly QueryContext context;
protected readonly ClaimsPrincipal user = new ClaimsPrincipal();
@ -51,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
public GraphQLTestBase()
{
schemaDef =
var schemaDef =
new Schema("my-schema")
.AddJson(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties())
@ -93,11 +93,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
A.CallTo(() => schema.Id).Returns(schemaId);
A.CallTo(() => schema.SchemaDef).Returns(schemaDef);
var allSchemas = new List<ISchemaEntity> { schema };
A.CallTo(() => appProvider.GetSchemasAsync(appId)).Returns(allSchemas);
sut = new CachingGraphQLService(cache, appProvider, assetQuery, contentQuery, new FakeUrlGenerator(), A.Fake<ISemanticLog>());
sut = CreateSut();
}
protected static IContentEntity CreateContent(Guid id, Guid refId, Guid assetId, NamedContentData data = null, NamedContentData dataDraft = null)
@ -210,5 +206,32 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
return serializer.Serialize(result);
}
private CachingGraphQLService CreateSut()
{
var appProvider = A.Fake<IAppProvider>();
A.CallTo(() => appProvider.GetSchemasAsync(appId))
.Returns(new List<ISchemaEntity> { schema });
var dataLoaderContext = new DataLoaderContextAccessor();
var services = new Dictionary<Type, object>
{
[typeof(IAppProvider)] = appProvider,
[typeof(IAssetQueryService)] = assetQuery,
[typeof(IContentQueryService)] = contentQuery,
[typeof(IDataLoaderContextAccessor)] = dataLoaderContext,
[typeof(IGraphQLUrlGenerator)] = new FakeUrlGenerator(),
[typeof(ISemanticLog)] = A.Fake<ISemanticLog>(),
[typeof(DataLoaderDocumentListener)] = new DataLoaderDocumentListener(dataLoaderContext)
};
var resolver = new FuncDependencyResolver(t => services[t]);
var cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
return new CachingGraphQLService(cache, resolver);
}
}
}

Loading…
Cancel
Save