protected Term SimpleMap(IDatumConverterFactory datumConverterFactory, Expression expr)
        {
            switch (expr.NodeType)
            {
            case ExpressionType.Constant:
            {
                var constantExpression = (ConstantExpression)expr;
                var datumConverter     = datumConverterFactory.Get(constantExpression.Type);
                var datum = datumConverter.ConvertObject(constantExpression.Value);
                return(new Term()
                    {
                        type = Term.TermType.DATUM,
                        datum = datum
                    });
            }

            case ExpressionType.Add:
            case ExpressionType.Modulo:
            case ExpressionType.Divide:
            case ExpressionType.Multiply:
            case ExpressionType.Subtract:
            case ExpressionType.Equal:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.AndAlso:
            case ExpressionType.OrElse:
            case ExpressionType.NotEqual:
            case ExpressionType.ArrayIndex:
                return(ConvertBinaryExpressionToTerm((BinaryExpression)expr, datumConverterFactory));

            case ExpressionType.Not:
            case ExpressionType.ArrayLength:
                return(ConvertUnaryExpressionToTerm((UnaryExpression)expr, datumConverterFactory));

            case ExpressionType.New:
            {
                var newExpression = (NewExpression)expr;
                if (AnonymousTypeDatumConverterFactory.Instance.IsTypeSupported(newExpression.Type))
                {
                    var retval = new Term()
                    {
                        type = Term.TermType.MAKE_OBJ,
                    };
                    foreach (var property in newExpression.Type.GetProperties().Select((p, i) => new { Property = p, Index = i }))
                    {
                        var key   = property.Property.Name;
                        var value = RecursiveMap(newExpression.Arguments[property.Index]);
                        retval.optargs.Add(new Term.AssocPair()
                            {
                                key = key, val = value
                            });
                    }
                    return(retval);
                }

                DefaultExpressionConverterFactory.ExpressionMappingDelegate <NewExpression> newExpressionMapping;
                if (expressionConverterFactory.TryGetNewExpressionMapping(newExpression.Constructor, out newExpressionMapping))
                {
                    return(newExpressionMapping(newExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory));
                }

                return(AttemptClientSideConversion(datumConverterFactory, expr));
            }

            case ExpressionType.Call:
            {
                var callExpression = (MethodCallExpression)expr;
                var method         = callExpression.Method;

                DefaultExpressionConverterFactory.ExpressionMappingDelegate <MethodCallExpression> methodCallMapping;
                if (expressionConverterFactory.TryGetMethodCallMapping(method, out methodCallMapping))
                {
                    return(methodCallMapping(callExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory));
                }
                else
                {
                    return(AttemptClientSideConversion(datumConverterFactory, expr));
                }
            }

            case ExpressionType.MemberAccess:
            {
                var memberExpression = (MemberExpression)expr;
                var member           = memberExpression.Member;

                DefaultExpressionConverterFactory.ExpressionMappingDelegate <MemberExpression> memberAccessMapping;
                if (expressionConverterFactory.TryGetMemberAccessMapping(member, out memberAccessMapping))
                {
                    return(memberAccessMapping(memberExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory));
                }
                else
                {
                    return(AttemptClientSideConversion(datumConverterFactory, expr));
                }
            }

            case ExpressionType.Conditional:
            {
                var conditionalExpression = (ConditionalExpression)expr;
                return(new Term()
                    {
                        type = Term.TermType.BRANCH,
                        args =
                        {
                            RecursiveMap(conditionalExpression.Test),
                            RecursiveMap(conditionalExpression.IfTrue),
                            RecursiveMap(conditionalExpression.IfFalse)
                        }
                    });
            }

            default:
            {
                return(AttemptClientSideConversion(datumConverterFactory, expr));
            }
            }
        }
        protected Term SimpleMap(IDatumConverterFactory datumConverterFactory, Expression expr)
        {
            switch (expr.NodeType)
            {
            case ExpressionType.Constant:
            {
                var constantExpression = (ConstantExpression)expr;
                var datumConverter     = datumConverterFactory.Get(constantExpression.Type);
                var datum = datumConverter.ConvertObject(constantExpression.Value);
                return(new Term()
                    {
                        type = Term.TermType.DATUM,
                        datum = datum
                    });
            }

            case ExpressionType.Add:
            case ExpressionType.Modulo:
            case ExpressionType.Divide:
            case ExpressionType.Multiply:
            case ExpressionType.Subtract:
            case ExpressionType.Equal:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.AndAlso:
            case ExpressionType.OrElse:
            case ExpressionType.NotEqual:
            case ExpressionType.ArrayIndex:
                return(ConvertBinaryExpressionToTerm((BinaryExpression)expr, datumConverterFactory));

            case ExpressionType.Not:
            case ExpressionType.ArrayLength:
                return(ConvertUnaryExpressionToTerm((UnaryExpression)expr, datumConverterFactory));

            case ExpressionType.New:
            {
                var newExpression = (NewExpression)expr;
                if (AnonymousTypeDatumConverterFactory.Instance.IsTypeSupported(newExpression.Type))
                {
                    var retval = new Term()
                    {
                        type = Term.TermType.MAKE_OBJ,
                    };
                    foreach (var property in newExpression.Type.GetProperties().Select((p, i) => new { Property = p, Index = i }))
                    {
                        var key   = property.Property.Name;
                        var value = RecursiveMap(newExpression.Arguments[property.Index]);
                        retval.optargs.Add(new Term.AssocPair()
                            {
                                key = key, val = value
                            });
                    }
                    return(retval);
                }

                DefaultExpressionConverterFactory.ExpressionMappingDelegate <NewExpression> newExpressionMapping;
                if (expressionConverterFactory.TryGetNewExpressionMapping(newExpression.Constructor, out newExpressionMapping))
                {
                    return(newExpressionMapping(newExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory));
                }

                return(AttemptClientSideConversion(datumConverterFactory, expr));
            }

            case ExpressionType.Call:
            {
                var callExpression = (MethodCallExpression)expr;
                var method         = callExpression.Method;

                DefaultExpressionConverterFactory.ExpressionMappingDelegate <MethodCallExpression> methodCallMapping;
                if (expressionConverterFactory.TryGetMethodCallMapping(method, out methodCallMapping))
                {
                    return(methodCallMapping(callExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory));
                }
                else
                {
                    return(AttemptClientSideConversion(datumConverterFactory, expr));
                }
            }

            case ExpressionType.MemberAccess:
            {
                var memberExpression = (MemberExpression)expr;
                var member           = memberExpression.Member;

                DefaultExpressionConverterFactory.ExpressionMappingDelegate <MemberExpression> memberAccessMapping;
                if (expressionConverterFactory.TryGetMemberAccessMapping(member, out memberAccessMapping))
                {
                    return(memberAccessMapping(memberExpression, RecursiveMap, datumConverterFactory, expressionConverterFactory));
                }

                Term serverSideTerm;
                if (ServerSideMemberAccess(datumConverterFactory, memberExpression, out serverSideTerm))
                {
                    return(serverSideTerm);
                }

                return(AttemptClientSideConversion(datumConverterFactory, expr));
            }

            case ExpressionType.Conditional:
            {
                var conditionalExpression = (ConditionalExpression)expr;
                return(new Term()
                    {
                        type = Term.TermType.BRANCH,
                        args =
                        {
                            RecursiveMap(conditionalExpression.Test),
                            RecursiveMap(conditionalExpression.IfTrue),
                            RecursiveMap(conditionalExpression.IfFalse)
                        }
                    });
            }

            case ExpressionType.Convert:
            {
                // The use-case for this right now is automatic boxing that occurs when setting a Dictionary<string,object>'s value
                // to a primitive.  In that particular case, we don't actually need to generate any ReQL for the conversion, so we're
                // just ignoring the Convert and mapping the expression inside.  Might need other behavior here in the future...
                return(RecursiveMap(((UnaryExpression)expr).Operand));
            }

            default:
            {
                return(AttemptClientSideConversion(datumConverterFactory, expr));
            }
            }
        }