< Summary

Information
Class: TeleFlow.Telegram.Internal.TelegramRequestTypeMetadataCache
Assembly: TeleFlow.Telegram.Client
File(s): /_/src/TeleFlow.Telegram.Client/Internal/TelegramRequestTypeMetadata.cs
Line coverage
100%
Covered lines: 27
Uncovered lines: 0
Coverable lines: 27
Total lines: 91
Line coverage: 100%
Branch coverage
90%
Covered branches: 18
Total branches: 20
Branch coverage: 90%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
Get(...)100%11100%
IsScalarType(...)92.85%1414100%
Create(...)75%44100%
IsAlwaysJsonIgnored(...)100%22100%

File(s)

/_/src/TeleFlow.Telegram.Client/Internal/TelegramRequestTypeMetadata.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2using System.Reflection;
 3using System.Text.Json.Serialization;
 4
 5namespace TeleFlow.Telegram.Internal;
 6
 7/// <summary>
 8/// Caches reflection metadata used by Telegram request content building.
 9/// The cache keeps JSON property discovery, ignored-property handling, and scalar detection in one place.
 10/// It is shared by JSON/multipart routing and multipart rendering so both paths interpret generated schema types consis
 11/// </summary>
 12internal static class TelegramRequestTypeMetadataCache
 13{
 114    private static readonly ConcurrentDictionary<Type, TelegramRequestTypeMetadata> MetadataCache = new();
 15
 16    public static TelegramRequestTypeMetadata Get(Type type)
 17    {
 14118        ArgumentNullException.ThrowIfNull(type);
 14119        return MetadataCache.GetOrAdd(type, Create);
 20    }
 21
 22    public static bool IsScalarType(Type type)
 23    {
 31324        ArgumentNullException.ThrowIfNull(type);
 25
 31326        var scalarType = Nullable.GetUnderlyingType(type) ?? type;
 27
 31328        return scalarType.IsPrimitive ||
 31329               scalarType.IsEnum ||
 31330               scalarType == typeof(string) ||
 31331               scalarType == typeof(decimal) ||
 31332               scalarType == typeof(DateTime) ||
 31333               scalarType == typeof(DateTimeOffset) ||
 31334               scalarType == typeof(Guid);
 35    }
 36
 37    private static TelegramRequestTypeMetadata Create(Type type)
 38    {
 4039        var readableProperties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
 22840            .Where(static property => property.CanRead && property.GetIndexParameters().Length == 0)
 4041            // Keep reflection metadata aligned with System.Text.Json and avoid evaluating ignored getters
 4042            // while deciding whether a request needs multipart.
 22743            .Where(static property => !IsAlwaysJsonIgnored(property))
 22644            .Select(static property => new TelegramRequestPropertyMetadata(
 22645                property,
 22646                property.GetCustomAttribute<JsonPropertyNameAttribute>()?.Name))
 4047            .ToArray();
 48
 4049        var telegramProperties = readableProperties
 22650            .Where(static property => property.JsonPropertyName is not null)
 4051            .ToArray();
 52
 4053        return new TelegramRequestTypeMetadata(IsScalarType(type), readableProperties, telegramProperties);
 54    }
 55
 56    private static bool IsAlwaysJsonIgnored(PropertyInfo property)
 57    {
 22758        var ignore = property.GetCustomAttribute<JsonIgnoreAttribute>();
 22759        return ignore?.Condition == JsonIgnoreCondition.Always;
 60    }
 61}
 62
 63/// <summary>
 64/// Reflection snapshot for one request-related CLR type.
 65/// It separates all readable properties from Telegram JSON fields discovered through JsonPropertyName metadata.
 66/// </summary>
 67internal sealed record TelegramRequestTypeMetadata(
 68    bool IsScalar,
 69    TelegramRequestPropertyMetadata[] ReadableProperties,
 70    TelegramRequestPropertyMetadata[] TelegramProperties);
 71
 72/// <summary>
 73/// Reflection wrapper around a readable CLR property and its optional Telegram JSON field name.
 74/// Multipart rendering uses it to read CLR values and write Telegram field names without repeating reflection rules.
 75/// </summary>
 76internal sealed record TelegramRequestPropertyMetadata(PropertyInfo Property, string? JsonPropertyName)
 77{
 78    public Type PropertyType => Property.PropertyType;
 79
 80    public string Name => Property.Name;
 81
 82    public string TelegramName =>
 83        JsonPropertyName ??
 84        throw new InvalidOperationException(
 85            $"Telegram payload property '{Property.DeclaringType?.FullName}.{Property.Name}' is missing JsonPropertyName
 86
 87    public object? GetValue(object value)
 88    {
 89        return Property.GetValue(value);
 90    }
 91}