Skip to content

Commit

Permalink
refactor interfaces and classes to v2
Browse files Browse the repository at this point in the history
* feat: improve strong-typing and conventions
* refactor: remove examples, update documentation
* fix: default to void type
* fix: export  proper request and notification classes
* refactor: attempt at resolving PR review concerns and recent issues
* fix: fix remaining two concerns
* refactor: make mediator code more readable
* refactor: break type mappings up in multiple files
* fix: test failure
* refactor: rename RequestBase to RequestData
* docs: update documentation to match code
* fix: changed bad import to be named properly
  • Loading branch information
ffMathy authored Sep 5, 2024
1 parent 2ab7eda commit 8ebf6c3
Show file tree
Hide file tree
Showing 49 changed files with 640 additions and 2,419 deletions.
100 changes: 43 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ Below the `requestHandler` pattern with internal resolver and with the inversify

```typescript
// request.ts -> Define the request
class Request implements IRequest<string> {
class Request extends RequestData<string> {
name: string;
}

// handlertest.ts -> Add the attribute to the request handler
@requestHandler(Request)
class HandlerTest implements IRequestHandler<Request, string> {
class HandlerTest implements RequestHandler<Request, string> {
handle(value: Request): Promise<string> {
return Promise.resolve(`Value passed ${value.name}`);
}
Expand All @@ -41,7 +41,7 @@ const r = new Request();
r.name = "Foo";

// Send the command
const result = await mediator.send<string>(r);
const result = await mediator.send(r);

// result = "Value passed Foo"
```
Expand All @@ -54,13 +54,13 @@ import { Mediator } from "mediatr-ts";
const result: string[] = [];

