예제 #1
0
        /*
         * Binary
         */

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        private static QueryGroup Parse <TEntity>(BinaryExpression expression)
            where TEntity : class
        {
            // Check directness
            if (IsDirect(expression))
            {
                return(new QueryGroup(QueryField.Parse <TEntity>(expression)));
            }

            // Variables
            var leftQueryGroup = Parse <TEntity>(expression.Left);

            // IsNot
            if (expression.Right.Type == StaticType.Boolean && expression.IsExtractable() == true)
            {
                var rightValue = (bool)expression.Right.GetValue();
                var isNot      = (expression.NodeType == ExpressionType.Equal && rightValue == false) ||
                                 (expression.NodeType == ExpressionType.NotEqual && rightValue == true);
                leftQueryGroup?.SetIsNot(isNot);
            }
            else
            {
                var rightQueryGroup = Parse <TEntity>(expression.Right);
                return(new QueryGroup(new[] { leftQueryGroup, rightQueryGroup }, GetConjunction(expression)));
            }

            // Return
            return(leftQueryGroup);
        }
예제 #2
0
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="expression"></param>
        /// <param name="unaryNodeType"></param>
        /// <returns></returns>
        private static QueryGroup Parse <TEntity>(MethodCallExpression expression,
                                                  ExpressionType?unaryNodeType = null)
            where TEntity : class
        {
            var queryFields = QueryField.Parse <TEntity>(expression, unaryNodeType);

            return(queryFields != null ? new QueryGroup(queryFields, GetConjunction(expression)) : null);
        }
예제 #3
0
        /*
         * Member
         */

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="expression"></param>
        /// <param name="unaryNodeType"></param>
        /// <returns></returns>
        private static QueryGroup Parse <TEntity>(MemberExpression expression,
                                                  ExpressionType?unaryNodeType = null)
            where TEntity : class
        {
            var queryFields = QueryField.Parse <TEntity>(expression, unaryNodeType);

            return(queryFields != null ? new QueryGroup(queryFields) : null);
        }
예제 #4
0
        private static QueryGroup Parse <TEntity>(BinaryExpression expression) where TEntity : class
        {
            var leftQueryGroup  = (QueryGroup)null;
            var rightQueryGroup = (QueryGroup)null;
            var skipRight       = false;
            var isEqualsTo      = true;

            /*
             * LEFT
             */

            // Get the value in the right
            if ((Nullable.GetUnderlyingType(expression.Right.Type) ?? expression.Right.Type) == typeof(bool) && (expression.Right.IsConstant() || expression.Right.IsMember()))
            {
                var value = expression.Right.GetValue();
                isEqualsTo = value is bool && Equals(value, false) != true;
                skipRight  = true;
            }

            // Binary
            if (expression.Left.IsBinary() == true)
            {
                leftQueryGroup = Parse <TEntity>(expression.Left.ToBinary());
                leftQueryGroup.SetIsNot(isEqualsTo == false);
            }
            // Unary
            else if (expression.Left.IsUnary() == true)
            {
                leftQueryGroup = Parse <TEntity>(expression.Left.ToUnary(), expression.NodeType, isEqualsTo: isEqualsTo);
            }
            // MethodCall
            else if (expression.Left.IsMethodCall())
            {
                leftQueryGroup = Parse <TEntity>(expression.Left.ToMethodCall(), isEqualsTo: isEqualsTo);
            }
            else
            {
                // Extractable
                if (expression.IsExtractable())
                {
                    leftQueryGroup = new QueryGroup(QueryField.Parse <TEntity>(expression).AsEnumerable());
                    skipRight      = true;
                }
            }

            /*
             * RIGHT
             */

            if (skipRight == false)
            {
                // Binary
                if (expression.Right.IsBinary() == true)
                {
                    rightQueryGroup = Parse <TEntity>(expression.Right.ToBinary());
                }
                // Unary
                if (expression.Right.IsUnary() == true)
                {
                    rightQueryGroup = Parse <TEntity>(expression.Right.ToUnary(), expression.NodeType);
                }
                // MethodCall
                else if (expression.Right.IsMethodCall())
                {
                    rightQueryGroup = Parse <TEntity>(expression.Right.ToMethodCall());
                }

                // Return both of them
                if (leftQueryGroup != null && rightQueryGroup != null)
                {
                    var conjunction = (expression.NodeType == ExpressionType.OrElse) ? Conjunction.Or : Conjunction.And;
                    return(new QueryGroup(null, new[] { leftQueryGroup, rightQueryGroup }, conjunction));
                }
            }

            // Return either one of them
            return(leftQueryGroup ?? rightQueryGroup);
        }
