Skip to content

Unwrap the whole union into a record #157

@shanoaice

Description

@shanoaice

I have the following two types:

[<JsonFSharpConverter(UnionTagName = "tag")>]
type ExUnion = 
| CaseOne of string
| CaseTwo of int

type ExRecord =
{ settings: ExUnion 
  // and some other fields that are the same for all cases of settings, which will be unwise to pack them into ExUnion
   }

let exVar = { settings = CaseOne "example" }

and I want the exVar to be serialized as follows, where the record field name indicates the field name of the case value, and another field that indicates the tag of the union:

{
	"tag": "CaseOne",
	"settings": "example"
}

with JsonUnionEncoding.AdjacentTag I was only able to get the follows:

{
	"settings": {
		"Case": "CaseOne",
		"Fields": "example"
	}
}

And I can't figure out how to achieve what I want.

EDIT: I figured out how to do that:

type ExRecord<'a> =
	{ settings: 'a }

[<JsonFSharpConverter(BaseUnionEncoding = JsonUnionEncoding.InternalTag, UnionUnwrapRecordCases = true, UnionTagName = "tag")]
type ExUnion = 
	| Case1 of ExRecord<string>
	| Case2 of ExRecord<int>

and call JsonSerializer.Serialize() on instances of ExUnion instead of ExRecord.
But I still feel that such pattern is a bit counterintuitive, since I want to represent a field in a record whose type is annotated by another field in the same record, on the same level. Wrapping that with a DU under the record feels like a more natural way to do that. Even worse, this reverse-wrapping won't work if I want to achieve the follows:

[<JsonFSharpConverter(UnionTagName = "tag")>]
type ExUnion1 = 
| CaseOne of string
| CaseTwo of int

[<JsonFSharpConverter(UnionTagName = "tag2")>]
type ExUnion2 =
| A of int
| B of string

type ExRecord =
{ settings: ExUnion1
  settings2: ExUnion2 }

let exVar = { settings = CaseOne "example"; settings2 = A 8 }

and serialize exVar into the follows:

{
	"tag": "CaseOne",
	"settings": "example",
	"tag2": "A",
	"settings2": 8
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions