Browse Source

Separate value for graphql.

pull/361/head
Sebastian Stehle 7 years ago
parent
commit
ba4a64ef42
  1. 4
      src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs
  2. 10
      src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs
  3. 2
      src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs
  4. 4
      src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs
  5. 10
      src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs
  6. 2
      src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs
  7. 2
      src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs
  8. 12
      src/Squidex/appsettings.json
  9. 36
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs
  10. 82
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs
  11. 25
      tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs

4
src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs

@ -9,7 +9,9 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
public sealed class AssetOptions
{
public int DefaultPageSize { get; set; } = 20;
public int DefaultPageSize { get; set; } = 200;
public int DefaultPageSizeGraphQl { get; set; } = 20;
public int MaxResults { get; set; } = 200;

10
src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs

@ -27,9 +27,9 @@ namespace Squidex.Domain.Apps.Entities.Assets
private readonly IAssetRepository assetRepository;
private readonly AssetOptions options;
public int DefaultPageSize
public int DefaultPageSizeGraphQl
{
get { return options.DefaultPageSize; }
get { return options.DefaultPageSizeGraphQl; }
}
public AssetQueryService(ITagService tagService, IAssetRepository assetRepository, IOptions<AssetOptions> options)
@ -120,7 +120,11 @@ namespace Squidex.Domain.Apps.Entities.Assets
result.Sort.Add(new SortNode(new List<string> { "lastModified" }, SortOrder.Descending));
}
if (result.Take > options.MaxResults)
if (result.Take == long.MaxValue)
{
result.Take = options.DefaultPageSize;
}
else if (result.Take > options.MaxResults)
{
result.Take = options.MaxResults;
}

2
src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs

@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
{
public interface IAssetQueryService
{
int DefaultPageSize { get; }
int DefaultPageSizeGraphQl { get; }
Task<IList<IAssetEntity>> QueryByHashAsync(Guid appId, string hash);

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

@ -9,7 +9,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
{
public sealed class ContentOptions
{
public int DefaultPageSize { get; set; } = 20;
public int DefaultPageSize { get; set; } = 200;
public int DefaultPageSizeGraphQl { get; set; } = 20;
public int MaxResults { get; set; } = 200;
}

10
src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs

@ -45,9 +45,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
private readonly ContentOptions options;
private readonly EdmModelBuilder modelBuilder;
public int DefaultPageSize
public int DefaultPageSizeGraphQl
{
get { return options.DefaultPageSize; }
get { return options.DefaultPageSizeGraphQl; }
}
public ContentQueryService(
@ -276,7 +276,11 @@ namespace Squidex.Domain.Apps.Entities.Contents
result.Sort.Add(new SortNode(new List<string> { "lastModified" }, SortOrder.Descending));
}
if (result.Take > options.MaxResults)
if (result.Take == long.MaxValue)
{
result.Take = options.DefaultPageSize;
}
else if (result.Take > options.MaxResults)
{
result.Take = options.MaxResults;
}

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

@ -99,7 +99,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var allSchemas = await appProvider.GetSchemasAsync(app.Id);
return new GraphQLModel(app, allSchemas, contentQuery.DefaultPageSize, assetQuery.DefaultPageSize, urlGenerator);
return new GraphQLModel(app, allSchemas, contentQuery.DefaultPageSizeGraphQl, assetQuery.DefaultPageSizeGraphQl, urlGenerator);
});
}

2
src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs

