private bool TryProcessPredicatelessAny(MethodCallExpression methodCallExpression, ScriptParameterDictionary parameters, out string result)
        {
            var invokedMethod = methodCallExpression.Method;

            if (invokedMethod.IsGenericMethod)
            {
                invokedMethod = invokedMethod.GetGenericMethodDefinition();
            }

            if (invokedMethod == AnyExtensionWithoutPredicate)
            {
                // Since extensins are static, we must pass the first method invocation argument as the expression,
                // not the methodCallExpression.Object (because that is null).
                var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(methodCallExpression.Arguments[0], parameters);

                if (IsInvokedOnDictionary(methodCallExpression))
                {
                    result = $"Object.keys({ownerExpressionString}).length > 0";
                    return(true);
                }

                result = $"{ownerExpressionString}.length > 0";
                return(true);
            }

            result = default;
            return(false);
        }
        public bool TryProcess(Expression expression, ScriptParameterDictionary parameters, out string result)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            if (expression is ConditionalExpression conditionalExpression)
            {
                var test    = _expressionProcessorPipeline.ProcessExpression(conditionalExpression.Test, parameters);
                var ifTrue  = _expressionProcessorPipeline.ProcessExpression(conditionalExpression.IfTrue, parameters);
                var ifFalse = _expressionProcessorPipeline.ProcessExpression(conditionalExpression.IfFalse, parameters);

                result = $"({test} ? {ifTrue} : {ifFalse})";

                return(true);
            }

            result = default;

            return(false);
        }
        public bool TryProcess(MemberExpression memberExpression, ScriptParameterDictionary parameters, out string result)
        {
            if (memberExpression == null)
            {
                throw new ArgumentNullException(nameof(memberExpression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            // TODO: Tests
            if (memberExpression.Member is PropertyInfo propertyInfo)
            {
                if (IsDictionaryCountAccess(propertyInfo))
                {
                    // Dictionaries are mapped to object literals based on their keys when they are serialized to JSON,
                    // so we can't use the .length as we would with a regular collection. But there are as many items
                    // in a dictionary as there are keys, so we need find the number of keys to resolve the expression.
                    var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(memberExpression.Expression, parameters);

                    // TODO: Check whether RavenDB provides a magic property for Dictionary key collections.
                    result = $"Object.keys({ownerExpressionString}).length";
                    return(true);
                }

                if (IsDictionaryKeysCollectionCountAccess(memberExpression, propertyInfo))
                {
                    // We need to navigate one level further up (i.e. doc.MyDictionary.Keys becomes doc.MyDictionary)
                    // because dictionaries are mapped to object literals with the respective keys when they become
                    // JSON, so the Keys segment becomes invalid.
                    var parentMemberExpression = ((MemberExpression)memberExpression.Expression).Expression;
                    var ownerExpressionString  = _expressionProcessorPipeline.ProcessExpression(parentMemberExpression, parameters);

                    // TODO: Check whether RavenDB provides a magic property for Dictionary key collections.
                    result = $"Object.keys({ownerExpressionString}).length";
                    return(true);
                }

                if (IsDictionaryValuesCollectionCountAccess(memberExpression, propertyInfo))
                {
                    // We need to navigate one level further up (i.e. doc.MyDictionary.Values becomes doc.MyDictionary)
                    // because dictionaries are mapped to object literals with the respective keys when they become
                    // JSON, so the Values segment becomes invalid.
                    var parentMemberExpression = ((MemberExpression)memberExpression.Expression).Expression;
                    var ownerExpressionString  = _expressionProcessorPipeline.ProcessExpression(parentMemberExpression, parameters);

                    // TODO: Check whether RavenDB provides a magic property for Dictionary value collections.
                    result = $"Object.values({ownerExpressionString}).length";
                    return(true);
                }
            }

            result = default;
            return(false);
        }
        public bool TryProcess(MethodCallExpression methodCallExpression, ScriptParameterDictionary parameters, out string result)
        {
            if (methodCallExpression == null)
            {
                throw new ArgumentNullException(nameof(methodCallExpression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            if (!integralTypes.Contains(methodCallExpression.Method.DeclaringType))
            {
                result = default;

                return(false);
            }

            if (methodCallExpression.Method.Name == ToStringMethodName)
            {
                var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(methodCallExpression.Object, parameters);

                result = $"{ownerExpressionString}.toString()";
                return(true);
            }

            result = default;
            return(false);
        }
示例#5
0
        public bool TryProcess(Expression expression, ScriptParameterDictionary parameters, out string result)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            var lambdaExpression = expression as LambdaExpression;

            if (lambdaExpression == null)
            {
                result = default;

                return(false);
            }

            var parameterList = string.Join(", ", lambdaExpression.Parameters.Select(p => p.Name));
            var body          = _expressionProcessorPipeline.ProcessExpression(lambdaExpression.Body, parameters);

            // TODO: Consider whether "return" is always correct (technically we can return void stuff in JS but what if
            result = $"function({parameterList}) {{ return {body}; }}";

            return(true);
        }
        public bool TryProcess(MemberExpression memberExpression, ScriptParameterDictionary parameters, out string result)
        {
            if (memberExpression == null)
            {
                throw new ArgumentNullException(nameof(memberExpression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            if (memberExpression.Member is PropertyInfo propertyInfo)
            {
                var memberOwnerType = propertyInfo.DeclaringType;
                if (memberOwnerType.IsGenericType)
                {
                    memberOwnerType = memberOwnerType.GetGenericTypeDefinition();
                }

                if (memberOwnerType == NullableType)
                {
                    if (propertyInfo.Name == "HasValue")
                    {
                        var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(memberExpression.Expression, parameters);

                        result = $"({ownerExpressionString} != null)";
                        return(true);
                    }

                    if (propertyInfo.Name == "Value")
                    {
                        var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(memberExpression.Expression, parameters);

                        result = $"{ownerExpressionString}";
                        return(true);
                    }
                }
            }

            result = default;
            return(false);
        }
示例#7
0
        public void BinaryOps_Integers_Assign()
        {
            var memberExpression   = LambdaExpression(doc => doc.SomeInt).Body;
            var constantExpression = Expression.Constant(1);
            var expression         = Expression.Assign(memberExpression, constantExpression);

            var parameters = new ScriptParameterDictionary();

            var result = expressionProcessorPipeline.ProcessExpression(expression, parameters);

            Assert.AreEqual(
                "(doc.SomeInt = args.__param1)",
                result);

            Assert.AreEqual(1, parameters.Count);
            Assert.AreEqual(1, parameters["__param1"]);
        }
示例#8
0
        public string CreateScriptCondition <TDocument>(Expression <Func <TDocument, bool> > condition, ScriptParameterDictionary parameters)
        {
            if (condition == null)
            {
                throw new ArgumentNullException(nameof(condition));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            var normalizedConditionBody = GetNormalizedConditionBody(condition);

            return(_expressionProcessorPipeline.ProcessExpression(normalizedConditionBody, parameters));
        }
        public bool TryProcess(MemberExpression memberExpression, ScriptParameterDictionary parameters, out string result)
        {
            if (memberExpression == null)
            {
                throw new ArgumentNullException(nameof(memberExpression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(memberExpression.Expression, parameters);

            // TODO: Consider cases when the property is called differently in the document than in the object model. Check out
            // Raven.Client.Documents.Linq.LinqPathProvider, maybe that can solve it out-of-the-box.
            result = $"{ownerExpressionString}.{memberExpression.Member.Name}";
            return(true);
        }
        public string CreateScriptBody(PropertyUpdateDescriptor[] propertyUpdates, ScriptParameterDictionary parameters)
        {
            var assignmentScripts = new List <string>(propertyUpdates.Length);

            foreach (var propertyUpdate in propertyUpdates)
            {
                var transformedMemberSelector = GetNormalizedExpression(propertyUpdate.MemberSelector);

                var assignmentExpression = Expression.Assign(
                    transformedMemberSelector,
                    Expression.Constant(propertyUpdate.NewValue));

                assignmentScripts.Add(_expressionProcessorPipeline.ProcessExpression(assignmentExpression, parameters));
            }

            return(string.Join(
                       "\n",
                       assignmentScripts.Select(script => $"\t{script};")));
        }
示例#11
0
        public bool TryProcess(MemberExpression memberExpression, ScriptParameterDictionary parameters, out string result)
        {
            if (memberExpression == null)
            {
                throw new ArgumentNullException(nameof(memberExpression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            if (memberExpression.Member is PropertyInfo propertyInfo && propertyInfo == NonStatic_Length)
            {
                var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(memberExpression.Expression, parameters);

                result = $"{ownerExpressionString}.length";
                return(true);
            }

            result = default;
            return(false);
        }
示例#12
0
        public bool TryProcess(MemberExpression memberExpression, ScriptParameterDictionary parameters, out string result)
        {
            if (memberExpression == null)
            {
                throw new ArgumentNullException(nameof(memberExpression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            // TODO: Tests
            if (memberExpression.Member is PropertyInfo propertyInfo && IsSpeciallyTreatedCountPropertyAccess(propertyInfo))
            {
                var ownerExpressionString = _expressionProcessorPipeline.ProcessExpression(memberExpression.Expression, parameters);

                result = $"{ownerExpressionString}.length";
                return(true);
            }

            result = default;
            return(false);
        }
        public bool TryProcess(Expression expression, ScriptParameterDictionary parameters, out string result)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            var binaryExpression = expression as BinaryExpression;

            if (binaryExpression == null)
            {
                result = default;

                return(false);
            }

            var operation = binaryExpression.NodeType;
            var left      = _expressionProcessorPipeline.ProcessExpression(binaryExpression.Left, parameters);
            var right     = _expressionProcessorPipeline.ProcessExpression(binaryExpression.Right, parameters);

            switch (operation)
            {
            case ExpressionType.Add:
            case ExpressionType.AddChecked:
                result = $"({left} + {right})";
                return(true);

            case ExpressionType.And:
                result = $"({left} & {right})";
                return(true);

            case ExpressionType.AndAlso:
                result = $"({left} && {right})";
                return(true);

            case ExpressionType.ArrayIndex:
                result = $"{left}[{right}]";
                return(true);

            case ExpressionType.Coalesce:
                result = $"({left} != null ? {left} : {right})";
                return(true);

            case ExpressionType.Divide:
                result = $"({left} / {right})";
                return(true);

            case ExpressionType.Equal:
                result = $"({left} == {right})";
                return(true);

            case ExpressionType.ExclusiveOr:
                result = $"({left} ^ {right})";
                return(true);

            case ExpressionType.GreaterThan:
                result = $"({left} > {right})";
                return(true);

            case ExpressionType.GreaterThanOrEqual:
                result = $"({left} >= {right})";
                return(true);

            case ExpressionType.LessThan:
                result = $"({left} < {right})";
                return(true);

            case ExpressionType.LessThanOrEqual:
                result = $"({left} <= {right})";
                return(true);

            case ExpressionType.Modulo:
                result = $"({left} % {right})";
                return(true);

            case ExpressionType.Multiply:
            case ExpressionType.MultiplyChecked:
                result = $"({left} * {right})";
                return(true);

            case ExpressionType.NotEqual:
                result = $"({left} != {right})";
                return(true);

            case ExpressionType.Or:
                result = $"({left} | {right})";
                return(true);

            case ExpressionType.OrElse:
                result = $"({left} || {right})";
                return(true);

            case ExpressionType.Subtract:
            case ExpressionType.SubtractChecked:
                result = $"({left} - {right})";
                return(true);

            case ExpressionType.Assign:
                result = $"({left} = {right})";
                return(true);

            case ExpressionType.Index:
                result = $"{left}[{right}]";
                return(true);

            case ExpressionType.AddAssign:
            case ExpressionType.AddAssignChecked:
                result = $"({left} += {right})";
                return(true);

            case ExpressionType.AndAssign:
                result = $"({left} &= {right})";
                return(true);

            case ExpressionType.DivideAssign:
                result = $"({left} /= {right})";
                return(true);

            case ExpressionType.ExclusiveOrAssign:
                result = $"({left} ^= {right})";
                return(true);

            case ExpressionType.ModuloAssign:
                result = $"({left} %= {right})";
                return(true);

            case ExpressionType.MultiplyAssign:
            case ExpressionType.MultiplyAssignChecked:
                result = $"({left} *= {right})";
                return(true);

            case ExpressionType.OrAssign:
                result = $"({left} |= {right})";
                return(true);

            case ExpressionType.SubtractAssign:
            case ExpressionType.SubtractAssignChecked:
                result = $"({left} -= {right})";
                return(true);

            default:
                result = default;
                return(false);
            }
        }
示例#14
0
        public bool TryProcess(Expression expression, ScriptParameterDictionary parameters, out string result)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            var unaryExpression = expression as UnaryExpression;

            if (unaryExpression == null)
            {
                result = default;

                return(false);
            }

            var operation = unaryExpression.NodeType;
            var operand   = _expressionProcessorPipeline.ProcessExpression(unaryExpression.Operand, parameters);

            switch (operation)
            {
            case ExpressionType.ArrayLength:
                result = $"{operand}.length";
                return(true);

            case ExpressionType.Convert:
                result = operand;
                return(true);

            case ExpressionType.Negate:
                result = $"-({operand})";
                return(true);

            case ExpressionType.UnaryPlus:
                result = $"+({operand})";
                return(true);

            case ExpressionType.Not:
                result = $"!({operand})";
                return(true);

            case ExpressionType.Decrement:
                result = $"({operand} - 1)";
                return(true);

            case ExpressionType.Increment:
                result = $"({operand} + 1)";
                return(true);

            case ExpressionType.PreIncrementAssign:
                result = $"(++{operand})";
                return(true);

            case ExpressionType.PreDecrementAssign:
                result = $"(--{operand})";
                return(true);

            case ExpressionType.PostIncrementAssign:
                result = $"({operand}++)";
                return(true);

            case ExpressionType.PostDecrementAssign:
                result = $"({operand}--)";
                return(true);

            default:
                result = default;
                return(false);
            }
        }
示例#15
0
        private bool TryProcessStaticStringMethodInvocation(MethodCallExpression methodCallExpression, MethodInfo methodInfo, ScriptParameterDictionary parameters, out string result)
        {
            if (methodInfo == Static_IsNullOrEmpty)
            {
                var methodParameterExpression = methodCallExpression.Arguments[0];
                var methodParameter           = _expressionProcessorPipeline.ProcessExpression(methodParameterExpression, parameters);

                result = $"({methodParameter} == null || {methodParameter} == '')";
                return(true);
            }
            else if (methodInfo == Static_IsNullOrWhiteSpace)
            {
                var methodParameterExpression = methodCallExpression.Arguments[0];
                var methodParameter           = _expressionProcessorPipeline.ProcessExpression(methodParameterExpression, parameters);

                result = $"({methodParameter} == null || {methodParameter}.trim() == '')";
                return(true);
            }

            /*
             * else if (methodInfo == Static_Concat)
             * {
             * }
             * else if (methodInfo == Static_Join)
             * {
             * }
             */

            result = null;
            return(false);
        }