<commit_before>using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models.Links;

namespace JsonApiDotNetCore.Models
{
    /// <summary>
    /// Create a HasMany relationship through a many-to-many join relationship.
    /// This type can only be applied on types that implement IList.
    /// </summary>
    /// 
    /// <example>
    /// In the following example, we expose a relationship named "tags"
    /// through the navigation property `ArticleTags`.
    /// The `Tags` property is decorated as `NotMapped` so that EF does not try
    /// to map this to a database relationship.
    /// <code>
    /// [NotMapped]
    /// [HasManyThrough("tags", nameof(ArticleTags))]
    /// public List&lt;Tag&gt; Tags { get; set; }
    /// public List&lt;ArticleTag&gt; ArticleTags { get; set; }
    /// </code>
    /// </example>
    public class HasManyThroughAttribute : HasManyAttribute
    {
        /// <summary>
        /// Create a HasMany relationship through a many-to-many join relationship.
        /// The public name exposed through the API will be based on the configured convention.
        /// </summary>
        /// 
        /// <param name="internalThroughName">The name of the navigation property that will be used to get the HasMany relationship</param>
        /// <param name="relationshipLinks">Which links are available. Defaults to <see cref="Link.All"/></param>
        /// <param name="canInclude">Whether or not this relationship can be included using the <c>?include=public-name</c> query string</param>
        /// <param name="mappedBy">The name of the entity mapped property, defaults to null</param>
        /// 
        /// <example>
        /// <code>
        /// [HasManyThrough(nameof(ArticleTags), documentLinks: Link.All, canInclude: true)]
        /// </code>
        /// </example>
        public HasManyThroughAttribute(string internalThroughName, Link relationshipLinks = Link.All, bool canInclude = true, string mappedBy = null)
        : base(null, relationshipLinks, canInclude, mappedBy)
        {
            InternalThroughName = internalThroughName;
        }

        /// <summary>
        /// Create a HasMany relationship through a many-to-many join relationship.
        /// </summary>
        /// 
        /// <param name="publicName">The relationship name as exposed by the API</param>
        /// <param name="internalThroughName">The name of the navigation property that will be used to get the HasMany relationship</param>
        /// <param name="documentLinks">Which links are available. Defaults to <see cref="Link.All"/></param>
        /// <param name="canInclude">Whether or not this relationship can be included using the <c>?include=public-name</c> query string</param>
        /// <param name="mappedBy">The name of the entity mapped property, defaults to null</param>
        /// 
        /// <example>
        /// <code>
        /// [HasManyThrough("tags", nameof(ArticleTags), documentLinks: Link.All, canInclude: true)]
        /// </code>
        /// </example>
        public HasManyThroughAttribute(string publicName, string internalThroughName, Link documentLinks = Link.All, bool canInclude = true, string mappedBy = null)
        : base(publicName, documentLinks, canInclude, mappedBy)
        {
            InternalThroughName = internalThroughName;
        }

