/// <summary> /// Parse and compile string expression and return BsonExpression /// </summary> internal static BsonExpression Parse(Tokenizer tokenizer, BsonExpressionParserMode mode, bool isRoot) { if (tokenizer == null) { throw new ArgumentNullException(nameof(tokenizer)); } var source = Expression.Parameter(typeof(IEnumerable <BsonDocument>), "source"); var root = Expression.Parameter(typeof(BsonDocument), "root"); var current = Expression.Parameter(typeof(BsonValue), "current"); var parameters = Expression.Parameter(typeof(BsonDocument), "parameters"); var expr = mode == BsonExpressionParserMode.Full ? BsonExpressionParser.ParseFullExpression(tokenizer, source, root, current, parameters, isRoot) : mode == BsonExpressionParserMode.Single ? BsonExpressionParser.ParseSingleExpression(tokenizer, source, root, current, parameters, isRoot) : mode == BsonExpressionParserMode.SelectDocument ? BsonExpressionParser.ParseSelectDocumentBuilder(tokenizer, source, root, current, parameters) : BsonExpressionParser.ParseUpdateDocumentBuilder(tokenizer, source, root, current, parameters); // before compile try find in cache if this source already has in cache (already compiled) var cached = _cache.GetOrAdd(expr.Source, (s) => { // compile linq expression (with left+right expressions) Compile(expr, source, root, current, parameters); return(expr); }); return(cached); }
/// <summary> /// Parse and compile string expression and return BsonExpression /// </summary> internal static BsonExpression Parse(Tokenizer tokenizer, BsonExpressionParserMode mode, bool isRoot) { if (tokenizer == null) { throw new ArgumentNullException(nameof(tokenizer)); } var context = new ExpressionContext(); var expr = mode == BsonExpressionParserMode.Full ? BsonExpressionParser.ParseFullExpression(tokenizer, context, isRoot) : mode == BsonExpressionParserMode.Single ? BsonExpressionParser.ParseSingleExpression(tokenizer, context, isRoot) : mode == BsonExpressionParserMode.SelectDocument ? BsonExpressionParser.ParseSelectDocumentBuilder(tokenizer, context) : BsonExpressionParser.ParseUpdateDocumentBuilder(tokenizer, context); // before compile try find in cache if this source already has in cache (already compiled) var cached = _cache.GetOrAdd(expr.Source, (s) => { // compile linq expression (with left+right expressions) Compile(expr, context); return(expr); }); return(cached); }
/// <summary> /// Returns documents that exists in ANY queries results (Union). /// </summary> public static BsonExpression Or(BsonExpression left, BsonExpression right) { if (left == null) { throw new ArgumentNullException(nameof(left)); } if (right == null) { throw new ArgumentNullException(nameof(right)); } return(BsonExpressionParser.CreateBinaryExpression("OR", left, right)); }
/// <summary> /// Returns document that exists in BOTH queries results. If both queries has indexes, left query has index preference (other side will be run in full scan) /// </summary> public static BsonExpression And(BsonExpression left, BsonExpression right) { if (left == null) { throw new ArgumentNullException(nameof(left)); } if (right == null) { throw new ArgumentNullException(nameof(right)); } return(BsonExpressionParser.CreateLogicExpression(BsonExpressionType.And, left, right)); }
public BsonExpression Resolve(bool predicate) { this.Visit(_expr); ENSURE(_nodes.Count == 0, "node stack must be empty when finish expression resolve"); var expression = _builder.ToString(); try { var e = BsonExpression.Create(expression, _parameters); // if expression must return an predicate but expression result is Path/Parameter/Call add `= true` if (predicate && (e.Type == BsonExpressionType.Path || e.Type == BsonExpressionType.Call || e.Type == BsonExpressionType.Parameter)) { expression = "(" + expression + " = true)"; e = BsonExpression.Create(expression, _parameters); } else if (e.Type == BsonExpressionType.And && e.Left.Type == BsonExpressionType.GreaterThanOrEqual && e.Right.Type == BsonExpressionType.LessThanOrEqual && e.Left.Left.Source == e.Right.Left.Source) //checks if expression is of the form "something >= x && something <= y", to be transformed into between expression { BsonExpression arr = BsonExpressionParser.NewArray(e.Left.Right, e.Right.Right); var op = BsonExpressionParser._operators["BETWEEN"]; e = new BsonExpression { Type = BsonExpressionType.Between, Parameters = e.Parameters, IsImmutable = e.Left.IsImmutable && e.Right.IsImmutable, UseSource = e.Left.UseSource || e.Right.UseSource, IsScalar = true, Fields = e.Fields, Expression = Expression.Call(op.Item2, new ExpressionContext().Collation, e.Left.Left.Expression, arr.Expression), Left = e.Left.Left, Right = arr, Source = e.Left.Left.Source + op.Item1 + arr.Source }; } return(e); } catch (Exception ex) { throw new NotSupportedException($"Invalid BsonExpression when converted from Linq expression: {_expr.ToString()} - `{expression}`", ex); } }
/// <summary> /// Parse and compile string expression and return BsonExpression /// </summary> internal static BsonExpression ParseAndCompile(Tokenizer tokenizer, BsonExpressionParserMode mode, BsonDocument parameters, DocumentScope scope) { if (tokenizer == null) { throw new ArgumentNullException(nameof(tokenizer)); } var context = new ExpressionContext(); var expr = mode == BsonExpressionParserMode.Full ? BsonExpressionParser.ParseFullExpression(tokenizer, context, parameters, scope) : mode == BsonExpressionParserMode.Single ? BsonExpressionParser.ParseSingleExpression(tokenizer, context, parameters, scope) : mode == BsonExpressionParserMode.SelectDocument ? BsonExpressionParser.ParseSelectDocumentBuilder(tokenizer, context, parameters) : BsonExpressionParser.ParseUpdateDocumentBuilder(tokenizer, context, parameters); // compile linq expression (with left+right expressions) Compile(expr, context); return(expr); }