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 and returns the updated version.
///
/// The document with the updated data. Its _Id is used to locate the existing document.
///
/// The updated document if the replacement was successful; otherwise, null if no matching document was found.
///
public virtual async Task ReplaceOneAsync(TDocument document)
{
var filter = Builders.Filter.Eq(doc => doc._Id, document._Id);
var options = new FindOneAndReplaceOptions
{
ReturnDocument = ReturnDocument.After // return the updated document
};
var result = await _collection.FindOneAndReplaceAsync(filter, document, options);
return result;
}
///
/// 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));
}
///
/// Executes an aggregation pipeline and returns the first document in the result asynchronously.
///
/// The type of the output document you expect from the pipeline.
/// The aggregation pipeline definition to execute.
/// The first document from the aggregation result, or null if none found.
public virtual Task FindOnePipelineAsync(PipelineDefinition pipeline)
{
return Task.Run(() => _collection.Aggregate(pipeline).FirstOrDefaultAsync());
}
}
}