< Summary

Information
Class: NGql.Core.Caching.TypeMetadataCache
Assembly: NGql.Core
File(s): /home/runner/work/NGql/NGql/src/Core/Caching/TypeCache.cs
Line coverage
100%
Covered lines: 2
Uncovered lines: 0
Coverable lines: 2
Total lines: 90
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%

File(s)

/home/runner/work/NGql/NGql/src/Core/Caching/TypeCache.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2using System.Diagnostics.CodeAnalysis;
 3using System.Reflection;
 4using System.Runtime.CompilerServices;
 5
 6namespace NGql.Core.Caching;
 7
 8/// <summary>
 9/// Simple cache for common GraphQL types with memory and CPU optimizations
 10/// </summary>
 11[SuppressMessage("Minor Code Smell", "S3267:Loops should be simplified with \"LINQ\" expressions")]
 12internal static class TypeCache
 13{
 14    private static readonly ConcurrentDictionary<string, string> CustomTypes = new();
 15
 16    // Pre-intern the most common GraphQL types (ordered by frequency)
 17    private static readonly string[] CommonTypes =
 18    [
 19        Constants.DefaultFieldType,    // "String" - most common
 20        "Int", "Boolean", "ID",        // Other common scalars
 21        Constants.ObjectFieldType,     // "object" - for nested fields
 22        "String!", "Int!", "Boolean!", // Non-null variants
 23        "Float", "Float!",             // Less common but still frequent
 24        Constants.ArrayTypeMarker      // "[]" - array marker
 25    ];
 26
 27    // Pre-intern common nullable type patterns
 28    private static readonly string[] CommonNullableTypes =
 29    [
 30        "String?", "Int?", "Boolean?", "ID?", "Float?"
 31    ];
 32
 33    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 34    public static string GetInternedType(ReadOnlySpan<char> type)
 35    {
 36        // ULTRA FAST PATH: Empty type defaults to String
 37        if (type.IsEmpty)
 38        {
 39            return Constants.DefaultFieldType;
 40        }
 41
 42        // OPTIMIZED PATH: Single combined check for both common and nullable types
 43        // This eliminates the O(n+m) double-loop pattern and does a single pass
 44        var allTypes = CombinedCommonTypes.Value;
 45        foreach (var commonType in allTypes)
 46        {
 47            if (type.SequenceEqual(commonType.AsSpan()))
 48            {
 49                return commonType; // Already interned
 50            }
 51        }
 52
 53        // Standard path for other types
 54        var typeString = type.ToString();
 55        return CustomTypes.GetOrAdd(typeString, typeString);
 56    }
 57
 58    // Lazy-initialized combined array to avoid allocation at static init time
 59    private static readonly Lazy<string[]> CombinedCommonTypes = new(() =>
 60    {
 61        var combined = new string[CommonTypes.Length + CommonNullableTypes.Length];
 62        CommonTypes.CopyTo(combined, 0);
 63        CommonNullableTypes.CopyTo(combined, CommonTypes.Length);
 64        return combined;
 65    });
 66
 67    /// <summary>
 68    /// Interns a type string for memory efficiency - alias for GetInternedType
 69    /// </summary>
 70    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 71    public static string InternType(ReadOnlySpan<char> type) => GetInternedType(type);
 72}
 73
 74/// <summary>
 75/// Caches reflection metadata for type introspection
 76/// </summary>
 77internal static class TypeMetadataCache
 78{
 79    /// <summary>
 80    /// Caches PropertyInfo pairs (Key, Value) for KeyValuePair&lt;,&gt; generic types.
 81    /// Caller must guarantee the cached type is a closed KeyValuePair&lt;TKey,TValue&gt; — those
 82    /// always expose Key and Value properties, so the cached pair is non-nullable.
 83    /// </summary>
 384    internal static readonly ConcurrentDictionary<Type, (PropertyInfo Key, PropertyInfo Value)> KvpPropertyCache = new()
 85
 86    /// <summary>
 87    /// Caches PropertyInfo[] per object type for the default WriteObject reflection branch.
 88    /// </summary>
 389    internal static readonly ConcurrentDictionary<Type, PropertyInfo[]> ObjectPropertyCache = new();
 90}

Methods/Properties

.cctor()