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;
///
/// Represents a MongoDB repository for entities,
/// implementing the contract defined by .
///
/// The type of the section entity managed by this repository.
public class SectionRepository : MongoRepository, ISectionRepository
{
private readonly ApiSettings _apiSettings;
public SectionRepository(IOptions apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
_apiSettings = apiSettings.Value;
} //For testing
///
/// Gets the configuration sections collection name from the API settings, falling back to a default value when not configured.
///
/// The configured collection name, or "config_sections" if _apiSettings.ConfigSections is null.
public override string GetCollectionName()
{
return _apiSettings.ConfigSections ?? "config_sections";
}
///
/// Retrieves all documents from the underlying collection by querying with an empty filter.
///
/// A task that represents the asynchronous operation, containing a list of all documents found in the collection.
public async Task> GetAll()
{
var result = await Collection.FindAsync(Builders.Filter.Empty);
return result.ToList();
}
///
/// Finds and returns the first whose SectionTitle matches the specified section value.
///
/// The section title used to look up the matching .
/// The first matching , or null if no section with the given title is found.
public async Task FindBySection(string section)
{
var result = await Collection.FindAsync(Builders.Filter.Eq(x => x.SectionTitle, section));
return await result.FirstOrDefaultAsync();
}
///
/// Asynchronously retrieves the first whose PointOfCare matches the specified value.
///
/// The point of care identifier used to filter the sections.
/// The first matching , or null if no section is found.
public async Task FindByPointOfCare(string pointOfCare)
{
var result = await Collection.FindAsync(Builders.Filter.Eq(x => x.PointOfCare, pointOfCare));
return await result.FirstOrDefaultAsync();
}
///
/// Finds a by its unique identifier in the underlying collection.
/// Returns null when no matching section exists.
///
/// The unique identifier of the section to retrieve.
/// A task containing the matching if found; otherwise, null.
public async Task FindById(string id)
{
var result = await Collection.FindAsync(Builders.Filter.Eq(x => x.Id, id));
return await result.FirstOrDefaultAsync();
}
///
/// Asynchronously retrieves a by its identifier from the collection, returning null when no matching document is found.
///
/// The identifier of the section to locate.
/// A instance if a document with the given identifier exists; otherwise, null.
public async Task FindById(object id)
{
var result = await Collection.FindAsync(Builders.Filter.Eq(x => x._id, id));
return await result.FirstOrDefaultAsync();
}
///
/// 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.
///
/// The patient location containing the unit name and bed used to locate the corresponding sections.
/// 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.
public async Task> 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();
}
///
/// Asynchronously inserts a single into the collection and returns the persisted entity retrieved by its identifier.
/// If the insertion fails, the error is logged and the method returns null instead of propagating the exception.
///
/// The section to insert into the collection.
/// The inserted on success, or null if the operation fails.
public async Task 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;
}
}
///
/// Updates an existing in the data store and returns the updated document.
/// If no section with the specified identifier is found, the method returns .
///
/// The section containing the identifier of the record to update and the new field values to persist.
/// The updated as it appears after the update, or if no matching record was found.
public async Task UpdateSection(Section section)
{
var filter = Builders.Filter.Eq("Id", section.Id);
var update = Builders.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 { ReturnDocument = ReturnDocument.After });
}
}