From cbe3178463dfa4ac534b8ca80e739f527f82134c Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 30 Mar 2017 18:55:44 -0500 Subject: [PATCH 1/2] test(acceptance): reproduce issue --- ...20170330234539_AddGuidProperty.Designer.cs | 102 ++++++++++++++++++ .../20170330234539_AddGuidProperty.cs | 25 +++++ .../Migrations/AppDbContextModelSnapshot.cs | 2 + .../Models/TodoItem.cs | 8 ++ .../Acceptance/Spec/AttributeFilterTests.cs | 67 ++++++++++++ .../Spec/FetchingRelationshipsTests.cs | 7 -- 6 files changed, 204 insertions(+), 7 deletions(-) create mode 100755 src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs create mode 100755 src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs create mode 100644 test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs diff --git a/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs b/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs new file mode 100755 index 0000000000..ded5d1b160 --- /dev/null +++ b/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.Designer.cs @@ -0,0 +1,102 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using JsonApiDotNetCoreExample.Data; + +namespace JsonApiDotNetCoreExample.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20170330234539_AddGuidProperty")] + partial class AddGuidProperty + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "1.1.1"); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("FirstName"); + + b.Property("LastName"); + + b.HasKey("Id"); + + b.ToTable("People"); + }); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AssigneeId"); + + b.Property("CollectionId"); + + b.Property("Description"); + + b.Property("GuidProperty"); + + b.Property("Ordinal"); + + b.Property("OwnerId"); + + b.HasKey("Id"); + + b.HasIndex("AssigneeId"); + + b.HasIndex("CollectionId"); + + b.HasIndex("OwnerId"); + + b.ToTable("TodoItems"); + }); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.Property("OwnerId"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("TodoItemCollections"); + }); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItem", b => + { + b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Assignee") + .WithMany("AssignedTodoItems") + .HasForeignKey("AssigneeId"); + + b.HasOne("JsonApiDotNetCoreExample.Models.TodoItemCollection", "Collection") + .WithMany("TodoItems") + .HasForeignKey("CollectionId"); + + b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") + .WithMany("TodoItems") + .HasForeignKey("OwnerId"); + }); + + modelBuilder.Entity("JsonApiDotNetCoreExample.Models.TodoItemCollection", b => + { + b.HasOne("JsonApiDotNetCoreExample.Models.Person", "Owner") + .WithMany("TodoItemCollections") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade); + }); + } + } +} diff --git a/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs b/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs new file mode 100755 index 0000000000..43ea19b242 --- /dev/null +++ b/src/JsonApiDotNetCoreExample/Migrations/20170330234539_AddGuidProperty.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace JsonApiDotNetCoreExample.Migrations +{ + public partial class AddGuidProperty : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "GuidProperty", + table: "TodoItems", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "GuidProperty", + table: "TodoItems"); + } + } +} diff --git a/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs b/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs index 21f5cbc221..6912fa093a 100755 --- a/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs +++ b/src/JsonApiDotNetCoreExample/Migrations/AppDbContextModelSnapshot.cs @@ -41,6 +41,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Description"); + b.Property("GuidProperty"); + b.Property("Ordinal"); b.Property("OwnerId"); diff --git a/src/JsonApiDotNetCoreExample/Models/TodoItem.cs b/src/JsonApiDotNetCoreExample/Models/TodoItem.cs index 008c42b1a6..27ad9716c6 100644 --- a/src/JsonApiDotNetCoreExample/Models/TodoItem.cs +++ b/src/JsonApiDotNetCoreExample/Models/TodoItem.cs @@ -5,11 +5,19 @@ namespace JsonApiDotNetCoreExample.Models { public class TodoItem : Identifiable { + public TodoItem() + { + GuidProperty = Guid.NewGuid(); + } + [Attr("description")] public string Description { get; set; } [Attr("ordinal")] public long Ordinal { get; set; } + + [Attr("guid-property")] + public Guid GuidProperty { get; set; } public int? OwnerId { get; set; } public int? AssigneeId { get; set; } diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs new file mode 100644 index 0000000000..5c10196d1f --- /dev/null +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/AttributeFilterTests.cs @@ -0,0 +1,67 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using DotNetCoreDocs; +using DotNetCoreDocs.Models; +using DotNetCoreDocs.Writers; +using JsonApiDotNetCoreExample; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Newtonsoft.Json; +using Xunit; +using JsonApiDotNetCore.Internal; +using JsonApiDotNetCoreExample.Data; +using Bogus; +using JsonApiDotNetCoreExample.Models; +using JsonApiDotNetCore.Serialization; +using System.Linq; + +namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec +{ + [Collection("WebHostCollection")] + public class AttributeFilterTests + { + private DocsFixture _fixture; + private Faker _todoItemFaker; + + public AttributeFilterTests(DocsFixture fixture) + { + _fixture = fixture; + _todoItemFaker = new Faker() + .RuleFor(t => t.Description, f => f.Lorem.Sentence()) + .RuleFor(t => t.Ordinal, f => f.Random.Number()); + } + + [Fact] + public async Task Can_Filter_On_Guid_Properties() + { + // arrange + var context = _fixture.GetService(); + var todoItem = _todoItemFaker.Generate(); + context.TodoItems.Add(todoItem); + await context.SaveChangesAsync(); + + var builder = new WebHostBuilder() + .UseStartup(); + var httpMethod = new HttpMethod("GET"); + var route = $"/api/v1/todo-items?filter[guid-property]={todoItem.GuidProperty}"; + var server = new TestServer(builder); + var client = server.CreateClient(); + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await client.SendAsync(request); + var body = await response.Content.ReadAsStringAsync(); + var deserializedBody = _fixture + .GetService() + .DeserializeList(body); + + var todoItemResponse = deserializedBody.Single(); + + // assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(todoItem.Id, todoItemResponse.Id); + Assert.Equal(todoItem.GuidProperty, todoItemResponse.GuidProperty); + } + } +} diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs index 6522e79b62..e6ca2663c0 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/FetchingRelationshipsTests.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; @@ -7,18 +5,13 @@ using Bogus; using DotNetCoreDocs; using DotNetCoreDocs.Writers; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample; using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; -using Newtonsoft.Json; using Xunit; -using Person = JsonApiDotNetCoreExample.Models.Person; - namespace JsonApiDotNetCoreExampleTests.Acceptance.Spec { [Collection("WebHostCollection")] From 1513211a517b50a7a686fe49d3dbd3bf2fc429de Mon Sep 17 00:00:00 2001 From: jaredcnance Date: Thu, 30 Mar 2017 18:56:14 -0500 Subject: [PATCH 2/2] fix(iQueryableExtensions): use TypeHelper better type conversion for Guids --- src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index e33359e90d..1ffeee4d5a 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -78,7 +78,7 @@ public static IQueryable Filter(this IQueryable sourc { // convert the incoming value to the target value type // "1" -> 1 - var convertedValue = Convert.ChangeType(filterQuery.PropertyValue, property.PropertyType); + var convertedValue = TypeHelper.ConvertType(filterQuery.PropertyValue, property.PropertyType); // {model} var parameter = Expression.Parameter(concreteType, "model"); // {model.Id}