From 167197ae4b9e86b877353de159c05fc19fd59942 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 22:52:49 +0000 Subject: [PATCH 01/10] Bump actions/dependency-review-action from 3 to 4 (#1442) --- .github/workflows/deps-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deps-review.yml b/.github/workflows/deps-review.yml index b9945082d5..b9d6d20fff 100644 --- a/.github/workflows/deps-review.yml +++ b/.github/workflows/deps-review.yml @@ -11,4 +11,4 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@v4 - name: 'Dependency Review' - uses: actions/dependency-review-action@v3 + uses: actions/dependency-review-action@v4 From 459e27bd0cd3b153390ee89b8835494fcfca38ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 00:19:23 +0000 Subject: [PATCH 02/10] Bump jetbrains.resharper.globaltools from 2023.3.2 to 2023.3.3 (#1443) --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 575923d62c..556e9c5598 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "jetbrains.resharper.globaltools": { - "version": "2023.3.2", + "version": "2023.3.3", "commands": [ "jb" ] From 8d37ce6488c552b5352f3774557945b869b96dfe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 23:52:10 +0000 Subject: [PATCH 03/10] Bump dotnet-reportgenerator-globaltool from 5.2.0 to 5.2.1 (#1453) --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 556e9c5598..9658fff117 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "dotnet-reportgenerator-globaltool": { - "version": "5.2.0", + "version": "5.2.1", "commands": [ "reportgenerator" ] From 412af65b275a372c8de935f2db7cf37b0e0f448f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 00:26:58 +0000 Subject: [PATCH 04/10] Bump codecov/codecov-action from 3 to 4 (#1452) --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb3aab63b2..0e41da591a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -138,7 +138,9 @@ jobs: dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage" --logger "GitHubActions;summary.includeSkippedTests=true" - name: Upload coverage to codecov.io if: matrix.os == 'ubuntu-latest' - uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + uses: codecov/codecov-action@v4 with: fail_ci_if_error: true verbose: true From d9d74f4bb2eda64a6196c3a6424185092e11ed0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Tue, 6 Feb 2024 21:42:12 -0500 Subject: [PATCH 05/10] doc: fix path of path example --- docs/usage/writing/updating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/writing/updating.md b/docs/usage/writing/updating.md index ea27e1a220..30e1b4fa7d 100644 --- a/docs/usage/writing/updating.md +++ b/docs/usage/writing/updating.md @@ -5,7 +5,7 @@ To modify the attributes of a single resource, send a PATCH request. The next example changes the article caption: ```http -PATCH /articles HTTP/1.1 +PATCH /articles/1 HTTP/1.1 { "data": { From 06195b84be389223508de5077a5127098cdef0c1 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:40:52 +0100 Subject: [PATCH 06/10] Update ROADMAP.md --- ROADMAP.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 270ae294e6..3ffba718e7 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,12 +2,14 @@ This document provides an overview of the direction this project is heading and lists what we intend to work on in the near future. -> Disclaimer: This is an open source project. The available time of our contributors varies and therefore we do not plan release dates. This document expresses our current intent, which may change over time. +> Disclaimer: This is an open-source project. The available time of our contributors varies and therefore we do not plan release dates. This document expresses our current intent, which may change over time. -We have interest in the following topics. It's too soon yet to decide whether they'll make it into v5.x or in a later major version. +We have an interest in the following topics. It's too soon yet to decide whether they'll make it into v5.x or in a later major version. +- OpenAPI (Swagger): Generate documentation and typed clients [#1046](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1046) +- Query strings on JSON-mapped columns [#1439](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1439) +- Improved SQL Server support [#1118](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1118) - Optimistic concurrency [#1119](https://github.com/json-api-dotnet/JsonApiDotNetCore/pull/1119) -- OpenAPI (Swagger) [#1046](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/1046) - Fluent API [#776](https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/776) - Idempotency [#1132](https://github.com/json-api-dotnet/JsonApiDotNetCore/pull/1132) From 587d972e208f40650da7a5723b067e1c839cc40b Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:43:41 +0100 Subject: [PATCH 07/10] Add sponsor link --- ROADMAP.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index 3ffba718e7..7ba6a2a5a8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -21,3 +21,5 @@ Please give us feedback that will give us insight on the following points: * Existing features that are missing some capability or otherwise don't work well enough. * Missing features that should be added to the product. * Design choices for a feature that is currently in-progress. + +Please consider to [sponsor the project](https://github.com/sponsors/json-api-dotnet). From 3f62b77c5e7ebf757d80d01ce0a3d455b51ad9e3 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sun, 18 Feb 2024 02:45:56 +0100 Subject: [PATCH 08/10] Replaces CreateTupleAccessExpressionForConstant with CloseOver, which is simpler and requires less reflection. --- .../QueryableBuilding/SelectClauseBuilder.cs | 4 +-- .../SkipTakeClauseBuilder.cs | 2 +- .../QueryableBuilding/WhereClauseBuilder.cs | 3 +- .../Queries/SystemExpressionBuilder.cs | 34 +++++++++++++++++++ .../Queries/SystemExpressionExtensions.cs | 33 ------------------ .../Resources/ResourceFactory.cs | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-) create mode 100644 src/JsonApiDotNetCore/Queries/SystemExpressionBuilder.cs delete mode 100644 src/JsonApiDotNetCore/Queries/SystemExpressionExtensions.cs diff --git a/src/JsonApiDotNetCore/Queries/QueryableBuilding/SelectClauseBuilder.cs b/src/JsonApiDotNetCore/Queries/QueryableBuilding/SelectClauseBuilder.cs index 858532d7c2..d1113946ad 100644 --- a/src/JsonApiDotNetCore/Queries/QueryableBuilding/SelectClauseBuilder.cs +++ b/src/JsonApiDotNetCore/Queries/QueryableBuilding/SelectClauseBuilder.cs @@ -93,9 +93,9 @@ private Expression CreateLambdaBodyInitializerForTypeHierarchy(FieldSelection se private static BinaryExpression CreateRuntimeTypeCheck(LambdaScope lambdaScope, Type concreteClrType) { // Emitting "resource.GetType() == typeof(Article)" instead of "resource is Article" so we don't need to check for most-derived - // types first. This way, we can fallback to "anything else" at the end without worrying about order. + // types first. This way, we can fall back to "anything else" at the end without worrying about order. - Expression concreteTypeConstant = concreteClrType.CreateTupleAccessExpressionForConstant(typeof(Type)); + Expression concreteTypeConstant = SystemExpressionBuilder.CloseOver(concreteClrType); MethodCallExpression getTypeCall = Expression.Call(lambdaScope.Accessor, TypeGetTypeMethod); return Expression.MakeBinary(ExpressionType.Equal, getTypeCall, concreteTypeConstant, false, TypeOpEqualityMethod); diff --git a/src/JsonApiDotNetCore/Queries/QueryableBuilding/SkipTakeClauseBuilder.cs b/src/JsonApiDotNetCore/Queries/QueryableBuilding/SkipTakeClauseBuilder.cs index b48fa696db..4c54586cb6 100644 --- a/src/JsonApiDotNetCore/Queries/QueryableBuilding/SkipTakeClauseBuilder.cs +++ b/src/JsonApiDotNetCore/Queries/QueryableBuilding/SkipTakeClauseBuilder.cs @@ -36,7 +36,7 @@ public override Expression VisitPagination(PaginationExpression expression, Quer private static Expression ExtensionMethodCall(Expression source, string operationName, int value, QueryClauseBuilderContext context) { - Expression constant = value.CreateTupleAccessExpressionForConstant(typeof(int)); + Expression constant = SystemExpressionBuilder.CloseOver(value); return Expression.Call(context.ExtensionType, operationName, [context.LambdaScope.Parameter.Type], source, constant); } diff --git a/src/JsonApiDotNetCore/Queries/QueryableBuilding/WhereClauseBuilder.cs b/src/JsonApiDotNetCore/Queries/QueryableBuilding/WhereClauseBuilder.cs index f14d795f7b..b5fafdd21b 100644 --- a/src/JsonApiDotNetCore/Queries/QueryableBuilding/WhereClauseBuilder.cs +++ b/src/JsonApiDotNetCore/Queries/QueryableBuilding/WhereClauseBuilder.cs @@ -245,7 +245,6 @@ public override Expression VisitNullConstant(NullConstantExpression expression, public override Expression VisitLiteralConstant(LiteralConstantExpression expression, QueryClauseBuilderContext context) { - Type type = expression.TypedValue.GetType(); - return expression.TypedValue.CreateTupleAccessExpressionForConstant(type); + return SystemExpressionBuilder.CloseOver(expression.TypedValue); } } diff --git a/src/JsonApiDotNetCore/Queries/SystemExpressionBuilder.cs b/src/JsonApiDotNetCore/Queries/SystemExpressionBuilder.cs new file mode 100644 index 0000000000..f625ee9b4f --- /dev/null +++ b/src/JsonApiDotNetCore/Queries/SystemExpressionBuilder.cs @@ -0,0 +1,34 @@ +using System.Linq.Expressions; +using System.Reflection; + +#pragma warning disable AV1008 + +namespace JsonApiDotNetCore.Queries; + +internal static class SystemExpressionBuilder +{ + private static readonly MethodInfo CloseOverOpenMethod = + typeof(SystemExpressionBuilder).GetMethods().Single(method => method is { Name: nameof(CloseOver), IsGenericMethod: true }); + + // To enable efficient query plan caching, inline constants (that vary per request) should be converted into query parameters. + // https://stackoverflow.com/questions/54075758/building-a-parameterized-entityframework-core-expression + // + // CloseOver can be used to change a query like: + // SELECT ... FROM ... WHERE x."Age" = 3 + // into: + // SELECT ... FROM ... WHERE x."Age" = @p0 + + public static Expression CloseOver(object value) + { + ArgumentGuard.NotNull(value); + + MethodInfo closeOverClosedMethod = CloseOverOpenMethod.MakeGenericMethod(value.GetType()); + return (Expression)closeOverClosedMethod.Invoke(null, [value])!; + } + + public static Expression CloseOver(T value) + { + // From https://github.com/dotnet/efcore/issues/28151#issuecomment-1374480257. + return ((Expression>)(() => value)).Body; + } +} diff --git a/src/JsonApiDotNetCore/Queries/SystemExpressionExtensions.cs b/src/JsonApiDotNetCore/Queries/SystemExpressionExtensions.cs deleted file mode 100644 index ef81aece33..0000000000 --- a/src/JsonApiDotNetCore/Queries/SystemExpressionExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Linq.Expressions; -using System.Reflection; - -namespace JsonApiDotNetCore.Queries; - -internal static class SystemExpressionExtensions -{ - public static Expression CreateTupleAccessExpressionForConstant(this object? value, Type type) - { - // To enable efficient query plan caching, inline constants (that vary per request) should be converted into query parameters. - // https://stackoverflow.com/questions/54075758/building-a-parameterized-entityframework-core-expression - - // This method can be used to change a query like: - // SELECT ... FROM ... WHERE x."Age" = 3 - // into: - // SELECT ... FROM ... WHERE x."Age" = @p0 - - // The code below builds the next expression for a type T that is unknown at compile time: - // Expression.Property(Expression.Constant(Tuple.Create(value)), "Item1") - // Which represents the next C# code: - // Tuple.Create(value).Item1; - - MethodInfo tupleCreateUnboundMethod = typeof(Tuple).GetMethods() - .Single(method => method is { Name: "Create", IsGenericMethod: true } && method.GetGenericArguments().Length == 1); - - MethodInfo tupleCreateClosedMethod = tupleCreateUnboundMethod.MakeGenericMethod(type); - - ConstantExpression constantExpression = Expression.Constant(value, type); - - MethodCallExpression tupleCreateCall = Expression.Call(tupleCreateClosedMethod, constantExpression); - return Expression.Property(tupleCreateCall, "Item1"); - } -} diff --git a/src/JsonApiDotNetCore/Resources/ResourceFactory.cs b/src/JsonApiDotNetCore/Resources/ResourceFactory.cs index 9d282b4938..f8af9dfa2f 100644 --- a/src/JsonApiDotNetCore/Resources/ResourceFactory.cs +++ b/src/JsonApiDotNetCore/Resources/ResourceFactory.cs @@ -102,7 +102,7 @@ public NewExpression CreateNewExpression(Type resourceClrType) { object constructorArgument = ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, constructorParameter.ParameterType); - Expression argumentExpression = constructorArgument.CreateTupleAccessExpressionForConstant(constructorArgument.GetType()); + Expression argumentExpression = SystemExpressionBuilder.CloseOver(constructorArgument); constructorArguments.Add(argumentExpression); } #pragma warning disable AV1210 // Catch a specific exception instead of Exception, SystemException or ApplicationException From df5902d3649fa85fd82bbdf9533a583736a79295 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Wed, 21 Feb 2024 06:29:48 +0100 Subject: [PATCH 09/10] Fix type/filename mismatch --- ...AssertionsExtension.cs => PropertyInfoAssertionsExtensions.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/OpenApiClientTests/{PropertyInfoAssertionsExtension.cs => PropertyInfoAssertionsExtensions.cs} (100%) diff --git a/test/OpenApiClientTests/PropertyInfoAssertionsExtension.cs b/test/OpenApiClientTests/PropertyInfoAssertionsExtensions.cs similarity index 100% rename from test/OpenApiClientTests/PropertyInfoAssertionsExtension.cs rename to test/OpenApiClientTests/PropertyInfoAssertionsExtensions.cs From d1707ef55642f258249a4dd9e2054f23e5acf6c9 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Wed, 21 Feb 2024 07:10:13 +0100 Subject: [PATCH 10/10] Resharper: "Local function can be made static" is at warning level in cibuild, but was turned off in IDE (#1473) --- JsonApiDotNetCore.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/JsonApiDotNetCore.sln.DotSettings b/JsonApiDotNetCore.sln.DotSettings index 6e4e064588..4f68cc519a 100644 --- a/JsonApiDotNetCore.sln.DotSettings +++ b/JsonApiDotNetCore.sln.DotSettings @@ -59,6 +59,7 @@ JsonApiDotNetCore.ArgumentGuard.NotNull($EXPR$); SUGGESTION HINT WARNING + SUGGESTION DO_NOT_SHOW HINT SUGGESTION