Skip to content

Commit 86cee8b

Browse files
authored
Remove redundant selectors in QueryLayer, only sort by ID when pagination enabled (#1735)
1 parent c00f552 commit 86cee8b

File tree

9 files changed

+62
-39
lines changed

9 files changed

+62
-39
lines changed

src/JsonApiDotNetCore/Queries/QueryLayer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace JsonApiDotNetCore.Queries;
1111
[PublicAPI]
1212
public sealed class QueryLayer
1313
{
14+
internal bool IsEmpty => Filter == null && Sort == null && Pagination?.PageSize == null && (Selection == null || Selection.IsEmpty);
15+
1416
public ResourceType ResourceType { get; }
1517

1618
public IncludeExpression? Include { get; set; }

src/JsonApiDotNetCore/Queries/QueryLayerComposer.cs

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,20 @@ private QueryLayer ComposeTopLayer(ImmutableArray<ExpressionInScope> constraints
173173
_paginationContext.PageSize = topPagination.PageSize;
174174
_paginationContext.PageNumber = topPagination.PageNumber;
175175

176-
return new QueryLayer(resourceType)
176+
var topLayer = new QueryLayer(resourceType)
177177
{
178178
Filter = GetFilter(expressionsInTopScope, resourceType),
179179
Sort = GetSort(expressionsInTopScope, resourceType),
180180
Pagination = topPagination,
181181
Selection = GetSelectionForSparseAttributeSet(resourceType)
182182
};
183+
184+
if (topLayer is { Pagination.PageSize: not null, Sort: null })
185+
{
186+
topLayer.Sort = CreateSortById(resourceType);
187+
}
188+
189+
return topLayer;
183190
}
184191

185192
private IncludeExpression ComposeChildren(QueryLayer topLayer, ImmutableArray<ExpressionInScope> constraints)
@@ -237,17 +244,22 @@ private IImmutableSet<IncludeElementExpression> ProcessIncludeSet(IImmutableSet<
237244
ResourceType resourceType = includeElement.Relationship.RightType;
238245
bool isToManyRelationship = includeElement.Relationship is HasManyAttribute;
239246

240-
var child = new QueryLayer(resourceType)
247+
var subLayer = new QueryLayer(resourceType)
241248
{
242249
Filter = isToManyRelationship ? GetFilter(expressionsInCurrentScope, resourceType) : null,
243250
Sort = isToManyRelationship ? GetSort(expressionsInCurrentScope, resourceType) : null,
244251
Pagination = isToManyRelationship ? GetPagination(expressionsInCurrentScope, resourceType) : null,
245252
Selection = GetSelectionForSparseAttributeSet(resourceType)
246253
};
247254

248-
selectors.IncludeRelationship(includeElement.Relationship, child);
255+
if (subLayer is { Pagination.PageSize: not null, Sort: null })
256+
{
257+
subLayer.Sort = CreateSortById(resourceType);
258+
}
249259

250-
IImmutableSet<IncludeElementExpression> updatedChildren = ProcessIncludeSet(includeElement.Children, child, relationshipChain, constraints);
260+
selectors.IncludeRelationship(includeElement.Relationship, subLayer);
261+
262+
IImmutableSet<IncludeElementExpression> updatedChildren = ProcessIncludeSet(includeElement.Children, subLayer, relationshipChain, constraints);
251263

252264
if (!ReferenceEquals(includeElement.Children, updatedChildren))
253265
{
@@ -256,9 +268,30 @@ private IImmutableSet<IncludeElementExpression> ProcessIncludeSet(IImmutableSet<
256268
}
257269
}
258270

271+
EliminateRedundantSelectors(parentLayer);
272+
259273
return updatesInChildren.Count == 0 ? includeElementsEvaluated : ApplyIncludeElementUpdates(includeElementsEvaluated, updatesInChildren);
260274
}
261275

276+
private static void EliminateRedundantSelectors(QueryLayer parentLayer)
277+
{
278+
if (parentLayer.Selection != null)
279+
{
280+
foreach ((ResourceType resourceType, FieldSelectors selectors) in parentLayer.Selection.ToArray())
281+
{
282+
if (selectors.ContainsOnlyRelationships && selectors.Values.OfType<QueryLayer>().All(subLayer => subLayer.IsEmpty))
283+
{
284+
parentLayer.Selection.Remove(resourceType);
285+
}
286+
}
287+
288+
if (parentLayer.Selection.IsEmpty)
289+
{
290+
parentLayer.Selection = null;
291+
}
292+
}
293+
}
294+
262295
private static ImmutableHashSet<IncludeElementExpression> ApplyIncludeElementUpdates(IImmutableSet<IncludeElementExpression> includeElements,
263296
Dictionary<IncludeElementExpression, IImmutableSet<IncludeElementExpression>> updatesInChildren)
264297
{
@@ -507,23 +540,21 @@ protected virtual IImmutableSet<IncludeElementExpression> GetIncludeElements(IIm
507540
return _resourceDefinitionAccessor.OnApplyFilter(resourceType, filter);
508541
}
509542

510-
protected virtual SortExpression GetSort(IReadOnlyCollection<QueryExpression> expressionsInScope, ResourceType resourceType)
543+
protected virtual SortExpression? GetSort(IReadOnlyCollection<QueryExpression> expressionsInScope, ResourceType resourceType)
511544
{
512545
ArgumentNullException.ThrowIfNull(expressionsInScope);
513546
ArgumentNullException.ThrowIfNull(resourceType);
514547

515548
SortExpression? sort = expressionsInScope.OfType<SortExpression>().FirstOrDefault();
516549

517-
sort = _resourceDefinitionAccessor.OnApplySort(resourceType, sort);
518-
519-
if (sort == null)
520-
{
521-
AttrAttribute idAttribute = GetIdAttribute(resourceType);
522-
var idAscendingSort = new SortElementExpression(new ResourceFieldChainExpression(idAttribute), true);
523-
sort = new SortExpression(ImmutableArray.Create(idAscendingSort));
524-
}
550+
return _resourceDefinitionAccessor.OnApplySort(resourceType, sort);
551+
}
525552

526-
return sort;
553+
private SortExpression CreateSortById(ResourceType resourceType)
554+
{
555+
AttrAttribute idAttribute = GetIdAttribute(resourceType);
556+
var idAscendingSort = new SortElementExpression(new ResourceFieldChainExpression(idAttribute), true);
557+
return new SortExpression(ImmutableArray.Create(idAscendingSort));
527558
}
528559

529560
protected virtual PaginationExpression GetPagination(IReadOnlyCollection<QueryExpression> expressionsInScope, ResourceType resourceType)

test/DapperTests/IntegrationTests/QueryStrings/FilterTests.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ SELECT COUNT(*)
7878
FROM "Tags" AS t1
7979
LEFT JOIN "RgbColors" AS t2 ON t1."Id" = t2."TagId"
8080
WHERE t2."Id" = @p1
81-
ORDER BY t1."Id"
8281
"""));
8382

8483
command.Parameters.Should().HaveCount(1);
@@ -144,7 +143,6 @@ SELECT COUNT(*)
144143
FROM "Tags" AS t1
145144
LEFT JOIN "RgbColors" AS t2 ON t1."Id" = t2."TagId"
146145
WHERE t2."Id" IN (@p1, @p2)
147-
ORDER BY t1."Id"
148146
"""));
149147

150148
command.Parameters.Should().HaveCount(2);
@@ -662,7 +660,6 @@ SELECT COUNT(*)
662660
SELECT t1."Id", t1."FirstName", t1."LastName"
663661
FROM "People" AS t1
664662
WHERE (NOT (t1."FirstName" = @p1)) OR (t1."FirstName" IS NULL)
665-
ORDER BY t1."Id"
666663
"""));
667664

668665
command.Parameters.Should().HaveCount(1);
@@ -867,7 +864,6 @@ SELECT COUNT(*)
867864
SELECT t1."Id", t1."Name"
868865
FROM "Tags" AS t1
869866
WHERE (t1."Name" LIKE '%A\%%' ESCAPE '\') OR (t1."Name" LIKE '%A\_%' ESCAPE '\') OR (t1."Name" LIKE '%A\\%' ESCAPE '\') OR (t1."Name" LIKE '%A''%') OR (t1."Name" LIKE '%\%\_\\''%' ESCAPE '\')
870-
ORDER BY t1."Id"
871867
"""));
872868

