Skip to content

Commit 2b8d026

Browse files
authored
Merge pull request #438 from proto-kit/feature/dependency-factory-all-static
Made all dependencyfactories static
2 parents 8c2ce0a + 112c9e7 commit 2b8d026

19 files changed

Lines changed: 207 additions & 142 deletions

File tree

packages/common/src/config/ModuleContainer.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import "reflect-metadata";
22

33
import {
4+
ClassProvider,
45
DependencyContainer,
56
Frequency,
67
InjectionToken,
@@ -18,6 +19,7 @@ import { MergeObjects, StringKeyOf, TypedClass } from "../types";
1819
import {
1920
DependencyFactory,
2021
InferDependencies,
22+
isGeneratedProvider,
2123
} from "../dependencyFactory/DependencyFactory";
2224
import { EventEmitterProxy } from "../events/EventEmitterProxy";
2325

@@ -116,11 +118,9 @@ export type FilterNeverValues<Type extends Record<string, unknown>> = {
116118

117119
export type DependenciesFromModules<Modules extends ModulesRecord> =
118120
FilterNeverValues<{
119-
[Key in keyof Modules]: Modules[Key] extends TypedClass<DependencyFactory>
120-
? InferDependencies<InstanceType<Modules[Key]>>
121-
: Modules[Key] extends DependencyFactory
122-
? InferDependencies<Modules[Key]>
123-
: never;
121+
[Key in keyof Modules]: Modules[Key] extends DependencyFactory<any>
122+
? InferDependencies<Modules[Key]>
123+
: never;
124124
}>;
125125

126126
export type ResolvableModules<Modules extends ModulesRecord> = MergeObjects<
@@ -265,7 +265,7 @@ export class ModuleContainer<Modules extends ModulesRecord>
265265
this.registerAliases(moduleName, useClass);
266266

267267
if (this.isDependencyFactory(useClass)) {
268-
this.useDependencyFactory(useClass);
268+
this.useDependencyFactory(useClass, moduleName);
269269
}
270270
}
271271
});
@@ -379,7 +379,9 @@ export class ModuleContainer<Modules extends ModulesRecord>
379379
}
380380
}
381381

