Add admin page for bundle
This commit is contained in:
@@ -948,4 +948,357 @@ public class PostgreSqlBacktestRepository : IBacktestRepository
|
||||
|
||||
return entities.Select(PostgreSqlMappers.Map);
|
||||
}
|
||||
|
||||
public (IEnumerable<BundleBacktestRequest> BundleRequests, int TotalCount) GetBundleBacktestRequestsPaginated(
|
||||
int page,
|
||||
int pageSize,
|
||||
BundleBacktestRequestSortableColumn sortBy = BundleBacktestRequestSortableColumn.CreatedAt,
|
||||
string sortOrder = "desc",
|
||||
BundleBacktestRequestsFilter? filter = null)
|
||||
{
|
||||
var baseQuery = _context.BundleBacktestRequests
|
||||
.AsNoTracking()
|
||||
.Include(b => b.User)
|
||||
.AsQueryable();
|
||||
|
||||
// Apply filters
|
||||
if (filter != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(filter.NameContains))
|
||||
{
|
||||
var nameLike = $"%{filter.NameContains.Trim()}%";
|
||||
baseQuery = baseQuery.Where(b => EF.Functions.ILike(b.Name, nameLike));
|
||||
}
|
||||
|
||||
if (filter.Status.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.Status == filter.Status.Value);
|
||||
}
|
||||
|
||||
if (filter.UserId.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.UserId == filter.UserId.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.UserNameContains))
|
||||
{
|
||||
var userNameLike = $"%{filter.UserNameContains.Trim()}%";
|
||||
baseQuery = baseQuery.Where(b => b.User != null && EF.Functions.ILike(b.User.Name, userNameLike));
|
||||
}
|
||||
|
||||
if (filter.TotalBacktestsMin.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests >= filter.TotalBacktestsMin.Value);
|
||||
}
|
||||
|
||||
if (filter.TotalBacktestsMax.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests <= filter.TotalBacktestsMax.Value);
|
||||
}
|
||||
|
||||
if (filter.CompletedBacktestsMin.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CompletedBacktests >= filter.CompletedBacktestsMin.Value);
|
||||
}
|
||||
|
||||
if (filter.CompletedBacktestsMax.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CompletedBacktests <= filter.CompletedBacktestsMax.Value);
|
||||
}
|
||||
|
||||
if (filter.ProgressPercentageMin.HasValue)
|
||||
{
|
||||
var minProgress = filter.ProgressPercentageMin.Value;
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests > 0 &&
|
||||
(double)b.CompletedBacktests / b.TotalBacktests * 100 >= minProgress);
|
||||
}
|
||||
|
||||
if (filter.ProgressPercentageMax.HasValue)
|
||||
{
|
||||
var maxProgress = filter.ProgressPercentageMax.Value;
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests > 0 &&
|
||||
(double)b.CompletedBacktests / b.TotalBacktests * 100 <= maxProgress);
|
||||
}
|
||||
|
||||
if (filter.CreatedAtFrom.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CreatedAt >= filter.CreatedAtFrom.Value);
|
||||
}
|
||||
|
||||
if (filter.CreatedAtTo.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CreatedAt <= filter.CreatedAtTo.Value);
|
||||
}
|
||||
}
|
||||
|
||||
var totalCount = baseQuery.Count();
|
||||
|
||||
// Apply sorting
|
||||
IQueryable<BundleBacktestRequestEntity> sortedQuery = sortBy switch
|
||||
{
|
||||
BundleBacktestRequestSortableColumn.RequestId => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.RequestId)
|
||||
: baseQuery.OrderBy(b => b.RequestId),
|
||||
BundleBacktestRequestSortableColumn.Name => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.Name)
|
||||
: baseQuery.OrderBy(b => b.Name),
|
||||
BundleBacktestRequestSortableColumn.Status => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.Status)
|
||||
: baseQuery.OrderBy(b => b.Status),
|
||||
BundleBacktestRequestSortableColumn.CreatedAt => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CreatedAt)
|
||||
: baseQuery.OrderBy(b => b.CreatedAt),
|
||||
BundleBacktestRequestSortableColumn.CompletedAt => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CompletedAt ?? DateTime.MinValue)
|
||||
: baseQuery.OrderBy(b => b.CompletedAt ?? DateTime.MaxValue),
|
||||
BundleBacktestRequestSortableColumn.TotalBacktests => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.TotalBacktests)
|
||||
: baseQuery.OrderBy(b => b.TotalBacktests),
|
||||
BundleBacktestRequestSortableColumn.CompletedBacktests => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CompletedBacktests)
|
||||
: baseQuery.OrderBy(b => b.CompletedBacktests),
|
||||
BundleBacktestRequestSortableColumn.FailedBacktests => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.FailedBacktests)
|
||||
: baseQuery.OrderBy(b => b.FailedBacktests),
|
||||
BundleBacktestRequestSortableColumn.ProgressPercentage => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.TotalBacktests > 0 ? (double)b.CompletedBacktests / b.TotalBacktests : 0)
|
||||
: baseQuery.OrderBy(b => b.TotalBacktests > 0 ? (double)b.CompletedBacktests / b.TotalBacktests : 0),
|
||||
BundleBacktestRequestSortableColumn.UserId => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.UserId ?? int.MaxValue)
|
||||
: baseQuery.OrderBy(b => b.UserId ?? int.MinValue),
|
||||
BundleBacktestRequestSortableColumn.UserName => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.User != null ? b.User.Name : string.Empty)
|
||||
: baseQuery.OrderBy(b => b.User != null ? b.User.Name : string.Empty),
|
||||
BundleBacktestRequestSortableColumn.UpdatedAt => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.UpdatedAt)
|
||||
: baseQuery.OrderBy(b => b.UpdatedAt),
|
||||
_ => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CreatedAt)
|
||||
: baseQuery.OrderBy(b => b.CreatedAt)
|
||||
};
|
||||
|
||||
var entities = sortedQuery
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToList();
|
||||
|
||||
var mappedRequests = entities.Select(PostgreSqlMappers.Map);
|
||||
|
||||
return (mappedRequests, totalCount);
|
||||
}
|
||||
|
||||
public async Task<(IEnumerable<BundleBacktestRequest> BundleRequests, int TotalCount)> GetBundleBacktestRequestsPaginatedAsync(
|
||||
int page,
|
||||
int pageSize,
|
||||
BundleBacktestRequestSortableColumn sortBy = BundleBacktestRequestSortableColumn.CreatedAt,
|
||||
string sortOrder = "desc",
|
||||
BundleBacktestRequestsFilter? filter = null)
|
||||
{
|
||||
var baseQuery = _context.BundleBacktestRequests
|
||||
.AsNoTracking()
|
||||
.Include(b => b.User)
|
||||
.AsQueryable();
|
||||
|
||||
// Apply filters
|
||||
if (filter != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(filter.NameContains))
|
||||
{
|
||||
var nameLike = $"%{filter.NameContains.Trim()}%";
|
||||
baseQuery = baseQuery.Where(b => EF.Functions.ILike(b.Name, nameLike));
|
||||
}
|
||||
|
||||
if (filter.Status.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.Status == filter.Status.Value);
|
||||
}
|
||||
|
||||
if (filter.UserId.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.UserId == filter.UserId.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(filter.UserNameContains))
|
||||
{
|
||||
var userNameLike = $"%{filter.UserNameContains.Trim()}%";
|
||||
baseQuery = baseQuery.Where(b => b.User != null && EF.Functions.ILike(b.User.Name, userNameLike));
|
||||
}
|
||||
|
||||
if (filter.TotalBacktestsMin.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests >= filter.TotalBacktestsMin.Value);
|
||||
}
|
||||
|
||||
if (filter.TotalBacktestsMax.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests <= filter.TotalBacktestsMax.Value);
|
||||
}
|
||||
|
||||
if (filter.CompletedBacktestsMin.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CompletedBacktests >= filter.CompletedBacktestsMin.Value);
|
||||
}
|
||||
|
||||
if (filter.CompletedBacktestsMax.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CompletedBacktests <= filter.CompletedBacktestsMax.Value);
|
||||
}
|
||||
|
||||
if (filter.ProgressPercentageMin.HasValue)
|
||||
{
|
||||
var minProgress = filter.ProgressPercentageMin.Value;
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests > 0 &&
|
||||
(double)b.CompletedBacktests / b.TotalBacktests * 100 >= minProgress);
|
||||
}
|
||||
|
||||
if (filter.ProgressPercentageMax.HasValue)
|
||||
{
|
||||
var maxProgress = filter.ProgressPercentageMax.Value;
|
||||
baseQuery = baseQuery.Where(b => b.TotalBacktests > 0 &&
|
||||
(double)b.CompletedBacktests / b.TotalBacktests * 100 <= maxProgress);
|
||||
}
|
||||
|
||||
if (filter.CreatedAtFrom.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CreatedAt >= filter.CreatedAtFrom.Value);
|
||||
}
|
||||
|
||||
if (filter.CreatedAtTo.HasValue)
|
||||
{
|
||||
baseQuery = baseQuery.Where(b => b.CreatedAt <= filter.CreatedAtTo.Value);
|
||||
}
|
||||
}
|
||||
|
||||
var totalCount = await baseQuery.CountAsync().ConfigureAwait(false);
|
||||
|
||||
// Apply sorting
|
||||
IQueryable<BundleBacktestRequestEntity> sortedQuery = sortBy switch
|
||||
{
|
||||
BundleBacktestRequestSortableColumn.RequestId => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.RequestId)
|
||||
: baseQuery.OrderBy(b => b.RequestId),
|
||||
BundleBacktestRequestSortableColumn.Name => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.Name)
|
||||
: baseQuery.OrderBy(b => b.Name),
|
||||
BundleBacktestRequestSortableColumn.Status => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.Status)
|
||||
: baseQuery.OrderBy(b => b.Status),
|
||||
BundleBacktestRequestSortableColumn.CreatedAt => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CreatedAt)
|
||||
: baseQuery.OrderBy(b => b.CreatedAt),
|
||||
BundleBacktestRequestSortableColumn.CompletedAt => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CompletedAt ?? DateTime.MinValue)
|
||||
: baseQuery.OrderBy(b => b.CompletedAt ?? DateTime.MaxValue),
|
||||
BundleBacktestRequestSortableColumn.TotalBacktests => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.TotalBacktests)
|
||||
: baseQuery.OrderBy(b => b.TotalBacktests),
|
||||
BundleBacktestRequestSortableColumn.CompletedBacktests => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CompletedBacktests)
|
||||
: baseQuery.OrderBy(b => b.CompletedBacktests),
|
||||
BundleBacktestRequestSortableColumn.FailedBacktests => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.FailedBacktests)
|
||||
: baseQuery.OrderBy(b => b.FailedBacktests),
|
||||
BundleBacktestRequestSortableColumn.ProgressPercentage => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.TotalBacktests > 0 ? (double)b.CompletedBacktests / b.TotalBacktests : 0)
|
||||
: baseQuery.OrderBy(b => b.TotalBacktests > 0 ? (double)b.CompletedBacktests / b.TotalBacktests : 0),
|
||||
BundleBacktestRequestSortableColumn.UserId => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.UserId ?? int.MaxValue)
|
||||
: baseQuery.OrderBy(b => b.UserId ?? int.MinValue),
|
||||
BundleBacktestRequestSortableColumn.UserName => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.User != null ? b.User.Name : string.Empty)
|
||||
: baseQuery.OrderBy(b => b.User != null ? b.User.Name : string.Empty),
|
||||
BundleBacktestRequestSortableColumn.UpdatedAt => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.UpdatedAt)
|
||||
: baseQuery.OrderBy(b => b.UpdatedAt),
|
||||
_ => sortOrder == "desc"
|
||||
? baseQuery.OrderByDescending(b => b.CreatedAt)
|
||||
: baseQuery.OrderBy(b => b.CreatedAt)
|
||||
};
|
||||
|
||||
var entities = await sortedQuery
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var mappedRequests = entities.Select(PostgreSqlMappers.Map);
|
||||
|
||||
return (mappedRequests, totalCount);
|
||||
}
|
||||
|
||||
public async Task<BundleBacktestRequestSummary> GetBundleBacktestRequestsSummaryAsync()
|
||||
{
|
||||
// Use ADO.NET directly for aggregation queries to avoid EF Core mapping issues
|
||||
var connection = _context.Database.GetDbConnection();
|
||||
await connection.OpenAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var statusCounts = new List<BundleBacktestRequestStatusCountResult>();
|
||||
var totalRequests = 0;
|
||||
|
||||
// Query 1: Status summary
|
||||
// Note: Status is stored as text in PostgreSQL, not as integer
|
||||
var statusSummarySql = @"
|
||||
SELECT ""Status"", COUNT(*) as Count
|
||||
FROM ""BundleBacktestRequests""
|
||||
GROUP BY ""Status""
|
||||
ORDER BY ""Status""";
|
||||
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = statusSummarySql;
|
||||
using (var reader = await command.ExecuteReaderAsync())
|
||||
{
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
var statusString = reader.GetString(0);
|
||||
var count = reader.GetInt32(1);
|
||||
|
||||
// Parse the string status to enum
|
||||
if (Enum.TryParse<BundleBacktestRequestStatus>(statusString, ignoreCase: true, out var status))
|
||||
{
|
||||
statusCounts.Add(new BundleBacktestRequestStatusCountResult
|
||||
{
|
||||
Status = status,
|
||||
Count = count
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Query 2: Total count
|
||||
var totalCountSql = @"
|
||||
SELECT COUNT(*) as Count
|
||||
FROM ""BundleBacktestRequests""";
|
||||
|
||||
using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = totalCountSql;
|
||||
var result = await command.ExecuteScalarAsync();
|
||||
totalRequests = result != null ? Convert.ToInt32(result) : 0;
|
||||
}
|
||||
|
||||
return new BundleBacktestRequestSummary
|
||||
{
|
||||
StatusCounts = statusCounts.Select(s => new BundleBacktestRequestStatusCount
|
||||
{
|
||||
Status = s.Status,
|
||||
Count = s.Count
|
||||
}).ToList(),
|
||||
TotalRequests = totalRequests
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
await connection.CloseAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private class BundleBacktestRequestStatusCountResult
|
||||
{
|
||||
public BundleBacktestRequestStatus Status { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user