Optimize slot endpoints (#750)

* Remove AsEnumerable usage in SlotsController

* Remove AsEnumerable usages from LBP3 categories

* Fix typo in OrderBy statement
This commit is contained in:
Josh 2023-04-26 15:13:27 -05:00 committed by GitHub
parent 6b3b8d8271
commit eb79d7cf48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 40 deletions

View file

@ -8,6 +8,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Entities.Token;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms; using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
using LBPUnion.ProjectLighthouse.Types.Misc;
using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Serialization;
using LBPUnion.ProjectLighthouse.Types.Users; using LBPUnion.ProjectLighthouse.Types.Users;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -213,8 +214,13 @@ public class SlotsController : ControllerBase
GameVersion gameVersion = token.GameVersion; GameVersion gameVersion = token.GameVersion;
List<SlotBase> slots = (await this.database.Slots.ByGameVersion(gameVersion, false, true) List<SlotBase> slots = (await this.database.Slots.ByGameVersion(gameVersion, false, true)
.ToAsyncEnumerable() .Select(s => new SlotMetadata
.OrderByDescending(s => s.RatingLBP1) {
Slot = s,
RatingLbp1 = this.database.RatedLevels.Where(r => r.SlotId == s.SlotId).Average(r => (double?)r.RatingLBP1) ?? 3.0,
})
.OrderByDescending(s => s.RatingLbp1)
.Select(s => s.Slot)
.Skip(Math.Max(0, pageStart - 1)) .Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 30)) .Take(Math.Min(pageSize, 30))
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token)); .ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
@ -304,12 +310,15 @@ public class SlotsController : ControllerBase
if (pageSize <= 0) return this.BadRequest(); if (pageSize <= 0) return this.BadRequest();
Random rand = new();
List<SlotBase> slots = (await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion) List<SlotBase> slots = (await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
.AsAsyncEnumerable() .Select(s => new SlotMetadata
.OrderByDescending(s => s.Thumbsup) {
.ThenBy(_ => rand.Next()) Slot = s,
ThumbsUp = this.database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
})
.OrderByDescending(s => s.ThumbsUp)
.ThenBy(_ => EF.Functions.Random())
.Select(s => s.Slot)
.Skip(Math.Max(0, pageStart - 1)) .Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 30)) .Take(Math.Min(pageSize, 30))
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token)); .ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
@ -335,24 +344,19 @@ public class SlotsController : ControllerBase
if (pageSize <= 0) return this.BadRequest(); if (pageSize <= 0) return this.BadRequest();
Random rand = new(); string game = getGameFilter(gameFilterType, token.GameVersion) switch
{
GameVersion.LittleBigPlanet1 => "LBP1",
GameVersion.LittleBigPlanet2 => "LBP2",
GameVersion.LittleBigPlanet3 => "LBP3",
GameVersion.LittleBigPlanetVita => "LBP2",
_ => "",
};
string colName = $"Plays{game}Unique";
List<SlotBase> slots = (await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion) List<SlotBase> slots = (await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
.AsAsyncEnumerable() .OrderByDescending(s => EF.Property<int>(s, colName))
.OrderByDescending(
// probably not the best way to do this?
s =>
{
return getGameFilter(gameFilterType, token.GameVersion) switch
{
GameVersion.LittleBigPlanet1 => s.PlaysLBP1Unique,
GameVersion.LittleBigPlanet2 => s.PlaysLBP2Unique,
GameVersion.LittleBigPlanet3 => s.PlaysLBP3Unique,
GameVersion.LittleBigPlanetVita => s.PlaysLBP2Unique,
_ => s.PlaysUnique,
};
})
.ThenBy(_ => rand.Next())
.Skip(Math.Max(0, pageStart - 1)) .Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 30)) .Take(Math.Min(pageSize, 30))
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token)); .ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
@ -379,9 +383,13 @@ public class SlotsController : ControllerBase
if (pageSize <= 0) return this.BadRequest(); if (pageSize <= 0) return this.BadRequest();
List<SlotBase> slots = (await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion) List<SlotBase> slots = (await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
.AsAsyncEnumerable() .Select(s => new SlotMetadata
{
Slot = s,
Hearts = this.database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
})
.OrderByDescending(s => s.Hearts) .OrderByDescending(s => s.Hearts)
.ThenBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue)) .Select(s => s.Slot)
.Skip(Math.Max(0, pageStart - 1)) .Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 30)) .Take(Math.Min(pageSize, 30))
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token)); .ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));

