From 34aed0a436c291244fc11aebf1154971de990c37 Mon Sep 17 00:00:00 2001 From: ntr Date: Wed, 30 Aug 2023 20:21:08 +1000 Subject: [PATCH] pure sql baybeee --- .vscode/launch.json | 35 +++++++++++++++ .vscode/settings.json | 3 ++ .vscode/tasks.json | 41 ++++++++++++++++++ Assets/Src/LapService.cs | 2 +- Server/Controllers/LapController.cs | 39 ++++++++++++++--- Server/Controllers/LapTimesController.cs | 26 +++++------ .../SpaceRaceDbContextModelSnapshot.cs | 2 +- Server/Program.cs | 2 + Server/Repositories/SpaceRaceDbContext.cs | 14 ++---- Server/Server.csproj | 1 + Server/Services/LapTimesService.cs | 43 +++++++++++++++++++ TODO.md | 4 -- 12 files changed, 173 insertions(+), 39 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 Server/Services/LapTimesService.cs diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3082541 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md. + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/Server/bin/Debug/net7.0/Server.dll", + "args": [], + "cwd": "${workspaceFolder}/Server", + "stopAtEntry": false, + // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser + "serverReadyAction": { + "action": "openExternally", + "pattern": "\\bNow listening on:\\s+(https?://\\S+)" + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..39f40dc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dotnet.defaultSolution": "Server/Server.sln" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..634fdb4 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Server/Server.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Server/Server.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/Server/Server.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Assets/Src/LapService.cs b/Assets/Src/LapService.cs index 851dae5..779d387 100644 --- a/Assets/Src/LapService.cs +++ b/Assets/Src/LapService.cs @@ -75,7 +75,7 @@ public class LapService { Created = DateTimeOffset.UtcNow, }; - Debug.Log(JsonConvert.SerializeObject(dto)); + Debug.Log($"Posting lap: {JsonConvert.SerializeObject(dto)}"); using (UnityWebRequest req = UnityWebRequest.Post("localhost:40080/Lap", JsonConvert.SerializeObject(dto), "application/json")) { yield return req.SendWebRequest(); diff --git a/Server/Controllers/LapController.cs b/Server/Controllers/LapController.cs index 2387619..35fa977 100644 --- a/Server/Controllers/LapController.cs +++ b/Server/Controllers/LapController.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Data.SqlClient; + +using Server.Services; using SpaceRace.Shared; namespace Server.Controllers; @@ -10,10 +12,16 @@ namespace Server.Controllers; public class LapController : ControllerBase { private readonly ILogger _logger; private SpaceRaceDbContext _db; + private LapTimesService _lapTimes; - public LapController(ILogger logger, SpaceRaceDbContext db) { + public LapController( + ILogger logger, + SpaceRaceDbContext db, + LapTimesService lapTimes + ){ _logger = logger; _db = db; + _lapTimes = lapTimes; } [HttpGet()] @@ -28,11 +36,25 @@ public class LapController : ControllerBase { } [HttpPost()] - public async Task Post(LapDTO dto) { + public async Task Post(LapDTO dto) { Lap existing = _db.Laps .SingleOrDefault(l => l.UserId == dto.UserId && l.Map == dto.Map); - Lap v = new Lap { + Lap NotFaster(Lap e) { + _logger.LogInformation($"Lap was not a PB."); + return e; + } + + Lap UpdateValues(Lap e) => new Lap { + Id = e.Id, + UserId = e.UserId, + Map = e.Map, + Time = dto.Time, + Sectors = dto.Sectors, + Created = DateTimeOffset.Now, + }; + + Lap Create() => new Lap { Id = Guid.NewGuid(), UserId = dto.UserId, Map = dto.Map, @@ -41,8 +63,13 @@ public class LapController : ControllerBase { Created = DateTimeOffset.UtcNow, }; - _db.Laps.Add(v); - await _db.SaveChangesAsync(); - return v; + Lap v = existing switch { + null => Create(), + Lap e when dto.Time < e.Time => UpdateValues(e), + _ => NotFaster(existing), + }; + + await _db.Laps.Upsert(v).RunAsync(); + return _lapTimes.LapTimes(v.UserId, v.Map); } } diff --git a/Server/Controllers/LapTimesController.cs b/Server/Controllers/LapTimesController.cs index 96eb924..c8ca977 100644 --- a/Server/Controllers/LapTimesController.cs +++ b/Server/Controllers/LapTimesController.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Data.SqlClient; + +using Server.Services; using SpaceRace.Shared; namespace Server.Controllers; @@ -10,29 +12,21 @@ namespace Server.Controllers; public class LapTimesController : ControllerBase { private readonly ILogger _logger; private SpaceRaceDbContext _db; + private LapTimesService _lapTimes; - public LapTimesController(ILogger logger, SpaceRaceDbContext db) { + public LapTimesController( + ILogger logger, + SpaceRaceDbContext db, + LapTimesService lapTimes + ){ _logger = logger; _db = db; + _lapTimes = lapTimes; } [HttpGet()] public LapTimesDTO LapTimes(Guid userId, string mapName) { _logger.LogInformation($"{userId} {mapName}"); - - PbDTO pb = _db.PbDTO - .Where(pb => pb.UserId == userId) - .Where(pb => pb.Map == mapName) - .SingleOrDefault(); - - PbDTO lapRecord = _db.PbDTO - .Where(pb => pb.Map == mapName) - .OrderBy(pb => pb.Position) - .FirstOrDefault(); - - return new LapTimesDTO { - Pb = pb, - LapRecord = lapRecord, - }; + return _lapTimes.LapTimes(userId, mapName); } } diff --git a/Server/Migrations/SpaceRaceDbContextModelSnapshot.cs b/Server/Migrations/SpaceRaceDbContextModelSnapshot.cs index 598e150..acfc3af 100644 --- a/Server/Migrations/SpaceRaceDbContextModelSnapshot.cs +++ b/Server/Migrations/SpaceRaceDbContextModelSnapshot.cs @@ -113,7 +113,7 @@ namespace Server.Migrations b.ToTable((string)null); - b.ToSqlQuery("WITH ranked AS (\n SELECT *, rank() OVER (ORDER BY \"Time\" ASC) AS \"Position\", COUNT(\"Id\") OVER () AS \"Completions\"\n FROM \"Laps\"\n)\n\nSELECT * FROM ranked"); + b.ToSqlQuery("SELECT *, rank() OVER (ORDER BY \"Time\" ASC) AS \"Position\", COUNT(\"Id\") OVER () AS \"Completions\"\n FROM \"Laps\"\n)\n\n"); }); #pragma warning restore 612, 618 } diff --git a/Server/Program.cs b/Server/Program.cs index 3cf1645..c61d46d 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Server; +using Server.Services; var builder = WebApplication.CreateBuilder(args); @@ -11,6 +12,7 @@ builder.Services.AddDbContextPool(options => { assembly => assembly.MigrationsAssembly(typeof(SpaceRaceDbContext).Assembly.FullName) ); }); +builder.Services.AddScoped(); var app = builder.Build(); diff --git a/Server/Repositories/SpaceRaceDbContext.cs b/Server/Repositories/SpaceRaceDbContext.cs index a9cef43..172f1e4 100644 --- a/Server/Repositories/SpaceRaceDbContext.cs +++ b/Server/Repositories/SpaceRaceDbContext.cs @@ -1,5 +1,7 @@ +using System; using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using SpaceRace.Shared; @@ -14,19 +16,8 @@ public class SpaceRaceDbContext : DbContext { protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); new SpaceRaceInitialiser(modelBuilder).Seed(); - - var pbQuery = $$""" - WITH ranked AS ( - SELECT *, rank() OVER (ORDER BY "Time" ASC) AS "Position", COUNT("Id") OVER () AS "Completions" - FROM "Laps" - ) - - SELECT * FROM ranked - """; - modelBuilder.Entity() .HasNoKey() - .ToSqlQuery(pbQuery) .ToTable(null as string); } } @@ -34,6 +25,7 @@ public class SpaceRaceDbContext : DbContext { [Index(nameof(UserId), nameof(Map), IsUnique = true)] [Index(nameof(Map))] public class Lap { + [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] public Guid Id { get; set; } public Guid UserId { get; set; } [Required] public DateTimeOffset Created { get; set; } diff --git a/Server/Server.csproj b/Server/Server.csproj index 0c09921..26e815a 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -7,6 +7,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Server/Services/LapTimesService.cs b/Server/Services/LapTimesService.cs new file mode 100644 index 0000000..32cf178 --- /dev/null +++ b/Server/Services/LapTimesService.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore; + +using SpaceRace.Shared; + +namespace Server.Services; + +public class LapTimesService { + private readonly ILogger _logger; + private SpaceRaceDbContext _db; + + public LapTimesService(ILogger logger, SpaceRaceDbContext db) { + _logger = logger; + _db = db; + } + + public LapTimesDTO LapTimes(Guid userId, string mapName) { + PbDTO pb = _db.PbDTO + .FromSql($$""" + WITH ranked AS ( + SELECT *, rank() OVER (ORDER BY "Time" ASC) AS "Position", COUNT("Id") OVER () AS "Completions" + FROM "Laps" + WHERE "Map" = {{mapName}} + ORDER BY "Position" ASC + ) + + SELECT * FROM ranked + WHERE "UserId" = {{userId}} + """).FirstOrDefault(); + + PbDTO lapRecord = _db.PbDTO + .FromSql($$""" + SELECT *, rank() OVER (ORDER BY "Time" ASC) AS "Position", COUNT("Id") OVER () AS "Completions" + FROM "Laps" + WHERE "Map" = {{mapName}} + ORDER BY "Position" ASC + """).FirstOrDefault(); + + return new LapTimesDTO { + Pb = pb, + LapRecord = lapRecord, + }; + } +} \ No newline at end of file diff --git a/TODO.md b/TODO.md index 0caeeb2..ddd0702 100644 --- a/TODO.md +++ b/TODO.md @@ -2,10 +2,6 @@ - post times to server - update on scene change - - check time is lower when posting - - return pb and lap record - - convert laps to lapDTO? - - include sectors - controls - mouse / controller sens