166 lines
7.2 KiB
C#

using Marco.Pms.Model.MongoDBModels.Expenses;
using Marco.Pms.Model.Utilities;
using Microsoft.Extensions.Configuration;
using MongoDB.Bson;
using MongoDB.Driver;
namespace Marco.Pms.Helpers.CacheHelper
{
public class ExpenseCache
{
private readonly IMongoCollection<ExpenseDetailsMongoDB> _collection;
public ExpenseCache(IConfiguration configuration)
{
var connectionString = configuration["MongoDB:ConnectionString"];
var mongoUrl = new MongoUrl(connectionString);
var client = new MongoClient(mongoUrl); // Your MongoDB connection string
var mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name
_collection = mongoDB.GetCollection<ExpenseDetailsMongoDB>("Expenses");
}
public async Task AddExpenseToCacheAsync(ExpenseDetailsMongoDB expense)
{
await _collection.InsertOneAsync(expense);
await InitializeCollectionAsync();
}
public async Task AddExpensesListToCacheAsync(List<ExpenseDetailsMongoDB> expenses)
{
// 1. Add a guard clause to avoid an unnecessary database call for an empty list.
if (expenses == null || !expenses.Any())
{
return;
}
// 2. Perform the insert operation. This is the only responsibility of this method.
await _collection.InsertManyAsync(expenses);
await InitializeCollectionAsync();
}
public async Task<(int totalPages, long totalCount, List<ExpenseDetailsMongoDB> expenseList)> GetExpenseListFromCacheAsync(Guid tenantId, Guid loggedInEmployeeId, bool viewAll,
bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? expenseFilter, string? searchString)
{
var filterBuilder = Builders<ExpenseDetailsMongoDB>.Filter;
var filter = filterBuilder.Empty;
// Permission-based filter
if (!viewAll && viewSelf)
{
filter &= filterBuilder.Eq(e => e.CreatedBy.Id, loggedInEmployeeId.ToString());
}
// Apply filters
if (expenseFilter != null)
{
if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue)
{
filter &= filterBuilder.Gte(e => e.CreatedAt, expenseFilter.StartDate.Value.Date)
& filterBuilder.Lte(e => e.CreatedAt, expenseFilter.EndDate.Value.Date.AddDays(1).AddTicks(-1));
}
if (expenseFilter.ProjectIds?.Any() == true)
{
filter &= filterBuilder.In(e => e.Project.Id, expenseFilter.ProjectIds.Select(p => p.ToString()).ToList());
}
if (expenseFilter.StatusIds?.Any() == true)
{
filter &= filterBuilder.In(e => e.Status.Id, expenseFilter.StatusIds.Select(p => p.ToString()).ToList());
}
if (expenseFilter.PaidById?.Any() == true)
{
filter &= filterBuilder.In(e => e.PaidBy.Id, expenseFilter.PaidById.Select(p => p.ToString()).ToList());
}
if (expenseFilter.CreatedByIds?.Any() == true && viewAll)
{
filter &= filterBuilder.In(e => e.CreatedBy.Id, expenseFilter.CreatedByIds.Select(p => p.ToString()).ToList());
}
}
if (!string.IsNullOrWhiteSpace(searchString))
{
var searchPattern = new BsonRegularExpression(searchString, "i");
// The base text searches remain the same
var searchClauses = new List<FilterDefinition<ExpenseDetailsMongoDB>>
{
filterBuilder.Regex(e => e.Description, searchPattern),
filterBuilder.Regex(e => e.TransactionId, searchPattern)
};
// Build the complex filter for PaidBy.FullName
var paidByFilter = new BsonDocument("$expr",
new BsonDocument("$regexMatch", new BsonDocument
{
{ "input", new BsonDocument("$concat", new BsonArray { "$PaidBy.FirstName", " ", "$PaidBy.LastName" }) },
{ "regex", searchString }, // BsonRegularExpression can't be used here, pass the string
{ "options", "i" } // Case-insensitivity option
})
);
searchClauses.Add(paidByFilter);
// Build the complex filter for CreatedBy.FullName
var createdByFilter = new BsonDocument("$expr",
new BsonDocument("$regexMatch", new BsonDocument
{
{ "input", new BsonDocument("$concat", new BsonArray { "$CreatedBy.FirstName", " ", "$CreatedBy.LastName" }) },
{ "regex", searchString },
{ "options", "i" }
})
);
searchClauses.Add(createdByFilter);
// Combine all clauses with an OR
filter &= filterBuilder.Or(searchClauses);
}
// Total count
var totalCount = await _collection.CountDocumentsAsync(filter);
var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
// Fetch paginated data
var expenses = await _collection
.Find(filter)
.Skip((pageNumber - 1) * pageSize)
.Limit(pageSize)
.SortByDescending(e => e.CreatedAt)
.ToListAsync();
return (totalPages, totalCount, expenses);
}
public async Task<ExpenseDetailsMongoDB> GetExpenseDetailsByIdAsync(Guid id, Guid tenantId)
{
var filter = Builders<ExpenseDetailsMongoDB>.Filter.And(
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.Id, id.ToString()),
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.TenantId, tenantId.ToString())
);
var expense = await _collection.Find(filter).FirstOrDefaultAsync();
return expense;
}
public async Task<bool> DeleteExpenseFromCacheAsync(Guid id, Guid tenantId)
{
var filter = Builders<ExpenseDetailsMongoDB>.Filter.And(
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.Id, id.ToString()),
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.TenantId, tenantId.ToString())
);
var result = await _collection.DeleteOneAsync(filter);
return result.DeletedCount > 0;
}
private async Task InitializeCollectionAsync()
{
var indexKeys = Builders<ExpenseDetailsMongoDB>.IndexKeys.Ascending(x => x.ExpireAt);
var indexOptions = new CreateIndexOptions
{
ExpireAfter = TimeSpan.Zero // required for fixed expiration time
};
var indexModel = new CreateIndexModel<ExpenseDetailsMongoDB>(indexKeys, indexOptions);
await _collection.Indexes.CreateOneAsync(indexModel);
}
}
}