Skip to content

Commit e8c146c

Browse files
author
Bart Koelman
committed
TODO: Replace squashed changes from #1142 with rebase on master after merge
Removed existing resource inheritance tests Resource inheritance: return derived types Resource inheritance: sparse fieldsets Changed the expression tokenizer to recognize dots in field chains Resource inheritance: derived includes Resource inheritance: derived filters Added ResourceFieldAttribute.Type and use it from QueryExpression.ToFullString() to provide improved debug info Resource inheritance: sorting on derived fields Added missing tests for GET abstract/concrete base primary types at secondary/relationship endpoints Resource graph validation: fail if field from base type does not exist on derived type Clarified error message on type mismatch in request body Rename inheritance tests Added extension method to obtain ClrType of a resource instance (we'll need this later) Resource inheritance: write endpoints Updated documentation Added rewriter unit tests to improve code coverage Exclude example project from code coverage
1 parent 978a311 commit e8c146c

File tree

188 files changed

+10174
-1390
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

188 files changed

+10174
-1390
lines changed

benchmarks/Serialization/ResourceSerializationBenchmarks.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,19 @@ protected override IEvaluatedIncludeCache CreateEvaluatedIncludeCache(IResourceG
127127
RelationshipAttribute multi4 = resourceAType.GetRelationshipByPropertyName(nameof(OutgoingResource.Multi4));
128128
RelationshipAttribute multi5 = resourceAType.GetRelationshipByPropertyName(nameof(OutgoingResource.Multi5));
129129

130-
ImmutableArray<ResourceFieldAttribute> chain = ImmutableArray.Create<ResourceFieldAttribute>(single2, single3, multi4, multi5);
131-
IEnumerable<ResourceFieldChainExpression> chains = new ResourceFieldChainExpression(chain).AsEnumerable();
132-
133-
var converter = new IncludeChainConverter();
134-
IncludeExpression include = converter.FromRelationshipChains(chains);
130+
var include = new IncludeExpression(new HashSet<IncludeElementExpression>
131+
{
132+
new(single2, new HashSet<IncludeElementExpression>
133+
{
134+
new(single3, new HashSet<IncludeElementExpression>
135+
{
136+
new(multi4, new HashSet<IncludeElementExpression>
137+
{
138+
new(multi5)
139+
}.ToImmutableHashSet())
140+
}.ToImmutableHashSet())
141+
}.ToImmutableHashSet())
142+
}.ToImmutableHashSet());
135143

136144
var cache = new EvaluatedIncludeCache();
137145
cache.Set(include);

benchmarks/Serialization/SerializationBenchmarkBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ public Task OnSetToManyRelationshipAsync<TResource>(TResource leftResource, HasM
180180
return Task.CompletedTask;
181181
}
182182

183-
public Task OnAddToRelationshipAsync<TResource, TId>(TId leftResourceId, HasManyAttribute hasManyRelationship, ISet<IIdentifiable> rightResourceIds,
183+
public Task OnAddToRelationshipAsync<TResource>(TResource leftResource, HasManyAttribute hasManyRelationship, ISet<IIdentifiable> rightResourceIds,
184184
CancellationToken cancellationToken)
185-
where TResource : class, IIdentifiable<TId>
185+
where TResource : class, IIdentifiable
186186
{
187187
return Task.CompletedTask;
188188
}

docs/usage/reading/filtering.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Expressions are composed using the following functions:
2424
| Ends with text | `endsWith` | `?filter=endsWith(description,'End')` |
2525
| Equals one value from set | `any` | `?filter=any(chapter,'Intro','Summary','Conclusion')` |
2626
| Collection contains items | `has` | `?filter=has(articles)` |
27+
| Type-check derived type (v5) | `isType` | `?filter=isType(,men)` |
2728
| Negation | `not` | `?filter=not(equals(lastName,null))` |
2829
| Conditional logical OR | `or` | `?filter=or(has(orders),has(invoices))` |
2930
| Conditional logical AND | `and` | `?filter=and(has(orders),has(invoices))` |
@@ -86,6 +87,31 @@ GET /customers?filter=has(orders,not(equals(status,'Paid'))) HTTP/1.1
8687

8788
Which returns only customers that have at least one unpaid order.
8889

90+
_since v5.0_
91+
92+
Use the `isType` filter function to perform a type check on a derived type. You can pass a nested filter, where the derived fields are accessible.
93+
The first parameter can be used to perform the type check on a to-one relationship path.
94+
95+
Only return men:
96+
```http
97+
GET /humans?filter=isType(,men) HTTP/1.1
98+
```
99+
100+
Only return men with beards:
101+
```http
102+
GET /humans?filter=isType(,men,equals(hasBeard,'true')) HTTP/1.1
103+
```
104+
105+
Only return people whose best friend is a man with children:
106+
```http
107+
GET /humans?filter=isType(bestFriend,men,has(children)) HTTP/1.1
108+
```
109+
110+
Only return people who have at least one female married child:
111+
```http
112+
GET /humans?filter=has(children,isType(,woman,not(equals(husband,null)))) HTTP/1.1
113+
```
114+
89115
# Legacy filters
90116

91117
The next section describes how filtering worked in versions prior to v4.0. They are always applied on the set of resources being requested (no nesting).

0 commit comments

Comments
 (0)