Skip to content

Fix/id type support #55

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 17 commits into from
Mar 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
\.vs/
13 changes: 11 additions & 2 deletions Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,14 @@ $revision = "{0:D4}" -f [convert]::ToInt32($revision, 10)
dotnet restore .\src\JsonApiDotNetCore\JsonApiDotNetCore.csproj
dotnet build .\src\JsonApiDotNetCore -c Release

If($env:APPVEYOR_REPO_TAG) { dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts }
Else { dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision }
echo "APPVEYOR_REPO_TAG: $env:APPVEYOR_REPO_TAG"
echo "VERSION-SUFFIX: alpha1-$revision"

If($env:APPVEYOR_REPO_TAG -eq $true) {
echo "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts "
dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts
}
Else {
echo "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision"
dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision
}
48 changes: 48 additions & 0 deletions JsonApiDotnetCore.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCore", "src\JsonApiDotNetCore\JsonApiDotNetCore.csproj", "{C0EC9E70-EB2E-436F-9D94-FA16FA774123}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCoreExample", "src\JsonApiDotNetCoreExample\JsonApiDotNetCoreExample.csproj", "{97EE048B-16C0-43F6-BDA9-4E762B2F579F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{24B15015-62E5-42E1-9BA0-ECE6BE7AA15F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCoreExampleTests", "test\JsonApiDotNetCoreExampleTests\JsonApiDotNetCoreExampleTests.csproj", "{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C5B4D998-CECB-454D-9F32-085A897577BE}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C0EC9E70-EB2E-436F-9D94-FA16FA774123}.Release|Any CPU.Build.0 = Release|Any CPU
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97EE048B-16C0-43F6-BDA9-4E762B2F579F}.Release|Any CPU.Build.0 = Release|Any CPU
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C0EC9E70-EB2E-436F-9D94-FA16FA774123} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF}
{97EE048B-16C0-43F6-BDA9-4E762B2F579F} = {7A2B7ADD-ECB5-4D00-AA6A-D45BD11C97CF}
{0B959765-40D2-43B5-87EE-FE2FEF9DBED5} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F}
EndGlobalSection
EndGlobal
13 changes: 1 addition & 12 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,8 @@
#exit if any command fails
set -e

artifactsFolder="./artifacts"

if [ -d $artifactsFolder ]; then
rm -R $artifactsFolder
fi

dotnet restore ./src/JsonApiDotNetCore/JsonApiDotNetCore.csproj
dotnet restore ./src/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj
dotnet restore ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj

dotnet test ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj

revision=${TRAVIS_JOB_ID:=1}
revision=$(printf "%04d" $revision)

dotnet pack ./src/JsonApiDotNetCore -c Release -o ./artifacts --version-suffix=$revision
dotnet test ./test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj
12 changes: 6 additions & 6 deletions src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private DocumentData _getData(ContextEntity contextEntity, IIdentifiable entity)
var data = new DocumentData
{
Type = contextEntity.EntityName,
Id = entity.Id.ToString()
Id = entity.StringId
};