예제 #5
0
        // Static Methods

        /// <summary>
        /// This method is used to parse the customized query tree expression. This method expects a dynamic object and converts it to the actual
        /// <see cref="QueryGroup"/> that defines the query tree expression.
        /// </summary>
        /// <param name="obj">
        /// A dynamic query tree expression to be parsed.
        /// Example:
        /// var expression = new { Conjunction = Conjunction.And, Company = "Microsoft",
        /// FirstName = new { Operation = Operation.Like, Value = "An%" },
        /// UpdatedDate = new { Operation = Operation.LessThan, Value = DateTime.UtcNow.Date }}
        /// </param>
        /// <returns>An instance of the <see cref="QueryGroup"/> object that contains the parsed query expression.</returns>
        public static QueryGroup Parse(object obj)
        {
            // Cannot further optimize and shortify this method, this one works like a charm for now.

            // Check for value
            if (obj == null)
            {
                throw new ArgumentNullException($"Parameter '{StringConstant.Obj.ToLower()}' cannot be null.");
            }

            // Variables
            var queryFields = new List <QueryField>();
            var queryGroups = new List <QueryGroup>();
            var conjunction = Conjunction.And;

            // Iterate every property
            var objectProperties = obj.GetType().GetProperties();

            objectProperties.ToList().ForEach(property =>
            {
                var fieldName = property.Name;

                // Identify the fields
                if (string.Equals(fieldName, StringConstant.Conjunction, StringComparison.CurrentCultureIgnoreCase))
                {
                    // Throws an exception if conjunction is not a conjunction type
                    if (property.PropertyType != typeof(Conjunction))
                    {
                        throw new InvalidQueryExpressionException($"Conjunction field must be of type {typeof(Conjunction).FullName}.");
                    }

                    // Conjunction
                    conjunction = (Conjunction)property.GetValue(obj);
                }
                else if (string.Equals(fieldName, StringConstant.QueryGroups, StringComparison.CurrentCultureIgnoreCase))
                {
                    // Child QueryGroups
                    var value = property.GetValue(obj);
                    if (value is Array)
                    {
                        ((Array)value).AsEnumerable().ToList().ForEach(item =>
                        {
                            queryGroups.Add(Parse(item));
                        });
                    }
                    else
                    {
                        queryGroups.Add(Parse(value));
                    }
                }
                else
                {
                    // Other pre-defined fields
                    var value = property.GetValue(obj);
                    var type  = value?.GetType();

                    if (type?.IsGenericType == false || value == null)
                    {
                        // Most likely, (Field.Name = <value|null>)
                        queryFields.Add(new QueryField(fieldName, value));
                    }
                    else
                    {
                        // Another dynamic object type, get the 'Operation' property
                        var properties        = type?.GetProperties();
                        var operationProperty = properties?.FirstOrDefault(p => p.Name.ToLower() == StringConstant.Operation.ToLower());

                        // The property 'Operation' must always be present
                        if (operationProperty == null)
                        {
                            throw new InvalidQueryExpressionException($"The 'Operation' property must be present for field '{property.Name}'.");
                        }

                        // The property operatoin must be of type 'RepoDb.Enumerations.Operation'
                        if (operationProperty.PropertyType != typeof(Operation))
                        {
                            throw new InvalidQueryExpressionException($"The 'Operation' property for field '{property.Name}' must be of type '{typeof(Operation).FullName}'.");
                        }

                        // The 'Value' property must always be present
                        var valueProperty = properties?.FirstOrDefault(p => p.Name.ToLower() == StringConstant.Value.ToLower());

                        // Check for the 'Value' property
                        if (valueProperty == null)
                        {
                            throw new InvalidQueryExpressionException($"The 'Value' property for dynamic type query must be present at field '{property.Name}'.");
                        }

                        // Get the 'Operation' and the 'Value' value
                        var operation = (Operation)operationProperty.GetValue(value);
                        value         = valueProperty.GetValue(value);

                        // For other operation, the 'Value' property must be present
                        if (value == null && (operation != Operation.Equal && operation != Operation.NotEqual))
                        {
                            throw new InvalidQueryExpressionException($"The value property '{valueProperty.Name}' must not be null.");
                        }

                        // Identify the 'Operation' and parse the correct value
                        if ((operation == Operation.Equal || operation == Operation.NotEqual) && value == null)
                        {
                            // Most likely, new { Field.Name = { Operation = Operation.<Equal|NotEqual>, Value = (object)null } }
                            // It should be (IS NULL) or (IS NOT NULL) in SQL Statement
                            queryFields.Add(new QueryField(fieldName, operation, value));
                        }
                        else if (operation == Operation.All || operation == Operation.Any)
                        {
                            // Special case: All (AND), Any (OR)
                            if (value.GetType().IsArray)
                            {
                                var childQueryGroupFields = new List <QueryField>();
                                ((Array)value).AsEnumerable().ToList().ForEach(underlyingValue =>
                                {
                                    childQueryGroupFields.Add(QueryField.Parse(fieldName, underlyingValue));
                                });
                                var queryGroup = new QueryGroup(childQueryGroupFields, null, operation == Operation.All ? Conjunction.And : Conjunction.Or);
                                queryGroups.Add(queryGroup);
                            }
                            else
                            {
                                queryFields.Add(QueryField.Parse(fieldName, value));
                            }
                        }
                        else
                        {
                            if (operation == Operation.Between || operation == Operation.NotBetween)
                            {
                                // Special case: (Field.Name = new { Operation = Operation.<Between|NotBetween>, Value = new [] { value1, value2 })
                                ValidateBetweenOperations(fieldName, operation, value);
                            }
                            else if (operation == Operation.In || operation == Operation.NotIn)
                            {
                                // Special case: (Field.Name = new { Operation = Operation.<In|NotIn>, Value = new [] { value1, value2 })
                                ValidateInOperations(fieldName, operation, value);
                            }
                            else
                            {
                                // Other Operations
                                ValidateOtherOperations(fieldName, operation, value);
                            }

                            // Add the field values
                            queryFields.Add(new QueryField(fieldName, operation, value));
                        }
                    }
                }
            });

            // Return
            return(new QueryGroup(queryFields, queryGroups, conjunction).FixParameters());
        }
