private ResultSetBuilder VisitContains(SymbolContainsExpression exp)
        {
            var memberName = ExHelper.GetMemberName(exp.Match, _itemType, exp);
            var result     = new ResultSetBuilder(_journal, _tx);
            var vals       = ExHelper.GetLiteralValue(exp.Values, _parameters, exp);

            if (!(vals is IEnumerable))
            {
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          string.Format("Parameter {0} does not implement IEnumerable.", exp.Values), exp);
            }

            try
            {
                result.IndexCollectionScan(memberName, (IEnumerable)vals, exp);
            }
            catch (InvalidCastException ex)
            {
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          string.Format("Parameter {0} value of type '{1}' cannot be used in " +
                                        "IN statement with column '{2}'. {3}", exp.Values, vals.GetType(), memberName, ex.Message), exp);
            }

            return(result);
        }
        private ResultSetBuilder VisitBinary(Expression expression)
        {
            switch (expression.NodeType)
            {
            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
                return(EvaluateEquals(expression));

            case ExpressionType.Or:
            case ExpressionType.And:
            case ExpressionType.OrElse:
            case ExpressionType.AndAlso:
                return(EvaluateLogical(expression));

            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
                return(EvaluateCompare(expression));

            default:
                throw QueryExceptionExtensions.NotSupported(
                          "Binary operation {0} cannot be bound to Journal operation",
                          expression.NodeType);
            }
        }
Example #3
0
        private QueryRowsResult BindPostResult(IEnumerable <long> rowIds)
        {
            var hadNonTimestampOrder = false;

            foreach (var tranform in _directExpressions)
            {
                switch (tranform.Expression)
                {
                case EJournalExpressionType.Single:
                    return(new QueryRowsResult(rowIds.Single()));

                case EJournalExpressionType.First:
                    return(new QueryRowsResult(rowIds.First()));

                case EJournalExpressionType.Last:
                    return(new QueryRowsResult(rowIds.Last()));

                case EJournalExpressionType.Reverse:
                    if (hadNonTimestampOrder)
                    {
                        rowIds = rowIds.Reverse();
                    }
                    break;

                case EJournalExpressionType.LongCount:
                case EJournalExpressionType.Count:
                    return(new QueryRowsResult(rowIds, tranform.Expression));

                case EJournalExpressionType.OrderByDescending:
                case EJournalExpressionType.OrderBy:
                    if (tranform.Column.ColumnID != Metadata.TimestampColumnID)
                    {
                        hadNonTimestampOrder = true;
                        rowIds = BindOrderBy(rowIds, tranform);
                    }
                    break;

                case EJournalExpressionType.Take:
                    rowIds = rowIds.Take(tranform.Count);
                    break;

                case EJournalExpressionType.Skip:
                    rowIds = rowIds.Skip(tranform.Count);
                    break;

                case EJournalExpressionType.FirstOrDefault:
                    return(new QueryRowsResult(rowIds.FirstOrDefault()));

                case EJournalExpressionType.LastOrDefault:
                    return(new QueryRowsResult(rowIds.LastOrDefault()));

                default:
                    throw QueryExceptionExtensions.NotSupported(
                              "Expression {0} is not expected to be post operation", tranform.Expression);
                }
            }
            return(new QueryRowsResult(rowIds));
        }
Example #4
0
        public static string GetMemberName(MemberExpression memEx, Type journalType)
        {
            if (memEx.Member.DeclaringType == null || !memEx.Member.DeclaringType.IsAssignableFrom(journalType))
            {
                throw QueryExceptionExtensions.NotSupported("Expressions of type \"column\" == value "
                                                            + "where column is an NFSdb property "
                                                            + "name are supported only");
            }

            return(memEx.Member.Name);
        }
