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

Support polymorphic unmarshaling #43

Open
clord opened this issue Aug 14, 2023 · 0 comments
Open

Support polymorphic unmarshaling #43

clord opened this issue Aug 14, 2023 · 0 comments

Comments

@clord
Copy link

clord commented Aug 14, 2023

I want to support polymophic discrimination through serialization. For example, see this short example:

package main

import (
	"encoding/json"
	"fmt"
)

type FruitType string

const (
	AppleType  FruitType = "Apple"
	BananaType FruitType = "Banana"
)

type Fruit interface {
	Type() FruitType
}

type fruitWrapper struct {
	Type FruitType `json:"type"`
}

type Apple struct {
	Type    FruitType `json:"type"`
	Variety string    `json:"variety"`
}

func (Apple) Type() FruitType { return AppleType }

type Banana struct {
	Type   FruitType `json:"type"`
	Length int       `json:"length"`
}

func (Banana) Type() FruitType { return BananaType }

func (f *Fruit) UnmarshalJSON(data []byte) error {
	var wrapper fruitWrapper
	if err := json.Unmarshal(data, &wrapper); err != nil {
		return err
	}

	switch wrapper.Type {
	case AppleType:
		var apple Apple
		if err := json.Unmarshal(data, &apple); err != nil {
			return err
		}
		*f = apple
	case BananaType:
		var banana Banana
		if err := json.Unmarshal(data, &banana); err != nil {
			return err
		}
		*f = banana
	default:
		return fmt.Errorf("unknown type")
	}

	return nil
}

func main() {
	jsonData := []byte(`{"type":"Apple","variety":"Fuji"}`)
	var fruit Fruit
	if err := json.Unmarshal(jsonData, &fruit); err != nil {
		fmt.Println(err)
		return
	}

	switch f := fruit.(type) {
	case Apple:
		fmt.Println("Apple variety:", f.Variety)
	case Banana:
		fmt.Println("Banana length:", f.Length)
	default:
		fmt.Println("Unknown fruit")
	}
}

To support this in oto, I suppose this function needs to support conditional unmarshalling, as above. To get correct TS code generation, we'd need to have all of the defined interfaces/structs tied together somehow, too.

Perhaps in the def, something like this:

type User interface { 
 // specializations: SpecificUser, AltUser, SomeOtherUserType
 Type() UserType
} 
...
// specializationOf: User
type SpecificUser struct {

then some mechanism to emit the correct code. I wonder at what the right level of codegen vs explicit specification is right, especially as Oto has the need to build these up in templates, too.

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