fix(jobs): align table and board query contracts

This commit is contained in:
cesnimda
2026-09-29 17:26:08 +02:00
parent 42a696bc86
commit 6fc8937701
21 changed files with 541 additions and 100 deletions
@@ -478,6 +478,13 @@ Canonical profile:
[FromQuery] string? sortDir = null,
CancellationToken cancellationToken = default
)
=> await ReadJobsAsync(page, pageSize, q, status, companyId, location, needsFollowUp, readiness,
includeDeleted, deletedOnly, sortBy, sortDir, false, cancellationToken);
// One logical query; only the response projection/pagination differs between the two views.
private async Task<ActionResult> ReadJobsAsync(int page, int pageSize, string? q, string? status,
int? companyId, string? location, bool needsFollowUp, string? readiness, bool includeDeleted,
bool deletedOnly, string? sortBy, string? sortDir, bool board, CancellationToken cancellationToken)
{
if (page < 1) page = 1;
if (pageSize is not (15 or 20 or 25)) pageSize = 15;
@@ -565,15 +572,18 @@ Canonical profile:
if (matchesFollowUp && matchesReadiness) filtered.Add(j);
}
filtered = key switch
var ordered = key switch
{
"company" => dirDesc ? filtered.OrderByDescending(j => j.Company.Name).ToList() : filtered.OrderBy(j => j.Company.Name).ToList(),
"jobTitle" => dirDesc ? filtered.OrderByDescending(j => j.JobTitle).ToList() : filtered.OrderBy(j => j.JobTitle).ToList(),
"status" => dirDesc ? filtered.OrderByDescending(j => j.Status).ToList() : filtered.OrderBy(j => j.Status).ToList(),
"location" => dirDesc ? filtered.OrderByDescending(j => j.Location).ToList() : filtered.OrderBy(j => j.Location).ToList(),
"daysSince" => dirDesc ? filtered.OrderBy(j => j.DateApplied).ToList() : filtered.OrderByDescending(j => j.DateApplied).ToList(),
_ => dirDesc ? filtered.OrderByDescending(j => j.DateApplied).ToList() : filtered.OrderBy(j => j.DateApplied).ToList(),
"company" => dirDesc ? filtered.OrderByDescending(j => j.Company.Name) : filtered.OrderBy(j => j.Company.Name),
"jobTitle" => dirDesc ? filtered.OrderByDescending(j => j.JobTitle) : filtered.OrderBy(j => j.JobTitle),
"status" => dirDesc ? filtered.OrderByDescending(j => j.Status) : filtered.OrderBy(j => j.Status),
"location" => dirDesc ? filtered.OrderByDescending(j => j.Location) : filtered.OrderBy(j => j.Location),
"daysSince" => dirDesc ? filtered.OrderBy(j => j.DateApplied) : filtered.OrderByDescending(j => j.DateApplied),
_ => dirDesc ? filtered.OrderByDescending(j => j.DateApplied) : filtered.OrderBy(j => j.DateApplied),
};
filtered = ordered.ThenBy(j => j.Id).ToList();
if (board) return Ok(filtered);
var totalCount = filtered.Count;
var pageItems = filtered.Skip((page - 1) * pageSize).Take(pageSize).ToList();
@@ -589,7 +599,7 @@ Canonical profile:
return Ok(new PagedResult<JobApplicationDto>(dtoItems, totalCount, page, pageSize));
}
query = key switch
var orderedQuery = key switch
{
"company" => dirDesc ? query.OrderByDescending(j => j.Company.Name) : query.OrderBy(j => j.Company.Name),
"jobTitle" => dirDesc ? query.OrderByDescending(j => j.JobTitle) : query.OrderBy(j => j.JobTitle),
@@ -599,6 +609,11 @@ Canonical profile:
"daysSince" => dirDesc ? query.OrderBy(j => j.DateApplied) : query.OrderByDescending(j => j.DateApplied),
_ => dirDesc ? query.OrderByDescending(j => j.DateApplied) : query.OrderBy(j => j.DateApplied),
};
query = orderedQuery.ThenBy(j => j.Id);
// ponytail: existing full-array Board contract is O(N); use a separately designed
// server-paged/virtualized Board if account size makes this unsuitable. Never truncate.
if (board) return Ok(await query.ToListAsync(cancellationToken));
var total = await query.CountAsync(cancellationToken);
@@ -648,22 +663,19 @@ Canonical profile:
[HttpGet("board")]
public async Task<ActionResult<List<JobApplication>>> GetBoard(
[FromQuery] bool includeDeleted = false,
CancellationToken cancellationToken = default
CancellationToken cancellationToken = default,
[FromQuery] string? q = null,
[FromQuery] string? status = null,
[FromQuery] int? companyId = null,
[FromQuery] string? location = null,
[FromQuery] bool needsFollowUp = false,
[FromQuery] string? readiness = null,
[FromQuery] bool deletedOnly = false,
[FromQuery] string? sortBy = null,
[FromQuery] string? sortDir = "desc"
)
{
var query = _db.JobApplications
.AsNoTracking()
.Include(j => j.Company)
.AsQueryable();
if (!includeDeleted) query = query.Where(j => !j.IsDeleted);
var items = await query
.OrderByDescending(j => j.DateApplied)
.ToListAsync(cancellationToken);
return Ok(items);
}
=> await ReadJobsAsync(1, 15, q, status, companyId, location, needsFollowUp, readiness,
includeDeleted, deletedOnly, sortBy, sortDir, true, cancellationToken);
[HttpGet("reminders")]
public async Task<ActionResult<List<JobApplicationDto>>> GetReminders(