Added initial test cases. Fixed circle search provider logic.
This commit is contained in:
@@ -9,58 +9,65 @@ public class CircleSearchProvider(AppDbContext context) : SearchProvider<CircleS
|
||||
{
|
||||
protected override IQueryable<CircleSearchItem> GetBaseQuery()
|
||||
{
|
||||
// Precompute LatestProductId per circle (by productId length, then value)
|
||||
var latestPerCircle =
|
||||
from vw in context.VoiceWorks.AsNoTracking()
|
||||
group vw by vw.CircleId into g
|
||||
let latest = g
|
||||
.OrderByDescending(x => x.ProductId.Length)
|
||||
.ThenByDescending(x => x.ProductId)
|
||||
.Select(x => x.ProductId)
|
||||
// Project from Circles so we can use correlated subqueries per CircleId.
|
||||
var q =
|
||||
from c in context.Circles.AsNoTracking()
|
||||
select new CircleSearchItem
|
||||
{
|
||||
CircleId = c.CircleId,
|
||||
Name = c.Name,
|
||||
MakerId = c.MakerId,
|
||||
Favorite = c.Favorite,
|
||||
Blacklisted = c.Blacklisted,
|
||||
Spam = c.Spam,
|
||||
|
||||
// Aggregates
|
||||
Downloads = context.VoiceWorks
|
||||
.Where(v => v.CircleId == c.CircleId)
|
||||
.Select(v => (int?)v.Downloads) // make nullable for Sum over empty set
|
||||
.Sum() ?? 0,
|
||||
|
||||
Releases = context.VoiceWorks
|
||||
.Count(v => v.CircleId == c.CircleId && v.SalesDate != null),
|
||||
|
||||
Pending = context.VoiceWorks
|
||||
.Count(v => v.CircleId == c.CircleId && v.ExpectedDate != null),
|
||||
|
||||
FirstReleaseDate = context.VoiceWorks
|
||||
.Where(v => v.CircleId == c.CircleId)
|
||||
.Select(v => v.SalesDate)
|
||||
.Min(),
|
||||
|
||||
LatestReleaseDate = context.VoiceWorks
|
||||
.Where(v => v.CircleId == c.CircleId)
|
||||
.Select(v => v.SalesDate)
|
||||
.Max(),
|
||||
|
||||
// "Latest" by ProductId length, then value
|
||||
LatestProductId = context.VoiceWorks
|
||||
.Where(v => v.CircleId == c.CircleId)
|
||||
.OrderByDescending(v => v.ProductId.Length)
|
||||
.ThenByDescending(v => v.ProductId)
|
||||
.Select(v => v.ProductId)
|
||||
.FirstOrDefault(),
|
||||
|
||||
// If you want these two in base query too:
|
||||
LatestVoiceWorkHasImage = context.VoiceWorks
|
||||
.Where(v => v.CircleId == c.CircleId)
|
||||
.OrderByDescending(v => v.ProductId.Length)
|
||||
.ThenByDescending(v => v.ProductId)
|
||||
.Select(v => (bool?)v.HasImage)
|
||||
.FirstOrDefault(),
|
||||
|
||||
LatestVoiceWorkSalesDate = context.VoiceWorks
|
||||
.Where(v => v.CircleId == c.CircleId)
|
||||
.OrderByDescending(v => v.ProductId.Length)
|
||||
.ThenByDescending(v => v.ProductId)
|
||||
.Select(v => v.SalesDate)
|
||||
.FirstOrDefault()
|
||||
select new { CircleId = g.Key, LatestProductId = latest };
|
||||
};
|
||||
|
||||
// Aggregates per circle
|
||||
var aggregates =
|
||||
from vw in context.VoiceWorks.AsNoTracking()
|
||||
group vw by vw.CircleId into g
|
||||
select new
|
||||
{
|
||||
CircleId = g.Key,
|
||||
Downloads = g.Sum(x => x.Downloads ?? 0),
|
||||
Releases = g.Count(x => x.SalesDate != null),
|
||||
Pending = g.Count(x => x.ExpectedDate != null),
|
||||
FirstReleaseDate = g.Min(x => x.SalesDate),
|
||||
LatestReleaseDate = g.Max(x => x.SalesDate)
|
||||
};
|
||||
|
||||
// Join circles with aggregates and latest product id
|
||||
var baseQuery =
|
||||
from c in context.Circles.AsNoTracking()
|
||||
join agg in aggregates on c.CircleId equals agg.CircleId into aggs
|
||||
from a in aggs.DefaultIfEmpty()
|
||||
join lp in latestPerCircle on c.CircleId equals lp.CircleId into lps
|
||||
from l in lps.DefaultIfEmpty()
|
||||
select new CircleSearchItem
|
||||
{
|
||||
CircleId = c.CircleId,
|
||||
Name = c.Name,
|
||||
MakerId = c.MakerId,
|
||||
Favorite = c.Favorite,
|
||||
Blacklisted = c.Blacklisted,
|
||||
Spam = c.Spam,
|
||||
Downloads = a != null ? a.Downloads : 0,
|
||||
Releases = a != null ? a.Releases : 0,
|
||||
Pending = a != null ? a.Pending : 0,
|
||||
FirstReleaseDate = a != null ? a.FirstReleaseDate : null,
|
||||
LatestReleaseDate = a != null ? a.LatestReleaseDate : null,
|
||||
LatestProductId = l != null ? l.LatestProductId : null,
|
||||
// these two get filled in during Select stage (below)
|
||||
LatestVoiceWorkHasImage = null,
|
||||
LatestVoiceWorkSalesDate = null
|
||||
};
|
||||
|
||||
return baseQuery;
|
||||
return q;
|
||||
}
|
||||
|
||||
protected override IQueryable<CircleSearchItem> ApplyFilters(IQueryable<CircleSearchItem> query, CircleSearchCriteria criteria)
|
||||
@@ -74,14 +81,21 @@ public class CircleSearchProvider(AppDbContext context) : SearchProvider<CircleS
|
||||
EF.Functions.Like(x.MakerId, term));
|
||||
}
|
||||
|
||||
//if (criteria.Status is CircleStatus.NotBlacklisted)
|
||||
// query = query.Where(x => !x.Blacklisted);
|
||||
//else if (criteria.Status is CircleStatus.Favorited)
|
||||
// query = query.Where(x => x.Favorite);
|
||||
//else if (criteria.Status is CircleStatus.Blacklisted)
|
||||
// query = query.Where(x => x.Blacklisted);
|
||||
//else if (criteria.Status is CircleStatus.Spam)
|
||||
// query = query.Where(x => x.Spam);
|
||||
switch (criteria.Status)
|
||||
{
|
||||
case CircleStatus.NotBlacklisted:
|
||||
query = query.Where(x => !x.Blacklisted);
|
||||
break;
|
||||
case CircleStatus.Favorited:
|
||||
query = query.Where(x => x.Favorite);
|
||||
break;
|
||||
case CircleStatus.Blacklisted:
|
||||
query = query.Where(x => x.Blacklisted);
|
||||
break;
|
||||
case CircleStatus.Spam:
|
||||
query = query.Where(x => x.Spam);
|
||||
break;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user