dstruct

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2023 License: MIT Imports: 6 Imported by: 4

README

dstruct

A golang package that allows one to create, modify and generate structs dynamically.

Features:

  • Building structs at runtime
  • Extending existing struct at runtime
  • Merging multiple structs at runtime
  • Adding new fields into struct
  • Removing existing fields from struct
  • Modifying field values in structs
  • Reading field values in strucst
  • Generating struct values

Sections

How it works?

Dstruct uses a tree to represent structs where nodes represent struct fields and children reprent struct fields subfields. This allows the struct to be easily modified. Once the tree stucture of the struct is built out the tree is converted into a dynamic struct with the aid of the reflect package.

Dstruct has 3 main interfaces that are implemented in order to allow these features:

  1. dstruct.Builder is responsible for adding and removing fields from a struct.
type Builder interface {
    AddField(name string, value interface{}, tag string) Builder
    Build() DynamicStructModifier
    GetField(name string) Builder
    GetFieldCopy(field string) Builder
    RemoveField(name string) Builder
}
  1. dstruct.DynamicStructModifier is responsible for reading and editing fields with the struct as well as storing the actual struct.

type DynamicStructModifier interface {
    Instance() any
    New() any
    Get(field string) (any, error)
    Set(field string, value any) error
}

  1. dstruct.GeneratedStruct is responsible for generating struct values and is an extention of the DynamicStructModifier. A generated struct values are randomly generation based on Generation functions.
type GeneratedStruct interface {
    DynamicStructModifier
    Generate()
    GetFieldGenerationConfig(field string) *generator.GenerationConfig
    SetFieldGenerationConfig(field string, generationConfig *generator.GenerationConfig) error
}

Using the Builder


type Person struct {
	Name string
	Age  int
}

func main() {
	structBuilder := dstruct.NewBuilder().
		AddField("Person", Person{Name: "Martin", Age: 25}, `json:"person"`).
		AddField("Job", "Software Developer", "").
		RemoveField("Person.Age")

	fmt.Printf("Sturct: %+v\n", structBuilder.Build().Instance())
}

Output

$ Struct: {Person:{Name:Martin} Job:Software Developer}

Using the Modifier


type Person struct {
	Name string
	Age  int
}

func main() {
	structBuilder := dstruct.NewBuilder().
		AddField("Person", Person{Name: "Martin", Age: 25}, `json:"person"`).
		AddField("Job", "Software Developer", "")

	structModifier := structBuilder.Build()
	structModifier.Set("Person.Name", "Martin Simango")
	structModifier.Set("Job", "Software Engineer")

	name, _ := structModifier.Get("Person.Name")

	fmt.Printf("New name: %s\n", name.(string))
	fmt.Printf("Struct: %+v\n", structModifier.Instance())
}

Output

$ New name: Martin Simango
$ Struct: {Person:{Name:Martin Simango Age:25} Job:Software Engineer}

Using the Struct Generator


type Person struct {
	Name string
	Age  int
}

func main() {
	structBuilder := dstruct.NewBuilder().
		AddField("Person", Person{Name: "Martin", Age: 25}, `json:"person"`).
		AddField("Job", "Software Developer", "")

	strct := structBuilder.Build().Instance()

	generatedStruct := dstruct.NewGeneratedStruct(strct)
	// change the age to be between 50 and 60
	generatedStruct.GetFieldGenerationConfig("Person.Age").SetIntMin(50).SetIntMax(60)
	generatedStruct.Generate()
	fmt.Printf("Struct with age between 50 and 60: %+v\n", generatedStruct.Instance())
	// change the age to be between 10 and 20
	generatedStruct.GetFieldGenerationConfig("Person.Age").SetIntMin(10).SetIntMax(20)
	generatedStruct.Generate()
	fmt.Printf("Struct with age between 10 and 20: %+v\n", generatedStruct.Instance())

}

Output:

$ Struct with age between 50 and 60: {Person:{Name:string Age:59} Job:string}
$ Struct with age between 10 and 20: {Person:{Name:string Age:16} Job:string}

Extending a struct

type Address struct {
	Street string
}

type Person struct {
	Name    string
	Age     int
	Address Address
}

func main() {
	strct := dstruct.ExtendStruct(Person{
		Name: "Martin",
		Age:  25,
		Address: Address{
			Street: "Alice Street",
		},
	})
	strct.GetField("Address").AddField("StreetNumber", 1, "")

	fmt.Printf("Extended struct: %+v\n", strct.Build().Instance())

}

Output:

$ Extended struct: {Name:Martin Age:25 Address:{Street:Alice Street StreetNumber:1}}

Merging structs

type PersonDetails struct {
	Age    int
	Height float64
}

type PersonName struct {
	Name    string
	Surname string
}

func main() {
	strct, _ := dstruct.MergeStructs(PersonDetails{Age: 0, Height: 190.4}, PersonName{Name: "Martin", Surname: "Simango"})
	fmt.Printf("Merged structs: %+v\n", strct)
}

