// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschraenkt) // 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 MongoDB.Driver; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.MongoDb; using Squidex.Infrastructure.Queries; using Squidex.Log; namespace Squidex.Domain.Apps.Entities.MongoDb.Contents { public sealed class MongoContentCollection : MongoRepositoryBase { private readonly QueryAsStream queryAsStream; private readonly QueryById queryBdId; private readonly QueryByIds queryByIds; private readonly QueryByQuery queryByQuery; private readonly QueryReferences queryReferences; private readonly QueryReferrers queryReferrers; private readonly QueryScheduled queryScheduled; private readonly string name; private readonly ReadPreference readPreference; public MongoContentCollection(string name, IMongoDatabase database, IAppProvider appProvider, ReadPreference readPreference) : base(database) { this.name = name; queryAsStream = new QueryAsStream(); queryBdId = new QueryById(); queryByIds = new QueryByIds(); queryByQuery = new QueryByQuery(appProvider); queryReferences = new QueryReferences(queryByIds); queryReferrers = new QueryReferrers(); queryScheduled = new QueryScheduled(); this.readPreference = readPreference; } public IMongoCollection GetInternalCollection() { return Collection; } protected override string CollectionName() { return name; } protected override MongoCollectionSettings CollectionSettings() { return new MongoCollectionSettings { ReadPreference = readPreference }; } protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct) { var operations = new OperationBase[] { queryAsStream, queryBdId, queryByIds, queryByQuery, queryReferences, queryReferrers, queryScheduled }; foreach (var operation in operations) { operation.Setup(collection); } return collection.Indexes.CreateManyAsync(operations.SelectMany(x => x.CreateIndexes()), ct); } public Task ResetScheduledAsync(DomainId documentId, CancellationToken ct) { return Collection.UpdateOneAsync(x => x.DocumentId == documentId, Update.Unset(x => x.ScheduleJob).Unset(x => x.ScheduledAt), cancellationToken: ct); } public IAsyncEnumerable StreamAll(DomainId appId, HashSet? schemaIds, CancellationToken ct) { return queryAsStream.StreamAll(appId, schemaIds, ct); } public async Task> QueryAsync(IAppEntity app, List schemas, Q q, CancellationToken ct) { using (Profiler.TraceMethod()) { if (q.Ids != null && q.Ids.Count > 0) { return await queryByIds.QueryAsync(app.Id, schemas, q, ct); } if (q.Referencing != default) { return await queryReferences.QueryAsync(app.Id, schemas, q, ct); } if (q.Reference != default) { return await queryByQuery.QueryAsync(app, schemas, q, ct); } return ResultList.CreateFrom(0); } } public async Task> QueryAsync(IAppEntity app, ISchemaEntity schema, Q q, CancellationToken ct) { using (Profiler.TraceMethod()) { if (q.Ids != null && q.Ids.Count > 0) { return await queryByIds.QueryAsync(app.Id, new List { schema }, q, ct); } if (q.Referencing == default) { return await queryByQuery.QueryAsync(app, schema, q, ct); } return ResultList.CreateFrom(0); } } public async Task FindContentAsync(ISchemaEntity schema, DomainId id, CancellationToken ct) { using (Profiler.TraceMethod()) { return await queryBdId.QueryAsync(schema, id, ct); } } public async Task QueryScheduledWithoutDataAsync(Instant now, Func callback, CancellationToken ct) { using (Profiler.TraceMethod()) { await queryScheduled.QueryAsync(now, callback, ct); } } public async Task> QueryIdsAsync(DomainId appId, HashSet ids, CancellationToken ct) { using (Profiler.TraceMethod()) { return await queryByIds.QueryIdsAsync(appId, ids, ct); } } public async Task> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode filterNode, CancellationToken ct) { using (Profiler.TraceMethod()) { return await queryByQuery.QueryIdsAsync(appId, schemaId, filterNode, ct); } } public async Task HasReferrersAsync(DomainId appId, DomainId contentId, CancellationToken ct) { using (Profiler.TraceMethod()) { return await queryReferrers.CheckExistsAsync(appId, contentId, ct); } } public async Task FindVersionAsync(DomainId documentId) { var result = await Collection.Find(x => x.DocumentId == documentId).Only(x => x.Version).FirstOrDefaultAsync(); return result?["vs"].AsInt64 ?? EtagVersion.Empty; } public Task UpsertVersionedAsync(DomainId documentId, long oldVersion, MongoContentEntity entity) { return Collection.UpsertVersionedAsync(documentId, oldVersion, entity.Version, entity); } public Task RemoveAsync(DomainId documentId) { return Collection.DeleteOneAsync(x => x.DocumentId == documentId); } public Task InsertManyAsync(IReadOnlyList entities) { if (entities.Count == 0) { return Task.CompletedTask; } return Collection.InsertManyAsync(entities, InsertUnordered); } } }