using adas_core.Application.Exceptions;
using adas_core.Application.Repositories.Interfaces;
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;
///
/// Repository for managing camera entities in the MongoDB database. This repository provides methods to create, retrieve, update, and search for cameras based on various criteria.
/// It also includes error handling and logging for debugging purposes.
///
public class CameraRepository : MongoRepository, ICameraRepository
{
private readonly ApiSettings _apiSettings;
///
/// Initializes a new instance of the CameraRepository class with the specified MongoDB database and API settings.
/// The constructor sets up the repository to interact with the "Cameras" collection in the database and allows for configuration through the provided API settings.
///
/// The MongoDB database instance.
/// The API settings containing configuration for the repository.
public CameraRepository(IMongoDatabase database, IOptions apiSettings) : base(database)
{
_apiSettings = apiSettings.Value;
}
///
/// Gets the name of the MongoDB collection that this repository interacts with. In this case, it returns the collection name for cameras as specified in the API settings.
///
/// The name of the MongoDB collection for cameras.
public override string GetCollectionName()
{
return _apiSettings.Cameras;
}
///
/// Retrieves a camera entity from the MongoDB database based on its unique identifier. The method takes an ObjectId as a parameter and returns the corresponding Camera object if found, or null if no matching camera is found.
/// It also includes error handling to log any exceptions that occur during the retrieval process.
///
/// The unique identifier of the camera to retrieve.
/// The Camera object if found; otherwise, null.
public async Task GetById(ObjectId cameraId)
{
try
{
var filter = Builders.Filter.Eq(x => x.Id, cameraId);
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}", cameraId, e);
return null;
}
}
///
/// Retrieves a camera entity from the MongoDB database based on its name. The method takes a string parameter representing the name of the camera and returns the corresponding Camera object if found, or null if no matching camera is found.
///
/// The name of the camera to retrieve.
/// The Camera object if found; otherwise, null.
public async Task GetByName(string name)
{
var filterBuilder = Builders.Filter;
var filter = filterBuilder.Eq(r => r.Name, name);
return await Collection.Find(filter).FirstOrDefaultAsync();
}
///
/// Retrieves a list of camera entities from the MongoDB database based on a list of unique identifiers.
/// The method takes a list of ObjectId values representing the camera IDs and returns a list of Camera objects that match any of the provided IDs.
///
/// The list of camera IDs to retrieve.
/// A list of Camera objects that match the provided IDs.
public List GetCameraInList(List configurationRelayList)
{
var filterBuilder = Builders.Filter;
var filter = filterBuilder.And(
filterBuilder.In(r => r.Id, configurationRelayList));
return Collection.Find(filter).ToList();
}
///
/// Retrieves a paginated list of camera entities from the MongoDB database based on the provided pagination filter.
/// The method takes a PaginationFilter object as a parameter, which contains information about the page number, page size, and any additional filtering criteria.
///
/// The pagination filter containing page number, page size, and any additional filtering criteria.
/// A paginated list of Camera objects.
/// Thrown when the provided filter is invalid or contains invalid data.
public IFindFluent GetPaginatedCameras(PaginationFilter filter)
{
var filterBuilder = Builders.Filter;
var sort = Builders.Sort.Ascending("name");
var filters = new List>();
if (filter.FilteredRequest == null)
return CreateFindFluent(filters, sort);
if (!string.IsNullOrWhiteSpace(filter.FilteredRequest.Text))
{
var textFilter = filter.FilteredRequest.Text;
if (textFilter.Length > 100)
throw new BadRequestException("Text filter too long");
var safeInput = Regex.Escape(textFilter);
filters.Add(
filterBuilder.Regex(
p => p.Name,
new BsonRegularExpression(safeInput, "i")
)
);
}
return CreateFindFluent(filters, sort);
}
///
/// Inserts a new camera entity into the MongoDB database. The method takes a Camera object as a parameter and attempts to insert it into the collection.
///
/// The Camera object to insert into the database.
/// The inserted Camera object if successful; otherwise, null.
public async Task InsertOneCamera(Camera camera)
{
try
{
await Collection.InsertOneAsync(camera);
return await GetById(camera.Id);
}
catch (Exception ex)
{
Log.Error("Error inserting camera: {camera}. Exception: {ex}",
JsonConvert.SerializeObject(camera, Formatting.Indented), ex);
return null;
}
}
///
/// Updates an existing camera entity in the MongoDB database based on its unique identifier. The method takes an ObjectId representing the camera ID and a Camera object containing the updated information.
///
/// The unique identifier of the camera to update.
/// The Camera object containing the updated information.
/// The updated Camera object if successful; otherwise, null.
public async Task UpdateCameraAsync(ObjectId objectId, Camera camera)
{
var filter = Builders.Filter.Eq("_id", objectId);
var update = Builders.Update
.Set(c => c.Streams, camera.Streams)
.Set(c => c.Name, camera.Name)
.Set(c => c.Username, camera.Username)
.Set(c => c.Password, camera.Password)
.Set(c => c.Driver, camera.Driver)
.Set(c => c.Ip, camera.Ip)
.Set(c => c.Streams, camera.Streams)
.Set(c => c.Ptz, camera.Ptz);
return await Collection.FindOneAndUpdateAsync(filter, update,
new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After });
}
///
/// Searches for camera entities in the MongoDB database based on a text string that matches the camera's name.
/// The method takes a string parameter representing the text to search for and returns a list of Camera objects whose names match the search criteria.
///
/// The text string to search for in the camera names.
/// A list of Camera objects whose names match the search criteria.
/// Thrown when the search text is too long.
public async Task> GetSearchByNameCameras(string textToSearch)
{
if (string.IsNullOrWhiteSpace(textToSearch))
return [];
if (textToSearch.Length > 100)
throw new BadRequestException("Search text too long");
var safeInput = Regex.Escape(textToSearch);
var filter = Builders.Filter.Regex(
c => c.Name,
new BsonRegularExpression(safeInput, "i")
);
return await Collection.Find(filter).ToListAsync();
}
///
/// Creates an IFindFluent object for querying the MongoDB collection based on a list of filter definitions and a sort definition.
///
/// A list of filter definitions to apply to the query.
/// A sort definition to apply to the query results.
/// An IFindFluent object for further query customization or execution.
private IFindFluent CreateFindFluent(List> filters, SortDefinition sort)
{
var combinedFilter = filters.Any()
? Builders.Filter.And(filters)
: Builders.Filter.Empty;
return Collection.Find(combinedFilter).Sort(sort);
}
}