예제 #6
0
        private static QueryGroup Parse <TEntity>(BinaryExpression expression) where TEntity : class
        {
            var leftQueryGroup  = (QueryGroup)null;
            var rightQueryGroup = (QueryGroup)null;
            var rightValue      = (object)null;
            var skipRight       = false;
            var isEqualsTo      = true;

            /*
             * LEFT
             */

            // Get the value in the right
            if (expression.IsExtractable())
            {
                rightValue = expression.Right.GetValue();
                skipRight  = true;
                if (rightValue is bool)
                {
                    isEqualsTo = Equals(rightValue, false) == false;
                }
            }

            // Binary
            if (expression.Left.IsBinary() == true)
            {
                leftQueryGroup = Parse <TEntity>(expression.Left.ToBinary());
                leftQueryGroup.SetIsNot(isEqualsTo == false);
            }
            // Unary
            else if (expression.Left.IsUnary() == true)
            {
                leftQueryGroup = Parse <TEntity>(expression.Left.ToUnary(), rightValue, expression.NodeType, isEqualsTo);
            }
            // MethodCall
            else if (expression.Left.IsMethodCall())
            {
                leftQueryGroup = Parse <TEntity>(expression.Left.ToMethodCall(), false, isEqualsTo);
            }
            else
            {
                // Extractable
                if (expression.IsExtractable())
                {
                    leftQueryGroup = new QueryGroup(QueryField.Parse <TEntity>(expression));
                    skipRight      = true;
                }
            }

            // Identify the node type
            if (expression.NodeType == ExpressionType.NotEqual)
            {
                leftQueryGroup.SetIsNot(leftQueryGroup.IsNot == isEqualsTo);
            }

            /*
             * RIGHT
             */

            if (skipRight == false)
            {
                // Binary
                if (expression.Right.IsBinary() == true)
                {
                    rightQueryGroup = Parse <TEntity>(expression.Right.ToBinary());
                }
                // Unary
                else if (expression.Right.IsUnary() == true)
                {
                    rightQueryGroup = Parse <TEntity>(expression.Right.ToUnary(), null, expression.NodeType, true);
                }
                // MethodCall
                else if (expression.Right.IsMethodCall())
                {
                    rightQueryGroup = Parse <TEntity>(expression.Right.ToMethodCall(), false, true);
                }

                // Return both of them
                if (leftQueryGroup != null && rightQueryGroup != null)
                {
                    var conjunction = (expression.NodeType == ExpressionType.OrElse) ? Conjunction.Or : Conjunction.And;
                    return(new QueryGroup(null, new[] { leftQueryGroup, rightQueryGroup }, conjunction));
                }
            }

            // Return either one of them
            return(leftQueryGroup ?? rightQueryGroup);
        }
