<commit_before>﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace IntelliTect.Coalesce.Helpers.IncludeTree
{
    public static class IncludeTreeExtensions
    {
        public static IncludeTree GetIncludeTree(this IQueryable queryable, string rootName = null)
        {
            var expression = queryable.Expression;
            IncludeTree root = (queryable.Provider as IncludableQueryProvider)?.IncludeTree ?? new IncludeTree { PropertyName = rootName };
            IncludeTree currentNode = null;

            // When we get to the root of the queryable, it won't be a MethodCallExpression.
            while (expression is MethodCallExpression)
            {
                // callExpr.Arguments[0] is the entire previous query.
                // callExpr.Arguments[1] is the lambda for the property specifier
                var callExpr = expression as MethodCallExpression;

                if (callExpr.Method.Name == nameof(EntityFrameworkQueryableExtensions.Include)
                 || callExpr.Method.Name == nameof(EntityFrameworkQueryableExtensions.ThenInclude))
                {
                    // I'm like a wizard with all these casts.
                    var body = ((MemberExpression)((LambdaExpression)((UnaryExpression)callExpr.Arguments[1]).Operand).Body);

                    IncludeTree tail;
                    var head = IncludeTree.ParseMemberExpression(body, out tail);

                    // If we had a child from a ThenInclude, add it to the tail of this node.
                    if (currentNode != null)
                        tail.AddChild(currentNode);

                    // Save the head of this expression in case we're parsing a ThenInclude.<commit_msg>Add proper exception when calling GetIncludeTree on something that can't have an IncludeTree.<commit_after>﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace IntelliTect.Coalesce.Helpers.IncludeTree
{
    public static class IncludeTreeExtensions
    {
        public static IncludeTree GetIncludeTree(this IQueryable queryable, string rootName = null)
        {
            if (!(queryable.Provider is IncludableQueryProvider) && !(queryable.Provider is EntityQueryProvider))
            {
                throw new ArgumentException(
                    $"Can't get an IncludeTree from an IQueryable with an IQueryProvider of type {queryable.Provider.GetType().Name}. "
                    + "Try using .IncludedSeparately(...) and .ThenIncluded(...) to capture includes.");
            }

            var expression = queryable.Expression;
            IncludeTree root = (queryable.Provider as IncludableQueryProvider)?.IncludeTree ?? new IncludeTree { PropertyName = rootName };
            IncludeTree currentNode = null;

            // When we get to the root of the queryable, it won't be a MethodCallExpression.
            while (expression is MethodCallExpression)
            {
                // callExpr.Arguments[0] is the entire previous query.
                // callExpr.Arguments[1] is the lambda for the property specifier
                var callExpr = expression as MethodCallExpression;

                if (callExpr.Method.Name == nameof(EntityFrameworkQueryableExtensions.Include)
                 || callExpr.Method.Name == nameof(EntityFrameworkQueryableExtensions.ThenInclude))
                {
                    // I'm like a wizard with all these casts.
                    var body = ((MemberExpression)((LambdaExpression)((UnaryExpression)callExpr.Arguments[1]).Operand).Body);

                    IncludeTree tail;
                    var head = IncludeTree.ParseMemberExpression(body, out tail);

                    // If we had a child from a ThenInclude, add it to the tail of this node.
                    if (currentNode != null)
                        tail.AddChild(currentNode);

                    // Save the head of this expression in case we're parsing a ThenInclude.
{'fraction_non_alphanumeric': 0.07397899649941657, 'fraction_numerical': 0.0014002333722287048, 'mean_word_length': 2.296923076923077, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4941104', 'n_tokens_mistral': 1024, 'n_tokens_neox': 967, 'n_words': 314}