Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
3 changes: 2 additions & 1 deletion src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ type public OpenApiClientTypeProvider(cfg: TypeProviderConfig) as this =
|> Seq.map(fun e -> $"%s{e.Message} @ %s{e.Pointer}")
|> String.concat "\n")

let defCompiler = DefinitionCompiler(schema, preferNullable)
let useDateOnly = cfg.SystemRuntimeAssemblyVersion.Major >= 6
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Thorium hi, may i ask your opinion about such implementation? Do you see any reason why it should not work?

let defCompiler = DefinitionCompiler(schema, preferNullable, useDateOnly)

let opCompiler =
OperationCompiler(schema, defCompiler, ignoreControllerPrefix, ignoreOperationId, preferAsync)
Expand Down
3 changes: 2 additions & 1 deletion src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ type public SwaggerTypeProvider(cfg: TypeProviderConfig) as this =

let schema = SwaggerParser.parseSchema schemaData

let defCompiler = DefinitionCompiler(schema, preferNullable)
let useDateOnly = cfg.SystemRuntimeAssemblyVersion.Major >= 6
let defCompiler = DefinitionCompiler(schema, preferNullable, useDateOnly)

let opCompiler =
OperationCompiler(schema, defCompiler, ignoreControllerPrefix, ignoreOperationId, preferAsync)
Expand Down
13 changes: 11 additions & 2 deletions src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ and NamespaceAbstraction(name: string) =
Some ty)

/// Object for compiling definitions.
type DefinitionCompiler(schema: SwaggerObject, provideNullable) as this =
type DefinitionCompiler(schema: SwaggerObject, provideNullable, useDateOnly: bool) as this =
let definitionToSchemaObject = Map.ofSeq schema.Definitions
let definitionToType = Collections.Generic.Dictionary<_, _>()
let nsRoot = NamespaceAbstraction("Root")
Expand Down Expand Up @@ -352,7 +352,16 @@ type DefinitionCompiler(schema: SwaggerObject, provideNullable) as this =
| Float -> typeof<float32>
| Double -> typeof<double>
| String -> typeof<string>
| Date
| Date ->
// Use DateOnly only when the target runtime supports it (.NET 6+).
// We check useDateOnly (derived from cfg.SystemRuntimeAssemblyVersion) rather than
// probing the design-time host process, which may differ from the consumer's runtime.
if useDateOnly then
System.Type.GetType("System.DateOnly")
|> Option.ofObj
|> Option.defaultValue typeof<DateTime>
else
typeof<DateTime>
| DateTime -> typeof<DateTime>
| File -> typeof<byte>.MakeArrayType 1
| Enum(_, "string") -> typeof<string>
Expand Down
13 changes: 11 additions & 2 deletions src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ and NamespaceAbstraction(name: string) =
Some ty)

/// Object for compiling definitions.
type DefinitionCompiler(schema: OpenApiDocument, provideNullable) as this =
type DefinitionCompiler(schema: OpenApiDocument, provideNullable, useDateOnly: bool) as this =
let pathToSchema =
if isNull schema.Components then
Map.empty
Expand Down Expand Up @@ -496,7 +496,16 @@ type DefinitionCompiler(schema: OpenApiDocument, provideNullable) as this =
// for `application/octet-stream` request body
// for `multipart/form-data` : https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#considerations-for-file-uploads
typeof<IO.Stream>
| HasFlag JsonSchemaType.String, "date"
| HasFlag JsonSchemaType.String, "date" ->
// Use DateOnly only when the target runtime supports it (.NET 6+).
// We check useDateOnly (derived from cfg.SystemRuntimeAssemblyVersion) rather than
// probing the design-time host process, which may differ from the consumer's runtime.
if useDateOnly then
System.Type.GetType("System.DateOnly")
|> Option.ofObj
|> Option.defaultValue typeof<DateTimeOffset>
else
typeof<DateTimeOffset>
| HasFlag JsonSchemaType.String, "date-time" -> typeof<DateTimeOffset>
| HasFlag JsonSchemaType.String, "uuid" -> typeof<Guid>
| HasFlag JsonSchemaType.String, _ -> typeof<string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ let ``PersonDto should have nullable birthDate property``() =
let birthDateProp = personType.GetProperty("BirthDate")
birthDateProp |> shouldNotEqual null

// The property should be Option<DateTimeOffset> (default) or Nullable<DateTimeOffset> (with PreferNullable=true)
// The property should be Option<DateOnly> (on .NET 6+) or Option<DateTimeOffset> (netstandard2.0)
let propType = birthDateProp.PropertyType
propType.IsGenericType |> shouldEqual true

Expand All @@ -29,6 +29,16 @@ let ``PersonDto should have nullable birthDate property``() =

hasNullableWrapper |> shouldEqual true

[<Fact>]
let ``PersonDto birthDate property should be Option<DateOnly> on NET6+``() =
let personType = typeof<TestApi.PersonDto>
let birthDateProp = personType.GetProperty("BirthDate")
birthDateProp |> shouldNotEqual null

// On NET6+, format: date should map to DateOnly wrapped in Option<T>
let propType = birthDateProp.PropertyType
propType |> shouldEqual typeof<Option<System.DateOnly>>

[<Fact>]
let ``PersonDto can deserialize JSON with null birthDate using type provider deserialization``() =
// This JSON is from the issue - a person with null birthDate
Expand Down
4 changes: 2 additions & 2 deletions tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module V2 =
let testSchema schemaStr =
let schema = SwaggerParser.parseSchema schemaStr

let defCompiler = DefinitionCompiler(schema, false)
let defCompiler = DefinitionCompiler(schema, false, Environment.Version.Major >= 6)
let opCompiler = OperationCompiler(schema, defCompiler, true, false, true)
opCompiler.CompileProvidedClients(defCompiler.Namespace)
ignore <| defCompiler.Namespace.GetProvidedTypes()
Expand All @@ -35,7 +35,7 @@ module V3 =
|> Seq.map (fun e -> e.Message)
|> String.concat ";\n- ")*)
try
let defCompiler = DefinitionCompiler(schema, false)
let defCompiler = DefinitionCompiler(schema, false, Environment.Version.Major >= 6)
let opCompiler = OperationCompiler(schema, defCompiler, true, false, true)
opCompiler.CompileProvidedClients(defCompiler.Namespace)
defCompiler.Namespace.GetProvidedTypes()
Expand Down
Loading