Skip to content

Experiments to fix #1671 #1712

New issue

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

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

Already on GitHub? # to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions src/Examples/GettingStarted/Data/SampleDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ public class SampleDbContext(DbContextOptions<SampleDbContext> options)
: DbContext(options)
{
public DbSet<Book> Books => Set<Book>();
public DbSet<House> Houses => Set<House>();
public DbSet<TinyHouse> TinyHouses => Set<TinyHouse>();
public DbSet<BigHouse> BigHouses => Set<BigHouse>();
}
25 changes: 25 additions & 0 deletions src/Examples/GettingStarted/Definitions/PersonDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using GettingStarted.Models;
using JetBrains.Annotations;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Queries.Expressions;
using JsonApiDotNetCore.Queries.Parsing;
using JsonApiDotNetCore.Resources;

namespace GettingStarted.Definitions;

[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
internal sealed class PersonDefinition(IResourceGraph resourceGraph, IResourceFactory resourceFactory)
: JsonApiResourceDefinition<Person, int>(resourceGraph)
{
private readonly IResourceFactory _resourceFactory = resourceFactory;

public override FilterExpression OnApplyFilter(FilterExpression? existingFilter)
{
var parser = new FilterParser(_resourceFactory);
FilterExpression isNotDeleted = parser.Parse("equals(isDeleted,'false')", ResourceType);
FilterExpression hasBooksWithName = parser.Parse("has(books,equals(author.name,'Mary Shelley'))", ResourceType);
FilterExpression ownsBigHouseWithFloorCount = parser.Parse("isType(house,bigHouses,equals(floorCount,'3'))", ResourceType);

return LogicalExpression.Compose(LogicalOperator.And, isNotDeleted, hasBooksWithName, ownsBigHouseWithFloorCount, existingFilter)!;
}
}
19 changes: 19 additions & 0 deletions src/Examples/GettingStarted/Models/Person.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@
[Attr]
public string Name { get; set; } = null!;

[Attr]
public bool IsDeleted { get; set; }

[HasMany]
public ICollection<Book> Books { get; set; } = new List<Book>();

[HasOne]
public House? House { get; set; }
}

[Resource]
public abstract class House : Identifiable<int>;

Check warning on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check warning on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check warning on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check warning on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 25 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.House' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

[Resource]
public sealed class TinyHouse : House;

Check warning on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check warning on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check warning on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 28 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.TinyHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

[Resource]
public sealed class BigHouse : House

Check warning on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check warning on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check warning on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)

Check failure on line 31 in src/Examples/GettingStarted/Models/Person.cs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

File 'Person.cs' contains additional type 'GettingStarted.Models.BigHouse' (https://github.com/dennisdoomen/CSharpGuidelines/blob/5.7.0/_rules/1507.md)
{
[Attr]
public int? FloorCount { get; set; }
}
18 changes: 15 additions & 3 deletions src/Examples/GettingStarted/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Diagnostics;
using GettingStarted.Data;
using GettingStarted.Definitions;
using GettingStarted.Models;
using JsonApiDotNetCore.Configuration;
using Microsoft.EntityFrameworkCore;
Expand Down Expand Up @@ -28,6 +29,8 @@
#endif
});

builder.Services.AddResourceDefinition<PersonDefinition>();

WebApplication app = builder.Build();

// Configure the HTTP request pipeline.
Expand Down Expand Up @@ -69,23 +72,32 @@ static async Task CreateSampleDataAsync(SampleDbContext dbContext)
PublishYear = 1818,
Author = new Person
{
Name = "Mary Shelley"
Name = "Mary Shelley",
House = new BigHouse
{
FloorCount = 3
}
}
}, new Book
{
Title = "Robinson Crusoe",
PublishYear = 1719,
Author = new Person
{
Name = "Daniel Defoe"
Name = "Daniel Defoe",
House = new TinyHouse()
}
}, new Book
{
Title = "Gulliver's Travels",
PublishYear = 1726,
Author = new Person
{
Name = "Jonathan Swift"
Name = "Jonathan Swift",
House = new BigHouse
{
FloorCount = 4
}
}
});

