using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Linq; using System.Linq.Expressions; using System.Reflection; namespace Core.Blueprint.Mongo { /// /// Provides methods for interacting with a MongoDB collection for a specific document type. /// Inherits from and implements . /// This class encapsulates common database operations such as querying, inserting, updating, and deleting documents. /// /// The type of document stored in the collection, which must implement . public class CollectionRepository(IMongoDatabase database) : ICollectionsRepository where TDocument : IDocument { private IMongoCollection _collection; /// /// Initializes the MongoDB collection based on the attribute /// applied to the type. Throws an exception if the attribute is not present. /// public void CollectionInitialization() { var collectionAttribute = typeof(TDocument).GetCustomAttribute(); if (collectionAttribute == null) { throw new InvalidOperationException($"The class {typeof(TDocument).Name} is missing the CollectionAttributeName attribute."); } string collectionName = collectionAttribute.Name; _collection = database.GetCollection(collectionName); } /// /// Returns all documents from the collection as an enumerable list. /// /// A task that represents the asynchronous operation. The task result contains an enumerable list of documents. public virtual async ValueTask> AsQueryable() { return await _collection.AsQueryable().ToListAsync(); } /// /// Filters documents in the collection based on the provided filter expression. /// /// A lambda expression that defines the filter criteria for the documents. /// A task that represents the asynchronous operation. The task result contains a list of documents that match the filter. public virtual async Task> FilterBy( Expression> filterExpression) { var objectResult = await _collection.FindAsync(filterExpression).ConfigureAwait(false); return objectResult.ToList(); } /// /// Filters documents in the collection based on the provided filter and projection expressions. /// Projects the filtered documents into a new type. /// /// The type to project the documents into. /// A lambda expression that defines the filter criteria for the documents. /// A lambda expression that defines how the documents should be projected. /// An enumerable collection of projected documents. public virtual IEnumerable FilterBy( Expression> filterExpression, Expression> projectionExpression) { return _collection.Find(filterExpression).Project(projectionExpression).ToEnumerable(); } /// /// Finds a single document that matches the provided filter expression. /// /// A lambda expression that defines the filter criteria for the document. /// The document that matches the filter, or null if no document is found. public virtual TDocument FindOne(Expression> filterExpression) { return _collection.Find(filterExpression).FirstOrDefault(); } /// /// Filters documents in the collection based on the provided MongoDB filter definition. /// /// A filter definition for MongoDB query. /// A task that represents the asynchronous operation. The task result contains a list of documents that match the filter. public virtual async Task> FilterByMongoFilterAsync(FilterDefinition filterDefinition) { var objectResult = await _collection.Find(filterDefinition).ToListAsync().ConfigureAwait(false); return objectResult; } /// /// Asynchronously finds a single document that matches the provided filter expression. /// /// A lambda expression that defines the filter criteria for the document. /// A task that represents the asynchronous operation. The task result contains the document that matches the filter, or null if no document is found. public virtual Task FindOneAsync(Expression> filterExpression) { return Task.Run(() => _collection.Find(filterExpression).FirstOrDefaultAsync()); } /// /// Finds a document by its unique identifier (ID). /// /// The unique identifier of the document. /// The document that matches the specified ID, or null if no document is found. public virtual TDocument FindById(string id) { var filter = Builders.Filter.Eq(doc => doc._Id, id); return _collection.Find(filter).SingleOrDefault(); } /// /// Asynchronously finds a document by its unique identifier (ID). /// /// The unique identifier of the document. /// A task that represents the asynchronous operation. The task result contains the document that matches the specified ID, or null if no document is found. public virtual Task FindByIdAsync(string id) { return Task.Run(() => { var objectId = new ObjectId(id); var filter = Builders.Filter.Eq(doc => doc._Id, id); return _collection.Find(filter).SingleOrDefaultAsync(); }); } /// /// Inserts a single document into the collection. /// /// The document to insert. public virtual void InsertOne(TDocument document) { _collection.InsertOne(document); } /// /// Asynchronously inserts a single document into the collection. /// /// The document to insert. /// A task that represents the asynchronous operation. public virtual Task InsertOneAsync(TDocument document) { return Task.Run(() => _collection.InsertOneAsync(document)); } /// /// Inserts multiple documents into the collection. /// /// The collection of documents to insert. public void InsertMany(ICollection documents) { _collection.InsertMany(documents); } /// /// Asynchronously inserts multiple documents into the collection. /// /// The collection of documents to insert. /// A task that represents the asynchronous operation. public virtual async Task InsertManyAsync(ICollection documents) { await _collection.InsertManyAsync(documents); } /// /// Replaces an existing document in the collection. /// /// The document with the updated data. public void ReplaceOne(TDocument document) { var filter = Builders.Filter.Eq(doc => doc._Id, document._Id); _collection.FindOneAndReplace(filter, document); } /// /// Asynchronously replaces an existing document in the collection. /// /// The document with the updated data. /// A task that represents the asynchronous operation. public virtual async Task ReplaceOneAsync(TDocument document) { var filter = Builders.Filter.Eq(doc => doc._Id, document._Id); await _collection.FindOneAndReplaceAsync(filter, document); } /// /// Deletes a single document from the collection based on the provided filter expression. /// /// A lambda expression that defines the filter criteria for the document to delete. public void DeleteOne(Expression> filterExpression) { _collection.FindOneAndDelete(filterExpression); } /// /// Asynchronously deletes a single document from the collection based on the provided filter expression. /// /// A lambda expression that defines the filter criteria for the document to delete. /// A task that represents the asynchronous operation. public async Task DeleteOneAsync(Expression> filterExpression) { return await _collection.FindOneAndDeleteAsync(filterExpression); } /// /// Deletes a single document from the collection based on its unique identifier (ID). /// /// The unique identifier of the document to delete. public void DeleteById(string id) { var objectId = new ObjectId(id); var filter = Builders.Filter.Eq(doc => doc._Id, id); _collection.FindOneAndDelete(filter); } /// /// Asynchronously deletes a single document from the collection based on its unique identifier (ID). /// /// The unique identifier of the document to delete. /// A task that represents the asynchronous operation. public Task DeleteByIdAsync(string id) { return Task.Run(() => { var objectId = new ObjectId(id); var filter = Builders.Filter.Eq(doc => doc._Id, id); _collection.FindOneAndDeleteAsync(filter); }); } /// /// Deletes multiple documents from the collection based on the provided filter expression. /// /// A lambda expression that defines the filter criteria for the documents to delete. public void DeleteMany(Expression> filterExpression) { _collection.DeleteMany(filterExpression); } /// /// Asynchronously deletes multiple documents from the collection based on the provided filter expression. /// /// A lambda expression that defines the filter criteria for the documents to delete. /// A task that represents the asynchronous operation. public Task DeleteManyAsync(Expression> filterExpression) { return Task.Run(() => _collection.DeleteManyAsync(filterExpression)); } } }