Sube carpetas API, API.Tests, Application y Domain del Backend

This commit is contained in:
FrancoRu
2026-09-18 13:35:59 -03:00
parent bbb09554bb
commit 2eb4eeef03
572 changed files with 56405 additions and 0 deletions
@@ -0,0 +1,10 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
/// <summary>
/// Repository interface for managing AuditLog entries.
/// </summary>
public interface IAuditLogRepository : IGenericRepository<AuditLog>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IBlogPostRepository : IGenericRepository<BlogPost>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IClubRepository : IGenericRepository<Club>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IDivisionRepository : IGenericRepository<Division>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IDivisionTeamRegistrationRepository : IGenericRepository<DivisionTeamRegistration>
{
}
@@ -0,0 +1,128 @@
using Application.DTOs.Abstract.Request;
using Domain.Entities.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Application.Interfaces.Repositories;
/// <summary>
/// Generic repository interface for common CRUD operations on entities.
/// </summary>
/// <typeparam name="TEntity">The entity type, which must inherit from EntityBase.</typeparam>
public interface IGenericRepository<TEntity> where TEntity : EntityBase
{
/// <summary>
/// Gets an entity by its unique identifier.
/// </summary>
/// <param name="id">The unique identifier of the entity.</param>
/// <param name="includes">Optional navigation property expressions to include related data.</param>
/// <returns>
/// A task representing the asynchronous operation. The task result contains the entity if found, otherwise null.
/// </returns>
Task<TEntity?> GetByIdAsync(Guid id, IEnumerable<Expression<Func<TEntity, object>>>? includes = null);
/// <summary>
/// Returns a queryable collection of entities for advanced querying scenarios.
/// </summary>
IQueryable<TEntity> GetQueryable();
/// <summary>
/// Gets all entities of type TEntity.
/// </summary>
/// <returns>
/// A task representing the asynchronous operation. The task result contains a collection of all entities.
/// </returns>
Task<IEnumerable<TEntity>> GetAllAsync();
/// <summary>
/// Finds entities matching the given predicate.
/// </summary>
/// <param name="predicate">The filter expression to match entities.</param>
/// <param name="includes">Optional navigation property expressions to include related data.</param>
/// <param name="filter">Optional pagination and filtering request.</param>
/// <param name="asSplitQuery">
/// Set true when including 2+ collection navigations in the same query —
/// otherwise EF Core joins them into one cartesian-product result set,
/// which is both slow and, combined with pagination, can return
/// incorrect rows.
/// </param>
/// <returns>
/// A task representing the asynchronous operation. The task result contains a collection of matching entities.
/// </returns>
Task<IEnumerable<TEntity>> FindAsync(
Expression<Func<TEntity, bool>> predicate,
IEnumerable<Expression<Func<TEntity, object>>>? includes = null,
PaginatedFilterRequest? filter = null,
bool asSplitQuery = false);
/// <summary>
/// Adds a new entity to the repository.
/// </summary>
/// <param name="entity">The entity to add.</param>
/// <returns>
/// A task representing the asynchronous operation. The task result contains the added entity.
/// </returns>
Task<TEntity> AddAsync(TEntity entity);
/// <summary>
/// Adds a range of entities to the repository.
/// </summary>
/// <param name="entities">The entities to add.</param>
/// <returns>
/// A task representing the asynchronous operation. The task result contains the added entities.
/// </returns>
Task<IEnumerable<TEntity>> AddRangeAsync(IEnumerable<TEntity> entities);
/// <summary>
/// Marks a single entity for deletion without calling SaveChanges.
/// </summary>
/// <param name="entity">The entity to remove.</param>
void Remove(TEntity entity);
/// <summary>
/// Deletes all entities matching expression directly via EF Core's ExecuteDeleteAsync, a single DB-side statement that bypasses the change tracker entirely.
/// </summary>
/// <param name="expression">The filter expression to match entities for removal.</param>
/// <returns>
/// A task representing the asynchronous operation. The task result contains the number of entities deleted.
/// </returns>
Task<int> RemoveAsync(Expression<Func<TEntity, bool>> expression);
/// <summary>
/// Counts the number of entities matching the given predicate, or all if predicate is null.
/// </summary>
/// <param name="predicate">The filter expression, optional.</param>
/// <returns>
/// A task representing the asynchronous operation. The task result contains the count of matching entities.
/// </returns>
Task<int> CountAsync(Expression<Func<TEntity, bool>>? predicate = null);
/// <summary>
/// Checks if any entity matches the given predicate.
/// </summary>
/// <param name="predicate">The filter expression.</param>
/// <returns>
/// A task representing the asynchronous operation. The task result is true if any entity matches, otherwise false.
/// </returns>
Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate);
/// <summary>
/// Updates a range of entities in the repository.
/// </summary>
/// <param name="entities">The entities to update.</param>
/// <returns>A task representing the asynchronous update operation.</returns>
Task UpdateRangeAsync(IEnumerable<TEntity> entities);
/// <summary>
/// Updates a single entity in the repository.
/// </summary>
/// <param name="entity">The entity to update.</param>
/// <returns>A task representing the asynchronous update operation.</returns>
Task UpdateAsync(TEntity entity);
}
@@ -0,0 +1,19 @@
using Domain.Entities.Models;
using System;
using System.Threading.Tasks;
namespace Application.Interfaces.Repositories;
/// <summary>
/// Repository interface for managing Match entities.
/// </summary>
public interface IMatchRepository : IGenericRepository<Match>
{
/// <summary>
/// Loads a single match by its id or slug with everything the public match detail needs: both teams, the venue, and the match's scorers with their players.
/// </summary>
/// <param name="idOrSlug">The match's GUID id or its slug.</param>
/// <returns>The match with its detail graph loaded, or null if not found.</returns>
Task<Match?> GetDetailByIdOrSlugAsync(string idOrSlug);
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IMatchSeriesRepository : IGenericRepository<MatchSeries>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IPlayerRepository : IGenericRepository<Player>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IPlayerSanctionRepository : IGenericRepository<PlayerSanction>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IPlayerStatisticRepository : IGenericRepository<PlayerStatistic>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IPlayerTeamRegistrationRepository : IGenericRepository<PlayerTeamRegistration>
{
}
@@ -0,0 +1,13 @@
using Application.DTOs.Scorer.Request;
using Application.DTOs.Scorer.Response;
using Domain.Entities.Models;
using System.Threading.Tasks;
namespace Application.Interfaces.Repositories;
public interface IScorerRepository : IGenericRepository<Scorer>
{
Task<(System.Collections.Generic.IEnumerable<ScorerByPlayerResponse> Items, int TotalCount)> GetPlayerScoresAsync(GetScorerFilteredRequest filter);
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface ISeasonRepository : IGenericRepository<Season>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IStageRepository : IGenericRepository<Stage>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IStageTeamMatchRepository : IGenericRepository<StageTeamMatch>
{
}
@@ -0,0 +1,22 @@
using Application.DTOs.Statistics.Response;
using System;
using System.Threading.Tasks;
namespace Application.Interfaces.Repositories;
/// <summary>
/// Read-only historical-statistics aggregations that group a person's data across every season by their stable PlayerId.
/// </summary>
public interface IStatisticsRepository
{
/// <summary>
/// Returns the player's statistic card with total and average points and games played per season and overall, or null when the player does not exist.
/// </summary>
Task<PlayerStatisticCardResponse?> GetPlayerCardAsync(Guid playerId);
/// <summary>
/// Returns the player's per-season trajectory with team, stats, and sanctions for each season they were registered, or null when the player does not exist.
/// </summary>
Task<PlayerHistoryResponse?> GetPlayerHistoryAsync(Guid playerId);
}
@@ -0,0 +1,10 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
/// <summary>
/// Repository interface for managing TeamPointDeduction entities, the disciplinary point deductions applied to teams in a division.
/// </summary>
public interface ITeamPointDeductionRepository : IGenericRepository<TeamPointDeduction>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface ITeamRepository : IGenericRepository<Team>
{
}
@@ -0,0 +1,10 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
/// <summary>
/// Repository interface for managing TeamStaff entities, a team's technical staff for a given tournament and season.
/// </summary>
public interface ITeamStaffRepository : IGenericRepository<TeamStaff>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface ITeamTournamentRegistrationRepository : IGenericRepository<TeamTournamentRegistration>
{
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface ITournamentRepository : IGenericRepository<Tournament>
{
}
@@ -0,0 +1,33 @@
using System;
using System.Threading.Tasks;
namespace Application.Interfaces.Repositories;
/// <summary>
/// Unit of Work interface for coordinating multiple repositories and saving changes atomically.
/// </summary>
public interface IUnitOfWork
{
IBlogPostRepository BlogPostRepository { get; }
IClubRepository ClubRepository { get; }
ITeamRepository TeamRepository { get; }
IVenueRepository VenueRepository { get; }
ITournamentRepository TournamentRepository { get; }
IStageRepository StageRepository { get; }
IPlayerStatisticRepository PlayerStatisticRepository { get; }
IPlayerSanctionRepository PlayerSanctionRepository { get; }
IPlayerRepository PlayerRepository { get; }
IMatchRepository MatchRepository { get; }
IMatchSeriesRepository MatchSeriesRepository { get; }
IDivisionRepository DivisionRepository { get; }
IStageTeamMatchRepository StageTeamMatchRepository { get; }
IPlayerTeamRegistrationRepository PlayerTeamRegistrationRepository { get; }
ITeamTournamentRegistrationRepository TeamTournamentRegistrationRepository { get; }
IDivisionTeamRegistrationRepository DivisionTeamRegistrationRepository { get; }
Task<int> SaveChangesAsync();
/// <summary>
/// Runs operation inside a single database transaction, rolling back entirely with no partial writes if the operation throws.
/// </summary>
Task ExecuteInTransactionAsync(Func<Task> operation);
}
@@ -0,0 +1,7 @@
using Domain.Entities.Models;
namespace Application.Interfaces.Repositories;
public interface IVenueRepository : IGenericRepository<Venue>
{
}