160 lines
8.2 KiB
C#
160 lines
8.2 KiB
C#
using adas_core.Application.Repositories.Interfaces;
|
|
using adas_core.Domain.Models;
|
|
using adas_core.Domain.Models.AppSettings;
|
|
using adas_core.Domain.Models.MongoModels;
|
|
using Microsoft.Extensions.Options;
|
|
using MongoDB.Driver;
|
|
using Newtonsoft.Json;
|
|
using Serilog;
|
|
|
|
namespace adas_core.Infrastructure.Repositories;
|
|
|
|
/// <summary>
|
|
/// Represents a MongoDB repository for <typeparamref name="Section"/> entities,
|
|
/// implementing the contract defined by <see cref="ISectionRepository"/>.
|
|
/// </summary>
|
|
/// <typeparam name="Section">The type of the section entity managed by this repository.</typeparam>
|
|
public class SectionRepository : MongoRepository<Section>, ISectionRepository
|
|
{
|
|
private readonly ApiSettings _apiSettings;
|
|
|
|
public SectionRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
|
|
{
|
|
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
|
|
_apiSettings = apiSettings.Value;
|
|
} //For testing
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Gets the configuration sections collection name from the API settings, falling back to a default value when not configured.
|
|
/// </summary>
|
|
/// <returns>The configured collection name, or "config_sections" if <c>_apiSettings.ConfigSections</c> is null.</returns>
|
|
public override string GetCollectionName()
|
|
{
|
|
return _apiSettings.ConfigSections ?? "config_sections";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves all <see cref="Section"/> documents from the underlying collection by querying with an empty filter.
|
|
/// </summary>
|
|
/// <returns>A task that represents the asynchronous operation, containing a list of all <see cref="Section"/> documents found in the collection.</returns>
|
|
public async Task<List<Section>> GetAll()
|
|
{
|
|
var result = await Collection.FindAsync(Builders<Section>.Filter.Empty);
|
|
|
|
return result.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds and returns the first <see cref="Section"/> whose <c>SectionTitle</c> matches the specified section value.
|
|
/// </summary>
|
|
/// <param name="section">The section title used to look up the matching <see cref="Section"/>.</param>
|
|
/// <returns>The first matching <see cref="Section"/>, or <c>null</c> if no section with the given title is found.</returns>
|
|
public async Task<Section?> FindBySection(string section)
|
|
{
|
|
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.SectionTitle, section));
|
|
|
|
return await result.FirstOrDefaultAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously retrieves the first <see cref="Section"/> whose <c>PointOfCare</c> matches the specified value.
|
|
/// </summary>
|
|
/// <param name="pointOfCare">The point of care identifier used to filter the sections.</param>
|
|
/// <returns>The first matching <see cref="Section"/>, or <c>null</c> if no section is found.</returns>
|
|
public async Task<Section?> FindByPointOfCare(string pointOfCare)
|
|
{
|
|
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.PointOfCare, pointOfCare));
|
|
|
|
return await result.FirstOrDefaultAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds a <see cref="Section"/> by its unique identifier in the underlying collection.
|
|
/// Returns <c>null</c> when no matching section exists.
|
|
/// </summary>
|
|
/// <param name="id">The unique identifier of the section to retrieve.</param>
|
|
/// <returns>A task containing the matching <see cref="Section"/> if found; otherwise, <c>null</c>.</returns>
|
|
public async Task<Section?> FindById(string id)
|
|
{
|
|
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.Id, id));
|
|
|
|
return await result.FirstOrDefaultAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously retrieves a <see cref="Section"/> by its identifier from the collection, returning <c>null</c> when no matching document is found.
|
|
/// </summary>
|
|
/// <param name="id">The identifier of the section to locate.</param>
|
|
/// <returns>A <see cref="Section"/> instance if a document with the given identifier exists; otherwise, <c>null</c>.</returns>
|
|
public async Task<Section?> FindById(object id)
|
|
{
|
|
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x._id, id));
|
|
return await result.FirstOrDefaultAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the active sections associated with the specified patient location by matching the unit name and bed against the section hierarchy.
|
|
/// Filtering is performed in memory after retrieving all sections because the underlying query does not support direct filtering on the collection's point of care field.
|
|
/// A section is considered matching when its point of care equals the unit name and contains a box with a null point of care for the requested bed, or when it contains a box whose point of care equals the unit name for the requested bed.
|
|
/// </summary>
|
|
/// <param name="location">The patient location containing the unit name and bed used to locate the corresponding sections.</param>
|
|
/// <returns>A task that represents the asynchronous operation. The task result contains a list of sections matching the provided patient location; an empty list is returned when no matching sections are found.</returns>
|
|
public async Task<List<Section>> FindByLocation(PatientLocation location)
|
|
{
|
|
//can not filter to Collection the where condition, it throws System.InvalidOperationException: '{}.pointOfCare is not supported.'
|
|
var sections = await GetAll();
|
|
|
|
return sections.Where(section =>
|
|
(section.PointOfCare == location.UnitName && section.Items.Any(item =>
|
|
item.Boxes.Any(box => box.PointOfCare == null && box.Bed == location.Bed && box.IsActive))) ||
|
|
section.Items.Any(item =>
|
|
item.Boxes.Any(box =>
|
|
box.PointOfCare == location.UnitName && box.Bed == location.Bed && box.IsActive))).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously inserts a single <see cref="Section"/> into the collection and returns the persisted entity retrieved by its identifier.
|
|
/// If the insertion fails, the error is logged and the method returns <c>null</c> instead of propagating the exception.
|
|
/// </summary>
|
|
/// <param name="section">The section to insert into the collection.</param>
|
|
/// <returns>The inserted <see cref="Section"/> on success, or <c>null</c> if the operation fails.</returns>
|
|
public async Task<Section?> InsertOneSection(Section section)
|
|
{
|
|
try
|
|
{
|
|
await Collection.InsertOneAsync(section);
|
|
return await FindById(section.Id);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error("Error inserting section: {section}. Exception: {ex}",
|
|
JsonConvert.SerializeObject(section, Formatting.Indented), ex);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Updates an existing <see cref="Section"/> in the data store and returns the updated document.
|
|
/// If no section with the specified identifier is found, the method returns <see langword="null"/>.
|
|
/// </summary>
|
|
/// <param name="section">The section containing the identifier of the record to update and the new field values to persist.</param>
|
|
/// <returns>The updated <see cref="Section"/> as it appears after the update, or <see langword="null"/> if no matching record was found.</returns>
|
|
public async Task<Section?> UpdateSection(Section section)
|
|
{
|
|
var filter = Builders<Section>.Filter.Eq("Id", section.Id);
|
|
var update = Builders<Section>.Update
|
|
.Set(c => c.Id, section.Id)
|
|
.Set(c => c.PointOfCare, section.PointOfCare)
|
|
.Set(c => c.SectionTitle, section.SectionTitle)
|
|
.Set(c => c.Configuration, section.Configuration)
|
|
.Set(c => c.Items, section.Items);
|
|
|
|
return await Collection.FindOneAndUpdateAsync(filter, update,
|
|
new FindOneAndUpdateOptions<Section, Section> { ReturnDocument = ReturnDocument.After });
|
|
}
|
|
} |