Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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/JsonApiDotNetCoreExample/Models/Person.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class Person : Identifiable, IHasMeta

[HasMany("todo-collections")]
public virtual List<TodoItemCollection> TodoItemCollections { get; set; }

[HasOne("unincludeable-item", Link.All, false)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change this to include the canInclude parameter name?

[HasOne("unincludeable-item", Link.All, canInclude : false)]

These examples serve as documentation, so being explicit improves readability.

public virtual TodoItem UnIncludeableItem { get; set; }

public Dictionary<string, object> GetMeta(IJsonApiContext context)
{
Expand Down
15 changes: 11 additions & 4 deletions src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,18 @@ public virtual IQueryable<TEntity> Include(IQueryable<TEntity> entities, string
{
var entity = _jsonApiContext.RequestEntity;
var relationship = entity.Relationships.FirstOrDefault(r => r.PublicRelationshipName == relationshipName);
if (relationship != null)
return entities.Include(relationship.InternalRelationshipName);
if (relationship == null)
{
throw new JsonApiException(400, $"Invalid relationship {relationshipName} on {entity.EntityName}",
$"{entity.EntityName} does not have a relationship named {relationshipName}");
}

if (!relationship.CanInclude)
{
throw new JsonApiException(400, $"Including the relationship {relationshipName} on {entity.EntityName} is not allowed");
}
return entities.Include(relationship.InternalRelationshipName);

throw new JsonApiException(400, $"Invalid relationship {relationshipName} on {entity.EntityName}",
$"{entity.EntityName} does not have a relationship named {relationshipName}");
}

public virtual async Task<IEnumerable<TEntity>> PageAsync(IQueryable<TEntity> entities, int pageSize, int pageNumber)
Expand Down
4 changes: 2 additions & 2 deletions src/JsonApiDotNetCore/Models/HasManyAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ namespace JsonApiDotNetCore.Models
{
public class HasManyAttribute : RelationshipAttribute
{
public HasManyAttribute(string publicName, Link documentLinks = Link.All)
: base(publicName, documentLinks)
public HasManyAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true)
: base(publicName, documentLinks, canInclude)
{ }

public override void SetValue(object entity, object newValue)
Expand Down
4 changes: 2 additions & 2 deletions src/JsonApiDotNetCore/Models/HasOneAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ namespace JsonApiDotNetCore.Models
{
public class HasOneAttribute : RelationshipAttribute
{
public HasOneAttribute(string publicName, Link documentLinks = Link.All)
: base(publicName, documentLinks)
public HasOneAttribute(string publicName, Link documentLinks = Link.All, bool canInclude = true)
: base(publicName, documentLinks, canInclude)
{ }

public override void SetValue(object entity, object newValue)
Expand Down
7 changes: 4 additions & 3 deletions src/JsonApiDotNetCore/Models/RelationshipAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ namespace JsonApiDotNetCore.Models
{
public abstract class RelationshipAttribute : Attribute
{
protected RelationshipAttribute(string publicName, Link documentLinks)
protected RelationshipAttribute(string publicName, Link documentLinks, bool canInclude)
{
PublicRelationshipName = publicName;
DocumentLinks = documentLinks;
CanInclude = canInclude;
}

public string PublicRelationshipName { get; }
Expand All @@ -16,6 +17,7 @@ protected RelationshipAttribute(string publicName, Link documentLinks)
public bool IsHasMany => GetType() == typeof(HasManyAttribute);
public bool IsHasOne => GetType() == typeof(HasOneAttribute);
public Link DocumentLinks { get; } = Link.All;
public bool CanInclude { get; }

public abstract void SetValue(object entity, object newValue);

Expand All @@ -26,8 +28,7 @@ public override string ToString()

public override bool Equals(object obj)
{
var attr = obj as RelationshipAttribute;
if (attr == null)
if (!(obj is RelationshipAttribute attr))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

{
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,5 +335,29 @@ public async Task Request_ToIncludeDeeplyNestedRelationships_Returns_400()
// assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}

[Fact]
public async Task Request_ToIncludeRelationshipMarkedCanIncludeFalse_Returns_400()
{
// arrange
var person = _context.People.First();

var builder = new WebHostBuilder()
.UseStartup<Startup>();

var httpMethod = new HttpMethod("GET");

var route = $"/api/v1/people/{person.Id}?include=unincludeable-item";

var server = new TestServer(builder);
var client = server.CreateClient();
var request = new HttpRequestMessage(httpMethod, route);

// act
var response = await client.SendAsync(request);

// assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
}
}