Inheritance: Shaolinq.Persistence.Linq.Expressions.SqlExpressionVisitor
        public static HashSet <string> Gather(Expression source)
        {
            var gatherer = new SqlReferencedAliasGatherer();

            gatherer.Visit(source);

            return(gatherer.aliases);
        }
        public static HashSet<string> Gather(Expression source)
        {
            var gatherer = new SqlReferencedAliasGatherer();

            gatherer.Visit(source);

            return gatherer.aliases;
        }
        private static bool CanBeJoinCondition(Expression expression, IEnumerable <string> left, IEnumerable <string> right, IEnumerable <string> all)
        {
            var referenced = SqlReferencedAliasGatherer.Gather(expression);

            var leftOkay  = referenced.Intersect(left).Any();
            var rightOkay = referenced.Intersect(right).Any();

            var subset = referenced.IsSubsetOf(all);

            return(leftOkay && rightOkay && subset);
        }
        protected override Expression VisitJoin(SqlJoinExpression join)
        {
            join = (SqlJoinExpression)base.VisitJoin(join);

            if (join.JoinType == SqlJoinType.CrossApply || join.JoinType == SqlJoinType.OuterApply)
            {
                if (join.Right is SqlTableExpression)
                {
                    return(new SqlJoinExpression(join.Type, SqlJoinType.Cross, join.Left, join.Right, null));
                }
                else
                {
                    var select = join.Right as SqlSelectExpression;

                    if (select != null && select.Take == null && select.Skip == null && !SqlAggregateChecker.HasAggregates(select) && (select.GroupBy == null || select.GroupBy.Count == 0))
                    {
                        var selectWithoutWhere = select.ChangeWhere(null);
                        var referencedAliases  = SqlReferencedAliasGatherer.Gather(selectWithoutWhere);
                        var declaredAliases    = SqlDeclaredAliasGatherer.Gather(join.Left);

                        referencedAliases.IntersectWith(declaredAliases);

                        if (referencedAliases.Count == 0)
                        {
                            var where = select.Where;

                            select = selectWithoutWhere;

                            var pc = ColumnProjector.ProjectColumns(new Nominator(Nominator.CanBeColumn), where, select.Columns, select.Alias, SqlDeclaredAliasGatherer.Gather(select.From));

                            select = select.ChangeColumns(pc.Columns);
                            where  = pc.Projector;

                            var joinType = (where == null) ? SqlJoinType.Cross : (join.JoinType == SqlJoinType.CrossApply ? SqlJoinType.Inner : SqlJoinType.Left);

                            return(new SqlJoinExpression(typeof(void), joinType, join.Left, select, where));
                        }
                    }
                }
            }

            return(join);
        }