Example #5
0
        private Expression BindLatestBy(Expression ex1, LambdaExpression lambda)
        {
            var prop = lambda.Body as MemberExpression;

            if (prop != null)
            {
                return(new LatestBySymbolExpression(prop.Member.Name, Visit(ex1)));
            }
            throw QueryExceptionExtensions.NotSupported("LatestBy is only supported with property" +
                                                        " expression, but instead had '{0}'",
                                                        lambda);
        }
        private ResultSetBuilder VisitConstant(ConstantExpression exp)
        {
            var expType = exp.Value.GetType();

            if (expType.GetInterfaces().Any(x =>
                                            x.IsGenericType &&
                                            x.GetGenericTypeDefinition() == typeof(IQueryable <>) &&
                                            x.GetGenericArguments()[0] == _itemType))
            {
                return(new ResultSetBuilder(_journal, _tx));
            }
            throw QueryExceptionExtensions.ExpressionNotSupported(
                      "Expression {0} cannot be bound to Journal operation.", exp);
        }
        private ResultSetBuilder VisitLatestBy(LatestBySymbolExpression exp)
        {
            try
            {
                var result = exp.Body != null?Visit(exp.Body) : new ResultSetBuilder(_journal, _tx);

                result.TakeLatestBy(exp.LatestBy);
                return(result);
            }
            catch (NFSdbQueryableNotSupportedException ex)
            {
                throw QueryExceptionExtensions.ExpressionNotSupported(ex.Message, exp);
            }
        }
        private ResultSetBuilder VisitFilter(FilterExpression exp)
        {
            var source = Visit(exp.Source);

            if (!source.CanApplyFilter())
            {
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          "Where cannot be applied after Take, Skip, Single, First or Count expressions.", exp);
            }
            var filter = Visit(exp.Filter);

            source.ApplyFilter(filter);
            return(source);
        }
Example #9
0
        private TT GetConstant <TT>(Expression expression)
        {
            var c = expression as ConstantExpression;

            if (c != null)
            {
                if (c.Type == typeof(TT))
                {
                    return((TT)c.Value);
                }
            }
            throw QueryExceptionExtensions.NotSupported("Expected constant expression of type {0} but got {1}",
                                                        typeof(T).Name, expression);
        }
Example #10
0
 public void ApplyMap(List <ColumnNameExpression> columns)
 {
     _columns = new List <string>(columns.Count);
     foreach (var columnExp in columns)
     {
         var col = Metadata.Columns.FirstOrDefault(c => string.Equals(c.PropertyName, columnExp.Name, StringComparison.OrdinalIgnoreCase));
         if (col == null)
         {
             throw QueryExceptionExtensions.ExpressionNotSupported(
                       "Column [{0}] does not exists in journal " + Metadata.Name, columnExp);
         }
         _columns.Add(col.PropertyName);
     }
 }
Example #11
0
        private Expression BindPostResult(Type resultType, ReadOnlyCollection <Expression> arguments, EJournalExpressionType expressionType)
        {
            if (resultType != typeof(T))
            {
                throw QueryExceptionExtensions.NotSupported("{0} operation canonly be bound to JournalQueryable of {1} but used on {2}",
                                                            expressionType, typeof(T).Name, resultType);
            }
            var source = arguments[0];

            if (arguments.Count > 1)
            {
                var lambda = GetLambda(arguments[1]);
                return(new PostResultExpression(new FilterExpression(Visit(lambda.Body), Visit(source)), expressionType));
            }
            return(new PostResultExpression(Visit(source), expressionType));
        }
