Skip to content

Add [DisallowNull] on TId in pipeline parameters #1583

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

Merged
merged 1 commit into from
Jun 30, 2024
Merged
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
7 changes: 4 additions & 3 deletions src/Examples/DapperExample/Repositories/DapperRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using Dapper;
using DapperExample.AtomicOperations;
using DapperExample.TranslationToSql;
@@ -177,7 +178,7 @@ public async Task<int> CountAsync(FilterExpression? filter, CancellationToken ca
}

/// <inheritdoc />
public Task<TResource> GetForCreateAsync(Type resourceClrType, TId id, CancellationToken cancellationToken)
public Task<TResource> GetForCreateAsync(Type resourceClrType, [DisallowNull] TId id, CancellationToken cancellationToken)
{
ArgumentGuard.NotNull(resourceClrType);

@@ -355,7 +356,7 @@ await ExecuteInTransactionAsync(async transaction =>
}

/// <inheritdoc />
public async Task DeleteAsync(TResource? resourceFromDatabase, TId id, CancellationToken cancellationToken)
public async Task DeleteAsync(TResource? resourceFromDatabase, [DisallowNull] TId id, CancellationToken cancellationToken)
{
TResource placeholderResource = resourceFromDatabase ?? _resourceFactory.CreateInstance<TResource>();
placeholderResource.Id = id;
@@ -451,7 +452,7 @@ await ExecuteInTransactionAsync(async transaction =>
}

/// <inheritdoc />
public async Task AddToToManyRelationshipAsync(TResource? leftResource, TId leftId, ISet<IIdentifiable> rightResourceIds,
public async Task AddToToManyRelationshipAsync(TResource? leftResource, [DisallowNull] TId leftId, ISet<IIdentifiable> rightResourceIds,
CancellationToken cancellationToken)
{
ArgumentGuard.NotNull(rightResourceIds);
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Errors;
using JsonApiDotNetCore.Queries;
@@ -114,7 +115,7 @@ private bool SetPrimaryTotalCountIsZero()
}

/// <inheritdoc />
public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)
public Task<TResource> GetAsync([DisallowNull] TId id, CancellationToken cancellationToken)
{
QueryLayer queryLayer = _queryLayerComposer.ComposeForGetById(id, _resourceType, TopFieldSelection.PreserveExisting);

@@ -124,14 +125,14 @@ public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)

if (resource == null)
{
throw new ResourceNotFoundException(id!.ToString()!, _resourceType.PublicName);
throw new ResourceNotFoundException(id.ToString()!, _resourceType.PublicName);
}

return Task.FromResult(resource);
}

/// <inheritdoc />
public Task<object?> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken)
public Task<object?> GetSecondaryAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
{
RelationshipAttribute? relationship = _resourceType.FindRelationshipByPublicName(relationshipName);

@@ -151,7 +152,7 @@ public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)

if (primaryResource == null)
{
throw new ResourceNotFoundException(id!.ToString()!, _resourceType.PublicName);
throw new ResourceNotFoundException(id.ToString()!, _resourceType.PublicName);
}

object? rightValue = relationship.GetValue(primaryResource);
@@ -164,7 +165,7 @@ public Task<TResource> GetAsync(TId id, CancellationToken cancellationToken)
return Task.FromResult(rightValue);
}

