https://github.com/soulka/golymorph
The golymorph module enables resolving polymorphic typing at runtime. It's usually used during JSON parsing.
https://github.com/soulka/golymorph
go golang json mapping polymorphism struct
Last synced: about 1 month ago
JSON representation
The golymorph module enables resolving polymorphic typing at runtime. It's usually used during JSON parsing.
- Host: GitHub
- URL: https://github.com/soulka/golymorph
- Owner: SoulKa
- License: mit
- Created: 2023-11-25T09:48:40.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-01-06T21:08:30.000Z (about 2 years ago)
- Last Synced: 2024-01-06T22:20:13.917Z (about 2 years ago)
- Topics: go, golang, json, mapping, polymorphism, struct
- Language: Go
- Homepage:
- Size: 58.6 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# golymorph [](https://github.com/SoulKa/golymorph/actions/workflows/go-test.yaml) [](https://godoc.org/github.com/SoulKa/golymorph)
The golymorph module enables resolving polymorphic typing at runtime. It's usually used in
conjunction with JSON parsing and the `mapstructure` module. In fact, this module takes the use case
of `mapstructure` a step further by allowing the user to define a custom type resolver.
## Installation
Standard `go get`:
```shell
go get github.com/SoulKa/golymorph
```
## Docs
The docs are hosted on [Godoc](http://godoc.org/github.com/SoulKa/golymorph).
## Use Case
Use this module to resolve polymorphic types at runtime. An example would be a struct that contains
a payload field which can be of different struct types not known at compile time:
```go
// the parent type that contains the polymorphic payload
type Event struct {
Timestamp string
Payload any // <-- AlertPayload or PingPayload?
}
// the polymorphic child types
type AlertPayload struct {
Type string
Message string
}
type PingPayload struct {
Type string
Ip string
}
```
If, for example, you have a JSON that you decode into the `Event` struct, it is cumbersome to parse the JSON into a map, look into the `type` field of the `payload` and after that select and parse the map into the correct type at the `payload` field of the `event` struct.
golymorph does exactly this:
1. Look at the value of a defined field anywhere in the given `map` or JSON
2. Find the correct type using the given pairs of `value ==> reflect.Type`
3. Assign the correct type at the given position anywhere in the "parent" struct
4. Fully decode the given JSON or `map`, now with a concrete struct type as `payload`
## Example
```go
package main
import (
"fmt"
"github.com/SoulKa/golymorph"
"reflect"
)
func main() {
// get a JSON that contains a payload with a type field that determines the type of the payload
alertEventJson := `{ "timestamp": "2023-11-27T22:14:09+00:00", "payload": { "type": "alert", "message": "something is broken!" } }`
// the parent type that contains the polymorphic payload
type Event struct {
Timestamp string
Payload any
}
// the polymorphic child types
type AlertPayload struct {
Type string
Message string
}
type PingPayload struct {
Type string
Ip string
}
// define a mapping from the type value to the type of the payload
typeMap := golymorph.TypeMap{
"alert": reflect.TypeOf(AlertPayload{}),
"ping": reflect.TypeOf(PingPayload{}),
}
// create a TypeResolver that assigns the type of the payload based on the type field
err, resolver := golymorph.NewPolymorphismBuilder().
DefineTypeAt("payload").
UsingTypeMap(typeMap).
WithDiscriminatorAt("type").
Build()
if err != nil {
panic(fmt.Sprintf("error building polymorpher: %s", err))
}
// create a new event
var event Event
if err := golymorph.UnmarshalJSON(resolver, []byte(alertEventJson), &event); err != nil {
panic(fmt.Sprintf("error unmarshalling event: %s", err))
}
// continue to work with the event
fmt.Printf("event: %+v\n", event)
fmt.Printf("event payload: %T %+v\n", event.Payload, event.Payload.(AlertPayload))
}
```
## Contributing
I am very happy for contributions or feature suggestions. As long as this module is not stable released (version 1.0.0) I am also open for refactorings.
**How to:**
- Fork it
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Added some feature')
- Push to the branch (git push origin my-new-feature)
- Create new Pull Request