diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs index c35802e59..fc0581b80 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs @@ -44,40 +44,43 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets .Descending(x => x.State.LastModified)); } - public async Task<(AssetState Value, long Version)> ReadAsync(Guid key) + public async Task> QueryAsync(Guid appId, HashSet mimeTypes = null, HashSet ids = null, string query = null, int take = 10, int skip = 0) { - var existing = - await Collection.Find(x => x.Id == key) - .FirstOrDefaultAsync(); + var filters = new List> + { + Filter.Eq(x => x.State.AppId, appId), + Filter.Eq(x => x.State.IsDeleted, false) + }; - if (existing != null) + if (ids != null && ids.Count > 0) { - return (existing.State, existing.Version); + filters.Add(Filter.In(x => x.Id, ids)); } - return (null, EtagVersion.NotFound); - } - - public async Task> QueryAsync(Guid appId, HashSet mimeTypes = null, HashSet ids = null, string query = null, int take = 10, int skip = 0) - { - var filter = CreateFilter(appId, mimeTypes, ids, query); + if (mimeTypes != null && mimeTypes.Count > 0) + { + filters.Add(Filter.In(x => x.State.MimeType, mimeTypes)); + } - var assetEntities = - await Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.State.LastModified) - .ToListAsync(); + if (!string.IsNullOrWhiteSpace(query)) + { + filters.Add(Filter.Regex(x => x.State.FileName, new BsonRegularExpression(query, "i"))); + } - return assetEntities.Select(x => x.State).ToList(); - } + var filter = Filter.And(filters); - public async Task CountAsync(Guid appId, HashSet mimeTypes = null, HashSet ids = null, string query = null) - { - var filter = CreateFilter(appId, mimeTypes, ids, query); + var find = Collection.Find(filter); - var assetsCount = - await Collection.Find(filter) + var assetEntities = + Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.State.LastModified) + .ToListAsync(); + var assetCount = + Collection.Find(filter) .CountAsync(); - return assetsCount; + await Task.WhenAll(assetEntities, assetCount); + + return ResultList.Create(assetEntities.Result.Select(x => x.State), assetCount.Result); } public async Task FindAssetAsync(Guid id) @@ -87,32 +90,18 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets return state; } - private static FilterDefinition CreateFilter(Guid appId, ICollection mimeTypes, ICollection ids, string query) + public async Task<(AssetState Value, long Version)> ReadAsync(Guid key) { - var filters = new List> - { - Filter.Eq(x => x.State.AppId, appId), - Filter.Eq(x => x.State.IsDeleted, false) - }; - - if (ids != null && ids.Count > 0) - { - filters.Add(Filter.In(x => x.Id, ids)); - } - - if (mimeTypes != null && mimeTypes.Count > 0) - { - filters.Add(Filter.In(x => x.State.MimeType, mimeTypes)); - } + var existing = + await Collection.Find(x => x.Id == key) + .FirstOrDefaultAsync(); - if (!string.IsNullOrWhiteSpace(query)) + if (existing != null) { - filters.Add(Filter.Regex(x => x.State.FileName, new BsonRegularExpression(query, "i"))); + return (existing.State, existing.Version); } - var filter = Filter.And(filters); - - return filter; + return (null, EtagVersion.NotFound); } public async Task WriteAsync(Guid key, AssetState value, long oldVersion, long newVersion) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs index 5d0f9eddb..f010e987c 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs @@ -51,13 +51,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas return (null, EtagVersion.NotFound); } - public async Task FindSchemaIdAsync(Guid appId, string name) + public async Task> QuerySchemaIdsAsync(Guid appId, string name) { - var schemaEntity = - await Collection.Find(x => x.AppId == appId && x.Name == name).Only(x => x.Id) - .FirstOrDefaultAsync(); + var schemaEntities = + await Collection.Find(x => x.AppId == appId && x.Name == name).Only(x => x.Id).SortByDescending(x => x.Version) + .ToListAsync(); - return schemaEntity != null ? Guid.Parse(schemaEntity["_id"].AsString) : Guid.Empty; + return schemaEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); } public async Task> QuerySchemaIdsAsync(Guid appId) diff --git a/src/Squidex.Domain.Apps.Entities/AppProvider.cs b/src/Squidex.Domain.Apps.Entities/AppProvider.cs index 297600ecf..e7a98a807 100644 --- a/src/Squidex.Domain.Apps.Entities/AppProvider.cs +++ b/src/Squidex.Domain.Apps.Entities/AppProvider.cs @@ -73,25 +73,22 @@ namespace Squidex.Domain.Apps.Entities return IsNotFound(app) ? null : app.State; } - public async Task GetSchemaAsync(Guid appId, string name, bool provideDeleted = false) + public async Task GetSchemaAsync(Guid appId, Guid id, bool provideDeleted = false) { - var schemaId = await GetSchemaIdAsync(appId, name); - - if (schemaId == Guid.Empty) - { - return null; - } - - var schema = await stateFactory.GetSingleAsync(schemaId); + var schema = await stateFactory.GetSingleAsync(id); return IsNotFound(provideDeleted, schema) ? null : schema.State; } - public async Task GetSchemaAsync(Guid appId, Guid id, bool provideDeleted = false) + public async Task GetSchemaAsync(Guid appId, string name, bool provideDeleted = false) { - var schema = await stateFactory.GetSingleAsync(id); + var ids = await schemaRepository.QuerySchemaIdsAsync(appId); - return IsNotFound(provideDeleted, schema) ? null : schema.State; + var schemas = + await Task.WhenAll( + ids.Select(id => stateFactory.GetSingleAsync(id))); + + return schemas.OrderByDescending(x => x.State.LastModified).FirstOrDefault(s => IsNotFound(provideDeleted, s))?.State; } public async Task> GetSchemasAsync(Guid appId) @@ -132,11 +129,6 @@ namespace Squidex.Domain.Apps.Entities return appRepository.FindAppIdByNameAsync(name); } - private Task GetSchemaIdAsync(Guid appId, string name) - { - return schemaRepository.FindSchemaIdAsync(appId, name); - } - private static bool IsNotFound(AppDomainObject app) { return app.Version < 0; diff --git a/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs b/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs index 10a16b6e3..2c35062d2 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs @@ -9,15 +9,14 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets.Repositories { public interface IAssetRepository { - Task> QueryAsync(Guid appId, HashSet mimeTypes = null, HashSet ids = null, string query = null, int take = 10, int skip = 0); + Task> QueryAsync(Guid appId, HashSet mimeTypes = null, HashSet ids = null, string query = null, int take = 10, int skip = 0); Task FindAssetAsync(Guid id); - - Task CountAsync(Guid appId, HashSet mimeTypes = null, HashSet ids = null, string query = null); } } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Repositories/ISchemaRepository.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Repositories/ISchemaRepository.cs index 642072660..3c20e1ba3 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Repositories/ISchemaRepository.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Repositories/ISchemaRepository.cs @@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Repositories { public interface ISchemaRepository { - Task FindSchemaIdAsync(Guid appId, string name); + Task> QuerySchemaIdsAsync(Guid appId, string name); Task> QuerySchemaIdsAsync(Guid appId); } diff --git a/src/Squidex.Infrastructure/IResultList.cs b/src/Squidex.Infrastructure/IResultList.cs new file mode 100644 index 000000000..b35bfe62d --- /dev/null +++ b/src/Squidex.Infrastructure/IResultList.cs @@ -0,0 +1,17 @@ +// ========================================================================== +// IResultList.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System.Collections.Generic; + +namespace Squidex.Infrastructure +{ + public interface IResultList : IReadOnlyList + { + long Total { get; } + } +} diff --git a/src/Squidex.Infrastructure/ResultList.cs b/src/Squidex.Infrastructure/ResultList.cs new file mode 100644 index 000000000..422873834 --- /dev/null +++ b/src/Squidex.Infrastructure/ResultList.cs @@ -0,0 +1,31 @@ +// ========================================================================== +// ResultList.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System.Collections.Generic; + +namespace Squidex.Infrastructure +{ + public static class ResultList + { + private sealed class Impl : List, IResultList + { + public long Total { get; } + + public Impl(IEnumerable items, long total) + : base(items) + { + Total = total; + } + } + + public static IResultList Create(IEnumerable items, long total) + { + return new Impl(items, total); + } + } +} diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs index d65cf73f7..910bd8fa6 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs @@ -102,15 +102,12 @@ namespace Squidex.Areas.Api.Controllers.Assets } } - var taskForItems = assetRepository.QueryAsync(App.Id, mimeTypeList, idsList, query, take, skip); - var taskForCount = assetRepository.CountAsync(App.Id, mimeTypeList, idsList, query); - - await Task.WhenAll(taskForItems, taskForCount); + var assets = await assetRepository.QueryAsync(App.Id, mimeTypeList, idsList, query, take, skip); var response = new AssetsDto { - Total = taskForCount.Result, - Items = taskForItems.Result.Select(x => SimpleMapper.Map(x, new AssetDto { FileType = x.FileName.FileType() })).ToArray() + Total = assets.Total, + Items = assets.Select(x => SimpleMapper.Map(x, new AssetDto { FileType = x.FileName.FileType() })).ToArray() }; return Ok(response); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs index 62379fac4..f75622415 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs @@ -137,7 +137,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL var assets = new List { asset }; A.CallTo(() => assetRepository.QueryAsync(app.Id, null, null, "my-query", 30, 5)) - .Returns(assets); + .Returns(ResultList.Create(assets, 0)); var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query }); @@ -546,7 +546,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL .Returns((schema, content)); A.CallTo(() => assetRepository.QueryAsync(app.Id, null, A>.That.Matches(x => x.Contains(assetRefId)), null, int.MaxValue, 0)) - .Returns(refAssets); + .Returns(ResultList.Create(refAssets, 0)); var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });