using adas_core.Application.Repositories.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.MongoModels;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using Newtonsoft.Json;
using Serilog;
using System.Text.RegularExpressions;
namespace adas_core.Infrastructure.Repositories;
///
/// Represents a repository for managing entities, providing MongoDB-backed data access through the base class and exposing the contract defined by .
///
/// The type of the entity managed by the repository.
/// This class combines a concrete MongoDB repository implementation with a domain-specific interface, enabling standardized persistence operations for relay entities.
public class RelayRepository : MongoRepository, IRelayRepository
{
private readonly ApiSettings _apiSettings;
public RelayRepository(IMongoDatabase database, IOptions apiSettings) : base(database)
{
_apiSettings = apiSettings.Value;
}
///
/// Retrieves the collection name for relays from the API settings configuration.
///
/// The configured relays collection name as specified in the API settings.
public override string GetCollectionName()
{
return _apiSettings.Relays;
}
///
/// Retrieves a from the collection by its identifier, returning the first match or null when no document is found or an error occurs while querying.
///
/// The unique identifier of the relay to look up.
/// The matching , or null if no document matches the identifier or the query fails.
public async Task GetById(ObjectId relayId)
{
try
{
var filter = Builders.Filter.Eq(x => x.Id, relayId);
var result = await Collection.FindAsync(filter, null);
return result.FirstOrDefault();
}
catch (Exception e)
{
Log.Error("Exception trying to get relay by id: {id}. Exception {e}", relayId, e);
return null;
}
}
///
/// Retrieves a list of relays from the collection whose identifiers are contained in the provided configuration list and whose type matches the specified value.
///
/// The collection of relay identifiers used to filter relays by their Id field.
/// The relay type used as an equality filter on the Type field.
/// A list of instances matching both the identifier and type filters; an empty list is returned when no relays match.
public List GetRelayByTypeInList(List configurationRelayList, RelayEnum.Type type)
{
var filterBuilder = Builders.Filter;
var filter = filterBuilder.And(
filterBuilder.In(r => r.Id, configurationRelayList),
filterBuilder.Eq(r => r.Type, type)
);
return Collection.Find(filter).ToList();
}
///
/// Retrieves the entries whose identifiers are contained in the supplied list, returning all matches as a list.
///
/// The collection of values used to match relays by their Id field.
/// A containing the relays whose identifiers are found in ; an empty list is returned when no matching relays exist.
public List GetRelayInList(List configurationRelayList)
{
var filterBuilder = Builders.Filter;
var filter = filterBuilder.And(
filterBuilder.In(r => r.Id, configurationRelayList));
return Collection.Find(filter).ToList();
}
///
/// Retrieves a paginated, sortable set of relays, optionally filtered by a case-insensitive text match on the relay name.
/// When the filter's text is null or empty, no text-based criteria are applied and the result is returned with the default ascending sort by relay name.
///
/// The pagination criteria containing the optional text filter applied against the relay name.
/// A fluent find query for entities, ordered by relay name in ascending order, ready for further pagination.
public IFindFluent GetPaginatedRelays(PaginationFilter filter)
{
var filterBuilder = Builders.Filter;
var sort = Builders.Sort.Ascending("relayName");
var filters = new List>();
if (filter.FilteredRequest == null) return CreateFindFluent(filters, sort);
if (!string.IsNullOrEmpty(filter.FilteredRequest?.Text))
{
var textFilter = filter.FilteredRequest.Text;
var textFilterEscaped = Regex.Escape(textFilter);
filters.Add(
filterBuilder.Or(
filterBuilder.Regex(p => p.RelayName,
new BsonRegularExpression(textFilterEscaped, "i"))
)
);
}
return CreateFindFluent(filters, sort);
}
///
/// Asynchronously inserts a new relay into the collection and returns the persisted entity fetched by its identifier.
/// On failure, the exception is logged and the method returns null instead of propagating the error.
///
/// The relay entity to insert into the collection.
/// The inserted relay retrieved by its identifier, or null if the insertion fails.
public async Task InsertOneRelayAsync(Relay request)
{
try
{
await Collection.InsertOneAsync(request);
return await GetById(request.Id);
}
catch (Exception ex)
{
Log.Error("Error inserting relay: {relay}. Exception: {ex}",
JsonConvert.SerializeObject(request, Formatting.Indented), ex);
return null;
}
}
///
/// Updates an existing relay document identified by the specified object identifier with the provided relay data and returns the updated entity.
///
/// The unique identifier of the relay document to update in the collection.
/// The relay instance containing the new values to apply to the existing document.
/// A task that represents the asynchronous operation, containing the updated after the update, or null if no matching document was found.
public async Task UpdateRelayAsync(ObjectId objectId, Relay relay)
{
var filter = Builders.Filter.Eq("_id", objectId);
var update = Builders.Update
.Set(c => c.Mode, relay.Mode)
.Set(c => c.RelayNumber, relay.RelayNumber)
.Set(c => c.Username, relay.Username)
.Set(c => c.Password, relay.Password)
.Set(c => c.Driver, relay.Driver)
.Set(c => c.Ip, relay.Ip)
.Set(c => c.Port, relay.Port)
.Set(c => c.RelayName, relay.RelayName);
return await Collection.FindOneAndUpdateAsync(filter, update,
new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After });
}
///
/// Retrieves a from the collection whose RelayName matches the specified name.
/// Returns null when no relay with the given name exists in the collection.
///
/// The name of the relay to look up. May be null, in which case the query matches relays with a null name.
/// A containing the matching , or null if no relay with the specified name is found.
public async Task GetByName(string? requestRelayName)
{
var filterBuilder = Builders.Filter;
var filter = filterBuilder.Eq(r => r.RelayName, requestRelayName);
return await Collection.Find(filter).FirstOrDefaultAsync();
}
///
/// Creates a fluent find query for the Relay collection by combining the provided filters with a logical AND, or applying an empty filter when no filters are supplied, and then applying the given sort definition.
///
/// The list of filter definitions to combine; when empty, an empty filter is used to match all documents.
/// The sort definition applied to the query results.
/// An representing the filtered and sorted Relay query.
private IFindFluent CreateFindFluent(List> filters, SortDefinition sort)
{
var combinedFilter = filters.Any()
? Builders.Filter.And(filters)
: Builders.Filter.Empty;
return Collection.Find(combinedFilter).Sort(sort);
}
}