Expand Down
4 changes: 2 additions & 2 deletions src/Examples/GettingStarted/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/people?include=books",
"launchUrl": "api/people/1/books",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Kestrel": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/people?include=books",
"launchUrl": "api/people/1/books",
"applicationUrl": "http://localhost:14141",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
60 changes: 60 additions & 0 deletions src/JsonApiDotNetCore/Queries/ChainInsertionFilterRewriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Collections.Immutable;
using JsonApiDotNetCore.Queries.Expressions;
using JsonApiDotNetCore.Resources.Annotations;

namespace JsonApiDotNetCore.Queries;

internal sealed class ChainInsertionFilterRewriter : QueryExpressionRewriter<object?>
{
private readonly ResourceFieldAttribute _fieldToInsert;
private bool _isInNestedScope;

public ChainInsertionFilterRewriter(ResourceFieldAttribute fieldToInsert)
{
ArgumentNullException.ThrowIfNull(fieldToInsert);

_fieldToInsert = fieldToInsert;
}

public override QueryExpression VisitResourceFieldChain(ResourceFieldChainExpression expression, object? argument)
{
if (_isInNestedScope)
{
return expression;
}

IImmutableList<ResourceFieldAttribute> newFields = expression.Fields.Insert(0, _fieldToInsert);
return new ResourceFieldChainExpression(newFields);
}

public override QueryExpression? VisitHas(HasExpression expression, object? argument)
{
if (Visit(expression.TargetCollection, argument) is ResourceFieldChainExpression newTargetCollection)
{
var backupIsInNestedScope = _isInNestedScope;
_isInNestedScope = true;
FilterExpression? newFilter = expression.Filter != null ? Visit(expression.Filter, argument) as FilterExpression : null;
_isInNestedScope = backupIsInNestedScope;

var newExpression = new HasExpression(newTargetCollection, newFilter);
return newExpression.Equals(expression) ? expression : newExpression;
}

return null;
}

public override QueryExpression VisitIsType(IsTypeExpression expression, object? argument)
{
ResourceFieldChainExpression? newTargetToOneRelationship = expression.TargetToOneRelationship != null
? Visit(expression.TargetToOneRelationship, argument) as ResourceFieldChainExpression
: null;

var backupIsInNestedScope = _isInNestedScope;
_isInNestedScope = true;
FilterExpression? newChild = expression.Child != null ? Visit(expression.Child, argument) as FilterExpression : null;
_isInNestedScope = backupIsInNestedScope;

var newExpression = new IsTypeExpression(newTargetToOneRelationship, expression.DerivedType, newChild);
return newExpression.Equals(expression) ? expression : newExpression;
}
}
48 changes: 38 additions & 10 deletions src/JsonApiDotNetCore/Queries/QueryLayerComposer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,36 +98,64 @@ public QueryLayerComposer(IEnumerable<IQueryConstraintProvider> constraintProvid
FilterExpression? primaryFilter = GetFilter(Array.Empty<QueryExpression>(), hasManyRelationship.LeftType);
FilterExpression? secondaryFilter = GetFilter(filtersInSecondaryScope, hasManyRelationship.RightType);

FilterExpression inverseFilter = GetInverseRelationshipFilter(primaryId, hasManyRelationship, inverseRelationship);
if (primaryFilter != null)
{
// This would hide total resource count on secondary to-one endpoint, but at least not crash anymore.
// return null;
}

FilterExpression inverseFilter = GetInverseRelationshipFilter(primaryId, hasManyRelationship, inverseRelationship, primaryFilter);

return LogicalExpression.Compose(LogicalOperator.And, inverseFilter, primaryFilter, secondaryFilter);
return LogicalExpression.Compose(LogicalOperator.And, inverseFilter, secondaryFilter);
}

