ore

package module
v0.0.0-...-f7d32da Latest Latest
Warning

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

Go to latest
Published: Apr 10, 2025 License: MIT Imports: 11 Imported by: 0

README ΒΆ

Ore: A Lightweight Dependency Injection Container for Go

Go Reference Go Report Card Mentioned in Awesome Go codecov

ore


Ore is a powerful and flexible Dependency Injection (DI) library for Go, designed to simplify complex application structures while maintaining performance and modularity.

🌐 Full Documentation: ore.lilury.com


Key Features

1. Flexible Lifetime Management
  • Singletons: Lifetime spans the entire application.
  • Scoped: Lifetime is tied to a specific context.
  • Transient: New instance created on every resolution.

2. Alias Support
  • Link multiple implementations to the same interface.
  • Easily resolve the preferred implementation or retrieve all registered options.

3. Graceful Termination
  • Application Termination: Shutdown all resolved singletons implementing Shutdowner in proper dependency order.
  • Context Termination: Dispose all resolved scoped instances implementing Disposer when the context ends.

4. Placeholder Registration
  • Register incomplete dependencies at application setup.
  • Provide runtime values dynamically when requests or events occur.

5. Multiple Containers (Modules)
  • Create isolated dependency graphs for modular applications.
  • Enforce module boundaries by separating service registrations and resolutions per container.

6. Advanced Dependency Validation
  • Detect and prevent common pitfalls like:
    • Missing Dependencies: Ensure all resolvers are registered.
    • Circular Dependencies: Avoid infinite loops in dependency resolution.
    • Lifetime Misalignment: Catch improper lifetime dependencies (e.g., singleton depending on transient).

7. Keyed and Keyless Registration
  • Support for multiple instances of the same type, scoped by keys.
  • Easily resolve services using keys to manage module-specific configurations.

8. Runtime Value Injection
  • Inject dependencies dynamically during runtime, tailored to request context or user data.

9. Context-Based Dependency Resolution
  • Dependencies can be tied to a specific context.Context.
  • Automatic cleanup of scoped services when the context ends.

Installation

go get -u github.com/narrowavenue/ore
Quick Example
package main

import (
  "context"
  "fmt"
  "github.com/narrowavenue/ore"
)

// Define a service
type MyService struct {
  Message string
}

func main() {
  // Register a singleton service
  ore.RegisterSingleton[SomeServiceInterface](&MyService{Message: "Hello, Ore!"})
  
  // Resolve the service
  service, _ := ore.Get[*SomeServiceInterface](context.Background())
  fmt.Println(service.Message) // Output: Hello, Ore!
}

For complete usage examples and advanced configurations, visit the Ore Documentation.


πŸ‘€ Contributors

Contributors


Contributing

Feel free to contribute by opening issues, suggesting features, or submitting pull requests. We welcome your feedback and contributions.


License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

View Source
var (
	DefaultContainer = NewContainer()
)

Functions ΒΆ

func ContainerID ΒΆ

func ContainerID() int32

func Get ΒΆ

func Get[T any](ctx context.Context) (T, context.Context)

Get Retrieves an instance based on type and key (panics if no valid implementations)

func GetFromContainer ΒΆ

func GetFromContainer[T any](con *Container, ctx context.Context) (T, context.Context)

GetFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations)

func GetKeyed ΒΆ

func GetKeyed[T any, K comparable](ctx context.Context, key K) (T, context.Context)

GetKeyed Retrieves an instance based on type and key (panics if no valid implementations)

func GetKeyedFromContainer ΒΆ

func GetKeyedFromContainer[T any, K comparable](con *Container, ctx context.Context, key K) (T, context.Context)

GetKeyedFromContainer Retrieves an instance from the given container based on type and key (panics if no valid implementations)

func GetKeyedList ΒΆ

func GetKeyedList[T any, K comparable](ctx context.Context, key K) ([]T, context.Context)

GetKeyedList Retrieves a list of instances based on type and key

