Skip to content

Commit 8a5e914

Browse files
authored
Merge pull request #1257 from json-api-dotnet/query-tweaks
Query tweaks
2 parents 2732109 + 039ee72 commit 8a5e914

38 files changed

+266
-247
lines changed

Diff for: .config/dotnet-tools.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
]
2222
},
2323
"dotnet-reportgenerator-globaltool": {
24-
"version": "5.1.15",
24+
"version": "5.1.19",
2525
"commands": [
2626
"reportgenerator"
2727
]
2828
},
2929
"docfx": {
30-
"version": "2.60.2",
30+
"version": "2.62.2",
3131
"commands": [
3232
"docfx"
3333
]

Diff for: Directory.Build.props

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<AspNetVersion>6.0.*</AspNetVersion>
55
<EFCoreVersion>7.0.*</EFCoreVersion>
66
<EFCorePostgresVersion>7.0.*</EFCorePostgresVersion>
7-
<MicrosoftCodeAnalysisVersion>4.4.*</MicrosoftCodeAnalysisVersion>
7+
<MicrosoftCodeAnalysisVersion>4.5.*</MicrosoftCodeAnalysisVersion>
88
<HumanizerVersion>2.14.1</HumanizerVersion>
99
<JsonApiDotNetCoreVersionPrefix>5.1.3</JsonApiDotNetCoreVersionPrefix>
1010
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodingGuidelines.ruleset</CodeAnalysisRuleSet>
@@ -17,7 +17,7 @@
1717

1818
<ItemGroup>
1919
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
20-
<PackageReference Include="CSharpGuidelinesAnalyzer" Version="3.8.2" PrivateAssets="All" />
20+
<PackageReference Include="CSharpGuidelinesAnalyzer" Version="3.8.3" PrivateAssets="All" />
2121
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CSharpGuidelinesAnalyzer.config" Visible="False" />
2222
</ItemGroup>
2323

Diff for: appveyor.yml

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
image:
22
- Ubuntu2004
3-
- Visual Studio 2022
3+
# Downgrade to workaround error NETSDK1194 during 'dotnet pack': The "--output" option isn't supported when building a solution.
4+
# https://stackoverflow.com/questions/75453953/how-to-fix-github-actions-dotnet-publish-workflow-error-the-output-option-i
5+
- Previous Visual Studio 2022
46

57
version: '{build}'
68

@@ -32,7 +34,7 @@ for:
3234
-
3335
matrix:
3436
only:
35-
- image: Visual Studio 2022
37+
- image: Previous Visual Studio 2022
3638
services:
3739
- postgresql15
3840
install:

Diff for: docs/usage/options.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ options.AllowClientGeneratedIds = true;
2222

2323
## Pagination
2424

25-
The default page size used for all resources can be overridden in options (10 by default). To disable paging, set it to `null`.
25+
The default page size used for all resources can be overridden in options (10 by default). To disable pagination, set it to `null`.
2626
The maximum page size and number allowed from client requests can be set too (unconstrained by default).
2727

2828
You can also include the total number of resources in each response.
@@ -38,7 +38,7 @@ options.IncludeTotalResourceCount = true;
3838
```
3939

4040
To retrieve the total number of resources on secondary and relationship endpoints, the reverse of the relationship must to be available. For example, in `GET /customers/1/orders`, both the relationships `[HasMany] Customer.Orders` and `[HasOne] Order.Customer` must be defined.
41-
If `IncludeTotalResourceCount` is set to `false` (or the inverse relationship is unavailable on a non-primary endpoint), best-effort paging links are returned instead. This means no `last` link and the `next` link only occurs when the current page is full.
41+
If `IncludeTotalResourceCount` is set to `false` (or the inverse relationship is unavailable on a non-primary endpoint), best-effort pagination links are returned instead. This means no `last` link and the `next` link only occurs when the current page is full.
4242

4343
## Relative Links
4444

Diff for: src/JsonApiDotNetCore.Annotations/Resources/Annotations/LinkTypes.shared.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ public enum LinkTypes
55
{
66
Self = 1 << 0,
77
Related = 1 << 1,
8-
Paging = 1 << 2,
8+
Pagination = 1 << 2,
99
NotConfigured = 1 << 3,
1010
None = 1 << 4,
11-
All = Self | Related | Paging
11+
All = Self | Related | Pagination
1212
}

Diff for: src/JsonApiDotNetCore/Configuration/IJsonApiOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public interface IJsonApiOptions
9999
bool IncludeTotalResourceCount { get; }
100100

101101
/// <summary>
102-
/// The page size (10 by default) that is used when not specified in query string. Set to <c>null</c> to not use paging by default.
102+
/// The page size (10 by default) that is used when not specified in query string. Set to <c>null</c> to not use pagination by default.
103103
/// </summary>
104104
PageSize? DefaultPageSize { get; }
105105

Diff for: src/JsonApiDotNetCore/Configuration/ResourceDescriptorAssemblyCache.cs

+1-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ internal sealed class ResourceDescriptorAssemblyCache
1212

1313
public void RegisterAssembly(Assembly assembly)
1414
{
15-
if (!_resourceDescriptorsPerAssembly.ContainsKey(assembly))
16-
{
17-
_resourceDescriptorsPerAssembly[assembly] = null;
18-
}
15+
_resourceDescriptorsPerAssembly.TryAdd(assembly, null);
1916
}
2017

2118
public IReadOnlyCollection<ResourceDescriptor> GetResourceDescriptors()

Diff for: src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ public virtual async Task<IActionResult> PostAsync([FromBody] TResource resource
207207
TResource? newResource = await _create.CreateAsync(resource, cancellationToken);
208208

209209
string resourceId = (newResource ?? resource).StringId!;
210-
string locationUrl = $"{HttpContext.Request.Path}/{resourceId}";
210+
string locationUrl = HttpContext.Request.Path.Add($"/{resourceId}");
211211

212212
if (newResource == null)
213213
{

Diff for: src/JsonApiDotNetCore/Errors/CannotClearRequiredRelationshipException.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ namespace JsonApiDotNetCore.Errors;
1010
[PublicAPI]
1111
public sealed class CannotClearRequiredRelationshipException : JsonApiException
1212
{
13-
public CannotClearRequiredRelationshipException(string relationshipName, string resourceId, string resourceType)
13+
public CannotClearRequiredRelationshipException(string relationshipName, string resourceType)
1414
: base(new ErrorObject(HttpStatusCode.BadRequest)
1515
{
1616
Title = "Failed to clear a required relationship.",
17-
Detail = $"The relationship '{relationshipName}' on resource type '{resourceType}' " +
18-
$"with ID '{resourceId}' cannot be cleared because it is a required relationship."
17+
Detail = $"The relationship '{relationshipName}' on resource type '{resourceType}' cannot be cleared because it is a required relationship."
1918
})
2019
{
2120
}

Diff for: src/JsonApiDotNetCore/Middleware/JsonApiRoutingConvention.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ public void Apply(ApplicationModel application)
101101
$"resource type '{resourceClrType}', which does not exist in the resource graph.");
102102
}
103103

104-
if (_controllerPerResourceTypeMap.ContainsKey(resourceType))
104+
if (_controllerPerResourceTypeMap.TryGetValue(resourceType, out ControllerModel? existingModel))
105105
{
106106
throw new InvalidConfigurationException(
107-
$"Multiple controllers found for resource type '{resourceType}': '{_controllerPerResourceTypeMap[resourceType].ControllerType}' and '{controller.ControllerType}'.");
107+
$"Multiple controllers found for resource type '{resourceType}': '{existingModel.ControllerType}' and '{controller.ControllerType}'.");
108108
}
109109

110110
_resourceTypePerControllerTypeMap.Add(controller.ControllerType, resourceType);
@@ -119,10 +119,10 @@ public void Apply(ApplicationModel application)
119119

120120
string template = TemplateFromResource(controller) ?? TemplateFromController(controller);
121121

122-
if (_registeredControllerNameByTemplate.ContainsKey(template))
122+
if (_registeredControllerNameByTemplate.TryGetValue(template, out string? controllerName))
123123
{
124124
throw new InvalidConfigurationException(
125-
$"Cannot register '{controller.ControllerType.FullName}' for template '{template}' because '{_registeredControllerNameByTemplate[template]}' was already registered for this template.");
125+
$"Cannot register '{controller.ControllerType.FullName}' for template '{template}' because '{controllerName}' was already registered for this template.");
126126
}
127127

128128
_registeredControllerNameByTemplate.Add(template, controller.ControllerType.FullName!);

Diff for: src/JsonApiDotNetCore/Queries/Expressions/LiteralConstantExpression.cs

+17-8
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@ namespace JsonApiDotNetCore.Queries.Expressions;
88
[PublicAPI]
99
public class LiteralConstantExpression : IdentifierExpression
1010
{
11-
public string Value { get; }
11+
private readonly string _stringValue;
1212

13-
public LiteralConstantExpression(string text)
13+
public object TypedValue { get; }
14+
15+
public LiteralConstantExpression(object typedValue)
16+
: this(typedValue, typedValue.ToString()!)
17+
{
18+
}
19+
20+
public LiteralConstantExpression(object typedValue, string stringValue)
1421
{
15-
ArgumentGuard.NotNull(text);
22+
ArgumentGuard.NotNull(typedValue);
23+
ArgumentGuard.NotNull(stringValue);
1624

17-
Value = text;
25+
TypedValue = typedValue;
26+
_stringValue = stringValue;
1827
}
1928

2029
public override TResult Accept<TArgument, TResult>(QueryExpressionVisitor<TArgument, TResult> visitor, TArgument argument)
@@ -24,8 +33,8 @@ public override TResult Accept<TArgument, TResult>(QueryExpressionVisitor<TArgum
2433

2534
public override string ToString()
2635
{
27-
string value = Value.Replace("\'", "\'\'");
28-
return $"'{value}'";
36+
string escapedValue = _stringValue.Replace("\'", "\'\'");
37+
return $"'{escapedValue}'";
2938
}
3039

3140
public override string ToFullString()
@@ -47,11 +56,11 @@ public override bool Equals(object? obj)
4756

4857
var other = (LiteralConstantExpression)obj;
4958

50-
return Value == other.Value;
59+
return Equals(TypedValue, other.TypedValue) && _stringValue == other._stringValue;
5160
}
5261

5362
public override int GetHashCode()
5463
{
55-
return Value.GetHashCode();
64+
return HashCode.Combine(TypedValue, _stringValue);
5665
}
5766
}

Diff for: src/JsonApiDotNetCore/Queries/IPaginationContext.cs

+7-6
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@
33
namespace JsonApiDotNetCore.Queries;
44

55
/// <summary>
6-
/// Tracks values used for pagination, which is a combined effort from options, query string parsing and fetching the total number of rows.
6+
/// Tracks values used for top-level pagination, which is a combined effort from options, query string parsing, resource definition callbacks and
7+
/// fetching the total number of rows.
78
/// </summary>
89
public interface IPaginationContext
910
{
1011
/// <summary>
11-
/// The value 1, unless specified from query string. Never null. Cannot be higher than options.MaximumPageNumber.
12+
/// The value 1, unless overridden from query string or resource definition. Should not be higher than <see cref="IJsonApiOptions.MaximumPageNumber" />.
1213
/// </summary>
1314
PageNumber PageNumber { get; set; }
1415

1516
/// <summary>
16-
/// The default page size from options, unless specified in query string. Can be <c>null</c>, which means no paging. Cannot be higher than
17-
/// options.MaximumPageSize.
17+
/// The default page size from options, unless overridden from query string or resource definition. Should not be higher than
18+
/// <see cref="IJsonApiOptions.MaximumPageSize" />. Can be <c>null</c>, which means pagination is disabled.
1819
/// </summary>
1920
PageSize? PageSize { get; set; }
2021

@@ -25,12 +26,12 @@ public interface IPaginationContext
2526
bool IsPageFull { get; set; }
2627

2728
/// <summary>
28-
/// The total number of resources. <c>null</c> when <see cref="IJsonApiOptions.IncludeTotalResourceCount" /> is set to <c>false</c>.
29+
/// The total number of resources, or <c>null</c> when <see cref="IJsonApiOptions.IncludeTotalResourceCount" /> is set to <c>false</c>.
2930
/// </summary>
3031
int? TotalResourceCount { get; set; }
3132

3233
/// <summary>
33-
/// The total number of resource pages. <c>null</c> when <see cref="IJsonApiOptions.IncludeTotalResourceCount" /> is set to <c>false</c> or
34+
/// The total number of resource pages, or <c>null</c> when <see cref="IJsonApiOptions.IncludeTotalResourceCount" /> is set to <c>false</c> or
3435
/// <see cref="PageSize" /> is <c>null</c>.
3536
/// </summary>
3637
int? TotalPageCount { get; }

0 commit comments

Comments
 (0)