Output:

$ Merged structs: {Age:0 Height:190.4 Name:Martin Surname:Simango}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CanExtend

func CanExtend(val any) bool

func GetPointerToSliceType

func GetPointerToSliceType(sliceType reflect.Type) any

func MergeStructs

func MergeStructs(strcts ...interface{}) (a any, err error)

MergeStructs merges two structs

func Print

func Print(strct any) string

Types

type Builder

type Builder interface {
	// AddField adds a field to the struct.
	AddField(name string, value interface{}, tag string) Builder

	// Build returns a DynamicStructModifier instance.
	Build() DynamicStructModifier

	// GetField returns a builder instance of the subfield of the struct that is currently being built.
	GetField(name string) Builder

	// GetFieldCopy returns a copy of a builder instance of the subfield of the struct that is currently being built.
	GetFieldCopy(field string) Builder

	// RemoveField removes a field from the struct.
	RemoveField(name string) Builder
}

func ExtendStruct

func ExtendStruct(val any) Builder

func NewBuilder

func NewBuilder() Builder

type DynamicStructModifier

type DynamicStructModifier interface {
	// Instance returns a copy of the struct
	Instance() any

	// New returns a pointer to the struct
	New() any

	// Get gets the value of the struct field `field` and returns an error if the field is not found
	Get(field string) (any, error)

	// Set sets the value of the struct field `field` and returns an error if the field is not found.
	//
	// The program will panic if the type of value does not match the type of the struct field `field`.
	Set(field string, value any) error
}

type DynamicStructModifierImpl

type DynamicStructModifierImpl struct {
	// contains filtered or unexported fields
}

func (*DynamicStructModifierImpl) Get

func (dm *DynamicStructModifierImpl) Get(field string) (any, error)

func (*DynamicStructModifierImpl) Instance

func (dm *DynamicStructModifierImpl) Instance() any

func (*DynamicStructModifierImpl) New

func (dm *DynamicStructModifierImpl) New() any

func (*DynamicStructModifierImpl) Set

func (dm *DynamicStructModifierImpl) Set(field string, value any) error

func (*DynamicStructModifierImpl) String

func (dm *DynamicStructModifierImpl) String() string

type Field

type Field struct {
	Name  string
	Tag   reflect.StructTag
	Value reflect.Value
	Type  reflect.Type

	StructIndex int
	SubFields   int
	// contains filtered or unexported fields
}

func (Field) GetFieldFQName

func (f Field) GetFieldFQName() string

func (Field) GetFieldName

func (f Field) GetFieldName() string

type FieldMap

type FieldMap map[string]*Node[Field]

type FieldModifier

type FieldModifier func(*Field)

type GeneratedStruct

type GeneratedStruct interface {
	DynamicStructModifier
	// Generate generates fields for the struct
	Generate()

	// GetFieldGenerationConfig gets the generation config for field within the struct.
	GetFieldGenerationConfig(field string) *generator.GenerationConfig

	// SetFieldGenerationConfig sets the generation config for field within the struct. It returns
	// an error if the field does not exist or if the field cannot be generated.
	// Fields that can be generated are struct fields of the most basic type i.e a struct fields
	// that are structs cannot be generated, however it's fields can be.
	//
	// Fields types that cannot be generated: structs, func, chan, any (will default to a nil value being generated).
	//
	// Note: Pointers to structs can be generated.
	SetFieldGenerationConfig(field string, generationConfig *generator.GenerationConfig) error
}

type GeneratedStructImpl

type GeneratedStructImpl struct {
	*DynamicStructModifierImpl
	// contains filtered or unexported fields
}

func NewGeneratedStruct

func NewGeneratedStruct(val any) *GeneratedStructImpl

func NewGeneratedStructWithConfig

func NewGeneratedStructWithConfig(val any, config *generator.GenerationConfig) *GeneratedStructImpl

func (*GeneratedStructImpl) Generate

func (gs *GeneratedStructImpl) Generate()

func (*GeneratedStructImpl) GetFieldGenerationConfig

func (gs *GeneratedStructImpl) GetFieldGenerationConfig(field string) *generator.GenerationConfig

func (*GeneratedStructImpl) SetFieldGenerationConfig

func (gs *GeneratedStructImpl) SetFieldGenerationConfig(field string, generationConfig *generator.GenerationConfig) error

type GenerationFields

type GenerationFields map[string]*generator.GenerationUnit

type Node

type Node[T any] struct {
	// contains filtered or unexported fields
}

Struct will be represented using a Tree

func (*Node[T]) AddNode

func (n *Node[T]) AddNode(name string, data *T)

func (*Node[T]) Copy

func (n *Node[T]) Copy() *Node[T]

func (*Node[T]) DeleteNode

func (n *Node[T]) DeleteNode(name string)

func (*Node[T]) GetNode

func (n *Node[T]) GetNode(name string) *Node[T]

func (*Node[T]) HasChildren

func (n *Node[T]) HasChildren() bool

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL