/* * 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); }
/// <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); }
/* * 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); }
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); }
// 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()); }
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); }
/// <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)); }