Skip to content

Fixing issue where total-records was 0 on POST and PATCH calls. #308

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 5 commits into from
Jun 23, 2018
Merged
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
15 changes: 7 additions & 8 deletions src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,20 @@ public Documents Build(IEnumerable<IIdentifiable> entities)

private Dictionary<string, object> GetMeta(IIdentifiable entity)
{
if (entity == null) return null;

var builder = _jsonApiContext.MetaBuilder;

if (entity is IHasMeta metaEntity)
builder.Add(metaEntity.GetMeta(_jsonApiContext));

if (_jsonApiContext.Options.IncludeTotalRecordCount)
if (_jsonApiContext.Options.IncludeTotalRecordCount && _jsonApiContext.PageManager.TotalRecords != null)
builder.Add("total-records", _jsonApiContext.PageManager.TotalRecords);

if (_requestMeta != null)
builder.Add(_requestMeta.GetMeta());

if (entity != null && entity is IHasMeta metaEntity)
builder.Add(metaEntity.GetMeta(_jsonApiContext));

var meta = builder.Build();
if (meta.Count > 0) return meta;
if (meta.Count > 0)
return meta;

return null;
}

Expand Down
4 changes: 2 additions & 2 deletions src/JsonApiDotNetCore/Internal/PageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ namespace JsonApiDotNetCore.Internal
{
public class PageManager
{
public int TotalRecords { get; set; }
public int? TotalRecords { get; set; }
public int PageSize { get; set; }
public int DefaultPageSize { get; set; }
public int CurrentPage { get; set; }
public bool IsPaginated => PageSize > 0;
public int TotalPages => (TotalRecords == 0) ? -1 : (int)Math.Ceiling(decimal.Divide(TotalRecords, PageSize));
public int TotalPages => (TotalRecords == null) ? -1 : (int)Math.Ceiling(decimal.Divide(TotalRecords.Value, PageSize));

public RootLinks GetPageLinks(LinkBuilder linkBuilder)
{
Expand Down
2 changes: 1 addition & 1 deletion src/JsonApiDotNetCore/JsonApiDotNetCore.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>2.3.0</VersionPrefix>
<VersionPrefix>2.3.1</VersionPrefix>
<TargetFrameworks>$(NetStandardVersion)</TargetFrameworks>
<AssemblyName>JsonApiDotNetCore</AssemblyName>
<PackageId>JsonApiDotNetCore</PackageId>
Expand Down
10 changes: 5 additions & 5 deletions src/JsonApiDotNetCore/Services/JsonApiContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,20 @@ internal static bool PathIsRelationship(string requestPath)
const char pathSegmentDelimiter = '/';

var span = requestPath.AsSpan();

// we need to iterate over the string, from the end,
// checking whether or not the 2nd to last path segment
// is "relationships"
// -2 is chosen in case the path ends with '/'
for(var i = requestPath.Length - 2; i >= 0; i--)
for (var i = requestPath.Length - 2; i >= 0; i--)
{
// if there are not enough characters left in the path to
// contain "relationships"
if(i < relationships.Length)
if (i < relationships.Length)
return false;

// we have found the first instance of '/'
if(span[i] == pathSegmentDelimiter)
if (span[i] == pathSegmentDelimiter)
{
// in the case of a "relationships" route, the next
// path segment will be "relationships"
Expand All @@ -112,7 +112,7 @@ internal static bool PathIsRelationship(string requestPath)

return false;
}

private PageManager GetPageManager()
{
if (Options.DefaultPageSize == 0 && (QuerySet == null || QuerySet.PageQuery.PageSize == 0))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCoreExample;
Expand Down Expand Up @@ -47,13 +48,123 @@ public async Task Total_Record_Count_Included()
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();
var documents = JsonConvert.DeserializeObject<Documents>(responseBody);

// assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(documents.Meta);
Assert.Equal((long)expectedCount, (long)documents.Meta["total-records"]);
}

[Fact]
public async Task Total_Record_Count_Included_When_None()
{
// arrange
_context.TodoItems.RemoveRange(_context.TodoItems);
_context.SaveChanges();
var builder = new WebHostBuilder()
.UseStartup<MetaStartup>();

var httpMethod = new HttpMethod("GET");
var route = $"/api/v1/todo-items";

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

// act
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();
var documents = JsonConvert.DeserializeObject<Documents>(responseBody);

// assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(documents.Meta);
Assert.Equal(0, (long)documents.Meta["total-records"]);
}

[Fact]
public async Task Total_Record_Count_Not_Included_In_POST_Response()
{
// arrange
_context.TodoItems.RemoveRange(_context.TodoItems);
_context.SaveChanges();
var builder = new WebHostBuilder()
.UseStartup<MetaStartup>();

var httpMethod = new HttpMethod("POST");
var route = $"/api/v1/todo-items";

var server = new TestServer(builder);
var client = server.CreateClient();
var request = new HttpRequestMessage(httpMethod, route);
var content = new
{
data = new
{
type = "todo-items",
attributes = new
{
description = "New Description",
}
}
};

request.Content = new StringContent(JsonConvert.SerializeObject(content));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json");

// act
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();
var documents = JsonConvert.DeserializeObject<Document>(responseBody);

// assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
Assert.False(documents.Meta.ContainsKey("total-records"));
}

[Fact]
public async Task Total_Record_Count_Not_Included_In_PATCH_Response()
{
// arrange
_context.TodoItems.RemoveRange(_context.TodoItems);
TodoItem todoItem = new TodoItem();
_context.TodoItems.Add(todoItem);
_context.SaveChanges();
var builder = new WebHostBuilder()
.UseStartup<MetaStartup>();

var httpMethod = new HttpMethod("PATCH");
var route = $"/api/v1/todo-items/{todoItem.Id}";

var server = new TestServer(builder);
var client = server.CreateClient();
var request = new HttpRequestMessage(httpMethod, route);
var content = new
{
data = new
{
type = "todo-items",
id = todoItem.Id,
attributes = new
{
description = "New Description",
}
}
};

request.Content = new StringContent(JsonConvert.SerializeObject(content));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json");

// act
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();
var documents = JsonConvert.DeserializeObject<Document>(responseBody);

// assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.False(documents.Meta.ContainsKey("total-records"));
}

[Fact]
public async Task EntityThatImplements_IHasMeta_Contains_MetaData()
{
Expand All @@ -73,26 +184,26 @@ public async Task EntityThatImplements_IHasMeta_Contains_MetaData()
// act
var response = await client.SendAsync(request);
var documents = JsonConvert.DeserializeObject<Documents>(await response.Content.ReadAsStringAsync());

// assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.NotNull(documents.Meta);
Assert.NotNull(expectedMeta);
Assert.NotEmpty(expectedMeta);
foreach(var hash in expectedMeta)

foreach (var hash in expectedMeta)
{
if(hash.Value is IList)
if (hash.Value is IList)
{
var listValue = (IList)hash.Value;
for(var i=0; i < listValue.Count; i++)
for (var i = 0; i < listValue.Count; i++)
Assert.Equal(listValue[i].ToString(), ((IList)documents.Meta[hash.Key])[i].ToString());
}
else
{
Assert.Equal(hash.Value, documents.Meta[hash.Key]);
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ public async Task Request_ForEmptyCollection_Returns_EmptyDataCollection()
var server = new TestServer(builder);
var client = server.CreateClient();
var request = new HttpRequestMessage(httpMethod, route);
var expectedBody = JsonConvert.SerializeObject(new {
data = new List<object>()
var expectedBody = JsonConvert.SerializeObject(new
{
data = new List<object>(),
meta = new Dictionary<string, int> { { "total-records", 0 } }
});

// act
Expand Down