Story
This commit is contained in:
19
SVSim.Database/Repositories/Story/IStoryMasterRepository.cs
Normal file
19
SVSim.Database/Repositories/Story/IStoryMasterRepository.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using SVSim.Database.Entities.Story;
|
||||
|
||||
namespace SVSim.Database.Repositories.Story;
|
||||
|
||||
public interface IStoryMasterRepository
|
||||
{
|
||||
Task<List<StorySection>> GetSectionsByFamilyAsync(StoryApiType apiType);
|
||||
Task<List<StoryWorld>> GetWorldsForSectionsAsync(IEnumerable<int> worldIds);
|
||||
Task<List<StoryChapter>> GetChaptersBySectionCharaAsync(int sectionId, int charaId);
|
||||
|
||||
/// <summary>
|
||||
/// Bulk-load chapter scalars (no owned collections) across multiple sections in one round-trip.
|
||||
/// Used by the section rollup to avoid N+1 per (section, chara) lookups.
|
||||
/// </summary>
|
||||
Task<List<StoryChapter>> GetChaptersBySectionsAsync(IEnumerable<int> sectionIds);
|
||||
|
||||
Task<StoryChapter?> GetChapterByIdAsync(int storyId);
|
||||
Task<SpecialBattleSetting?> GetSbsByIdAsync(int sbsId);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using SVSim.Database.Entities.Story;
|
||||
|
||||
namespace SVSim.Database.Repositories.Story;
|
||||
|
||||
public interface IViewerStoryProgressRepository
|
||||
{
|
||||
Task<Dictionary<int, ViewerStoryProgress>> GetProgressForChaptersAsync(long viewerId, IEnumerable<int> storyIds);
|
||||
Task<HashSet<int>> GetBranchUnlockedStoryIdsAsync(long viewerId, IEnumerable<int> storyIds);
|
||||
|
||||
Task UpsertProgressAsync(long viewerId, int storyId, bool? isFinish, bool? isSkipped);
|
||||
Task UpsertBranchUnlockAsync(long viewerId, int storyId);
|
||||
}
|
||||
49
SVSim.Database/Repositories/Story/StoryMasterRepository.cs
Normal file
49
SVSim.Database/Repositories/Story/StoryMasterRepository.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database.Entities.Story;
|
||||
|
||||
namespace SVSim.Database.Repositories.Story;
|
||||
|
||||
public class StoryMasterRepository : IStoryMasterRepository
|
||||
{
|
||||
private readonly SVSimDbContext _db;
|
||||
public StoryMasterRepository(SVSimDbContext db) { _db = db; }
|
||||
|
||||
public Task<List<StorySection>> GetSectionsByFamilyAsync(StoryApiType apiType)
|
||||
{
|
||||
var families = apiType == StoryApiType.AllStory
|
||||
? new[] { StoryApiType.Main } // AllStory effectively returns Main per spec
|
||||
: new[] { apiType };
|
||||
return _db.StorySections.Where(s => families.Contains(s.StoryApiType))
|
||||
.OrderBy(s => s.AllStoryOrderId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<List<StoryWorld>> GetWorldsForSectionsAsync(IEnumerable<int> worldIds)
|
||||
=> _db.StoryWorlds.Where(w => worldIds.Contains(w.Id)).ToListAsync();
|
||||
|
||||
public Task<List<StoryChapter>> GetChaptersBySectionCharaAsync(int sectionId, int charaId)
|
||||
=> _db.StoryChapters
|
||||
.Include(c => c.BattleSettings).Include(c => c.Rewards).Include(c => c.SubChapters)
|
||||
.Where(c => c.SectionId == sectionId && c.CharaId == charaId)
|
||||
.ToListAsync();
|
||||
|
||||
// No Includes — the rollup only reads SectionId/CharaId/StoryId. Including the three owned
|
||||
// collections here would cartesian-explode across ~677 chapters and turn a single query into
|
||||
// a multi-MB result set.
|
||||
public Task<List<StoryChapter>> GetChaptersBySectionsAsync(IEnumerable<int> sectionIds)
|
||||
{
|
||||
var ids = sectionIds.ToList();
|
||||
return _db.StoryChapters
|
||||
.AsNoTracking()
|
||||
.Where(c => ids.Contains(c.SectionId))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public Task<StoryChapter?> GetChapterByIdAsync(int storyId)
|
||||
=> _db.StoryChapters
|
||||
.Include(c => c.BattleSettings).Include(c => c.Rewards).Include(c => c.SubChapters)
|
||||
.FirstOrDefaultAsync(c => c.StoryId == storyId);
|
||||
|
||||
public Task<SpecialBattleSetting?> GetSbsByIdAsync(int sbsId)
|
||||
=> _db.SpecialBattleSettings.FirstOrDefaultAsync(s => s.Id == sbsId);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database.Entities.Story;
|
||||
|
||||
namespace SVSim.Database.Repositories.Story;
|
||||
|
||||
public class ViewerStoryProgressRepository : IViewerStoryProgressRepository
|
||||
{
|
||||
private readonly SVSimDbContext _db;
|
||||
public ViewerStoryProgressRepository(SVSimDbContext db) { _db = db; }
|
||||
|
||||
public async Task<Dictionary<int, ViewerStoryProgress>> GetProgressForChaptersAsync(
|
||||
long viewerId, IEnumerable<int> storyIds)
|
||||
{
|
||||
var ids = storyIds.ToList();
|
||||
var rows = await _db.ViewerStoryProgress
|
||||
.Where(p => p.ViewerId == viewerId && ids.Contains(p.StoryId))
|
||||
.ToListAsync();
|
||||
return rows.ToDictionary(r => r.StoryId);
|
||||
}
|
||||
|
||||
public async Task<HashSet<int>> GetBranchUnlockedStoryIdsAsync(long viewerId, IEnumerable<int> storyIds)
|
||||
{
|
||||
var ids = storyIds.ToList();
|
||||
var rows = await _db.ViewerStoryBranchUnlocks
|
||||
.Where(u => u.ViewerId == viewerId && ids.Contains(u.StoryId))
|
||||
.Select(u => u.StoryId)
|
||||
.ToListAsync();
|
||||
return new HashSet<int>(rows);
|
||||
}
|
||||
|
||||
public async Task UpsertProgressAsync(long viewerId, int storyId, bool? isFinish, bool? isSkipped)
|
||||
{
|
||||
var row = await _db.ViewerStoryProgress.FirstOrDefaultAsync(
|
||||
p => p.ViewerId == viewerId && p.StoryId == storyId);
|
||||
if (row is null)
|
||||
{
|
||||
row = new ViewerStoryProgress { ViewerId = viewerId, StoryId = storyId };
|
||||
_db.ViewerStoryProgress.Add(row);
|
||||
}
|
||||
if (isFinish.HasValue) { row.IsFinish = isFinish.Value; if (isFinish.Value) row.FinishedAt = DateTime.UtcNow; }
|
||||
if (isSkipped.HasValue) { row.IsSkipped = isSkipped.Value; if (isSkipped.Value) row.SkippedAt = DateTime.UtcNow; }
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpsertBranchUnlockAsync(long viewerId, int storyId)
|
||||
{
|
||||
bool exists = await _db.ViewerStoryBranchUnlocks
|
||||
.AnyAsync(u => u.ViewerId == viewerId && u.StoryId == storyId);
|
||||
if (!exists)
|
||||
{
|
||||
_db.ViewerStoryBranchUnlocks.Add(new ViewerStoryBranchUnlock
|
||||
{ ViewerId = viewerId, StoryId = storyId, UnlockedAt = DateTime.UtcNow });
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user