private static FilterExpression GetInverseRelationshipFilter<TId>([DisallowNull] TId primaryId, HasManyAttribute relationship,
RelationshipAttribute inverseRelationship)
RelationshipAttribute inverseRelationship, FilterExpression? primaryFilter)
{
return inverseRelationship is HasManyAttribute hasManyInverseRelationship
? GetInverseHasManyRelationshipFilter(primaryId, relationship, hasManyInverseRelationship)
: GetInverseHasOneRelationshipFilter(primaryId, relationship, (HasOneAttribute)inverseRelationship);
? GetInverseHasManyRelationshipFilter(primaryId, relationship, hasManyInverseRelationship, primaryFilter)
: GetInverseHasOneRelationshipFilter(primaryId, relationship, (HasOneAttribute)inverseRelationship, primaryFilter);
}

private static ComparisonExpression GetInverseHasOneRelationshipFilter<TId>([DisallowNull] TId primaryId, HasManyAttribute relationship,
HasOneAttribute inverseRelationship)
private static FilterExpression GetInverseHasOneRelationshipFilter<TId>([DisallowNull] TId primaryId, HasManyAttribute relationship,
HasOneAttribute inverseRelationship, FilterExpression? primaryFilter)
{
AttrAttribute idAttribute = GetIdAttribute(relationship.LeftType);
var idChain = new ResourceFieldChainExpression(ImmutableArray.Create<ResourceFieldAttribute>(inverseRelationship, idAttribute));
var idComparison = new ComparisonExpression(ComparisonOperator.Equals, idChain, new LiteralConstantExpression(primaryId));

FilterExpression? newPrimaryFilter = null;

return new ComparisonExpression(ComparisonOperator.Equals, idChain, new LiteralConstantExpression(primaryId));
if (primaryFilter != null)
{
// many-to-one. This is the hard part. We can special-case for built-in has() and isType() usage, however third-party filters can't participate.
// Because there is no way of indicating in an expression "this chain belongs to something related"; the parsers only know that.
// For example, see the third-party SumExpression.Selector with SumFilterParser in test project.

// For example:
// input: and(equals(isDeleted,'false'), has(books ,equals(author.name,'Mary Shelley')),isType( house,bigHouses,equals(floorCount,'3')))
// output: and(equals(author.isDeleted,'false'),has(author.books,equals(author.name,'Mary Shelley')),isType(author.house,bigHouses,equals(floorCount,'3')))
// ^ ^ ^! ^ ^!
// Note how some chains are updated, while others (expressions on related types) are intentionally not.

var rewriter = new ChainInsertionFilterRewriter(inverseRelationship);
newPrimaryFilter = (FilterExpression?)rewriter.Visit(primaryFilter, null);
}

return LogicalExpression.Compose(LogicalOperator.And, idComparison, newPrimaryFilter)!;
}

private static HasExpression GetInverseHasManyRelationshipFilter<TId>([DisallowNull] TId primaryId, HasManyAttribute relationship,
HasManyAttribute inverseRelationship)
HasManyAttribute inverseRelationship, FilterExpression? primaryFilter)
{
// many-to-many. This one is easy, we can just push into the sub-condition of has().

AttrAttribute idAttribute = GetIdAttribute(relationship.LeftType);
var idChain = new ResourceFieldChainExpression(ImmutableArray.Create<ResourceFieldAttribute>(idAttribute));
var idComparison = new ComparisonExpression(ComparisonOperator.Equals, idChain, new LiteralConstantExpression(primaryId));

return new HasExpression(new ResourceFieldChainExpression(inverseRelationship), idComparison);
FilterExpression filter = LogicalExpression.Compose(LogicalOperator.And, idComparison, primaryFilter)!;
return new HasExpression(new ResourceFieldChainExpression(inverseRelationship), filter);
}

/// <inheritdoc />
Expand Down
Loading