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

Unwrap the whole union into a record #157

Open
shanoaice opened this issue Apr 29, 2023 · 1 comment
Open

Unwrap the whole union into a record #157

shanoaice opened this issue Apr 29, 2023 · 1 comment

Comments

@shanoaice
Copy link

shanoaice commented Apr 29, 2023

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
}
@shanoaice
Copy link
Author

shanoaice commented Sep 3, 2023

Hello, is there any ways to achieve that without using obj and downcast?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant