using SurrealDb.Net; using TarninaHub.Application.Abstractions; using TarninaHub.Application.Dtos; namespace TarninaHub.Infrastructure.Persistence; public sealed class PartnershipService : IPartnershipService { private const string SelectFields = "type::string(id) AS id, type::string(initiator) AS initiator, subject, " + "array::map(partners, |$p| type::string($p)) AS partners, status"; private readonly ISurrealDbClient _client; public PartnershipService(ISurrealDbClient client) { _client = client; } public async Task> ListForUserAsync( string userId, bool isStaff, CancellationToken cancellationToken) { var parameters = new Dictionary(); var where = string.Empty; if (!isStaff) { var (table, id) = SurrealRecordId.Split(userId); where = " WHERE initiator = type::record($table, $id)"; parameters["table"] = table; parameters["id"] = id; } var response = await _client.RawQuery( $"SELECT {SelectFields} FROM partnership{where} ORDER BY subject ASC;", parameters, cancellationToken); response.EnsureAllOks(); var rows = response.GetValue>(0) ?? []; return rows.Select(Map).ToList(); } public async Task CreateAsync( string initiatorId, CreatePartnershipRequest request, CancellationToken cancellationToken) { var partnershipId = Guid.NewGuid().ToString("N"); var (initiatorTable, initiatorIdPart) = SurrealRecordId.Split(initiatorId); var partners = request.Partners ?? []; var parameters = new Dictionary { ["id"] = partnershipId, ["subject"] = request.Subject, ["initiatorTable"] = initiatorTable, ["initiatorId"] = initiatorIdPart, }; var partnerExpressions = new List(partners.Count); for (var i = 0; i < partners.Count; i++) { var (table, id) = SurrealRecordId.Split(partners[i]); parameters[$"table{i}"] = table; parameters[$"id{i}"] = id; partnerExpressions.Add($"type::record($table{i}, $id{i})"); } var response = await _client.RawQuery( "CREATE type::record('partnership', $id) SET " + "initiator = type::record($initiatorTable, $initiatorId), subject = $subject, " + $"partners = [{string.Join(", ", partnerExpressions)}], status = 'proposed'; " + $"SELECT {SelectFields} FROM type::record('partnership', $id) LIMIT 1;", parameters, cancellationToken); response.EnsureAllOks(); var rows = response.GetValue>(1) ?? []; return rows.Count > 0 ? Map(rows[0]) : throw new InvalidOperationException("Partnership could not be loaded after creation."); } private static PartnershipResponse Map(PartnershipRow row) => new( row.Id, row.Initiator, row.Subject, row.Partners, row.Status); }