Finished voice work search provider implementation, and added several more tests.
This commit is contained in:
@@ -47,7 +47,7 @@ public class VoiceWorkSearchProvider(AppDbContext context, IVoiceWorkFullTextSea
|
|||||||
filteredQuery = ApplyKeywordsFilter(filteredQuery, criteria);
|
filteredQuery = ApplyKeywordsFilter(filteredQuery, criteria);
|
||||||
filteredQuery = ApplyCircleStatusFilter(filteredQuery, criteria);
|
filteredQuery = ApplyCircleStatusFilter(filteredQuery, criteria);
|
||||||
filteredQuery = ApplyTagStatusFilter(filteredQuery, criteria);
|
filteredQuery = ApplyTagStatusFilter(filteredQuery, criteria);
|
||||||
//filteredQuery = FilterCreatorStatus(filteredQuery, searchProperties.CreatorStatus, _voiceWorkContext);
|
filteredQuery = ApplyCreatorStatusFilter(filteredQuery, criteria);
|
||||||
filteredQuery = ApplyTagIdsFilter(filteredQuery, criteria);
|
filteredQuery = ApplyTagIdsFilter(filteredQuery, criteria);
|
||||||
filteredQuery = ApplyCreatorIdsFilter(filteredQuery, criteria);
|
filteredQuery = ApplyCreatorIdsFilter(filteredQuery, criteria);
|
||||||
|
|
||||||
@@ -175,6 +175,54 @@ public class VoiceWorkSearchProvider(AppDbContext context, IVoiceWorkFullTextSea
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IQueryable<VoiceWorkQuery> ApplyCreatorStatusFilter(IQueryable<VoiceWorkQuery> query, VoiceWorkSearchCriteria criteria)
|
||||||
|
{
|
||||||
|
if (criteria.CreatorStatus is null)
|
||||||
|
return query;
|
||||||
|
|
||||||
|
// Handy local predicates that translate to EXISTS subqueries
|
||||||
|
bool HasFav(int voiceWorkId) =>
|
||||||
|
context.VoiceWorkCreators
|
||||||
|
.Join(context.Creators, vwc => vwc.CreatorId, c => c.CreatorId, (vwc, c) => new { vwc, c })
|
||||||
|
.Any(x => x.vwc.VoiceWorkId == voiceWorkId && x.c.Favorite);
|
||||||
|
|
||||||
|
bool HasBlk(int voiceWorkId) =>
|
||||||
|
context.VoiceWorkCreators
|
||||||
|
.Join(context.Creators, vwc => vwc.CreatorId, c => c.CreatorId, (vwc, c) => new { vwc, c })
|
||||||
|
.Any(x => x.vwc.VoiceWorkId == voiceWorkId && x.c.Blacklisted);
|
||||||
|
|
||||||
|
return criteria.CreatorStatus switch
|
||||||
|
{
|
||||||
|
CreatorStatus.NotBlacklisted =>
|
||||||
|
query.Where(q => !context.VoiceWorkCreators
|
||||||
|
.Join(context.Creators, vwc => vwc.CreatorId, c => c.CreatorId, (vwc, c) => new { vwc, c })
|
||||||
|
.Any(x => x.vwc.VoiceWorkId == q.VoiceWork.VoiceWorkId && x.c.Blacklisted)),
|
||||||
|
|
||||||
|
CreatorStatus.Blacklisted =>
|
||||||
|
query.Where(q => context.VoiceWorkCreators
|
||||||
|
.Join(context.Creators, vwc => vwc.CreatorId, c => c.CreatorId, (vwc, c) => new { vwc, c })
|
||||||
|
.Any(x => x.vwc.VoiceWorkId == q.VoiceWork.VoiceWorkId && x.c.Blacklisted)),
|
||||||
|
|
||||||
|
CreatorStatus.FavoriteIncludeBlacklist =>
|
||||||
|
query.Where(q => context.VoiceWorkCreators
|
||||||
|
.Join(context.Creators, vwc => vwc.CreatorId, c => c.CreatorId, (vwc, c) => new { vwc, c })
|
||||||
|
.Any(x => x.vwc.VoiceWorkId == q.VoiceWork.VoiceWorkId && x.c.Favorite)),
|
||||||
|
|
||||||
|
CreatorStatus.FavoriteExcludeBlacklist =>
|
||||||
|
query.Where(q =>
|
||||||
|
context.VoiceWorkCreators
|
||||||
|
.Join(context.Creators, vwc => vwc.CreatorId, c => c.CreatorId, (vwc, c) => new { vwc, c })
|
||||||
|
.Any(x => x.vwc.VoiceWorkId == q.VoiceWork.VoiceWorkId && x.c.Favorite)
|
||||||
|
&&
|
||||||
|
!context.VoiceWorkCreators
|
||||||
|
.Join(context.Creators, vwc => vwc.CreatorId, c => c.CreatorId, (vwc, c) => new { vwc, c })
|
||||||
|
.Any(x => x.vwc.VoiceWorkId == q.VoiceWork.VoiceWorkId && x.c.Blacklisted)
|
||||||
|
),
|
||||||
|
|
||||||
|
_ => query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private IQueryable<VoiceWorkQuery> ApplyTagIdsFilter(IQueryable<VoiceWorkQuery> filteredQuery, VoiceWorkSearchCriteria criteria)
|
private IQueryable<VoiceWorkQuery> ApplyTagIdsFilter(IQueryable<VoiceWorkQuery> filteredQuery, VoiceWorkSearchCriteria criteria)
|
||||||
{
|
{
|
||||||
if (criteria.TagIds.Length == 0)
|
if (criteria.TagIds.Length == 0)
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ public class VoiceWorkSearchProviderFixture : MariaDbFixture
|
|||||||
);
|
);
|
||||||
|
|
||||||
context.VoiceWorks.AddRange(
|
context.VoiceWorks.AddRange(
|
||||||
new() { VoiceWorkId = 1, CircleId = 1, ProductId = "RJ0000001", ProductName = "Today Sounds", Description = "An average product.", Status = (byte)VoiceWorkStatus.Available, SalesDate = new(2025, 1, 1) },
|
new() { VoiceWorkId = 1, CircleId = 1, ProductId = "RJ0000001", ProductName = "Today Sounds", Description = "An average product.", Status = (byte)VoiceWorkStatus.Available, SalesDate = new(2025, 1, 1), Downloads = 500, WishlistCount = 750, StarRating = 35 },
|
||||||
new() { VoiceWorkId = 2, CircleId = 2, ProductId = "RJ0000002", ProductName = "Super Comfy ASMR", Description = "An amazing product!", Status = (byte)VoiceWorkStatus.NewRelease, SalesDate = new(2025, 1, 3) },
|
new() { VoiceWorkId = 2, CircleId = 2, ProductId = "RJ0000002", ProductName = "Super Comfy ASMR", Description = "An amazing product!", Status = (byte)VoiceWorkStatus.NewRelease, SalesDate = new(2025, 1, 3), Downloads = 5000, WishlistCount = 12000, StarRating = 50, Favorite = true },
|
||||||
new() { VoiceWorkId = 3, CircleId = 3, ProductId = "RJ0000003", ProductName = "Low Effort", Description = "A bad product.", Status = (byte)VoiceWorkStatus.Available, SalesDate = new(2025, 1, 2) },
|
new() { VoiceWorkId = 3, CircleId = 3, ProductId = "RJ0000003", ProductName = "Low Effort", Description = "A bad product.", Status = (byte)VoiceWorkStatus.Available, SalesDate = new(2025, 1, 2), Downloads = 50, WishlistCount = 100, StarRating = 20 },
|
||||||
new() { VoiceWorkId = 4, CircleId = 1, ProductId = "RJ0000004", ProductName = "Tomorrow Sounds", Description = "A average upcoming product.", Status = (byte)VoiceWorkStatus.Upcoming, ExpectedDate = new(2025, 1, 4) },
|
new() { VoiceWorkId = 4, CircleId = 1, ProductId = "RJ0000004", ProductName = "Tomorrow Sounds", Description = "A average upcoming product.", Status = (byte)VoiceWorkStatus.Upcoming, ExpectedDate = new(2025, 1, 1), WishlistCount = 300 },
|
||||||
new() { VoiceWorkId = 5, CircleId = 2, ProductId = "RJ0000005", ProductName = "Super Comfy ASMR+", Description = "All your favorite sounds, plus more!", Status = (byte)VoiceWorkStatus.NewAndUpcoming, ExpectedDate = new(2025, 1, 5) }
|
new() { VoiceWorkId = 5, CircleId = 2, ProductId = "RJ0000005", ProductName = "Super Comfy ASMR+", Description = "All your favorite sounds, plus more!", Status = (byte)VoiceWorkStatus.NewAndUpcoming, ExpectedDate = new(2025, 1, 11), WishlistCount = 10000 }
|
||||||
);
|
);
|
||||||
|
|
||||||
context.Tags.AddRange(
|
context.Tags.AddRange(
|
||||||
@@ -38,7 +38,8 @@ public class VoiceWorkSearchProviderFixture : MariaDbFixture
|
|||||||
new() { TagId = 5, Name = "ツンデレ", Favorite = true },
|
new() { TagId = 5, Name = "ツンデレ", Favorite = true },
|
||||||
new() { TagId = 6, Name = "オールハッピー" },
|
new() { TagId = 6, Name = "オールハッピー" },
|
||||||
new() { TagId = 7, Name = "ギャル" },
|
new() { TagId = 7, Name = "ギャル" },
|
||||||
new() { TagId = 8, Name = "メイド" }
|
new() { TagId = 8, Name = "メイド" },
|
||||||
|
new() { TagId = 9, Name = "ノンフィクション/体験談", Blacklisted = true }
|
||||||
);
|
);
|
||||||
|
|
||||||
context.EnglishTags.AddRange(
|
context.EnglishTags.AddRange(
|
||||||
@@ -49,7 +50,8 @@ public class VoiceWorkSearchProviderFixture : MariaDbFixture
|
|||||||
new() { EnglishTagId = 5, TagId = 5, Name = "Tsundere" },
|
new() { EnglishTagId = 5, TagId = 5, Name = "Tsundere" },
|
||||||
new() { EnglishTagId = 6, TagId = 6, Name = "All Happy" },
|
new() { EnglishTagId = 6, TagId = 6, Name = "All Happy" },
|
||||||
new() { EnglishTagId = 7, TagId = 7, Name = "Gal" },
|
new() { EnglishTagId = 7, TagId = 7, Name = "Gal" },
|
||||||
new() { EnglishTagId = 8, TagId = 8, Name = "Maid" }
|
new() { EnglishTagId = 8, TagId = 8, Name = "Maid" },
|
||||||
|
new() { EnglishTagId = 9, TagId = 9, Name = "Non-Fiction / Narrative" }
|
||||||
);
|
);
|
||||||
|
|
||||||
context.VoiceWorkTags.AddRange(
|
context.VoiceWorkTags.AddRange(
|
||||||
@@ -62,31 +64,31 @@ public class VoiceWorkSearchProviderFixture : MariaDbFixture
|
|||||||
new() { VoiceWorkId = 2, TagId = 5 }, // Tsundere
|
new() { VoiceWorkId = 2, TagId = 5 }, // Tsundere
|
||||||
new() { VoiceWorkId = 2, TagId = 6 }, // All Happy
|
new() { VoiceWorkId = 2, TagId = 6 }, // All Happy
|
||||||
new() { VoiceWorkId = 2, TagId = 7 }, // Gal
|
new() { VoiceWorkId = 2, TagId = 7 }, // Gal
|
||||||
new() { VoiceWorkId = 2, TagId = 8 } // Maid
|
new() { VoiceWorkId = 2, TagId = 8 }, // Maid
|
||||||
|
|
||||||
//new() { VoiceWorkId = 3, TagId = 1 },
|
new() { VoiceWorkId = 3, TagId = 5 }, // Tsundere
|
||||||
//new() { VoiceWorkId = 3, TagId = 1 },
|
new() { VoiceWorkId = 3, TagId = 9 } // Non-Fiction / Narrative
|
||||||
//new() { VoiceWorkId = 3, TagId = 1 },
|
//new() { VoiceWorkId = 3, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 3, TagId = 1 },
|
//new() { VoiceWorkId = 3, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 3, TagId = 1 },
|
//new() { VoiceWorkId = 3, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 3, TagId = 1 },
|
//new() { VoiceWorkId = 3, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 3, TagId = 1 },
|
//new() { VoiceWorkId = 3, TagId = 1 },
|
||||||
|
|
||||||
//new() { VoiceWorkId = 4, TagId = 1 },
|
//new() { VoiceWorkId = 4, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 4, TagId = 1 },
|
//new() { VoiceWorkId = 4, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 4, TagId = 1 },
|
//new() { VoiceWorkId = 4, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 4, TagId = 1 },
|
//new() { VoiceWorkId = 4, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 4, TagId = 1 },
|
//new() { VoiceWorkId = 4, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 4, TagId = 1 },
|
//new() { VoiceWorkId = 4, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 4, TagId = 1 },
|
//new() { VoiceWorkId = 4, TagId = 1 },
|
||||||
|
|
||||||
//new() { VoiceWorkId = 5, TagId = 1 },
|
//new() { VoiceWorkId = 5, TagId = 5 } // Tsundere
|
||||||
//new() { VoiceWorkId = 5, TagId = 1 },
|
//new() { VoiceWorkId = 5, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 5, TagId = 1 },
|
//new() { VoiceWorkId = 5, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 5, TagId = 1 },
|
//new() { VoiceWorkId = 5, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 5, TagId = 1 },
|
//new() { VoiceWorkId = 5, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 5, TagId = 1 },
|
//new() { VoiceWorkId = 5, TagId = 1 },
|
||||||
//new() { VoiceWorkId = 5, TagId = 1 }
|
//new() { VoiceWorkId = 5, TagId = 1 }
|
||||||
);
|
);
|
||||||
|
|
||||||
context.Creators.AddRange(
|
context.Creators.AddRange(
|
||||||
@@ -97,6 +99,20 @@ public class VoiceWorkSearchProviderFixture : MariaDbFixture
|
|||||||
new() { CreatorId = 5, Name = "山田じぇみ子", Blacklisted = true }
|
new() { CreatorId = 5, Name = "山田じぇみ子", Blacklisted = true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
context.VoiceWorkCreators.AddRange(
|
||||||
|
new() { VoiceWorkId = 1, CreatorId = 2 }, // 秋野かえで
|
||||||
|
|
||||||
|
new() { VoiceWorkId = 2, CreatorId = 1 }, // 陽向葵ゅか
|
||||||
|
|
||||||
|
new() { VoiceWorkId = 3, CreatorId = 5 }, // 山田じぇみ子
|
||||||
|
new() { VoiceWorkId = 3, CreatorId = 1 }, // 陽向葵ゅか
|
||||||
|
|
||||||
|
new() { VoiceWorkId = 4, CreatorId = 3 }, // 柚木つばめ
|
||||||
|
|
||||||
|
new() { VoiceWorkId = 5, CreatorId = 1 }, // 陽向葵ゅか
|
||||||
|
new() { VoiceWorkId = 5, CreatorId = 4 } // 逢坂成美
|
||||||
|
);
|
||||||
|
|
||||||
// <Product Id> <Maker Id> <Circle Name> <Product Name> <Product Description> <Tags> <Creators>
|
// <Product Id> <Maker Id> <Circle Name> <Product Name> <Product Description> <Tags> <Creators>
|
||||||
context.VoiceWorkSearches.AddRange(
|
context.VoiceWorkSearches.AddRange(
|
||||||
new() { VoiceWorkId = 1, SearchText = "RJ0000001 RG00001 Good Dreams Today Sounds An average product. ASMR Office Lady" },
|
new() { VoiceWorkId = 1, SearchText = "RJ0000001 RG00001 Good Dreams Today Sounds An average product. ASMR Office Lady" },
|
||||||
|
|||||||
@@ -174,4 +174,544 @@ public class VoiceWorkSearchProviderTests(VoiceWorkSearchProviderFixture fixture
|
|||||||
result.TotalItems.ShouldBe(1);
|
result.TotalItems.ShouldBe(1);
|
||||||
result.Items.ShouldAllBe(item => (item.Description ?? string.Empty).Contains("All Your Favorite", StringComparison.OrdinalIgnoreCase));
|
result.Items.ShouldAllBe(item => (item.Description ?? string.Empty).Contains("All Your Favorite", StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Tags_Favorite_Exclude_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
TagStatus = TagStatus.FavoriteExcludeBlacklist
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(1);
|
||||||
|
result.TotalItems.ShouldBe(1);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Tags_Favorite_Include_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
TagStatus = TagStatus.FavoriteIncludeBlacklist
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(2);
|
||||||
|
result.TotalItems.ShouldBe(2);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002", "RJ0000003"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Tags_Not_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
TagStatus = TagStatus.NotBlacklisted
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(4);
|
||||||
|
result.TotalItems.ShouldBe(4);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000001", "RJ0000002", "RJ0000004", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Tags_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
TagStatus = TagStatus.Blacklisted
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(1);
|
||||||
|
result.TotalItems.ShouldBe(1);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000003"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_TagIds_Or()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
TagIds = [1,2],
|
||||||
|
IncludeAllTags = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(2);
|
||||||
|
result.TotalItems.ShouldBe(2);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000001", "RJ0000002"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_TagIds_And()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
TagIds = [1, 2],
|
||||||
|
IncludeAllTags = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(1);
|
||||||
|
result.TotalItems.ShouldBe(1);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000001"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Creators_Favorite_Exclude_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
CreatorStatus = CreatorStatus.FavoriteExcludeBlacklist
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(2);
|
||||||
|
result.TotalItems.ShouldBe(2);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Creators_Favorite_Include_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
CreatorStatus = CreatorStatus.FavoriteIncludeBlacklist
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(3);
|
||||||
|
result.TotalItems.ShouldBe(3);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002", "RJ0000003", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Creators_Not_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
CreatorStatus = CreatorStatus.NotBlacklisted
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(4);
|
||||||
|
result.TotalItems.ShouldBe(4);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000001", "RJ0000002", "RJ0000004", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Creators_Blacklisted()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
CreatorStatus = CreatorStatus.Blacklisted
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(1);
|
||||||
|
result.TotalItems.ShouldBe(1);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000003"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_CreatorIds_Or()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
CreatorIds = [1, 4],
|
||||||
|
IncludeAllCreators = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(3);
|
||||||
|
result.TotalItems.ShouldBe(3);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002", "RJ0000003", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_CreatorIds_And()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
CreatorIds = [1, 4],
|
||||||
|
IncludeAllCreators = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items.Length.ShouldBe(1);
|
||||||
|
result.TotalItems.ShouldBe(1);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_Release_Date_Ascending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.ReleaseDate, Application.Common.Search.SortDirection.Ascending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000001", "RJ0000004", "RJ0000003", "RJ0000002", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_Release_Date_Descending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.ReleaseDate, Application.Common.Search.SortDirection.Descending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000005", "RJ0000002", "RJ0000003", "RJ0000001", "RJ0000004"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_Downloads_Ascending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.Downloads, Application.Common.Search.SortDirection.Ascending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000004", "RJ0000005", "RJ0000003", "RJ0000001", "RJ0000002"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_Downloads_Descending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.Downloads, Application.Common.Search.SortDirection.Descending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002", "RJ0000001", "RJ0000003", "RJ0000004", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_WishlistCount_Ascending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.WishlistCount, Application.Common.Search.SortDirection.Ascending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000003", "RJ0000004", "RJ0000001", "RJ0000005", "RJ0000002"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_WishlistCount_Descending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.WishlistCount, Application.Common.Search.SortDirection.Descending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002", "RJ0000005", "RJ0000001", "RJ0000004", "RJ0000003"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_StarRating_Ascending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.StarRating, Application.Common.Search.SortDirection.Ascending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000004", "RJ0000005", "RJ0000003", "RJ0000001", "RJ0000002"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Sort_By_StarRating_Descending()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
SortOptions =
|
||||||
|
[
|
||||||
|
new(VoiceWorkSortField.StarRating, Application.Common.Search.SortDirection.Descending)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002", "RJ0000001", "RJ0000003", "RJ0000004", "RJ0000005"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Release_Date_Range()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
ReleaseDateStart = new DateTime(2025, 1, 1),
|
||||||
|
ReleaseDateEnd = new DateTime(2025, 1, 2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000001", "RJ0000003"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Downloads_Range()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
MinDownloads = 100,
|
||||||
|
MaxDownloads = 10000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000001", "RJ0000002"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Filter_Favorite()
|
||||||
|
{
|
||||||
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
VoiceWorkSearchProvider provider = InitializeVoiceWorkSearchProvider(context);
|
||||||
|
|
||||||
|
var options = new SearchOptions<VoiceWorkSearchCriteria, VoiceWorkSortField>()
|
||||||
|
{
|
||||||
|
Criteria = new()
|
||||||
|
{
|
||||||
|
ShowFavoriteVoiceWorks = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await provider.SearchAsync(options);
|
||||||
|
|
||||||
|
result.Items
|
||||||
|
.OrderBy(item => item.ProductId)
|
||||||
|
.Select(item => item.ProductId)
|
||||||
|
.ShouldBe(["RJ0000002"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user