func GetKeyedListFromContainer ΒΆ

func GetKeyedListFromContainer[T any, K comparable](con *Container, ctx context.Context, key K) ([]T, context.Context)

GetKeyedListFromContainer Retrieves a list of instances from the given container based on type and key

func GetList ΒΆ

func GetList[T any](ctx context.Context) ([]T, context.Context)

GetList Retrieves a list of instances based on type and key

func GetListFromContainer ΒΆ

func GetListFromContainer[T any](con *Container, ctx context.Context) ([]T, context.Context)

GetListFromContainer Retrieves a list of instances from the given container based on type and key

func GetResolvedScopedInstances ΒΆ

func GetResolvedScopedInstances[TInterface any](ctx context.Context) []TInterface

GetResolvedScopedInstances retrieves a list of Scoped instances that implement the [TInterface]. The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the most recently created one. If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. It would return only the instances which had been resolved. Other lazy implementations which have never been invoked will not be returned. This function is useful for cleaning operations.

Example:

     disposableInstances := ore.GetResolvedScopedInstances[Disposer](ctx)
	 for _, disposable := range disposableInstances {
	   disposable.Dispose()
	 }

func GetResolvedSingletons ΒΆ

func GetResolvedSingletons[TInterface any]() []TInterface

GetResolvedSingletons retrieves a list of Singleton instances that implement the [TInterface]. The returned instances are sorted by creation time (a.k.a the invocation order), the first one being the "most recently" created one. If an instance "A" depends on certain instances "B" and "C" then this function guarantee to return "B" and "C" before "A" in the list. It would return only the instances which had been resolved. Other lazy implementations which have never been invoked will not be returned. This function is useful for cleaning operations.

Example:

     disposableSingletons := ore.GetResolvedSingletons[Disposer]()
	 for _, disposable := range disposableSingletons {
	   disposable.Dispose()
	 }

func GetResolvedSingletonsFromContainer ΒΆ

func GetResolvedSingletonsFromContainer[TInterface any](con *Container) []TInterface

GetResolvedSingletonsFromContainer retrieves a list of Singleton instances that implement the [TInterface] from the given container. See GetResolvedSingletons for more information.

func IsSealed ΒΆ

func IsSealed() bool

IsSealed checks whether the DEFAULT container is sealed (in readonly mode)

func Name ΒΆ

func Name() string

func ProvideKeyedScopedValue ΒΆ

func ProvideKeyedScopedValue[T any, K comparable](ctx context.Context, value T, key K) context.Context

