private static string ComputeNewObject(Expression predicate, RequestBuilderConfiguration configuration) { var newPredicate = (predicate as NewExpression); var properties = newPredicate.Arguments.Select(a => ComputeMemberAccess(a, configuration)); return(string.Join(",", properties)); }
/// <summary> /// Converts fields case depending on configuration provided /// </summary> /// <param name="fieldName"></param> /// <param name="configuration"></param> /// <returns></returns> public static string Run(string fieldName, RequestBuilderConfiguration configuration) { return(configuration.CaseContract switch { CaseContract.SnakeCase => fieldName.ToSnakeCase(), CaseContract.PascalCase => fieldName.ToPascalCase(), CaseContract.CamelCase => fieldName.ToCamelCase(), _ => fieldName });
/// <summary> /// Interprets a list of fields and add to each of them a "desc" sort modificator /// </summary> /// <param name="predicate"></param> /// <param name="configuration"></param> /// <returns></returns> public static string Run(Expression predicate, RequestBuilderConfiguration configuration) { if (predicate is null) { throw new ArgumentNullException(nameof(predicate)); } return(string.Join(",", MemberPredicateInterpreter.Run(predicate, configuration) .Split(',').Select(s => s + " desc"))); }
private static string UnrollMemberPath(MemberExpression predicate, RequestBuilderConfiguration configuration) { var path = ""; if (predicate.Expression != null && predicate.Expression is MemberExpression) { path = UnrollMemberPath(predicate.Expression as MemberExpression, configuration) + "."; } return(path + FieldInterpreter.Run(predicate.Member.Name, configuration)); }
public void Setup() { snakeCaseConfiguration = new RequestBuilderConfiguration { CaseContract = CaseContract.SnakeCase }; camelCaseConfiguration = new RequestBuilderConfiguration { CaseContract = CaseContract.CamelCase }; pascalCaseConfiguration = new RequestBuilderConfiguration { CaseContract = CaseContract.PascalCase }; }
/// <summary> /// Interprets the public properties of the generic type to generate a list of selects /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static string Run <T>(RequestBuilderConfiguration configuration) { var properties = typeof(T) .GetProperties(); var fields = new List <string>(); foreach (var p in properties) { fields.Add(GetFields(p, configuration)); } return(string.Join(",", fields.Where(f => !string.IsNullOrEmpty(f)))); }
/// <summary> /// Assembles a request from the statements /// </summary> /// <param name="selects"></param> /// <param name="filters"></param> /// <param name="excludes"></param> /// <param name="orders"></param> /// <param name="search"></param> /// <param name="take"></param> /// <param name="skip"></param> /// <param name="configuration"></param> /// <returns></returns> public static string Run( string selects, string filters, string excludes, string orders, string search, int take, int skip, RequestBuilderConfiguration configuration ) { if (string.IsNullOrEmpty(selects)) { throw new ArgumentNullException(nameof(selects)); } string body = $"fields {selects};"; if (!string.IsNullOrEmpty(filters)) { body += $"\nwhere {filters};"; } if (!string.IsNullOrEmpty(excludes)) { body += $"\nexclude {excludes};"; } if (!string.IsNullOrEmpty(orders)) { body += $"\nsort {orders};"; } if (!string.IsNullOrEmpty(search)) { body += $"\nsearch {search};"; } if (take != default) { body += $"\nlimit {take.ToString(CultureInfo.InvariantCulture)};"; } if (skip != default) { body += $"\noffset {skip.ToString(CultureInfo.InvariantCulture)};"; } return(body); }
private static string ComputeMemberAccess(Expression predicate, RequestBuilderConfiguration configuration) { var memberExpression = (predicate as MemberExpression); switch (memberExpression.Member.MemberType) { case System.Reflection.MemberTypes.Property: var path = UnrollMemberPath(memberExpression, configuration); return(path); default: throw new NotImplementedException($"Works only with properties of the Generic object"); } }
/// <summary> /// Returns a member or list of members as a string from a predicate /// </summary> /// <param name="predicate"></param> /// <param name="configuration"></param> /// <returns></returns> public static string Run(Expression predicate, RequestBuilderConfiguration configuration) { if (predicate is null) { throw new ArgumentNullException(nameof(predicate)); } switch (predicate.NodeType) { case ExpressionType.MemberAccess: return(ComputeMemberAccess(predicate, configuration)); case ExpressionType.New: return(ComputeNewObject(predicate, configuration)); default: throw new Exception("Invalid predicate provided"); } }
private static string GetFields(PropertyInfo property, RequestBuilderConfiguration configuration, string parentPath = "") { var fields = new List <string>(); var path = parentPath + FieldInterpreter.Run(property.Name, configuration); if (property.GetCustomAttribute <IncludeAttribute>() != null) { foreach (var p in property.PropertyType.GetProperties()) { fields.Add(GetFields(p, configuration, path + ".")); } } else if (property.GetCustomAttribute <ExcludeAttribute>() == null) { fields.Add(path); } return(string.Join(",", fields)); }
private static string ComputeConstant(Expression constant, RequestBuilderConfiguration configuration) { var value = (constant as ConstantExpression).Value; if (value is string) { return($"\"{(value as string).Replace("\"", "\\\"")}\""); } if (value is bool boolean) { return(boolean ? "true" : "false"); } if (value is null) { return("null"); } if (value is IConvertible) { return((value as IConvertible).ToString(CultureInfo.InvariantCulture)); } return(value.ToString()); }
private static string ComputeMemberAccess(Expression predicate, RequestBuilderConfiguration configuration) { return(MemberPredicateInterpreter.Run(predicate, configuration)); }
/// <summary> /// Interpretes a predicate to convert it to a string usable by IGDB API /// </summary> /// <param name="predicate"></param> /// <returns></returns> public static string Run(Expression predicate, RequestBuilderConfiguration configuration, bool invert = false, ArrayPostfixMode arrayPostfixMode = ArrayPostfixMode.ContainsAny) { if (predicate is null) { throw new ArgumentNullException(nameof(predicate)); } var binaryPredicate = predicate as BinaryExpression; switch (predicate.NodeType) { /* * First part of switch : binary operators * ------- * if Node type referes to a binary operators we set the operator * and let the method continue after the switch to create the * expression. * binary operators are either logical operators (&& or ||), * relational operators (>, >=, <, <=) or equality operators (==, !=) */ case ExpressionType.AndAlso: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, "&", configuration)); case ExpressionType.OrElse: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, "|", configuration)); case ExpressionType.GreaterThan: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, ">", configuration)); case ExpressionType.GreaterThanOrEqual: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, ">=", configuration)); case ExpressionType.LessThan: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, "<", configuration)); case ExpressionType.LessThanOrEqual: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, "<=", configuration)); case ExpressionType.NotEqual: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, "!=", configuration)); case ExpressionType.Equal: return(ComputeBinaryOperator(binaryPredicate.Left, binaryPredicate.Right, "=", configuration)); /* * Second part of switch : members * ------- * If node type refers to a member, a constant or an array then * then return an interpretation. */ case ExpressionType.MemberAccess: return(ComputeMemberAccess(predicate, configuration)); case ExpressionType.Constant: return(ComputeConstant(predicate, configuration)); case ExpressionType.NewArrayInit: return(ComputeArray(predicate, arrayPostfixMode, configuration)); /* * Third part of switch : methods * ------- * if node type referes to a method corresponding to */ case ExpressionType.Not: return(ComputeNotCall(predicate, configuration)); case ExpressionType.Call: return(ComputeMethodCall(predicate, configuration, invert)); default: throw new InvalidPredicateException(predicate); } }
private static string ComputeArray(Expression array, ArrayPostfixMode arrayPostfixMode, RequestBuilderConfiguration configuration) { var list = string.Join( ",", (array as NewArrayExpression).Expressions.Select(e => Run(e as ConstantExpression, configuration)) ); return(arrayPostfixMode switch { ArrayPostfixMode.ContainsAny => $"({list})", ArrayPostfixMode.ContainsAll => $"[{list}]", ArrayPostfixMode.ExactMatch => $"{{{list}}}", _ => throw new Exception("Unknown array postfix mode"), });
public void Setup() { configuration = new RequestBuilderConfiguration { CaseContract = CaseContract.SnakeCase }; }
private static string ComputeBinaryOperator(Expression left, Expression right, string binaryOperator, RequestBuilderConfiguration configuration) { var leftMember = Run(left, configuration); var rightMember = Run(right, configuration); return($"{leftMember} {binaryOperator} {rightMember}"); }
/// <summary> /// Constructor. /// </summary> public RequestBuilder(RequestBuilderConfiguration configuration) { selects = "*"; orders = ""; this.configuration = configuration; }