Skip to content

Commit

Permalink
Merge pull request #272 from inversify/feat/update-container-with-sna…
Browse files Browse the repository at this point in the history
…pshot

Update container with snapshot
  • Loading branch information
notaphplover authored Jan 10, 2025
2 parents 6808cd5 + a4c91d1 commit d1c0d8c
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,22 @@ describe(Container.name, () => {
beforeAll(() => {
activationServiceMock = {
add: jest.fn(),
clone: jest.fn(),
removeAllByModuleId: jest.fn(),
removeAllByServiceId: jest.fn(),
} as Partial<
jest.Mocked<ActivationsService>
> as jest.Mocked<ActivationsService>;
bindingServiceMock = {
clone: jest.fn(),
get: jest.fn(),
removeAllByModuleId: jest.fn(),
removeAllByServiceId: jest.fn(),
set: jest.fn(),
} as Partial<jest.Mocked<BindingService>> as jest.Mocked<BindingService>;
deactivationServiceMock = {
add: jest.fn(),
clone: jest.fn(),
removeAllByModuleId: jest.fn(),
removeAllByServiceId: jest.fn(),
} as Partial<
Expand Down Expand Up @@ -1009,6 +1012,73 @@ describe(Container.name, () => {
});
});

describe('.restore', () => {
describe('having a container with no snapshots', () => {
let container: Container;

beforeAll(() => {
container = new Container();
});

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

beforeAll(() => {
try {
container.restore();
} catch (error: unknown) {
result = error;
}
});

it('should throw an InversifyContainerError', () => {
const expectedErrorProperties: Partial<InversifyContainerError> = {
kind: InversifyContainerErrorKind.invalidOperation,
message: 'No snapshot available to restore',
};

expect(result).toBeInstanceOf(InversifyContainerError);
expect(result).toStrictEqual(
expect.objectContaining(expectedErrorProperties),
);
});
});
});
});

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

beforeAll(() => {
result = new Container().snapshot();
});

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

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

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

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

it('should return undefined', () => {
expect(result).toBeUndefined();
});
});
});

describe('.unbind', () => {
let serviceIdentifierFixture: ServiceIdentifier;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { BindToFluentSyntax } from '../../binding/models/BindingFluentSyntax';
import { BindToFluentSyntaxImplementation } from '../../binding/models/BindingFluentSyntaxImplementation';
import { InversifyContainerError } from '../../error/models/InversifyContainerError';
import { InversifyContainerErrorKind } from '../../error/models/InversifyContainerErrorKind';
import { Snapshot } from '../../snapshot/models/Snapshot';
import {
ContainerModule,
ContainerModuleLoadOptions,
Expand All @@ -47,10 +48,11 @@ interface InternalContainerOptions {
const DEFAULT_DEFAULT_SCOPE: BindingScope = bindingScopeValues.Transient;

export class Container {
readonly #activationService: ActivationsService;
readonly #bindingService: BindingService;
readonly #deactivationService: DeactivationsService;
#activationService: ActivationsService;
#bindingService: BindingService;
#deactivationService: DeactivationsService;
readonly #options: InternalContainerOptions;
readonly #snapshots: Snapshot[];

constructor(options?: ContainerOptions) {
if (options?.parent !== undefined) {
Expand All @@ -72,6 +74,7 @@ export class Container {
this.#options = {
defaultScope: options?.defaultScope ?? DEFAULT_DEFAULT_SCOPE,
};
this.#snapshots = [];
}

public bind<T>(
Expand Down Expand Up @@ -233,6 +236,29 @@ export class Container {
});
}

public restore(): void {
const snapshot: Snapshot | undefined = this.#snapshots.pop();

if (snapshot === undefined) {
throw new InversifyContainerError(
InversifyContainerErrorKind.invalidOperation,
'No snapshot available to restore',
);
}

this.#activationService = snapshot.activationService;
this.#bindingService = snapshot.bindingService;
this.#deactivationService = snapshot.deactivationService;
}

public snapshot(): void {
this.#snapshots.push({
activationService: this.#activationService.clone(),
bindingService: this.#bindingService.clone(),
deactivationService: this.#deactivationService.clone(),
});
}

public async unbind(serviceIdentifier: ServiceIdentifier): Promise<void> {
await resolveServiceDeactivations(
this.#buildDeactivationParams(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {
ActivationsService,
BindingService,
DeactivationsService,
} from '@inversifyjs/core';

export interface Snapshot {
activationService: ActivationsService;
bindingService: BindingService;
deactivationService: DeactivationsService;
}

0 comments on commit d1c0d8c

Please sign in to comment.