<commit_before>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using Signum.Engine.Maps;
using Signum.Entities;
using Signum.Utilities;
using Signum.Utilities.Reflection;
using Signum.Engine.Properties;
using System.Data.SqlClient;
using Signum.Utilities.ExpressionTrees;

namespace Signum.Engine.Linq
{
    internal interface IProjectionRow
    {
        FieldReader Reader { get; }

        IRetriever Retriever { get; }

        IEnumerable<S> Lookup<K, S>(ProjectionToken token, K key);
    }

    internal class ProjectionRowEnumerator<T> : IProjectionRow, IEnumerator<T>
    {
        public FieldReader Reader { get; private set;}
        public IRetriever Retriever { get; private set; }

        public IProjectionRow Parent { get; private set; }

        SqlDataReader dataReader;

        T current;
        Func<IProjectionRow, T> projector; 
        Expression<Func<IProjectionRow, T>> projectorExpression;

        Dictionary<ProjectionToken, IEnumerable> lookups;

        internal ProjectionRowEnumerator(SqlDataReader dataReader, Expression<Func<IProjectionRow, T>> projectorExpression, Dictionary<ProjectionToken, IEnumerable> lookups, IRetriever retriever)
        {
            this.dataReader = dataReader;
            this.Reader = new FieldReader(dataReader);

            this.projectorExpression = ExpressionCompilableAsserter.Assert(projectorExpression);
            this.projector = projectorExpression.Compile();
            this.lookups = lookups;
            this.Row = -1;
            this.Retriever = retriever;
        }

        public T Current
        {
            get { return this.current; }
        }

        object IEnumerator.Current
        {
            get { return this.current; }
        }

        public int Row;
        public bool MoveNext()
        {
            if (dataReader.Read())
            {
                this.Row++;
                this.current = this.projector(this);
                return true;
            }
            return false;
        }

        public void Reset()
        {
        }

        public void Dispose()
        {
        }
 
        public IEnumerable<S> Lookup<K, S>(ProjectionToken token, K key)
        {
            Lookup<K, S> lookup = (Lookup<K, S>)lookups[token];

            if (!lookup.Contains(key))
                return Enumerable.Empty<S>();
            else
                return lookup[key];
        }
    }

    internal class ProjectionRowEnumerable<T> : IEnumerable<T>, IEnumerable
    {
        ProjectionRowEnumerator<T> enumerator;

        internal ProjectionRowEnumerable(ProjectionRowEnumerator<T> enumerator)
        {
            this.enumerator = enumerator;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return Interlocked.Exchange(ref enumerator, null)
                .ThrowIfNullC("Cannot enumerate more than once");
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }

    internal class ExpressionCompilableAsserter : SimpleExpressionVisitor
    {
        protected override Expression Visit(Expression exp)
        {
            try
            {
                if (exp != null && exp.NodeType == ExpressionType.Block)
                    return exp;

                return base.Visit(exp);
            }
            catch (InvalidOperationException e)
            {
                if (e.Message.StartsWith("Unhandled Expression"))
                    throw new NotSupportedException("The expression can not be compiled:\r\n{0}".Formato(exp.NiceToString()));
                throw;
            }
        }

        internal static Expression<Func<IProjectionRow, T>> Assert<T>(Expression<Func<IProjectionRow, T>> projectorExpression)
        {
            return (Expression<Func<IProjectionRow, T>>)new ExpressionCompilableAsserter().Visit(projectorExpression);
        }
    }
}<commit_msg>Fixes test<commit_after>﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using Signum.Engine.Maps;
using Signum.Entities;
using Signum.Utilities;
using Signum.Utilities.Reflection;
using Signum.Engine.Properties;
using System.Data.SqlClient;
using Signum.Utilities.ExpressionTrees;

namespace Signum.Engine.Linq
{
    internal interface IProjectionRow
    {
        FieldReader Reader { get; }

        IRetriever Retriever { get; }

        IEnumerable<S> Lookup<K, S>(ProjectionToken token, K key);
    }

    internal class ProjectionRowEnumerator<T> : IProjectionRow, IEnumerator<T>
    {
        public FieldReader Reader { get; private set;}
        public IRetriever Retriever { get; private set; }

        public IProjectionRow Parent { get; private set; }

        SqlDataReader dataReader;

        T current;
        Func<IProjectionRow, T> projector; 
        Expression<Func<IProjectionRow, T>> projectorExpression;

        Dictionary<ProjectionToken, IEnumerable> lookups;

        internal ProjectionRowEnumerator(SqlDataReader dataReader, Expression<Func<IProjectionRow, T>> projectorExpression, Dictionary<ProjectionToken, IEnumerable> lookups, IRetriever retriever)
        {
            this.dataReader = dataReader;
            this.Reader = new FieldReader(dataReader);

            this.projectorExpression = ExpressionCompilableAsserter.Assert(projectorExpression);
            this.projector = projectorExpression.Compile();
            this.lookups = lookups;
            this.Row = -1;
            this.Retriever = retriever;
        }

        public T Current
        {
            get { return this.current; }
        }

        object IEnumerator.Current
        {
            get { return this.current; }
        }

        public int Row;
        public bool MoveNext()
        {
            if (dataReader.Read())
            {
                this.Row++;
                this.current = this.projector(this);
                return true;
            }
            return false;
        }

        public void Reset()
        {
        }

        public void Dispose()
        {
        }
 
        public IEnumerable<S> Lookup<K, S>(ProjectionToken token, K key)
        {
            Lookup<K, S> lookup = (Lookup<K, S>)lookups[token];

            if (!lookup.Contains(key))
                return Enumerable.Empty<S>();
            else
                return lookup[key];
        }
    }

    internal class ProjectionRowEnumerable<T> : IEnumerable<T>, IEnumerable
    {
        ProjectionRowEnumerator<T> enumerator;

        internal ProjectionRowEnumerable(ProjectionRowEnumerator<T> enumerator)
        {
            this.enumerator = enumerator;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return Interlocked.Exchange(ref enumerator, null)
                .ThrowIfNullC("Cannot enumerate more than once");
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }

    internal class ExpressionCompilableAsserter : ExpressionVisitor
    {
        public override Expression Visit(Expression exp)
        {
            try
            {
                return base.Visit(exp);
            }
            catch (InvalidOperationException e)
            {
                if (e.Message.StartsWith("Unhandled Expression"))
                    throw new NotSupportedException("The expression can not be compiled:\r\n{0}".Formato(exp.NiceToString()));
                throw;
            }
        }

        internal static Expression<Func<IProjectionRow, T>> Assert<T>(Expression<Func<IProjectionRow, T>> projectorExpression)
        {
            return (Expression<Func<IProjectionRow, T>>)new ExpressionCompilableAsserter().Visit(projectorExpression);
        }
    }
}
{'fraction_non_alphanumeric': 0.08606865447256326, 'fraction_numerical': 0.0005011275369581559, 'mean_word_length': 2.0481099656357387, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 59, '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': '2123008', 'n_tokens_mistral': 2150, 'n_tokens_neox': 2085, 'n_words': 456}