873869
command.Parameters.Should().BeEmpty();
@@ -1177,7 +1173,6 @@ SELECT 1
11771173
LEFT JOIN "People" AS t3 ON t2."AssigneeId" = t3."Id"
11781174
WHERE (t1."Id" = t2."OwnerId") AND (NOT (t3."Id" IS NULL)) AND (t3."FirstName" IS NULL)
11791175
)
1180-
ORDER BY t1."Id"
11811176
"""));
11821177

11831178
command.Parameters.Should().BeEmpty();

test/DapperTests/IntegrationTests/QueryStrings/IncludeTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ SELECT COUNT(*)
165165
INNER JOIN "People" AS t3 ON t1."OwnerId" = t3."Id"
166166
LEFT JOIN "TodoItems" AS t4 ON t3."Id" = t4."AssigneeId"
167167
LEFT JOIN "Tags" AS t5 ON t1."Id" = t5."TodoItemId"
168-
ORDER BY t1."Priority", t1."LastModifiedAt" DESC, t4."Priority", t4."LastModifiedAt" DESC, t5."Id"
168+
ORDER BY t1."Priority", t1."LastModifiedAt" DESC, t4."Priority", t4."LastModifiedAt" DESC
169169
"""));
170170

171171
command.Parameters.Should().BeEmpty();
@@ -231,7 +231,7 @@ SELECT COUNT(*)
231231
FROM "TodoItems" AS t1
232232
LEFT JOIN "Tags" AS t2 ON t1."Id" = t2."TodoItemId"
233233
LEFT JOIN "RgbColors" AS t3 ON t2."Id" = t3."TagId"
234-
ORDER BY t1."Priority", t1."LastModifiedAt" DESC, t2."Id"
234+
ORDER BY t1."Priority", t1."LastModifiedAt" DESC
235235
"""));
236236

237237
command.Parameters.Should().BeEmpty();

test/DapperTests/IntegrationTests/QueryStrings/SortTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ ORDER BY (
349349
SELECT COUNT(*)
350350
FROM "Tags" AS t3
351351
WHERE t2."Id" = t3."TodoItemId"
352-
) DESC, t2."Id", t4."Id"
352+
) DESC, t2."Id"
353353
"""));
354354

