77
88namespace JsonApiToolkit . Extensions . Querying ;
99
10- internal static partial class NestedPropertyNavigator
10+ /// <summary>
11+ /// Builds LINQ expressions for collection navigations: <c>Any(item => predicate)</c>
12+ /// for nested paths (e.g. <c>tags.name</c>) and <c>Contains(value)</c> for primitive
13+ /// collections used as filter targets (e.g. <c>filter[tags][in]=value</c>).
14+ /// </summary>
15+ internal static class CollectionFilterBuilder
1116{
1217 /// <summary>
1318 /// Builds a filter expression for collection navigation using Any().
14- /// e.g., collection.Any(item => item.Property == value)
19+ /// e.g., collection.Any(item => item.Property == value)
1520 /// </summary>
16- private static Expression ? BuildCollectionFilterExpression (
21+ internal static Expression ? BuildCollectionFilterExpression (
1722 Expression collectionAccess ,
1823 Type elementType ,
1924 string [ ] remainingParts ,
@@ -22,17 +27,17 @@ internal static partial class NestedPropertyNavigator
2227 int depth
2328 )
2429 {
25- if ( depth > MaxRecursionDepth )
30+ if ( depth > PropertyNavigator . MaxRecursionDepth )
2631 {
2732 throw new JsonApiBadRequestException (
28- $ "Filter path recursion depth exceeds maximum of { MaxRecursionDepth } . "
33+ $ "Filter path recursion depth exceeds maximum of { PropertyNavigator . MaxRecursionDepth } . "
2934 + "Simplify the filter expression or reduce collection nesting." ,
3035 JsonApiErrorCodes . QueryTooComplex ,
3136 new ErrorSource { Parameter = $ "filter[{ filter . Field } ]" } ,
3237 new Dictionary < string , object >
3338 {
3439 [ "field" ] = filter . Field ,
35- [ "maxDepth" ] = MaxRecursionDepth ,
40+ [ "maxDepth" ] = PropertyNavigator . MaxRecursionDepth ,
3641 [ "actualDepth" ] = depth ,
3742 }
3843 ) ;
@@ -65,12 +70,16 @@ int depth
6570 }
6671
6772 Expression propertyAccess = Expression . Property ( itemParam , prop ) ;
68- innerExpression = BuildPropertyFilterExpression ( propertyAccess , filter , logger ) ;
73+ innerExpression = PropertyFilterBuilder . BuildPropertyFilterExpression (
74+ propertyAccess ,
75+ filter ,
76+ logger
77+ ) ;
6978 }
7079 else
7180 {
7281 // Nested property access - recursively build
73- innerExpression = BuildSafeNestedFilterExpression (
82+ innerExpression = PropertyNavigator . BuildSafeNestedFilterExpression (
7483 itemParam ,
7584 innerFilter ,
7685 logger ,
@@ -95,7 +104,7 @@ int depth
95104 /// Builds a filter expression when the property itself is a collection.
96105 /// e.g., entity.Tags.Contains("value") for filter[tags][in]=value
97106 /// </summary>
98- private static Expression ? BuildCollectionPropertyFilterExpression (
107+ internal static Expression ? BuildCollectionPropertyFilterExpression (
99108 Expression collectionAccess ,
100109 Type elementType ,
101110 FilterParameter filter ,
@@ -146,7 +155,7 @@ int depth
146155 {
147156 logger ? . LogWarning (
148157 "Failed to convert '{Value}' to {ElementType} for collection filter" ,
149- SanitizeForLog ( filter . Value ) ,
158+ FilterLogSanitizer . SanitizeForLog ( filter . Value ) ,
150159 elementType . Name
151160 ) ;
152161 return null ;
@@ -172,7 +181,7 @@ int depth
172181 {
173182 logger ? . LogWarning (
174183 "Failed to convert '{Value}' to {ElementType} for collection filter" ,
175- SanitizeForLog ( filter . Value ) ,
184+ FilterLogSanitizer . SanitizeForLog ( filter . Value ) ,
176185 elementType . Name
177186 ) ;
178187 return null ;
0 commit comments