Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resource inheritance #1142

Merged
merged 19 commits into from
Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions JsonApiDotNetCore.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ $left$ = $right$;</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=B3D9EE6B4EC62A4F961EB15F9ADEC2C6/ReplacePattern/@EntryValue">$collection$.IsNullOrEmpty()</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=B3D9EE6B4EC62A4F961EB15F9ADEC2C6/SearchPattern/@EntryValue">$collection$ == null || !$collection$.Any()</s:String>
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=B3D9EE6B4EC62A4F961EB15F9ADEC2C6/Severity/@EntryValue">WARNING</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Accurize/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=appsettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Assignee/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Contoso/@EntryIndexedValue">True</s:Boolean>
Expand Down
18 changes: 13 additions & 5 deletions benchmarks/Serialization/ResourceSerializationBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,19 @@ protected override IEvaluatedIncludeCache CreateEvaluatedIncludeCache(IResourceG
RelationshipAttribute multi4 = resourceAType.GetRelationshipByPropertyName(nameof(OutgoingResource.Multi4));
RelationshipAttribute multi5 = resourceAType.GetRelationshipByPropertyName(nameof(OutgoingResource.Multi5));

ImmutableArray<ResourceFieldAttribute> chain = ImmutableArray.Create<ResourceFieldAttribute>(single2, single3, multi4, multi5);
IEnumerable<ResourceFieldChainExpression> chains = new ResourceFieldChainExpression(chain).AsEnumerable();

var converter = new IncludeChainConverter();
IncludeExpression include = converter.FromRelationshipChains(chains);
var include = new IncludeExpression(new HashSet<IncludeElementExpression>
{
new(single2, new HashSet<IncludeElementExpression>
{
new(single3, new HashSet<IncludeElementExpression>
{
new(multi4, new HashSet<IncludeElementExpression>
{
new(multi5)
}.ToImmutableHashSet())
}.ToImmutableHashSet())
}.ToImmutableHashSet())
}.ToImmutableHashSet());

var cache = new EvaluatedIncludeCache();
cache.Set(include);
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/Serialization/SerializationBenchmarkBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ public Task OnSetToManyRelationshipAsync<TResource>(TResource leftResource, HasM
return Task.CompletedTask;
}

public Task OnAddToRelationshipAsync<TResource, TId>(TId leftResourceId, HasManyAttribute hasManyRelationship, ISet<IIdentifiable> rightResourceIds,
public Task OnAddToRelationshipAsync<TResource>(TResource leftResource, HasManyAttribute hasManyRelationship, ISet<IIdentifiable> rightResourceIds,
CancellationToken cancellationToken)
where TResource : class, IIdentifiable<TId>
where TResource : class, IIdentifiable
{
return Task.CompletedTask;
}
Expand Down
27 changes: 27 additions & 0 deletions docs/usage/reading/filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Expressions are composed using the following functions:
| Ends with text | `endsWith` | `?filter=endsWith(description,'End')` |
| Equals one value from set | `any` | `?filter=any(chapter,'Intro','Summary','Conclusion')` |
| Collection contains items | `has` | `?filter=has(articles)` |
| Type-check derived type (v5) | `isType` | `?filter=isType(,men)` |
| Negation | `not` | `?filter=not(equals(lastName,null))` |
| Conditional logical OR | `or` | `?filter=or(has(orders),has(invoices))` |
| Conditional logical AND | `and` | `?filter=and(has(orders),has(invoices))` |
Expand Down Expand Up @@ -86,6 +87,32 @@ GET /customers?filter=has(orders,not(equals(status,'Paid'))) HTTP/1.1

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

_since v5.0_

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.

Only return men:
```http
GET /humans?filter=isType(,men) HTTP/1.1
```

Only return men with beards:
```http
GET /humans?filter=isType(,men,equals(hasBeard,'true')) HTTP/1.1
```

The first parameter of `isType` can be used to perform the type check on a to-one relationship path.

Only return people whose best friend is a man with children:
```http
GET /humans?filter=isType(bestFriend,men,has(children)) HTTP/1.1
```

Only return people who have at least one female married child:
```http
GET /humans?filter=has(children,isType(,woman,not(equals(husband,null)))) HTTP/1.1
```

# Legacy filters

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).
Expand Down
Loading