Example #12
0
        public void IndexCollectionScan(string memberName, IEnumerable values, Expression exp)
        {
            var p      = new RowScanPlanItem(_journal, _tx);
            var column = Metadata.GetColumnByPropertyName(memberName);

            switch (column.DataType.ColumnType)
            {
            case EFieldType.Byte:
                p.AddContainsScan(column, ToIList <byte>(values));
                break;

            case EFieldType.Bool:
                p.AddContainsScan(column, ToIList <bool>(values));
                break;

            case EFieldType.Int16:
                p.AddContainsScan(column, ToIList <short>(values));
                break;

            case EFieldType.Int32:
                p.AddContainsScan(column, ToIList <int>(values));
                break;

            case EFieldType.Int64:
                p.AddContainsScan(column, ToIList <long>(values));
                break;

            case EFieldType.Double:
                p.AddContainsScan(column, ToIList <double>(values));
                break;

            case EFieldType.Symbol:
            case EFieldType.String:
                p.AddContainsScan(column, ToIList <string>(values));
                break;

            case EFieldType.DateTime:
            case EFieldType.DateTimeEpochMs:
                p.AddContainsScan(column, ToIList <DateTime>(values));
                break;

            default:
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          string.Format("Column of type {0} cannot be bound to Contains expressions", column.DataType.ColumnType), exp);
            }
            _planHead = p;
        }
        public override object Execute(Expression expression)
        {
            var lambda = expression as LambdaExpression;

            if (lambda == null && _cache != null && expression.NodeType != ExpressionType.Constant)
            {
                return(_cache.Execute(expression));
            }

            var result = GetExecutionPlan(expression);
            var res    = result.Build();

            if (res.IsSingle)
            {
                var rowID = res.RowID;

                // First / Last OrDefault can return null.
                if (rowID == 0)
                {
                    return(null);
                }
                int  partitionID         = RowIDUtil.ToPartitionIndex(rowID);
                var  lastPartitionReader = _tx.Read(partitionID);
                long localRowID          = RowIDUtil.ToLocalRowID(rowID);

                // ReSharper disable once PossibleNullReferenceException
                return(lastPartitionReader.Read <T>(localRowID, _tx.ReadCache));
            }

            switch (res.PostExpression)
            {
            case EJournalExpressionType.None:
                return(new ResultSet <T>(res.Rowids, _tx));

            case EJournalExpressionType.LongCount:
                return(res.Rowids.LongCount());

            case EJournalExpressionType.Count:
                return(res.Rowids.Count());

            default:
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          string.Format("Post expression {0} is not supported at this level", res.PostExpression), expression);
            }
        }
Example #14
0
        private Expression BindContains(Expression source, Expression match)
        {
            var constSource = source as ConstantExpression;

            if (constSource != null && !IsQuery(constSource))
            {
                var stringEnum = constSource.Value as IEnumerable;
                if (stringEnum != null)
                {
                    match = Visit(match);
                    return(new SymbolContainsExpression(match, Expression.Constant(stringEnum)));
                }
            }

            throw QueryExceptionExtensions.NotSupported(
                      "List.Contains, Array.Contains allowed only. Unable to execute Contains on {0}.",
                      constSource);
        }
Example #15
0
 private Expression BindUnion(Type type, Expression expression1, Expression expression2)
 {
     if (typeof(IQueryable <T>).IsAssignableFrom(type))
     {
         var mc1 = expression1 as MethodCallExpression;
         var mc2 = expression2 as MethodCallExpression;
         if (mc1 != null && mc2 != null)
         {
             if (IsQuery(mc1.Arguments[0]) && IsQuery(mc2.Arguments[0]))
             {
                 return(new UnionExpression(Visit(mc1), Visit(mc2)));
             }
         }
     }
     throw QueryExceptionExtensions.NotSupported("Union of 2 journal queriables supported. " +
                                                 "Attempted to join '{0}' with '{1}' instead.",
                                                 expression1, expression2);
 }
Example #16
0
        public static string GetMemberName(Expression expression, Type journalType, Expression parentExpression)
        {
            var ex = expression as MemberExpression;

            if (ex != null)
            {
                var memEx = ex;
                return(GetMemberName(memEx, journalType));
            }

            var match = expression as ColumnNameExpression;

            if (match != null)
            {
                return(match.Name);
            }
            throw QueryExceptionExtensions.ExpressionNotSupported("Cannot extract column name from expression ", parentExpression);
        }