예제 #7
0
 /// <summary>
 /// Queries a data from the database table function.
 /// </summary>
 /// <typeparam name="TEntity">The type of the data entity object.</typeparam>
 /// <param name="connection">The connection object to be used.</param>
 /// <param name="funcName">Function name.</param>
 /// <param name="parameters">The dynamic expression of function parameters.</param>
 /// <param name="orderBy">The order definition of the fields to be used.</param>
 /// <param name="hints">The table hints to be used.</param>
 /// <param name="cacheKey">
 /// The key to the cache. If the cache key is present in the cache, then the item from the cache will be returned instead. Setting this
 /// to null would force to query from the database.
 /// </param>
 /// <param name="cacheItemExpiration">The expiration in minutes of the cache item.</param>
 /// <param name="commandTimeout">The command timeout in seconds to be used.</param>
 /// <param name="transaction">The transaction to be used.</param>
 /// <param name="cache">The cache object to be used.</param>
 /// <param name="trace">The trace object to be used.</param>
 /// <param name="statementBuilder">The statement builder object to be used.</param>
 /// <returns>An enumerable list of data entity object.</returns>
 public static IEnumerable <TEntity> QueryAllTableFunc <TEntity>(this IDbConnection connection,
                                                                 string funcName,
                                                                 object parameters,
                                                                 IEnumerable <OrderField> orderBy = null,
                                                                 string hints                       = null,
                                                                 string cacheKey                    = null,
                                                                 int cacheItemExpiration            = Constant.DefaultCacheItemExpirationInMinutes,
                                                                 int?commandTimeout                 = null,
                                                                 IDbTransaction transaction         = null,
                                                                 ICache cache                       = null,
                                                                 ITrace trace                       = null,
                                                                 IStatementBuilder statementBuilder = null)
     where TEntity : class
 {
     return(QueryAllTableFunc <TEntity>(connection: connection,
                                        funcName: funcName,
                                        parameters: parameters == null ? null : QueryField.Parse(parameters),
                                        orderBy: orderBy,
                                        hints: hints,
                                        cacheKey: cacheKey,
                                        cacheItemExpiration: cacheItemExpiration,
                                        commandTimeout: commandTimeout,
                                        transaction: transaction,
                                        cache: cache,
                                        trace: trace,
                                        statementBuilder: statementBuilder));
 }