Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonProvider.Load(value: JsonValue) #1424

Merged
merged 2 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 20 additions & 5 deletions src/CommonProviderImplementation/Helpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ module internal ProviderHelpers =
let private webUrisCache = createInternetFileCache "DesignTimeURIs" cacheDuration

// part of the information needed by generateType
type TypeProviderSpec =
type TypeProviderSpec<'RuntimeValue> =
{ //the generated type
GeneratedType : ProvidedTypeDefinition
//the representation type (what's returned from the constructors, may or may not be the same as Type)
Expand All @@ -162,10 +162,13 @@ module internal ProviderHelpers =
CreateFromTextReader : Expr<TextReader> -> Expr
CreateListFromTextReader : (Expr<TextReader> -> Expr) option
// the constructor from a text reader to an array of the representation
CreateFromTextReaderForSampleList : Expr<TextReader> -> Expr }
CreateFromTextReaderForSampleList : Expr<TextReader> -> Expr
/// Runtime representation of underlying data (e.g. JsonValue) * Mapper function
CreateFromValue: (Type * (Expr<'RuntimeValue> -> Expr)) option
}

type private ParseTextResult =
{ Spec : TypeProviderSpec
type private ParseTextResult<'RuntimeValue> =
{ Spec : TypeProviderSpec<'RuntimeValue>
IsUri : bool
IsResource : bool }

Expand Down Expand Up @@ -455,7 +458,19 @@ module internal ProviderHelpers =
asyncMap resultType readerAsync spec.CreateFromTextReader)
m.AddXmlDoc <| sprintf "Loads %s from the specified uri" formatName
yield m :> _


// Generate static Load value method
match spec.CreateFromValue with
| None -> ()
| Some (valueType, valueMapper) ->
let args = [ ProvidedParameter("value", valueType) ]
let m = ProvidedMethod("Load", args, resultType, isStatic = true,
invokeCode = fun (Singleton value) ->
let value = value |> Expr.Cast
<@ %value @> |> valueMapper)
m.AddXmlDoc <| sprintf "Loads %s from the specified value" formatName
yield m :> _

if not parseResult.IsResource then

match source with
Expand Down
6 changes: 4 additions & 2 deletions src/Csv/CsvProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,10 @@ type public CsvProvider(cfg:TypeProviderConfig) as this =
separators, quote, hasHeaders, ignoreErrors, skipRows, cacheRows)
Expr.Let(stringArrayToRowVar, stringArrayToRow, Expr.Let(rowToStringArrayVar, rowToStringArray, body))
CreateListFromTextReader = None
CreateFromTextReaderForSampleList = fun _ -> failwith "Not Applicable" }

CreateFromTextReaderForSampleList = fun _ -> failwith "Not Applicable"
CreateFromValue = None
}

let maxNumberOfRows = if inferRows > 0 then Some inferRows else None

// On the CsvProvider the schema might be partial and we will still infer from the sample
Expand Down
4 changes: 3 additions & 1 deletion src/Html/HtmlProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ type public HtmlProvider(cfg:TypeProviderConfig) as this =
RepresentationType = htmlType
CreateFromTextReader = fun reader -> <@@ HtmlDocument.Create(includeLayoutTables, %reader) @@>
CreateListFromTextReader = None
CreateFromTextReaderForSampleList = fun _ -> failwith "Not Applicable" }
CreateFromTextReaderForSampleList = fun _ -> failwith "Not Applicable"
CreateFromValue = None
}

generateType "HTML" (Sample sample) getSpec this cfg encodingStr resolutionFolder resource typeName (*maxNumberOfRows*)None

Expand Down
16 changes: 9 additions & 7 deletions src/Json/JsonProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,15 @@ type public JsonProvider(cfg:TypeProviderConfig) as this =
result.Convert <@@ JsonDocument.Create(%reader) @@>
CreateListFromTextReader = Some (fun reader ->
result.Convert <@@ JsonDocument.CreateList(%reader) @@>)
CreateFromTextReaderForSampleList = fun reader ->
result.Convert <@@ JsonDocument.CreateList(%reader) @@> }

let source =
if sampleIsList then
SampleList sample
else
CreateFromTextReaderForSampleList = fun reader ->
result.Convert <@@ JsonDocument.CreateList(%reader) @@>
CreateFromValue = Some (typeof<JsonValue>, fun value -> result.Convert <@@ JsonDocument.Create(%value, "") @@>)
}

let source =
if sampleIsList then
SampleList sample
else
Sample sample

generateType "JSON" source getSpec this cfg encodingStr resolutionFolder resource typeName (*maxNumberOfRows*)None
Expand Down
14 changes: 9 additions & 5 deletions src/Xml/XmlProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ type public XmlProvider(cfg:TypeProviderConfig) as this =
result.Converter <@@ XmlElement.Create(%reader) @@>
CreateListFromTextReader = None
CreateFromTextReaderForSampleList = fun reader -> // hack: this will actually parse the schema
<@@ XmlSchema.parseSchemaFromTextReader resolutionFolder %reader @@> }
<@@ XmlSchema.parseSchemaFromTextReader resolutionFolder %reader @@>
CreateFromValue = None
}


else
Expand Down Expand Up @@ -100,10 +102,12 @@ type public XmlProvider(cfg:TypeProviderConfig) as this =
CreateFromTextReader = fun reader ->
result.Converter <@@ XmlElement.Create(%reader) @@>
CreateListFromTextReader = None
CreateFromTextReaderForSampleList = fun reader ->
result.Converter <@@ XmlElement.CreateList(%reader) @@> }

