Files
adas-core/adas-core.Infrastructure/Repositories/DischargeRepository.cs
T

486 lines
23 KiB
C#

using adas_core.Application.Exceptions;
using adas_core.Application.Repositories.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Masters;
using adas_core.Domain.Models.MongoModels;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using Serilog;
using MongoUtils = adas_core.Infrastructure.Utils.MongoUtils;
namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing Discharge entities in MongoDB. Provides methods for CRUD operations and specific queries related to discharges.
/// </summary>
/// <!-- aidoc:v1 sig=6c520ba -->
public class DischargeRepository : MongoRepository<Discharge>, IDischargeRepository
{
private readonly ApiSettings _apiSettings;
/// <summary>
/// Initializes a new instance of the DischargeRepository class with the specified API settings and MongoDB database.
/// </summary>
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <!-- aidoc:v1 sig=37f77f4 body=12fddac -->
public DischargeRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
_apiSettings = apiSettings.Value;
}
/// <summary>
/// Gets the name of the MongoDB collection for discharges from the API settings.
/// </summary>
/// <returns>The name of the MongoDB collection for discharges.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=d8f9298 -->
public override string GetCollectionName()
{
return _apiSettings.Discharges;
}
/// <summary>
/// Inserts a new discharge record into the MongoDB collection. Sets the discharge date to the current UTC time before insertion.
/// </summary>
/// <param name="discharge">The discharge record to insert.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=e47013f body=e384f70 -->
public override async Task InsertOneAsync(Discharge discharge)
{
try
{
discharge.DischargeDate = DateTime.UtcNow;
await base.InsertOneAsync(discharge);
}
catch (Exception e)
{
Log.Warning("Exception trying to insert discharge: {discharge}. Exception {e}", discharge, e);
}
}
/// <summary>
/// Deletes a discharge record from the MongoDB collection based on the specified ID.
/// </summary>
/// <param name="id">The ID of the discharge record to delete.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=3de1ad6 body=7e7d153 -->
public async Task Delete(ObjectId id)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(x => x.Id, id);
await Collection.DeleteOneAsync(filter, null);
}
catch (Exception e)
{
Log.Error("Exception trying to delete discharge: {id}. Exception {e}", id, e);
throw;
}
}
/// <summary>
/// Updates an existing discharge record in the MongoDB collection. If the update operation fails, a ConflictException is thrown.
/// </summary>
/// <param name="discharge">The discharge record to update.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="ConflictException"></exception>
/// <!-- aidoc:v1 sig=1ecc041 body=d41cd7e -->
public async Task Update(Discharge discharge)
{
try
{
await UpdateOneAsync(discharge.Id, discharge);
}
catch (Exception e)
{
Log.Error("Exception trying to update discharge: {discharge}. Exception {e}", discharge, e);
throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed);
}
}
/// <summary>
/// Updates the unit name of a discharge record in the MongoDB collection based on the specified ID. If the update operation fails, an error is logged.
/// </summary>
/// <param name="id">The ID of the discharge record to update.</param>
/// <param name="unit">The new unit name to set.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc-review:v1 severity=high kind=stale_summary
/// "The summary claims 'If the update operation fails, an error is logged,' but the method body contains no try/catch, error handling, or logging — only an unawaited UpdateOneAsync call." -->
public async Task UpdateUnit(ObjectId id, string unit)
{
var filterBuilder = Builders<Discharge>.Filter;
var filter = filterBuilder.Eq(p => p.Id, id);
var update = Builders<Discharge>.Update
.Set(p => p.PatientLocation!.UnitName, unit);
await Collection.UpdateOneAsync(filter, update);
}
/// <summary>
/// Updates the patient information of a discharge record in the MongoDB collection based on the specified ID. If the update operation fails, an error is logged.
/// </summary>
/// <param name="id">The ID of the discharge record to update.</param>
/// <param name="patient">The new patient information to set.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary claims 'If the update operation fails, an error is logged', but the code has no try-catch or logging mechanism — any failure would propagate as an exception." -->
public async Task UpdatePatient(ObjectId id, Patient patient)
{
var filterBuilder = Builders<Discharge>.Filter;
var filter = filterBuilder.Eq(p => p.Id, id);
var update = Builders<Discharge>.Update
.Set(p => p.Patient, patient);
await Collection.UpdateOneAsync(filter, update);
}
/// <summary>
/// Finds and retrieves all discharge records from the MongoDB collection. If an error occurs during retrieval, an error is logged and an empty list is returned.
/// </summary>
/// <returns>A task representing the asynchronous operation, containing a list of all discharge records.</returns>
/// <!-- aidoc:v1 sig=87546e9 body=77eea29 -->
public async Task<IEnumerable<Discharge>> FindAll()
{
try
{
var result = await Collection.FindAsync(_ => true);
return await result.ToListAsync();
}
catch (Exception ex)
{
Log.Error("Error getting all discharges. Exception: {ex}", ex);
return [];
}
}
/// <summary>
/// Finds and retrieves a discharge record from the MongoDB collection based on the specified ID. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="id">The ID of the discharge record to retrieve.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record if found, or null if not found or an error occurs.</returns>
/// <!-- aidoc:v1 sig=16a9670 body=05bd4d2 -->
public async Task<Discharge?> FindById(ObjectId id)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(p => p.Id, id);
var result = await Collection.FindAsync(filter);
return await result.FirstOrDefaultAsync();
}
catch (Exception ex)
{
Log.Error("Error searching discharge by id: {id}. Exception: {ex}", id, ex);
return null;
}
}
/// <summary>
/// Finds and retrieves discharge records from the MongoDB collection based on the specified unit name. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="unit">The unit name to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified unit name, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=26a3520 body=9cee09f -->
public async Task<IEnumerable<Discharge>?> FindByUnit(string unit)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(p => p.PatientLocation!.UnitName, unit);
var result = await Collection.FindAsync(filter);
return result.ToEnumerable();
}
catch (Exception ex)
{
Log.Error("Error searching discharge by Unit id: {unit}. Exception: {ex}", unit, ex);
return null;
}
}
/// <summary>
/// Counts the number of discharge records in the MongoDB collection that match the specified unit ID. If an error occurs during counting, an error is logged and 0 is returned.
/// </summary>
/// <param name="unitId">The ID of the unit to count discharge records for.</param>
/// <returns>A task representing the asynchronous operation, containing the count of discharge records matching the specified unit ID, or 0 if an error occurs.</returns>
/// <!-- aidoc:v1 sig=baa8175 body=1403f2e -->
public async Task<long> CountByUnitId(ObjectId unitId)
{
try
{
return await Collection.CountDocumentsAsync(
Builders<Discharge>.Filter.Eq(p => p.UnitId, unitId));
}
catch (Exception e)
{
Log.Error(e.Message);
return 0;
}
}
/// <summary>
/// Finds and retrieves discharge records from the MongoDB collection based on the specified destination. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="destination">The destination to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified destination, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=7f6b4ab body=f403711 -->
public async Task<IEnumerable<Discharge>?> FindByDestination(string destination)
{
try
{
var filter = string.IsNullOrEmpty(destination)
? Builders<Discharge>.Filter.Empty
: Builders<Discharge>.Filter.Eq(p => p.Destination, destination);
var result = await Collection.FindAsync(filter);
return result.ToEnumerable();
}
catch (Exception ex)
{
Log.Error("Error searching discharges by destination: {destination}. Exception: {ex}", destination, ex);
return null;
}
}
/// <summary>
/// Finds and retrieves discharge records from the MongoDB collection based on the specified unit IDs. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="unitIds">The IDs of the units to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified unit IDs, or null if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states that on error an error is logged and null is returned, but the method has no try/catch and no logging; exceptions would propagate, not be swallowed and converted to null." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "The returns tag claims 'null if an error occurs', but the implementation never returns null on error (no exception handling); it only returns the ToListAsync result." -->
public async Task<IEnumerable<Discharge>?> GetDischargesByUnitIds(IEnumerable<ObjectId>? unitIds)
{
var filterUnit = Builders<Discharge>.Filter.In("unitId", unitIds);
return await Collection.Find(filterUnit).ToListAsync();
}
/// <summary>
/// Finds and retrieves discharge records from the MongoDB collection based on the specified Point of Care ID. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="pocId">The ID of the Point of Care to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified Point of Care ID, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=13fd339 body=8de0a6c -->
public async Task<IEnumerable<Discharge>?> FindByPoCId(ObjectId pocId)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(p => p.PointOfCareId, pocId);
var result = await Collection.FindAsync(filter);
return result.ToEnumerable();
}
catch (Exception ex)
{
Log.Error("Error searching discharges by PointOfCare: {destination}. Exception: {ex}", pocId, ex);
return null;
}
}
/// <summary>
/// Finds and retrieves discharge records from the MongoDB collection based on the specified service. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="service">The service to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified service, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=8f5cc53 body=fa9829a -->
public async Task<IEnumerable<Discharge>?> FindByService(string service)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(p => p.Service, service);
var result = await Collection.FindAsync(filter);
return result.ToEnumerable();
}
catch (Exception ex)
{
Log.Error("Error searching discharges by service: {origin}. Exception: {ex}", service, ex);
return null;
}
}
/// <summary>
/// Finds and retrieves a discharge record from the MongoDB collection based on the specified patient location. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="location">The patient location to search for.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record matching the specified patient location, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=d6f8db9 body=a619aca -->
public async Task<Discharge?> GetDischargeByLocation(PatientLocation location)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(p => p.PatientLocation, location);
var result = await Collection.FindAsync(filter);
return await result.FirstOrDefaultAsync();
}
catch (Exception e)
{
Log.Error($"Unable to get discharge by location on repository Exception: {e}");
return null;
}
}
/// <summary>
/// Finds and retrieves a discharge record from the MongoDB collection based on the specified Point of Care ID. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="id">The ID of the Point of Care to search for.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record matching the specified Point of Care ID, or null if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "Returns tag only mentions null in the error case, but FirstOrDefaultAsync also returns null when no matching discharge record is found" -->
public async Task<Discharge?> GetDischargeByPointOfCareId(ObjectId id)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(p => p.PointOfCareId, id);
var result = await Collection.FindAsync(filter);
return await result.FirstOrDefaultAsync();
}
catch (Exception e)
{
Log.Error($"Unable to get discharge by location on repository Exception: {e}");
return null;
}
}
/// <summary>
/// Updates the master list options for discharge records in the MongoDB collection based on the specified unit IDs, update option, and master list type.
/// The method parses the master list type and performs updates accordingly. If an error occurs during the update process, an error is logged and an empty list is returned.
/// </summary>
/// <param name="unitIds">The list of unit IDs for which to update the master list options.</param>
/// <param name="opt">The update option specifying the changes to be applied to the master list.</param>
/// <param name="typeName">The name of the master list type to be updated.</param>
/// <returns>A task representing the asynchronous operation, containing the updated discharge records, or an empty list if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states the method 'performs updates accordingly', but the switch cases are empty (only comments) and no actual update logic is present in the code." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary claims 'If an error occurs during the update process, an error is logged and an empty list is returned', but there is no error handling or logging in the code, and the method always returns an empty list." -->
public Task<IEnumerable<Discharge>> UpdateMasterListOption(List<ObjectId> unitIds, UpdateOptionMasterListDto opt,
string typeName)
{
var isParsed = Enum.TryParse<MasterListType>(typeName, out var parsedTypeName);
if (isParsed)
switch (parsedTypeName)
{
case MasterListType.DestinationList:
// destination
// destinationOption
break;
case MasterListType.ServiceList:
// service
break;
}
return Task.FromResult<IEnumerable<Discharge>>(new List<Discharge>());
}
/// <summary>
/// Deletes discharge records from the MongoDB collection based on the specified unit ID. If an error occurs during deletion, an error is logged and false is returned; otherwise, true is returned upon successful deletion.
/// </summary>
/// <param name="unitId">The ID of the unit for which to delete discharge records.</param>
/// <returns>A task representing the asynchronous operation, containing true if the deletion was successful, or false if an error occurred.</returns>
/// <!-- aidoc:v1 sig=d4333b3 body=a16e555 -->
public async Task<bool> DeleteByUnitId(ObjectId unitId)
{
try
{
var filter = Builders<Discharge>.Filter.Where(p => p.UnitId == unitId);
await Collection.DeleteManyAsync(filter);
return true;
}
catch (Exception ex)
{
Log.Error(ex.Message);
return false;
}
}
/// <summary>
/// Deletes master list options for discharge records in the MongoDB collection based on the specified unit IDs, update option, and master list type.
/// </summary>
/// <param name="unitIds">The list of unit IDs for which to delete master list options.</param>
/// <param name="opt">The update option specifying the changes to be applied to the master list.</param>
/// <param name="typeName">The name of the master list type to be updated.</param>
/// <returns>A task representing the asynchronous operation, containing the updated discharge records, or an empty list if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_param_role
/// "The <param name=\"opt\"> description calls it 'The update option specifying the changes to be applied to the master list', but the method is a delete operation (DeleteMasterListOption), so this should describe a delete option, not an update option." -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_param_role
/// "The <param name=\"typeName\"> description says 'The name of the master list type to be updated', but the method performs deletion, not update." -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_returns
/// "The <returns> description says 'containing the updated discharge records', but the method deletes and returns discharge records, it does not update them." -->
public Task<IEnumerable<Discharge>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt, string typeName)
{
var isParsed = Enum.TryParse<MasterListType>(typeName, out var parsedTypeName);
if (isParsed)
switch (parsedTypeName)
{
case MasterListType.DestinationList:
// destination
// destinationOption
break;
case MasterListType.ServiceList:
// service
break;
}
return Task.FromResult<IEnumerable<Discharge>>(new List<Discharge>());
}
/// <summary>
/// Finds and retrieves a discharge record from the MongoDB collection based on the specified patient ID. If an error occurs during retrieval, an error is logged and null is returned.
/// </summary>
/// <param name="patientId">The ID of the patient for which to retrieve the discharge record.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record if found, or null if an error occurs or the record is not found.</returns>
/// <!-- aidoc:v1 sig=e4173bb body=474ce38 -->
public async Task<Discharge?> GetByPatientId(ObjectId patientId)
{
try
{
var filter = Builders<Discharge>.Filter.Eq(p => p.PatientId, patientId);
var result = await Collection.FindAsync(filter);
return await result.FirstOrDefaultAsync();
}
catch (Exception e)
{
Log.Error($"Unable to get discharge by patient id on repository Exception: {e}");
return null;
}
}
/// <summary>
/// Creates indexes for the MongoDB collection based on the specified fields and options.
/// The method ensures that unique indexes are created for the medical discharge and admin discharge fields, with a partial filter expression to only include documents where both fields exist.
/// If an error occurs during index creation, an error is logged.
/// </summary>
/// <returns></returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_summary
/// "Summary claims 'If an error occurs during index creation, an error is logged,' but the method body has no try/catch or logging code; error handling is delegated to MongoUtils.EnsureIndexes." -->
public override async Task CreateIndexes()
{
var optionsUq = new CreateIndexOptions<Discharge>
{
Background = true,
Unique = true,
PartialFilterExpression = Builders<Discharge>.Filter.Exists(p => p.MedicalDischarge) &
Builders<Discharge>.Filter.Exists(p => p.AdminDischarge)
};
var indexes = new List<CreateIndexModel<Discharge>>
{
new("{ medicalDischarge: 1 }", optionsUq),
new("{ adminDischarge: 1 }", optionsUq)
};
await MongoUtils.EnsureIndexes(Collection, indexes);
}
}