@@ -46,7 +46,7 @@ public QueryLayerComposer(IEnumerable<IQueryConstraintProvider> constraintProvid
46
46
}
47
47
48
48
/// <inheritdoc />
49
- public FilterExpression ? GetTopFilterFromConstraints ( ResourceType primaryResourceType )
49
+ public FilterExpression ? GetPrimaryFilterFromConstraints ( ResourceType primaryResourceType )
50
50
{
51
51
ExpressionInScope [ ] constraints = _constraintProviders . SelectMany ( provider => provider . GetConstraints ( ) ) . ToArray ( ) ;
52
52
@@ -65,6 +65,75 @@ public QueryLayerComposer(IEnumerable<IQueryConstraintProvider> constraintProvid
65
65
return GetFilter ( filtersInTopScope , primaryResourceType ) ;
66
66
}
67
67
68
+ /// <inheritdoc />
69
+ public FilterExpression ? GetSecondaryFilterFromConstraints < TId > ( TId primaryId , HasManyAttribute hasManyRelationship )
70
+ {
71
+ ArgumentGuard . NotNull ( hasManyRelationship , nameof ( hasManyRelationship ) ) ;
72
+
73
+ if ( hasManyRelationship . InverseNavigationProperty == null )
74
+ {
75
+ return null ;
76
+ }
77
+
78
+ RelationshipAttribute ? inverseRelationship =
79
+ hasManyRelationship . RightType . FindRelationshipByPropertyName ( hasManyRelationship . InverseNavigationProperty . Name ) ;
80
+
81
+ if ( inverseRelationship == null )
82
+ {
83
+ return null ;
84
+ }
85
+
86
+ ExpressionInScope [ ] constraints = _constraintProviders . SelectMany ( provider => provider . GetConstraints ( ) ) . ToArray ( ) ;
87
+
88
+ var secondaryScope = new ResourceFieldChainExpression ( hasManyRelationship ) ;
89
+
90
+ // @formatter:wrap_chained_method_calls chop_always
91
+ // @formatter:keep_existing_linebreaks true
92
+
93
+ FilterExpression [ ] filtersInSecondaryScope = constraints
94
+ . Where ( constraint => secondaryScope . Equals ( constraint . Scope ) )
95
+ . Select ( constraint => constraint . Expression )
96
+ . OfType < FilterExpression > ( )
97
+ . ToArray ( ) ;
98
+
99
+ // @formatter:keep_existing_linebreaks restore
100
+ // @formatter:wrap_chained_method_calls restore
101
+
102
+ FilterExpression ? primaryFilter = GetFilter ( Array . Empty < QueryExpression > ( ) , hasManyRelationship . LeftType ) ;
103
+ FilterExpression ? secondaryFilter = GetFilter ( filtersInSecondaryScope , hasManyRelationship . RightType ) ;
104
+
105
+ FilterExpression inverseFilter = GetInverseRelationshipFilter ( primaryId , hasManyRelationship , inverseRelationship ) ;
106
+
107
+ return LogicalExpression . Compose ( LogicalOperator . And , inverseFilter , primaryFilter , secondaryFilter ) ;
108
+ }
109
+
110
+ private static FilterExpression GetInverseRelationshipFilter < TId > ( TId primaryId , HasManyAttribute relationship ,
111
+ RelationshipAttribute inverseRelationship )
112
+ {
113
+ return inverseRelationship is HasManyAttribute hasManyInverseRelationship
114
+ ? GetInverseHasManyRelationshipFilter ( primaryId , relationship , hasManyInverseRelationship )
115
+ : GetInverseHasOneRelationshipFilter ( primaryId , relationship , ( HasOneAttribute ) inverseRelationship ) ;
116
+ }
117
+
118
+ private static FilterExpression GetInverseHasOneRelationshipFilter < TId > ( TId primaryId , HasManyAttribute relationship ,
119
+ HasOneAttribute inverseRelationship )
120
+ {
121
+ AttrAttribute idAttribute = GetIdAttribute ( relationship . LeftType ) ;
122
+ var idChain = new ResourceFieldChainExpression ( ImmutableArray . Create < ResourceFieldAttribute > ( inverseRelationship , idAttribute ) ) ;
123
+
124
+ return new ComparisonExpression ( ComparisonOperator . Equals , idChain , new LiteralConstantExpression ( primaryId ! . ToString ( ) ! ) ) ;
125
+ }
126
+
127
+ private static FilterExpression GetInverseHasManyRelationshipFilter < TId > ( TId primaryId , HasManyAttribute relationship ,
128
+ HasManyAttribute inverseRelationship )
129
+ {
130
+ AttrAttribute idAttribute = GetIdAttribute ( relationship . LeftType ) ;
131
+ var idChain = new ResourceFieldChainExpression ( ImmutableArray . Create < ResourceFieldAttribute > ( idAttribute ) ) ;
132
+ var idComparison = new ComparisonExpression ( ComparisonOperator . Equals , idChain , new LiteralConstantExpression ( primaryId ! . ToString ( ) ! ) ) ;
133
+
134
+ return new HasExpression ( new ResourceFieldChainExpression ( inverseRelationship ) , idComparison ) ;
135
+ }
136
+
68
137
/// <inheritdoc />
69
138
public QueryLayer ComposeFromConstraints ( ResourceType requestResourceType )
70
139
{
@@ -309,7 +378,7 @@ private IncludeExpression RewriteIncludeForSecondaryEndpoint(IncludeExpression?
309
378
filter = new AnyExpression ( idChain , constants ) ;
310
379
}
311
380
312
- return filter == null ? existingFilter : existingFilter == null ? filter : new LogicalExpression ( LogicalOperator . And , filter , existingFilter ) ;
381
+ return LogicalExpression . Compose ( LogicalOperator . And , filter , existingFilter ) ;
313
382
}
314
383
315
384
/// <inheritdoc />
@@ -419,8 +488,8 @@ protected virtual IImmutableSet<IncludeElementExpression> GetIncludeElements(IIm
419
488
ArgumentGuard . NotNull ( expressionsInScope , nameof ( expressionsInScope ) ) ;
420
489
ArgumentGuard . NotNull ( resourceType , nameof ( resourceType ) ) ;
421
490
422
- ImmutableArray < FilterExpression > filters = expressionsInScope . OfType < FilterExpression > ( ) . ToImmutableArray ( ) ;
423
- FilterExpression ? filter = filters . Length > 1 ? new LogicalExpression ( LogicalOperator . And , filters ) : filters . FirstOrDefault ( ) ;
491
+ FilterExpression [ ] filters = expressionsInScope . OfType < FilterExpression > ( ) . ToArray ( ) ;
492
+ FilterExpression ? filter = LogicalExpression . Compose ( LogicalOperator . And , filters ) ;
424
493
425
494
return _resourceDefinitionAccessor . OnApplyFilter ( resourceType , filter ) ;
426
495
}
0 commit comments