< Summary

Information
Class: Services.BitrixStockServices.EfSqlRawParameterGuard
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/BitrixStockServices/EfSqlRawParameterGuard.cs
Line coverage
72%
Covered lines: 13
Uncovered lines: 5
Coverable lines: 18
Total lines: 42
Line coverage: 72.2%
Branch coverage
80%
Covered branches: 8
Total branches: 10
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
Validate(...)100%88100%
Materialize(...)100%210%
Materialize(...)0%620%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/BitrixStockServices/EfSqlRawParameterGuard.cs

#LineLine coverage
 1using System.Text.RegularExpressions;
 2
 3namespace Services.BitrixStockServices;
 4
 5/// <summary>
 6/// Защита от передачи <see cref="CancellationToken"/> в params object[] ExecuteSqlRawAsync
 7/// (попадает в SQL как {N} и ломает EF: "store type mapping for CancellationToken").
 8/// </summary>
 9public static class EfSqlRawParameterGuard
 10{
 111    private static readonly Regex PlaceholderRegex = new(@"\{(\d+)\}", RegexOptions.Compiled);
 12
 13    public static void Validate(string sql, IReadOnlyList<object?> parameters, string checkpoint)
 14    {
 23815        for (var i = 0; i < parameters.Count; i++)
 16        {
 11017            if (parameters[i] is CancellationToken)
 718                throw new InvalidOperationException(
 719                    $"[{checkpoint}] CancellationToken на позиции {i} в SQL-параметрах — используйте перегрузку ExecuteS
 20        }
 21
 922        var maxIndex = PlaceholderRegex.Matches(sql)
 6423            .Select(m => int.Parse(m.Groups[1].Value))
 924            .DefaultIfEmpty(-1)
 925            .Max();
 26
 927        if (maxIndex >= 0 && parameters.Count <= maxIndex)
 228            throw new InvalidOperationException(
 229                $"[{checkpoint}] Ожидается минимум {maxIndex + 1} SQL-параметров, передано {parameters.Count}");
 730    }
 31
 032    public static object[] Materialize(params object?[] parameters) => Materialize((IReadOnlyList<object?>)parameters);
 33
 34    /// <summary>EF ExecuteSqlRawAsync: object?[] → object[]. null остаётся null — EF Core 8 + Pomelo обрабатывает его к
 35    public static object[] Materialize(IReadOnlyList<object?> parameters)
 36    {
 037        var result = new object[parameters.Count];
 038        for (var i = 0; i < parameters.Count; i++)
 039            result[i] = parameters[i]!;
 040        return result;
 41    }
 42}