< Summary

Information
Class: Api.Utils.DbExceptionUtils
Assembly: Api
File(s): /home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Utils/DbExceptionUtils.cs
Line coverage
80%
Covered lines: 20
Uncovered lines: 5
Coverable lines: 25
Total lines: 64
Line coverage: 80%
Branch coverage
62%
Covered branches: 5
Total branches: 8
Branch coverage: 62.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
SaveChangesOrThrowAsync()50%4481.82%
TryGetPostgresException(...)75%4478.57%

File(s)

/home/runner/work/ProjectRead.ing/ProjectRead.ing/Api/Utils/DbExceptionUtils.cs

#LineLine coverage
 1// SPDX-FileCopyrightText: 2026 Alper Çelik <[email protected]>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5using Api.Database;
 6using HotChocolate;
 7using Npgsql;
 8
 9namespace Api.Utils;
 10
 11public static class DbExceptionUtils
 12{
 13    /// <summary>
 14    /// Saves changes; when PostgreSQL reports an error with <paramref name="sqlState"/>
 15    /// (<see langword="null"/> matches any PostgreSQL error), throws a
 16    /// <see cref="DomainException"/> tagged with <paramref name="code"/>/<paramref name="message"/>
 17    /// instead of the raw database error.
 18    /// </summary>
 19    public static async Task SaveChangesOrThrowAsync(
 20        this PGContext db,
 21        string? sqlState,
 22        string code,
 23        string message,
 24        CancellationToken ct
 25    )
 126    {
 27        try
 128        {
 129            await db.SaveChangesAsync(cancellationToken: ct);
 130        }
 131        catch (Exception ex) when (TryGetPostgresException(ex, out var pg))
 132        {
 133            if (sqlState is not null && sqlState != pg.SqlState)
 034            {
 035                throw;
 36            }
 37
 138            throw new DomainException(code, message);
 39        }
 140    }
 41
 42    /// <summary>
 43    /// Unwraps the PostgreSQL error behind an EF Core save failure, if there is one.
 44    /// </summary>
 45    public static bool TryGetPostgresException(Exception ex, out PostgresException pg)
 146    {
 147        while (true)
 148        {
 149            if (ex is PostgresException postgres)
 150            {
 151                pg = postgres;
 152                return true;
 53            }
 54
 155            if (ex.InnerException is null)
 056            {
 057                pg = null!;
 058                return false;
 59            }
 60
 161            ex = ex.InnerException;
 162        }
 163    }
 64}