Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<PropertyGroup Label="NuGet">
<Version>3.1.0</Version>
<Version>3.1.1</Version>
</PropertyGroup>

</Project>
5 changes: 3 additions & 2 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@
* Changed `GraphQLOptionsDefaults.WebSocketConnectionInitTimeoutInMs` const type to `double`
* Improved Relay XML documentation comments

### 3.1.1 - Unreleased
### 3.1.1 - 2026-04-03
Comment thread
xperiandri marked this conversation as resolved.
Outdated

* Fixed planning phase crash when inline fragments reference types not included in union or interface definitions
* 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.
12 changes: 4 additions & 8 deletions src/FSharp.Data.GraphQL.Client.DesignTime/ProvidedTypesHelper.fs
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,6 @@ module internal ProvidedOperation =
tdef.AddXmlDoc("Represents a GraphQL operation on the server.")
tdef.AddMembersDelayed(fun _ ->
let operationResultDef = ProvidedOperationResult.makeProvidedType(operationType)
let isScalar (typeName: string) =
match schemaTypes.TryFind typeName with
| Some introspectionType -> introspectionType.Kind = TypeKind.SCALAR
| None -> false
let variables =
let rec mapVariable (variableName : string) (variableType : InputType) =
match variableType with
Expand All @@ -309,11 +305,11 @@ module internal ProvidedOperation =
| Some uploadInputTypeName when typeName = uploadInputTypeName ->
struct (variableName, typeName, TypeMapping.makeOption typeof<Upload>)
| _ ->
match TypeMapping.scalar.TryFind(typeName) with
match TypeMapping.tryFindScalarType schemaTypes typeName with
| Some t -> struct (variableName,typeName, TypeMapping.makeOption t)
| None when isScalar typeName -> struct (variableName, typeName, typeof<string option>)
| None when TypeMapping.isScalarTypeName schemaTypes typeName -> struct (variableName, typeName, typeof<string option>)
| None ->
match schemaProvidedTypes.TryFind(typeName) with
match schemaProvidedTypes.TryFind typeName with
| Some t -> struct (variableName, typeName, TypeMapping.makeOption t)
| None -> failwith $"""Unable to find variable type "%s{typeName}" in the schema definition."""
| ListType itype ->
Expand Down Expand Up @@ -381,7 +377,7 @@ module internal ProvidedOperation =
tdef.DeclaredProperties |> Seq.exists ((fun p -> p.PropertyType) >> existsUploadType)
variables |> Seq.exists (fun struct (_, _, t) -> existsUploadType t)
|| variables
|> Seq.where (fun struct (_, typeName, _) -> TypeMapping.scalar.TryGetValue typeName |> fst |> not)
|> Seq.where (fun struct (_, typeName, _) -> not (TypeMapping.isScalarTypeName schemaTypes typeName))
|> Seq.choose (fun struct (_, typeName, _) -> schemaProvidedTypes |> Map.tryFind typeName)
|> Seq.exists existsUploadTypeDefinition
let runMethodOverloads : MemberInfo list =
Expand Down
17 changes: 14 additions & 3 deletions src/FSharp.Data.GraphQL.Client/BaseTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,19 @@ module internal TypeMapping =
"URI", typeof<Uri> |]
|> Map.ofArray

let isBuiltInScalarTypeName (name : string) =
scalar |> Map.containsKey name

let isScalarTypeName (schemaTypes : Map<TypeName, IntrospectionType>) (name : string) =
match schemaTypes.TryFind name with
| Some schemaType -> schemaType.Kind = TypeKind.SCALAR
| None -> isBuiltInScalarTypeName name

let tryFindScalarType (schemaTypes : Map<TypeName, IntrospectionType>) (name : string) =
if isScalarTypeName schemaTypes name
then scalar |> Map.tryFind name
else None

let getSchemaTypes (introspection : IntrospectionSchema) =
let schemaTypeNames =
[| "__TypeKind"
Expand All @@ -179,13 +192,11 @@ module internal TypeMapping =
"__EnumValue"
"__Directive"
"__Schema" |]
let isScalarType (name : string) =
scalar |> Map.containsKey name
let isIntrospectionType (name : string) =
schemaTypeNames |> Array.contains name
introspection.Types
|> Array.choose (fun t ->
if not (isIntrospectionType t.Name) && not (isScalarType t.Name)
if not (isIntrospectionType t.Name) && not (t.Kind = TypeKind.SCALAR && isBuiltInScalarTypeName t.Name)
then Some(t.Name, t)
else None)
|> Map.ofArray
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@

<ItemGroup>
<Content Include="introspection.json" />
<Content Include="reserved_scalar_input_date_introspection.json" />
<Content Include="reserved_scalar_object_date_introspection.json" />
<None Include="operation.graphql">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
<Compile Include="Helpers.fs" />
<Compile Include="ReservedScalarNameProviderTests.fs" />
<Compile Include="LocalProviderTests.fs" />
<Compile Include="LocalProviderWithOptionalParametersOnlyTests.fs" />
<Compile Include="SwapiLocalProviderTests.fs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module FSharp.Data.GraphQL.IntegrationTests.ReservedScalarNameProviderTests

open Xunit
open FSharp.Data.GraphQL

type ObjectDateProvider = GraphQLProvider<"reserved_scalar_object_date_introspection.json">
type InputDateProvider = GraphQLProvider<"reserved_scalar_input_date_introspection.json">

module ObjectDateSchema =
type SchemaDate = ObjectDateProvider.Types.Date

let operation =
ObjectDateProvider.Operation<"""query Q {
dateInfo {
value
category
}
}""">()

let compileSmoke () =
let schemaDate = SchemaDate(value = "2026-04-03", category = "default")
let operationInstance : ObjectDateProvider.Operations.Q = operation
schemaDate |> ignore
operationInstance |> ignore

module InputDateSchema =
type SchemaDate = InputDateProvider.Types.Date

let operation =
InputDateProvider.Operation<"""query Q($input: Date) {
echoDate(input: $input)
}""">()

let compileSmoke () =
let schemaDate = SchemaDate(value = "2026-04-03", category = "default")
let deferredRun : unit -> _ =
fun () -> operation.Run(Unchecked.defaultof<GraphQLProviderRuntimeContext>, schemaDate)
schemaDate |> ignore
deferredRun |> ignore

[<Fact>]
let ``Should allow object types that reuse reserved scalar names`` () =
ObjectDateSchema.compileSmoke ()

[<Fact>]
let ``Should allow input object types that reuse reserved scalar names`` () =
InputDateSchema.compileSmoke ()
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": null,
"subscriptionType": null,
"types": [
{
"kind": "SCALAR",
"name": "String",
"description": null,
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Query",
"description": null,
"fields": [
{
"name": "echoDate",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "INPUT_OBJECT",
"name": "Date",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "Date",
"description": null,
"fields": null,
"inputFields": [
{
"name": "value",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "category",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
}
],
"directives": []
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": null,
"subscriptionType": null,
"types": [
{
"kind": "SCALAR",
"name": "String",
"description": null,
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Query",
"description": null,
"fields": [
{
"name": "dateInfo",
"description": null,
"args": [],
"type": {
"kind": "OBJECT",
"name": "Date",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Date",
"description": null,
"fields": [
{
"name": "value",
"description": null,
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "category",
"description": null,
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
}
],
"directives": []
}
}
}