-
Notifications
You must be signed in to change notification settings - Fork 284
Expand file tree
/
Copy pathJsonConversionsGenerator.fs
More file actions
125 lines (111 loc) · 5.15 KB
/
JsonConversionsGenerator.fs
File metadata and controls
125 lines (111 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// ----------------------------------------------------------------------------------------------
// Conversions from string to various primitive types
// ----------------------------------------------------------------------------------------------
module ProviderImplementation.JsonConversionsGenerator
open System
open FSharp.Quotations
open FSharp.Data
open FSharp.Data.Runtime
open FSharp.Data.Runtime.BaseTypes
open FSharp.Data.Runtime.StructuralTypes
open ProviderImplementation
open ProviderImplementation.QuotationBuilder
#nowarn "10001"
let getConversionQuotation missingValuesStr cultureStr typ (value: Expr<JsonValue option>) =
if typ = typeof<string> then
<@@ JsonRuntime.ConvertString(cultureStr, %value) @@>
elif typ = typeof<int> || typ = typeof<Bit0> || typ = typeof<Bit1> then
<@@ JsonRuntime.ConvertInteger(cultureStr, %value) @@>
elif typ = typeof<int64> then
<@@ JsonRuntime.ConvertInteger64(cultureStr, %value) @@>
elif typ = typeof<decimal> then
<@@ JsonRuntime.ConvertDecimal(cultureStr, %value) @@>
elif typ = typeof<float> then
<@@ JsonRuntime.ConvertFloat(cultureStr, missingValuesStr, %value) @@>
elif typ = typeof<bool> || typ = typeof<Bit> then
<@@ JsonRuntime.ConvertBoolean(%value) @@>
elif typ = typeof<DateTimeOffset> then
<@@ JsonRuntime.ConvertDateTimeOffset(cultureStr, %value) @@>
elif typ = typeof<DateTime> then
<@@ JsonRuntime.ConvertDateTime(cultureStr, %value) @@>
elif typ = typeof<TimeSpan> then
<@@ JsonRuntime.ConvertTimeSpan(cultureStr, %value) @@>
#if NET6_0_OR_GREATER
elif typ = typeof<DateOnly> then
<@@ JsonRuntime.ConvertDateOnly(cultureStr, %value) @@>
elif typ = typeof<TimeOnly> then
<@@ JsonRuntime.ConvertTimeOnly(cultureStr, %value) @@>
#endif
elif typ = typeof<Guid> then
<@@ JsonRuntime.ConvertGuid(%value) @@>
else
failwith "getConversionQuotation: Unsupported primitive type"
type internal JsonConversionCallingType =
| JsonDocument
| JsonValueOption
| JsonValueOptionAndPath
/// Creates a function that takes Expr<JsonValue option> and converts it to
/// an expression of other type - the type is specified by `field`
let internal convertJsonValue
missingValuesStr
cultureStr
canPassAllConversionCallingTypes
exceptionIfMissing
(field: PrimitiveInferedValue)
=
let returnType =
match field.TypeWrapper with
| TypeWrapper.None -> field.TypeWithMeasure
| TypeWrapper.Option -> typedefof<option<_>>.MakeGenericType field.TypeWithMeasure
| TypeWrapper.Nullable -> typedefof<Nullable<_>>.MakeGenericType field.TypeWithMeasure
let wrapInLetIfNeeded (value: Expr) getBody =
match value with
| Patterns.Var var ->
let varExpr = Expr.Cast<'T>(Expr.Var var)
getBody varExpr
| _ ->
let var = Var("value", typeof<'T>)
let varExpr = Expr.Cast<'T>(Expr.Var var)
Expr.Let(var, value, getBody varExpr)
let convert (value: Expr) =
let convert value =
getConversionQuotation missingValuesStr cultureStr field.InferedType value
let getNonOptionalValueMethod =
if exceptionIfMissing then
nameof (JsonRuntime.GetNonOptionalValueStrict)
else
nameof (JsonRuntime.GetNonOptionalValue)
match field.TypeWrapper, canPassAllConversionCallingTypes with
| TypeWrapper.None, true ->
wrapInLetIfNeeded value (fun (varExpr: Expr<JsonValueOptionAndPath>) ->
typeof<JsonRuntime>?(getNonOptionalValueMethod)
(field.RuntimeType)
(<@ (%varExpr).Path @>, convert <@ (%varExpr).JsonOpt @>, <@ (%varExpr).JsonOpt @>))
| TypeWrapper.None, false ->
wrapInLetIfNeeded value (fun (varExpr: Expr<IJsonDocument>) ->
typeof<JsonRuntime>?(getNonOptionalValueMethod)
(field.RuntimeType)
(<@ (%varExpr).Path() @>, convert <@ Some (%varExpr).JsonValue @>, <@ Some (%varExpr).JsonValue @>))
| TypeWrapper.Option, true -> convert <@ (%%value: JsonValue option) @>
| TypeWrapper.Option, false ->
//TODO: not covered in tests
convert <@ Some (%%value: IJsonDocument).JsonValue @>
| TypeWrapper.Nullable, true ->
//TODO: not covered in tests
typeof<TextRuntime>?(nameof (TextRuntime.OptionToNullable))
(field.RuntimeType)
(convert <@ (%%value: JsonValue option) @>)
| TypeWrapper.Nullable, false ->
//TODO: not covered in tests
typeof<TextRuntime>?(nameof (TextRuntime.OptionToNullable))
(field.RuntimeType)
(convert <@ Some (%%value: IJsonDocument).JsonValue @>)
let conversionCallingType =
if canPassAllConversionCallingTypes then
match field.TypeWrapper with
| TypeWrapper.None -> JsonValueOptionAndPath
| TypeWrapper.Option
| TypeWrapper.Nullable -> JsonValueOption
else
JsonDocument
returnType, convert, conversionCallingType