Skip to content

Commit 50afc6b

Browse files
authored
removed Lazy keyword, separated Keyed methods (#15)
2 parents 9336c47 + d82a8d1 commit 50afc6b

34 files changed

+904
-761
lines changed

README.md

Lines changed: 70 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ the management of object lifetimes and the inversion of control in your applicat
4545

4646
- **Concurrency-Safe**: Utilizes a mutex to ensure safe concurrent access to the container.
4747

48+
49+
- **Placeholder Service Registration**: Designed to simplify scenarios where certain dependencies cannot be resolved at the time of service registration but can be resolved later during runtime.
50+
51+
52+
- **Isolated Containers**: Enables the creation of multiple isolated, modular containers to support more scalable and testable architectures, especially for Modular Monoliths.
53+
54+
55+
- **Aliases**: A powerful way to register type mappings, allowing one type to be treated as another, typically an interface or a more abstract type.
56+
57+
58+
- **Runtime Validation**: Allow for better error handling and validation during the startup or testing phases of an application (circular dependencies, lifetime misalignment, and missing dependencies).
59+
60+
61+
- **Graceful Termination**: To ensure graceful application (or context) termination and proper cleanup of resources, including shutting down all resolved objects created during the application (or context) lifetime.
4862
<br />
4963

5064
## Installation
@@ -99,7 +113,7 @@ var c Counter
99113
c = &models.SimpleCounter{}
100114

101115
// register
102-
ore.RegisterEagerSingleton[Counter](c)
116+
ore.RegisterSingleton[Counter](c)
103117

104118
ctx := context.Background()
105119

@@ -115,11 +129,11 @@ c.AddOne()
115129

116130
```go
117131
// register
118-
ore.RegisterLazyCreator[Counter](ore.Scoped, &models.SimpleCounter{})
132+
ore.RegisterCreator[Counter](ore.Scoped, &models.SimpleCounter{})
119133

120134
// OR
121-
//ore.RegisterLazyCreator[Counter](ore.Transient, &models.SimpleCounter{})
122-
//ore.RegisterLazyCreator[Counter](ore.Singleton, &models.SimpleCounter{})
135+
//ore.RegisterCreator[Counter](ore.Transient, &models.SimpleCounter{})
136+
//ore.RegisterCreator[Counter](ore.Singleton, &models.SimpleCounter{})
123137

124138
ctx := context.Background()
125139

@@ -142,29 +156,30 @@ fmt.Println("TOTAL: ", c.GetCount())
142156

143157
```go
144158
// register
145-
ore.RegisterLazyFunc[Counter](ore.Scoped, func(ctx context.Context) (Counter, context.Context) {
159+
ore.RegisterFunc[Counter](ore.Scoped, func(ctx context.Context) (Counter, context.Context) {
146160
return &models.SimpleCounter{}, ctx
147161
})
148162

149163
// OR
150-
//ore.RegisterLazyFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) {
164+
//ore.RegisterFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) {
151165
// return &models.SimpleCounter{}, ctx
152166
//})
153167

154168
// Keyed service registration
155-
//ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) {
169+
//ore.RegisterKeyedFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) {
156170
// return &models.SimpleCounter{}, ctx
157-
//}, "name here", 1234)
171+
//}, "key-here")
158172

159173
ctx := context.Background()
160174

161175
// retrieve
162176
c, ctx := ore.Get[Counter](ctx)
177+
163178
c.AddOne()
164179
c.AddOne()
165180

166181
// Keyed service retrieval
167-
//c, ctx := ore.Get[Counter](ctx, "name here", 1234)
182+
//c, ctx := ore.GetKeyed[Counter](ctx, "key-here")
168183

169184
// retrieve again
170185
c, ctx = ore.Get[Counter](ctx)
@@ -180,15 +195,15 @@ fmt.Println("TOTAL: ", c.GetCount())
180195

181196
```go
182197
// register
183-
ore.RegisterLazyCreator[Counter](ore.Scoped, &models.SimpleCounter{})
198+
ore.RegisterCreator[Counter](ore.Scoped, &models.SimpleCounter{})
184199

185-
ore.RegisterLazyCreator[Counter](ore.Scoped, &yetAnotherCounter{})
200+
ore.RegisterCreator[Counter](ore.Scoped, &yetAnotherCounter{})
186201

187-
ore.RegisterLazyFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) {
202+
ore.RegisterFunc[Counter](ore.Transient, func(ctx context.Context) (Counter, context.Context) {
188203
return &models.SimpleCounter{}, ctx
189204
})
190205

191-
ore.RegisterLazyCreator[Counter](ore.Singleton, &yetAnotherCounter{})
206+
ore.RegisterCreator[Counter](ore.Singleton, &yetAnotherCounter{})
192207

193208
ctx := context.Background()
194209

@@ -217,18 +232,18 @@ The last registered implementation takes precedence, so you can register a mock
217232

218233
```go
219234
// register
220-
ore.RegisterLazyFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) {
235+
ore.RegisterKeyedFunc[Counter](ore.Singleton, func(ctx context.Context) (Counter, context.Context) {
221236
return &models.SimpleCounter{}, ctx
222-
}, "name here", 1234)
237+
}, "key-here")
223238

224-
//ore.RegisterLazyCreator[Counter](ore.Scoped, &models.SimpleCounter{}, "name here", 1234)
239+
//ore.RegisterKeyedCreator[Counter](ore.Scoped, &models.SimpleCounter{}, "key-here")
225240

226-
//ore.RegisterEagerSingleton[Counter](&models.SimpleCounter{}, "name here", 1234)
241+
//ore.RegisterKeyedSingleton[Counter](&models.SimpleCounter{}, "key-here")
227242

228243
ctx := context.Background()
229244

230245
// Keyed service retrieval
231-
c, ctx := ore.Get[Counter](ctx, "name here", 1234)
246+
c, ctx := ore.GetKeyed[Counter](ctx, "key-here")
232247
c.AddOne()
233248

234249
// prints out: `TOTAL: 1`
@@ -249,13 +264,13 @@ type Trader struct {
249264
} //implements IPerson
250265

251266
func TestGetInterfaceAlias(t *testing.T) {
252-
ore.RegisterLazyFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) {
267+
ore.RegisterFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) {
253268
return &Broker{Name: "Peter"}, ctx
254269
})
255-
ore.RegisterLazyFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) {
270+
ore.RegisterFunc(ore.Scoped, func(ctx context.Context) (*Broker, context.Context) {
256271
return &Broker{Name: "John"}, ctx
257272
})
258-
ore.RegisterLazyFunc(ore.Scoped, func(ctx context.Context) (*Trader, context.Context) {
273+
ore.RegisterFunc(ore.Scoped, func(ctx context.Context) (*Trader, context.Context) {
259274
return &Trader{Name: "Mary"}, ctx
260275
})
261276

@@ -321,9 +336,9 @@ Here how Ore can help you:
321336
type Shutdowner interface {
322337
Shutdown()
323338
}
324-
ore.RegisterEagerSingleton(&Logger{}) //*Logger implements Shutdowner
325-
ore.RegisterEagerSingleton(&SomeRepository{}) //*SomeRepository implements Shutdowner
326-
ore.RegisterEagerSingleton(&SomeService{}, "some_module") //*SomeService implements Shutdowner
339+
ore.RegisterSingleton(&Logger{}) //*Logger implements Shutdowner
340+
ore.RegisterSingleton(&SomeRepository{}) //*SomeRepository implements Shutdowner
341+
ore.RegisterKeyedSingleton(&SomeService{}, "some_module") //*SomeService implements Shutdowner
327342

328343
//On application termination, Ore can help to retrieve all the singletons implementation
329344
//of the `Shutdowner` interface.
@@ -360,7 +375,7 @@ Here how Ore can help you:
360375
type Disposer interface {
361376
Dispose()
362377
}
363-
ore.RegisterLazyCreator(ore.Scoped, &SomeDisposableService{}) //*SomeDisposableService implements Disposer
378+
ore.RegisterCreator(ore.Scoped, &SomeDisposableService{}) //*SomeDisposableService implements Disposer
364379

365380
//a new request arrive
366381
ctx, cancel := context.WithCancel(context.Background())
@@ -392,24 +407,24 @@ The `ore.GetResolvedScopedInstances[TInterface](context)` function returns a lis
392407

393408
### Multiple Containers (a.k.a Modules)
394409

395-
| DefaultContainer | Custom container |
396-
|------------------|------------------|
397-
| Get | GetFromContainer |
398-
| GetList | GetListFromContainer |
410+
| DefaultContainer | Custom container |
411+
|-----------------------|------------------------------------|
412+
| Get | GetFromContainer |
413+
| GetList | GetListFromContainer |
399414
| GetResolvedSingletons | GetResolvedSingletonsFromContainer |
400-
| RegisterAlias | RegisterAliasToContainer |
401-
| RegisterEagerSingleton | RegisterEagerSingletonToContainer |
402-
| RegisterLazyCreator | RegisterLazyCreatorToContainer |
403-
| RegisterLazyFunc | RegisterLazyFuncToContainer |
404-
| RegisterPlaceHolder | RegisterPlaceHolderToContainer |
405-
| ProvideScopedValue | ProvideScopedValueToContainer |
415+
| RegisterAlias | RegisterAliasToContainer |
416+
| RegisterSingleton | RegisterSingletonToContainer |
417+
| RegisterCreator | RegisterCreatorToContainer |
418+
| RegisterFunc | RegisterFuncToContainer |
419+
| RegisterPlaceholder | RegisterPlaceholderToContainer |
420+
| ProvideScopedValue | ProvideScopedValueToContainer |
406421

407422
Most of time you only need the Default Container. In rare use case such as the Modular Monolith Architecture, you might want to use multiple containers, one per module. Ore provides minimum support for "module" in this case:
408423

409424
```go
410425
//broker module
411426
brokerContainer := ore.NewContainer()
412-
ore.RegisterLazyFuncToContainer(brokerContainer, ore.Singleton, func(ctx context.Context) (*Broker, context.Context) {
427+
ore.RegisterFuncToContainer(brokerContainer, ore.Singleton, func(ctx context.Context) (*Broker, context.Context) {
413428
brs, ctx = ore.GetFromContainer[*BrokerageSystem](brokerContainer, ctx)
414429
return &Broker{brs}, ctx
415430
})
@@ -420,7 +435,7 @@ broker, _ := ore.GetFromContainer[*Broker](brokerContainer, context.Background()
420435

421436
//trader module
422437
traderContainer := ore.NewContainer()
423-
ore.RegisterLazyFuncToContainer(traderContainer, ore.Singleton, func(ctx context.Context) (*Trader, context.Context) {
438+
ore.RegisterFuncToContainer(traderContainer, ore.Singleton, func(ctx context.Context) (*Trader, context.Context) {
424439
mkp, ctx = ore.GetFromContainer[*MarketPlace](traderContainer, ctx)
425440
return &Trader{mkp}, ctx
426441
})
@@ -438,14 +453,14 @@ A common scenario is that your "Service" depends on something which you couldn't
438453

439454
```go
440455
//register SomeService which depends on "someConfig"
441-
ore.RegisterLazyFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) {
442-
someConfig, ctx := ore.Get[string](ctx, "someConfig")
456+
ore.RegisterFunc[*SomeService](ore.Scoped, func(ctx context.Context) (*SomeService, context.Context) {
457+
someConfig, ctx := ore.GetKeyed[string](ctx, "someConfig")
443458
return &SomeService{someConfig}, ctx
444459
})
445460

446461
//someConfig is unknow at registration time because
447462
//this value depends on the future user's request
448-
ore.RegisterPlaceHolder[string]("someConfig")
463+
ore.RegisterKeyedPlaceholder[string]("someConfig")
449464

450465
//a new request arrive
451466
ctx := context.Background()
@@ -455,14 +470,14 @@ ctx = context.WithValue(ctx, "role", "admin")
455470
//inject a different somConfig value depending on the request's content
456471
userRole := ctx.Value("role").(string)
457472
if userRole == "admin" {
458-
ctx = ore.ProvideScopedValue(ctx, "Admin config", "someConfig")
473+
ctx = ore.ProvideKeyedScopedValue(ctx, "Admin config", "someConfig")
459474
} else if userRole == "supervisor" {
460-
ctx = ore.ProvideScopedValue(ctx, "Supervisor config", "someConfig")
475+
ctx = ore.ProvideKeyedScopedValue(ctx, "Supervisor config", "someConfig")
461476
} else if userRole == "user" {
462477
if (isAuthenticatedUser) {
463-
ctx = ore.ProvideScopedValue(ctx, "Public user config", "someConfig")
478+
ctx = ore.ProvideKeyedScopedValue(ctx, "Private user config", "someConfig")
464479
} else {
465-
ctx = ore.ProvideScopedValue(ctx, "Private user config", "someConfig")
480+
ctx = ore.ProvideKeyedScopedValue(ctx, "Public user config", "someConfig")
466481
}
467482
}
468483

@@ -473,14 +488,14 @@ fmt.Println(service.someConfig) //"Admin config"
473488

474489
([See full codes here](./examples/placeholderdemo/main.go))
475490

476-
- `ore.RegisterPlaceHolder[T](key...)` registers a future value with Scoped lifetime.
491+
- `ore.RegisterPlaceholder[T](key...)` registers a future value with Scoped lifetime.
477492
- This value will be injected in runtime using the `ProvideScopedValue` function.
478493
- Resolving objects which depend on this value will panic if the value has not been provided.
479494

480495
- `ore.ProvideScopedValue[T](context, value T, key...)` injects a concrete value into the given context
481496
- `ore` can access (`Get()` or `GetList()`) to this value only if the corresponding placeholder (which matches the type and keys) is registered.
482497

483-
- A value provided to a placeholder would never replace value returned by other resolvers. It's the opposite, if a type (and key) could be resolved by a real resolver (such as `RegisterLazyFunc`, `RegisterLazyCreator`...), then the later would take precedent.
498+
- A value provided to a placeholder would never replace value returned by other resolvers. It's the opposite, if a type (and key) could be resolved by a real resolver (such as `RegisterFunc`, `RegisterCreator`...), then the later would take precedent.
484499

485500
<br/>
486501

@@ -513,7 +528,7 @@ func (gc *genericCounter[T]) GetCount(ctx context.Context) T {
513528
```go
514529

515530
// register
516-
ore.RegisterLazyFunc[GenericCounter[int]](ore.Scoped, func(ctx context.Context) (GenericCounter[int], context.Context) {
531+
ore.RegisterFunc[GenericCounter[int]](ore.Scoped, func(ctx context.Context) (GenericCounter[int], context.Context) {
517532
return &genericCounter[int]{}, ctx
518533
})
519534

@@ -530,15 +545,15 @@ goos: windows
530545
goarch: amd64
531546
pkg: github.com/firasdarwish/ore
532547
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
533-
BenchmarkRegisterLazyFunc-20 5706694 196.9 ns/op
534-
BenchmarkRegisterLazyCreator-20 6283534 184.5 ns/op
535-
BenchmarkRegisterEagerSingleton-20 5146953 211.5 ns/op
536-
BenchmarkInitialGet-20 3440072 352.1 ns/op
537-
BenchmarkGet-20 9806043 121.8 ns/op
538-
BenchmarkInitialGetList-20 1601787 747.9 ns/op
539-
BenchmarkGetList-20 4237449 282.1 ns/op
548+
BenchmarkRegisterFunc-20 5612482 214.6 ns/op
549+
BenchmarkRegisterCreator-20 6498038 174.1 ns/op
550+
BenchmarkRegisterSingleton-20 5474991 259.1 ns/op
551+
BenchmarkInitialGet-20 2297595 514.3 ns/op
552+
BenchmarkGet-20 9389530 122.1 ns/op
553+
BenchmarkInitialGetList-20 1000000 1072 ns/op
554+
BenchmarkGetList-20 3970850 301.7 ns/op
540555
PASS
541-
ok github.com/firasdarwish/ore 11.427s
556+
ok github.com/firasdarwish/ore 10.883s
542557
```
543558

544559
Checkout also [examples/benchperf/README.md](examples/benchperf/README.md)

0 commit comments

Comments
 (0)