private void SetNonPrimaryTotalCount(TId id, RelationshipAttribute relationship)
private void SetNonPrimaryTotalCount([DisallowNull] TId id, RelationshipAttribute relationship)
{
if (_options.IncludeTotalResourceCount && relationship is HasManyAttribute hasManyRelationship)
{
@@ -188,7 +189,7 @@ private void SetNonPrimaryTotalCount(TId id, RelationshipAttribute relationship)
}

/// <inheritdoc />
public Task<object?> GetRelationshipAsync(TId id, string relationshipName, CancellationToken cancellationToken)
public Task<object?> GetRelationshipAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
{
return GetSecondaryAsync(id, relationshipName, cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ public AddToRelationshipProcessor(IAddToRelationshipService<TResource, TId> serv
var leftId = (TId)operation.Resource.GetTypedId();
ISet<IIdentifiable> rightResourceIds = operation.GetSecondaryResources();

await _service.AddToToManyRelationshipAsync(leftId, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);
await _service.AddToToManyRelationshipAsync(leftId!, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);

return null;
}
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ public DeleteProcessor(IDeleteService<TResource, TId> service)
ArgumentGuard.NotNull(operation);

var id = (TId)operation.Resource.GetTypedId();
await _service.DeleteAsync(id, cancellationToken);
await _service.DeleteAsync(id!, cancellationToken);

return null;
}
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ public RemoveFromRelationshipProcessor(IRemoveFromRelationshipService<TResource,
var leftId = (TId)operation.Resource.GetTypedId();
ISet<IIdentifiable> rightResourceIds = operation.GetSecondaryResources();

await _service.RemoveFromToManyRelationshipAsync(leftId, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);
await _service.RemoveFromToManyRelationshipAsync(leftId!, operation.Request.Relationship!.PublicName, rightResourceIds, cancellationToken);

return null;
}
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ public SetRelationshipProcessor(ISetRelationshipService<TResource, TId> service)
var leftId = (TId)operation.Resource.GetTypedId();
object? rightValue = GetRelationshipRightValue(operation);

await _service.SetRelationshipAsync(leftId, operation.Request.Relationship!.PublicName, rightValue, cancellationToken);
await _service.SetRelationshipAsync(leftId!, operation.Request.Relationship!.PublicName, rightValue, cancellationToken);

return null;
}
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ public UpdateProcessor(IUpdateService<TResource, TId> service)
ArgumentGuard.NotNull(operation);

var resource = (TResource)operation.Resource;
TResource? updated = await _service.UpdateAsync(resource.Id, resource, cancellationToken);
TResource? updated = await _service.UpdateAsync(resource.Id!, resource, cancellationToken);

return updated == null ? null : operation.WithResource(updated);
}
21 changes: 11 additions & 10 deletions src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Errors;
using JsonApiDotNetCore.Middleware;
@@ -108,7 +109,7 @@ public virtual async Task<IActionResult> GetAsync(CancellationToken cancellation
/// GET /articles/1 HTTP/1.1
/// ]]></code>
/// </summary>
public virtual async Task<IActionResult> GetAsync(TId id, CancellationToken cancellationToken)
public virtual async Task<IActionResult> GetAsync([DisallowNull] TId id, CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
{
@@ -133,7 +134,7 @@ public virtual async Task<IActionResult> GetAsync(TId id, CancellationToken canc
/// GET /articles/1/revisions HTTP/1.1
/// ]]></code>
/// </summary>
public virtual async Task<IActionResult> GetSecondaryAsync(TId id, string relationshipName, CancellationToken cancellationToken)
public virtual async Task<IActionResult> GetSecondaryAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
{
@@ -162,7 +163,7 @@ public virtual async Task<IActionResult> GetSecondaryAsync(TId id, string relati
/// GET /articles/1/relationships/revisions HTTP/1.1
/// ]]></code>
/// </summary>
public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName, CancellationToken cancellationToken)
public virtual async Task<IActionResult> GetRelationshipAsync([DisallowNull] TId id, string relationshipName, CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
{
@@ -246,8 +247,8 @@ private string GetLocationUrl(string resourceId)
/// <param name="cancellationToken">
/// Propagates notification that request handling should be canceled.
/// </param>
public virtual async Task<IActionResult> PostRelationshipAsync(TId id, string relationshipName, [FromBody] ISet<IIdentifiable> rightResourceIds,
CancellationToken cancellationToken)
public virtual async Task<IActionResult> PostRelationshipAsync([DisallowNull] TId id, string relationshipName,
[FromBody] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
{
@@ -275,7 +276,7 @@ public virtual async Task<IActionResult> PostRelationshipAsync(TId id, string re
/// PATCH /articles/1 HTTP/1.1
/// ]]></code>
/// </summary>
public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] TResource resource, CancellationToken cancellationToken)
public virtual async Task<IActionResult> PatchAsync([DisallowNull] TId id, [FromBody] TResource resource, CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
{
@@ -321,7 +322,7 @@ public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] TResource
/// <param name="cancellationToken">
/// Propagates notification that request handling should be canceled.
/// </param>
public virtual async Task<IActionResult> PatchRelationshipAsync(TId id, string relationshipName, [FromBody] object? rightValue,
public virtual async Task<IActionResult> PatchRelationshipAsync([DisallowNull] TId id, string relationshipName, [FromBody] object? rightValue,
CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
@@ -348,7 +349,7 @@ public virtual async Task<IActionResult> PatchRelationshipAsync(TId id, string r
/// DELETE /articles/1 HTTP/1.1
/// ]]></code>
/// </summary>
public virtual async Task<IActionResult> DeleteAsync(TId id, CancellationToken cancellationToken)
public virtual async Task<IActionResult> DeleteAsync([DisallowNull] TId id, CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
{
@@ -382,8 +383,8 @@ public virtual async Task<IActionResult> DeleteAsync(TId id, CancellationToken c
/// <param name="cancellationToken">
/// Propagates notification that request handling should be canceled.
/// </param>
public virtual async Task<IActionResult> DeleteRelationshipAsync(TId id, string relationshipName, [FromBody] ISet<IIdentifiable> rightResourceIds,
CancellationToken cancellationToken)
public virtual async Task<IActionResult> DeleteRelationshipAsync([DisallowNull] TId id, string relationshipName,
[FromBody] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
{
_traceWriter.LogMethodStart(new
{
21 changes: 12 additions & 9 deletions src/JsonApiDotNetCore/Controllers/JsonApiController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Resources;
using JsonApiDotNetCore.Services;
@@ -50,23 +51,25 @@ public override async Task<IActionResult> GetAsync(CancellationToken cancellatio
/// <inheritdoc />
[HttpGet("{id}")]
[HttpHead("{id}")]
public override async Task<IActionResult> GetAsync([Required] TId id, CancellationToken cancellationToken)
public override async Task<IActionResult> GetAsync([Required] [DisallowNull] TId id, CancellationToken cancellationToken)
{
return await base.GetAsync(id, cancellationToken);
}

/// <inheritdoc />
[HttpGet("{id}/{relationshipName}")]
[HttpHead("{id}/{relationshipName}")]
public override async Task<IActionResult> GetSecondaryAsync([Required] TId id, [Required] string relationshipName, CancellationToken cancellationToken)
public override async Task<IActionResult> GetSecondaryAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
CancellationToken cancellationToken)
{
return await base.GetSecondaryAsync(id, relationshipName, cancellationToken);
}

/// <inheritdoc />
[HttpGet("{id}/relationships/{relationshipName}")]
[HttpHead("{id}/relationships/{relationshipName}")]
public override async Task<IActionResult> GetRelationshipAsync([Required] TId id, [Required] string relationshipName, CancellationToken cancellationToken)
public override async Task<IActionResult> GetRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
CancellationToken cancellationToken)
{
return await base.GetRelationshipAsync(id, relationshipName, cancellationToken);
}
@@ -80,38 +83,38 @@ public override async Task<IActionResult> PostAsync([Required] TResource resourc

/// <inheritdoc />
[HttpPost("{id}/relationships/{relationshipName}")]
public override async Task<IActionResult> PostRelationshipAsync([Required] TId id, [Required] string relationshipName,
public override async Task<IActionResult> PostRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
[Required] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
{
return await base.PostRelationshipAsync(id, relationshipName, rightResourceIds, cancellationToken);
}

/// <inheritdoc />
[HttpPatch("{id}")]
public override async Task<IActionResult> PatchAsync([Required] TId id, [Required] TResource resource, CancellationToken cancellationToken)
public override async Task<IActionResult> PatchAsync([Required] [DisallowNull] TId id, [Required] TResource resource, CancellationToken cancellationToken)
{
return await base.PatchAsync(id, resource, cancellationToken);
}

/// <inheritdoc />
[HttpPatch("{id}/relationships/{relationshipName}")]
// Parameter `[Required] object? rightValue` makes Swashbuckle generate the OpenAPI request body as required. We don't actually validate ModelState, so it doesn't hurt.
public override async Task<IActionResult> PatchRelationshipAsync([Required] TId id, [Required] string relationshipName, [Required] object? rightValue,
CancellationToken cancellationToken)
public override async Task<IActionResult> PatchRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
[Required] object? rightValue, CancellationToken cancellationToken)
{
return await base.PatchRelationshipAsync(id, relationshipName, rightValue, cancellationToken);
}

/// <inheritdoc />
[HttpDelete("{id}")]
public override async Task<IActionResult> DeleteAsync([Required] TId id, CancellationToken cancellationToken)
public override async Task<IActionResult> DeleteAsync([Required] [DisallowNull] TId id, CancellationToken cancellationToken)
{
return await base.DeleteAsync(id, cancellationToken);
}

/// <inheritdoc />
[HttpDelete("{id}/relationships/{relationshipName}")]
public override async Task<IActionResult> DeleteRelationshipAsync([Required] TId id, [Required] string relationshipName,
public override async Task<IActionResult> DeleteRelationshipAsync([Required] [DisallowNull] TId id, [Required] string relationshipName,
[Required] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
{
return await base.DeleteRelationshipAsync(id, relationshipName, rightResourceIds, cancellationToken);
11 changes: 6 additions & 5 deletions src/JsonApiDotNetCore/Queries/IQueryLayerComposer.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.Queries.Expressions;
using JsonApiDotNetCore.Resources;
@@ -18,7 +19,7 @@ public interface IQueryLayerComposer
/// <summary>
/// Builds a filter from constraints, used to determine total resource count on a secondary collection endpoint.
/// </summary>
FilterExpression? GetSecondaryFilterFromConstraints<TId>(TId primaryId, HasManyAttribute hasManyRelationship);
FilterExpression? GetSecondaryFilterFromConstraints<TId>([DisallowNull] TId primaryId, HasManyAttribute hasManyRelationship);

/// <summary>
/// Collects constraints and builds a <see cref="QueryLayer" /> out of them, used to retrieve the actual resources.
@@ -28,7 +29,7 @@ public interface IQueryLayerComposer
/// <summary>
/// Collects constraints and builds a <see cref="QueryLayer" /> out of them, used to retrieve one resource.
/// </summary>
QueryLayer ComposeForGetById<TId>(TId id, ResourceType primaryResourceType, TopFieldSelection fieldSelection);
QueryLayer ComposeForGetById<TId>([DisallowNull] TId id, ResourceType primaryResourceType, TopFieldSelection fieldSelection);

/// <summary>
/// Collects constraints and builds the secondary layer for a relationship endpoint.
@@ -38,14 +39,14 @@ public interface IQueryLayerComposer
/// <summary>
/// Wraps a layer for a secondary endpoint into a primary layer, rewriting top-level includes.
/// </summary>
QueryLayer WrapLayerForSecondaryEndpoint<TId>(QueryLayer secondaryLayer, ResourceType primaryResourceType, TId primaryId,
QueryLayer WrapLayerForSecondaryEndpoint<TId>(QueryLayer secondaryLayer, ResourceType primaryResourceType, [DisallowNull] TId primaryId,
RelationshipAttribute relationship);

/// <summary>
/// Builds a query that retrieves the primary resource, including all of its attributes and all targeted relationships, during a create/update/delete
/// request.
/// </summary>
QueryLayer ComposeForUpdate<TId>(TId id, ResourceType primaryResourceType);
QueryLayer ComposeForUpdate<TId>([DisallowNull] TId id, ResourceType primaryResourceType);

/// <summary>
/// Builds a query for each targeted relationship with a filter to match on its right resource IDs.
@@ -60,5 +61,5 @@ QueryLayer WrapLayerForSecondaryEndpoint<TId>(QueryLayer secondaryLayer, Resourc
/// <summary>
/// Builds a query for a to-many relationship with a filter to match on its left and right resource IDs.
/// </summary>
QueryLayer ComposeForHasMany<TId>(HasManyAttribute hasManyRelationship, TId leftId, ICollection<IIdentifiable> rightResourceIds);
QueryLayer ComposeForHasMany<TId>(HasManyAttribute hasManyRelationship, [DisallowNull] TId leftId, ICollection<IIdentifiable> rightResourceIds);
}
Loading
Loading