Example #17
0
        public static object GetLiteralValue(Expression literalExpression, IEnumerable <QlParameter> parameters, Expression parentExpression)
        {
            var valExp = literalExpression as ValueListExpression;

            if (valExp != null)
            {
                return(valExp.Values.Select(v => GetLiteralValue(v, parameters, parentExpression)).ToList());
            }

            if (literalExpression is LiteralExpression)
            {
                literalExpression = ((LiteralExpression)literalExpression).Constant;
            }
            else
            {
                var exp = literalExpression as ParameterNameExpression;
                if (exp != null)
                {
                    var         paramExp = exp;
                    QlParameter p;
                    if (parameters == null ||
                        (p =
                             parameters.FirstOrDefault(
                                 pp => string.Equals(pp.Name, paramExp.Name, StringComparison.OrdinalIgnoreCase))) == null)
                    {
                        throw QueryExceptionExtensions.ExpressionNotSupported(
                                  "Unable to evaluate <{0}>. Parameter value not passed.", parentExpression);
                    }
                    return(p.Value);
                }
            }

            if (!(literalExpression is ConstantExpression))
            {
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          "Unable to evaluate <{0}>. Expressions of type column = " +
                          "'literal' are supported only.", parentExpression);
            }

            var memEx = (ConstantExpression)literalExpression;

            return(memEx.Value);
        }
Example #18
0
        private Expression BindWhere(Type resultType, Expression source, LambdaExpression predicate)
        {
            if (resultType != typeof(IQueryable <T>))
            {
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          "Usage of expressions in select statment is not allowed."
                          + " Please convert to IEnumerable and perform select statement.", source);
            }
            var where = Visit(predicate.Body);
            if (source is ConstantExpression)
            {
                return(where);
            }

            source = Visit(source);
            if (!(source is FilterExpression) && !(source is PostResultExpression))
            {
                return(new IntersectExpression(source, where));
            }

            return(new FilterExpression(where, source));
        }
        private ResultSetBuilder VisitOrderBy(OrderExpression exp)
        {
            var result    = Visit(exp.Body);
            var predicate = exp.Predicate;

            var lambda = predicate as LambdaExpression;

            if (lambda != null)
            {
                predicate = lambda.Body;
            }

            var member = ExHelper.GetMemberName(predicate, _itemType, exp);
            var column = _journal.Metadata.TryGetColumnByPropertyName(member);

            if (column == null)
            {
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          string.Format("Column '{0}' does not exist", member), exp);
            }
            result.ApplyOrderBy(column, (EJournalExpressionType)exp.NodeType);
            return(result);
        }
