From 39417b00e3f7798c6878e9da9a9041b5f010b3d4 Mon Sep 17 00:00:00 2001 From: Brandon Henricks <78803523+bluemodus-brandon@users.noreply.github.com> Date: Thu, 11 Jul 2024 22:57:36 -0400 Subject: [PATCH] Enhance expression handling and refactoring Refactored `ContentItemQueryExpressionVisitor.cs` to make `ExtractFieldValues` and `GetExpressionValue` methods static, improving design by eliminating the need for class instances for these operations. Added multiple new methods and `using` directives in `ExpressionExtensions.cs` to expand expression handling capabilities, including reflection and collection processing. Introduced utility methods for more efficient and flexible value extraction from expressions, supporting a variety of types and scenarios. These changes significantly enhance the utility and maintainability of the `XperienceCommunity.DataContext` namespace, making the data context more dynamic and capable of handling a broader range of data manipulation and querying scenarios. --- .../ContentItemQueryExpressionVisitor.cs | 4 +- .../Extensions/ExpressionExtensions.cs | 120 +++++++++++++++++- 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/src/XperienceCommunity.DataContext/ContentItemQueryExpressionVisitor.cs b/src/XperienceCommunity.DataContext/ContentItemQueryExpressionVisitor.cs index 5f6c3d0..18d3926 100644 --- a/src/XperienceCommunity.DataContext/ContentItemQueryExpressionVisitor.cs +++ b/src/XperienceCommunity.DataContext/ContentItemQueryExpressionVisitor.cs @@ -308,13 +308,13 @@ private void AddWhereInCondition(string columnName, IEnumerable? values) return null; } - private IEnumerable ExtractFieldValues(MemberExpression fieldExpression) + private static IEnumerable ExtractFieldValues(MemberExpression fieldExpression) { var value = GetExpressionValue(fieldExpression); return ExtractValues(value); } - private object? GetExpressionValue(Expression expression) + private static object? GetExpressionValue(Expression expression) { switch (expression) { diff --git a/src/XperienceCommunity.DataContext/Extensions/ExpressionExtensions.cs b/src/XperienceCommunity.DataContext/Extensions/ExpressionExtensions.cs index 0c28aa4..1008259 100644 --- a/src/XperienceCommunity.DataContext/Extensions/ExpressionExtensions.cs +++ b/src/XperienceCommunity.DataContext/Extensions/ExpressionExtensions.cs @@ -1,9 +1,72 @@ -using System.Linq.Expressions; +using System.Collections; +using System.Linq.Expressions; +using System.Reflection; namespace XperienceCommunity.DataContext.Extensions { internal static class ExpressionExtensions { + /// + /// Extracts the values from a collection expression. + /// + /// The collection expression. + /// The extracted values as an enumerable of objects. + internal static IEnumerable? ExtractCollectionValues(this MemberExpression collectionExpression) + { + if (collectionExpression.Expression != null) + { + var value = GetExpressionValue(collectionExpression.Expression); + + return ExtractValues(value); + } + + return null; + } + + /// + /// Extracts the values from a field expression. + /// + /// The field expression. + /// The extracted values as an enumerable of objects. + internal static IEnumerable ExtractFieldValues(this MemberExpression fieldExpression) + { + var value = GetExpressionValue(fieldExpression); + return ExtractValues(value); + } + + /// + /// Gets the value of an expression. + /// + /// The expression. + /// The value of the expression. + internal static object? GetExpressionValue(Expression expression) + { + switch (expression) + { + case ConstantExpression constantExpression: + return constantExpression.Value!; + + case MemberExpression memberExpression: + var container = GetExpressionValue(memberExpression.Expression!); + var member = memberExpression.Member; + switch (member) + { + case FieldInfo fieldInfo: + return fieldInfo.GetValue(container); + + case PropertyInfo propertyInfo: + return propertyInfo.GetValue(container); + + default: + throw new NotSupportedException( + $"The member type '{member.GetType().Name}' is not supported."); + } + default: + throw new NotSupportedException( + $"The expression type '{expression.GetType().Name}' is not supported."); + } + } + /// /// Gets the member name from a method call expression. /// @@ -18,5 +81,60 @@ internal static class ExpressionExtensions return null; } + + private static IEnumerable ExtractValues(object? value) + { + if (value is null) + { + return []; + } + + if (value is IEnumerable objectEnumerable) + { + return objectEnumerable; + } + + if (value is IEnumerable intEnumerable) + { + return intEnumerable.Cast(); + } + + if (value is IEnumerable stringEnumerable) + { + return stringEnumerable.Cast(); + } + + if (value is IEnumerable guidEnumerable) + { + return guidEnumerable.Cast(); + } + + if (value is IEnumerable enumerable) + { + var list = new List(); + + foreach (var item in enumerable) + { + var itemValues = ExtractValues(item); + list.AddRange(itemValues); + } + + return list; + } + + // Check if the object has a property that is a collection + var properties = value.GetType().GetProperties(); + + var collectionProperty = properties.FirstOrDefault(p => + p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)); + + if (collectionProperty != null) + { + var collectionValue = collectionProperty.GetValue(value); + return ExtractValues(collectionValue); + } + + return new[] { value }; + } } }