oto icon indicating copy to clipboard operation
oto copied to clipboard

Support polymorphic unmarshaling

Open clord opened this issue 1 year ago • 0 comments

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.

clord avatar Aug 14 '23 22:08 clord