355355
command.Parameters.Should().HaveCount(1);
@@ -415,7 +415,7 @@ SELECT COUNT(*)
415415
SELECT t1."Id", t1."FirstName", t1."LastName", t2."Id", t2."CreatedAt", t2."Description", t2."DurationInHours", t2."LastModifiedAt", t2."Priority"
416416
FROM "People" AS t1
417417
LEFT JOIN "TodoItems" AS t2 ON t1."Id" = t2."OwnerId"
418-
ORDER BY t1."Id", (
418+
ORDER BY (
419419
SELECT COUNT(*)
420420
FROM "Tags" AS t3
421421
WHERE t2."Id" = t3."TodoItemId"

test/DapperTests/IntegrationTests/QueryStrings/SparseFieldSets.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ SELECT COUNT(*)
215215
FROM "TodoItems" AS t1
216216
LEFT JOIN "Tags" AS t2 ON t1."Id" = t2."TodoItemId"
217217
WHERE t1."Id" = @p1
218-
ORDER BY t2."Id"
219218
"""));
220219

221220
command.Parameters.Should().HaveCount(1);
@@ -400,7 +399,6 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
400399
FROM "TodoItems" AS t1
401400
LEFT JOIN "Tags" AS t2 ON t1."Id" = t2."TodoItemId"
402401
WHERE t1."Id" = @p1
403-
ORDER BY t2."Id"
404402
"""));
405403

406404
command.Parameters.Should().HaveCount(1);

test/DapperTests/IntegrationTests/ReadWrite/Relationships/FetchRelationshipTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ SELECT COUNT(*)
168168
FROM "TodoItems" AS t1
169169
LEFT JOIN "Tags" AS t2 ON t1."Id" = t2."TodoItemId"
170170
WHERE t1."Id" = @p1
171-
ORDER BY t2."Id"
172171
"""));
173172

174173
command.Parameters.Should().HaveCount(1);

test/DapperTests/IntegrationTests/ReadWrite/Resources/FetchResourceTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ SELECT COUNT(*)
246246
FROM "TodoItems" AS t1
247247
LEFT JOIN "Tags" AS t2 ON t1."Id" = t2."TodoItemId"
248248
WHERE t1."Id" = @p1
249-
ORDER BY t2."Id"
250249
"""));
251250

252251
command.Parameters.Should().HaveCount(1);

test/DapperTests/IntegrationTests/Sql/SubQueryInJoinTests.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ SELECT COUNT(*)
6262
SELECT t1."Id", t1."FirstName", t1."LastName", t2."Id", t2."LastUsedAt", t2."UserName"
6363
FROM "People" AS t1
6464
LEFT JOIN "LoginAccounts" AS t2 ON t1."AccountId" = t2."Id"
65-
ORDER BY t1."Id"
6665
"""));
6766

6867
command.Parameters.Should().BeEmpty();
@@ -111,7 +110,7 @@ SELECT COUNT(*)
111110
SELECT t1."Id", t1."FirstName", t1."LastName", t2."Id", t2."CreatedAt", t2."Description", t2."DurationInHours", t2."LastModifiedAt", t2."Priority"
112111
FROM "People" AS t1
113112
LEFT JOIN "TodoItems" AS t2 ON t1."Id" = t2."OwnerId"
114-
ORDER BY t1."Id", t2."Priority", t2."LastModifiedAt" DESC
113+
ORDER BY t2."Priority", t2."LastModifiedAt" DESC
115114
"""));
116115

