From 6204a168252f63a2dab0ce21ed5cb13f52935510 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 10 Oct 2019 12:41:07 +0200 Subject: [PATCH 1/7] chore: remove example projects --- JsonApiDotnetCore.sln | 30 --- src/Examples/OperationsExample/.gitignore | 236 ------------------ .../Controllers/OperationsController.cs | 14 -- .../OperationsExample.csproj | 30 --- src/Examples/OperationsExample/Program.cs | 15 -- .../Properties/launchSettings.json | 27 -- src/Examples/OperationsExample/Startup.cs | 55 ---- .../OperationsExample/appsettings.json | 13 - .../Controllers/CoursesController.cs | 20 -- .../Controllers/DepartmentsController.cs | 21 -- .../Controllers/StudentsController.cs | 20 -- .../Models/AutoMapperAdapter.cs | 25 -- .../Profiles/CourseProfile.cs | 40 --- .../Profiles/DepartmentProfile.cs | 14 -- .../Profiles/StudentProfile.cs | 35 --- .../Program.cs | 15 -- .../Properties/launchSettings.json | 24 -- .../ResourceEntitySeparationExample.csproj | 16 -- .../Startup.cs | 88 ------- .../appsettings.Development.json | 9 - .../appsettings.json | 12 - .../OperationsExampleTests.csproj | 1 - ...esourceEntitySeparationExampleTests.csproj | 1 - 23 files changed, 761 deletions(-) delete mode 100644 src/Examples/OperationsExample/.gitignore delete mode 100644 src/Examples/OperationsExample/Controllers/OperationsController.cs delete mode 100644 src/Examples/OperationsExample/OperationsExample.csproj delete mode 100644 src/Examples/OperationsExample/Program.cs delete mode 100644 src/Examples/OperationsExample/Properties/launchSettings.json delete mode 100644 src/Examples/OperationsExample/Startup.cs delete mode 100644 src/Examples/OperationsExample/appsettings.json delete mode 100644 src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Models/AutoMapperAdapter.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Profiles/CourseProfile.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Profiles/DepartmentProfile.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Profiles/StudentProfile.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Program.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/Properties/launchSettings.json delete mode 100644 src/Examples/ResourceEntitySeparationExample/ResourceEntitySeparationExample.csproj delete mode 100644 src/Examples/ResourceEntitySeparationExample/Startup.cs delete mode 100644 src/Examples/ResourceEntitySeparationExample/appsettings.Development.json delete mode 100644 src/Examples/ResourceEntitySeparationExample/appsettings.json diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index a0be085cb2..ac0721d13c 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -29,10 +29,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoEntityFrameworkExample", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportsExample", "src\Examples\ReportsExample\ReportsExample.csproj", "{1CC0831C-ED1D-442E-8421-331D50BD41F1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OperationsExample", "src\Examples\OperationsExample\OperationsExample.csproj", "{3AB43764-C57A-4B75-8C03-C671D3925BF3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceEntitySeparationExample", "src\Examples\ResourceEntitySeparationExample\ResourceEntitySeparationExample.csproj", "{623792C0-5B7D-4D7D-A276-73F908FD4C34}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonApiDotNetCoreExampleTests", "test\JsonApiDotNetCoreExampleTests\JsonApiDotNetCoreExampleTests.csproj", "{CAF331F8-9255-4D72-A1A8-A54141E99F1E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoEntityFrameworkTests", "test\NoEntityFrameworkTests\NoEntityFrameworkTests.csproj", "{4F15A8F8-5BC6-45A1-BC51-03F921B726A4}" @@ -99,30 +95,6 @@ Global {1CC0831C-ED1D-442E-8421-331D50BD41F1}.Release|x64.Build.0 = Release|Any CPU {1CC0831C-ED1D-442E-8421-331D50BD41F1}.Release|x86.ActiveCfg = Release|Any CPU {1CC0831C-ED1D-442E-8421-331D50BD41F1}.Release|x86.Build.0 = Release|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Debug|x64.ActiveCfg = Debug|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Debug|x64.Build.0 = Debug|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Debug|x86.ActiveCfg = Debug|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Debug|x86.Build.0 = Debug|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Release|Any CPU.Build.0 = Release|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Release|x64.ActiveCfg = Release|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Release|x64.Build.0 = Release|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Release|x86.ActiveCfg = Release|Any CPU - {3AB43764-C57A-4B75-8C03-C671D3925BF3}.Release|x86.Build.0 = Release|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Debug|Any CPU.Build.0 = Debug|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Debug|x64.ActiveCfg = Debug|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Debug|x64.Build.0 = Debug|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Debug|x86.ActiveCfg = Debug|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Debug|x86.Build.0 = Debug|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Release|Any CPU.ActiveCfg = Release|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Release|Any CPU.Build.0 = Release|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Release|x64.ActiveCfg = Release|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Release|x64.Build.0 = Release|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Release|x86.ActiveCfg = Release|Any CPU - {623792C0-5B7D-4D7D-A276-73F908FD4C34}.Release|x86.Build.0 = Release|Any CPU {CAF331F8-9255-4D72-A1A8-A54141E99F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CAF331F8-9255-4D72-A1A8-A54141E99F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU {CAF331F8-9255-4D72-A1A8-A54141E99F1E}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -225,8 +197,6 @@ Global {27FA7CD3-8DCD-4104-9AB4-B2D927F421B5} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {99BAF03C-362B-41FA-9FFF-67F697EFC28C} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {1CC0831C-ED1D-442E-8421-331D50BD41F1} = {026FBC6C-AF76-4568-9B87-EC73457899FD} - {3AB43764-C57A-4B75-8C03-C671D3925BF3} = {026FBC6C-AF76-4568-9B87-EC73457899FD} - {623792C0-5B7D-4D7D-A276-73F908FD4C34} = {026FBC6C-AF76-4568-9B87-EC73457899FD} {CAF331F8-9255-4D72-A1A8-A54141E99F1E} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {4F15A8F8-5BC6-45A1-BC51-03F921B726A4} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {8788FF65-C2B6-40B2-A3A0-1E3D91C02664} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} diff --git a/src/Examples/OperationsExample/.gitignore b/src/Examples/OperationsExample/.gitignore deleted file mode 100644 index 0f552f400b..0000000000 --- a/src/Examples/OperationsExample/.gitignore +++ /dev/null @@ -1,236 +0,0 @@ -_data/ - -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ diff --git a/src/Examples/OperationsExample/Controllers/OperationsController.cs b/src/Examples/OperationsExample/Controllers/OperationsController.cs deleted file mode 100644 index 6e56791f9c..0000000000 --- a/src/Examples/OperationsExample/Controllers/OperationsController.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JsonApiDotNetCore.Controllers; -using JsonApiDotNetCore.Services.Operations; -using Microsoft.AspNetCore.Mvc; - -namespace OperationsExample.Controllers -{ - [Route("api/bulk")] - public class OperationsController : JsonApiOperationsController - { - public OperationsController(IOperationsProcessor processor) - : base(processor) - { } - } -} diff --git a/src/Examples/OperationsExample/OperationsExample.csproj b/src/Examples/OperationsExample/OperationsExample.csproj deleted file mode 100644 index efb3f2b3d4..0000000000 --- a/src/Examples/OperationsExample/OperationsExample.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - $(NetCoreAppVersion) - true - OperationsExample - Exe - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Examples/OperationsExample/Program.cs b/src/Examples/OperationsExample/Program.cs deleted file mode 100644 index 1c2b6b267a..0000000000 --- a/src/Examples/OperationsExample/Program.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; - -namespace OperationsExample -{ - public class Program - { - public static void Main(string[] args) => BuildWebHost(args).Run(); - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .Build(); - } -} diff --git a/src/Examples/OperationsExample/Properties/launchSettings.json b/src/Examples/OperationsExample/Properties/launchSettings.json deleted file mode 100644 index b0d8e5bd4b..0000000000 --- a/src/Examples/OperationsExample/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:53656/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "OperationsExample": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:53657/" - } - } -} \ No newline at end of file diff --git a/src/Examples/OperationsExample/Startup.cs b/src/Examples/OperationsExample/Startup.cs deleted file mode 100644 index a889ad85d6..0000000000 --- a/src/Examples/OperationsExample/Startup.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCoreExample.Data; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace OperationsExample -{ - public class Startup - { - public readonly IConfiguration Config; - - public Startup(IHostingEnvironment env) - { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddEnvironmentVariables(); - - Config = builder.Build(); - } - - public virtual IServiceProvider ConfigureServices(IServiceCollection services) - { - var loggerFactory = new LoggerFactory(); - loggerFactory.AddConsole(LogLevel.Warning); - - services.AddSingleton(loggerFactory); - - services.AddDbContext(options => options.UseNpgsql(GetDbConnectionString()), ServiceLifetime.Scoped); - - services.AddJsonApi(opt => opt.EnableOperations = true); - - return services.BuildServiceProvider(); - } - - public virtual void Configure( - IApplicationBuilder app, - IHostingEnvironment env, - ILoggerFactory loggerFactory, - AppDbContext context) - { - context.Database.EnsureCreated(); - - loggerFactory.AddConsole(Config.GetSection("Logging")); - app.UseJsonApi(); - } - - public string GetDbConnectionString() => Config["Data:DefaultConnection"]; - } -} diff --git a/src/Examples/OperationsExample/appsettings.json b/src/Examples/OperationsExample/appsettings.json deleted file mode 100644 index 73030b1743..0000000000 --- a/src/Examples/OperationsExample/appsettings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Data": { - "DefaultConnection": "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Warning", - "System": "Warning", - "Microsoft": "Warning" - } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs b/src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs deleted file mode 100644 index 48d280f5cb..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Controllers/CoursesController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Controllers; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Services; -using JsonApiDotNetCoreExample.Models.Resources; -using Microsoft.Extensions.Logging; - -namespace ResourceEntitySeparationExample.Controllers -{ - public class CoursesController : JsonApiController - { - public CoursesController( - IJsonApiOptions jsonApiOptions, - IResourceGraph resourceGraph, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiOptions, resourceGraph, resourceService, loggerFactory) - { } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs b/src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs deleted file mode 100644 index 63310743ac..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Controllers/DepartmentsController.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Controllers; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Services; -using JsonApiDotNetCoreExample.Models.Resources; -using Microsoft.Extensions.Logging; - -namespace ResourceEntitySeparationExample.Controllers -{ - public class DepartmentsController : JsonApiController - { - public DepartmentsController( - IJsonApiOptions jsonApiOptions, - IResourceGraph resourceGraph, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiOptions, resourceGraph, resourceService, loggerFactory) - { } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs b/src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs deleted file mode 100644 index 5f3551849a..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Controllers/StudentsController.cs +++ /dev/null @@ -1,20 +0,0 @@ -using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Controllers; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Services; -using JsonApiDotNetCoreExample.Models.Resources; -using Microsoft.Extensions.Logging; - -namespace ResourceEntitySeparationExample.Controllers -{ - public class StudentsController : JsonApiController - { - public StudentsController( - IJsonApiOptions jsonApiOptions, - IResourceGraph resourceGraph, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiOptions, resourceGraph, resourceService, loggerFactory) - { } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Models/AutoMapperAdapter.cs b/src/Examples/ResourceEntitySeparationExample/Models/AutoMapperAdapter.cs deleted file mode 100644 index 732b45babb..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Models/AutoMapperAdapter.cs +++ /dev/null @@ -1,25 +0,0 @@ -using AutoMapper; -using JsonApiDotNetCore.Models; - -namespace ResourceEntitySeparationExample.Models -{ - public class AutoMapperAdapter : IResourceMapper - { - private readonly IMapper _mapper; - - public AutoMapperAdapter(IMapper mapper) - { - _mapper = mapper; - } - - public TDestination Map(object source) - { - return _mapper.Map(source); - } - - public TDestination Map(TSource source) - { - return _mapper.Map(source); - } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Profiles/CourseProfile.cs b/src/Examples/ResourceEntitySeparationExample/Profiles/CourseProfile.cs deleted file mode 100644 index cc817045af..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Profiles/CourseProfile.cs +++ /dev/null @@ -1,40 +0,0 @@ -using AutoMapper; -using JsonApiDotNetCoreExample.Models.Entities; -using JsonApiDotNetCoreExample.Models.Resources; -using System.Collections.Generic; - -namespace ResourceEntitySeparationExample.Profiles -{ - public class CourseProfile : Profile - { - public CourseProfile() - { - CreateMap() - .ForMember(r => r.Students, opt => opt.MapFrom(e => StudentsFromRegistrations(e.Students))) - .ForMember(r => r.Department, opt => opt.MapFrom(e => new DepartmentResource - { - Id = e.Department.Id, - Name = e.Department.Name - })); - - CreateMap(); - } - - private ICollection StudentsFromRegistrations(ICollection registrations) - { - ICollection students = new HashSet(); - foreach(CourseStudentEntity reg in registrations) - { - StudentEntity e = reg.Student; - students.Add(new StudentResource - { - Id = e.Id, - FirstName = e.FirstName, - LastName = e.LastName, - Address = e.Address - }); - } - return students.Count == 0 ? null : students; - } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Profiles/DepartmentProfile.cs b/src/Examples/ResourceEntitySeparationExample/Profiles/DepartmentProfile.cs deleted file mode 100644 index c8f26fd125..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Profiles/DepartmentProfile.cs +++ /dev/null @@ -1,14 +0,0 @@ -using AutoMapper; -using JsonApiDotNetCoreExample.Models.Entities; -using JsonApiDotNetCoreExample.Models.Resources; - -namespace ResourceEntitySeparationExample.Profiles -{ - public class DepartmentProfile : Profile - { - public DepartmentProfile() - { - CreateMap(); - } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Profiles/StudentProfile.cs b/src/Examples/ResourceEntitySeparationExample/Profiles/StudentProfile.cs deleted file mode 100644 index 160f64c79a..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Profiles/StudentProfile.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using AutoMapper; -using JsonApiDotNetCoreExample.Models.Entities; -using JsonApiDotNetCoreExample.Models.Resources; - -namespace ResourceEntitySeparationExample.Profiles -{ - public class StudentProfile : Profile - { - public StudentProfile() - { - CreateMap() - .ForMember(d => d.Courses, opt => opt.MapFrom(e => CoursesFromRegistrations(e.Courses))); - - CreateMap(); - } - - private ICollection CoursesFromRegistrations(ICollection registrations) - { - ICollection courses = new HashSet(); - foreach (CourseStudentEntity reg in registrations) - { - CourseEntity e = reg.Course; - courses.Add(new CourseResource - { - Id = e.Id, - Number = e.Number, - Title = e.Title, - Description = e.Description - }); - } - return courses.Count == 0 ? null : courses; - } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Program.cs b/src/Examples/ResourceEntitySeparationExample/Program.cs deleted file mode 100644 index 3af82b653a..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Program.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; - -namespace ResourceEntitySeparationExample -{ - public class Program - { - public static void Main(string[] args) => BuildWebHost(args).Run(); - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .Build(); - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/Properties/launchSettings.json b/src/Examples/ResourceEntitySeparationExample/Properties/launchSettings.json deleted file mode 100644 index a51fc0dc79..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Properties/launchSettings.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:57181/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "api/v1/students", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "ResourceEntitySeparationExample": { - "commandName": "Project", - "environmentVariables": {} - } - } -} \ No newline at end of file diff --git a/src/Examples/ResourceEntitySeparationExample/ResourceEntitySeparationExample.csproj b/src/Examples/ResourceEntitySeparationExample/ResourceEntitySeparationExample.csproj deleted file mode 100644 index fa6088fa63..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/ResourceEntitySeparationExample.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netcoreapp2.0 - - - - - - - - - - - - diff --git a/src/Examples/ResourceEntitySeparationExample/Startup.cs b/src/Examples/ResourceEntitySeparationExample/Startup.cs deleted file mode 100644 index f87dea6935..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/Startup.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using AutoMapper; -using JsonApiDotNetCore.Data; -using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Services; -using JsonApiDotNetCoreExample.Data; -using JsonApiDotNetCoreExample.Models.Entities; -using JsonApiDotNetCoreExample.Models.Resources; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using ResourceEntitySeparationExample.Models; - -namespace ResourceEntitySeparationExample -{ - public class Startup - { - public readonly IConfiguration Config; - - public Startup(IHostingEnvironment env) - { - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - - Config = builder.Build(); - } - - public virtual IServiceProvider ConfigureServices(IServiceCollection services) - { - var loggerFactory = new LoggerFactory(); - loggerFactory.AddConsole(LogLevel.Warning); - services.AddSingleton(loggerFactory); - - services.AddDbContext(options => options - .UseNpgsql(GetDbConnectionString()), - ServiceLifetime.Transient); - services.AddScoped>(); - - - services.AddJsonApi(options => { - options.Namespace = "api/v1"; - options.DefaultPageSize = 10; - options.IncludeTotalRecordCount = true; - options.EnableResourceHooks = false; // not supported with ResourceEntitySeparation - options.BuildResourceGraph((builder) => - { - builder.AddResource("courses"); - builder.AddResource("departments"); - builder.AddResource("students"); - }); - }); - - services.AddAutoMapper(); - services.AddScoped(); - - services.AddScoped, EntityResourceService>(); - services.AddScoped, EntityResourceService>(); - services.AddScoped, EntityResourceService>(); - - var provider = services.BuildServiceProvider(); - var appContext = provider.GetRequiredService(); - if (appContext == null) - throw new ArgumentException(); - - return provider; - } - - public virtual void Configure( - IApplicationBuilder app, - IHostingEnvironment env, - ILoggerFactory loggerFactory, - AppDbContext context) - { - context.Database.EnsureCreated(); - loggerFactory.AddConsole(Config.GetSection("Logging")); - app.UseJsonApi(); - } - - public string GetDbConnectionString() => Config["Data:DefaultConnection"]; - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/appsettings.Development.json b/src/Examples/ResourceEntitySeparationExample/appsettings.Development.json deleted file mode 100644 index e203e9407e..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/src/Examples/ResourceEntitySeparationExample/appsettings.json b/src/Examples/ResourceEntitySeparationExample/appsettings.json deleted file mode 100644 index dc8fc4fae6..0000000000 --- a/src/Examples/ResourceEntitySeparationExample/appsettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Data": { - "DefaultConnection": "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Warning", - "Microsoft.EntityFrameworkCore.Database.Command": "Information" - } - } -} diff --git a/test/OperationsExampleTests/OperationsExampleTests.csproj b/test/OperationsExampleTests/OperationsExampleTests.csproj index f84b550354..c2ab5b84dd 100644 --- a/test/OperationsExampleTests/OperationsExampleTests.csproj +++ b/test/OperationsExampleTests/OperationsExampleTests.csproj @@ -13,7 +13,6 @@ - diff --git a/test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj b/test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj index cfa496283e..5a79c7b9d3 100644 --- a/test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj +++ b/test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj @@ -12,7 +12,6 @@ - From 54ff111f41c7f751c86084afe5ce07a314fb0ee9 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 10 Oct 2019 12:52:41 +0200 Subject: [PATCH 2/7] chore: remove bulk related code --- .../Configuration/JsonApiOptions.cs | 11 - .../JsonApiOperationsController.cs | 60 ---- .../IServiceCollectionExtensions.cs | 20 -- .../Formatters/JsonApiReader.cs | 14 - .../ResourceIdentifierObject.cs | 10 +- .../Models/Operations/Operation.cs | 82 ----- .../Models/Operations/OperationCode.cs | 14 - .../Models/Operations/OperationsDocument.cs | 17 - .../Models/Operations/Params.cs | 13 - .../Models/Operations/ResourceReference.cs | 10 - .../Contracts/ICurrentRequest.cs | 1 - .../Serialization/IOperationsDeserializer.cs | 11 - .../Serialization/OperationsDeserializer.cs | 299 ------------------ .../Services/IJsonApiContext.cs | 58 ---- .../Services/Operations/IOpProcessor.cs | 10 - .../Operations/OperationProcessorResolver.cs | 115 ------- .../Operations/OperationsProcessor.cs | 165 ---------- .../Processors/CreateOpProcessor.cs | 80 ----- .../Operations/Processors/GetOpProcessor.cs | 172 ---------- .../Processors/RemoveOpProcessor.cs | 63 ---- .../Processors/UpdateOpProcessor.cs | 73 ----- 21 files changed, 1 insertion(+), 1297 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs delete mode 100644 src/JsonApiDotNetCore/Models/Operations/Operation.cs delete mode 100644 src/JsonApiDotNetCore/Models/Operations/OperationCode.cs delete mode 100644 src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs delete mode 100644 src/JsonApiDotNetCore/Models/Operations/Params.cs delete mode 100644 src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs delete mode 100644 src/JsonApiDotNetCore/Serialization/IOperationsDeserializer.cs delete mode 100644 src/JsonApiDotNetCore/Serialization/OperationsDeserializer.cs delete mode 100644 src/JsonApiDotNetCore/Services/IJsonApiContext.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs delete mode 100644 src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index 967bb4c617..2b3e9bae21 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -131,17 +131,6 @@ public class JsonApiOptions : IJsonApiOptions public NullAttributeResponseBehavior NullAttributeResponseBehavior { get; set; } public DefaultAttributeResponseBehavior DefaultAttributeResponseBehavior { get; set; } - /// - /// Whether or not to allow json:api v1.1 operation requests. - /// This is a beta feature and there may be breaking changes - /// in subsequent releases. For now, ijt should be considered - /// experimental. - /// - /// - /// This will be enabled by default in a subsequent patch JsonApiDotNetCore v2.2.x - /// - public bool EnableOperations { get; set; } - /// /// Whether or not to validate model state. /// diff --git a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs b/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs deleted file mode 100644 index f6db9f0d06..0000000000 --- a/src/JsonApiDotNetCore/Controllers/JsonApiOperationsController.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Threading.Tasks; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Services.Operations; -using Microsoft.AspNetCore.Mvc; - -namespace JsonApiDotNetCore.Controllers -{ - /// - /// A controller to be used for bulk operations as defined in the json:api 1.1 specification - /// - public class JsonApiOperationsController : ControllerBase - { - private readonly IOperationsProcessor _operationsProcessor; - - /// - /// The processor to handle bulk operations. - /// - public JsonApiOperationsController(IOperationsProcessor operationsProcessor) - { - _operationsProcessor = operationsProcessor; - } - - /// - /// Bulk endpoint for json:api operations - /// - /// - /// A json:api operations request document - /// - /// - /// - /// PATCH /api/bulk HTTP/1.1 - /// Content-Type: application/vnd.api+json - /// - /// { - /// "operations": [{ - /// "op": "add", - /// "ref": { - /// "type": "authors" - /// }, - /// "data": { - /// "type": "authors", - /// "attributes": { - /// "name": "jaredcnance" - /// } - /// } - /// }] - /// } - /// - /// - [HttpPatch] - public virtual async Task PatchAsync([FromBody] OperationsDocument doc) - { - if (doc == null) return new StatusCodeResult(422); - - var results = await _operationsProcessor.ProcessAsync(doc.Operations); - - return Ok(new OperationsDocument(results)); - } - } -} diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index 23d36a6d1e..f4d7be5f77 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -213,7 +213,6 @@ public static void AddJsonApiInternals( services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -264,25 +263,6 @@ public static void AddClientSerialization(this IServiceCollection services) } - private static void AddOperationServices(IServiceCollection services) - { - services.AddScoped(); - - services.AddScoped(typeof(ICreateOpProcessor<>), typeof(CreateOpProcessor<>)); - services.AddScoped(typeof(ICreateOpProcessor<,>), typeof(CreateOpProcessor<,>)); - - services.AddScoped(typeof(IGetOpProcessor<>), typeof(GetOpProcessor<>)); - services.AddScoped(typeof(IGetOpProcessor<,>), typeof(GetOpProcessor<,>)); - - services.AddScoped(typeof(IRemoveOpProcessor<>), typeof(RemoveOpProcessor<>)); - services.AddScoped(typeof(IRemoveOpProcessor<,>), typeof(RemoveOpProcessor<,>)); - - services.AddScoped(typeof(IUpdateOpProcessor<>), typeof(UpdateOpProcessor<>)); - services.AddScoped(typeof(IUpdateOpProcessor<,>), typeof(UpdateOpProcessor<,>)); - - services.AddScoped(); - } - public static void SerializeAsJsonApi(this MvcOptions options, JsonApiOptions jsonApiOptions) { options.InputFormatters.Insert(0, new JsonApiInputFormatter()); diff --git a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs index 592c46256e..c51af2c5b6 100644 --- a/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs +++ b/src/JsonApiDotNetCore/Formatters/JsonApiReader.cs @@ -5,7 +5,6 @@ using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Managers.Contracts; using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Serialization.Deserializer; using JsonApiDotNetCore.Serialization.Server; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.Logging; @@ -15,19 +14,13 @@ namespace JsonApiDotNetCore.Formatters /// public class JsonApiReader : IJsonApiReader { - private readonly IOperationsDeserializer _operationsDeserializer; private readonly IJsonApiDeserializer _deserializer; - private readonly ICurrentRequest _currentRequest; private readonly ILogger _logger; public JsonApiReader(IJsonApiDeserializer deserializer, - IOperationsDeserializer operationsDeserializer, - ICurrentRequest currentRequest, ILoggerFactory loggerFactory) { _deserializer = deserializer; - _operationsDeserializer = operationsDeserializer; - _currentRequest = currentRequest; _logger = loggerFactory.CreateLogger(); } @@ -44,12 +37,6 @@ public Task ReadAsync(InputFormatterContext context) { var body = GetRequestBody(context.HttpContext.Request.Body); - if (_currentRequest.IsBulkRequest) - { - var operations = _operationsDeserializer.Deserialize(body); - return InputFormatterResult.SuccessAsync(operations); - } - object model = _deserializer.Deserialize(body); if (model == null) @@ -115,7 +102,6 @@ private bool CheckForId(IList modelList) } } return false; - } private string GetRequestBody(Stream body) diff --git a/src/JsonApiDotNetCore/Models/JsonApiDocuments/ResourceIdentifierObject.cs b/src/JsonApiDotNetCore/Models/JsonApiDocuments/ResourceIdentifierObject.cs index aac5af98be..939cae0820 100644 --- a/src/JsonApiDotNetCore/Models/JsonApiDocuments/ResourceIdentifierObject.cs +++ b/src/JsonApiDotNetCore/Models/JsonApiDocuments/ResourceIdentifierObject.cs @@ -17,14 +17,6 @@ public ResourceIdentifierObject(string type, string id) [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore, Order = -2)] public string Id { get; set; } - [JsonIgnore] - //[JsonProperty("lid")] - public string LocalId { get; set; } - - - public override string ToString() - { - return $"(type: {Type}, id: {Id})"; - } + public override string ToString() => $"(type: {Type}, id: {Id})"; } } diff --git a/src/JsonApiDotNetCore/Models/Operations/Operation.cs b/src/JsonApiDotNetCore/Models/Operations/Operation.cs deleted file mode 100644 index be6310c0da..0000000000 --- a/src/JsonApiDotNetCore/Models/Operations/Operation.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Collections.Generic; -using JsonApiDotNetCore.Models.Links; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Linq; - -namespace JsonApiDotNetCore.Models.Operations -{ - public class Operation - { - [JsonProperty("links", NullValueHandling = NullValueHandling.Ignore)] - public TopLevelLinks Links { get; set; } - - [JsonProperty("included", NullValueHandling = NullValueHandling.Ignore)] - public List Included { get; set; } - - [JsonProperty("meta", NullValueHandling = NullValueHandling.Ignore)] - public Dictionary Meta { get; set; } - - [JsonProperty("op"), JsonConverter(typeof(StringEnumConverter))] - public OperationCode Op { get; set; } - - [JsonProperty("ref", NullValueHandling = NullValueHandling.Ignore)] - public ResourceReference Ref { get; set; } - - [JsonProperty("params", NullValueHandling = NullValueHandling.Ignore)] - public Params Params { get; set; } - - [JsonProperty("data")] - public object Data - { - get - { - if (DataIsList) return DataList; - return DataObject; - } - set => SetData(value); - } - - private void SetData(object data) - { - if (data is JArray jArray) - { - DataIsList = true; - DataList = jArray.ToObject>(); - } - else if (data is List dataList) - { - DataIsList = true; - DataList = dataList; - } - else if (data is JObject jObject) - { - DataObject = jObject.ToObject(); - } - else if (data is ResourceObject dataObject) - { - DataObject = dataObject; - } - } - - [JsonIgnore] - public bool DataIsList { get; private set; } - - [JsonIgnore] - public List DataList { get; private set; } - - [JsonIgnore] - public ResourceObject DataObject { get; private set; } - - public string GetResourceTypeName() - { - if (Ref != null) - return Ref.Type?.ToString(); - - if (DataIsList) - return DataList[0].Type?.ToString(); - - return DataObject.Type?.ToString(); - } - } -} diff --git a/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs b/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs deleted file mode 100644 index 6b6905cd59..0000000000 --- a/src/JsonApiDotNetCore/Models/Operations/OperationCode.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace JsonApiDotNetCore.Models.Operations -{ - [JsonConverter(typeof(StringEnumConverter))] - public enum OperationCode - { - get = 1, - add = 2, - update = 3, - remove = 4 - } -} diff --git a/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs b/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs deleted file mode 100644 index 3228e9ca88..0000000000 --- a/src/JsonApiDotNetCore/Models/Operations/OperationsDocument.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace JsonApiDotNetCore.Models.Operations -{ - public class OperationsDocument - { - public OperationsDocument() { } - public OperationsDocument(List operations) - { - Operations = operations; - } - - [JsonProperty("operations")] - public List Operations { get; set; } - } -} diff --git a/src/JsonApiDotNetCore/Models/Operations/Params.cs b/src/JsonApiDotNetCore/Models/Operations/Params.cs deleted file mode 100644 index 470e8f4aa3..0000000000 --- a/src/JsonApiDotNetCore/Models/Operations/Params.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace JsonApiDotNetCore.Models.Operations -{ - public class Params - { - public List Include { get; set; } - public List Sort { get; set; } - public Dictionary Filter { get; set; } - public string Page { get; set; } - public Dictionary Fields { get; set; } - } -} diff --git a/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs b/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs deleted file mode 100644 index 5291d61a19..0000000000 --- a/src/JsonApiDotNetCore/Models/Operations/ResourceReference.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace JsonApiDotNetCore.Models.Operations -{ - public class ResourceReference : ResourceIdentifierObject - { - [JsonProperty("relationship")] - public string Relationship { get; set; } - } -} diff --git a/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs b/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs index 515ef454f8..fdaab75d6b 100644 --- a/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs +++ b/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs @@ -49,7 +49,6 @@ public interface ICurrentRequest : IQueryRequest /// Which query params are filtered /// QueryParams DisabledQueryParams { get; set; } - bool IsBulkRequest { get; set; } } } diff --git a/src/JsonApiDotNetCore/Serialization/IOperationsDeserializer.cs b/src/JsonApiDotNetCore/Serialization/IOperationsDeserializer.cs deleted file mode 100644 index bc6c2f7726..0000000000 --- a/src/JsonApiDotNetCore/Serialization/IOperationsDeserializer.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using JsonApiDotNetCore.Models; - -namespace JsonApiDotNetCore.Serialization.Deserializer -{ - public interface IOperationsDeserializer - { - object Deserialize(string body); - object DocumentToObject(ResourceObject data, List included = null); - } -} diff --git a/src/JsonApiDotNetCore/Serialization/OperationsDeserializer.cs b/src/JsonApiDotNetCore/Serialization/OperationsDeserializer.cs deleted file mode 100644 index 07cb4489c5..0000000000 --- a/src/JsonApiDotNetCore/Serialization/OperationsDeserializer.cs +++ /dev/null @@ -1,299 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using JsonApiDotNetCore.Extensions; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Models.Operations; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace JsonApiDotNetCore.Serialization.Deserializer -{ - /// - /// Legacy document parser to be used for Bulk requests. - /// Will probably remove this for v4. - /// - public class OperationsDeserializer : IOperationsDeserializer - { - private readonly ITargetedFields _targetedFieldsManager; - private readonly IResourceGraph _resourceGraph; - private readonly JsonSerializer _jsonSerializer; - - public OperationsDeserializer(ITargetedFields updatedFieldsManager, - IResourceGraph resourceGraph) - { - _targetedFieldsManager = updatedFieldsManager; - _resourceGraph = resourceGraph; - } - - public object Deserialize(string requestBody) - { - try - { - JToken bodyJToken; - using (JsonReader jsonReader = new JsonTextReader(new StringReader(requestBody))) - { - jsonReader.DateParseHandling = DateParseHandling.None; - bodyJToken = JToken.Load(jsonReader); - } - var operations = JsonConvert.DeserializeObject(requestBody); - if (operations == null) - throw new JsonApiException(400, "Failed to deserialize operations request."); - - return operations; - } - catch (JsonApiException) - { - throw; - } - catch (Exception e) - { - throw new JsonApiException(400, "Failed to deserialize request body", e); - } - } - - public object DocumentToObject(ResourceObject data, List included = null) - { - if (data == null) - throw new JsonApiException(422, "Failed to deserialize document as json:api."); - - var contextEntity = _resourceGraph.GetContextEntity(data.Type?.ToString()); - if (contextEntity == null) - { - throw new JsonApiException(400, - message: $"This API does not contain a json:api resource named '{data.Type}'.", - detail: "This resource is not registered on the ResourceGraph. " - + "If you are using Entity Framework, make sure the DbSet matches the expected resource name. " - + "If you have manually registered the resource, check that the call to AddResource correctly sets the public name."); - } - - - var entity = Activator.CreateInstance(contextEntity.EntityType); - - entity = SetEntityAttributes(entity, contextEntity, data.Attributes); - entity = SetRelationships(entity, contextEntity, data.Relationships, included); - - var identifiableEntity = (IIdentifiable)entity; - - if (data.Id != null) - identifiableEntity.StringId = data.Id?.ToString(); - - return identifiableEntity; - } - - private object SetEntityAttributes( - object entity, ContextEntity contextEntity, Dictionary attributeValues) - { - if (attributeValues == null || attributeValues.Count == 0) - return entity; - - foreach (var attr in contextEntity.Attributes) - { - if (attributeValues.TryGetValue(attr.PublicAttributeName, out object newValue)) - { - if (attr.IsImmutable) - continue; - var convertedValue = ConvertAttrValue(newValue, attr.PropertyInfo.PropertyType); - attr.SetValue(entity, convertedValue); - _targetedFieldsManager.Attributes.Add(attr); - } - } - - return entity; - } - - private object ConvertAttrValue(object newValue, Type targetType) - { - if (newValue is JContainer jObject) - return DeserializeComplexType(jObject, targetType); - - var convertedValue = TypeHelper.ConvertType(newValue, targetType); - return convertedValue; - } - - private object DeserializeComplexType(JContainer obj, Type targetType) - { - return obj.ToObject(targetType, _jsonSerializer); - } - - private object SetRelationships( - object entity, - ContextEntity contextEntity, - Dictionary relationships, - List included = null) - { - if (relationships == null || relationships.Count == 0) - return entity; - - var entityProperties = entity.GetType().GetProperties(); - - foreach (var attr in contextEntity.Relationships) - { - entity = attr.IsHasOne - ? SetHasOneRelationship(entity, entityProperties, (HasOneAttribute)attr, contextEntity, relationships, included) - : SetHasManyRelationship(entity, entityProperties, (HasManyAttribute)attr, contextEntity, relationships, included); - } - - return entity; - } - - private object SetHasOneRelationship(object entity, - PropertyInfo[] entityProperties, - HasOneAttribute attr, - ContextEntity contextEntity, - Dictionary relationships, - List included = null) - { - var relationshipName = attr.PublicRelationshipName; - - if (relationships.TryGetValue(relationshipName, out RelationshipEntry relationshipData) == false) - return entity; - - var rio = (ResourceIdentifierObject)relationshipData.Data; - - var foreignKey = attr.IdentifiablePropertyName; - var foreignKeyProperty = entityProperties.FirstOrDefault(p => p.Name == foreignKey); - if (foreignKeyProperty == null && rio == null) - return entity; - - SetHasOneForeignKeyValue(entity, attr, foreignKeyProperty, rio); - SetHasOneNavigationPropertyValue(entity, attr, rio, included); - - // recursive call ... - if (included != null) - { - var navigationPropertyValue = attr.GetValue(entity); - - var resourceGraphEntity = _resourceGraph.GetContextEntity(attr.DependentType); - if (navigationPropertyValue != null && resourceGraphEntity != null) - - { - var includedResource = included.SingleOrDefault(r => r.Type == rio.Type && r.Id == rio.Id); - if (includedResource != null) - SetRelationships(navigationPropertyValue, resourceGraphEntity, includedResource.Relationships, included); - } - } - - return entity; - } - - private void SetHasOneForeignKeyValue(object entity, HasOneAttribute hasOneAttr, PropertyInfo foreignKeyProperty, ResourceIdentifierObject rio) - { - var foreignKeyPropertyValue = rio?.Id ?? null; - if (foreignKeyProperty != null) - { - // in the case of the HasOne independent side of the relationship, we should still create the shell entity on the other side - // we should not actually require the resource to have a foreign key (be the dependent side of the relationship) - - // e.g. PATCH /articles - // {... { "relationships":{ "Owner": { "data": null } } } } - bool foreignKeyPropertyIsNullableType = Nullable.GetUnderlyingType(foreignKeyProperty.PropertyType) != null - || foreignKeyProperty.PropertyType == typeof(string); - if (rio == null && !foreignKeyPropertyIsNullableType) - throw new JsonApiException(400, $"Cannot set required relationship identifier '{hasOneAttr.IdentifiablePropertyName}' to null because it is a non-nullable type."); - - var convertedValue = TypeHelper.ConvertType(foreignKeyPropertyValue, foreignKeyProperty.PropertyType); - /// todo: as a part of the process of decoupling JADNC (specifically - /// through the decoupling IJsonApiContext), we now no longer need to - /// store the updated relationship values in this property. For now - /// just assigning null as value, will remove this property later as a whole. - /// see #512 - if (convertedValue == null) _targetedFieldsManager.Relationships.Add(hasOneAttr); - } - } - - /// - /// Sets the value of the navigation property for the related resource. - /// If the resource has been included, all attributes will be set. - /// If the resource has not been included, only the id will be set. - /// - private void SetHasOneNavigationPropertyValue(object entity, HasOneAttribute hasOneAttr, ResourceIdentifierObject rio, List included) - { - // if the resource identifier is null, there should be no reason to instantiate an instance - if (rio != null && rio.Id != null) - { - // we have now set the FK property on the resource, now we need to check to see if the - // related entity was included in the payload and update its attributes - var includedRelationshipObject = GetIncludedRelationship(rio, included, hasOneAttr); - if (includedRelationshipObject != null) - hasOneAttr.SetValue(entity, includedRelationshipObject); - - /// todo: as a part of the process of decoupling JADNC (specifically - /// through the decoupling IJsonApiContext), we now no longer need to - /// store the updated relationship values in this property. For now - /// just assigning null as value, will remove this property later as a whole. - /// see #512 - _targetedFieldsManager.Relationships.Add(hasOneAttr); - } - } - - private object SetHasManyRelationship(object entity, - PropertyInfo[] entityProperties, - HasManyAttribute attr, - ContextEntity contextEntity, - Dictionary relationships, - List included = null) - { - var relationshipName = attr.PublicRelationshipName; - - if (relationships.TryGetValue(relationshipName, out RelationshipEntry relationshipData)) - { - if (relationshipData.IsManyData == false) - return entity; - - var relatedResources = relationshipData.ManyData.Select(r => - { - var instance = GetIncludedRelationship(r, included, attr); - return instance; - }); - - var convertedCollection = TypeHelper.ConvertCollection(relatedResources, attr.DependentType); - - attr.SetValue(entity, convertedCollection); - _targetedFieldsManager.Relationships.Add(attr); - } - - return entity; - } - - private IIdentifiable GetIncludedRelationship(ResourceIdentifierObject relatedResourceIdentifier, List includedResources, RelationshipAttribute relationshipAttr) - { - // at this point we can be sure the relationshipAttr.Type is IIdentifiable because we were able to successfully build the ResourceGraph - var relatedInstance = relationshipAttr.DependentType.New(); - relatedInstance.StringId = relatedResourceIdentifier.Id; - - // can't provide any more data other than the rio since it is not contained in the included section - if (includedResources == null || includedResources.Count == 0) - return relatedInstance; - - var includedResource = GetLinkedResource(relatedResourceIdentifier, includedResources); - if (includedResource == null) - return relatedInstance; - - var contextEntity = _resourceGraph.GetContextEntity(relationshipAttr.DependentType); - if (contextEntity == null) - throw new JsonApiException(400, $"Included type '{relationshipAttr.DependentType}' is not a registered json:api resource."); - - SetEntityAttributes(relatedInstance, contextEntity, includedResource.Attributes); - - return relatedInstance; - } - - private ResourceObject GetLinkedResource(ResourceIdentifierObject relatedResourceIdentifier, List includedResources) - { - try - { - return includedResources.SingleOrDefault(r => r.Type == relatedResourceIdentifier.Type && r.Id == relatedResourceIdentifier.Id); - } - catch (InvalidOperationException e) - { - throw new JsonApiException(400, $"A compound document MUST NOT include more than one resource object for each type and id pair." - + $"The duplicate pair was '{relatedResourceIdentifier.Type}, {relatedResourceIdentifier.Id}'", e); - } - } - } -} \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs deleted file mode 100644 index 6cb2a96905..0000000000 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using JsonApiDotNetCore.Configuration; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Internal.Query; - -namespace JsonApiDotNetCore.Services -{ - public interface IJsonApiApplication - { - IJsonApiOptions Options { get; set; } - [Obsolete("Use standalone resourcegraph")] - IResourceGraph ResourceGraph { get; set; } - } - - public interface IQueryRequest - { - QuerySet QuerySet { get; set; } - } - - public interface IJsonApiRequest : IJsonApiApplication, IQueryRequest - { - /// - /// If the request is a bulk json:api v1.1 operations request. - /// This is determined by the ` - /// ` class. - /// - /// See [json-api/1254](https://github.com/json-api/json-api/pull/1254) for details. - /// - bool IsBulkOperationRequest { get; set; } - - /// - /// The ``for the target route. - /// - /// - /// - /// For a `GET /articles` request, `RequestEntity` will be set - /// to the `Article` resource representation on the `JsonApiContext`. - /// - ContextEntity RequestEntity { get; set; } - - /// - /// The concrete type of the controller that was activated by the MVC routing middleware - /// - Type ControllerType { get; set; } - - /// - /// The json:api meta data at the document level - /// - Dictionary DocumentMeta { get; set; } - - /// - /// If the request is on the `{id}/relationships/{relationshipName}` route - /// - bool IsRelationshipPath { get; } - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs deleted file mode 100644 index 0a2d30397c..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/IOpProcessor.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using JsonApiDotNetCore.Models.Operations; - -namespace JsonApiDotNetCore.Services.Operations -{ - public interface IOpProcessor - { - Task ProcessAsync(Operation operation); - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs b/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs deleted file mode 100644 index 41dc43a1f7..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/OperationProcessorResolver.cs +++ /dev/null @@ -1,115 +0,0 @@ -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Internal.Generics; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Services.Operations.Processors; - -namespace JsonApiDotNetCore.Services.Operations -{ - /// - /// Used to resolve at runtime based on the required operation - /// - public interface IOperationProcessorResolver - { - /// - /// Locates the correct - /// - IOpProcessor LocateCreateService(Operation operation); - - /// - /// Locates the correct - /// - IOpProcessor LocateGetService(Operation operation); - - /// - /// Locates the correct - /// - IOpProcessor LocateRemoveService(Operation operation); - - /// - /// Locates the correct - /// - IOpProcessor LocateUpdateService(Operation operation); - } - - /// - public class OperationProcessorResolver : IOperationProcessorResolver - { - private readonly IGenericProcessorFactory _processorFactory; - private readonly IContextEntityProvider _provider; - - /// - public OperationProcessorResolver( - IGenericProcessorFactory processorFactory, - IContextEntityProvider provider) - { - _processorFactory = processorFactory; - _provider = provider; - } - - /// - public IOpProcessor LocateCreateService(Operation operation) - { - var resource = operation.GetResourceTypeName(); - - var contextEntity = GetResourceMetadata(resource); - - var processor = _processorFactory.GetProcessor( - typeof(ICreateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType - ); - - return processor; - } - - /// - public IOpProcessor LocateGetService(Operation operation) - { - var resource = operation.GetResourceTypeName(); - - var contextEntity = GetResourceMetadata(resource); - - var processor = _processorFactory.GetProcessor( - typeof(IGetOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType - ); - - return processor; - } - - /// - public IOpProcessor LocateRemoveService(Operation operation) - { - var resource = operation.GetResourceTypeName(); - - var contextEntity = GetResourceMetadata(resource); - - var processor = _processorFactory.GetProcessor( - typeof(IRemoveOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType - ); - - return processor; - } - - /// - public IOpProcessor LocateUpdateService(Operation operation) - { - var resource = operation.GetResourceTypeName(); - - var contextEntity = GetResourceMetadata(resource); - - var processor = _processorFactory.GetProcessor( - typeof(IUpdateOpProcessor<,>), contextEntity.EntityType, contextEntity.IdentityType - ); - - return processor; - } - - private ContextEntity GetResourceMetadata(string resourceName) - { - var contextEntity = _provider.GetContextEntity(resourceName); - if(contextEntity == null) - throw new JsonApiException(400, $"This API does not expose a resource of type '{resourceName}'."); - - return contextEntity; - } - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs deleted file mode 100644 index fcbff7c613..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/OperationsProcessor.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using JsonApiDotNetCore.Data; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Managers.Contracts; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Models.Operations; -using Microsoft.EntityFrameworkCore; - -namespace JsonApiDotNetCore.Services.Operations -{ - public interface IOperationsProcessor - { - Task> ProcessAsync(List inputOps); - } - - public class OperationsProcessor : IOperationsProcessor - { - private readonly IOperationProcessorResolver _processorResolver; - private readonly DbContext _dbContext; - private readonly ICurrentRequest _currentRequest; - private readonly IResourceGraph _resourceGraph; - - public OperationsProcessor( - IOperationProcessorResolver processorResolver, - IDbContextResolver dbContextResolver, - ICurrentRequest currentRequest, - IResourceGraph resourceGraph) - { - _processorResolver = processorResolver; - _dbContext = dbContextResolver.GetContext(); - _currentRequest = currentRequest; - _resourceGraph = resourceGraph; - } - - public async Task> ProcessAsync(List inputOps) - { - var outputOps = new List(); - var opIndex = 0; - OperationCode? lastAttemptedOperation = null; // used for error messages only - - using (var transaction = await _dbContext.Database.BeginTransactionAsync()) - { - try - { - foreach (var op in inputOps) - { - //_jsonApiContext.BeginOperation(); - - lastAttemptedOperation = op.Op; - await ProcessOperation(op, outputOps); - opIndex++; - } - - transaction.Commit(); - return outputOps; - } - catch (JsonApiException e) - { - transaction.Rollback(); - throw new JsonApiException(e.GetStatusCode(), $"Transaction failed on operation[{opIndex}] ({lastAttemptedOperation}).", e); - } - catch (Exception e) - { - transaction.Rollback(); - throw new JsonApiException(500, $"Transaction failed on operation[{opIndex}] ({lastAttemptedOperation}) for an unexpected reason.", e); - } - } - } - - private async Task ProcessOperation(Operation op, List outputOps) - { - ReplaceLocalIdsInResourceObject(op.DataObject, outputOps); - ReplaceLocalIdsInRef(op.Ref, outputOps); - - string type = null; - if (op.Op == OperationCode.add || op.Op == OperationCode.update) - { - type = op.DataObject.Type; - } - else if (op.Op == OperationCode.get || op.Op == OperationCode.remove) - { - type = op.Ref.Type; - } - _currentRequest.SetRequestResource(_resourceGraph.GetEntityFromControllerName(type)); - - var processor = GetOperationsProcessor(op); - var resultOp = await processor.ProcessAsync(op); - - if (resultOp != null) - outputOps.Add(resultOp); - } - - private void ReplaceLocalIdsInResourceObject(ResourceObject resourceObject, List outputOps) - { - if (resourceObject == null) - return; - - // it is strange to me that a top level resource object might use a lid. - // by not replacing it, we avoid a case where the first operation is an 'add' with an 'lid' - // and we would be unable to locate the matching 'lid' in 'outputOps' - // - // we also create a scenario where I might try to update a resource I just created - // in this case, the 'data.id' will be null, but the 'ref.id' will be replaced by the correct 'id' from 'outputOps' - // - // if(HasLocalId(resourceObject)) - // resourceObject.Id = GetIdFromLocalId(outputOps, resourceObject.LocalId); - - if (resourceObject.Relationships != null) - { - foreach (var relationshipDictionary in resourceObject.Relationships) - { - if (relationshipDictionary.Value.IsManyData) - { - foreach (var relationship in relationshipDictionary.Value.ManyData) - if (HasLocalId(relationship)) - relationship.Id = GetIdFromLocalId(outputOps, relationship.LocalId); - } - else - { - var relationship = relationshipDictionary.Value.SingleData; - if (HasLocalId(relationship)) - relationship.Id = GetIdFromLocalId(outputOps, relationship.LocalId); - } - } - } - } - - private void ReplaceLocalIdsInRef(ResourceReference resourceRef, List outputOps) - { - if (resourceRef == null) return; - if (HasLocalId(resourceRef)) - resourceRef.Id = GetIdFromLocalId(outputOps, resourceRef.LocalId); - } - - private bool HasLocalId(ResourceIdentifierObject rio) => string.IsNullOrEmpty(rio.LocalId) == false; - - private string GetIdFromLocalId(List outputOps, string localId) - { - var referencedOp = outputOps.FirstOrDefault(o => o.DataObject.LocalId == localId); - if (referencedOp == null) throw new JsonApiException(400, $"Could not locate lid '{localId}' in document."); - return referencedOp.DataObject.Id; - } - - private IOpProcessor GetOperationsProcessor(Operation op) - { - switch (op.Op) - { - case OperationCode.add: - return _processorResolver.LocateCreateService(op); - case OperationCode.get: - return _processorResolver.LocateGetService(op); - case OperationCode.remove: - return _processorResolver.LocateRemoveService(op); - case OperationCode.update: - return _processorResolver.LocateUpdateService(op); - default: - throw new JsonApiException(400, $"'{op.Op}' is not a valid operation code"); - } - } - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs deleted file mode 100644 index 4eb5c65961..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/CreateOpProcessor.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Threading.Tasks; -using JsonApiDotNetCore.Builders; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Serialization.Deserializer; - -namespace JsonApiDotNetCore.Services.Operations.Processors -{ - public interface ICreateOpProcessor : ICreateOpProcessor - where T : class, IIdentifiable - { } - - public interface ICreateOpProcessor : IOpProcessor - where T : class, IIdentifiable - { } - - public class CreateOpProcessor - : CreateOpProcessor, ICreateOpProcessor - where T : class, IIdentifiable - { - public CreateOpProcessor( - ICreateService service, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph - ) : base(service, deserializer, documentBuilder, resourceGraph) - { } - } - - public interface IBaseDocumentBuilder - { - ResourceObject GetData(ContextEntity contextEntity, IIdentifiable singleResource); - } - - public class CreateOpProcessor : ICreateOpProcessor - where T : class, IIdentifiable - { - private readonly ICreateService _service; - private readonly IOperationsDeserializer _deserializer; - private readonly IBaseDocumentBuilder _documentBuilder; - private readonly IResourceGraph _resourceGraph; - - public CreateOpProcessor( - ICreateService service, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph) - { - _service = service; - _deserializer = deserializer; - _documentBuilder = documentBuilder; - _resourceGraph = resourceGraph; - } - - public async Task ProcessAsync(Operation operation) - { - - var model = (T)_deserializer.DocumentToObject(operation.DataObject); - var result = await _service.CreateAsync(model); - - var operationResult = new Operation - { - Op = OperationCode.add - }; - - operationResult.Data = _documentBuilder.GetData( - _resourceGraph.GetContextEntity(operation.GetResourceTypeName()), - result); - - // we need to persist the original request localId so that subsequent operations - // can locate the result of this operation by its localId - operationResult.DataObject.LocalId = operation.DataObject.LocalId; - - return null; - //return operationResult; - } - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs deleted file mode 100644 index ec2144bb77..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/GetOpProcessor.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using JsonApiDotNetCore.Builders; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Serialization.Deserializer; - -namespace JsonApiDotNetCore.Services.Operations.Processors -{ - /// - /// Handles all "" operations - /// - /// The resource type - public interface IGetOpProcessor : IGetOpProcessor - where T : class, IIdentifiable - { } - - /// - /// Handles all "" operations - /// - /// The resource type - /// The resource identifier type - public interface IGetOpProcessor : IOpProcessor - where T : class, IIdentifiable - { } - - /// - public class GetOpProcessor : GetOpProcessor, IGetOpProcessor - where T : class, IIdentifiable - { - /// - public GetOpProcessor( - IGetAllService getAll, - IGetByIdService getById, - IGetRelationshipService getRelationship, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph - ) : base(getAll, getById, getRelationship, deserializer, documentBuilder, resourceGraph) - { } - } - - /// - public class GetOpProcessor : IGetOpProcessor - where T : class, IIdentifiable - { - private readonly IGetAllService _getAll; - private readonly IGetByIdService _getById; - private readonly IGetRelationshipService _getRelationship; - private readonly IOperationsDeserializer _deserializer; - private readonly IBaseDocumentBuilder _documentBuilder; - private readonly IResourceGraph _resourceGraph; - - /// - public GetOpProcessor( - IGetAllService getAll, - IGetByIdService getById, - IGetRelationshipService getRelationship, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph) - { - _getAll = getAll; - _getById = getById; - _getRelationship = getRelationship; - _deserializer = deserializer; - _documentBuilder = documentBuilder; - _resourceGraph = resourceGraph; - } - - /// - public async Task ProcessAsync(Operation operation) - { - var operationResult = new Operation - { - Op = OperationCode.get - }; - - operationResult.Data = string.IsNullOrWhiteSpace(operation.Ref.Id) - ? await GetAllAsync(operation) - : string.IsNullOrWhiteSpace(operation.Ref.Relationship) - ? await GetByIdAsync(operation) - : await GetRelationshipAsync(operation); - - return operationResult; - } - - private async Task GetAllAsync(Operation operation) - { - var result = await _getAll.GetAsync(); - - var operations = new List(); - foreach (var resource in result) - { - var doc = _documentBuilder.GetData( - _resourceGraph.GetContextEntity(operation.GetResourceTypeName()), - resource); - operations.Add(doc); - } - - return operations; - } - - private async Task GetByIdAsync(Operation operation) - { - var id = GetReferenceId(operation); - var result = await _getById.GetAsync(id); - - // this is a bit ugly but we need to bomb the entire transaction if the entity cannot be found - // in the future it would probably be better to return a result status along with the doc to - // avoid throwing exceptions on 4xx errors. - // consider response type (status, document) - if (result == null) - throw new JsonApiException(404, $"Could not find '{operation.Ref.Type}' record with id '{operation.Ref.Id}'"); - - var doc = _documentBuilder.GetData( - _resourceGraph.GetContextEntity(operation.GetResourceTypeName()), - result); - - return doc; - } - - private async Task GetRelationshipAsync(Operation operation) - { - var id = GetReferenceId(operation); - var result = await _getRelationship.GetRelationshipAsync(id, operation.Ref.Relationship); - - // TODO: need a better way to get the ContextEntity from a relationship name - // when no generic parameter is available - var relationshipType = _resourceGraph.GetContextEntity(operation.GetResourceTypeName()) - .Relationships.Single(r => r.Is(operation.Ref.Relationship)).DependentType; - - var relatedContextEntity = _resourceGraph.GetContextEntity(relationshipType); - - if (result == null) - return null; - - if (result is IIdentifiable singleResource) - return GetData(relatedContextEntity, singleResource); - - if (result is IEnumerable multipleResults) - return GetData(relatedContextEntity, multipleResults); - - throw new JsonApiException(500, - $"An unexpected type was returned from '{_getRelationship.GetType()}.{nameof(IGetRelationshipService.GetRelationshipAsync)}'.", - detail: $"Type '{result.GetType()} does not implement {nameof(IIdentifiable)} nor {nameof(IEnumerable)}'"); - } - - private ResourceObject GetData(ContextEntity contextEntity, IIdentifiable singleResource) - { - return _documentBuilder.GetData(contextEntity, singleResource); - } - - private List GetData(ContextEntity contextEntity, IEnumerable multipleResults) - { - var resources = new List(); - foreach (var singleResult in multipleResults) - { - if (singleResult is IIdentifiable resource) - resources.Add(_documentBuilder.GetData(contextEntity, resource)); - } - - return resources; - } - - private TId GetReferenceId(Operation operation) => TypeHelper.ConvertType(operation.Ref.Id); - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs deleted file mode 100644 index c1c80d21fa..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/RemoveOpProcessor.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Threading.Tasks; -using JsonApiDotNetCore.Builders; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Serialization.Deserializer; - -namespace JsonApiDotNetCore.Services.Operations.Processors -{ - public interface IRemoveOpProcessor : IRemoveOpProcessor - where T : class, IIdentifiable - { } - - public interface IRemoveOpProcessor : IOpProcessor - where T : class, IIdentifiable - { } - - public class RemoveOpProcessor : RemoveOpProcessor, IRemoveOpProcessor - where T : class, IIdentifiable - { - public RemoveOpProcessor( - IDeleteService service, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph - ) : base(service, deserializer, documentBuilder, resourceGraph) - { } - } - - public class RemoveOpProcessor : IRemoveOpProcessor - where T : class, IIdentifiable - { - private readonly IDeleteService _service; - private readonly IOperationsDeserializer _deserializer; - private readonly IBaseDocumentBuilder _documentBuilder; - private readonly IResourceGraph _resourceGraph; - - public RemoveOpProcessor( - IDeleteService service, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph) - { - _service = service; - _deserializer = deserializer; - _documentBuilder = documentBuilder; - _resourceGraph = resourceGraph; - } - - public async Task ProcessAsync(Operation operation) - { - var stringId = operation.Ref?.Id?.ToString(); - if (string.IsNullOrWhiteSpace(stringId)) - throw new JsonApiException(400, "The ref.id parameter is required for remove operations"); - - var id = TypeHelper.ConvertType(stringId); - var result = await _service.DeleteAsync(id); - - return null; - } - } -} diff --git a/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs b/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs deleted file mode 100644 index 37d22d14f1..0000000000 --- a/src/JsonApiDotNetCore/Services/Operations/Processors/UpdateOpProcessor.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Threading.Tasks; -using JsonApiDotNetCore.Builders; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Internal.Contracts; -using JsonApiDotNetCore.Models; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCore.Serialization.Deserializer; - -namespace JsonApiDotNetCore.Services.Operations.Processors -{ - public interface IUpdateOpProcessor : IUpdateOpProcessor - where T : class, IIdentifiable - { } - - public interface IUpdateOpProcessor : IOpProcessor - where T : class, IIdentifiable - { } - - public class UpdateOpProcessor : UpdateOpProcessor, IUpdateOpProcessor - where T : class, IIdentifiable - { - public UpdateOpProcessor( - IUpdateService service, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph - ) : base(service, deserializer, documentBuilder, resourceGraph) - { } - } - - public class UpdateOpProcessor : IUpdateOpProcessor - where T : class, IIdentifiable - { - private readonly IUpdateService _service; - private readonly IOperationsDeserializer _deserializer; - private readonly IBaseDocumentBuilder _documentBuilder; - private readonly IResourceGraph _resourceGraph; - - public UpdateOpProcessor( - IUpdateService service, - IOperationsDeserializer deserializer, - IBaseDocumentBuilder documentBuilder, - IResourceGraph resourceGraph) - { - _service = service; - _deserializer = deserializer; - _documentBuilder = documentBuilder; - _resourceGraph = resourceGraph; - } - - public async Task ProcessAsync(Operation operation) - { - if (string.IsNullOrWhiteSpace(operation?.DataObject?.Id?.ToString())) - throw new JsonApiException(400, "The data.id parameter is required for replace operations"); - - //var model = (T)_deserializer.DocumentToObject(operation.DataObject); - T model = null; // TODO - - var result = await _service.UpdateAsync(model.Id, model); - if (result == null) - throw new JsonApiException(404, $"Could not find an instance of '{operation.DataObject.Type}' with id {operation.DataObject.Id}"); - - var operationResult = new Operation - { - Op = OperationCode.update - }; - - operationResult.Data = _documentBuilder.GetData(_resourceGraph.GetContextEntity(operation.GetResourceTypeName()), result); - - return operationResult; - } - } -} From e4a4d9c0fd6d7979925a8a69dc31f4751ad72f6f Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 10 Oct 2019 12:59:33 +0200 Subject: [PATCH 3/7] chore: remove bulk related tests --- JsonApiDotnetCore.sln | 15 - src/JsonApiDotNetCore/AssemblyInfo.cs | 1 - .../Configuration/IJsonApiOptions.cs | 1 - .../IServiceCollectionExtensions.cs | 9 - .../Hooks/Execution/ResourcePipelineEnum.cs | 5 +- .../Hooks/IResourceHookContainer.cs | 9 +- .../Middleware/RequestMiddleware.cs | 7 - .../Contracts/ICurrentRequest.cs | 2 +- .../RequestServices/CurrentRequest.cs | 1 - test/OperationsExampleTests/.gitignore | 234 -------------- test/OperationsExampleTests/Add/AddTests.cs | 294 ------------------ .../Factories/ArticleFactory.cs | 25 -- .../Factories/AuthorFactory.cs | 25 -- test/OperationsExampleTests/Fixture.cs | 60 ---- .../Get/GetByIdTests.cs | 78 ----- .../Get/GetRelationshipTests.cs | 87 ------ test/OperationsExampleTests/Get/GetTests.cs | 73 ----- .../OperationsExampleTests.csproj | 23 -- .../Remove/RemoveTests.cs | 85 ----- test/OperationsExampleTests/TestStartup.cs | 25 -- .../Transactions/TransactionFailureTests.cs | 80 ----- .../Update/UpdateTests.cs | 112 ------- test/OperationsExampleTests/appsettings.json | 15 - .../Serialization/DeserializerTestsSetup.cs | 1 - 24 files changed, 4 insertions(+), 1263 deletions(-) delete mode 100644 test/OperationsExampleTests/.gitignore delete mode 100644 test/OperationsExampleTests/Add/AddTests.cs delete mode 100644 test/OperationsExampleTests/Factories/ArticleFactory.cs delete mode 100644 test/OperationsExampleTests/Factories/AuthorFactory.cs delete mode 100644 test/OperationsExampleTests/Fixture.cs delete mode 100644 test/OperationsExampleTests/Get/GetByIdTests.cs delete mode 100644 test/OperationsExampleTests/Get/GetRelationshipTests.cs delete mode 100644 test/OperationsExampleTests/Get/GetTests.cs delete mode 100644 test/OperationsExampleTests/OperationsExampleTests.csproj delete mode 100644 test/OperationsExampleTests/Remove/RemoveTests.cs delete mode 100644 test/OperationsExampleTests/TestStartup.cs delete mode 100644 test/OperationsExampleTests/Transactions/TransactionFailureTests.cs delete mode 100644 test/OperationsExampleTests/Update/UpdateTests.cs delete mode 100644 test/OperationsExampleTests/appsettings.json diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index ac0721d13c..38e0bef4d4 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -35,8 +35,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoEntityFrameworkTests", "t EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "test\UnitTests\UnitTests.csproj", "{8788FF65-C2B6-40B2-A3A0-1E3D91C02664}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OperationsExampleTests", "test\OperationsExampleTests\OperationsExampleTests.csproj", "{65BF5960-3D9B-4230-99F4-A12CAA130792}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceEntitySeparationExampleTests", "test\ResourceEntitySeparationExampleTests\ResourceEntitySeparationExampleTests.csproj", "{778C4EB9-BD65-4C0F-9230-B5CB1D72186A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscoveryTests", "test\DiscoveryTests\DiscoveryTests.csproj", "{03032A2F-664D-4DD8-A82F-AD8A482EDD85}" @@ -127,18 +125,6 @@ Global {8788FF65-C2B6-40B2-A3A0-1E3D91C02664}.Release|x64.Build.0 = Release|Any CPU {8788FF65-C2B6-40B2-A3A0-1E3D91C02664}.Release|x86.ActiveCfg = Release|Any CPU {8788FF65-C2B6-40B2-A3A0-1E3D91C02664}.Release|x86.Build.0 = Release|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Debug|x64.ActiveCfg = Debug|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Debug|x64.Build.0 = Debug|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Debug|x86.ActiveCfg = Debug|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Debug|x86.Build.0 = Debug|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Release|Any CPU.ActiveCfg = Release|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Release|Any CPU.Build.0 = Release|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Release|x64.ActiveCfg = Release|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Release|x64.Build.0 = Release|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Release|x86.ActiveCfg = Release|Any CPU - {65BF5960-3D9B-4230-99F4-A12CAA130792}.Release|x86.Build.0 = Release|Any CPU {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|Any CPU.Build.0 = Debug|Any CPU {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -200,7 +186,6 @@ Global {CAF331F8-9255-4D72-A1A8-A54141E99F1E} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {4F15A8F8-5BC6-45A1-BC51-03F921B726A4} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {8788FF65-C2B6-40B2-A3A0-1E3D91C02664} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} - {65BF5960-3D9B-4230-99F4-A12CAA130792} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {778C4EB9-BD65-4C0F-9230-B5CB1D72186A} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {03032A2F-664D-4DD8-A82F-AD8A482EDD85} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {DF0FCFB2-CB12-44BA-BBB5-1BE0BCFCD14C} = {076E1AE4-FD25-4684-B826-CAAE37FEA0AA} diff --git a/src/JsonApiDotNetCore/AssemblyInfo.cs b/src/JsonApiDotNetCore/AssemblyInfo.cs index dc8b9ba84c..6fa08b113d 100644 --- a/src/JsonApiDotNetCore/AssemblyInfo.cs +++ b/src/JsonApiDotNetCore/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("OperationsExampleTests")] [assembly:InternalsVisibleTo("UnitTests")] [assembly:InternalsVisibleTo("JsonApiDotNetCoreExampleTests")] [assembly:InternalsVisibleTo("NoEntityFrameworkTests")] diff --git a/src/JsonApiDotNetCore/Configuration/IJsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/IJsonApiOptions.cs index 7fc46ba8ff..2fd5984118 100644 --- a/src/JsonApiDotNetCore/Configuration/IJsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/IJsonApiOptions.cs @@ -23,7 +23,6 @@ public interface IJsonApiOptions : ILinksConfiguration, ISerializerOptions int DefaultPageSize { get; } bool ValidateModelState { get; } bool AllowClientGeneratedIds { get; } - bool EnableOperations { get; set; } IResourceGraph ResourceGraph { get; set; } bool AllowCustomQueryParameters { get; set; } string Namespace { get; set; } diff --git a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs index f4d7be5f77..dfa3bc3124 100644 --- a/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs @@ -15,16 +15,12 @@ using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Hooks; using JsonApiDotNetCore.Services; -using JsonApiDotNetCore.Services.Operations; -using JsonApiDotNetCore.Services.Operations.Processors; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using JsonApiDotNetCore.Internal.Contracts; using JsonApiDotNetCore.Query; -using JsonApiDotNetCore.Serialization.Deserializer; -using JsonApiDotNetCore.Query; using JsonApiDotNetCore.Serialization.Server.Builders; using JsonApiDotNetCore.Serialization.Server; using JsonApiDotNetCore.Serialization.Client; @@ -161,11 +157,6 @@ public static void AddJsonApiInternals( services.AddSingleton(new DbContextOptionsBuilder().Options); } - if (jsonApiOptions.EnableOperations) - { - AddOperationServices(services); - } - services.AddScoped(typeof(IEntityRepository<>), typeof(DefaultEntityRepository<>)); services.AddScoped(typeof(IEntityRepository<,>), typeof(DefaultEntityRepository<,>)); diff --git a/src/JsonApiDotNetCore/Hooks/Execution/ResourcePipelineEnum.cs b/src/JsonApiDotNetCore/Hooks/Execution/ResourcePipelineEnum.cs index 177423ed4f..3f952c8f52 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/ResourcePipelineEnum.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/ResourcePipelineEnum.cs @@ -14,9 +14,6 @@ public enum ResourcePipeline Post, Patch, PatchRelationship, - Delete, - BulkPost, - BulkPatch, - BulkDelete + Delete } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs index 38d296f8f0..54d64142d2 100644 --- a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs +++ b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs @@ -24,8 +24,7 @@ public interface IBeforeHooks where TResource : class, IIdentifiable /// layer just before creation of entities of type . /// /// For the pipeline, - /// will typically contain one entry. For , - /// can contain multiple entities. + /// will typically contain one entry. /// /// The returned may be a subset /// of , in which case the operation of the @@ -55,8 +54,6 @@ public interface IBeforeHooks where TResource : class, IIdentifiable /// /// For the pipeline, the /// will typically contain one entity. - /// For , this it may contain - /// multiple entities. /// /// The returned may be a subset /// of the property in parameter , @@ -65,7 +62,7 @@ public interface IBeforeHooks where TResource : class, IIdentifiable /// changes of the properties on the entities. /// /// If new relationships are to be created with the to-be-updated entities, - /// this will be reflected by the corresponding NavigationProperty being set. + /// this will be reflected by the corresponding NavigationProperty beinƒg set. /// For each of these relationships, the /// hook is fired after the execution of this hook. /// @@ -85,8 +82,6 @@ public interface IBeforeHooks where TResource : class, IIdentifiable /// /// For the pipeline, /// will typically contain one entity. - /// For , this it may contain - /// multiple entities. /// /// The returned may be a subset /// of , in which case the operation of the diff --git a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs index a2dfded363..26cd278546 100644 --- a/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs +++ b/src/JsonApiDotNetCore/Middleware/RequestMiddleware.cs @@ -33,18 +33,11 @@ public async Task Invoke(HttpContext httpContext, if (IsValid()) { - _currentRequest.IsBulkRequest = PathIsBulk(); _currentRequest.IsRelationshipPath = PathIsRelationship(); await _next(httpContext); } } - private bool PathIsBulk() - { - var actionName = (string)_httpContext.GetRouteData().Values["action"]; - return actionName.ToLower().Contains("bulk"); - } - protected bool PathIsRelationship() { var actionName = (string)_httpContext.GetRouteData().Values["action"]; diff --git a/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs b/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs index fdaab75d6b..e215d64aa1 100644 --- a/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs +++ b/src/JsonApiDotNetCore/RequestServices/Contracts/ICurrentRequest.cs @@ -12,7 +12,7 @@ namespace JsonApiDotNetCore.Managers.Contracts /// This is the former RequestManager. TODO: not done. /// Metadata associated to the current json:api request. /// - public interface ICurrentRequest : IQueryRequest + public interface ICurrentRequest { /// /// The request namespace. This may be an absolute or relative path diff --git a/src/JsonApiDotNetCore/RequestServices/CurrentRequest.cs b/src/JsonApiDotNetCore/RequestServices/CurrentRequest.cs index 150243dc72..9a81e87406 100644 --- a/src/JsonApiDotNetCore/RequestServices/CurrentRequest.cs +++ b/src/JsonApiDotNetCore/RequestServices/CurrentRequest.cs @@ -25,7 +25,6 @@ class CurrentRequest : ICurrentRequest public Dictionary RelationshipsToUpdate { get; set; } - public bool IsBulkRequest { get; set; } = false; public RelationshipAttribute RequestRelationship { get; set; } public List GetFields() diff --git a/test/OperationsExampleTests/.gitignore b/test/OperationsExampleTests/.gitignore deleted file mode 100644 index 0ca27f04e1..0000000000 --- a/test/OperationsExampleTests/.gitignore +++ /dev/null @@ -1,234 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Microsoft Azure ApplicationInsights config file -ApplicationInsights.config - -# Windows Store app package directory -AppPackages/ -BundleArtifacts/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe - -# FAKE - F# Make -.fake/ diff --git a/test/OperationsExampleTests/Add/AddTests.cs b/test/OperationsExampleTests/Add/AddTests.cs deleted file mode 100644 index 0deaaa6a82..0000000000 --- a/test/OperationsExampleTests/Add/AddTests.cs +++ /dev/null @@ -1,294 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Bogus; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCoreExample.Data; -using Microsoft.EntityFrameworkCore; -using OperationsExampleTests.Factories; -using Xunit; - -namespace OperationsExampleTests -{ - public class AddTests : Fixture - { - private readonly Faker _faker = new Faker(); - - [Fact] - public async Task Can_Create_Author() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - var content = new - { - operations = new[] { - new { - op = "add", - data = new { - type = "authors", - attributes = new { - name = author.Name - } - } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - - var id = data.Operations.Single().DataObject.Id; - var lastAuthor = await context.Authors.SingleAsync(a => a.StringId == id); - Assert.Equal(author.Name, lastAuthor.Name); - } - - [Fact] - public async Task Can_Create_Authors() - { - // arrange - var expectedCount = _faker.Random.Int(1, 10); - var context = GetService(); - var authors = AuthorFactory.Get(expectedCount); - var content = new - { - operations = new List() - }; - - for (int i = 0; i < expectedCount; i++) - { - content.operations.Add( - new - { - op = "add", - data = new - { - type = "authors", - attributes = new - { - name = authors[i].Name - } - } - } - ); - } - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(expectedCount, data.Operations.Count); - - for (int i = 0; i < expectedCount; i++) - { - var dataObject = data.Operations[i].DataObject; - var author = context.Authors.Single(a => a.StringId == dataObject.Id); - Assert.Equal(authors[i].Name, author.Name); - } - } - - [Fact] - public async Task Can_Create_Article_With_Existing_Author() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - var article = ArticleFactory.Get(); - - context.Authors.Add(author); - await context.SaveChangesAsync(); - - - //const string authorLocalId = "author-1"; - - var content = new - { - operations = new object[] { - new { - op = "add", - data = new { - type = "articles", - attributes = new { - name = article.Name - }, - relationships = new { - author = new { - data = new { - type = "authors", - id = author.Id - } - } - } - } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Single(data.Operations); - - - var lastAuthor = await context.Authors - .Include(a => a.Articles) - .SingleAsync(a => a.Id == author.Id); - var articleOperationResult = data.Operations[0]; - - // author validation: sanity checks - Assert.NotNull(lastAuthor); - Assert.Equal(author.Name, lastAuthor.Name); - - //// article validation - Assert.Single(lastAuthor.Articles); - Assert.Equal(article.Name, lastAuthor.Articles[0].Name); - Assert.Equal(articleOperationResult.DataObject.Id, lastAuthor.Articles[0].StringId); - } - - [Fact] - public async Task Can_Create_Articles_With_Existing_Author() - { - - - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - context.Authors.Add(author); - await context.SaveChangesAsync(); - var expectedCount = _faker.Random.Int(1, 10); - var articles = ArticleFactory.Get(expectedCount); - - var content = new - { - operations = new List() - }; - - for (int i = 0; i < expectedCount; i++) - { - content.operations.Add( - new - { - op = "add", - data = new - { - type = "articles", - attributes = new - { - name = articles[i].Name - }, - relationships = new - { - author = new - { - data = new - { - type = "authors", - id = author.Id - } - } - } - } - } - ); - } - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(expectedCount, data.Operations.Count); - - // author validation: sanity checks - var lastAuthor = context.Authors.Include(a => a.Articles).Single(a => a.Id == author.Id); - Assert.NotNull(lastAuthor); - Assert.Equal(author.Name, lastAuthor.Name); - - // articles validation - Assert.True(lastAuthor.Articles.Count == expectedCount); - for (int i = 0; i < expectedCount; i++) - { - var article = articles[i]; - Assert.NotNull(lastAuthor.Articles.FirstOrDefault(a => a.Name == article.Name)); - } - } - - [Fact] - public async Task Can_Create_Author_With_Article_Using_LocalId() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - var article = ArticleFactory.Get(); - const string authorLocalId = "author-1"; - - var content = new - { - operations = new object[] { - new { - op = "add", - data = new { - lid = authorLocalId, - type = "authors", - attributes = new { - name = author.Name - }, - } - }, - new { - op = "add", - data = new { - type = "articles", - attributes = new { - name = article.Name - }, - relationships = new { - author = new { - data = new { - type = "authors", - lid = authorLocalId - } - } - } - } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(2, data.Operations.Count); - - var authorOperationResult = data.Operations[0]; - var id = authorOperationResult.DataObject.Id; - var lastAuthor = await context.Authors - .Include(a => a.Articles) - .SingleAsync(a => a.StringId == id); - var articleOperationResult = data.Operations[1]; - - // author validation - Assert.Equal(authorLocalId, authorOperationResult.DataObject.LocalId); - Assert.Equal(author.Name, lastAuthor.Name); - - // article validation - Assert.Single(lastAuthor.Articles); - Assert.Equal(article.Name, lastAuthor.Articles[0].Name); - Assert.Equal(articleOperationResult.DataObject.Id, lastAuthor.Articles[0].StringId); - } - } -} diff --git a/test/OperationsExampleTests/Factories/ArticleFactory.cs b/test/OperationsExampleTests/Factories/ArticleFactory.cs deleted file mode 100644 index a03bc3fbea..0000000000 --- a/test/OperationsExampleTests/Factories/ArticleFactory.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using Bogus; -using JsonApiDotNetCoreExample.Models; - -namespace OperationsExampleTests.Factories -{ - public static class ArticleFactory - { - public static Article Get() - { - var faker = new Faker
(); - faker.RuleFor(m => m.Name, f => f.Lorem.Sentence()); - return faker.Generate(); - } - - public static List
Get(int count) - { - var articles = new List
(); - for (int i = 0; i < count; i++) - articles.Add(Get()); - - return articles; - } - } -} diff --git a/test/OperationsExampleTests/Factories/AuthorFactory.cs b/test/OperationsExampleTests/Factories/AuthorFactory.cs deleted file mode 100644 index e80b100a59..0000000000 --- a/test/OperationsExampleTests/Factories/AuthorFactory.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using Bogus; -using JsonApiDotNetCoreExample.Models; - -namespace OperationsExampleTests.Factories -{ - public static class AuthorFactory - { - public static Author Get() - { - var faker = new Faker(); - faker.RuleFor(m => m.Name, f => f.Person.UserName); - return faker.Generate(); - } - - public static List Get(int count) - { - var authors = new List(); - for (int i = 0; i < count; i++) - authors.Add(Get()); - - return authors; - } - } -} diff --git a/test/OperationsExampleTests/Fixture.cs b/test/OperationsExampleTests/Fixture.cs deleted file mode 100644 index 11621d36e4..0000000000 --- a/test/OperationsExampleTests/Fixture.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using JsonApiDotNetCoreExample.Data; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Newtonsoft.Json; -using Xunit; - -[assembly: CollectionBehavior(DisableTestParallelization = true)] -namespace OperationsExampleTests -{ - public class Fixture : IDisposable - { - public Fixture() - { - var builder = new WebHostBuilder().UseStartup(); - Server = new TestServer(builder); - Client = Server.CreateClient(); - } - - public TestServer Server { get; private set; } - public HttpClient Client { get; } - - public void Dispose() - { - try - { - var context = GetService(); - context.Articles.RemoveRange(context.Articles); - context.Authors.RemoveRange(context.Authors); - context.SaveChanges(); - } // it is possible the test may try to do something that is an invalid db operation - // validation should be left up to the test, so we should not bomb the run in the - // disposal of that context - catch (Exception) { } - } - - public T GetService() => (T)Server.Host.Services.GetService(typeof(T)); - - public async Task PatchAsync(string route, object data) - { - var httpMethod = new HttpMethod("PATCH"); - var request = new HttpRequestMessage(httpMethod, route); - request.Content = new StringContent(JsonConvert.SerializeObject(data)); - request.Content.Headers.ContentLength = 1; - request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); - return await Client.SendAsync(request); - } - - public async Task<(HttpResponseMessage response, T data)> PatchAsync(string route, object data) - { - var response = await PatchAsync(route, data); - var json = await response.Content.ReadAsStringAsync(); - var obj = JsonConvert.DeserializeObject(json); - return (response, obj); - } - } -} diff --git a/test/OperationsExampleTests/Get/GetByIdTests.cs b/test/OperationsExampleTests/Get/GetByIdTests.cs deleted file mode 100644 index 1056082895..0000000000 --- a/test/OperationsExampleTests/Get/GetByIdTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Bogus; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCoreExample.Data; -using OperationsExampleTests.Factories; -using Xunit; - -namespace OperationsExampleTests -{ - public class GetTests : Fixture, IDisposable - { - private readonly Faker _faker = new Faker(); - - [Fact] - public async Task Can_Get_Author_By_Id() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - context.Authors.Add(author); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "get"}, - { "ref", new { type = "authors", id = author.StringId } } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.NotNull(data); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Single(data.Operations); - Assert.Equal(author.Id.ToString(), data.Operations.Single().DataObject.Id); - } - - [Fact] - public async Task Get_Author_By_Id_Returns_404_If_NotFound() - { - // arrange - var authorId = _faker.Random.Int(max: 0).ToString(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "get"}, - { "ref", new { type = "authors", id = authorId } } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); - Assert.NotNull(data); - Assert.Single(data.Errors); - Assert.True(data.Errors[0].Detail.Contains("authors"), "The error detail should contain the name of the entity that could not be found."); - Assert.True(data.Errors[0].Detail.Contains(authorId), "The error detail should contain the entity id that could not be found"); - Assert.True(data.Errors[0].Title.Contains("operation[0]"), "The error title should contain the operation identifier that failed"); - } - } -} diff --git a/test/OperationsExampleTests/Get/GetRelationshipTests.cs b/test/OperationsExampleTests/Get/GetRelationshipTests.cs deleted file mode 100644 index 0aeef6f3ec..0000000000 --- a/test/OperationsExampleTests/Get/GetRelationshipTests.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Bogus; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCoreExample.Data; -using OperationsExampleTests.Factories; -using Xunit; - -namespace OperationsExampleTests -{ - public class GetRelationshipTests : Fixture, IDisposable - { - private readonly Faker _faker = new Faker(); - - [Fact] - public async Task Can_Get_HasOne_Relationship() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - var article = ArticleFactory.Get(); - article.Author = author; - context.Articles.Add(article); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "get"}, - { "ref", new { type = "articles", id = article.StringId, relationship = "author" } } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.NotNull(data); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Single(data.Operations); - var resourceObject = data.Operations.Single().DataObject; - Assert.Equal(author.Id.ToString(), resourceObject.Id); - Assert.Equal("authors", resourceObject.Type); - } - - [Fact] - public async Task Can_Get_HasMany_Relationship() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - var article = ArticleFactory.Get(); - article.Author = author; - context.Articles.Add(article); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "get"}, - { "ref", new { type = "authors", id = author.StringId, relationship = "articles" } } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.NotNull(data); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Single(data.Operations); - - var resourceObject = data.Operations.Single().DataList.Single(); - Assert.Equal(article.Id.ToString(), resourceObject.Id); - Assert.Equal("articles", resourceObject.Type); - } - } -} diff --git a/test/OperationsExampleTests/Get/GetTests.cs b/test/OperationsExampleTests/Get/GetTests.cs deleted file mode 100644 index f0d3fdffd8..0000000000 --- a/test/OperationsExampleTests/Get/GetTests.cs +++ /dev/null @@ -1,73 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Bogus; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCoreExample.Data; -using OperationsExampleTests.Factories; -using Xunit; - -namespace OperationsExampleTests -{ - public class GetByIdTests : Fixture, IDisposable - { - private readonly Faker _faker = new Faker(); - - [Fact] - public async Task Can_Get_Authors() - { - // arrange - var expectedCount = _faker.Random.Int(1, 10); - var context = GetService(); - context.Articles.RemoveRange(context.Articles); - context.Authors.RemoveRange(context.Authors); - var authors = AuthorFactory.Get(expectedCount); - context.AddRange(authors); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "get"}, - { "ref", new { type = "authors" } } - } - } - }; - - // act - var result = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(result.response); - Assert.NotNull(result.data); - Assert.Equal(HttpStatusCode.OK, result.response.StatusCode); - Assert.Single(result.data.Operations); - Assert.Equal(expectedCount, result.data.Operations.Single().DataList.Count); - } - - [Fact] - public async Task Get_Non_Existent_Type_Returns_400() - { - // arrange - var content = new - { - operations = new[] { - new Dictionary { - { "op", "get"}, - { "ref", new { type = "non-existent-type" } } - } - } - }; - - // act - var result = await PatchAsync("api/bulk", content); - - // assert - Assert.Equal(HttpStatusCode.BadRequest, result.response.StatusCode); - } - } -} diff --git a/test/OperationsExampleTests/OperationsExampleTests.csproj b/test/OperationsExampleTests/OperationsExampleTests.csproj deleted file mode 100644 index c2ab5b84dd..0000000000 --- a/test/OperationsExampleTests/OperationsExampleTests.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - $(NetCoreAppVersion) - false - OperationsExampleTests - - - - - - - - - - - - - - - PreserveNewest - - - diff --git a/test/OperationsExampleTests/Remove/RemoveTests.cs b/test/OperationsExampleTests/Remove/RemoveTests.cs deleted file mode 100644 index b5e0cffaf3..0000000000 --- a/test/OperationsExampleTests/Remove/RemoveTests.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Bogus; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCoreExample.Data; -using OperationsExampleTests.Factories; -using Xunit; - -namespace OperationsExampleTests -{ - public class RemoveTests : Fixture - { - private readonly Faker _faker = new Faker(); - - [Fact] - public async Task Can_Remove_Author() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - context.Authors.Add(author); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "remove"}, - { "ref", new { type = "authors", id = author.StringId } } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.NotNull(data); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Empty(data.Operations); - Assert.Null(context.Authors.SingleOrDefault(a => a.Id == author.Id)); - } - - [Fact] - public async Task Can_Remove_Authors() - { - // arrange - var count = _faker.Random.Int(1, 10); - var context = GetService(); - - var authors = AuthorFactory.Get(count); - - context.Authors.AddRange(authors); - context.SaveChanges(); - - var content = new - { - operations = new List() - }; - - for (int i = 0; i < count; i++) - content.operations.Add( - new Dictionary { - { "op", "remove"}, - { "ref", new { type = "authors", id = authors[i].StringId } } - } - ); - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.NotNull(data); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Empty(data.Operations); - - for (int i = 0; i < count; i++) - Assert.Null(context.Authors.SingleOrDefault(a => a.Id == authors[i].Id)); - } - } -} diff --git a/test/OperationsExampleTests/TestStartup.cs b/test/OperationsExampleTests/TestStartup.cs deleted file mode 100644 index 449c193177..0000000000 --- a/test/OperationsExampleTests/TestStartup.cs +++ /dev/null @@ -1,25 +0,0 @@ -using JsonApiDotNetCore.Data; -using JsonApiDotNetCore.Services; -using JsonApiDotNetCoreExample.Data; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using OperationsExample; -using System; -using UnitTests; - -namespace OperationsExampleTests -{ - public class TestStartup : Startup - { - public TestStartup(IHostingEnvironment env) : base(env) - { } - - public override IServiceProvider ConfigureServices(IServiceCollection services) - { - base.ConfigureServices(services); - services.AddScoped(); - services.AddSingleton>(); - return services.BuildServiceProvider(); - } - } -} diff --git a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs b/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs deleted file mode 100644 index 191711651d..0000000000 --- a/test/OperationsExampleTests/Transactions/TransactionFailureTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Bogus; -using JsonApiDotNetCore.Internal; -using JsonApiDotNetCoreExample.Data; -using Microsoft.EntityFrameworkCore; -using OperationsExampleTests.Factories; -using Xunit; - -namespace OperationsExampleTests -{ - public class TransactionFailureTests : Fixture - { - private readonly Faker _faker = new Faker(); - - [Fact] - public async Task Cannot_Create_Author_If_Article_Creation_Fails() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - var article = ArticleFactory.Get(); - - // do this so that the name is random enough for db validations - author.Name = Guid.NewGuid().ToString("N"); - article.Name = Guid.NewGuid().ToString("N"); - - var content = new - { - operations = new object[] { - new { - op = "add", - data = new { - type = "authors", - attributes = new { - name = author.Name - }, - } - }, - new { - op = "add", - data = new { - type = "articles", - attributes = new { - name = article.Name - }, - // by not including the author, the article creation will fail - // relationships = new { - // author = new { - // data = new { - // type = "authors", - // lid = authorLocalId - // } - // } - // } - } - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - // for now, it is up to application implementations to perform validation and - // provide the proper HTTP response code - Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); - Assert.Single(data.Errors); - Assert.Contains("operation[1] (add)", data.Errors[0].Title); - - var dbAuthors = await context.Authors.Where(a => a.Name == author.Name).ToListAsync(); - var dbArticles = await context.Articles.Where(a => a.Name == article.Name).ToListAsync(); - Assert.Empty(dbAuthors); - Assert.Empty(dbArticles); - } - } -} diff --git a/test/OperationsExampleTests/Update/UpdateTests.cs b/test/OperationsExampleTests/Update/UpdateTests.cs deleted file mode 100644 index c5d220b2f5..0000000000 --- a/test/OperationsExampleTests/Update/UpdateTests.cs +++ /dev/null @@ -1,112 +0,0 @@ -using Bogus; -using JsonApiDotNetCore.Models.Operations; -using JsonApiDotNetCoreExample.Data; -using OperationsExampleTests.Factories; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace OperationsExampleTests.Update -{ - public class UpdateTests : Fixture - { - private readonly Faker _faker = new Faker(); - - [Fact] - public async Task Can_Update_Author() - { - // arrange - var context = GetService(); - var author = AuthorFactory.Get(); - var updates = AuthorFactory.Get(); - context.Authors.Add(author); - context.SaveChanges(); - - var content = new - { - operations = new[] { - new Dictionary { - { "op", "update" }, - { "ref", new { - type = "authors", - id = author.Id, - } }, - { "data", new { - type = "authors", - id = author.Id, - attributes = new - { - name = updates.Name - } - } }, - } - } - }; - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Single(data.Operations); - - var attrs = data.Operations.Single().DataObject.Attributes; - Assert.Equal(updates.Name, attrs["name"]); - } - - [Fact] - public async Task Can_Update_Authors() - { - // arrange - var count = _faker.Random.Int(1, 10); - var context = GetService(); - - var authors = AuthorFactory.Get(count); - var updates = AuthorFactory.Get(count); - - context.Authors.AddRange(authors); - context.SaveChanges(); - - var content = new - { - operations = new List() - }; - - for (int i = 0; i < count; i++) - content.operations.Add(new Dictionary { - { "op", "update" }, - { "ref", new { - type = "authors", - id = authors[i].Id, - } }, - { "data", new { - type = "authors", - id = authors[i].Id, - attributes = new - { - name = updates[i].Name - } - } }, - }); - - // act - var (response, data) = await PatchAsync("api/bulk", content); - - // assert - Assert.NotNull(response); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(count, data.Operations.Count); - - for (int i = 0; i < count; i++) - { - var attrs = data.Operations[i].DataObject.Attributes; - Assert.Equal(updates[i].Name, attrs["name"]); - } - } - } -} diff --git a/test/OperationsExampleTests/appsettings.json b/test/OperationsExampleTests/appsettings.json deleted file mode 100644 index 84f8cf4220..0000000000 --- a/test/OperationsExampleTests/appsettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Data": { - "DefaultConnection": - "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Warning", - "System": "Warning", - "Microsoft": "Warning", - "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter": "Critical" - } - } -} diff --git a/test/UnitTests/Serialization/DeserializerTestsSetup.cs b/test/UnitTests/Serialization/DeserializerTestsSetup.cs index 7f2fd92f32..dc9dff4aae 100644 --- a/test/UnitTests/Serialization/DeserializerTestsSetup.cs +++ b/test/UnitTests/Serialization/DeserializerTestsSetup.cs @@ -1,7 +1,6 @@ using JsonApiDotNetCore.Internal.Contracts; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Serialization.Deserializer; using System.Collections.Generic; namespace UnitTests.Serialization From 3b5a12cbb38dc6de8454bb497fe85d8661a505dc Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 10 Oct 2019 13:11:30 +0200 Subject: [PATCH 4/7] chore: remove logic related to ER splitting --- .../Data/DefaultEntityRepository.cs | 90 +++----------- .../Models/IResourceMapper.cs | 23 ---- .../Services/EntityResourceService.cs | 110 ++++++------------ 3 files changed, 51 insertions(+), 172 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Models/IResourceMapper.cs diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index 07a1bdb2e7..0f5057cb51 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -171,20 +171,14 @@ private void LoadInverseRelationships(object trackedRelationshipValue, Relations { var relationEntry = _context.Entry((IIdentifiable)trackedRelationshipValue); if (IsHasOneRelationship(hasOneAttr.InverseNavigation, trackedRelationshipValue.GetType())) - { relationEntry.Reference(hasOneAttr.InverseNavigation).Load(); - } else - { relationEntry.Collection(hasOneAttr.InverseNavigation).Load(); - } } else if (relationshipAttr is HasManyAttribute hasManyAttr && !(relationshipAttr is HasManyThroughAttribute)) { foreach (IIdentifiable relationshipValue in (IList)trackedRelationshipValue) - { _context.Entry(relationshipValue).Reference(hasManyAttr.InverseNavigation).Load(); - } } } @@ -193,15 +187,14 @@ private bool IsHasOneRelationship(string internalRelationshipName, Type type) var relationshipAttr = _resourceGraph.GetContextEntity(type).Relationships.SingleOrDefault(r => r.InternalRelationshipName == internalRelationshipName); if (relationshipAttr != null) { - if (relationshipAttr is HasOneAttribute) return true; + if (relationshipAttr is HasOneAttribute) + return true; + return false; } - else - { - // relationshipAttr is null when we don't put a [RelationshipAttribute] on the inverse navigation property. - // In this case we use relfection to figure out what kind of relationship is pointing back. - return !(type.GetProperty(internalRelationshipName).PropertyType.Inherits(typeof(IEnumerable))); - } + // relationshipAttr is null when we don't put a [RelationshipAttribute] on the inverse navigation property. + // In this case we use relfection to figure out what kind of relationship is pointing back. + return !(type.GetProperty(internalRelationshipName).PropertyType.Inherits(typeof(IEnumerable))); } @@ -213,22 +206,16 @@ public void DetachRelationshipPointers(TEntity entity) { if (relationshipAttr is HasOneAttribute hasOneAttr) { - var relationshipValue = GetEntityResourceSeparationValue(entity, hasOneAttr) ?? (IIdentifiable)hasOneAttr.GetValue(entity); + var relationshipValue = (IIdentifiable)hasOneAttr.GetValue(entity); if (relationshipValue == null) continue; _context.Entry(relationshipValue).State = EntityState.Detached; } else { IEnumerable relationshipValueList = (IEnumerable)relationshipAttr.GetValue(entity); - /// This adds support for resource-entity separation in the case of one-to-many. - /// todo: currently there is no support for many to many relations. - if (relationshipAttr is HasManyAttribute hasMany) - relationshipValueList = GetEntityResourceSeparationValue(entity, hasMany) ?? relationshipValueList; if (relationshipValueList == null) continue; foreach (var pointer in relationshipValueList) - { _context.Entry(pointer).State = EntityState.Detached; - } /// detaching has many relationships is not sufficient to /// trigger a full reload of relationships: the navigation /// property actually needs to be nulled out, otherwise @@ -286,45 +273,30 @@ private object GetTrackedRelationshipValue(RelationshipAttribute relationshipAtt wasAlreadyAttached = false; if (relationshipAttr is HasOneAttribute hasOneAttr) { - /// This adds support for resource-entity separation in the case of one-to-one. - var relationshipValue = GetEntityResourceSeparationValue(entity, hasOneAttr) ?? (IIdentifiable)hasOneAttr.GetValue(entity); + var relationshipValue = (IIdentifiable)hasOneAttr.GetValue(entity); if (relationshipValue == null) return null; return GetTrackedHasOneRelationshipValue(relationshipValue, hasOneAttr, ref wasAlreadyAttached); } - else - { - IEnumerable relationshipValueList = (IEnumerable)relationshipAttr.GetValue(entity); - /// This adds support for resource-entity separation in the case of one-to-many. - /// todo: currently there is no support for many to many relations. - if (relationshipAttr is HasManyAttribute hasMany) - relationshipValueList = GetEntityResourceSeparationValue(entity, hasMany) ?? relationshipValueList; - if (relationshipValueList == null) return null; - return GetTrackedManyRelationshipValue(relationshipValueList, relationshipAttr, ref wasAlreadyAttached); - } + + IEnumerable relationshipValueList = (IEnumerable)relationshipAttr.GetValue(entity); + if (relationshipValueList == null) + return null; + + return GetTrackedManyRelationshipValue(relationshipValueList, relationshipAttr, ref wasAlreadyAttached); } - // helper method used in GetTrackedRelationshipValue. See comments there. + // helper method used in GetTrackedRelationshipValue. See comments below. private IList GetTrackedManyRelationshipValue(IEnumerable relationshipValueList, RelationshipAttribute relationshipAttr, ref bool wasAlreadyAttached) { if (relationshipValueList == null) return null; bool _wasAlreadyAttached = false; - /// if we're not using entity resource separation, we can just read off the related type - /// from the RelationshipAttribute. If we DO use separation, RelationshipAttribute.DependentType - /// will point to the Resource, not the Entity, which is not the one we need here. - bool entityResourceSeparation = relationshipAttr.EntityPropertyName != null; - Type entityType = entityResourceSeparation ? null : relationshipAttr.DependentType; var trackedPointerCollection = relationshipValueList.Select(pointer => - { - /// todo: we can't just use relationshipAttr.DependentType because - /// this will point to the Resource type in the case of entity resource - /// separation. We should consider to store entity type on - /// the relationship attribute too. - entityType = entityType ?? pointer.GetType(); + { // convert each element in the value list to relationshipAttr.DependentType. var tracked = AttachOrGetTracked(pointer); if (tracked != null) _wasAlreadyAttached = true; - return Convert.ChangeType(tracked ?? pointer, entityType); - }).ToList().Cast(entityType); + return Convert.ChangeType(tracked ?? pointer, relationshipAttr.DependentType); + }).ToList().Cast(relationshipAttr.DependentType); if (_wasAlreadyAttached) wasAlreadyAttached = true; return (IList)trackedPointerCollection; } @@ -513,32 +485,6 @@ private void AssignHasManyThrough(TEntity entity, HasManyThroughAttribute hasMan } } - /// - /// A helper method that gets the relationship value in the case of - /// entity resource separation. - /// - private IIdentifiable GetEntityResourceSeparationValue(TEntity entity, HasOneAttribute attribute) - { - if (attribute.EntityPropertyName == null) - { - return null; - } - return (IIdentifiable)entity.GetType().GetProperty(attribute.EntityPropertyName)?.GetValue(entity); - } - - /// - /// A helper method that gets the relationship value in the case of - /// entity resource separation. - /// - private IEnumerable GetEntityResourceSeparationValue(TEntity entity, HasManyAttribute attribute) - { - if (attribute.EntityPropertyName == null) - { - return null; - } - return ((IEnumerable)(entity.GetType().GetProperty(attribute.EntityPropertyName)?.GetValue(entity))).Cast(); - } - /// /// Given a iidentifiable relationshipvalue, verify if an entity of the underlying /// type with the same ID is already attached to the dbContext, and if so, return it. diff --git a/src/JsonApiDotNetCore/Models/IResourceMapper.cs b/src/JsonApiDotNetCore/Models/IResourceMapper.cs deleted file mode 100644 index 94034f715b..0000000000 --- a/src/JsonApiDotNetCore/Models/IResourceMapper.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace JsonApiDotNetCore.Models -{ - public interface IResourceMapper - { - /// - /// Execute a mapping from the source object to a new destination object. - /// The source type is inferred from the source object. - /// - /// Destination type to create - /// Source object to map from - /// Mapped destination object - TDestination Map(object source); - - /// - /// Execute a mapping from the source object to a new destination object. - /// - /// Source type to use, regardless of the runtime type - /// Destination type to create - /// Source object to map from - /// Mapped destination object - TDestination Map(TSource source); - } -} diff --git a/src/JsonApiDotNetCore/Services/EntityResourceService.cs b/src/JsonApiDotNetCore/Services/EntityResourceService.cs index abc208377a..dbd8b37e5c 100644 --- a/src/JsonApiDotNetCore/Services/EntityResourceService.cs +++ b/src/JsonApiDotNetCore/Services/EntityResourceService.cs @@ -19,28 +19,25 @@ namespace JsonApiDotNetCore.Services /// Entity mapping class /// /// - /// /// - public class EntityResourceService : + public class EntityResourceService : IResourceService where TResource : class, IIdentifiable - where TEntity : class, IIdentifiable { private readonly IPageQueryService _pageManager; private readonly ICurrentRequest _currentRequest; private readonly IJsonApiOptions _options; private readonly ITargetedFields _targetedFields; private readonly IResourceGraph _resourceGraph; - private readonly IEntityRepository _repository; + private readonly IEntityRepository _repository; private readonly ILogger _logger; - private readonly IResourceMapper _mapper; private readonly IResourceHookExecutor _hookExecutor; private readonly IIncludeService _includeService; private readonly ISparseFieldsService _sparseFieldsService; private readonly ContextEntity _currentRequestResource; public EntityResourceService( - IEntityRepository repository, + IEntityRepository repository, IJsonApiOptions options, ITargetedFields updatedFields, ICurrentRequest currentRequest, @@ -49,7 +46,6 @@ public EntityResourceService( IPageQueryService pageManager, IResourceGraph resourceGraph, IResourceHookExecutor hookExecutor = null, - IResourceMapper mapper = null, ILoggerFactory loggerFactory = null) { _currentRequest = currentRequest; @@ -60,19 +56,13 @@ public EntityResourceService( _targetedFields = updatedFields; _resourceGraph = resourceGraph; _repository = repository; - if (mapper == null && typeof(TResource) != typeof(TEntity)) - { - throw new InvalidOperationException("Resource and Entity types are NOT the same. Please provide a mapper."); - } _hookExecutor = hookExecutor; - _mapper = mapper; - _logger = loggerFactory?.CreateLogger>(); + _logger = loggerFactory?.CreateLogger>(); _currentRequestResource = resourceGraph.GetContextEntity(); } - public virtual async Task CreateAsync(TResource resource) + public virtual async Task CreateAsync(TResource entity) { - var entity = MapIn(resource); entity = IsNull(_hookExecutor) ? entity : _hookExecutor.BeforeCreate(AsList(entity), ResourcePipeline.Post).SingleOrDefault(); entity = await _repository.CreateAsync(entity); @@ -81,22 +71,22 @@ public virtual async Task CreateAsync(TResource resource) // https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/343 if (ShouldIncludeRelationships()) { - if (_repository is IEntityFrameworkRepository efRepository) + if (_repository is IEntityFrameworkRepository efRepository) efRepository.DetachRelationshipPointers(entity); entity = await GetWithRelationshipsAsync(entity.Id); - } + if (!IsNull(_hookExecutor, entity)) { _hookExecutor.AfterCreate(AsList(entity), ResourcePipeline.Post); entity = _hookExecutor.OnReturn(AsList(entity), ResourcePipeline.Get).SingleOrDefault(); } - return MapOut(entity); + return entity; } public virtual async Task DeleteAsync(TId id) { - var entity = (TEntity)Activator.CreateInstance(typeof(TEntity)); + var entity = (TResource)Activator.CreateInstance(typeof(TResource)); entity.Id = id; if (!IsNull(_hookExecutor, entity)) _hookExecutor.BeforeDelete(AsList(entity), ResourcePipeline.Delete); var succeeded = await _repository.DeleteAsync(entity.Id); @@ -105,7 +95,7 @@ public virtual async Task DeleteAsync(TId id) } public virtual async Task> GetAsync() { - _hookExecutor?.BeforeRead(ResourcePipeline.Get); + _hookExecutor?.BeforeRead(ResourcePipeline.Get); var entities = _repository.Get(); entities = ApplySortAndFilterQuery(entities); @@ -133,9 +123,9 @@ public virtual async Task> GetAsync() public virtual async Task GetAsync(TId id) { var pipeline = ResourcePipeline.GetSingle; - _hookExecutor?.BeforeRead(pipeline, id.ToString()); + _hookExecutor?.BeforeRead(pipeline, id.ToString()); - TEntity entity; + TResource entity; if (ShouldIncludeRelationships()) entity = await GetWithRelationshipsAsync(id); else @@ -146,7 +136,7 @@ public virtual async Task GetAsync(TId id) _hookExecutor.AfterRead(AsList(entity), pipeline); entity = _hookExecutor.OnReturn(AsList(entity), pipeline).SingleOrDefault(); } - return MapOut(entity); + return entity; } // triggered by GET /articles/1/relationships/{relationshipName} @@ -155,7 +145,7 @@ public virtual async Task GetRelationshipsAsync(TId id, string relati var relationship = GetRelationship(relationshipName); // BeforeRead hook execution - _hookExecutor?.BeforeRead(ResourcePipeline.GetRelationship, id.ToString()); + _hookExecutor?.BeforeRead(ResourcePipeline.GetRelationship, id.ToString()); // TODO: it would be better if we could distinguish whether or not the relationship was not found, // vs the relationship not being set on the instance of T @@ -169,9 +159,7 @@ public virtual async Task GetRelationshipsAsync(TId id, string relati entity = _hookExecutor.OnReturn(AsList(entity), ResourcePipeline.GetRelationship).SingleOrDefault(); } - var resource = MapOut(entity); - - return resource; + return entity; } // triggered by GET /articles/1/{relationshipName} @@ -182,9 +170,8 @@ public virtual async Task GetRelationshipAsync(TId id, string relationsh return _resourceGraph.GetRelationship(resource, relationship.InternalRelationshipName); } - public virtual async Task UpdateAsync(TId id, TResource resource) + public virtual async Task UpdateAsync(TId id, TResource entity) { - var entity = MapIn(resource); entity = IsNull(_hookExecutor) ? entity : _hookExecutor.BeforeUpdate(AsList(entity), ResourcePipeline.Patch).SingleOrDefault(); entity = await _repository.UpdateAsync(entity); @@ -193,7 +180,7 @@ public virtual async Task UpdateAsync(TId id, TResource resource) _hookExecutor.AfterUpdate(AsList(entity), ResourcePipeline.Patch); entity = _hookExecutor.OnReturn(AsList(entity), ResourcePipeline.Patch).SingleOrDefault(); } - return MapOut(entity); + return entity; } // triggered by PATCH /articles/1/relationships/{relationshipName} @@ -217,13 +204,12 @@ public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipNa } - protected virtual async Task> ApplyPageQueryAsync(IQueryable entities) + protected virtual async Task> ApplyPageQueryAsync(IQueryable entities) { if (!(_pageManager.PageSize > 0)) { var allEntities = await _repository.ToListAsync(entities); - return (typeof(TResource) == typeof(TEntity)) ? allEntities as IEnumerable : - _mapper.Map>(allEntities); + return allEntities as IEnumerable; } if (_logger?.IsEnabled(LogLevel.Information) == true) @@ -232,12 +218,10 @@ protected virtual async Task> ApplyPageQueryAsync(IQuerya $"with {_pageManager.PageSize} entities"); } - var pagedEntities = await _repository.PageAsync(entities, _pageManager.PageSize, _pageManager.CurrentPage); - - return MapOut(pagedEntities); + return await _repository.PageAsync(entities, _pageManager.PageSize, _pageManager.CurrentPage); } - protected virtual IQueryable ApplySortAndFilterQuery(IQueryable entities) + protected virtual IQueryable ApplySortAndFilterQuery(IQueryable entities) { var query = _currentRequest.QuerySet; @@ -258,7 +242,7 @@ protected virtual IQueryable ApplySortAndFilterQuery(IQueryable /// /// - protected virtual IQueryable IncludeRelationships(IQueryable entities) + protected virtual IQueryable IncludeRelationships(IQueryable entities) { foreach (var r in _includeService.Get()) entities = _repository.Include(entities, r.ToArray()); @@ -271,7 +255,7 @@ protected virtual IQueryable IncludeRelationships(IQueryable e /// /// /// - private async Task GetWithRelationshipsAsync(TId id) + private async Task GetWithRelationshipsAsync(TId id) { var sparseFieldset = _sparseFieldsService.Get(); var query = _repository.Select(_repository.Get(), sparseFieldset.Select(a => a.InternalAttributeName).ToList()).Where(e => e.Id.Equals(id)); @@ -279,7 +263,7 @@ private async Task GetWithRelationshipsAsync(TId id) foreach (var chain in _includeService.Get()) query = _repository.Include(query, chain.ToArray()); - TEntity value; + TResource value; // https://github.com/aspnet/EntityFrameworkCore/issues/6573 if (sparseFieldset.Count() > 0) value = query.FirstOrDefault(); @@ -306,49 +290,16 @@ private bool IsNull(params object[] values) } private RelationshipAttribute GetRelationship(string relationshipName) - { + { var relationship = _currentRequestResource.Relationships.Single(r => r.Is(relationshipName)); if (relationship == null) throw new JsonApiException(422, $"Relationship '{relationshipName}' does not exist on resource '{typeof(TResource)}'."); return relationship; } - /// - /// Casts the entity given to `TResource` or maps it to its equal - /// - /// - /// - private TResource MapOut(TEntity entity) - { - return (typeof(TResource) == typeof(TEntity)) ? entity as TResource : _mapper.Map(entity); - } - - private IEnumerable MapOut(IEnumerable entities) - => (typeof(TResource) == typeof(TEntity)) - ? entities as IEnumerable - : _mapper.Map>(entities); - - private TEntity MapIn(TResource resource) - => (typeof(TResource) == typeof(TEntity)) - ? resource as TEntity - : _mapper.Map(resource); - - private List AsList(TEntity entity) - { - return new List { entity }; - } - } - /// - /// No mapping - /// - /// - /// - public class EntityResourceService : EntityResourceService, - IResourceService - where TResource : class, IIdentifiable - { - public EntityResourceService(IEntityRepository repository, IJsonApiOptions options, ITargetedFields updatedFields, ICurrentRequest currentRequest, IIncludeService includeService, ISparseFieldsService sparseFieldsService, IPageQueryService pageManager, IResourceGraph resourceGraph, IResourceHookExecutor hookExecutor = null, IResourceMapper mapper = null, ILoggerFactory loggerFactory = null) : base(repository, options, updatedFields, currentRequest, includeService, sparseFieldsService, pageManager, resourceGraph, hookExecutor, mapper, loggerFactory) + private List AsList(TResource entity) { + return new List { entity }; } } @@ -360,7 +311,12 @@ public class EntityResourceService : EntityResourceService where TResource : class, IIdentifiable { - public EntityResourceService(IEntityRepository repository, IJsonApiOptions options, ITargetedFields updatedFields, ICurrentRequest currentRequest, IIncludeService includeService, ISparseFieldsService sparseFieldsService, IPageQueryService pageManager, IResourceGraph resourceGraph, IResourceHookExecutor hookExecutor = null, IResourceMapper mapper = null, ILoggerFactory loggerFactory = null) : base(repository, options, updatedFields, currentRequest, includeService, sparseFieldsService, pageManager, resourceGraph, hookExecutor, mapper, loggerFactory) + public EntityResourceService(IEntityRepository repository, IJsonApiOptions options, + ITargetedFields updatedFields, ICurrentRequest currentRequest, + IIncludeService includeService, ISparseFieldsService sparseFieldsService, + IPageQueryService pageManager, IResourceGraph resourceGraph, + IResourceHookExecutor hookExecutor = null, ILoggerFactory loggerFactory = null) + : base(repository, options, updatedFields, currentRequest, includeService, sparseFieldsService, pageManager, resourceGraph, hookExecutor, loggerFactory) { } } From 4c321fb641efb83e4d9c9435fdf06c6ce859b8f9 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 10 Oct 2019 13:12:00 +0200 Subject: [PATCH 5/7] chore: remove split test project --- JsonApiDotnetCore.sln | 15 - .../Acceptance/AddTests.cs | 212 -------------- .../Acceptance/DeleteTests.cs | 68 ----- .../Acceptance/GetTests.cs | 267 ------------------ .../Acceptance/RelationshipGetTests.cs | 226 --------------- .../Acceptance/RelationshipModifyTests.cs | 95 ------- .../Acceptance/UpdateTests.cs | 121 -------- ...esourceEntitySeparationExampleTests.csproj | 28 -- .../TestCollection.cs | 9 - .../TestFixture.cs | 94 ------ .../TestStartup.cs | 22 -- .../appsettings.json | 15 - 12 files changed, 1172 deletions(-) delete mode 100644 test/ResourceEntitySeparationExampleTests/Acceptance/AddTests.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/Acceptance/DeleteTests.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/Acceptance/GetTests.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipGetTests.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipModifyTests.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/Acceptance/UpdateTests.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj delete mode 100644 test/ResourceEntitySeparationExampleTests/TestCollection.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/TestFixture.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/TestStartup.cs delete mode 100644 test/ResourceEntitySeparationExampleTests/appsettings.json diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index 38e0bef4d4..0b778836b4 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -35,8 +35,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoEntityFrameworkTests", "t EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "test\UnitTests\UnitTests.csproj", "{8788FF65-C2B6-40B2-A3A0-1E3D91C02664}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceEntitySeparationExampleTests", "test\ResourceEntitySeparationExampleTests\ResourceEntitySeparationExampleTests.csproj", "{778C4EB9-BD65-4C0F-9230-B5CB1D72186A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscoveryTests", "test\DiscoveryTests\DiscoveryTests.csproj", "{03032A2F-664D-4DD8-A82F-AD8A482EDD85}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GettingStarted", "src\Examples\GettingStarted\GettingStarted.csproj", "{92BFF50F-BF96-43AD-AB86-A8B861C32412}" @@ -125,18 +123,6 @@ Global {8788FF65-C2B6-40B2-A3A0-1E3D91C02664}.Release|x64.Build.0 = Release|Any CPU {8788FF65-C2B6-40B2-A3A0-1E3D91C02664}.Release|x86.ActiveCfg = Release|Any CPU {8788FF65-C2B6-40B2-A3A0-1E3D91C02664}.Release|x86.Build.0 = Release|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|x64.ActiveCfg = Debug|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|x64.Build.0 = Debug|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|x86.ActiveCfg = Debug|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Debug|x86.Build.0 = Debug|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Release|Any CPU.Build.0 = Release|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Release|x64.ActiveCfg = Release|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Release|x64.Build.0 = Release|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Release|x86.ActiveCfg = Release|Any CPU - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A}.Release|x86.Build.0 = Release|Any CPU {03032A2F-664D-4DD8-A82F-AD8A482EDD85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {03032A2F-664D-4DD8-A82F-AD8A482EDD85}.Debug|Any CPU.Build.0 = Debug|Any CPU {03032A2F-664D-4DD8-A82F-AD8A482EDD85}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -186,7 +172,6 @@ Global {CAF331F8-9255-4D72-A1A8-A54141E99F1E} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {4F15A8F8-5BC6-45A1-BC51-03F921B726A4} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {8788FF65-C2B6-40B2-A3A0-1E3D91C02664} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} - {778C4EB9-BD65-4C0F-9230-B5CB1D72186A} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {03032A2F-664D-4DD8-A82F-AD8A482EDD85} = {24B15015-62E5-42E1-9BA0-ECE6BE7AA15F} {DF0FCFB2-CB12-44BA-BBB5-1BE0BCFCD14C} = {076E1AE4-FD25-4684-B826-CAAE37FEA0AA} EndGlobalSection diff --git a/test/ResourceEntitySeparationExampleTests/Acceptance/AddTests.cs b/test/ResourceEntitySeparationExampleTests/Acceptance/AddTests.cs deleted file mode 100644 index 53105ee4b6..0000000000 --- a/test/ResourceEntitySeparationExampleTests/Acceptance/AddTests.cs +++ /dev/null @@ -1,212 +0,0 @@ -using JsonApiDotNetCoreExample.Models.Resources; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization.Infrastructure; -using Xunit; - -namespace ResourceEntitySeparationExampleTests.Acceptance -{ - [Collection("TestCollection")] - public class AddTests - { - private readonly TestFixture _fixture; - - public AddTests(TestFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task Can_Create_Course() - { - // arrange - var route = $"/api/v1/courses/"; - var course = _fixture.CourseFaker.Generate(); - var content = new - { - data = new - { - type = "courses", - attributes = new Dictionary() - { - { "number", course.Number }, - { "title", course.Title }, - { "description", course.Description } - } - } - }; - - // act - var (response, data) = await _fixture.PostAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(course.Number, data.Number); - Assert.Equal(course.Title, data.Title); - Assert.Equal(course.Description, data.Description); - } - - [Fact] - public async Task Can_Create_Course_With_Department_Id() - { - // arrange - var route = $"/api/v1/courses/"; - var course = _fixture.CourseFaker.Generate(); - - var department = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(department); - _fixture.Context.SaveChanges(); - - var content = new - { - data = new - { - type = "courses", - attributes = new Dictionary - { - { "number", course.Number }, - { "title", course.Title }, - { "description", course.Description } - }, - relationships = new - { - department = new - { - data = new - { - type = "departments", - id = department.Id - } - } - } - } - }; - - // act - var (response, data) = await _fixture.PostAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(course.Number, data.Number); - Assert.Equal(course.Title, data.Title); - Assert.Equal(course.Description, data.Description); - Assert.Equal(department.Id, data.Department.Id); - } - - [Fact] - public async Task Can_Create_Department() - { - // arrange - var route = $"/api/v1/departments/"; - var dept = _fixture.DepartmentFaker.Generate(); - var content = new - { - data = new - { - type = "departments", - attributes = new Dictionary() - { - { "name", dept.Name } - } - } - }; - - // act - var (response, data) = await _fixture.PostAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(dept.Name, data.Name); - } - - [Fact] - public async Task Can_Create_Department_With_Courses() - { - // arrange - var route = $"/api/v1/departments/"; - var dept = _fixture.DepartmentFaker.Generate(); - - var one = _fixture.CourseFaker.Generate(); - var two = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(one); - _fixture.Context.Courses.Add(two); - _fixture.Context.SaveChanges(); - - var content = new - { - data = new - { - type = "departments", - attributes = new Dictionary - { - { "name", dept.Name } - }, - relationships = new - { - courses = new - { - data = new[] - { - new - { - type = "courses", - id = one.Id - }, - new - { - type = "courses", - id = two.Id - } - } - } - } - } - }; - - // act - var (response, data) = await _fixture.PostAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(dept.Name, data.Name); - Assert.NotEmpty(data.Courses); - Assert.NotNull(data.Courses.SingleOrDefault(c => c.Id == one.Id)); - Assert.NotNull(data.Courses.SingleOrDefault(c => c.Id == two.Id)); - } - - [Fact] - public async Task Can_Create_Student() - { - // arrange - var route = $"/api/v1/students/"; - var student = _fixture.StudentFaker.Generate(); - var content = new - { - data = new - { - type = "students", - attributes = new Dictionary() - { - { "firstname", student.FirstName }, - { "lastname", student.LastName } - } - } - }; - - // act - var (response, data) = await _fixture.PostAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(student.FirstName, data.FirstName); - Assert.Equal(student.LastName, data.LastName); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/Acceptance/DeleteTests.cs b/test/ResourceEntitySeparationExampleTests/Acceptance/DeleteTests.cs deleted file mode 100644 index a5602e9936..0000000000 --- a/test/ResourceEntitySeparationExampleTests/Acceptance/DeleteTests.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace ResourceEntitySeparationExampleTests.Acceptance -{ - [Collection("TestCollection")] - public class DeleteTests - { - private readonly TestFixture _fixture; - - public DeleteTests(TestFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task Can_Delete_Course() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}"; - - // act - var response = await _fixture.DeleteAsync(route); - - // assert - Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); - } - - [Fact] - public async Task Can_Delete_Department() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/departments/{dept.Id}"; - - // act - var response = await _fixture.DeleteAsync(route); - - // assert - Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); - } - - [Fact] - public async Task Can_Delete_Student() - { - // arrange - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/students/{student.Id}"; - - // act - var response = await _fixture.DeleteAsync(route); - - // assert - Assert.Equal(HttpStatusCode.NoContent, response.StatusCode); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/Acceptance/GetTests.cs b/test/ResourceEntitySeparationExampleTests/Acceptance/GetTests.cs deleted file mode 100644 index 2d0d486b3c..0000000000 --- a/test/ResourceEntitySeparationExampleTests/Acceptance/GetTests.cs +++ /dev/null @@ -1,267 +0,0 @@ -using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Serialization.Contracts; - -using JsonApiDotNetCoreExample.Models.Entities; -using JsonApiDotNetCoreExample.Models.Resources; -using JsonApiDotNetCoreExampleTests.Helpers.Extensions; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Xunit; - -namespace ResourceEntitySeparationExampleTests.Acceptance -{ - [Collection("TestCollection")] - public class GetTests - { - private readonly TestFixture _fixture; - - public GetTests(TestFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task Can_Get_Courses() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Course_By_Id() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}"; - - // act - var (response, data) = await _fixture.GetAsync(route); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(course.Number, data.Number); - Assert.Equal(course.Title, data.Title); - Assert.Equal(course.Description, data.Description); - } - - [Fact] - public async Task Can_Get_Course_With_Relationships() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - - var course = _fixture.CourseFaker.Generate(); - course.Department = dept; - _fixture.Context.Courses.Add(course); - - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - - var reg = new CourseStudentEntity(course, student); - _fixture.Context.Registrations.Add(reg); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}?include=students,department"; - - // act - var (response, data) = await _fixture.GetAsync(route); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - - Assert.Equal(course.Number, data.Number); - Assert.Equal(course.Title, data.Title); - Assert.Equal(course.Description, data.Description); - - Assert.NotEmpty(data.Students); - Assert.NotNull(data.Students[0]); - Assert.Equal(student.Id, data.Students[0].Id); - Assert.Equal(student.LastName, data.Students[0].LastName); - - Assert.NotNull(data.Department); - Assert.Equal(dept.Id, data.Department.Id); - Assert.Equal(dept.Name, data.Department.Name); - } - - [Fact] - public async Task Can_Get_Departments() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/departments"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Department_By_Id() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/departments/{dept.Id}"; - - // act - var (response, data) = await _fixture.GetAsync(route); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(dept.Id, data.Id); - Assert.Equal(dept.Name, data.Name); - } - - [Fact] - public async Task Can_Get_Department_With_Relationships() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - - var course = _fixture.CourseFaker.Generate(); - course.Department = dept; - _fixture.Context.Courses.Add(course); - - var othercourse = _fixture.CourseFaker.Generate(); - othercourse.Department = dept; - _fixture.Context.Courses.Add(othercourse); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/departments/{dept.Id}?include=courses"; - - // act - var (response, data) = await _fixture.GetAsync(route); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - - Assert.Equal(dept.Id, data.Id); - Assert.Equal(dept.Name, data.Name); - - Assert.NotEmpty(data.Courses); - Assert.Equal(2, data.Courses.Count); - } - - [Fact] - public async Task Can_Get_Students() - { - // arrange - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/students"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Student_By_Id() - { - // arrange - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - _fixture.Context.SaveChanges(); - - var httpMethod = new HttpMethod("GET"); - var route = $"/api/v1/students/{student.Id}"; - - var request = new HttpRequestMessage(httpMethod, route); - - // act - var response = await _fixture.Server.CreateClient().SendAsync(request); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = (StudentResource)_fixture.Server.GetDeserializer() - .Deserialize(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.Equal(student.FirstName, deserializedBody.FirstName); - Assert.Equal(student.LastName, deserializedBody.LastName); - } - - [Fact] - public async Task Can_Get_Student_With_Relationships() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - _fixture.Context.SaveChanges(); - - var reg = new CourseStudentEntity(course, student); - _fixture.Context.Registrations.Add(reg); - _fixture.Context.SaveChanges(); - - var httpMethod = new HttpMethod("GET"); - var route = $"/api/v1/students/{student.Id}?include=courses"; - - var request = new HttpRequestMessage(httpMethod, route); - - // act - var response = await _fixture.Server.CreateClient().SendAsync(request); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = (StudentResource)_fixture.Server.GetDeserializer() - .Deserialize(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - - Assert.Equal(student.FirstName, deserializedBody.FirstName); - Assert.Equal(student.LastName, deserializedBody.LastName); - - Assert.NotEmpty(deserializedBody.Courses); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipGetTests.cs b/test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipGetTests.cs deleted file mode 100644 index a3ceff5b8f..0000000000 --- a/test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipGetTests.cs +++ /dev/null @@ -1,226 +0,0 @@ -using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Serialization.Contracts; - -using JsonApiDotNetCoreExample.Models.Entities; -using JsonApiDotNetCoreExample.Models.Resources; -using JsonApiDotNetCoreExampleTests.Helpers.Extensions; -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace ResourceEntitySeparationExampleTests.Acceptance -{ - [Collection("TestCollection")] - public class RelationshipGetTests - { - private readonly TestFixture _fixture; - - public RelationshipGetTests(TestFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task Can_Get_Courses_For_Department() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - var course = _fixture.CourseFaker.Generate(); - course.Department = dept; - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/departments/{dept.Id}/courses"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Course_Relationships_For_Department() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - var course = _fixture.CourseFaker.Generate(); - course.Department = dept; - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/departments/{dept.Id}/relationships/courses"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Courses_For_Student() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - - var reg = new CourseStudentEntity(course, student); - _fixture.Context.Registrations.Add(reg); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/students/{student.Id}/courses"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Course_Relationships_For_Student() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - - var reg = new CourseStudentEntity(course, student); - _fixture.Context.Registrations.Add(reg); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/students/{student.Id}/relationships/courses"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Department_For_Course() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - var course = _fixture.CourseFaker.Generate(); - course.Department = dept; - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}/department"; - - // act - var (response, data) = await _fixture.GetAsync(route); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(dept.Name, data.Name); - } - - [Fact] - public async Task Can_Get_Department_Relationships_For_Course() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - var course = _fixture.CourseFaker.Generate(); - course.Department = dept; - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}/relationships/department"; - - // act - var (response, data) = await _fixture.GetAsync(route); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - } - - [Fact] - public async Task Can_Get_Students_For_Course() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - _fixture.Context.SaveChanges(); - - var reg = new CourseStudentEntity(course, student); - _fixture.Context.Registrations.Add(reg); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}/students"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - - [Fact] - public async Task Can_Get_Student_Relationships_For_Course() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - - var reg = new CourseStudentEntity(course, student); - _fixture.Context.Registrations.Add(reg); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}/relationships/students"; - - // act - var response = await _fixture.SendAsync("GET", route, null); - var responseBody = await response.Content.ReadAsStringAsync(); - var deserializedBody = _fixture.Server.GetDeserializer() - .DeserializeList(responseBody); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(deserializedBody); - Assert.NotEmpty(deserializedBody); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipModifyTests.cs b/test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipModifyTests.cs deleted file mode 100644 index 2fd6ffc81d..0000000000 --- a/test/ResourceEntitySeparationExampleTests/Acceptance/RelationshipModifyTests.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Newtonsoft.Json; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Xunit; - -namespace ResourceEntitySeparationExampleTests.Acceptance -{ - [Collection("TestCollection")] - public class RelationshipModifyTests - { - private readonly TestFixture _fixture; - - public RelationshipModifyTests(TestFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task Can_Patch_HasOne_Relationship() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/courses/{course.Id}/relationships/department"; - var content = new - { - data = new - { - type = "departments", - id = $"{dept.Id}" - } - }; - - // act - var response = await _fixture.SendAsync("PATCH", route, content); - var responseBody = await response.Content.ReadAsStringAsync(); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - - _fixture.Context.Entry(course).Reload(); - Assert.Equal(dept.Id, course.DepartmentId); - } - - [Fact] - public async Task Can_Patch_HasMany_Relationship() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - - var course1 = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course1); - var course2 = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course2); - _fixture.Context.SaveChanges(); - - var route = $"/api/v1/departments/{dept.Id}/relationships/courses"; - var content = new - { - data = new List - { - new { - type = "courses", - id = $"{course1.Id}" - }, - new { - type = "courses", - id = $"{course2.Id}" - } - } - }; - - // act - var response = await _fixture.SendAsync("PATCH", route, content); - var responseBody = await response.Content.ReadAsStringAsync(); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - - _fixture.Context.Entry(course1).Reload(); - _fixture.Context.Entry(course2).Reload(); - Assert.Equal(dept.Id, course1.DepartmentId); - Assert.Equal(dept.Id, course2.DepartmentId); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/Acceptance/UpdateTests.cs b/test/ResourceEntitySeparationExampleTests/Acceptance/UpdateTests.cs deleted file mode 100644 index eeb838c475..0000000000 --- a/test/ResourceEntitySeparationExampleTests/Acceptance/UpdateTests.cs +++ /dev/null @@ -1,121 +0,0 @@ -using JsonApiDotNetCoreExample.Models.Resources; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace ResourceEntitySeparationExampleTests.Acceptance -{ - [Collection("TestCollection")] - public class UpdateTests - { - private readonly TestFixture _fixture; - - public UpdateTests(TestFixture fixture) - { - _fixture = fixture; - } - - [Fact] - public async Task Can_Update_Course() - { - // arrange - var course = _fixture.CourseFaker.Generate(); - _fixture.Context.Courses.Add(course); - _fixture.Context.SaveChanges(); - - var updatedCourse = _fixture.CourseFaker.Generate(); - - var route = $"/api/v1/courses/{course.Id}"; - var content = new - { - data = new - { - id = course.Id, - type = "courses", - attributes = new Dictionary() - { - { "number", updatedCourse.Number } - } - } - }; - - // act - var (response, data) = await _fixture.PatchAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(course.Id, data.Id); - Assert.Equal(updatedCourse.Number, data.Number); - } - - [Fact] - public async Task Can_Update_Department() - { - // arrange - var dept = _fixture.DepartmentFaker.Generate(); - _fixture.Context.Departments.Add(dept); - _fixture.Context.SaveChanges(); - - var updatedDept = _fixture.DepartmentFaker.Generate(); - - var route = $"/api/v1/departments/{dept.Id}"; - var content = new - { - data = new - { - id = dept.Id, - type = "departments", - attributes = new Dictionary() - { - { "name", updatedDept.Name } - } - } - }; - - // act - var (response, data) = await _fixture.PatchAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(dept.Id, data.Id); - Assert.Equal(updatedDept.Name, data.Name); - } - - [Fact] - public async Task Can_Update_Student() - { - // arrange - var student = _fixture.StudentFaker.Generate(); - _fixture.Context.Students.Add(student); - _fixture.Context.SaveChanges(); - - var updatedStudent = _fixture.StudentFaker.Generate(); - - var route = $"/api/v1/students/{student.Id}"; - var content = new - { - data = new - { - id = student.Id, - type = "students", - attributes = new Dictionary() - { - { "lastname", updatedStudent.LastName } - } - } - }; - - // act - var (response, data) = await _fixture.PatchAsync(route, content); - - // assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.NotNull(data); - Assert.Equal(student.Id, data.Id); - Assert.Equal(updatedStudent.LastName, data.LastName); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj b/test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj deleted file mode 100644 index 5a79c7b9d3..0000000000 --- a/test/ResourceEntitySeparationExampleTests/ResourceEntitySeparationExampleTests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - netcoreapp2.0 - - false - - - - - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers - all - - - - diff --git a/test/ResourceEntitySeparationExampleTests/TestCollection.cs b/test/ResourceEntitySeparationExampleTests/TestCollection.cs deleted file mode 100644 index 42a16eb67a..0000000000 --- a/test/ResourceEntitySeparationExampleTests/TestCollection.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Xunit; - -[assembly: CollectionBehavior(DisableTestParallelization = true)] -namespace ResourceEntitySeparationExampleTests -{ - [CollectionDefinition("TestCollection")] - public class TestCollection : ICollectionFixture - { } -} diff --git a/test/ResourceEntitySeparationExampleTests/TestFixture.cs b/test/ResourceEntitySeparationExampleTests/TestFixture.cs deleted file mode 100644 index aaa12ff860..0000000000 --- a/test/ResourceEntitySeparationExampleTests/TestFixture.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Bogus; -using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Serialization.Contracts; - -using JsonApiDotNetCoreExample.Data; -using JsonApiDotNetCoreExample.Models.Entities; -using JsonApiDotNetCoreExampleTests.Helpers.Extensions; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Newtonsoft.Json; -using System; -using System.Collections; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; - -namespace ResourceEntitySeparationExampleTests -{ - public class TestFixture : IDisposable - { - public HttpClient Client { get; private set; } - public AppDbContext Context { get; private set; } - public TestServer Server { get; private set; } - - public Faker CourseFaker { get; private set; } - public Faker DepartmentFaker { get; private set; } - public Faker StudentFaker { get; private set; } - - public TestFixture() - { - var builder = new WebHostBuilder().UseStartup(); - Server = new TestServer(builder); - Context = Server.GetService(); - Context.Database.EnsureCreated(); - Client = Server.CreateClient(); - - CourseFaker = new Faker() - .RuleFor(c => c.Number, f => f.Random.Int(min: 0, max: 1000)) - .RuleFor(c => c.Title, f => f.Name.JobArea()) - .RuleFor(c => c.Description, f => f.Lorem.Paragraph()); - - DepartmentFaker = new Faker() - .RuleFor(d => d.Name, f => f.Commerce.Department()); - - StudentFaker = new Faker() - .RuleFor(s => s.FirstName, f => f.Name.FirstName()) - .RuleFor(s => s.LastName, f => f.Name.LastName()); - } - - public void Dispose() - { - Server.Dispose(); - } - - public async Task DeleteAsync(string route) - { - return await SendAsync("DELETE", route, null); - } - - public async Task<(HttpResponseMessage response, T data)> GetAsync(string route) - { - return await SendAsync("GET", route, null); - } - - public async Task<(HttpResponseMessage response, T data)> PatchAsync(string route, object data) - { - return await SendAsync("PATCH", route, data); - } - - public async Task<(HttpResponseMessage response, T data)> PostAsync(string route, object data) - { - return await SendAsync("POST", route, data); - } - - public async Task SendAsync(string method, string route, object data) - { - var httpMethod = new HttpMethod(method); - var request = new HttpRequestMessage(httpMethod, route) - { - Content = new StringContent(JsonConvert.SerializeObject(data)) - }; - request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); - return await Client.SendAsync(request); - } - - public async Task<(HttpResponseMessage response, T data)> SendAsync(string method, string route, object data) - { - var response = await SendAsync(method, route, data); - var json = await response.Content.ReadAsStringAsync(); - var obj = (T)Server.GetDeserializer().Deserialize(json); - return (response, obj); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/TestStartup.cs b/test/ResourceEntitySeparationExampleTests/TestStartup.cs deleted file mode 100644 index c7b74ad55d..0000000000 --- a/test/ResourceEntitySeparationExampleTests/TestStartup.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JsonApiDotNetCore.Services; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using ResourceEntitySeparationExample; -using System; -using UnitTests; - -namespace ResourceEntitySeparationExampleTests -{ - public class TestStartup : Startup - { - public TestStartup(IHostingEnvironment env) : base(env) - { } - - public override IServiceProvider ConfigureServices(IServiceCollection services) - { - base.ConfigureServices(services); - services.AddScoped(); - return services.BuildServiceProvider(); - } - } -} diff --git a/test/ResourceEntitySeparationExampleTests/appsettings.json b/test/ResourceEntitySeparationExampleTests/appsettings.json deleted file mode 100644 index 603b456dc6..0000000000 --- a/test/ResourceEntitySeparationExampleTests/appsettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Data": { - "DefaultConnection": - "Host=localhost;Port=5432;Database=JsonApiDotNetCoreExample;User ID=postgres;Password=postgres" - }, - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Warning", - "Microsoft": "Warning", - "JsonApiDotNetCore.Middleware.JsonApiExceptionFilter": "Critical" - } - } -} From 40c92033cd728f54d2694c64dd92b6b85d801014 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 10 Oct 2019 13:14:31 +0200 Subject: [PATCH 6/7] chore: update other test projects to pass again --- .../Services/CustomArticleService.cs | 7 ++++++- .../Acceptance/Extensibility/NoEntityFrameworkTests.cs | 4 ---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs b/src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs index c3e6a98dc2..0035f6855c 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Services/CustomArticleService.cs @@ -16,7 +16,12 @@ namespace JsonApiDotNetCoreExample.Services { public class CustomArticleService : EntityResourceService
{ - public CustomArticleService(IEntityRepository repository, IJsonApiOptions options, ITargetedFields updatedFields, ICurrentRequest currentRequest, IIncludeService includeService, ISparseFieldsService sparseFieldsService, IPageQueryService pageManager, IResourceGraph resourceGraph, IResourceHookExecutor hookExecutor = null, IResourceMapper mapper = null, ILoggerFactory loggerFactory = null) : base(repository, options, updatedFields, currentRequest, includeService, sparseFieldsService, pageManager, resourceGraph, hookExecutor, mapper, loggerFactory) + public CustomArticleService(IEntityRepository repository, IJsonApiOptions options, + ITargetedFields updatedFields, ICurrentRequest currentRequest, + IIncludeService includeService, ISparseFieldsService sparseFieldsService, + IPageQueryService pageManager, IResourceGraph resourceGraph, + IResourceHookExecutor hookExecutor = null, ILoggerFactory loggerFactory = null) + : base(repository, options, updatedFields, currentRequest, includeService, sparseFieldsService, pageManager, resourceGraph, hookExecutor, loggerFactory) { } diff --git a/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs b/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs index b7271e19a0..e964da8d1e 100644 --- a/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs +++ b/test/NoEntityFrameworkTests/Acceptance/Extensibility/NoEntityFrameworkTests.cs @@ -3,11 +3,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; -using JsonApiDotNetCore.Serialization; -using JsonApiDotNetCore.Serialization.Contracts; - using JsonApiDotNetCoreExample.Models; -using JsonApiDotNetCoreExampleTests.Helpers.Extensions; using Newtonsoft.Json; using Xunit; From 622875aaa25a8dc0cdf0269caa2feba044e7e9b0 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 10 Oct 2019 13:20:37 +0200 Subject: [PATCH 7/7] chore: fix typo --- src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs index 54d64142d2..99c1fef714 100644 --- a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs +++ b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs @@ -62,7 +62,7 @@ public interface IBeforeHooks where TResource : class, IIdentifiable /// changes of the properties on the entities. /// /// If new relationships are to be created with the to-be-updated entities, - /// this will be reflected by the corresponding NavigationProperty beinƒg set. + /// this will be reflected by the corresponding NavigationProperty being set. /// For each of these relationships, the /// hook is fired after the execution of this hook. ///