Skip to content

Commit

Permalink
feat(command-bus): add the possibility of passing an existing context…
Browse files Browse the repository at this point in the history
… to sendSync
  • Loading branch information
gtoselli committed Sep 10, 2024
1 parent 0c48728 commit 970ed55
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export interface IContextManager<TContext> {
wrapWithContext<T>(operation: (context: TContext) => Promise<T>): Promise<T>;
wrapWithContext<T>(operation: (context: TContext) => Promise<T>, context?: TContext): Promise<T>;
}
42 changes: 38 additions & 4 deletions packages/ddd-toolkit/src/command-bus/local-command-bus.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,11 @@ describe('LocalCommandBus', () => {
let commandBus: LocalCommandBus<TContext>;

class FooContextManager implements IContextManager<TContext> {
public async wrapWithContext<T>(operation: (context: TContext) => Promise<T>): Promise<T> {
const context: TContext = { contextKey: 'foo-bar' };
public async wrapWithContext<T>(
operation: (context: TContext) => Promise<T>,
existingContext: TContext,
): Promise<T> {
const context: TContext = existingContext || { contextKey: 'foo-context' };
return await operation(context);
}
}
Expand All @@ -193,11 +196,42 @@ describe('LocalCommandBus', () => {
});

describe('When sendSync a foo command', () => {
it('context should be passed to command', async () => {
it('context should be passed to command handler', async () => {
const command = new FooCommand({ foo: 'bar' });
await commandBus.sendSync(command);

expect(FooHandlerMock).toHaveBeenCalledWith([command, { contextKey: 'foo-bar' }]);
expect(FooHandlerMock).toHaveBeenCalledWith([command, { contextKey: 'foo-context' }]);
});
});

describe('When sendSync a foo command with existing context', () => {
it('context should be passed to command handler', async () => {
const command = new FooCommand({ foo: 'bar' });
await commandBus.sendSync(command, { contextKey: 'bar-context' });

expect(FooHandlerMock).toHaveBeenCalledWith([command, { contextKey: 'bar-context' }]);
});
});
});

describe('Given one registered failing handler to foo command', () => {
const FooHandlerMock = jest.fn();

class FooCommandHandler implements ICommandHandler<FooCommand> {
async handle(...args: unknown[]) {
return await FooHandlerMock(args);
}
}

beforeEach(() => {
FooHandlerMock.mockRejectedValue(new Error('ko'));
commandBus.register(FooCommand, new FooCommandHandler());
});

describe('When sendSync a foo command', () => {
it('should throw', async () => {
const command = new FooCommand({ foo: 'bar' });
await expect(() => commandBus.sendSync(command)).rejects.toThrow();
});
});
});
Expand Down
7 changes: 5 additions & 2 deletions packages/ddd-toolkit/src/command-bus/local-command-bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@ export class LocalCommandBus<TContext = void> implements ICommandBus<TContext> {
void this.handleCommand(command, handler);
}

public async sendSync<C extends ICommand<unknown, unknown>>(command: C): Promise<C['_returnType']> {
public async sendSync<C extends ICommand<unknown, unknown>>(
command: C,
context?: TContext,
): Promise<C['_returnType']> {
const handler = this.handlers[command.name] as ICommandHandler<C, TContext>;
if (!handler) throw new Error(`No handler found for ${command.name}`);

return this.contextManager
? await this.contextManager.wrapWithContext(async (context) => {
return await handler.handle(command, context);
})
}, context)
: await handler.handle(command);
}

Expand Down

0 comments on commit 970ed55

Please sign in to comment.