382-
private isDependencyFactory(type: any): type is DependencyFactory {
382+
private isDependencyFactory<T, Class extends ClassProvider<T>["useClass"]>(
383+
type: Class
384+
): type is DependencyFactory<T> & Class {
383385
return "dependencies" in type;
384386
}
385387

@@ -399,9 +401,13 @@ export class ModuleContainer<Modules extends ModulesRecord>
399401
* This will be automatically called for every module, but can also be called
400402
* explicitly to initialize an extra factory
401403
* @param factory
404+
* @param token
402405
* @private
403406
*/
404-
protected useDependencyFactory(factory: DependencyFactory) {
407+
protected useDependencyFactory<T>(
408+
factory: DependencyFactory<T>,
409+
token?: string
410+
) {
405411
const dependencies = factory.dependencies();
406412

407413
// eslint-disable-next-line sonarjs/cognitive-complexity
@@ -422,7 +428,20 @@ export class ModuleContainer<Modules extends ModulesRecord>
422428
}
423429

424430
// Find correct provider type and call respective register
425-
if (isValueProvider(declaration)) {
431+
if (isGeneratedProvider(declaration)) {
432+
if (token === undefined) {
433+
throw new Error(
434+
"Cannot use generated provider without injection token"
435+
);
436+
}
437+
// Here we first resolve the instance and then give it to the generator
438+
this.container.register(key, {
439+
useFactory: instanceCachingFactory((container) => {
440+
const instance = container.resolve<T>(token);
441+
return declaration.useGenerated(instance, this.container);
442+
}),
443+
});
444+
} else if (isValueProvider(declaration)) {
426445
this.container.register(key, declaration);
427446
} else if (isFactoryProvider(declaration)) {
428447
// this enables us to have a singletoned factory
@@ -442,7 +461,7 @@ export class ModuleContainer<Modules extends ModulesRecord>
442461

443462
// Register static dependencies
444463
if (this.isDependencyFactory(declaration.useClass)) {
445-
this.useDependencyFactory(declaration.useClass);
464+
this.useDependencyFactory(declaration.useClass, key);
446465
}
447466
} else if (isTokenProvider(declaration)) {
448467
this.container.register(key, declaration, {
@@ -476,10 +495,6 @@ export class ModuleContainer<Modules extends ModulesRecord>
476495
container.reset();
477496
return container;
478497
});
479-
480-
if (this.isDependencyFactory(containedModule)) {
481-
this.useDependencyFactory(containedModule);
482-
}
483498
},
484499
{ frequency: ModuleContainer.moduleDecorationFrequency }
485500
);
@@ -496,10 +511,10 @@ export class ModuleContainer<Modules extends ModulesRecord>
496511
this.registerValue({
497512
ChildContainerProvider: () => this.container.createChildContainer(),
498513
});
514+
this.container.register("ParentContainer", { useValue: this });
499515

500516
// register all provided modules when the container is created
501517
this.registerModules(this.definition);
502-
this.container.register("ParentContainer", { useValue: this });
503518
}
504519

505520
public get dependencyContainer(): DependencyContainer {
Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
ClassProvider,
3+
DependencyContainer,
34
FactoryProvider,
45
TokenProvider,
56
ValueProvider,
@@ -8,15 +9,26 @@ import {
89
import { TypedClass } from "../types";
910
import { noop } from "../utils";
1011

11-
export type DependencyDeclaration<Dependency> =
12+
export type GeneratedProvider<Dependency, Module> = {
13+
useGenerated: (module: Module, container: DependencyContainer) => Dependency;
14+
};
15+
16+
export type DependencyDeclaration<Dependency, This = unknown> =
1217
| ClassProvider<Dependency>
1318
| FactoryProvider<Dependency>
1419
| TokenProvider<Dependency>
15-
| ValueProvider<Dependency>;
20+
| ValueProvider<Dependency>
21+
| GeneratedProvider<Dependency, This>;
1622

17-
export type DependencyRecord = Record<
23+
export function isGeneratedProvider<Dependency, Module>(
24+
input: DependencyDeclaration<Dependency, Module>
25+
): input is GeneratedProvider<Dependency, Module> {
26+
return "useGenerated" in input;
27+
}
28+
29+
export type DependencyRecord<This = unknown> = Record<
1830
string,
19-
DependencyDeclaration<unknown> & { forceOverwrite?: boolean }
31+
DependencyDeclaration<unknown, This> & { forceOverwrite?: boolean }
2032
>;
2133

2234
/**
@@ -31,37 +43,39 @@ export type DependencyRecord = Record<
3143
* DependencyFactories are designed to only be used statically for sets of
3244
* deps that are necessary for the sequencer to work.
3345
*/
34-
export interface DependencyFactory {
35-
dependencies: () => DependencyRecord;
46+
export interface DependencyFactory<Type> {
47+
dependencies: () => DependencyRecord<Type>;
3648
}
3749

38-
export function dependencyFactory<T>() {
50+
export function dependencyFactory<T extends TypedClass<unknown>>() {
3951
return (
4052
/**
41-
* Check if the target class itself satisfies DependencyFactory
53+
* Check if the target class extends RuntimeModule, while
54+
* also providing static config presets
4255
*/
43-
target: TypedClass<T> & DependencyFactory
56+
target: T & DependencyFactory<InstanceType<T>>
4457
) => {
4558
noop();
4659
};
4760
}
4861

4962
export type TypeFromDependencyDeclaration<
50-
Declaration extends DependencyDeclaration<unknown>,
63+
Declaration extends DependencyDeclaration<any>,
5164
> =
52-
Declaration extends DependencyDeclaration<infer Dependency>
65+
Declaration extends DependencyDeclaration<infer Dependency, any>
5366
? Dependency
5467
: never;
5568

5669
export type CapitalizeAny<Key extends string | number | symbol> =
5770
Key extends string ? Capitalize<Key> : Key;
5871

59-
export type MapDependencyRecordToTypes<Record extends DependencyRecord> = {
72+
export type MapDependencyRecordToTypes<Record extends DependencyRecord<any>> = {
6073
[Key in keyof Record as CapitalizeAny<Key>]: TypedClass<
6174
TypeFromDependencyDeclaration<Record[Key]>
6275
>;
6376
};
6477

65-
export type InferDependencies<Class> = Class extends DependencyFactory
66-
? MapDependencyRecordToTypes<ReturnType<Class["dependencies"]>>
67-
: never;
78+
export type InferDependencies<Class extends TypedClass<any>> =
79+
Class extends DependencyFactory<any>
80+
? MapDependencyRecordToTypes<ReturnType<Class["dependencies"]>>
81+
: never;

packages/common/test/config/ModuleContainer.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class TestModule extends BaseTestModule<TestModuleConfig> {
4444
dependencyModule1: {
4545
useClass: ChildModule,
4646
},
47+
dependencyModule2: {
48+
useGenerated: (module: TestModule) => "test",
49+
},
4750
};
4851
}
4952
}
@@ -108,6 +111,9 @@ describe("moduleContainer", () => {
108111

109112
expect(dm.x()).toBe("dependency factory works");
110113
expect(dm.testModule).toBeDefined();
114+
115+
const dm2 = container.resolve("DependencyModule2");
116+
expect(dm2).toBe("test");
111117
});
112118

113119
it("should throw on resolution, if config was not provided", () => {

packages/module/src/factories/MethodIdFactory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { dependencyFactory, DependencyRecord } from "@proto-kit/common";
1+
import { dependencyFactory } from "@proto-kit/common";
22

33
import { MethodIdResolver } from "../runtime/MethodIdResolver";
44

@@ -9,6 +9,6 @@ export class MethodIdFactory {
99
methodIdResolver: {
1010
useClass: MethodIdResolver,
1111
},
12-
} satisfies DependencyRecord;
12+
};
1313
}
1414
}

packages/persistance/src/PrismaDatabaseConnection.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
StorageDependencyMinimumDependencies,
66
Tracer,
77
} from "@proto-kit/sequencer";
8-
import { DependencyFactory, OmitKeys } from "@proto-kit/common";
8+
import { OmitKeys } from "@proto-kit/common";
99

1010
import { PrismaStateService } from "./services/prisma/PrismaStateService";
1111
import { PrismaBatchStore } from "./services/prisma/PrismaBatchStore";
@@ -38,7 +38,7 @@ export interface PrismaConnection {
3838
@sequencerModule()
3939
export class PrismaDatabaseConnection
4040
extends SequencerModule<PrismaDatabaseConfig>
41-
implements DependencyFactory, PrismaConnection
41+
implements PrismaConnection
4242
{
4343
public constructor(private readonly tracer: Tracer) {
4444
super();
@@ -53,13 +53,20 @@ export class PrismaDatabaseConnection
5353
return this.initializedClient;
5454
}
5555

56-
public dependencies(): OmitKeys<
57-
StorageDependencyMinimumDependencies,
56+
public static dependencies(): OmitKeys<
57+
StorageDependencyMinimumDependencies<{
58+
readonly prisma: PrismaDatabaseConnection;
59+
}>,
5860
"blockTreeStore" | "asyncLinkedLeafStore" | "unprovenLinkedLeafStore"
5961
> {
6062
return {
6163
asyncStateService: {
62-
useFactory: () => new PrismaStateService(this, this.tracer, "batch"),
64+
useGenerated: (service) =>
65+
new PrismaStateService(
66+
service.prisma,
67+
service.prisma.tracer,
68+
"batch"
69+
),
6370
},
6471
batchStorage: {
6572
useClass: PrismaBatchStore,
@@ -71,7 +78,12 @@ export class PrismaDatabaseConnection
7178
useClass: PrismaBlockStorage,
7279
},
7380
unprovenStateService: {
74-
useFactory: () => new PrismaStateService(this, this.tracer, "block"),
81+
useGenerated: (service) =>
82+
new PrismaStateService(
83+
service.prisma,
84+
service.prisma.tracer,
85+
"block"
86+
),
7587
},
7688
settlementStorage: {
7789
useClass: PrismaSettlementStorage,

packages/persistance/src/PrismaRedisDatabase.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
closeable,
77
Tracer,
88
} from "@proto-kit/sequencer";
9-
import { ChildContainerProvider } from "@proto-kit/common";
9+
import { ChildContainerProvider, dependencyFactory } from "@proto-kit/common";
1010
import { PrismaClient } from "@prisma/client";
1111
import { RedisClientType } from "redis";
1212
import { inject } from "tsyringe";
@@ -31,6 +31,7 @@ export interface PrismaRedisCombinedConfig {
3131

3232
@sequencerModule()
3333
@closeable()
34+
@dependencyFactory()
3435
export class PrismaRedisDatabase
3536
extends SequencerModule<PrismaRedisCombinedConfig>
3637
implements PrismaConnection, RedisConnection, Database
@@ -63,28 +64,28 @@ export class PrismaRedisDatabase
6364
this.redis.create(childContainerProvider);
6465
}
6566

66-
public dependencies(): StorageDependencyMinimumDependencies {
67+
public static dependencies(): StorageDependencyMinimumDependencies<PrismaRedisDatabase> {
6768
return {
68-
...this.prisma.dependencies(),
69-
...this.redis.dependencies(),
69+
...PrismaDatabaseConnection.dependencies(),
70+
...RedisConnectionModule.dependencies(),
7071

7172
asyncLinkedLeafStore: {
72-
useFactory: () => {
73+
useGenerated: (module) => {
7374
return new PrismaLinkedLeafStore(
74-
this.prisma,
75-
this.redis,
76-
this.tracer,
75+
module.prisma,
76+
module.redis,
77+
module.tracer,
7778
"batch"
7879
);
7980
},
8081
},
8182

8283
unprovenLinkedLeafStore: {
83-
useFactory: () => {
84+
useGenerated: (module) => {
8485
return new PrismaLinkedLeafStore(
85-
this.prisma,
86-
this.redis,
87-
this.tracer,
86+
module.prisma,
87+
module.redis,
88+
module.tracer,
8889
"block"
8990
);
9091
},

0 commit comments

Comments
 (0)