da

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2025 License: MIT Imports: 6 Imported by: 3

README

da - Dynamic Application

Easily manage massive monoliths in code

The da package provides a powerful application container for managing object dependencies, lifecycle, and service discovery in large, dynamic Go applications.

Quick Start

import "github.com/michaelquigley/df/da"

// Create application with config
app := da.NewApplication(config)

// Add factories to build objects
da.WithFactory(app, &DatabaseFactory{})
da.WithFactory(app, &LoggerFactory{})

// Initialize: build objects and link dependencies  
app.Initialize()

// Start all startable services
app.Start()

// Clean shutdown
defer app.Stop()

Key Features

  • 🏭 Factory Pattern: Automatic object creation and registration
  • 🔗 Dependency Injection: Type-safe object retrieval and linking
  • ♻️ Lifecycle Management: Initialize → Start → Stop pattern
  • 🔍 Service Discovery: Find objects by type or interface
  • 📋 Container Introspection: Debug and inspect container contents
  • ⚡ Thread-Safe: Concurrent access to container objects

Core Components

  • Container - Object storage with singleton and named object support
  • Application[C] - Orchestrates object creation and lifecycle
  • Factory[C] - Interface for creating and registering objects
  • Lifecycle interfaces: Startable, Stoppable, Linkable

Object Management

Register and retrieve objects

// Store singleton objects (one per type)
da.Set(container, database)
da.SetAs[DataStore](container, database)  // store as interface

// Retrieve objects by type
db, found := da.Get[*Database](container)
stores := da.OfType[DataStore](container)  // all matching interface

// Named objects (multiple per type)
da.SetNamed(container, "primary", primaryDB)
da.SetNamed(container, "cache", cacheDB)

Factory Pattern

Create objects with dependencies

type DatabaseFactory struct{}

func (f *DatabaseFactory) Build(app *da.Application[Config]) error {
    // Get config from container
    cfg, _ := da.Get[Config](app.R)
    
    // Create and register database
    db := &Database{URL: cfg.DatabaseURL}
    da.SetAs[*Database](app.R, db)
    return nil
}

Lifecycle Management

Objects implement lifecycle interfaces

type Database struct {
    URL       string
    Connected bool
}

// da.Startable - called during app.Start()
func (d *Database) Start() error {
    return d.Connect()
}

// da.Stoppable - called during app.Stop()  
func (d *Database) Stop() error {
    d.Connected = false
    return nil
}

// da.Linkable - called after all objects created
func (d *Database) Link(container *da.Container) error {
    logger, _ := da.Get[*Logger](container)
    d.logger = logger
    return nil
}

Common Patterns

Application Bootstrap

type AppConfig struct {
    DatabaseURL string `json:"database_url"`
    LogLevel    string `json:"log_level"`
}

// Load config and create application
config := loadConfig()
app := da.NewApplication(config)

// Register all factories
da.WithFactory(app, &DatabaseFactory{})
da.WithFactory(app, &CacheFactory{})
da.WithFactory(app, &HTTPServerFactory{})

// Initialize and start
app.Initialize()  // builds all objects
app.Start()       // starts all Startable objects

Service Discovery

// Find all objects implementing an interface
allCaches := da.AsType[CacheService](container)
allStartables := da.AsType[da.Startable](container)

// Container introspection for debugging
data := container.Inspect()
fmt.Printf("Container has %d objects\n", data.Summary.Total)

Examples

See examples/ for tutorials on basic containers, dependency injection, and lifecycle management.


Part of the df framework - dynamic foundation for Go applications

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AsType

func AsType[T any](c *Container) []T

AsType visits all objects in the container and returns any that can be cast to type T. This enables finding objects by interface or supertype regardless of their registration type.

func Get

func Get[T any](c *Container) (T, bool)

Get retrieves an object of type T from the container. Returns the object and true if found, or zero value and false if not found.

func GetNamed

func GetNamed[T any](c *Container, name string) (T, bool)

GetNamed retrieves a named object of type T from the container. Returns the object and true if found, or zero value and false if not found.

func Has

func Has[T any](c *Container) bool

Has checks if an object of type T exists in the container.

func HasNamed

func HasNamed[T any](c *Container, name string) bool

HasNamed checks if a named object of type T with the given name exists in the container.

func OfType

func OfType[T any](c *Container) []T

OfType retrieves all objects of type T from the container (both singleton and named). Returns a slice containing the singleton (if exists) followed by all named instances.

func Remove

func Remove[T any](c *Container) bool

Remove removes an object of type T from the container. Returns true if the object was found and removed, false if it didn't exist.

func RemoveNamed

func RemoveNamed[T any](c *Container, name string) bool

RemoveNamed removes a named object of type T with the given name from the container. Returns true if the object was found and removed, false if it didn't exist.

func Set

func Set(c *Container, object any)

Set registers a singleton object in the container by its type. If an object of the same type already exists, it will be replaced.

func SetAs

func SetAs[T any](c *Container, object T)

SetAs registers a singleton object in the container by the specified type. If an object of the same type already exists, it will be replaced.

func SetNamed

func SetNamed(c *Container, name string, object any)

