diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 0b747b8c..eb4054de 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -33,5 +33,5 @@ jobs: with: global-json-file: global.json dotnet-version: | - 9.x + 10.x 8.x diff --git a/.github/workflows/publish-ci.yml b/.github/workflows/publish-ci.yml index a6b76300..f31487b5 100644 --- a/.github/workflows/publish-ci.yml +++ b/.github/workflows/publish-ci.yml @@ -8,7 +8,7 @@ on: env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 DOTNET_NOLOGO: true - DOTNET_SDK_VERSION: 9.0.307 + DOTNET_SDK_VERSION: 10.0.202 jobs: publish: diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 849de8d2..d4df8454 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -9,7 +9,7 @@ env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 DOTNET_NOLOGO: true SLEEP_DURATION: 60 - DOTNET_SDK_VERSION: 9.0.307 + DOTNET_SDK_VERSION: 10.0.202 jobs: publish: diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 9333d342..07356a39 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, windows-latest, macOS-latest] - dotnet: [9.0.307] + dotnet: [10.0.202] runs-on: ${{ matrix.os }} steps: diff --git a/Directory.Build.props b/Directory.Build.props index 37bb94b2..aff702c9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,9 +1,9 @@ - net8.0 - 9.0 - 9.0.* + net10.0 + 10.0 + 10.0.* true true $(NoWarn);NU1504;NU1701 @@ -11,7 +11,7 @@ - 3.1.1 + 4.0.0 diff --git a/Packages.props b/Packages.props index e2860d90..8d49347e 100644 --- a/Packages.props +++ b/Packages.props @@ -1,10 +1,10 @@  - 8.0.* - 8.0.* - 8.0.* - 9.0.202 + 10.0.* + 10.0.* + 10.0.* + 10.1.202 4.17.* 2.9.3 6.* diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e4a2d805..948a801c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,9 @@ #### 0.0.1-beta - 2016-04-19 + * Initial release #### 0.0.2-beta - 2016-09-01 + * Introduced intermediate representation of GraphQL operation execution. * Introduced ability to convert GraphQL query to LINQ. * Replaced current asynchronous API resolver internals. @@ -9,11 +11,13 @@ * Minor bugfixes and performance optimizations. ### 0.0.3-beta - 2018-03-22 + * Introduced a sample for GraphQL over WebSocket Protocol * Introduced support for Stream and Defer directives * Minor bugfixes. ### 0.0.4-beta - 2018-05-31 + * Introduced support for middlewares in the execution pipeline. * Introduced new package, named FSharp.Data.GraphQL.Server.Middleware, with generic, built-in middlewares. * Introduced QueryWeightMiddleware, a generic execution middleware to measure query complexity and optionally block query execution with a threshold. @@ -26,9 +30,11 @@ * Added support for nested deferred and streamed results (currently does have a maximum degree of two nested operations). ### 0.0.4-beta01 - 2018-05-31 + * Fix package dependency versions ### 0.0.5-beta - 2018-08-10 + * Upgraded dependencies on Newtonsoft.Json to the latest version. * Changing subscription field definitions to have a generic output type - the output is not required to be a GraphQL type anymore. * Implemented experimental support for @live directive, through a subscription system. @@ -36,86 +42,108 @@ * Added support for asynchronous subscription field definitions. ### 0.0.6-beta - 2018-08-10 + * Fixes for introspection query * Use string identifier to publish to subscription ### 0.0.7-beta - 2018-09-17 + * **Breaking Change:** Async Pub/Sub methods for subscription and live directive handler interfaces * Add Long Scalar definition ### 0.0.8-beta - 2018-10-27 + * Add subscription field to introspection schema ### 0.0.8-beta01 - 2018-10-28 + * Add subscription field to introspection schema ### 0.0.9 - 2018-11-02 + * Fixed a bug where output def of a subscription field was not reachable for introspection. ### 0.0.10-beta - 2018-11-13 + * Deferred and Streamed results now return their fields in the direct result as well. The value of those fields will be an empty list or null. * Live results now send the immediate result in the direct result, instead of the deferred result. ### 0.0.11-beta - 2018-11-21 + * Deferred and Streamed results fixes for GQL interfaces. ### 0.0.12-beta - 2018-11-21 + * Deferred and Streamed results fixes for GQL interfaces when at the top-level of query. ### 0.0.16-beta - 2019-01-03 + * **Breaking Change** The `ISubscriptionProvider` interface now has additional methods to publish to subscriptions by tag. * **Breaking Change** Renamed interface methods in `ISubscriptionProvider` from XxAsync to AsyncXx to reserve the former for TPL extensions. * Fixes for stream and defer execution. ### 0.0.17-beta - 2019-01-11 + * Execute deferred results in parallel. ### 0.0.18-beta - 2019-01-16 + * Fix dispose of deferred/stream responses. ### 1.0.0-beta - 2019-04-27 + * **Breaking Change** New type provider API! see samples/client-provider for details. * Fixes for #216 enum as a variable. * Upgraded paket and dependencies. ### 1.0.0-beta2 - 2019-04-27 + * **Breaking Change** GraphQLProvider now makes Nullable GraphQL inputs optional method arguments instead of options * **Breaking Change** GraphQLProvider uses the operation name as the generated operation type's names. if no operation name is specified it uses "Operation" + the query string's hash * Make the type provider cross-targeting * **Breaking Change** Add postcompile phase to middleware interface ### 1.0.0-beta3 - 2019-05-10 + * **Breaking Change** GraphQLProvider record types constructors now receive option arguments as optional arguments * Revision on scalar types parsing - fixed some wrong behaviors such as parsing ints as floats ### 1.0.0-beta4 - 2019-05-13 + * Fixing a bug when converting variable types to variables json in a query ### 1.0.0-beta5 - 2019-05-13 + * Fixing a bug when parsing json objects with no fields in serialization ### 1.0.0-beta6 - 2019-05-17 + * Changing constructors of provided types to have overloads instead of optional parameters (needed because of a limitation of the Type Provider SDK) * Adding support for field aliases * Operation result errors and custom data now are provided as their respective types instead of options (`Operation Error []` and `Map`) ### 1.0.0-beta7 - 2019-05-17 + * Minor bug fixes * Fixing an error on overload constructor definition ### 1.0.0-beta8 - 2019-05-22 + * Performance improvements ### 1.0.0-beta9 - 2019-05-22 + * Fixing dependency issue on Server component ### 1.0.0-beta90 - 2019-05-29 + * Fixing a wrong cast for System.Uri type * Adding support for file uploads through [GraphQL Multipart Request Spec](https://github.com/jaydenseric/graphql-multipart-request-spec) * Changing variable parameters of Run/AsyncRun methods to work as overloaded methods instead of one having optional parameters * Minor bug fixes ### 1.0.0 - 2019-07-04 + * Changing the internal client of the Type provider (`System.Net.Http.HttpClient`) * Fixing several minor bugs of the file upload system in the client provider * Limiting the upload type of the client provider to be a scalar type (provider fails if it is not) @@ -129,34 +157,40 @@ * **Breaking Change** Renaming `FSharp.Data.GraphQL.Server.Middlewares` package to `FSharp.Data.GraphQL.Server.Middleware` ### 1.0.1 - 2019-07-05 + * Adjusting package dependencies (`FParsec`, `System.Net.Http`, and `FSharp.Data.GraphQL.Server` are not locked anymore) ### 1.0.2 - 2019-08-19 + * fixed false positive validation errors related to variable usage. ### 1.0.3 - 2020-03-03 + * Correct printing of queries without names * Correct printing of ListValue and ObjectValue * Traverse list values in argument lists * Added test cases for object inputs for GraphQL functions - ### 1.0.4 - 2020-03-22 + * TypeProvider now treats custom scalars as strings * The Guid scalar was mapped to a DateTime - ### 1.0.5 - 2020-03-23 + * Support opening static classes * Add additional case in client to support failed requests that don't return a path. ### 1.0.6 - 2020-12-15 + * TypeProvider accepts IHttpClientFactory as input ### 1.0.7 - 2020-12-30 + * Add static TypeProvider parameter `explicitOptionalParameters`. ### 1.0.8 - 2021-04-18 + * Remove Desktop build * Update documentation and build tools * Upgrade build scripts @@ -166,6 +200,7 @@ * Fix parser bug. Thanks to @njlr ### 2.0.0 - 2024-03-24 + * **Breaking Change** Migrated to .NET 6/7 and F# 7 * **Breaking Change** Implemented GraphQL error handling using `IGQLError` interface instead of exceptions * **Breaking Change** Implemented parsing variables as `JsonElement` @@ -186,17 +221,21 @@ * Fixed various introspection and default value encoding issues ### 2.1.0 - 2024-04-13 + * Improved server exception logging by including exception in log message * Documentation and README improvements ### 2.2.0 - 2024-05-08 + * Improved `AddGraphQLOptions` * Added Altair and GraphiQL to sample projects ### 2.2.1 - 2024-06-16 + * Fixed `JsonSerializerOptions` read-only instance error ### 3.0.0 - 2025-11-30 + * **Breaking Change** Migrated to .NET 8 and F# 9.0 with `FSharp.Core` 9.0.x * **Breaking Change** Updated scalar `CoerceOutput` signature to `objnull -> 'Primitive option` * **Breaking Change** Moved GraphQL error extensions to standard `extensions` field according to specification @@ -244,3 +283,9 @@ * Fixed planning phase crash when inline fragments reference types not included in union or interface definitions * Fixed GraphQL client provider handling for schema types that reuse reserved scalar names such as `Date`, so introspection kind now takes precedence over built-in scalar mappings. + +### 4.0.0 - Unreleased + +* **Breaking Change** Migrated to .NET 10 +* **Breaking Change** Made Relay `Edge` a read-only struct +* Improved Relay XML documentation comments diff --git a/build/Program.fs b/build/Program.fs index e1cd7d83..22bbb133 100644 --- a/build/Program.fs +++ b/build/Program.fs @@ -32,7 +32,7 @@ let ctx = Context.forceFakeContext () let embedAll = ctx.Arguments |> List.exists (fun arg -> arg = BuildArguments.EmbedAll) module DotNetCli = - let setVersion (o : DotNet.Options) = { o with Version = Some "9.0.307" } + let setVersion (o : DotNet.Options) = { o with Version = Some "10.0.202" } let setRestoreOptions (o : DotNet.RestoreOptions) = o.WithCommon setVersion let configurationString = Environment.environVarOrDefault "CONFIGURATION" "Release" @@ -50,7 +50,7 @@ let configuration = // - for documentation, you also need to edit info in "docs/tools/generate.fsx" [] -let DotNetMoniker = "net8.0" +let DotNetMoniker = "net10.0" let project = "FSharp.Data.GraphQL" let release = ReleaseNotes.load "RELEASE_NOTES.md" @@ -77,6 +77,7 @@ Target.create BuildTarget <| fun _ -> "FSharp.Data.GraphQL.slnx" |> DotNet.build (fun options -> { options with + Common = options.Common.WithRedirectOutput true |> DotNetCli.setVersion Configuration = configuration MSBuildParams = { options.MSBuildParams with @@ -90,8 +91,10 @@ Target.create BuildTarget <| fun _ -> }) let startGraphQLServer (project : string) port (streamRef : DataRef) = - CreateProcess.fromRawCommandLine "dotnet" $"run --project {project} --no-build --configuration {configurationString} --urls=http://localhost:%i{port}/" + CreateProcess.fromRawCommandLine "dotnet" $"run --project {project} --no-build --no-launch-profile --configuration {configurationString} --urls=http://localhost:%i{port}/" |> CreateProcess.withStandardInput (CreatePipe streamRef) + |> CreateProcess.redirectOutput + |> CreateProcess.withOutputEventsNotNull Trace.trace Trace.traceError |> Proc.start |> ignore @@ -116,8 +119,8 @@ let runTests (project : string) (args : string) = ] } } - .WithCommon - DotNetCli.setVersion) + |> _.WithRedirectOutput(true) + |> _.WithCommon(DotNetCli.setVersion)) project let starWarsServerStream = StreamRef.Empty @@ -156,7 +159,7 @@ Target.create BuildIntegrationTestServerTarget <| fun _ -> options.MSBuildParams with DisableInternalBinLog = true } - Common = { options.Common with CustomParams = Some "--no-dependencies" } + Common = { DotNetCli.setVersion options.Common with CustomParams = Some "--no-dependencies" } }) @@ -197,13 +200,36 @@ Target.create UpdateIntrospectionFileTarget <| fun _ -> .Wait () client.Dispose () +let unitTestsProjectPath = + "tests" + "FSharp.Data.GraphQL.Tests" + "FSharp.Data.GraphQL.Tests.fsproj" + +let integrationTestsProjectPath = + "tests" + "FSharp.Data.GraphQL.IntegrationTests" + "FSharp.Data.GraphQL.IntegrationTests.fsproj" + +let [] BuildIntegrationTestsTarget = "BuildIntegrationTests" +Target.create BuildIntegrationTestsTarget <| fun _ -> + integrationTestsProjectPath + |> DotNet.build (fun options -> { + options with + Configuration = configuration + MSBuildParams = { + options.MSBuildParams with + DisableInternalBinLog = true + } + Common = DotNetCli.setVersion options.Common + }) + let [] RunUnitTestsTarget = "RunUnitTests" Target.create RunUnitTestsTarget <| fun _ -> - runTests "tests/FSharp.Data.GraphQL.Tests/FSharp.Data.GraphQL.Tests.fsproj" "" + runTests unitTestsProjectPath "" let [] RunIntegrationTestsTarget = "RunIntegrationTests" Target.create RunIntegrationTestsTarget <| fun _ -> - runTests "tests/FSharp.Data.GraphQL.IntegrationTests/FSharp.Data.GraphQL.IntegrationTests.fsproj" "" //"--filter Execution=Sync" + runTests integrationTestsProjectPath "" //"--filter Execution=Sync" let prepareDocGen () = Shell.rm "docs/release-notes.md" @@ -219,12 +245,18 @@ let prepareDocGen () = let [] GenerateDocsTarget = "GenerateDocs" Target.create GenerateDocsTarget <| fun _ -> prepareDocGen () - DotNet.exec DotNetCli.setVersion "fsdocs" "build --clean" |> ignore + let result = DotNet.exec DotNetCli.setVersion "fsdocs" "build --clean" + if not result.OK then + result.Errors |> Seq.iter (Trace.traceError) + failwithf "fsdocs build failed with exit code %d" result.ExitCode let [] GenerateDocsWatchTarget = "GenerateDocsWatch" Target.create GenerateDocsWatchTarget <| fun _ -> prepareDocGen () - DotNet.exec DotNetCli.setVersion "fsdocs" "watch --clean" |> ignore + let result = DotNet.exec DotNetCli.setVersion "fsdocs" "watch --clean" + if not result.OK then + result.Errors |> Seq.iter (Trace.traceError) + failwithf "fsdocs watch failed with exit code %d" result.ExitCode System.Console.ReadKey () |> ignore let [] ReleaseDocsTarget = "ReleaseDocs" @@ -378,6 +410,7 @@ Target.create "PackAndPush" ignore ==> BuildIntegrationTestServerTarget ==> StartIntegrationServerTarget ==> UpdateIntrospectionFileTarget +==> BuildIntegrationTestsTarget ==> RunIntegrationTestsTarget ==> "All" =?> (GenerateDocsTarget, Environment.environVar "GITHUB_ACTIONS" = "True") diff --git a/samples/relay-book-store/relay-book-store.fsproj b/samples/relay-book-store/relay-book-store.fsproj index 8ab45f6d..492a31de 100644 --- a/samples/relay-book-store/relay-book-store.fsproj +++ b/samples/relay-book-store/relay-book-store.fsproj @@ -15,8 +15,6 @@ - - diff --git a/samples/star-wars-api/Program.fs b/samples/star-wars-api/Program.fs index e5132664..d2e8600b 100644 --- a/samples/star-wars-api/Program.fs +++ b/samples/star-wars-api/Program.fs @@ -1,8 +1,9 @@ module FSharp.Data.GraphQL.Samples.StarWarsApi.Program -open Microsoft.AspNetCore +open Microsoft.AspNetCore.Builder open Microsoft.AspNetCore.Hosting open Microsoft.Extensions.Configuration +open Microsoft.Extensions.Hosting let exitCode = 0 @@ -29,11 +30,14 @@ let buildWebHost (args : string array) = .AddJsonFile("appsettings.json", false, true) .AddJsonFile($"appsettings.{envName}.json", true) |> ignore - WebHost + Host .CreateDefaultBuilder(args) - .UseConfiguration(config) - .ConfigureAppConfiguration(configureAppConfiguration) - .UseStartup() + .ConfigureWebHostDefaults(fun webBuilder -> + webBuilder + .UseConfiguration(config) + .ConfigureAppConfiguration(configureAppConfiguration) + .UseStartup() + |> ignore) [] let main args = diff --git a/samples/star-wars-api/star-wars-api.fsproj b/samples/star-wars-api/star-wars-api.fsproj index 0e566d7a..1937930c 100644 --- a/samples/star-wars-api/star-wars-api.fsproj +++ b/samples/star-wars-api/star-wars-api.fsproj @@ -7,7 +7,6 @@ - diff --git a/src/FSharp.Data.GraphQL.Client.DesignTime/ProvidedTypesHelper.fs b/src/FSharp.Data.GraphQL.Client.DesignTime/ProvidedTypesHelper.fs index 621c5b2c..504207bb 100644 --- a/src/FSharp.Data.GraphQL.Client.DesignTime/ProvidedTypesHelper.fs +++ b/src/FSharp.Data.GraphQL.Client.DesignTime/ProvidedTypesHelper.fs @@ -322,16 +322,7 @@ module internal ProvidedOperation = let buildVariablesExprFromArgs (varNames : string list) (args : Expr list) = let mapVariableExpr (name : string) (value : Expr) = let value = Expr.Coerce(value, typeof) - <@@ let rec mapVariableValue (value : obj) = - match value with - | null -> null - | :? string -> value // We need this because strings are enumerables, and we don't want to enumerate them recursively as an object - | :? EnumBase as v -> v.GetValue() |> box - | :? RecordBase as v -> v.ToDictionary() |> box - | OptionValue v -> v |> Option.map mapVariableValue |> box - | EnumerableValue v -> v |> Array.map mapVariableValue |> box - | v -> v - (name, mapVariableValue %%value) @@> + <@@ (name, VariableMapping.mapVariableValue %%value) @@> let args = let varArgs = List.skip (args.Length - variables.Length) args (varNames, varArgs) ||> List.map2 mapVariableExpr diff --git a/src/FSharp.Data.GraphQL.Client/BaseTypes.fs b/src/FSharp.Data.GraphQL.Client/BaseTypes.fs index e981d83c..5bc66444 100644 --- a/src/FSharp.Data.GraphQL.Client/BaseTypes.fs +++ b/src/FSharp.Data.GraphQL.Client/BaseTypes.fs @@ -459,3 +459,17 @@ type OperationResultBase (rawResponse: HttpResponseMessage, responseJson : JsonV type OperationBase (query : string) = /// Gets the query string of the operation. member _.Query = query + +module VariableMapping = + + open FSharp.Data.GraphQL.Client.ReflectionPatterns + + let rec mapVariableValue (value : obj) = + match value with + | null -> null + | :? string -> value + | :? EnumBase as v -> v.GetValue() |> box + | :? RecordBase as v -> v.ToDictionary() |> box + | OptionValue v -> v |> Option.map mapVariableValue |> box + | EnumerableValue v -> v |> Array.map mapVariableValue |> box + | v -> v diff --git a/src/FSharp.Data.GraphQL.Server.Relay/Connections.fs b/src/FSharp.Data.GraphQL.Server.Relay/Connections.fs index 5938b63c..369d6d3c 100644 --- a/src/FSharp.Data.GraphQL.Server.Relay/Connections.fs +++ b/src/FSharp.Data.GraphQL.Server.Relay/Connections.fs @@ -3,6 +3,7 @@ namespace FSharp.Data.GraphQL.Server.Relay +open System.Runtime.CompilerServices open FSharp.Data.GraphQL.Types open FSharp.Data.GraphQL.Types.Patterns @@ -11,6 +12,7 @@ open FSharp.Data.GraphQL.Types.Patterns /// Edges are used to traverse connections in Relay pagination. /// /// The type of the node at the end of this edge. +[] type Edge<'Node> = { /// Opaque cursor string used to identify this node's position in the connection. Cursor : string diff --git a/tests/FSharp.Data.GraphQL.IntegrationTests.Server/FSharp.Data.GraphQL.IntegrationTests.Server.fsproj b/tests/FSharp.Data.GraphQL.IntegrationTests.Server/FSharp.Data.GraphQL.IntegrationTests.Server.fsproj index 359157c7..6a4a691b 100644 --- a/tests/FSharp.Data.GraphQL.IntegrationTests.Server/FSharp.Data.GraphQL.IntegrationTests.Server.fsproj +++ b/tests/FSharp.Data.GraphQL.IntegrationTests.Server/FSharp.Data.GraphQL.IntegrationTests.Server.fsproj @@ -10,7 +10,6 @@ - diff --git a/tests/FSharp.Data.GraphQL.IntegrationTests.Server/Program.fs b/tests/FSharp.Data.GraphQL.IntegrationTests.Server/Program.fs index 857bbf95..46fec9b6 100644 --- a/tests/FSharp.Data.GraphQL.IntegrationTests.Server/Program.fs +++ b/tests/FSharp.Data.GraphQL.IntegrationTests.Server/Program.fs @@ -1,17 +1,18 @@ namespace FSharp.Data.GraphQL.IntegrationTests.Server -open Microsoft.AspNetCore +open Microsoft.Extensions.Hosting open Microsoft.AspNetCore.Hosting module Program = let exitCode = 0 - let buildWebHost args = - WebHost + let buildHost args = + Host .CreateDefaultBuilder(args) - .UseStartup() + .ConfigureWebHostDefaults(fun webBuilder -> + webBuilder.UseStartup() |> ignore) [] let main args = - buildWebHost(args).Build().Run() + buildHost(args).Build().Run() exitCode diff --git a/tests/FSharp.Data.GraphQL.IntegrationTests/FSharp.Data.GraphQL.IntegrationTests.fsproj b/tests/FSharp.Data.GraphQL.IntegrationTests/FSharp.Data.GraphQL.IntegrationTests.fsproj index 5ef03404..44bc1d17 100644 --- a/tests/FSharp.Data.GraphQL.IntegrationTests/FSharp.Data.GraphQL.IntegrationTests.fsproj +++ b/tests/FSharp.Data.GraphQL.IntegrationTests/FSharp.Data.GraphQL.IntegrationTests.fsproj @@ -9,8 +9,6 @@ - -