using MongoDB.Bson; using MongoDB.Driver; namespace FozFc.Api.Infrastructure.Mongo; public sealed class DocumentRepository : IDocumentRepository { private readonly MongoContext _context; public DocumentRepository(MongoContext context) => _context = context; private static string IsoNow() => DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); public static string NewId() => ObjectId.GenerateNewId().ToString(); public async Task> FindAsync( string collection, BsonDocument filter, BsonDocument? sort, int limit, CancellationToken ct = default) { var find = _context.Collection(collection).Find(filter); if (sort is { ElementCount: > 0 }) find = find.Sort(sort); if (limit > 0) find = find.Limit(limit); return await find.ToListAsync(ct); } public Task GetByIdAsync(string collection, string id, CancellationToken ct = default) => FindOneByFieldAsync(collection, "_id", id, ct); public async Task FindOneByFieldAsync(string collection, string field, BsonValue value, CancellationToken ct = default) { var filter = new BsonDocument(field, value); return await _context.Collection(collection).Find(filter).FirstOrDefaultAsync(ct); } public Task InsertAsync(string collection, BsonDocument document, CancellationToken ct = default) => _context.Collection(collection).InsertOneAsync(document, cancellationToken: ct); public async Task UpsertAsync( string collection, string id, BsonDocument body, bool setUpdatedAt, CancellationToken ct = default) { body.Remove("id"); body.Remove("_id"); var now = IsoNow(); if (setUpdatedAt) body["updatedAt"] = now; var update = new BsonDocument { { "$set", body } }; if (!body.Contains("createdAt")) { update["$setOnInsert"] = new BsonDocument("createdAt", now); } await _context.Collection(collection).UpdateOneAsync( new BsonDocument("_id", id), update, new UpdateOptions { IsUpsert = true }, ct); return await GetByIdAsync(collection, id, ct) ?? body; } public async Task UpdateAsync(string collection, string id, BsonDocument body, CancellationToken ct = default) { body.Remove("id"); body.Remove("_id"); body["updatedAt"] = IsoNow(); var result = await _context.Collection(collection).UpdateOneAsync( new BsonDocument("_id", id), new BsonDocument("$set", body), cancellationToken: ct); return result.MatchedCount > 0; } public Task DeleteAsync(string collection, string id, CancellationToken ct = default) => _context.Collection(collection).DeleteOneAsync(new BsonDocument("_id", id), ct); }