< Summary - ZhEaIsNsAaBn.Libraries coverage (affected: 23 packages)

Information
Line coverage
86%
Covered lines: 25
Uncovered lines: 4
Coverable lines: 29
Total lines: 77
Line coverage: 86.2%
Branch coverage
82%
Covered branches: 33
Total branches: 40
Branch coverage: 82.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Split(...)96.66%3030100%
Key(...)100%11100%
Format(...)40%231050%

File(s)

/home/runner/work/ZhEaIsNsAaBn.Libraries.V1/ZhEaIsNsAaBn.Libraries.V1/src/DataBasePackages/ZhEaIsNsAaBn.DbSeeder/Ordering/SeedRowLevels.cs

#LineLine coverage
 1namespace ZhEaIsNsAaBn.DbSeeder;
 2
 3/// <summary>
 4/// Splits the rows of a self-referencing table into dependency levels: level 0 references no row of the file (or only i
 5/// only rows of earlier levels. Each level is one ordinary upsert, so a row is always written after the row it points t
 6/// insert / update counts and audit stamps stay exact.
 7/// </summary>
 8internal static class SeedRowLevels
 9{
 10    /// <param name="columns">The written columns.</param>
 11    /// <param name="rows">The rows (values aligned with <paramref name="columns"/>).</param>
 12    /// <param name="selfReferences">The table's foreign keys to itself whose columns are all written.</param>
 13    /// <returns>The levels; or the indexes of the rows left in a cycle.</returns>
 14    public static (IReadOnlyList<IReadOnlyList<IReadOnlyList<object?>>>? Levels, IReadOnlyList<int> Cycle) Split(
 15            IReadOnlyList<SeedColumn> columns,
 16            IReadOnlyList<IReadOnlyList<object?>> rows,
 17            IReadOnlyList<IForeignKey> selfReferences
 18        )
 19    {
 185620        if ( selfReferences.Count == 0 ) { return ( [ rows ], [] ); }
 21
 22
 17823        var index        = columns.Select( ( c, i ) => (c.PropertyName, i) ).ToDictionary( x => x.PropertyName, x => x.i
 17824        var dependencies = new HashSet<int>[ rows.Count ];
 25
 71226        foreach ( var foreignKey in selfReferences )
 27        {
 17828            var principal = foreignKey.PrincipalKey.Properties.Select( p => index[ p.Name ] ).ToArray();
 17829            var dependent = foreignKey.Properties.Select( p => index[ p.Name ] ).ToArray();
 17830            var byKey     = new Dictionary<string, int>( StringComparer.Ordinal );
 31
 194932            for ( var r = 0; r < rows.Count; r++ ) { byKey.TryAdd( Key( rows[ r ], principal ), r ); }
 33
 34
 141835            for ( var r = 0; r < rows.Count; r++ )
 36            {
 53137                dependencies[ r ] ??= [];
 38
 53139                if ( dependent.Any( c => rows[ r ][ c ] is null ) ) { continue; }
 40
 70941                if ( byKey.TryGetValue( Key( rows[ r ], dependent ), out var parent ) && parent != r ) { dependencies[ r
 42            }
 43        }
 44
 45
 17846        var levels = new List<IReadOnlyList<IReadOnlyList<object?>>>();
 17847        var done   = new HashSet<int>();
 48
 69749        while ( done.Count < rows.Count )
 50        {
 52251            var level = Enumerable.Range( 0, rows.Count ).Where( r => !done.Contains( r ) && dependencies[ r ].All( done
 52
 52553            if ( level.Count == 0 ) { return ( null, Enumerable.Range( 0, rows.Count ).Where( r => !done.Contains( r ) )
 54
 55
 51956            levels.Add( level.Select( r => rows[ r ] ).ToList() );
 51957            done.UnionWith( level );
 58        }
 59
 60
 17561        return ( levels, [] );
 62    }
 63
 64
 65    /// The text of the values at <paramref name="columns"/> (a row key).
 162766    internal static string Key( IReadOnlyList<object?> row, int[] columns ) => string.Join( '\u001F', columns.Select( c 
 67
 68    private static string Format( object? value )
 162769        => value switch
 162770               {
 071                   null           => "\u0000",
 072                   byte[] bytes   => Convert.ToBase64String( bytes ),
 073                   DateTime date  => date.ToString( "O", CultureInfo.InvariantCulture ),
 162774                   IFormattable f => f.ToString( null, CultureInfo.InvariantCulture ),
 075                   _              => value.ToString() ?? string.Empty
 162776               };
 77}