| title | Basic Usage | |||
|---|---|---|---|---|
| description | Common patterns for registration, atomization, and deatomization | |||
| author | zoobzio | |||
| published | 2025-01-01 | |||
| updated | 2025-01-06 | |||
| tags |
|
Common patterns for working with atom.
atomizer, err := atom.Use[User]()
if err != nil {
log.Fatalf("failed to register User: %v", err)
}Register all types at startup for predictable initialization:
func init() {
types := []func() error{
func() error { _, err := atom.Use[User](); return err },
func() error { _, err := atom.Use[Order](); return err },
func() error { _, err := atom.Use[Product](); return err },
}
for _, register := range types {
if err := register(); err != nil {
log.Fatalf("type registration failed: %v", err)
}
}
}Registration fails for unsupported types:
type Invalid struct {
Data map[string]any // Maps are not supported
}
_, err := atom.Use[Invalid]()
// err: "type Invalid: field "Data": map types are not supported"user := &User{Name: "Alice", Age: 30}
atom := atomizer.Atomize(user)Use NewAtom() to create a properly sized empty atom:
atom := atomizer.NewAtom()
atom.Strings["Name"] = "Bob"
atom.Ints["Age"] = 25Access fields through type-specific maps:
atom := atomizer.Atomize(user)
name := atom.Strings["Name"]
age := atom.Ints["Age"]
active := atom.Bools["Active"]
created := atom.Times["CreatedAt"]if name, ok := atom.Strings["Name"]; ok {
fmt.Println("Name:", name)
}restored, err := atomizer.Deatomize(atom)
if err != nil {
log.Printf("deatomize failed: %v", err)
return
}Deatomization can fail for overflow:
type Small struct {
Value int8
}
atomizer, _ := atom.Use[Small]()
a := &atom.Atom{Ints: map[string]int64{"Value": 200}}
_, err := atomizer.Deatomize(a)
// err: "value 200 overflows int8 (range -128 to 127)"Missing fields are left at their zero value:
atom := &atom.Atom{
Strings: map[string]string{"Name": "Alice"},
// Age not set
}
user, _ := atomizer.Deatomize(atom)
fmt.Println(user.Name) // "Alice"
fmt.Println(user.Age) // 0 (zero value)fields := atomizer.Fields()
for _, f := range fields {
fmt.Printf("%s -> %s\n", f.Name, f.Table)
}
// ID -> ints
// Name -> strings
// Email -> stringsstringFields := atomizer.FieldsIn(atom.TableStrings)
// ["Name", "Email"]
intFields := atomizer.FieldsIn(atom.TableInts)
// ["ID", "Age"]table, ok := atomizer.TableFor("Age")
if ok {
fmt.Println("Age is stored in:", table) // "ints"
}Pointer fields use separate tables and can be nil:
type Config struct {
Name string
MaxRetry *int64
Timeout *float64
}
atomizer, _ := atom.Use[Config]()
cfg := &Config{Name: "default", MaxRetry: nil}
atom := atomizer.Atomize(cfg)
// atom.Strings["Name"] = "default"
// atom.IntPtrs["MaxRetry"] = nilatom := atomizer.NewAtom()
atom.Strings["Name"] = "custom"
retries := int64(3)
atom.IntPtrs["MaxRetry"] = &retries
cfg, _ := atomizer.Deatomize(atom)
fmt.Println(*cfg.MaxRetry) // 3type User struct {
Name string
Tags []string
Scores []int64
}
atomizer, _ := atom.Use[User]()
user := &User{
Name: "Alice",
Tags: []string{"admin", "verified"},
Scores: []int64{95, 87, 92},
}
atom := atomizer.Atomize(user)
// atom.Strings["Name"] = "Alice"
// atom.StringSlices["Tags"] = ["admin", "verified"]
// atom.IntSlices["Scores"] = [95, 87, 92]// Nil slice - no entry in atom
user := &User{Tags: nil}
atom := atomizer.Atomize(user)
_, ok := atom.StringSlices["Tags"] // ok = false
// Empty slice - empty entry in atom
user := &User{Tags: []string{}}
atom := atomizer.Atomize(user)
tags := atom.StringSlices["Tags"] // tags = []spec := atomizer.Spec()
fmt.Println(spec.TypeName) // "User"
fmt.Println(spec.PackageName) // "github.com/example/app"Each atom carries its type spec:
atom := atomizer.Atomize(user)
fmt.Println(atom.Spec.TypeName) // "User"Register types at application startup:
func main() {
// Register all types first
userAtomizer, _ = atom.Use[User]()
orderAtomizer, _ = atom.Use[Order]()
// Then use them
runApp()
}Store atomizers rather than calling Use repeatedly:
// Good
var userAtomizer *atom.Atomizer[User]
func init() {
userAtomizer, _ = atom.Use[User]()
}
func ProcessUser(u *User) *atom.Atom {
return userAtomizer.Atomize(u)
}Always check deatomization errors:
// Bad
user, _ := atomizer.Deatomize(atom)
// Good
user, err := atomizer.Deatomize(atom)
if err != nil {
return fmt.Errorf("deatomize: %w", err)
}- Custom Types Guide - Named types and byte arrays
- Nested Structs Guide - Working with nested data
- Interfaces Guide - Custom serialization