Skip to content

Commit

Permalink
finish up first version of ROCrateObject serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
HLWeil committed Oct 18, 2024
1 parent d35c76a commit 9f9b9c7
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 135 deletions.
124 changes: 13 additions & 111 deletions src/ARCtrl/JsonIO/ROCrateObject.fs
Original file line number Diff line number Diff line change
@@ -1,123 +1,25 @@
namespace ARCtrl.Json

open ARCtrl
open ARCtrl.ROCrate
open System
open ARCtrl.ROCrate
open Thoth.Json.Core
open DynamicObj

module rec ROCrateObject =

#if !FABLE_COMPILER
let (|SomeObj|_|) =
// create generalized option type
let ty = typedefof<option<_>>
fun (a:obj) ->
// Check for nulls otherwise 'a.GetType()' would fail
if isNull a
then
None
else
let aty = a.GetType()
// Get option'.Value
let v = aty.GetProperty("Value")
if aty.IsGenericType && aty.GetGenericTypeDefinition() = ty then
// return value if existing
Some(v.GetValue(a, [| |]))
else
None
#endif


let genericEncoder (obj : obj) : IEncodable =
match obj with
| :? string as s -> Encode.string s
| :? int as i -> Encode.int i
| :? bool as b -> Encode.bool b
| :? float as f -> Encode.float f
| :? DateTime as d -> Encode.dateTime d
| :? ROCrateObject as o -> encoder o
#if !FABLE_COMPILER
| SomeObj o -> genericEncoder o
#endif
| null -> Encode.nil
| :? System.Collections.IEnumerable as l -> [ for x in l -> genericEncoder x] |> Encode.list
| _ -> failwith "Unknown type"

let rec encoder(obj: ROCrateObject) =
obj.GetProperties true
|> Seq.map (fun kv ->
kv.Key,
genericEncoder obj
)
|> Encode.object

[<AutoOpen>]
module ROCrateObjectExtensions =

let rec decoder : Decoder<obj> =
let rec decode() =
let decodeObject : Decoder<ROCrateObject> =
{ new Decoder<ROCrateObject> with
member _.Decode(helpers, value) =
if helpers.isObject value then
let getters = Decode.Getters(helpers, value)
let properties = helpers.getProperties value
let builder =
fun (get : Decode.IGetters) ->
let o = ROCrateObject(
id = get.Required.Field "@id" Decode.string,
schemaType = get.Required.Field "@type" Decode.string
)
for property in properties do
if property <> "@id" && property <> "@type" then
o.SetProperty(property,get.Required.Field property (decode()))
o
let result = builder getters
match getters.Errors with
| [] -> Ok result
| fst :: _ as errors ->
if errors.Length > 1 then
("", BadOneOf errors) |> Error
else
Error fst
else
("", BadPrimitive("an object", value)) |> Error
}
let resizeArray : Decoder<ResizeArray<obj>> =
{ new Decoder<ResizeArray<obj>> with
member _.Decode(helpers, value) =
if helpers.isArray value then
let mutable i = -1
let tokens = helpers.asArray value
let arr = ResizeArray()
type ROCrateObject with

(Ok arr, tokens)
||> Array.fold (fun acc value ->
i <- i + 1
static member fromROCrateJsonString (s:string) =
Decode.fromJsonString ROCrateObject.decoder s

match acc with
| Error _ -> acc
| Ok acc ->
match decode().Decode(helpers, value) with
| Error er ->
Error(
er
|> Helpers.prependPath (
".[" + (i.ToString()) + "]"
)
)
| Ok value ->
acc.Add value
Ok acc
)
else
("", BadPrimitive("an array", value)) |> Error
}
Decode.oneOf [
Decode.map box (decodeObject)
Decode.map box (resizeArray)
Decode.map box (Decode.string)
Decode.map box (Decode.int)
Decode.map box (Decode.decimal)
/// exports in json-ld format
static member toROCrateJsonString(?spaces) =
fun (obj:ROCrateObject) ->
ROCrateObject.encoder obj
|> Encode.toJsonString (Encode.defaultSpaces spaces)

]
decode()
member this.ToROCrateJsonString(?spaces) =
ROCrateObject.toROCrateJsonString(?spaces=spaces) this
44 changes: 20 additions & 24 deletions src/Json/ROCrateObject.fs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ module rec ROCrateObject =
)
|> Encode.object


let rec decoderWith (constructorByTypeFunc : string -> (string -> string -> string option -> #ROCrateObject)) : Decoder<obj> =
let rec decode() =
/// Returns a decoder
///
/// If expectObject is set to true, decoder fails if top-level value is not an ROCrate object
let rec getDecoder (expectObject : bool) : Decoder<obj> =
let rec decode(expectObject) =
let decodeObject : Decoder<ROCrateObject> =
{ new Decoder<ROCrateObject> with
member _.Decode(helpers, value) =
Expand All @@ -65,12 +67,10 @@ module rec ROCrateObject =
fun (get : Decode.IGetters) ->
let t = get.Required.Field "@type" Decode.string
let id = get.Required.Field "@id" Decode.string
let additionalType = get.Optional.Field "@additionalType" Decode.string
let f = constructorByTypeFunc t
let o = f t id additionalType :> ROCrateObject
let o = ROCrateObject(id,t)
for property in properties do
if property <> "@id" && property <> "@type" then
o.SetProperty(property,get.Required.Field property (decode()))
o.SetProperty(property,get.Required.Field property (decode(false)))
o
let result = builder getters
match getters.Errors with
Expand Down Expand Up @@ -98,7 +98,7 @@ module rec ROCrateObject =
match acc with
| Error _ -> acc
| Ok acc ->
match decode().Decode(helpers, value) with
match decode(false).Decode(helpers, value) with
| Error er ->
Error(
er
Expand All @@ -113,23 +113,19 @@ module rec ROCrateObject =
else
("", BadPrimitive("an array", value)) |> Error
}
Decode.oneOf [
if expectObject then
Decode.map box (decodeObject)
Decode.map box (resizeArray)
Decode.map box (Decode.string)
Decode.map box (Decode.int)
Decode.map box (Decode.decimal)

]
decode()

let untypedDecoder = decoderWith (fun _ ->
fun id t additionalType -> ROCrateObject(id,t,?additionalType = additionalType)
)
else
Decode.oneOf [
Decode.map box (decodeObject)
Decode.map box (resizeArray)
Decode.map box (Decode.string)
Decode.map box (Decode.int)
Decode.map box (Decode.decimal)

let typings : (string*(string->string->string option->#ROCrateObject)) list=
[
ROCrate.Assay
]
decode(expectObject)

let decoder : Decoder<ROCrateObject> = Decode.map unbox (getDecoder(true))

]
let genericDecoder : Decoder<obj> = getDecoder(false)

0 comments on commit 9f9b9c7

Please sign in to comment.