using Microsoft.Extensions.Logging; using MongoDB.Driver; namespace StellaOps.Feedser.Storage.Mongo.Documents; public sealed class DocumentStore : IDocumentStore { private readonly IMongoCollection _collection; private readonly ILogger _logger; public DocumentStore(IMongoDatabase database, ILogger logger) { _collection = (database ?? throw new ArgumentNullException(nameof(database))) .GetCollection(MongoStorageDefaults.Collections.Document); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task UpsertAsync(DocumentRecord record, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(record); var document = DocumentDocumentExtensions.FromRecord(record); var filter = Builders.Filter.Eq(x => x.SourceName, record.SourceName) & Builders.Filter.Eq(x => x.Uri, record.Uri); var options = new FindOneAndReplaceOptions { IsUpsert = true, ReturnDocument = ReturnDocument.After, }; var replaced = await _collection.FindOneAndReplaceAsync(filter, document, options, cancellationToken).ConfigureAwait(false); _logger.LogDebug("Upserted document {Source}/{Uri}", record.SourceName, record.Uri); return (replaced ?? document).ToRecord(); } public async Task FindBySourceAndUriAsync(string sourceName, string uri, CancellationToken cancellationToken) { ArgumentException.ThrowIfNullOrEmpty(sourceName); ArgumentException.ThrowIfNullOrEmpty(uri); var filter = Builders.Filter.Eq(x => x.SourceName, sourceName) & Builders.Filter.Eq(x => x.Uri, uri); var document = await _collection.Find(filter).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); return document?.ToRecord(); } public async Task FindAsync(Guid id, CancellationToken cancellationToken) { var document = await _collection.Find(x => x.Id == id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); return document?.ToRecord(); } public async Task UpdateStatusAsync(Guid id, string status, CancellationToken cancellationToken) { ArgumentException.ThrowIfNullOrEmpty(status); var update = Builders.Update .Set(x => x.Status, status) .Set(x => x.LastModified, DateTime.UtcNow); var result = await _collection.UpdateOneAsync(x => x.Id == id, update, cancellationToken: cancellationToken).ConfigureAwait(false); return result.MatchedCount > 0; } }