Skip to content

Commit

Permalink
Merge pull request #308 from nwise/master
Browse files Browse the repository at this point in the history
Fixing issue where total-records was 0 on POST and PATCH calls.
  • Loading branch information
jaredcnance authored Jun 23, 2018
2 parents 8f7f0f7 + 0a7faed commit 9013643
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 24 deletions.
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
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

0 comments on commit 9013643

Please sign in to comment.