ProvideKeyedScopedValue injects a concrete value into the given context. This value will be available only to the default container. And the container can only resolve this value if it has the matching (type and key's) Placeholder registered. Checkout the RegisterPlaceholder function for more info.

func ProvideKeyedScopedValueToContainer ΒΆ

func ProvideKeyedScopedValueToContainer[T any, K comparable](con *Container, ctx context.Context, value T, key K) context.Context

ProvideKeyedScopedValueToContainer injects a concrete value into the given context. This value will be available only to the given container. And the container can only resolve this value if it has the matching (type and key's) Placeholder registered. Checkout the RegisterPlaceholderToContainer function for more info.

func ProvideScopedValue ΒΆ

func ProvideScopedValue[T any](ctx context.Context, value T) context.Context

ProvideScopedValue injects a concrete value into the given context. This value will be available only to the default container. And the container can only resolve this value if it has the matching (type and key's) Placeholder registered. Checkout the RegisterPlaceholder function for more info.

func ProvideScopedValueToContainer ΒΆ

func ProvideScopedValueToContainer[T any](con *Container, ctx context.Context, value T) context.Context

ProvideScopedValueToContainer injects a concrete value into the given context. This value will be available only to the given container. And the container can only resolve this value if it has the matching (type and key's) Placeholder registered. Checkout the RegisterPlaceholderToContainer function for more info.

func RegisterAlias ΒΆ

func RegisterAlias[TInterface, TImpl any]()

RegisterAlias Registers an interface type to a concrete implementation. Allowing you to register the concrete implementation to the default container and later get the interface from it.

func RegisterAliasToContainer ΒΆ

func RegisterAliasToContainer[TInterface, TImpl any](con *Container)

RegisterAliasToContainer Registers an interface type to a concrete implementation in the given container. Allowing you to register the concrete implementation to the container and later get the interface from it.

func RegisterCreator ΒΆ

func RegisterCreator[T any](lifetime Lifetime, creator Creator[T])

RegisterCreator Registers a lazily initialized value using a `Creator[T]` interface

func RegisterCreatorToContainer ΒΆ

func RegisterCreatorToContainer[T any](con *Container, lifetime Lifetime, creator Creator[T])

RegisterCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface

func RegisterFunc ΒΆ

func RegisterFunc[T any](lifetime Lifetime, initializer Initializer[T])

RegisterFunc Registers a lazily initialized value using an `Initializer[T]` function signature

func RegisterFuncToContainer ΒΆ

func RegisterFuncToContainer[T any](con *Container, lifetime Lifetime, initializer Initializer[T])

RegisterFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature

func RegisterKeyedCreator ΒΆ

func RegisterKeyedCreator[T any, K comparable](lifetime Lifetime, creator Creator[T], key K)

RegisterKeyedCreator Registers a lazily initialized value using a `Creator[T]` interface

func RegisterKeyedCreatorToContainer ΒΆ

func RegisterKeyedCreatorToContainer[T any, K comparable](con *Container, lifetime Lifetime, creator Creator[T], key K)

RegisterKeyedCreatorToContainer Registers a lazily initialized value to the given container using a `Creator[T]` interface

func RegisterKeyedFunc ΒΆ

func RegisterKeyedFunc[T any, K comparable](lifetime Lifetime, initializer Initializer[T], key K)

RegisterKeyedFunc Registers a lazily initialized value using an `Initializer[T]` function signature

func RegisterKeyedFuncToContainer ΒΆ

func RegisterKeyedFuncToContainer[T any, K comparable](con *Container, lifetime Lifetime, initializer Initializer[T], key K)

RegisterKeyedFuncToContainer Registers a lazily initialized value to the given container using an `Initializer[T]` function signature

func RegisterKeyedPlaceholder ΒΆ

func RegisterKeyedPlaceholder[T any, K comparable](key K)

RegisterKeyedPlaceholder registers a future value with Scoped lifetime. This value will be injected in runtime using the ProvideScopedValue function. Resolving objects which depend on this value will panic if the value has not been provided. Placeholder with the same type and key can be registered only once.

func RegisterKeyedPlaceholderToContainer ΒΆ

func RegisterKeyedPlaceholderToContainer[T any, K comparable](con *Container, key K)

RegisterKeyedPlaceholderToContainer registers a future value with Scoped lifetime to the given container. This value will be injected in runtime using the ProvideScopedValue function. Resolving objects which depend on this value will panic if the value has not been provided. Placeholder with the same type and key can be registered only once.

func RegisterKeyedSingleton ΒΆ

func RegisterKeyedSingleton[T any, K comparable](impl T, key K)

RegisterKeyedSingleton Registers an eagerly instantiated singleton value To register an eagerly instantiated scoped value use ProvideScopedValue

func RegisterKeyedSingletonToContainer ΒΆ

func RegisterKeyedSingletonToContainer[T any, K comparable](con *Container, impl T, key K)

RegisterKeyedSingletonToContainer Registers an eagerly instantiated singleton value to the given container. To register an eagerly instantiated scoped value use ProvideScopedValueToContainer

func RegisterPlaceholder ΒΆ

func RegisterPlaceholder[T any]()

RegisterPlaceholder registers a future value with Scoped lifetime. This value will be injected in runtime using the ProvideScopedValue function. Resolving objects which depend on this value will panic if the value has not been provided. Placeholder with the same type and key can be registered only once.

func RegisterPlaceholderToContainer ΒΆ

func RegisterPlaceholderToContainer[T any](con *Container)

RegisterPlaceholderToContainer registers a future value with Scoped lifetime to the given container. This value will be injected in runtime using the ProvideScopedValue function. Resolving objects which depend on this value will panic if the value has not been provided. Placeholder with the same type and key can be registered only once.

func RegisterSingleton ΒΆ

func RegisterSingleton[T any](impl T)

RegisterSingleton Registers an eagerly instantiated singleton value To register an eagerly instantiated scoped value use ProvideScopedValue

func RegisterSingletonToContainer ΒΆ

func RegisterSingletonToContainer[T any](con *Container, impl T)

RegisterSingletonToContainer Registers an eagerly instantiated singleton value to the given container. To register an eagerly instantiated scoped value use ProvideScopedValueToContainer

func Seal ΒΆ

func Seal()

Seal puts the DEFAULT container into read-only mode, preventing any further registrations.

func Validate ΒΆ

func Validate()

Validate invokes all registered resolvers. It panics if any of them fails. It is recommended to call this function on application start, or in the CI/CD test pipeline The objective is to panic early when the container is bad configured. For eg:

  • (1) Missing dependency (forget to register certain resolvers)
  • (2) cyclic dependency
  • (3) lifetime misalignment (a longer lifetime service depends on a shorter one).

Types ΒΆ

type Container ΒΆ

type Container struct {
	//DisableValidation is false by default, Set to true to skip validation.
	// Use case: you called the [Validate] function (either in the test pipeline or on application startup).
	// So you are confident that your registrations are good:
	//
	//   - no missing dependencies
	//   - no circular dependencies
	//   - no lifetime misalignment (a longer lifetime service depends on a shorter one).
	//
	// You don't need Ore to validate over and over again each time it creates a new concrete.
	// It's a waste of resource especially when you will need Ore to create a million of transient concretes
	// and any "pico" seconds or memory allocation matter for you.
	//
	// In this case, you can set DisableValidation = true.
	//
	// This config would impact also the [GetResolvedSingletons] and the [GetResolvedScopedInstances] functions,
	// the returning order would be no longer guaranteed.
	DisableValidation bool
	// contains filtered or unexported fields
}

func NewContainer ΒΆ

func NewContainer() *Container

func (*Container) ContainerID ΒΆ

func (c *Container) ContainerID() int32

func (*Container) IsSealed ΒΆ

func (this *Container) IsSealed() bool

IsSealed checks whether the container is sealed (in readonly mode)

func (*Container) Name ΒΆ

func (c *Container) Name() string

func (*Container) Seal ΒΆ

func (this *Container) Seal()

Seal puts the container into read-only mode, preventing any further registrations.

func (*Container) SetName ΒΆ

func (this *Container) SetName(name string) *Container

func (*Container) Validate ΒΆ

func (this *Container) Validate()

Validate invokes all registered resolvers. It panics if any of them fails. It is recommended to call this function on application start, or in the CI/CD test pipeline The objective is to panic early when the container is bad configured. For eg:

  • (1) Missing dependency (forget to register certain resolvers)
  • (2) cyclic dependency
  • (3) lifetime misalignment (a longer lifetime service depends on a shorter one).

type Creator ΒΆ

type Creator[T any] interface {
	New(ctx context.Context) (T, context.Context)
}

type Initializer ΒΆ

type Initializer[T any] func(ctx context.Context) (T, context.Context)

type Lifetime ΒΆ

type Lifetime int
const (
	Transient Lifetime = 0
	Scoped    Lifetime = 1
	Singleton Lifetime = 2
)

The bigger the value, the longer the lifetime

func (Lifetime) String ΒΆ

func (this Lifetime) String() string

Directories ΒΆ

Path Synopsis
internal
testtools/assert2
assert2 package add missing assertions from testify/assert package
assert2 package add missing assertions from testify/assert package

Jump to

Keyboard shortcuts

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