< Summary

Information
Class: NGql.Core.Abstractions.InlineFragmentDefinition
Assembly: NGql.Core
File(s): /home/runner/work/NGql/NGql/src/Core/Abstractions/InlineFragmentDefinition.cs
Line coverage
100%
Covered lines: 21
Uncovered lines: 0
Coverable lines: 21
Total lines: 122
Line coverage: 100%
Branch coverage
100%
Covered branches: 18
Total branches: 18
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
get_TypeName()100%11100%
get_Fields()100%22100%
GetOrCreateFieldsStore()100%22100%
get_InlineFragments()100%22100%
get_SpreadFragments()100%22100%
get_Directives()100%22100%
get_HasDirectives()100%22100%
AddDirective(...)100%11100%
.cctor()100%11100%
Equals(...)100%44100%
GetHashCode()100%11100%

File(s)

/home/runner/work/NGql/NGql/src/Core/Abstractions/InlineFragmentDefinition.cs

#LineLine coverage
 1using System.Diagnostics.CodeAnalysis;
 2using System.Text.Json.Serialization;
 3
 4namespace NGql.Core.Abstractions;
 5
 6/// <summary>
 7///     Represents a GraphQL inline fragment — a type-conditional selection set rendered as
 8///     <c>... on TypeName { … }</c>. Used to narrow a parent field whose schema type is a
 9///     union or interface to a specific concrete type.
 10/// </summary>
 11/// <remarks>
 12///     Inline fragments are siblings of regular fields under their parent <see cref="FieldDefinition"/>
 13///     (see <see cref="FieldDefinition.InlineFragments"/>). They are kept in a separate collection
 14///     because their access pattern (lookup by type name) and rendering shape (the <c>... on</c>
 15///     prefix) differ from regular fields. Nested inline fragments — fragments inside fragments —
 16///     are supported recursively.
 17/// </remarks>
 18[SuppressMessage("Minor Code Smell", "S2292:Trivial properties should be auto-implemented")]
 19public sealed record InlineFragmentDefinition
 20{
 21    internal FieldChildren? _fields;
 22    internal Dictionary<string, InlineFragmentDefinition>? _fragments;
 23    internal List<string>? _spreadFragments;
 24    internal List<FieldDirective>? _directives;
 25
 26    /// <summary>
 27    /// Creates an inline fragment for <paramref name="typeName"/> with no children.
 28    /// </summary>
 29    /// <param name="typeName">The GraphQL type the fragment narrows to (e.g. <c>"Repository"</c>).
 30    /// Rendered verbatim — case matters, GraphQL type names are case-sensitive.</param>
 990631    public InlineFragmentDefinition(string typeName)
 32    {
 990633        if (string.IsNullOrWhiteSpace(typeName))
 34        {
 935            throw new ArgumentException("Inline fragment type name cannot be null or whitespace.", nameof(typeName));
 36        }
 37
 989738        TypeName = typeName;
 989739    }
 40
 41    /// <summary>
 42    /// The GraphQL type the fragment narrows to. Rendered verbatim after <c>... on </c>.
 43    /// </summary>
 44    [JsonPropertyName("typeName")]
 1011645    public string TypeName { get; init; }
 46
 47    /// <summary>
 48    /// Fields selected when the parent value's runtime type is <see cref="TypeName"/>.
 49    /// </summary>
 50    [JsonPropertyName("fields")]
 51    public IReadOnlyDictionary<string, FieldDefinition> Fields
 3352        => (IReadOnlyDictionary<string, FieldDefinition>?)_fields ?? EmptyFields;
 53
 54    /// <summary>
 55    /// Get-or-add the underlying <see cref="FieldChildren"/> store. Internal so the builder
 56    /// can pass a stable reference when the user's lambda adds fields to the fragment.
 57    /// </summary>
 58    internal FieldChildren GetOrCreateFieldsStore()
 21059        => _fields ??= new FieldChildren();
 60
 61    /// <summary>
 62    /// Nested inline fragments inside this fragment's selection set. Useful when the fragment's
 63    /// fields themselves return union/interface types that need further narrowing.
 64    /// </summary>
 65    [JsonPropertyName("inlineFragments")]
 66    public IReadOnlyDictionary<string, InlineFragmentDefinition> InlineFragments
 1567        => (IReadOnlyDictionary<string, InlineFragmentDefinition>?)_fragments ?? EmptyFragments;
 68
 69    /// <summary>
 70    /// Names of <see cref="NamedFragmentDefinition"/>s spread into this inline fragment's
 71    /// selection set. See <see cref="FieldDefinition.SpreadFragments"/> for the contract; this
 72    /// property mirrors it.
 73    /// </summary>
 74    [JsonPropertyName("spreadFragments")]
 75    public IReadOnlyList<string> SpreadFragments
 676        => (IReadOnlyList<string>?)_spreadFragments ?? EmptySpreadFragments;
 77
 78    /// <summary>
 79    /// Directives attached to this inline fragment, in the order they were added. Rendered after
 80    /// <c>... on TypeName</c> and before the selection set, e.g. <c>... on Admin @include(if:$a){ … }</c>.
 81    /// Returns an empty list (never null) when the fragment has no directives.
 82    /// </summary>
 83    /// <remarks>
 84    /// See <see cref="Builders.FieldBuilder.IncludeIf(Variable)"/>/<see cref="Builders.FieldBuilder.SkipIf(Variable)"/>
 85    /// <see cref="Builders.FieldBuilder.Directive(string, System.Collections.Generic.Dictionary{string, object?})"/>
 86    /// called on the <see cref="Builders.FieldBuilder"/> passed to
 87    /// <see cref="Builders.FieldBuilder.OnType(string, System.Action{Builders.FieldBuilder})"/>'s
 88    /// lambda — the same directive API fields expose, attaching to the fragment itself rather than
 89    /// its parent field.
 90    /// </remarks>
 91    [JsonPropertyName("directives")]
 92    public IReadOnlyList<FieldDirective> Directives
 693        => (IReadOnlyList<FieldDirective>?)_directives ?? EmptyDirectives;
 94
 95    /// <summary>
 96    /// Gets a value indicating whether this inline fragment carries any directives. Unlike reading
 97    /// <see cref="Directives"/>, this check allocates nothing on directive-less fragments.
 98    /// </summary>
 99    [JsonIgnore]
 6100    public bool HasDirectives => _directives is { Count: > 0 };
 101
 102    /// <summary>
 103    /// Append a directive to this fragment's directive list. Shares <see cref="DirectiveListOps"/>
 104    /// with <see cref="FieldDefinition.AddDirective"/>, so <c>include</c>/<c>skip</c> collapse
 105    /// (last-call-wins) and every other directive dedups structurally, identically to fields.
 106    /// </summary>
 3107    internal void AddDirective(FieldDirective directive) => DirectiveListOps.Add(ref _directives, directive);
 108
 3109    private static readonly IReadOnlyDictionary<string, FieldDefinition> EmptyFields = new Dictionary<string, FieldDefin
 3110    private static readonly IReadOnlyDictionary<string, InlineFragmentDefinition> EmptyFragments = new Dictionary<string
 3111    private static readonly IReadOnlyList<string> EmptySpreadFragments = Array.Empty<string>();
 3112    private static readonly IReadOnlyList<FieldDirective> EmptyDirectives = Array.Empty<FieldDirective>();
 113
 114    public bool Equals(InlineFragmentDefinition? other)
 115    {
 21116        if (other is null) return false;
 18117        if (ReferenceEquals(this, other)) return true;
 12118        return string.Equals(TypeName, other.TypeName, StringComparison.Ordinal);
 119    }
 120
 6121    public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(TypeName);
 122}