let source =
CreateFromTextReaderForSampleList = fun reader ->
result.Converter <@@ XmlElement.CreateList(%reader) @@>
CreateFromValue = None
}

let source =
if schema <> "" then
Schema schema
elif sampleIsList then
Expand Down
8 changes: 7 additions & 1 deletion tests/FSharp.Data.DesignTime.Tests/SignatureTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ let expectedDirectory = sourceDirectory ++ "expected"

let resolutionFolder = sourceDirectory ++ ".." ++ "FSharp.Data.Tests" ++ "Data"
let assemblyName = "FSharp.Data.dll"
let netstandard2RuntimeAssembly = sourceDirectory ++ ".." ++ ".." ++ "src" ++ "FSharp.Data" ++ "bin" ++ "Release" ++ "netstandard2.0" ++ assemblyName
let netstandard2RuntimeAssembly = sourceDirectory ++ ".." ++ ".." ++ "src" ++ "FSharp.Data" ++ "bin" ++
#if DEBUG
"Debug"
#else
"Release"
#endif
Comment on lines +32 to +36
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why this change?

Copy link
Contributor Author

@gbtb gbtb Jan 12, 2022

Choose a reason for hiding this comment

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

Maybe it's just my workflow, but I rarely build projects in a Release configuration while developing. So I've ran tests in debug mode and was a bit puzzled when all of them failed at once, because of missing Release-build dll . So I've thought synchronizing configurations of test assembly and required assembly would be convenient

Copy link
Collaborator

Choose a reason for hiding this comment

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

Cool!. I think this is fine. I had to make a change when building/testing for .NET 5 to run tests in release, since at the time the compiler could stack overflow. That may no longer be the case (there have been a years' worth of compiler improvements since then). This is probably a better way to do it.

++ "netstandard2.0" ++ assemblyName

let getRuntimeRefs platform = TypeProviderInstantiation.GetRuntimeAssemblyRefs platform

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri))), new Func<_,_>(id)))

static member Load: value:JsonValue -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(value, ""), new Func<_,_>(id)))

static member Parse: text:string -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(((new StringReader(text)) :> TextReader)), new Func<_,_>(id)))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri))), new Func<_,_>(id)))

static member Load: value:JsonValue -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(value, ""), new Func<_,_>(id)))

static member Parse: text:string -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(((new StringReader(text)) :> TextReader)), new Func<_,_>(id)))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri))), new Func<_,_>(id)))

static member Load: value:JsonValue -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(value, ""), new Func<_,_>(id)))

static member Parse: text:string -> JsonProvider+JsonProvider+Root[]
JsonRuntime.ConvertArray(JsonDocument.Create(((new StringReader(text)) :> TextReader)), new Func<_,_>(id)))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+WorldBank
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+WorldBank
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+WorldBank
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+Root
JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri)))

static member Load: value:JsonValue -> JsonProvider+Root
JsonDocument.Create(value, "")

static member Parse: text:string -> JsonProvider+Root
JsonDocument.Create(((new StringReader(text)) :> TextReader))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class JsonProvider : obj
static member Load: uri:string -> JsonProvider+JsonProvider+Topic[]
JsonRuntime.ConvertArray(JsonDocument.Create(FSharpAsync.RunSynchronously((IO.asyncReadTextAtRuntime false "<RESOLUTION_FOLDER>" "" "JSON" "" uri))), new Func<_,_>(id)))

static member Load: value:JsonValue -> JsonProvider+JsonProvider+Topic[]
JsonRuntime.ConvertArray(JsonDocument.Create(value, ""), new Func<_,_>(id)))

static member Parse: text:string -> JsonProvider+JsonProvider+Topic[]
JsonRuntime.ConvertArray(JsonDocument.Create(((new StringReader(text)) :> TextReader)), new Func<_,_>(id)))

Expand Down
29 changes: 29 additions & 0 deletions tests/FSharp.Data.Tests/JsonProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -728,3 +728,32 @@ let ``Getting a large decimal at runtime when an integer was inferred should thr
let ``ParseList return result list`` () =
let prov = NumericFields.ParseList(""" [{"a":123}, {"a":987}] """)
prov |> Array.map (fun v -> v.A) |> Array.sort |> should equal [|123M; 987M|]


type ServiceResponse = JsonProvider<"""[
{ "code": 0, "value": {"generic payload": "yes"}, "message": null},
{ "code": 1, "value": null, "message": "Warning"},
{ "code": 2, "value": [], "message": "Exception"}
]
""", SampleIsList = true>

type FirstPayload = JsonProvider<"""{ "x" : 0.500, "y" : 0.000 }""">
type SecondPayload = JsonProvider<"""{"user": "alice", "role": "admin", "registeredSince": "2021-11-01"}""">

[<Test>]
let ``Can re-load JsonValue`` () =
let json = FirstPayload.Parse("""{ "x" : -0.250, "y" : 12345}""")
FirstPayload.Load(json.JsonValue) |> should equal json

[<Test>]
let ``Can load different nested payloads`` () =
let json1 = ServiceResponse.Parse("""{ "code": 0, "value": { "x" : -0.250, "y" : 12345}, "message": null}""")
let json2 = ServiceResponse.Parse("""{ "code": 0, "value": {"user": "alice", "role": "admin", "registeredSince": "2021-11-01"}, "message": null}""")
let payload1 = FirstPayload.Load(json1.Value.JsonValue)

let payload2 = SecondPayload.Load(json2.Value.JsonValue)
payload1.X |> should equal -0.250
payload1.Y |> should equal 12345
payload2.User |> should equal "alice"
payload2.Role |> should equal "admin"
payload2.RegisteredSince |> should equal (DateTime(2021, 11, 1))