feat(friend): add ViewerFriend + ViewerFriendApply + ViewerPlayedTogether entities

Lays the persistence foundation for the /friend/* API surface. Three new
model classes with composite PKs / unique constraints / FK cascades registered
on SVSimDbContext; 4/4 persistence tests pass on SQLite in-memory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-09 21:40:08 -04:00
parent c1eec9057a
commit 1813217c16
5 changed files with 187 additions and 0 deletions

View File

@@ -112,6 +112,10 @@ public class SVSimDbContext : DbContext
public DbSet<SerialCodeRewardEntry> SerialCodeRewards => Set<SerialCodeRewardEntry>();
public DbSet<ViewerSerialCodeRedemption> ViewerSerialCodeRedemptions => Set<ViewerSerialCodeRedemption>();
public DbSet<ViewerFriend> ViewerFriends => Set<ViewerFriend>();
public DbSet<ViewerFriendApply> ViewerFriendApplies => Set<ViewerFriendApply>();
public DbSet<ViewerPlayedTogether> ViewerPlayedTogethers => Set<ViewerPlayedTogether>();
#endregion
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
@@ -455,6 +459,31 @@ public class SVSimDbContext : DbContext
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<ViewerFriend>(b =>
{
b.HasKey(e => new { e.OwnerViewerId, e.FriendViewerId });
b.HasIndex(e => new { e.OwnerViewerId, e.CreatedAt });
b.HasOne<Viewer>().WithMany().HasForeignKey(e => e.OwnerViewerId).OnDelete(DeleteBehavior.Cascade);
b.HasOne<Viewer>().WithMany().HasForeignKey(e => e.FriendViewerId).OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<ViewerFriendApply>(b =>
{
b.HasKey(e => e.Id);
b.HasIndex(e => new { e.FromViewerId, e.ToViewerId }).IsUnique();
b.HasIndex(e => e.ToViewerId);
b.HasOne<Viewer>().WithMany().HasForeignKey(e => e.FromViewerId).OnDelete(DeleteBehavior.Cascade);
b.HasOne<Viewer>().WithMany().HasForeignKey(e => e.ToViewerId).OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<ViewerPlayedTogether>(b =>
{
b.HasKey(e => new { e.OwnerViewerId, e.OpponentViewerId });
b.HasIndex(e => new { e.OwnerViewerId, e.PlayedAt });
b.HasOne<Viewer>().WithMany().HasForeignKey(e => e.OwnerViewerId).OnDelete(DeleteBehavior.Cascade);
// OpponentViewerId is NOT an FK — we want survivors' history to outlive a deleted opponent.
});
base.OnModelCreating(modelBuilder);
}