Example #20
0
        public static string GetMemberName(Expression expression, Type journalType)
        {
            ExpressionType leftType = expression.GetLeft().NodeType;
            var            member   = leftType == ExpressionType.MemberAccess || leftType == (ExpressionType)EJournalExpressionType.Column
                ? expression.GetLeft()
                : expression.GetRight();

            var ex = member as MemberExpression;

            if (ex != null)
            {
                var memEx = ex;
                return(GetMemberName(memEx, journalType));
            }

            var match = member as ColumnNameExpression;

            if (match != null)
            {
                return(match.Name);
            }
            throw QueryExceptionExtensions.ExpressionNotSupported("Cannot extract column name from expression ", expression);
        }
        private ResultSetBuilder EvaluateEquals(Expression expression)
        {
            if (expression.NodeType == ExpressionType.Equal ||
                expression.NodeType == ExpressionType.NotEqual)
            {
                var literal    = ExHelper.GetLiteralValue(expression, _parameters);
                var memberName = ExHelper.GetMemberName(expression, _itemType);

                IColumnMetadata column;
                try
                {
                    column = _journal.Metadata.GetColumnByPropertyName(memberName);
                }
                catch (NFSdbConfigurationException)
                {
                    throw QueryExceptionExtensions.ExpressionNotSupported(
                              string.Format("Column {0} does not exist", memberName), expression);
                }

                if (_journal.Metadata.TimestampColumnID == column.ColumnID)
                {
                    if (expression.NodeType == ExpressionType.Equal)
                    {
                        if (literal is long || literal is DateTime)
                        {
                            if (GetTimestamp(_journal.Metadata) != null &&
                                GetTimestamp(_journal.Metadata).PropertyName == memberName)
                            {
                                DateInterval filterInterval;
                                if (literal is long)
                                {
                                    var timestamp = (long)literal;
                                    filterInterval = new DateInterval(DateUtils.UnixTimestampToDateTime(timestamp),
                                                                      DateUtils.UnixTimestampToDateTime(timestamp + 1));
                                }
                                else
                                {
                                    var timestamp = (DateTime)literal;
                                    filterInterval = new DateInterval(timestamp,
                                                                      new DateTime(timestamp.Ticks + 1, timestamp.Kind));
                                }

                                var result = new ResultSetBuilder(_journal, _tx);
                                result.TimestampInterval(filterInterval);
                                return(result);
                            }
                        }
                    }
                }

                var res = new ResultSetBuilder(_journal, _tx);
                try
                {
                    if (literal != null)
                    {
                        if (expression.NodeType == ExpressionType.Equal)
                        {
                            ReflectionHelper.CallStaticPrivateGeneric("CreateColumnScan", this,
                                                                      column.DataType.Clazz, column, literal, res);
                        }
                        else if (expression.NodeType == ExpressionType.NotEqual)
                        {
                            ReflectionHelper.CallStaticPrivateGeneric("CreateColumnNotEqualScan", this,
                                                                      column.DataType.Clazz, column, literal, res);
                        }
                    }
                    else
                    {
                        if (expression.NodeType == ExpressionType.Equal)
                        {
                            ReflectionHelper.CallStaticPrivateGeneric("CreateColumnScan", this,
                                                                      column.DataType.Clazz, column, null, res);
                        }
                        else if (expression.NodeType == ExpressionType.NotEqual)
                        {
                            ReflectionHelper.CallStaticPrivateGeneric("CreateColumnNotEqualScan", this,
                                                                      column.DataType.Clazz, column, null, res);
                        }
                    }
                }
                catch (NFSdbQueryableNotSupportedException ex)
                {
                    throw QueryExceptionExtensions.ExpressionNotSupported(ex.Message, expression);
                }
                catch (InvalidCastException ex)
                {
                    throw QueryExceptionExtensions.ExpressionNotSupported(ex.Message, expression);
                }
                return(res);
            }

            throw new NotSupportedException(
                      string.Format("Unable to translate expression {0} to journal operation", expression));
        }
        private ResultSetBuilder EvaluateCompare(Expression exp)
        {
            var memberName = ExHelper.GetMemberName(exp, _itemType);
            var literal    = ExHelper.GetLiteralValue(exp, _parameters);

            var columnMetadata = GetTimestamp(_journal.Metadata);

            if (columnMetadata != null &&
                string.Equals(columnMetadata.PropertyName, memberName, StringComparison.OrdinalIgnoreCase) &&
                (literal is long || literal is DateTime))
            {
                DateInterval filterInterval;
                var          nodeType = exp.NodeType;
                if (exp.GetLeft().NodeType == ExpressionType.Constant)
                {
                    nodeType = InvertComarison(nodeType);
                }

                switch (nodeType)
                {
                case ExpressionType.GreaterThan:
                    var timestamp = literal is long
                                    ?DateUtils.UnixTimestampToDateTime((long)literal + 1)
                                        : ((DateTime)literal).AddTicks(1);

                    filterInterval = DateInterval.From(timestamp);
                    break;

                case ExpressionType.GreaterThanOrEqual:
                    timestamp = literal is long
                                ?DateUtils.UnixTimestampToDateTime((long)literal)
                                    : (DateTime)literal;

                    filterInterval = DateInterval.From(timestamp);
                    break;

                case ExpressionType.LessThan:
                    timestamp = literal is long
                                ?DateUtils.UnixTimestampToDateTime((long)literal)
                                    : (DateTime)literal;

                    filterInterval = DateInterval.To(timestamp);
                    break;

                case ExpressionType.LessThanOrEqual:
                    timestamp = literal is long
                                ?DateUtils.UnixTimestampToDateTime((long)literal + 1)
                                    : ((DateTime)literal).AddTicks(1);

                    filterInterval = DateInterval.To(timestamp);
                    break;

                default:
                    throw QueryExceptionExtensions.ExpressionNotSupported(string.Format(
                                                                              "Timestamp column operation {0} is not supported. Supported operations are <, >, <=, >=",
                                                                              nodeType), exp);
                }

                var result = new ResultSetBuilder(_journal, _tx);
                result.TimestampInterval(filterInterval);
                return(result);
            }
            throw QueryExceptionExtensions.ExpressionNotSupported(
                      "Comparison is supported for timestamp column only. Unable to bind '{0} to journal query operation",
                      exp);
        }
        public ResultSetBuilder Visit(Expression exp)
        {
            if (exp == null)
            {
                return(null);
            }

            switch (exp.NodeType)
            {
            case ExpressionType.Negate:
            case ExpressionType.NegateChecked:
            case ExpressionType.Not:
            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
            case ExpressionType.ArrayLength:
            case ExpressionType.Quote:
            case ExpressionType.TypeAs:
            case ExpressionType.UnaryPlus:
                return(VisitUnary((UnaryExpression)exp));

            case ExpressionType.Add:
            case ExpressionType.AddChecked:
            case ExpressionType.Subtract:
            case ExpressionType.SubtractChecked:
            case ExpressionType.Multiply:
            case ExpressionType.MultiplyChecked:
            case ExpressionType.Divide:
            case ExpressionType.Modulo:
            case ExpressionType.And:
            case ExpressionType.AndAlso:
            case ExpressionType.Or:
            case ExpressionType.OrElse:
            case ExpressionType.LessThan:
            case ExpressionType.LessThanOrEqual:
            case ExpressionType.GreaterThan:
            case ExpressionType.GreaterThanOrEqual:
            case ExpressionType.Equal:
            case ExpressionType.NotEqual:
            case ExpressionType.Coalesce:
            case ExpressionType.ArrayIndex:
            case ExpressionType.RightShift:
            case ExpressionType.LeftShift:
            case ExpressionType.ExclusiveOr:
            case ExpressionType.Power:
                return(VisitBinary(exp));

            case ExpressionType.Constant:
                return(VisitConstant((ConstantExpression)exp));
            }

            switch ((EJournalExpressionType)exp.NodeType)
            {
            case EJournalExpressionType.Contains:
                return(VisitContains((SymbolContainsExpression)exp));

            case EJournalExpressionType.Single:
            case EJournalExpressionType.Count:
            case EJournalExpressionType.LongCount:
            case EJournalExpressionType.Reverse:
            case EJournalExpressionType.First:
            case EJournalExpressionType.FirstOrDefault:
            case EJournalExpressionType.Last:
            case EJournalExpressionType.LastOrDefault:
                return(VisitCall((PostResultExpression)exp));

            case EJournalExpressionType.OrderBy:
            case EJournalExpressionType.OrderByDescending:
                return(VisitOrderBy((OrderExpression)exp));

            case EJournalExpressionType.Take:
            case EJournalExpressionType.Skip:
                return(VisitCall((SliceExpression)exp));

            case EJournalExpressionType.Map:
                return(VisitCall((MapExpression)exp));

            case EJournalExpressionType.LatestBy:
                return(VisitLatestBy((LatestBySymbolExpression)exp));

            case EJournalExpressionType.Intersect:
                var intsct = (IntersectExpression)exp;
                return(VisitSet(intsct.Left, intsct.Right, ExpressionType.And));

            case EJournalExpressionType.Union:
                var union = (UnionExpression)exp;
                return(VisitSet(union.Left, union.Right, ExpressionType.Or));

            case EJournalExpressionType.Filter:
                return(VisitFilter((FilterExpression)exp));

            case EJournalExpressionType.Journal:
                return(new ResultSetBuilder(_journal, _tx));

            default:
                throw QueryExceptionExtensions.ExpressionNotSupported(
                          "Expression {0} cannot be bound to Journal operation.", exp);
            }
        }