getters.go
package ore
import (
"context"
"sort"
)
func getLastRegisteredResolver(typeId typeID) (serviceResolver, int) {
// try to get service resolver from container
lock.RLock()
resolvers, resolverExists := container[typeId]
lock.RUnlock()
if !resolverExists {
return nil, -1
}
count := len(resolvers)
if count == 0 {
return nil, -1
}
// index of the last implementation
lastIndex := count - 1
return resolvers[lastIndex], lastIndex
}
// Get Retrieves an instance based on type and key (panics if no valid implementations)
func Get[T any](ctx context.Context, key ...KeyStringer) (T, context.Context) {
pointerTypeName := getPointerTypeName[T]()
typeID := getTypeID(pointerTypeName, key)
lastRegisteredResolver, lastIndex := getLastRegisteredResolver(typeID)
if lastRegisteredResolver == nil { //not found, T is an alias
lock.RLock()
implementations, implExists := aliases[pointerTypeName]
lock.RUnlock()
if !implExists {
panic(noValidImplementation[T]())
}
count := len(implementations)
if count == 0 {
panic(noValidImplementation[T]())
}
for i := count - 1; i >= 0; i-- {
impl := implementations[i]
typeID = getTypeID(impl, key)
lastRegisteredResolver, lastIndex = getLastRegisteredResolver(typeID)
if lastRegisteredResolver != nil {
break
}
}
}
if lastRegisteredResolver == nil {
panic(noValidImplementation[T]())
}
con, ctx := lastRegisteredResolver.resolveService(ctx, typeID, lastIndex)
return con.value.(T), ctx
}
// GetList Retrieves a list of instances based on type and key
func GetList[T any](ctx context.Context, key ...KeyStringer) ([]T, context.Context) {
inputPointerTypeName := getPointerTypeName[T]()
lock.RLock()
pointerTypeNames, implExists := aliases[inputPointerTypeName]
lock.RUnlock()
if implExists {
pointerTypeNames = append(pointerTypeNames, inputPointerTypeName)
} else {
pointerTypeNames = []pointerTypeName{inputPointerTypeName}
}
servicesArray := []T{}
for i := 0; i < len(pointerTypeNames); i++ {
pointerTypeName := pointerTypeNames[i]
// generate type identifier
typeID := getTypeID(pointerTypeName, key)
// try to get service resolver from container
lock.RLock()
resolvers, resolverExists := container[typeID]
lock.RUnlock()
if !resolverExists {
continue
}
for index := 0; index < len(resolvers); index++ {
resolver := resolvers[index]
con, newCtx := resolver.resolveService(ctx, typeID, index)
servicesArray = append(servicesArray, con.value.(T))
ctx = newCtx
}
}
return servicesArray, ctx
}
// 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.
// 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 GetResolvedSingletons[TInterface any]() []TInterface {
lock.RLock()
defer lock.RUnlock()
list := []*concrete{}
//filtering
for _, resolvers := range container {
for _, resolver := range resolvers {
con, isInvokedSingleton := resolver.getInvokedSingleton()
if isInvokedSingleton {
if _, ok := con.value.(TInterface); ok {
list = append(list, con)
}
}
}
}
return sortAndSelect[TInterface](list)
}
// 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.
// 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 GetResolvedScopedInstances[TInterface any](ctx context.Context) []TInterface {
contextKeyRepository, ok := ctx.Value(contextKeysRepositoryID).(contextKeysRepository)
if !ok {
return []TInterface{}
}
list := []*concrete{}
//filtering
for _, contextKey := range contextKeyRepository {
con := ctx.Value(contextKey).(*concrete)
if _, ok := con.value.(TInterface); ok {
list = append(list, con)
}
}
return sortAndSelect[TInterface](list)
}
// sortAndSelect sorts concretes by invocation order and return its value.
func sortAndSelect[TInterface any](list []*concrete) []TInterface {
//sorting
sort.Slice(list, func(i, j int) bool {
return list[i].createdAt.After(list[j].createdAt)
})
//selecting
result := make([]TInterface, len(list))
for i := 0; i < len(list); i++ {
result[i] = list[i].value.(TInterface)
}
return result
}