View file

@ -1,10 +1,11 @@
#nullable enable #nullable enable
using System.Security.Cryptography;
using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Database;
using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Misc;
using LBPUnion.ProjectLighthouse.Types.Users; using LBPUnion.ProjectLighthouse.Types.Users;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
@ -14,13 +15,27 @@ public class HighestRatedCategory : Category
public override string Description { get; set; } = "Community Highest Rated content"; public override string Description { get; set; } = "Community Highest Rated content";
public override string IconHash { get; set; } = "g820603"; public override string IconHash { get; set; } = "g820603";
public override string Endpoint { get; set; } = "thumbs"; public override string Endpoint { get; set; } = "thumbs";
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).AsEnumerable().MaxBy(s => s.Thumbsup); public override SlotEntity? GetPreviewSlot(DatabaseContext database) =>
public override IEnumerable<SlotEntity> GetSlots database.Slots.Where(s => s.Type == SlotType.User)
(DatabaseContext database, int pageStart, int pageSize) .Select(s => new SlotMetadata
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true) {
.AsEnumerable() Slot = s,
.OrderByDescending(s => s.Thumbsup) ThumbsUp = database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
.ThenBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue)) })
.OrderByDescending(s => s.ThumbsUp)
.Select(s => s.Slot)
.FirstOrDefault();
public override IEnumerable<SlotEntity> GetSlots(DatabaseContext database, int pageStart, int pageSize) =>
database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
.Select(s => new SlotMetadata
{
Slot = s,
ThumbsUp = database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
})
.OrderByDescending(s => s.ThumbsUp)
.ThenBy(_ => EF.Functions.Random())
.Select(s => s.Slot)
.Skip(Math.Max(0, pageStart - 1)) .Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 20)); .Take(Math.Min(pageSize, 20));
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User); public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User);

View file

@ -1,9 +1,9 @@
#nullable enable #nullable enable
using System.Security.Cryptography;
using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Database;
using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Misc;
using LBPUnion.ProjectLighthouse.Types.Users; using LBPUnion.ProjectLighthouse.Types.Users;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
@ -14,13 +14,27 @@ public class MostHeartedCategory : Category
public override string Description { get; set; } = "The Most Hearted Content"; public override string Description { get; set; } = "The Most Hearted Content";
public override string IconHash { get; set; } = "g820607"; public override string IconHash { get; set; } = "g820607";
public override string Endpoint { get; set; } = "mostHearted"; public override string Endpoint { get; set; } = "mostHearted";
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).AsEnumerable().MaxBy(s => s.Hearts);
public override IEnumerable<SlotEntity> GetSlots public override SlotEntity? GetPreviewSlot(DatabaseContext database) =>
(DatabaseContext database, int pageStart, int pageSize) database.Slots.Where(s => s.Type == SlotType.User)
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true) .Select(s => new SlotMetadata
.AsEnumerable() {
Slot = s,
Hearts = database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
})
.OrderByDescending(s => s.Hearts) .OrderByDescending(s => s.Hearts)
.ThenBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue)) .Select(s => s.Slot)
.FirstOrDefault();
public override IEnumerable<SlotEntity> GetSlots(DatabaseContext database, int pageStart, int pageSize) =>
database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
.Select(s => new SlotMetadata
{
Slot = s,
Hearts = database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
})
.OrderByDescending(s => s.Hearts)
.Select(s => s.Slot)
.Skip(Math.Max(0, pageStart - 1)) .Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 20)); .Take(Math.Min(pageSize, 20));
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User); public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User);

View file

@ -0,0 +1,11 @@
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
namespace LBPUnion.ProjectLighthouse.Types.Misc;
public class SlotMetadata
{
public required SlotEntity Slot { get; init; }
public double RatingLbp1 { get; init; }
public int ThumbsUp { get; init; }
public int Hearts { get; init; }
}

View file

@ -60,6 +60,7 @@ public class GameUserSlot : SlotBase, INeedsPreparationForSerialization
[XmlElement("resource")] [XmlElement("resource")]
public string[]? Resources { get; set; } public string[]? Resources { get; set; }
public bool ShouldSerializeResources() => false;
[XmlElement("icon")] [XmlElement("icon")]
public string IconHash { get; set; } = ""; public string IconHash { get; set; } = "";