// The notification class
class Ping implements INotification {
constructor(public value?: string){}
class Ping extends NotificationData {
constructor(public value?: string){ super(); }
}

// The notification handler
@notificationHandler(Ping)
class Pong1 implements INotificationHandler<Ping> {
class Pong1 implements NotificationHandler<Ping> {
async handle(notification: Ping): Promise<void> {
result.push(notification.value);
}
Expand All @@ -77,63 +77,65 @@ mediator.publish(new Ping(message));
By default, the notification handlers will run in the order that they are loaded in. This might not be desirable, since it depends on the order of the imports. To change the order, you can set it explicitly.

```typescript
import { mediatorSettings, Mediator } from "mediatr-ts";
import { Mediator, NotificationData, NotificationHandler } from "mediatr-ts";

const result: string[] = [];

// The notification class
class Ping implements INotification {
class Ping extends NotificationData {
constructor(public value?: string){}
}

// The notification handler
@notificationHandler(Ping)
class Pong2 implements INotificationHandler<Ping> {
class Pong2 implements NotificationHandler<Ping> {
async handle(notification: Ping): Promise<void> {
result.push(notification.value);
result.push(notification.value + " from 2");
}
}

// The notification handler
@notificationHandler(Ping)
class Pong1 implements INotificationHandler<Ping> {
class Pong1 implements NotificationHandler<Ping> {
async handle(notification: Ping): Promise<void> {
result.push(notification.value);
result.push(notification.value + " from 1");
}
}

const mediator = new Mediator();
mediator.publish(new Ping(message));
mediator.publish(new Ping("Foo"));

// result: [ "Foo" ]
// result: [ "Foo from 2", "Foo from 1" ]

// Set the order of the pipeline behaviors. PipelineBehaviorTest2 will be executed first, and then PipelineBehaviorTest1.
mediatorSettings.dispatcher.notifications.setOrder(Ping, [
mediator.dispatcher.notifications.setOrder(Ping, [
Pong2,
Pong1
]);

const mediator = new Mediator();
mediator.publish(new Ping("Foo"));

//...
// result: [ "Foo from 1", "Foo from 2" ]
```

### Pipeline behaviors

```typescript
class Request {
import { Mediator, PipelineBehavior, RequestHandler, RequestData } from "mediatr-ts";

class Request extends RequestData {
name?: string;
}

@requestHandler(Request)
class HandlerTest implements IRequestHandler<Request, string> {
class HandlerTest implements RequestHandler<Request, string> {
handle(value: Request): Promise<string> {
return Promise.resolve(`Value passed ${value.name}`);
}
}

@pipelineBehavior()
class PipelineBehaviorTest1 implements IPipelineBehavior {
class PipelineBehaviorTest1 implements PipelineBehavior {
async handle(request: IRequest<unknown>, next: () => unknown): Promise<unknown> {
if(request instanceof Request) {
request.name += " with stuff 1";
Expand All @@ -149,7 +151,7 @@ class PipelineBehaviorTest1 implements IPipelineBehavior {
}

@pipelineBehavior()
class PipelineBehaviorTest2 implements IPipelineBehavior {
class PipelineBehaviorTest2 implements PipelineBehavior {
async handle(request: IRequest<unknown>, next: () => unknown): Promise<unknown> {
if(request instanceof Request) {
request.name += " with stuff 2";
Expand Down Expand Up @@ -178,31 +180,28 @@ const result = await mediator.send(r);
By default, the pipeline behaviors will run in the order that they are loaded in. This might not be desirable, since it depends on the order of the imports. To change the order, you can set it explicitly.

```typescript
import { mediatorSettings, Mediator } from "mediatr-ts";
import { Mediator, PipelineBehavior } from "mediatr-ts";

@pipelineBehavior()
class PipelineBehaviorTest1 implements IPipelineBehavior {
class PipelineBehaviorTest1 implements PipelineBehavior {
async handle(request: IRequest<unknown>, next: () => unknown): Promise<unknown> {
return result;
}
}

@pipelineBehavior()
class PipelineBehaviorTest2 implements IPipelineBehavior {
class PipelineBehaviorTest2 implements PipelineBehavior {
async handle(request: IRequest<unknown>, next: () => unknown): Promise<unknown> {
return result;
}
}

const mediator = new Mediator();
// Set the order of the pipeline behaviors. PipelineBehaviorTest2 will be executed first, and then PipelineBehaviorTest1.
mediatorSettings.dispatcher.behaviors.setOrder([
mediator.pipelineBehaviors.setOrder([
PipelineBehaviorTest2,
PipelineBehaviorTest1
]);

const mediator = new Mediator();

//...
```

## Integrating with Dependency Injection containers
Expand All @@ -213,34 +212,21 @@ At the very beginning of your app you **MUST** setup the resolver with Inversify

```typescript
import { Container } from "inversify";
import { mediatorSettings, Mediator, IResolver } from "mediatr-ts";
import { Mediator, Resolver, requestHandler, RequestData } from "mediatr-ts";

const container = new Container();

// inversify.resolver.ts -> Implement the resolver
class InversifyResolver implements IResolver {
resolve<T>(name: string): T {
return container.get(name);
}

add(name: string, instance: Function): void {
container.bind(name).to(instance as any);
class InversifyResolver implements Resolver {
resolve<T>(type: Class<T>): T {
return container.get(type);
}

remove(name: string): void {
// not necessary- can be blank, never called by the lib, for debugging / testing only
container.unbind(name);
}

clear(): void {
// not necessary- can be blank, never called by the lib, for debugging / testing only
container.unbindAll();
add<T>(type: Class<T>): void {
container.bind(type).toSelf();
}
}

// Set the resolver of MediatR-TS
mediatorSettings.resolver = new InversifyResolver();

// You can later configure the inversify container
interface IWarrior {
fight(): string;
Expand All @@ -260,18 +246,19 @@ class Ninja implements IWarrior {
container.bind<IWarrior>(TYPES.IWarrior).to(Ninja);

// The request object
class Request implements IRequest<number> {
class Request extends RequestData<number> {
public thenumber: number;

constructor(thenumber: number) {
super();
this.thenumber = thenumber;
}
}

// Decorate the handler request with Handler and injectable attribute, notice the warrior property
@requestHandler(Request)
@injectable()
class HandlerRequest implements IRequestHandler<Request, string> {
class HandlerRequest implements RequestHandler<Request, string> {
@inject(TYPES.IWarrior)
public warrior: IWarrior; // Instantiated by the inversify

Expand All @@ -280,12 +267,11 @@ class HandlerRequest implements IRequestHandler<Request, string> {
}
}

const mediator = new Mediator();
const result = await mediator.send<string>(new Request(99));
const mediator = new Mediator({
resolver: new InversifyResolver()
});

// result => "We has 99 ninja fight"
```
const result = await mediator.send(new Request(99));

## Examples

You can find some basic examples on the `src/examples` folder
// result => "We has 99 ninja fight"
```
20 changes: 0 additions & 20 deletions examples/cjs/README.md

This file was deleted.

Loading

0 comments on commit 8ebf6c3

Please sign in to comment.