using SurrealDb.Net; using TarninaHub.Application.Abstractions; using TarninaHub.Application.Dtos; namespace TarninaHub.Infrastructure.Persistence; public sealed class TrendService : ITrendService { private readonly ISurrealDbClient _client; public TrendService(ISurrealDbClient client) { _client = client; } public async Task GetAsync( string? challengeId, DateTimeOffset from, DateTimeOffset to, CancellationToken cancellationToken) { var counts = await CountSubmissionsAsync(challengeId, from, to, cancellationToken); var challenges = await LoadChallengesAsync(cancellationToken); var points = challenges .Where(challenge => string.IsNullOrWhiteSpace(challengeId) || string.Equals(challenge.Id, challengeId, StringComparison.Ordinal)) .Select(challenge => new TrendPoint( challenge.Id, challenge.Name, counts.GetValueOrDefault(challenge.Id))) .OrderByDescending(point => point.SubmissionCount) .ToList(); return new TrendsResponse(from, to, points); } private async Task> CountSubmissionsAsync( string? challengeId, DateTimeOffset from, DateTimeOffset to, CancellationToken cancellationToken) { var parameters = new Dictionary { ["from"] = from, ["to"] = to }; var clauses = new List { "created_at >= $from", "created_at <= $to" }; if (!string.IsNullOrWhiteSpace(challengeId)) { var (table, id) = SurrealRecordId.Split(challengeId); clauses.Add("problem.challenge = type::record($challengeTable, $challengeId)"); parameters["challengeTable"] = table; parameters["challengeId"] = id; } var response = await _client.RawQuery( "SELECT type::string(problem.challenge) AS challenge FROM submission WHERE " + string.Join(" AND ", clauses) + ";", parameters, cancellationToken); response.EnsureAllOks(); var rows = response.GetValue>(0) ?? []; return rows .Where(row => !string.IsNullOrWhiteSpace(row.Challenge)) .GroupBy(row => row.Challenge) .ToDictionary(group => group.Key, group => group.Count()); } private async Task> LoadChallengesAsync(CancellationToken cancellationToken) { var response = await _client.RawQuery( "SELECT type::string(id) AS id, name, order FROM social_challenge ORDER BY order;", cancellationToken: cancellationToken); response.EnsureAllOks(); return response.GetValue>(0) ?? []; } }