public static string CreateQuery <TableType>(ParameterFactory parameterFactory, Expression <Func <TableType, bool> > expression) where TableType : DatabaseTable, new()
        {
            var visitor = new WhereExpressionVisitor <TableType>(parameterFactory);

            visitor.Visit(expression);
            var query = visitor.GetQuery();

            return(query.HasValue()
                                ? " WHERE " + query
                                : string.Empty);
        }
        public override Expression Visit(Expression node)
        {
            if (node is MethodCallExpression methodCallExpression && methodCallExpression.Method.Name == "Contains")
            {
                var argumentVisitor = new WhereExpressionVisitor <TableType>(new ParameterFactory());
                argumentVisitor.Visit(methodCallExpression.Arguments);

                var callVisitor = new WhereExpressionVisitor <TableType>(new ParameterFactory());
                callVisitor.Visit(methodCallExpression.Object);

                if (methodCallExpression.Method.DeclaringType == typeof(string))
                {
                    stringBuilder.Append(callVisitor.stringBuilder);
                    stringBuilder.Append(" LIKE ");
                    stringBuilder.Append(parameterFactory.Create("%" + argumentVisitor.parameterFactory.parameters.Single().Value + "%"));
                    return(node);
                }
                else if (methodCallExpression.Method.DeclaringType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(methodCallExpression.Method.DeclaringType))
                {
                    stringBuilder.Append(argumentVisitor.stringBuilder);
                    stringBuilder.Append(" IN ");
                    stringBuilder.Append('(');
                    for (var i = 0; i < callVisitor.parameterFactory.parameters.Count; i++)
                    {
                        var parameter       = callVisitor.parameterFactory.parameters[i];
                        var value           = parameter.Value;
                        var valueExpression = parameterFactory.Create(value);
                        stringBuilder.Append(valueExpression);
                        if (i != callVisitor.parameterFactory.parameters.Count - 1)
                        {
                            stringBuilder.Append(',');
                            stringBuilder.Append(' ');
                        }
                    }
                    stringBuilder.Append(')');
                    return(node);
                }
            }

            if (node is MemberExpression memberExpression && memberExpression.Expression.Type == typeof(TableType) && memberExpression.Expression.NodeType == ExpressionType.Parameter)
            {
                var columnExpression = "[" + memberExpression.Member.Name + "]";
                stringBuilder.Append(columnExpression);
                return(node);
            }

            if (node is MemberExpression m)
            {
                var objectMember       = Expression.Convert(m, typeof(object));
                var getterLambda       = Expression.Lambda <Func <object> >(objectMember);
                var getter             = getterLambda.Compile();
                var value              = getter.Invoke();
                var parameterizedValue = parameterFactory.Create(value);
                stringBuilder.Append(parameterizedValue);
                return(node);
            }

            if (node is ConstantExpression constantExpression)
            {
                if (constantExpression.Value == null)
                {
                    stringBuilder.Append("NULL");
                    return(node);
                }
                else if (constantExpression.Value.GetType().IsClass == false || constantExpression.Value is string)
                {
                    var value = constantExpression.Value;
                    var parameterizedValue = parameterFactory.Create(value);
                    stringBuilder.Append(parameterizedValue);
                    return(node);
                }
                else
                {
                    var fields = constantExpression.Value.GetType().GetFields();
                    if (fields.Length != 1)
                    {
                        throw new NotSupportedException();
                    }
                    var field = fields.Single();
                    var value = field.GetValue(constantExpression.Value);
                    var parameterizedValue = parameterFactory.Create(value);
                    stringBuilder.Append(parameterizedValue);
                    return(node);
                }
            }

            if (node is BinaryExpression binaryExpression)
            {
                var addParantheses = binaryExpression.NodeType.In(ExpressionType.AndAlso, ExpressionType.OrElse);

                operatorStack.Push(node.NodeType);

                if (addParantheses)
                {
                    stringBuilder.Append('(');
                }
                Visit(binaryExpression.Left);
                if (addParantheses)
                {
                    stringBuilder.Append(')');
                }

                var operatorIndex       = stringBuilder.Length;
                var operatorPlaceholder = "{{" + Guid.NewGuid() + "}}";
                stringBuilder.Append(operatorPlaceholder);

                if (addParantheses)
                {
                    stringBuilder.Append('(');
                }
                Visit(binaryExpression.Right);
                if (addParantheses)
                {
                    stringBuilder.Append(')');
                }

                var operatorExpression = GetOperatorExpression(node.NodeType, binaryExpression.Left, binaryExpression.Right);
                stringBuilder.Replace(operatorPlaceholder, operatorExpression, operatorIndex, Guid.Empty.ToString().Length + "{{}}".Length);

                operatorStack.Pop();
                return(node);
            }

            return(base.Visit(node));
        }