Forgot unversioned xd
This commit is contained in:
15
SVSim.Database/Common/BaseEntity.cs
Normal file
15
SVSim.Database/Common/BaseEntity.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace SVSim.Database.Common;
|
||||
|
||||
public class BaseEntity<TKey> : ITimeTrackedEntity
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public virtual TKey Id { get; set; }
|
||||
|
||||
public DateTime DateCreated { get; set; } = DateTime.MinValue;
|
||||
|
||||
public DateTime? DateUpdated { get; set; }
|
||||
}
|
||||
8
SVSim.Database/Common/IDataSeeder.cs
Normal file
8
SVSim.Database/Common/IDataSeeder.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace SVSim.Database.Common;
|
||||
|
||||
public interface IDataSeeder
|
||||
{
|
||||
void Seed(ModelBuilder builder);
|
||||
}
|
||||
14
SVSim.Database/Common/ITimeTrackedEntity.cs
Normal file
14
SVSim.Database/Common/ITimeTrackedEntity.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace SVSim.Database.Common;
|
||||
|
||||
public interface ITimeTrackedEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="DateTime"/> this entity was first added to the database.
|
||||
/// </summary>
|
||||
DateTime DateCreated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DateTime"/> this entity was last updated.
|
||||
/// </summary>
|
||||
DateTime? DateUpdated { get; set; }
|
||||
}
|
||||
33857
SVSim.Database/Migrations/20260523152741_Initial.Designer.cs
generated
Normal file
33857
SVSim.Database/Migrations/20260523152741_Initial.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
7071
SVSim.Database/Migrations/20260523152741_Initial.cs
Normal file
7071
SVSim.Database/Migrations/20260523152741_Initial.cs
Normal file
File diff suppressed because it is too large
Load Diff
14
SVSim.Database/Models/DeckCard.cs
Normal file
14
SVSim.Database/Models/DeckCard.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace SVSim.Database.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ShadowverseCardEntry"/> that appears in a <see cref="ShadowverseDeckEntry"/> N times.
|
||||
/// </summary>
|
||||
[Owned]
|
||||
public class DeckCard
|
||||
{
|
||||
public ShadowverseCardEntry Card { get; set; } = new ShadowverseCardEntry();
|
||||
|
||||
public int Count { get; set; }
|
||||
}
|
||||
90
SVSim.Database/Repositories/Deck/DeckRepository.cs
Normal file
90
SVSim.Database/Repositories/Deck/DeckRepository.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
|
||||
namespace SVSim.Database.Repositories.Deck;
|
||||
|
||||
public class DeckRepository : IDeckRepository
|
||||
{
|
||||
private const int MaxDecksPerFormat = 50;
|
||||
|
||||
private readonly SVSimDbContext _dbContext;
|
||||
|
||||
public DeckRepository(SVSimDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task<List<ShadowverseDeckEntry>> GetDecks(long viewerId, Format format)
|
||||
{
|
||||
var viewer = await _dbContext.Viewers
|
||||
.AsNoTracking()
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Class)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Sleeve)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.LeaderSkin)
|
||||
.FirstOrDefaultAsync(v => v.Id == viewerId);
|
||||
|
||||
return viewer?.Decks.Where(d => d.Format == format).OrderBy(d => d.Number).ToList()
|
||||
?? new List<ShadowverseDeckEntry>();
|
||||
}
|
||||
|
||||
public async Task<ShadowverseDeckEntry?> GetDeck(long viewerId, Format format, int deckNo)
|
||||
{
|
||||
var viewer = await _dbContext.Viewers
|
||||
.AsNoTracking()
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Class)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Sleeve)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.LeaderSkin)
|
||||
.FirstOrDefaultAsync(v => v.Id == viewerId);
|
||||
|
||||
return viewer?.Decks.FirstOrDefault(d => d.Format == format && d.Number == deckNo);
|
||||
}
|
||||
|
||||
public async Task<int> GetEmptyDeckNumber(long viewerId, Format format)
|
||||
{
|
||||
var taken = (await GetDecks(viewerId, format)).Select(d => d.Number).ToHashSet();
|
||||
for (int i = 1; i <= MaxDecksPerFormat; i++)
|
||||
{
|
||||
if (!taken.Contains(i)) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<ShadowverseDeckEntry> UpsertDeck(long viewerId, Format format, int deckNo,
|
||||
Action<ShadowverseDeckEntry> mutate)
|
||||
{
|
||||
var viewer = await _dbContext.Viewers
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Class)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Sleeve)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.LeaderSkin)
|
||||
.FirstOrDefaultAsync(v => v.Id == viewerId)
|
||||
?? throw new InvalidOperationException($"Viewer {viewerId} not found.");
|
||||
|
||||
var deck = viewer.Decks.FirstOrDefault(d => d.Format == format && d.Number == deckNo);
|
||||
if (deck is null)
|
||||
{
|
||||
deck = new ShadowverseDeckEntry { Format = format, Number = deckNo };
|
||||
viewer.Decks.Add(deck);
|
||||
}
|
||||
|
||||
mutate(deck);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return deck;
|
||||
}
|
||||
|
||||
public async Task DeleteDecks(long viewerId, Format format, IEnumerable<int> deckNos)
|
||||
{
|
||||
var viewer = await _dbContext.Viewers
|
||||
.Include(v => v.Decks)
|
||||
.FirstOrDefaultAsync(v => v.Id == viewerId);
|
||||
if (viewer is null) return;
|
||||
|
||||
var nos = deckNos.ToHashSet();
|
||||
var toRemove = viewer.Decks.Where(d => d.Format == format && nos.Contains(d.Number)).ToList();
|
||||
// Decks.ViewerId is nullable, so removing from the collection alone just orphans the
|
||||
// row (clears ViewerId, leaves the deck in the DB). Delete from the DbSet directly so
|
||||
// is_delete=1 and /deck/delete_deck_list actually remove the row.
|
||||
_dbContext.Decks.RemoveRange(toRemove);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
13
SVSim.Database/Repositories/Deck/IDeckRepository.cs
Normal file
13
SVSim.Database/Repositories/Deck/IDeckRepository.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
|
||||
namespace SVSim.Database.Repositories.Deck;
|
||||
|
||||
public interface IDeckRepository
|
||||
{
|
||||
Task<List<ShadowverseDeckEntry>> GetDecks(long viewerId, Format format);
|
||||
Task<ShadowverseDeckEntry?> GetDeck(long viewerId, Format format, int deckNo);
|
||||
Task<int> GetEmptyDeckNumber(long viewerId, Format format);
|
||||
Task<ShadowverseDeckEntry> UpsertDeck(long viewerId, Format format, int deckNo, Action<ShadowverseDeckEntry> mutate);
|
||||
Task DeleteDecks(long viewerId, Format format, IEnumerable<int> deckNos);
|
||||
}
|
||||
Reference in New Issue
Block a user