if (_jsonApiContext.IsRelationshipData)
Expand Down Expand Up @@ -124,8 +124,8 @@ private void _addRelationships(DocumentData data, ContextEntity contextEntity, I
{
Links = new Links
{
Self = linkBuilder.GetSelfRelationLink(contextEntity.EntityName, entity.Id.ToString(), r.InternalRelationshipName),
Related = linkBuilder.GetRelatedRelationLink(contextEntity.EntityName, entity.Id.ToString(), r.InternalRelationshipName)
Self = linkBuilder.GetSelfRelationLink(contextEntity.EntityName, entity.StringId, r.InternalRelationshipName),
Related = linkBuilder.GetRelatedRelationLink(contextEntity.EntityName, entity.StringId, r.InternalRelationshipName)
}
};

Expand Down Expand Up @@ -175,7 +175,7 @@ private DocumentData _getIncludedEntity(IIdentifiable entity)
var data = new DocumentData
{
Type = contextEntity.EntityName,
Id = entity.Id.ToString()
Id = entity.StringId
};

data.Attributes = new Dictionary<string, object>();
Expand Down Expand Up @@ -205,7 +205,7 @@ private List<Dictionary<string, string>> _getRelationships(IEnumerable<object> e
{
relationships.Add(new Dictionary<string, string> {
{"type", typeName.EntityName.Dasherize() },
{"id", ((IIdentifiable)entity).Id.ToString() }
{"id", ((IIdentifiable)entity).StringId }
});
}
return relationships;
Expand All @@ -218,7 +218,7 @@ private Dictionary<string, string> _getRelationship(object entity, string relati

return new Dictionary<string, string> {
{"type", typeName.EntityName.Dasherize() },
{"id", ((IIdentifiable)entity).Id.ToString() }
{"id", ((IIdentifiable)entity).StringId }
};
}
}
Expand Down
29 changes: 14 additions & 15 deletions src/JsonApiDotNetCore/Controllers/JsonApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace JsonApiDotNetCore.Controllers
{
public class JsonApiController<T>
public class JsonApiController<T>
: JsonApiController<T, int> where T : class, IIdentifiable<int>
{
public JsonApiController(
Expand All @@ -24,7 +24,7 @@ public JsonApiController(
{ }
}

public class JsonApiController<T, TId>
public class JsonApiController<T, TId>
: JsonApiControllerMixin where T : class, IIdentifiable<TId>
{
private readonly IEntityRepository<T, TId> _entities;
Expand Down Expand Up @@ -77,7 +77,7 @@ public virtual async Task<IActionResult> GetAsync()
public virtual async Task<IActionResult> GetAsync(TId id)
{
T entity;
if(_jsonApiContext.QuerySet?.IncludedRelationships != null)
if (_jsonApiContext.QuerySet?.IncludedRelationships != null)
entity = await _getWithRelationshipsAsync(id);
else
entity = await _entities.GetAsync(id);
Expand Down Expand Up @@ -138,8 +138,7 @@ public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
return UnprocessableEntity();
}

var stringId = entity.Id.ToString();
if(stringId.Length > 0 && stringId != "0")
if (!string.IsNullOrEmpty(entity.StringId))
return Forbidden();

await _entities.CreateAsync(entity);
Expand All @@ -158,7 +157,7 @@ public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)

var updatedEntity = await _entities.UpdateAsync(id, entity);

if(updatedEntity == null) return NotFound();
if (updatedEntity == null) return NotFound();

return Ok(updatedEntity);
}
Expand All @@ -185,12 +184,12 @@ public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string
.Relationships
.FirstOrDefault(r => r.InternalRelationshipName == relationshipName);

var relationshipIds = relationships.Select(r=>r.Id);
var relationshipIds = relationships.Select(r => r.Id);

await _entities.UpdateRelationshipsAsync(entity, relationship, relationshipIds);

return Ok();

}

[HttpDelete("{id}")]
Expand All @@ -208,14 +207,14 @@ private IQueryable<T> ApplySortAndFilterQuery(IQueryable<T> entities)
{
var query = _jsonApiContext.QuerySet;

if(_jsonApiContext.QuerySet == null)
if (_jsonApiContext.QuerySet == null)
return entities;

if(query.Filters.Count > 0)
foreach(var filter in query.Filters)
if (query.Filters.Count > 0)
foreach (var filter in query.Filters)
entities = _entities.Filter(entities, filter);

if(query.SortParameters != null && query.SortParameters.Count > 0)
if (query.SortParameters != null && query.SortParameters.Count > 0)
entities = _entities.Sort(entities, query.SortParameters);

return entities;
Expand All @@ -224,7 +223,7 @@ private IQueryable<T> ApplySortAndFilterQuery(IQueryable<T> entities)
private async Task<IEnumerable<T>> ApplyPageQueryAsync(IQueryable<T> entities)
{
var pageManager = _jsonApiContext.PageManager;
if(!pageManager.IsPaginated)
if (!pageManager.IsPaginated)
return entities;

var query = _jsonApiContext.QuerySet?.PageQuery ?? new PageQuery();
Expand All @@ -238,7 +237,7 @@ private IQueryable<T> IncludeRelationships(IQueryable<T> entities, List<string>
{
_jsonApiContext.IncludedRelationships = relationships;

foreach(var r in relationships)
foreach (var r in relationships)
entities = _entities.Include(entities, r.ToProperCase());

return entities;
Expand Down
5 changes: 4 additions & 1 deletion src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.EntityFrameworkCore;

namespace JsonApiDotNetCore.Formatters
{
Expand Down Expand Up @@ -37,13 +38,15 @@ public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
var loggerFactory = GetService<ILoggerFactory>(context);
var logger = loggerFactory?.CreateLogger<JsonApiInputFormatter>();

var dbContext = GetService<DbContext>(context);

try
{
var body = GetRequestBody(context.HttpContext.Request.Body);
var jsonApiContext = GetService<IJsonApiContext>(context);
var model = jsonApiContext.IsRelationshipPath ?
JsonApiDeSerializer.DeserializeRelationship(body, jsonApiContext) :
JsonApiDeSerializer.Deserialize(body, jsonApiContext);
JsonApiDeSerializer.Deserialize(body, jsonApiContext, dbContext);

if(model == null)
logger?.LogError("An error occurred while de-serializing the payload");
Expand Down
19 changes: 11 additions & 8 deletions src/JsonApiDotNetCore/Internal/Generics/GenericProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Models;
Expand All @@ -18,21 +16,26 @@ public GenericProcessor(DbContext context)
}

public async Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable<string> relationshipIds)
{
SetRelationships(parent, relationship, relationshipIds);

await _context.SaveChangesAsync();
}

public void SetRelationships(object parent, RelationshipAttribute relationship, IEnumerable<string> relationshipIds)
{
var relationshipType = relationship.Type;

if(relationship.IsHasMany)
if (relationship.IsHasMany)
{
var entities = _context.GetDbSet<T>().Where(x => relationshipIds.Contains(x.Id.ToString())).ToList();
var entities = _context.GetDbSet<T>().Where(x => relationshipIds.Contains(x.StringId)).ToList();
relationship.SetValue(parent, entities);
}
else
{
var entity = _context.GetDbSet<T>().SingleOrDefault(x => relationshipIds.First() == x.Id.ToString());
var entity = _context.GetDbSet<T>().SingleOrDefault(x => relationshipIds.First() == x.StringId);
relationship.SetValue(parent, entity);
}

await _context.SaveChangesAsync();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ namespace JsonApiDotNetCore.Internal
public interface IGenericProcessor
{
Task UpdateRelationshipsAsync(object parent, RelationshipAttribute relationship, IEnumerable<string> relationshipIds);
void SetRelationships(object parent, RelationshipAttribute relationship, IEnumerable<string> relationshipIds);
}
}
24 changes: 24 additions & 0 deletions src/JsonApiDotNetCore/Internal/TypeHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Reflection;

namespace JsonApiDotNetCore.Internal
{
public static class TypeHelper
{
public static object ConvertType(object value, Type type)
{
if(value == null)
return null;

if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
type = Nullable.GetUnderlyingType(type);

var stringValue = value.ToString();

if(type == typeof(Guid))
return Guid.Parse(stringValue);

return Convert.ChangeType(stringValue, type);
}
}
}
4 changes: 2 additions & 2 deletions src/JsonApiDotNetCore/Models/IIdentifiable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ namespace JsonApiDotNetCore.Models
{
public interface IIdentifiable
{
object Id { get; set; }
string StringId { get; set; }
}

public interface IIdentifiable<T> : IIdentifiable
{
new T Id { get; set; }
T Id { get; set; }
}
}
32 changes: 29 additions & 3 deletions src/JsonApiDotNetCore/Models/Identifiable.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
using JsonApiDotNetCore.Internal;

namespace JsonApiDotNetCore.Models
{
public class Identifiable : Identifiable<int>
Expand All @@ -7,10 +11,32 @@ public class Identifiable<T> : IIdentifiable<T>, IIdentifiable
{
public virtual T Id { get; set; }

object IIdentifiable.Id
[NotMapped]
public string StringId
{
get { return GetStringId(Id); }
set { Id = (T)GetConcreteId(value); }
}

protected virtual string GetStringId(object value)
{
var type = typeof(T);
var stringValue = value.ToString();

if(type == typeof(Guid))
{
var guid = Guid.Parse(stringValue);
return (guid == Guid.Empty ? string.Empty : stringValue);
}

if(stringValue == "0") return string.Empty;

return stringValue;
}

protected virtual object GetConcreteId(string value)
{
get { return Id; }
set { Id = (T)value; }
return TypeHelper.ConvertType(value, typeof(T));
}
}
}
Loading