SetNamed registers a named object in the container by its type and name. If an object with the same type and name already exists, it will be replaced.

Types

type Application

type Application[C any] struct {
	Cfg       C            // configuration object
	C         *Container   // dependency injection container
	Factories []Factory[C] // factories for creating and registering objects
}

Application orchestrates the lifecycle of a dependency injection container with configuration. It manages object creation through factories, dependency linking, startup, and shutdown phases.

func NewApplication

func NewApplication[C any](cfg C) *Application[C]

NewApplication creates a new application with the given configuration. The configuration object is automatically registered in the container.

func WithFactory

func WithFactory[C any](a *Application[C], f Factory[C]) *Application[C]

WithFactory adds a factory to the application for fluent configuration. Returns the application to enable method chaining.

func WithFactoryFunc

func WithFactoryFunc[C any](a *Application[C], f func(a *Application[C]) error) *Application[C]

WithFactoryFunc adds a function factory to the application for fluent configuration. Returns the application to enable method chaining.

func (*Application[C]) Build

func (a *Application[C]) Build() error

Build executes all registered factories to create and register objects in the container. Factories are responsible for calling SetAs[T]() to register their created objects.

func (*Application[C]) Configure

func (a *Application[C]) Configure(path string, opts ...*dd.Options) error

Configure loads additional configuration from a file and merges it with the existing configuration. Supports JSON and YAML file formats based on file extension.

func (*Application[C]) Initialize

func (a *Application[C]) Initialize(configPaths ...string) error

Initialize executes Configure, Build, and Link phases in sequence. Returns on first error without proceeding to subsequent phases.

func (*Application[C]) InitializeWithOptions

func (a *Application[C]) InitializeWithOptions(opts *dd.Options, configPaths ...string) error

InitializeWithOptions executes Configure, Build, and Link phases in sequence with custom options. Returns on first error without proceeding to subsequent phases.

func (a *Application[C]) Link() error

Link establishes dependencies between objects by calling Link() on all Linkable objects. This phase occurs after Build() to ensure all objects exist before dependency resolution. Returns the first error encountered, which stops the linking process.

func (*Application[C]) Start

func (a *Application[C]) Start() error

Start initializes all Startable objects after linking is complete. Returns the first error encountered, which stops the startup process.

func (*Application[C]) Stop

func (a *Application[C]) Stop() error

Stop shuts down all Stoppable objects for graceful cleanup. Returns the first error encountered, but continues attempting to stop remaining objects.

type Container

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

Container is an application container that manages singletons and objects by type and (optionally) by name.

func NewContainer

func NewContainer() *Container

NewContainer creates and returns a new empty container.

func (*Container) Clear

func (c *Container) Clear()

Clear removes all objects from the container.

func (*Container) Inspect

func (c *Container) Inspect(format InspectFormat) (string, error)

Inspect returns a formatted representation of the container contents. Supports table, JSON, and YAML formats for human and machine consumption.

func (*Container) Types

func (c *Container) Types() []reflect.Type

Types returns a slice of all registered types in the container. Useful for debugging and introspection.

func (*Container) Visit

func (c *Container) Visit(f func(object any) error) error

Visit calls the provided function for each object in the container.

type Factory

type Factory[C any] interface {
	Build(a *Application[C]) error
}

Factory creates and registers objects in the application container. Implementations should use SetAs[T]() to register created objects with the container.

type FactoryFunc

type FactoryFunc[C any] func(a *Application[C]) error

FactoryFunc is a function type that implements Factory[C]. It allows using raw functions as factories without defining separate types.

func (FactoryFunc[C]) Build

func (f FactoryFunc[C]) Build(a *Application[C]) error

Build implements the Factory interface for FactoryFunc.

type InspectData

type InspectData struct {
	Summary InspectSummary  `json:"summary" yaml:"summary"`
	Objects []InspectObject `json:"objects" yaml:"objects"`
}

InspectData represents the structured data for container inspection.

type InspectFormat

type InspectFormat string

InspectFormat defines the output format for container inspection.

const (
	InspectHuman InspectFormat = "human"
	InspectJSON  InspectFormat = "json"
	InspectYAML  InspectFormat = "yaml"
)

type InspectObject

type InspectObject struct {
	Type    string  `json:"type" yaml:"type"`
	Storage string  `json:"storage" yaml:"storage"`
	Name    *string `json:"name" yaml:"name"`
	Value   string  `json:"value" yaml:"value"`
}

InspectObject represents a single object in the container for inspection.

type InspectSummary

type InspectSummary struct {
	Total      int `json:"total" yaml:"total"`
	Singletons int `json:"singletons" yaml:"singletons"`
	Named      int `json:"named" yaml:"named"`
}

InspectSummary provides aggregate statistics about the container.

type Linkable

type Linkable interface {
	Link(*Container) error
}

Linkable defines objects that can establish connections to other container objects during the linking phase after all objects have been created.

type Startable

type Startable interface {
	Start() error
}

Startable defines objects that require initialization after linking is complete.

type Stoppable

type Stoppable interface {
	Stop() error
}

Stoppable defines objects that require cleanup during shutdown.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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