@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
{
public interface IContentQueryService
{
int DefaultPageSize { get; }
int DefaultPageSizeGraphQl { get; }
Task<IList<IContentEntity>> QueryAsync(QueryContext context, IReadOnlyList<Guid> ids);

12
src/Squidex/appsettings.json

@ -150,7 +150,11 @@
/*
* The default page size if not specified by a query.
*/
"defaultPageSize": 20,
"defaultPageSize": 200,
/*
* The default page size for graphql if not specified by a query.
*/
"defaultPageSizeGraphQL": 20,
/*
* The maximum number of items to return for each query.
*
@ -163,7 +167,11 @@
/*
* The default page size if not specified by a query.
*/
"defaultPageSize": 20,
"defaultPageSize": 200,
/*
* The default page size for graphql if not specified by a query.
*/
"defaultPageSizeGraphQL": 20,
/*
* The maximum number of items to return for each query.
*

36
tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs

@ -15,6 +15,7 @@ using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Tags;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Queries;
using Xunit;
@ -49,13 +50,15 @@ namespace Squidex.Domain.Apps.Entities.Assets
["id3"] = "name3"
});
sut = new AssetQueryService(tagService, assetRepository, Options.Create(new AssetOptions()));
var options = Options.Create(new AssetOptions { DefaultPageSize = 30 });
sut = new AssetQueryService(tagService, assetRepository, options);
}
[Fact]
public void Should_provide_default_page_size()
{
var result = sut.DefaultPageSize;
var result = sut.DefaultPageSizeGraphQl;
Assert.Equal(20, result);
}
@ -128,27 +131,44 @@ namespace Squidex.Domain.Apps.Entities.Assets
[Fact]
public async Task Should_transform_odata_query()
{
await sut.QueryAsync(context, Q.Empty.WithODataQuery("$top=100&$orderby=fileName asc&$search=Hello World"));
var query = Q.Empty.WithODataQuery("$top=100&$orderby=fileName asc&$search=Hello World");
await sut.QueryAsync(context, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Matches(x => x.ToString() == "FullText: 'Hello World'; Take: 100; Sort: fileName Ascending")))
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("FullText: 'Hello World'; Take: 100; Sort: fileName Ascending")))
.MustHaveHappened();
}
[Fact]
public async Task Should_transform_odata_query_and_enrich_with_defaults()
{
await sut.QueryAsync(context, Q.Empty.WithODataQuery("$filter=fileName eq 'ABC'"));
var query = Q.Empty.WithODataQuery("$top=200&$filter=fileName eq 'ABC'");
await sut.QueryAsync(context, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Matches(x => x.ToString() == "Filter: fileName == 'ABC'; Take: 200; Sort: lastModified Descending")))
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("Filter: fileName == 'ABC'; Take: 200; Sort: lastModified Descending")))
.MustHaveHappened();
}
[Fact]
public async Task Should_apply_default_page_size()
{
var query = Q.Empty;
await sut.QueryAsync(context, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("Take: 30; Sort: lastModified Descending")))
.MustHaveHappened();
}
[Fact]
public async Task Should_limit_number_of_assets()
{
await sut.QueryAsync(context, Q.Empty.WithODataQuery("$top=300&$skip=20"));
var query = Q.Empty.WithODataQuery("$top=300&$skip=20");
await sut.QueryAsync(context, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Matches(x => x.ToString() == "Skip: 20; Take: 200; Sort: lastModified Descending")))
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("Skip: 20; Take: 200; Sort: lastModified Descending")))
.MustHaveHappened();
}

82
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs

@ -11,6 +11,7 @@ using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using FakeItEasy;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Microsoft.OData;
using Squidex.Domain.Apps.Core.Apps;
@ -22,6 +23,7 @@ using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.Edm;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Queries;
using Squidex.Infrastructure.Security;
@ -49,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
private readonly NamedContentData contentTransformed = new NamedContentData();
private readonly ClaimsPrincipal user;
private readonly ClaimsIdentity identity = new ClaimsIdentity();
private readonly EdmModelBuilder modelBuilder = A.Fake<EdmModelBuilder>();
private readonly EdmModelBuilder modelBuilder = new EdmModelBuilder(new MemoryCache(Options.Create(new MemoryCacheOptions())));
private readonly QueryContext context;
private readonly ContentQueryService sut;
@ -71,19 +73,22 @@ namespace Squidex.Domain.Apps.Entities.Contents
context = QueryContext.Create(app, user);
var options = Options.Create(new ContentOptions { DefaultPageSize = 30 });
sut = new ContentQueryService(
appProvider,
urlGenerator,
contentRepository,
contentVersionLoader,
scriptEngine,
Options.Create(new ContentOptions()), modelBuilder);
options,
modelBuilder);
}
[Fact]
public void Should_provide_default_page_size()
{
var result = sut.DefaultPageSize;
var result = sut.DefaultPageSizeGraphQl;
Assert.Equal(20, result);
}
@ -128,17 +133,33 @@ namespace Squidex.Domain.Apps.Entities.Contents
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.ThrowIfSchemaNotExistsAsync(ctx, schemaId.Name));
}
public static IEnumerable<object[]> SingleDataFrontend = new[]
[Fact]
public async Task Should_apply_default_page_size()
{
new object[] { true, new[] { Status.Archived, Status.Draft, Status.Published } },
new object[] { false, new[] { Status.Archived, Status.Draft, Status.Published } }
};
SetupClaims();
SetupSchema();
public static IEnumerable<object[]> SingleDataApi = new[]
var query = Q.Empty;
await sut.QueryAsync(context, schemaId.Name, query);
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(Status.Published), A<Query>.That.Is("Take: 30; Sort: lastModified Descending")))
.MustHaveHappened();
}
[Fact]
public async Task Should_limit_number_of_contents()
{
new object[] { true, new[] { Status.Draft, Status.Published } },
new object[] { false, new[] { Status.Published } }
};
SetupClaims();
SetupSchema();
var query = Q.Empty.WithODataQuery("$top=300&$skip=20");
await sut.QueryAsync(context, schemaId.Name, query);
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(Status.Published), A<Query>.That.Is("Skip: 20; Take: 200; Sort: lastModified Descending")))
.MustHaveHappened();
}
[Fact]
public async Task Should_throw_for_single_content_if_no_permission()
@ -157,7 +178,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
SetupClaims();
SetupSchema();
A.CallTo(() => contentRepository.FindContentAsync(app, schema, new[] { Status.Published }, contentId))
A.CallTo(() => contentRepository.FindContentAsync(app, schema, A<Status[]>.That.Is(Status.Published), contentId))
.Returns((IContentEntity)null);
var ctx = context;
@ -165,6 +186,18 @@ namespace Squidex.Domain.Apps.Entities.Contents
await Assert.ThrowsAsync<DomainObjectNotFoundException>(async () => await sut.FindContentAsync(ctx, schemaId.Name, contentId));
}
public static IEnumerable<object[]> SingleDataFrontend = new[]
{
new object[] { true, new[] { Status.Archived, Status.Draft, Status.Published } },
new object[] { false, new[] { Status.Archived, Status.Draft, Status.Published } }
};
public static IEnumerable<object[]> SingleDataApi = new[]
{
new object[] { true, new[] { Status.Draft, Status.Published } },
new object[] { false, new[] { Status.Published } }
};
[Theory]
[MemberData(nameof(SingleDataFrontend))]
public async Task Should_return_single_content_for_frontend_without_transform(bool unpublished, params Status[] status)
@ -175,7 +208,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
SetupSchema();
SetupScripting(contentId);
A.CallTo(() => contentRepository.FindContentAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), contentId))
A.CallTo(() => contentRepository.FindContentAsync(app, schema, A<Status[]>.That.Is(status), contentId))
.Returns(content);
var ctx = context.WithUnpublished(unpublished);
@ -199,7 +232,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
SetupSchema();
SetupScripting(contentId);
A.CallTo(() => contentRepository.FindContentAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), contentId))
A.CallTo(() => contentRepository.FindContentAsync(app, schema, A<Status[]>.That.Is(status), contentId))
.Returns(content);
var ctx = context.WithUnpublished(unpublished);
@ -318,10 +351,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
SetupClaims();
SetupSchema();
A.CallTo(() => modelBuilder.BuildEdmModel(app, schema, A<bool>.Ignored))
.Throws(new ODataException());
var query = Q.Empty.WithODataQuery("$filter=invalid");
return Assert.ThrowsAsync<ValidationException>(() => sut.QueryAsync(context, schemaId.Name, Q.Empty.WithODataQuery("query")));
return Assert.ThrowsAsync<ValidationException>(() => sut.QueryAsync(context, schemaId.Name, query));
}
public static IEnumerable<object[]> ManyIdDataFrontend = new[]
@ -349,9 +381,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
var ids = Enumerable.Range(0, count).Select(x => Guid.NewGuid()).ToList();
SetupClaims(true);
SetupContents(status, total, ids);
SetupSchema();
SetupScripting(ids.ToArray());
SetupContents(status, total, ids);
var ctx = context.WithArchived(archive).WithUnpublished(unpublished);
@ -373,9 +405,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
var ids = Enumerable.Range(0, count).Select(x => Guid.NewGuid()).ToList();
SetupClaims();
SetupContents(status, total, ids);
SetupSchema();
SetupScripting(ids.ToArray());
SetupContents(status, total, ids);
var ctx = context.WithArchived(archive).WithUnpublished(unpublished);
@ -397,9 +429,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
var ids = Enumerable.Range(0, count).Select(x => Guid.NewGuid()).ToList();
SetupClaims(true);
SetupContents(status, ids);
SetupSchema();
SetupScripting(ids.ToArray());
SetupContents(status, ids);
var ctx = context.WithArchived(archive).WithUnpublished(unpublished);
@ -420,9 +452,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
var ids = Enumerable.Range(0, count).Select(x => Guid.NewGuid()).ToList();
SetupClaims();
SetupContents(status, ids);
SetupSchema();
SetupScripting(ids.ToArray());
SetupContents(status, ids);
var ctx = context.WithArchived(archive).WithUnpublished(unpublished);
@ -440,8 +472,8 @@ namespace Squidex.Domain.Apps.Entities.Contents
var ids = Enumerable.Range(0, 1).Select(x => Guid.NewGuid()).ToList();
SetupClaims(false, false);
SetupSchema();
SetupContents(new Status[0], ids);
SetupSchema();
var ctx = context;
@ -492,19 +524,19 @@ namespace Squidex.Domain.Apps.Entities.Contents
private void SetupContents(Status[] status, int count, int total, IContentEntity content)
{
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), A<Query>.Ignored))
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(status), A<Query>.Ignored))
.Returns(ResultList.Create(total, Enumerable.Repeat(content, count)));
}
private void SetupContents(Status[] status, int total, List<Guid> ids)
{
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), A<HashSet<Guid>>.Ignored))
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(status), A<HashSet<Guid>>.Ignored))
.Returns(ResultList.Create(total, ids.Select(x => CreateContent(x)).Shuffle()));
}
private void SetupContents(Status[] status, List<Guid> ids)
{
A.CallTo(() => contentRepository.QueryAsync(app, A<Status[]>.That.IsSameSequenceAs(status), A<HashSet<Guid>>.Ignored))
A.CallTo(() => contentRepository.QueryAsync(app, A<Status[]>.That.Is(status), A<HashSet<Guid>>.Ignored))
.Returns(ids.Select(x => (CreateContent(x), schema)).ToList());
}

25
tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs

@ -0,0 +1,25 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using FakeItEasy;
using Squidex.Infrastructure.Queries;
namespace Squidex.Domain.Apps.Entities.TestHelpers
{
public static class AExtensions
{
public static Query Is(this INegatableArgumentConstraintManager<Query> that, string query)
{
return that.Matches(x => x.ToString() == query);
}
public static T[] Is<T>(this INegatableArgumentConstraintManager<T[]> that, params T[] values)
{
return that.IsSameSequenceAs(values);
}
}
}
Loading…
Cancel
Save