Skip to main content

Mold

The mold package is a struct transformation engine that modifies field values based on struct tags. It operates at both field and struct levels.

How It Works

The mold tag on struct fields triggers transformation functions. The framework automatically runs the mold transformer on query results to enrich response data.

Built-in: User Name Translation

The most common built-in usage is translating user IDs into display names:

type User struct {
orm.FullAuditedModel
// CreatedBy string `mold:"translate=user?"` ← inherited from FullAuditedModel
// CreatedByName string `bun:",scanonly"` ← populated by mold
}

When a query result contains CreatedBy = "user-123", the mold transformer looks up the user data dictionary and sets CreatedByName = "Alice".

Interfaces

Transformer

type Transformer interface {
Struct(ctx context.Context, value any) error
Field(ctx context.Context, value any, tags string) error
}

FieldTransformer

Implement custom field-level transformations:

type FieldTransformer interface {
Tag() string
Transform(ctx context.Context, fl FieldLevel) error
}

StructTransformer

Implement custom struct-level transformations:

type StructTransformer interface {
Transform(ctx context.Context, sl StructLevel) error
}

Interceptor

Redirect transformation to inner values (e.g., sql.NullString → its inner string):

type Interceptor interface {
Intercept(current reflect.Value) (inner reflect.Value)
}

FieldLevel API

Inside a field transformer, FieldLevel provides:

MethodReturnsPurpose
Transformer()TransformerAccess the parent transformer
Name()stringCurrent field name
Parent()reflect.ValueParent struct value
Field()reflect.ValueCurrent field value
Param()stringParameter from tag (e.g., user? in translate=user?)
SiblingField(name)reflect.Value, boolAccess sibling field by name

Tag Format

mold:"function=param"

Multiple transformations:

mold:"function1=param1,function2=param2"

Data Dictionary Resolution

The translate transformer resolves field values through a data dictionary:

type DataDictResolver interface {
Resolve(ctx context.Context, dictType string, keys []string) (map[string]string, error)
}

The ? suffix in translate=user? means the translation is optional — if the lookup fails, the original value is kept instead of returning an error.

Cached Resolution

The CachedDataDictResolver wraps a DataDictResolver with in-request caching to avoid redundant lookups when the same dict type is resolved multiple times in a single request.