diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs index f5366299b..5c93059f2 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs @@ -21,25 +21,25 @@ namespace Squidex.Domain.Apps.Entities.Assets public sealed class AssetCommandMiddleware : GrainCommandMiddleware { private readonly IAssetStore assetStore; - private readonly IAssetQueryService assetQueryService; + private readonly IAssetQueryService assetQuery; private readonly IAssetThumbnailGenerator assetThumbnailGenerator; private readonly IEnumerable> tagGenerators; public AssetCommandMiddleware( IGrainFactory grainFactory, - IAssetQueryService assetQueryService, + IAssetQueryService assetQuery, IAssetStore assetStore, IAssetThumbnailGenerator assetThumbnailGenerator, IEnumerable> tagGenerators) : base(grainFactory) { Guard.NotNull(assetStore, nameof(assetStore)); - Guard.NotNull(assetQueryService, nameof(assetQueryService)); + Guard.NotNull(assetQuery, nameof(assetQuery)); Guard.NotNull(assetThumbnailGenerator, nameof(assetThumbnailGenerator)); Guard.NotNull(tagGenerators, nameof(tagGenerators)); this.assetStore = assetStore; - this.assetQueryService = assetQueryService; + this.assetQuery = assetQuery; this.assetThumbnailGenerator = assetThumbnailGenerator; this.tagGenerators = tagGenerators; @@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Assets try { - var existings = await assetQueryService.QueryByHashAsync(createAsset.AppId.Id, createAsset.FileHash); + var existings = await assetQuery.QueryByHashAsync(createAsset.AppId.Id, createAsset.FileHash); AssetCreatedResult result = null; diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs index c0a77b6a8..c6bf83fac 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs @@ -9,6 +9,8 @@ namespace Squidex.Domain.Apps.Entities.Assets { public sealed class AssetOptions { + public int DefaultPageSize { get; set; } = 20; + public int MaxResults { get; set; } = 200; public long MaxSize { get; set; } = 5 * 1024 * 1024; diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs index 9edfe22fb..ee40d2c51 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs @@ -27,6 +27,11 @@ namespace Squidex.Domain.Apps.Entities.Assets private readonly IAssetRepository assetRepository; private readonly AssetOptions options; + public int DefaultPageSize + { + get { return options.DefaultPageSize; } + } + public AssetQueryService(ITagService tagService, IAssetRepository assetRepository, IOptions options) { Guard.NotNull(tagService, nameof(tagService)); diff --git a/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs b/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs index f93f0f69b..f83a437dc 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs @@ -14,6 +14,8 @@ namespace Squidex.Domain.Apps.Entities.Assets { public interface IAssetQueryService { + int DefaultPageSize { get; } + Task> QueryByHashAsync(Guid appId, string hash); Task> QueryAsync(QueryContext contex, Q query); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs index 4b58d7312..72ca1309b 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs @@ -9,6 +9,8 @@ namespace Squidex.Domain.Apps.Entities.Contents { public sealed class ContentOptions { + public int DefaultPageSize { get; set; } = 20; + public int MaxResults { get; set; } = 200; } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs index 6d3b16f17..3648d433b 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs @@ -45,6 +45,11 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly ContentOptions options; private readonly EdmModelBuilder modelBuilder; + public int DefaultPageSize + { + get { return options.DefaultPageSize; } + } + public ContentQueryService( IAppProvider appProvider, IAssetUrlGenerator assetUrlGenerator, diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs index bdb223f40..b43d93c1a 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs +++ b/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, urlGenerator); + return new GraphQLModel(app, allSchemas, contentQuery.DefaultPageSize, assetQuery.DefaultPageSize, urlGenerator); }); } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs index d5b1316fb..54a2793ab 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLExecutionContext.cs @@ -18,10 +18,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL public IGraphQLUrlGenerator UrlGenerator { get; } public GraphQLExecutionContext(QueryContext context, - IAssetQueryService assetQueryService, + IAssetQueryService assetQuery, IContentQueryService contentQuery, IGraphQLUrlGenerator urlGenerator) - : base(context, assetQueryService, contentQuery) + : base(context, assetQuery, contentQuery) { UrlGenerator = urlGenerator; } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs index 56521688b..019374092 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using GraphQL; using GraphQL.Resolvers; using GraphQL.Types; +using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps; @@ -39,7 +40,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL public bool CanGenerateAssetSourceUrl { get; } - public GraphQLModel(IAppEntity app, IEnumerable schemas, IGraphQLUrlGenerator urlGenerator) + public GraphQLModel(IAppEntity app, + IEnumerable schemas, + int pageSizeContents, + int pageSizeAssets, + IGraphQLUrlGenerator urlGenerator) { this.app = app; @@ -52,17 +57,17 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL schemasById = schemas.Where(x => x.SchemaDef.IsPublished).ToDictionary(x => x.Id); - graphQLSchema = BuildSchema(this); + graphQLSchema = BuildSchema(this, pageSizeContents, pageSizeAssets); graphQLSchema.RegisterValueConverter(JsonConverter.Instance); InitializeContentTypes(); } - private static GraphQLSchema BuildSchema(GraphQLModel model) + private static GraphQLSchema BuildSchema(GraphQLModel model, int pageSizeContents, int pageSizeAssets) { var schemas = model.schemasById.Values; - return new GraphQLSchema { Query = new AppQueriesGraphType(model, schemas) }; + return new GraphQLSchema { Query = new AppQueriesGraphType(model, pageSizeContents, pageSizeAssets, schemas) }; } private void InitializeContentTypes() diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs index 3b97da85b..7ef69ecbd 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/AppQueriesGraphType.cs @@ -17,12 +17,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types { public sealed class AppQueriesGraphType : ObjectGraphType { - public AppQueriesGraphType(IGraphModel model, IEnumerable schemas) + public AppQueriesGraphType(IGraphModel model, int pageSizeContents, int pageSizeAssets, IEnumerable schemas) { var assetType = model.GetAssetType(); AddAssetFind(assetType); - AddAssetsQueries(assetType); + AddAssetsQueries(assetType, pageSizeAssets); foreach (var schema in schemas) { @@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types var contentType = model.GetContentType(schema.Id); AddContentFind(schemaId, schemaType, schemaName, contentType); - AddContentQueries(schemaId, schemaType, schemaName, contentType); + AddContentQueries(schemaId, schemaType, schemaName, contentType, pageSizeContents); } Description = "The app queries."; @@ -73,12 +73,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types }); } - private void AddAssetsQueries(IGraphType assetType) + private void AddAssetsQueries(IGraphType assetType, int pageSize) { AddField(new FieldType { Name = "queryAssets", - Arguments = CreateAssetQueryArguments(), + Arguments = CreateAssetQueryArguments(pageSize), ResolvedType = new ListGraphType(new NonNullGraphType(assetType)), Resolver = ResolveAsync((c, e) => { @@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types AddField(new FieldType { Name = "queryAssetsWithTotal", - Arguments = CreateAssetQueryArguments(), + Arguments = CreateAssetQueryArguments(pageSize), ResolvedType = new AssetsResultGraphType(assetType), Resolver = ResolveAsync((c, e) => { @@ -104,12 +104,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types }); } - private void AddContentQueries(Guid schemaId, string schemaType, string schemaName, IGraphType contentType) + private void AddContentQueries(Guid schemaId, string schemaType, string schemaName, IGraphType contentType, int pageSize) { AddField(new FieldType { Name = $"query{schemaType}Contents", - Arguments = CreateContentQueryArguments(), + Arguments = CreateContentQueryArguments(pageSize), ResolvedType = new ListGraphType(new NonNullGraphType(contentType)), Resolver = ResolveAsync((c, e) => { @@ -123,7 +123,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types AddField(new FieldType { Name = $"query{schemaType}ContentsWithTotal", - Arguments = CreateContentQueryArguments(), + Arguments = CreateContentQueryArguments(pageSize), ResolvedType = new ContentsResultGraphType(schemaType, schemaName, contentType), Resolver = ResolveAsync((c, e) => { @@ -163,15 +163,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types }; } - private static QueryArguments CreateAssetQueryArguments() + private static QueryArguments CreateAssetQueryArguments(int pageSize) { return new QueryArguments { new QueryArgument(AllTypes.None) { Name = "take", - Description = "Optional number of assets to take (Default: 20).", - DefaultValue = 20, + Description = $"Optional number of assets to take (Default: {pageSize}).", + DefaultValue = pageSize, ResolvedType = AllTypes.Int }, new QueryArgument(AllTypes.None) @@ -191,15 +191,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types }; } - private static QueryArguments CreateContentQueryArguments() + private static QueryArguments CreateContentQueryArguments(int pageSize) { return new QueryArguments { new QueryArgument(AllTypes.None) { Name = "top", - Description = "Optional number of contents to take (Default: 20).", - DefaultValue = 20, + Description = $"Optional number of contents to take (Default: {pageSize}).", + DefaultValue = pageSize, ResolvedType = AllTypes.Int }, new QueryArgument(AllTypes.None) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs b/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs index f93bdc1d7..f7cd0007f 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs @@ -14,6 +14,8 @@ namespace Squidex.Domain.Apps.Entities.Contents { public interface IContentQueryService { + int DefaultPageSize { get; } + Task> QueryAsync(QueryContext context, IReadOnlyList ids); Task> QueryAsync(QueryContext context, string schemaIdOrName, Q query); diff --git a/src/Squidex/appsettings.json b/src/Squidex/appsettings.json index 21bfb1ac0..c5741c060 100644 --- a/src/Squidex/appsettings.json +++ b/src/Squidex/appsettings.json @@ -147,6 +147,10 @@ }, "content": { + /* + * The default page size if not specified by a query. + */ + "defaultPageSize": 20, /* * The maximum number of items to return for each query. * @@ -156,6 +160,10 @@ }, "assets": { + /* + * The default page size if not specified by a query. + */ + "defaultPageSize": 20, /* * The maximum number of items to return for each query. * diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs index 1ec545b2c..4868012ec 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs @@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { public class AssetCommandMiddlewareTests : HandlerTestBase { - private readonly IAssetQueryService assetQueryService = A.Fake(); + private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake(); private readonly IAssetStore assetStore = A.Fake(); private readonly ITagService tagService = A.Fake(); @@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.Assets asset = new AssetGrain(Store, tagService, A.Dummy()); asset.ActivateAsync(Id).Wait(); - A.CallTo(() => assetQueryService.QueryByHashAsync(AppId, A.Ignored)) + A.CallTo(() => assetQuery.QueryByHashAsync(AppId, A.Ignored)) .Returns(new List()); A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A>.Ignored, A>.Ignored)) @@ -61,7 +61,7 @@ namespace Squidex.Domain.Apps.Entities.Assets A.CallTo(() => grainFactory.GetGrain(Id, null)) .Returns(asset); - sut = new AssetCommandMiddleware(grainFactory, assetQueryService, assetStore, assetThumbnailGenerator, new[] { tagGenerator }); + sut = new AssetCommandMiddleware(grainFactory, assetQuery, assetStore, assetThumbnailGenerator, new[] { tagGenerator }); } [Fact] @@ -205,7 +205,7 @@ namespace Squidex.Domain.Apps.Entities.Assets A.CallTo(() => temp.FileName).Returns(fileName); A.CallTo(() => temp.FileSize).Returns(fileSize); - A.CallTo(() => assetQueryService.QueryByHashAsync(A.Ignored, A.Ignored)) + A.CallTo(() => assetQuery.QueryByHashAsync(A.Ignored, A.Ignored)) .Returns(new List { existing }); } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs index a9796bd40..cb05b142d 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs @@ -52,6 +52,14 @@ namespace Squidex.Domain.Apps.Entities.Assets sut = new AssetQueryService(tagService, assetRepository, Options.Create(new AssetOptions())); } + [Fact] + public void Should_provide_default_page_size() + { + var result = sut.DefaultPageSize; + + Assert.Equal(20, result); + } + [Fact] public async Task Should_find_asset_by_id_and_resolve_tags() { diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs index a27b6b0ad..8568d05e5 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs @@ -80,6 +80,14 @@ namespace Squidex.Domain.Apps.Entities.Contents Options.Create(new ContentOptions()), modelBuilder); } + [Fact] + public void Should_provide_default_page_size() + { + var result = sut.DefaultPageSize; + + Assert.Equal(20, result); + } + [Fact] public async Task Should_return_schema_from_id_if_string_is_guid() {