< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: AsyncResponse.Internal.RelationalNamePlan
Assembly: AsyncResponse.Transports.PostgreSQL
File(s): /_/src/Shared/RelationalNamePlan.cs
Line coverage
100%
Covered lines: 15
Uncovered lines: 0
Coverable lines: 15
Total lines: 71
Line coverage: 100%
Branch coverage
91%
Covered branches: 11
Total branches: 12
Branch coverage: 91.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
RequireDistinct(...)100%66100%
DerivedName(...)83.33%66100%

File(s)

/_/src/Shared/RelationalNamePlan.cs

#LineLine coverage
 1namespace AsyncResponse.Internal;
 2
 3/// <summary>
 4/// Pairwise distinctness for a store's effective object-name plan: the configured names plus every
 5/// index and sequence name derived from them. Derived-name helpers reserve suffix space by
 6/// truncating the stem, so two long configured names can still derive one name — and a configured
 7/// name can occupy a derived one outright — after which <c>CREATE ... IF NOT EXISTS</c> (or SQL
 8/// Server's <c>IF OBJECT_ID(...) IS NULL</c>) silently skips the object instead of failing.
 9/// Source-linked into the packages that own such a plan (separate packages cannot share compiled
 10/// code); the caller supplies the guidance tail so each options type keeps naming its own objects.
 11/// </summary>
 12internal static class RelationalNamePlan
 13{
 14    /// <summary>
 15    /// Throws when two entries resolve to the same name. Comparison is case-insensitive even where
 16    /// the DDL quotes identifiers (case-sensitive to PostgreSQL): a plan distinct only by letter
 17    /// case is a misconfiguration magnet, and SQL Server's catalogs fold case by default anyway.
 18    /// </summary>
 19    public static void RequireDistinct((string Role, string Name)[] plan, string optionsName, string guidance)
 20    {
 685621        for (var i = 0; i < plan.Length; i++)
 22        {
 1028023            for (var j = i + 1; j < plan.Length; j++)
 24            {
 257225                if (string.Equals(plan[i].Name, plan[j].Name, StringComparison.OrdinalIgnoreCase))
 26                {
 27                    // BOTH spellings, not just one: the comparison folds case, so a collision can
 28                    // exist between names the operator's configuration shows as different
 29                    // ("Messages" vs "messages"). Reporting a single spelling made that error read
 30                    // as a false positive, with nothing pointing at the case-fold rule above.
 431                    throw new InvalidOperationException(
 432                        $"{optionsName}: the {plan[i].Role} ('{plan[i].Name}') and the {plan[j].Role} ('{plan[j].Name}')
 433                        $"the same name — object names are compared case-insensitively" + guidance);
 34                }
 35            }
 36        }
 85637    }
 38
 39    /// <summary>
 40    /// A derived object name with the suffix space RESERVED before the provider's identifier cap:
 41    /// the stem is truncated, never the composed name. Truncating "{stem}{suffix}" as a whole lets
 42    /// a maximum-length table derive its OWN name, after which <c>CREATE ... IF NOT EXISTS</c> (or
 43    /// SQL Server's <c>IF OBJECT_ID(...) IS NULL</c> / <c>sys.indexes</c> guard) matches the
 44    /// existing object and silently creates nothing — and two derived names can collapse onto one
 45    /// another the same way.
 46    /// <para>
 47    /// The single implementation of a rule that was previously copy-pasted across the channel and
 48    /// transport stores, each with its own cap constant. Callers pass their provider's cap.
 49    /// </para>
 50    /// </summary>
 51    /// <exception cref="ArgumentOutOfRangeException">
 52    /// <paramref name="suffix"/> leaves no room for a stem inside <paramref name="identifierCap"/>.
 53    /// Guarded explicitly: the slice below would otherwise take a negative length and fail schema
 54    /// creation with a bare index-out-of-range that names neither the suffix nor the cap.
 55    /// </exception>
 56    public static string DerivedName(string stem, string suffix, int identifierCap)
 57    {
 256658        if (identifierCap <= 0 || stem.Length + suffix.Length <= identifierCap)
 255059            return stem + suffix;
 60
 1661        if (suffix.Length >= identifierCap)
 62        {
 263            throw new ArgumentOutOfRangeException(
 264                nameof(suffix),
 265                $"The derived-name suffix '{suffix}' is {suffix.Length} characters, which leaves no room for a stem insi
 266                $"{identifierCap}-character identifier limit. Shorten the suffix.");
 67        }
 68
 1469        return stem[..(identifierCap - suffix.Length)] + suffix;
 70    }
 71}