// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors; using Squidex.Infrastructure; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.Queries; namespace Squidex.Domain.Apps.Entities.MongoDb.Assets { public sealed partial class MongoAssetRepository : MongoRepositoryBase, IAssetRepository { private readonly MongoDbOptions options; public MongoAssetRepository(IMongoDatabase database, IOptions options) : base(database) { Guard.NotNull(options, nameof(options)); this.options = options.Value; } protected override string CollectionName() { return "States_Assets"; } protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default) { return collection.Indexes.CreateManyAsync( new[] { new CreateIndexModel( Index .Ascending(x => x.AppId) .Ascending(x => x.IsDeleted) .Ascending(x => x.FileName) .Ascending(x => x.Tags) .Descending(x => x.LastModified), new CreateIndexOptions { Name = options.IsDocumentDb ? "FileName_Tags" : null }), new CreateIndexModel( Index .Ascending(x => x.AppId) .Ascending(x => x.IsDeleted) .Ascending(x => x.FileHash), new CreateIndexOptions { Name = options.IsDocumentDb ? "FileHash" : null }), new CreateIndexModel( Index .Ascending(x => x.AppId) .Ascending(x => x.IsDeleted) .Ascending(x => x.Slug), new CreateIndexOptions { Name = options.IsDocumentDb ? "Slug" : null }) }, ct); } public async Task> QueryAsync(Guid appId, Query query) { using (Profiler.TraceMethod("QueryAsyncByQuery")) { try { query = query.AdjustToModel(); var filter = query.BuildFilter(appId); var contentCount = Collection.Find(filter).CountDocumentsAsync(); var contentItems = Collection.Find(filter) .AssetTake(query) .AssetSkip(query) .AssetSort(query) .ToListAsync(); await Task.WhenAll(contentItems, contentCount); return ResultList.Create(contentCount.Result, contentItems.Result); } catch (MongoQueryException ex) { if (ex.Message.Contains("17406")) { throw new DomainException("Result set is too large to be retrieved. Use $top parameter to reduce the number of items."); } else { throw; } } } } public async Task> QueryAsync(Guid appId, HashSet ids) { using (Profiler.TraceMethod("QueryAsyncByIds")) { var find = Collection.Find(x => ids.Contains(x.Id)).SortByDescending(x => x.LastModified); var assetItems = await find.ToListAsync(); return ResultList.Create(assetItems.Count, assetItems.OfType()); } } public async Task FindAssetBySlugAsync(Guid appId, string slug) { using (Profiler.TraceMethod()) { var assetEntity = await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.Slug == slug) .FirstOrDefaultAsync(); return assetEntity; } } public async Task> QueryByHashAsync(Guid appId, string hash) { using (Profiler.TraceMethod()) { var assetEntities = await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.FileHash == hash) .ToListAsync(); return assetEntities.OfType().ToList(); } } public async Task FindAssetAsync(Guid id, bool allowDeleted = false) { using (Profiler.TraceMethod()) { var assetEntity = await Collection.Find(x => x.Id == id) .FirstOrDefaultAsync(); if (assetEntity?.IsDeleted == true && !allowDeleted) { return null; } return assetEntity; } } public Task RemoveAsync(Guid appId) { return Collection.DeleteManyAsync(x => x.IndexedAppId == appId); } } }