117116
command.Parameters.Should().BeEmpty();
@@ -160,7 +159,7 @@ SELECT COUNT(*)
160159
SELECT t1."Id", t1."FirstName", t1."LastName", t2."Id", t2."CreatedAt", t2."Description", t2."DurationInHours", t2."LastModifiedAt", t2."Priority"
161160
FROM "People" AS t1
162161
LEFT JOIN "TodoItems" AS t2 ON t1."Id" = t2."OwnerId"
163-
ORDER BY t1."Id", t2."Description"
162+
ORDER BY t2."Description"
164163
"""));
165164

166165
command.Parameters.Should().BeEmpty();
@@ -209,7 +208,7 @@ SELECT COUNT(*)
209208
SELECT t1."Id", t1."FirstName", t1."LastName", t2."Id", t2."CreatedAt", t2."Description", t2."DurationInHours", t2."LastModifiedAt", t2."Priority"
210209
FROM "People" AS t1
211210
LEFT JOIN "TodoItems" AS t2 ON t1."Id" = t2."OwnerId"
212-
ORDER BY t1."Id", (
211+
ORDER BY (
213212
SELECT COUNT(*)
214213
FROM "Tags" AS t3
215214
WHERE t2."Id" = t3."TodoItemId"
@@ -263,7 +262,7 @@ SELECT COUNT(*)
263262
FROM "People" AS t1
264263
LEFT JOIN "TodoItems" AS t2 ON t1."Id" = t2."OwnerId"
265264
LEFT JOIN "Tags" AS t4 ON t2."Id" = t4."TodoItemId"
266-
ORDER BY t1."Id", (
265+
ORDER BY (
267266
SELECT COUNT(*)
268267
FROM "Tags" AS t3
269268
WHERE t2."Id" = t3."TodoItemId"
@@ -326,11 +325,11 @@ SELECT COUNT(*)
326325
SELECT COUNT(*)
327326
FROM "Tags" AS t4
328327
WHERE t3."Id" = t4."TodoItemId"
329-
), t5."Id", (
328+
), (
330329
SELECT COUNT(*)
331330
FROM "Tags" AS t7
332331
WHERE t6."Id" = t7."TodoItemId"
333-
), t8."Id"
332+
)
334333
"""));
335334

336335
command.Parameters.Should().BeEmpty();
@@ -383,7 +382,7 @@ LEFT JOIN (
383382
FROM "TodoItems" AS t2
384383
WHERE t2."Description" = @p1
385384
) AS t3 ON t1."Id" = t3."OwnerId"
386-
ORDER BY t1."Id", t3."Priority", t3."LastModifiedAt" DESC
385+
ORDER BY t3."Priority", t3."LastModifiedAt" DESC
387386
"""));
388387

389388
command.Parameters.Should().HaveCount(1);
@@ -441,7 +440,7 @@ SELECT 1
441440
WHERE t2."Id" = t3."TodoItemId"
442441
)
443442
) AS t4 ON t1."Id" = t4."OwnerId"
444-
ORDER BY t1."Id", t4."Priority", t4."LastModifiedAt" DESC
443+
ORDER BY t4."Priority", t4."LastModifiedAt" DESC
445444
"""));
446445

447446
command.Parameters.Should().BeEmpty();
@@ -498,7 +497,7 @@ SELECT COUNT(*)
498497
WHERE t2."Id" = t3."TodoItemId"
499498
) > @p1
500499
) AS t4 ON t1."Id" = t4."OwnerId"
501-
ORDER BY t1."Id", t4."Priority", t4."LastModifiedAt" DESC
500+
ORDER BY t4."Priority", t4."LastModifiedAt" DESC
502501
"""));
503502

504503
command.Parameters.Should().HaveCount(1);
@@ -554,7 +553,7 @@ LEFT JOIN (
554553
LEFT JOIN "Tags" AS t4 ON t2."Id" = t4."TodoItemId"
555554
WHERE t2."Description" = @p1
556555
) AS t5 ON t1."Id" = t5."OwnerId"
557-
ORDER BY t1."Id", (
556+
ORDER BY (
558557
SELECT COUNT(*)
559558
FROM "Tags" AS t3
560559
WHERE t5."Id" = t3."TodoItemId"
@@ -620,7 +619,7 @@ WHERE NOT (t5."Name" = @p2)
620619
) AS t6 ON t2."Id" = t6."TodoItemId"
621620
WHERE NOT (t2."Description" = @p1)
622621
) AS t7 ON t1."Id" = t7."OwnerId"
623-
ORDER BY t1."Id", (
622+
ORDER BY (
624623
SELECT COUNT(*)
625624
FROM "Tags" AS t3
626625
WHERE t7."Id" = t3."TodoItemId"

0 commit comments

Comments
 (0)