Skip to content

Commit

Permalink
feat(core): update services with clone
Browse files Browse the repository at this point in the history
Update ActivationService to implement Cloneable.
Update BindingService to implement Cloneable.
Update DeactivationService to implement Cloneable.
  • Loading branch information
notaphplover committed Jan 9, 2025
1 parent 53a8ccd commit 7cbcacd
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,15 @@ describe(Container.name, () => {
jest.Mocked<DeactivationsService>
> as jest.Mocked<DeactivationsService>;

(ActivationsService as jest.Mock<() => ActivationsService>).mockReturnValue(
activationServiceMock,
);
(BindingService as jest.Mock<() => BindingService>).mockReturnValue(
(
ActivationsService.build as jest.Mock<() => ActivationsService>
).mockReturnValue(activationServiceMock);

(BindingService.build as jest.Mock<() => BindingService>).mockReturnValue(
bindingServiceMock,
);
(
DeactivationsService as jest.Mock<() => DeactivationsService>
DeactivationsService.build as jest.Mock<() => DeactivationsService>
).mockReturnValue(deactivationServiceMock);
});

Expand All @@ -99,25 +100,34 @@ describe(Container.name, () => {
jest.clearAllMocks();
});

it('should call new ActivationsService', () => {
expect(ActivationsService).toHaveBeenCalledTimes(2);
expect(ActivationsService).toHaveBeenNthCalledWith(1, undefined);
expect(ActivationsService).toHaveBeenNthCalledWith(
it('should call new ActivationsService.build()', () => {
expect(ActivationsService.build).toHaveBeenCalledTimes(2);
expect(ActivationsService.build).toHaveBeenNthCalledWith(
1,
undefined,
);
expect(ActivationsService.build).toHaveBeenNthCalledWith(
2,
activationServiceMock,
);
});

it('should call new BindingService', () => {
expect(BindingService).toHaveBeenCalledTimes(2);
expect(BindingService).toHaveBeenNthCalledWith(1, undefined);
expect(BindingService).toHaveBeenNthCalledWith(2, bindingServiceMock);
it('should call BindingService.build', () => {
expect(BindingService.build).toHaveBeenCalledTimes(2);
expect(BindingService.build).toHaveBeenNthCalledWith(1, undefined);
expect(BindingService.build).toHaveBeenNthCalledWith(
2,
bindingServiceMock,
);
});

it('should call new DeactivationsService', () => {
expect(DeactivationsService).toHaveBeenCalledTimes(2);
expect(DeactivationsService).toHaveBeenNthCalledWith(1, undefined);
expect(DeactivationsService).toHaveBeenNthCalledWith(
it('should call DeactivationsService.build()', () => {
expect(DeactivationsService.build).toHaveBeenCalledTimes(2);
expect(DeactivationsService.build).toHaveBeenNthCalledWith(
1,
undefined,
);
expect(DeactivationsService.build).toHaveBeenNthCalledWith(
2,
deactivationServiceMock,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,19 @@ export class Container {

constructor(options?: ContainerOptions) {
if (options?.parent !== undefined) {
this.#activationService = new ActivationsService(
this.#activationService = ActivationsService.build(
options.parent.#activationService,
);
this.#bindingService = new BindingService(options.parent.#bindingService);
this.#deactivationService = new DeactivationsService(
this.#bindingService = BindingService.build(
options.parent.#bindingService,
);
this.#deactivationService = DeactivationsService.build(
options.parent.#deactivationService,
);
} else {
this.#activationService = new ActivationsService(undefined);
this.#bindingService = new BindingService(undefined);
this.#deactivationService = new DeactivationsService(undefined);
this.#activationService = ActivationsService.build(undefined);
this.#bindingService = BindingService.build(undefined);
this.#deactivationService = DeactivationsService.build(undefined);
}

this.#options = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ describe(ActivationsService.name, () => {
OneToManyMapStar<BindingActivation, BindingActivationRelation>
>;

parentActivationService = new ActivationsService(undefined);
parentActivationService = ActivationsService.build(undefined);

activationsService = new ActivationsService(parentActivationService);
activationsService = ActivationsService.build(parentActivationService);
});

describe('.add', () => {
Expand Down Expand Up @@ -79,6 +79,31 @@ describe(ActivationsService.name, () => {
});
});

describe('.clone', () => {
describe('when called', () => {
let result: unknown;

beforeAll(() => {
activationMapsMock.clone.mockReturnValueOnce(activationMapsMock);

result = activationsService.clone();
});

afterAll(() => {
jest.clearAllMocks();
});

it('should call activationMaps.clone', () => {
expect(activationMapsMock.clone).toHaveBeenCalledTimes(1);
expect(activationMapsMock.clone).toHaveBeenCalledWith();
});

it('should return a clone()', () => {
expect(result).toStrictEqual(activationsService);
});
});
});

describe('.get', () => {
let serviceIdFixture: ServiceIdentifier;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ServiceIdentifier } from '@inversifyjs/common';

import { chain } from '../../common/calculations/chain';
import { Cloneable } from '../../common/models/Cloneable';
import { OneToManyMapStar } from '../../common/models/OneToManyMapStar';
import { BindingActivation } from '../models/BindingActivation';

Expand All @@ -14,37 +15,57 @@ export interface BindingActivationRelation {
[ActivationRelationKind.serviceId]: ServiceIdentifier;
}

export class ActivationsService {
export class ActivationsService implements Cloneable<ActivationsService> {
readonly #activationMaps: OneToManyMapStar<
BindingActivation,
BindingActivationRelation
>;

readonly #parent: ActivationsService | undefined;

constructor(parent: ActivationsService | undefined) {
this.#activationMaps = new OneToManyMapStar<
private constructor(
parent: ActivationsService | undefined,
activationMaps?: OneToManyMapStar<
BindingActivation,
BindingActivationRelation
>({
moduleId: {
isOptional: true,
},
serviceId: {
isOptional: false,
},
});
>,
) {
this.#activationMaps =
activationMaps ??
new OneToManyMapStar<BindingActivation, BindingActivationRelation>({
moduleId: {
isOptional: true,
},
serviceId: {
isOptional: false,
},
});

this.#parent = parent;
}

public static build(
parent: ActivationsService | undefined,
): ActivationsService {
return new ActivationsService(parent);
}

public add(
activation: BindingActivation,
relation: BindingActivationRelation,
): void {
this.#activationMaps.set(activation, relation);
}

public clone(): ActivationsService {
const clone: ActivationsService = new ActivationsService(
this.#parent,
this.#activationMaps.clone(),
);

return clone;
}

public get(
serviceIdentifier: ServiceIdentifier,
): Iterable<BindingActivation> | undefined {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,34 @@ describe(BindingService.name, () => {
},
}) as jest.Mocked<OneToManyMapStar<Binding<unknown>, BindingRelation>>;

parentBindingService = new BindingService(undefined);
parentBindingService = BindingService.build(undefined);

bindingService = new BindingService(parentBindingService);
bindingService = BindingService.build(parentBindingService);
});

describe('.clone', () => {
describe('when called', () => {
let result: unknown;

beforeAll(() => {
bindingMapsMock.clone.mockReturnValueOnce(bindingMapsMock);

result = bindingService.clone();
});

afterAll(() => {
jest.clearAllMocks();
});

it('should call activationMaps.clone()', () => {
expect(bindingMapsMock.clone).toHaveBeenCalledTimes(1);
expect(bindingMapsMock.clone).toHaveBeenCalledWith();
});

it('should return a clone()', () => {
expect(result).toStrictEqual(bindingService);
});
});
});

describe('.get', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ServiceIdentifier } from '@inversifyjs/common';

import { Cloneable } from '../../common/models/Cloneable';
import { OneToManyMapStar } from '../../common/models/OneToManyMapStar';
import { Binding } from '../models/Binding';

Expand All @@ -13,26 +14,41 @@ export interface BindingRelation {
[BindingRelationKind.serviceId]: ServiceIdentifier;
}

export class BindingService {
export class BindingService implements Cloneable<BindingService> {
readonly #bindingMaps: OneToManyMapStar<Binding<unknown>, BindingRelation>;

readonly #parent: BindingService | undefined;

constructor(parent: BindingService | undefined) {
this.#bindingMaps = new OneToManyMapStar<Binding<unknown>, BindingRelation>(
{
private constructor(
parent: BindingService | undefined,
bindingMaps?: OneToManyMapStar<Binding<unknown>, BindingRelation>,
) {
this.#bindingMaps =
bindingMaps ??
new OneToManyMapStar<Binding<unknown>, BindingRelation>({
moduleId: {
isOptional: true,
},
serviceId: {
isOptional: false,
},
},
);
});

this.#parent = parent;
}

public static build(parent: BindingService | undefined): BindingService {
return new BindingService(parent);
}

public clone(): BindingService {
const clone: BindingService = new BindingService(
this.#parent,
this.#bindingMaps.clone(),
);

return clone;
}

public get<TResolved>(
serviceIdentifier: ServiceIdentifier,
): Iterable<Binding<TResolved>> | undefined {
Expand Down
Loading

0 comments on commit 7cbcacd

Please sign in to comment.