        /// <summary>
        /// Traverses the through the provided entity and returns the 
        /// value of the relationship on the other side of a join entity
        /// (e.g. Articles.ArticleTags.Tag).
        /// </summary>
        public override object GetValue(object entity)
        {
            var throughNavigationProperty = entity.GetType()
                                        .GetProperties()
                                        .SingleOrDefault(p => string.Equals(p.Name, InternalThroughName, StringComparison.OrdinalIgnoreCase));

            var throughEntities = throughNavigationProperty.GetValue(entity);

            if (throughEntities == null)
                // return an empty list for the right-type of the property.
                return TypeHelper.CreateListFor(RightType);

            // the right entities are included on the navigation/through entities. Extract and return them.
            var rightEntities = new List<IIdentifiable>();
            foreach (var rightEntity in (IList)throughEntities)
                rightEntities.Add((IIdentifiable)RightProperty.GetValue(rightEntity));

            return rightEntities.Cast(RightType);<commit_msg>Removed leftover `mappedby` property (#679)<commit_after>using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models.Links;

namespace JsonApiDotNetCore.Models
{
    /// <summary>
    /// Create a HasMany relationship through a many-to-many join relationship.
    /// This type can only be applied on types that implement IList.
    /// </summary>
    /// 
    /// <example>
    /// In the following example, we expose a relationship named "tags"
    /// through the navigation property `ArticleTags`.
    /// The `Tags` property is decorated as `NotMapped` so that EF does not try
    /// to map this to a database relationship.
    /// <code>
    /// [NotMapped]
    /// [HasManyThrough("tags", nameof(ArticleTags))]
    /// public List&lt;Tag&gt; Tags { get; set; }
    /// public List&lt;ArticleTag&gt; ArticleTags { get; set; }
    /// </code>
    /// </example>
    public class HasManyThroughAttribute : HasManyAttribute
    {
        /// <summary>
        /// Create a HasMany relationship through a many-to-many join relationship.
        /// The public name exposed through the API will be based on the configured convention.
        /// </summary>
        /// 
        /// <param name="internalThroughName">The name of the navigation property that will be used to get the HasMany relationship</param>
        /// <param name="relationshipLinks">Which links are available. Defaults to <see cref="Link.All"/></param>
        /// <param name="canInclude">Whether or not this relationship can be included using the <c>?include=public-name</c> query string</param>
        /// 
        /// <example>
        /// <code>
        /// [HasManyThrough(nameof(ArticleTags), documentLinks: Link.All, canInclude: true)]
        /// </code>
        /// </example>
        public HasManyThroughAttribute(string internalThroughName, Link relationshipLinks = Link.All, bool canInclude = true)
        : base(null, relationshipLinks, canInclude)
        {
            InternalThroughName = internalThroughName;
        }

        /// <summary>
        /// Create a HasMany relationship through a many-to-many join relationship.
        /// </summary>
        /// 
        /// <param name="publicName">The relationship name as exposed by the API</param>
        /// <param name="internalThroughName">The name of the navigation property that will be used to get the HasMany relationship</param>
        /// <param name="documentLinks">Which links are available. Defaults to <see cref="Link.All"/></param>
        /// <param name="canInclude">Whether or not this relationship can be included using the <c>?include=public-name</c> query string</param>
        /// 
        /// <example>
        /// <code>
        /// [HasManyThrough("tags", nameof(ArticleTags), documentLinks: Link.All, canInclude: true)]
        /// </code>
        /// </example>
        public HasManyThroughAttribute(string publicName, string internalThroughName, Link documentLinks = Link.All, bool canInclude = true)
        : base(publicName, documentLinks, canInclude)
        {
            InternalThroughName = internalThroughName;
        }

        /// <summary>
        /// Traverses the through the provided entity and returns the 
        /// value of the relationship on the other side of a join entity
        /// (e.g. Articles.ArticleTags.Tag).
        /// </summary>
        public override object GetValue(object entity)
        {
            var throughNavigationProperty = entity.GetType()
                                        .GetProperties()
                                        .SingleOrDefault(p => string.Equals(p.Name, InternalThroughName, StringComparison.OrdinalIgnoreCase));

            var throughEntities = throughNavigationProperty.GetValue(entity);

            if (throughEntities == null)
                // return an empty list for the right-type of the property.
                return TypeHelper.CreateListFor(RightType);

            // the right entities are included on the navigation/through entities. Extract and return them.
            var rightEntities = new List<IIdentifiable>();
            foreach (var rightEntity in (IList)throughEntities)
                rightEntities.Add((IIdentifiable)RightProperty.GetValue(rightEntity));

            return rightEntities.Cast(RightType);
{'fraction_non_alphanumeric': 0.11182772190642763, 'fraction_numerical': 0.00032794053344993443, 'mean_word_length': 2.3772609819121446, 'pattern_counts': {'":': 0, '<': 89, '<?xml version=': 0, '>': 91, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6440193', 'n_tokens_mistral': 2294, 'n_tokens_neox': 2221, 'n_words': 731}