Skip to content

Commit 898c0ae

Browse files
committed
Implementing DomainEventJsonDeserializer and DomainEventMapping
Description: - DomainEventJsonDeserializer. Is in charge of converting a string event to a DomainEvent. - DomainEventMapping It is a collaborator of DomainEventJsonDeserializer. It has the information about the relation between event types and DomainEvents in a map. This map has been constructed dinamically (using the DI) calling the subscribedTo method for the subscribers. So, it treats subscribers as the source of truth. ________________________________________________________________________ There are more work to do in the next commits: - Rethink the types, a huge amount of types with any right now - DomainEvent is receiving the name as param in the constructor but probably it won't be needed. That would allow to only declare an abstract method that will be implemented in each DomainEvent.
1 parent a5415f0 commit 898c0ae

File tree

10 files changed

+76
-27
lines changed

10 files changed

+76
-27
lines changed

src/Contexts/Mooc/Courses/domain/CourseCreatedDomainEvent.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ export class CourseCreatedDomainEvent extends DomainEvent {
1313

1414
constructor({
1515
id,
16-
eventId,
17-
duration,
1816
name,
17+
duration,
18+
eventId,
1919
occurredOn
2020
}: {
2121
id: string;
@@ -42,7 +42,7 @@ export class CourseCreatedDomainEvent extends DomainEvent {
4242
body: CreateCourseDomainEventBody,
4343
eventId: string,
4444
occurredOn: Date
45-
): CourseCreatedDomainEvent {
45+
): DomainEvent {
4646
return new CourseCreatedDomainEvent({
4747
id: aggregateId,
4848
duration: body.duration,

src/Contexts/Mooc/CoursesCounter/application/Increment/IncrementCoursesCounterOnCourseCreated.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { DomainEventSubscriber } from '../../../../Shared/domain/DomainEventSubscriber';
22
import { CourseCreatedDomainEvent } from '../../../Courses/domain/CourseCreatedDomainEvent';
3-
import { CoursesCounterIncrementer } from './CoursesCounterIncrementer';
43
import { CourseId } from '../../../Shared/domain/Courses/CourseId';
4+
import { CoursesCounterIncrementer } from './CoursesCounterIncrementer';
55

66
export class IncrementCoursesCounterOnCourseCreated implements DomainEventSubscriber<CourseCreatedDomainEvent> {
77
constructor(private incrementer: CoursesCounterIncrementer) {}
88

9-
subscribedTo(): string[] {
10-
return [CourseCreatedDomainEvent.EVENT_NAME];
9+
subscribedTo(): any[] {
10+
return [CourseCreatedDomainEvent];
1111
}
1212

1313
async on(domainEvent: CourseCreatedDomainEvent) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { DomainEvent } from './DomainEvent';
22

33
export interface DomainEventSubscriber<T extends DomainEvent> {
4-
subscribedTo(): Array<string>;
4+
subscribedTo(): Array<any>;
55

66
on(domainEvent: T): Promise<void>;
77
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { DomainEvent } from '../../domain/DomainEvent';
2+
import { DomainEventMapping } from './DomainEventMapping';
3+
4+
export class DomainEventJsonDeserializer {
5+
private mapping: DomainEventMapping;
6+
7+
constructor(mapping: DomainEventMapping) {
8+
this.mapping = mapping;
9+
}
10+
11+
deserialize(event: string): DomainEvent {
12+
const eventData = JSON.parse(event).data;
13+
const eventName = eventData.type;
14+
const eventClass = this.mapping.for(eventName);
15+
16+
if (!eventClass) {
17+
throw new Error(`The event ${eventName} doesn't exist or has no subscribers`);
18+
}
19+
20+
return eventClass.fromPrimitives(
21+
eventData.attributes.id,
22+
eventData.attributes,
23+
eventData.id,
24+
eventData.occurred_on
25+
);
26+
}
27+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { DomainEventSubscriber } from '../../domain/DomainEventSubscriber';
2+
3+
export class DomainEventMapping {
4+
mapping: any;
5+
6+
constructor(mapping: any) {
7+
this.mapping = mapping.reduce((prev: any, subscriber: DomainEventSubscriber<any>) => {
8+
subscriber.subscribedTo().forEach(event => {
9+
prev[event.EVENT_NAME] = event;
10+
});
11+
return prev;
12+
}, {});
13+
}
14+
15+
for(name: string) {
16+
if (!this.mapping[name]) {
17+
throw new Error(`The Domain Event Class for ${name} doesn't exists or have no subscribers`);
18+
}
19+
return this.mapping[name];
20+
}
21+
}

src/Contexts/Shared/infrastructure/EventBus/EventEmitterBus.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { EventEmitter } from 'events';
12
import { DomainEvent } from '../../domain/DomainEvent';
23
import { DomainEventSubscriber } from '../../domain/DomainEventSubscriber';
3-
import { EventEmitter } from 'events';
44

55
export class EventEmitterBus extends EventEmitter {
66
constructor(subscribers: Array<DomainEventSubscriber<DomainEvent>>) {
@@ -17,7 +17,7 @@ export class EventEmitterBus extends EventEmitter {
1717

1818
private registerSubscriber(subscriber: DomainEventSubscriber<DomainEvent>) {
1919
subscriber.subscribedTo().map(event => {
20-
this.on(event, subscriber.on);
20+
this.on(event.EVENT_NAME, subscriber.on);
2121
});
2222
}
2323

src/Contexts/Shared/infrastructure/EventBus/InMemorySyncEventBus.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { EventBus } from '../../domain/EventBus';
21
import { DomainEvent } from '../../domain/DomainEvent';
32
import { DomainEventSubscriber } from '../../domain/DomainEventSubscriber';
3+
import { EventBus } from '../../domain/EventBus';
44

55
type Subscription = {
66
boundedCallback: Function;
@@ -27,7 +27,7 @@ export class InMemorySyncEventBus implements EventBus {
2727
}
2828

2929
addSubscribers(subscribers: Array<DomainEventSubscriber<DomainEvent>>) {
30-
subscribers.map(subscriber => subscriber.subscribedTo().map(event => this.subscribe(event, subscriber)));
30+
subscribers.map(subscriber => subscriber.subscribedTo().map(event => this.subscribe(event.EVENT_NAME, subscriber)));
3131
}
3232

3333
private subscribe(topic: string, subscriber: DomainEventSubscriber<DomainEvent>): void {

src/apps/mooc_backend/config/dependency-injection/Shared/application.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
services:
2-
32
Mooc.shared.ConnectionManager:
43
factory:
54
class: ../../../../../Contexts/Shared/infrastructure/persistence/mongo/MongoClientFactory
@@ -13,3 +12,11 @@ services:
1312
Mooc.shared.EventBus:
1413
class: ../../../../../Contexts/Shared/infrastructure/EventBus/InMemoryAsyncEventBus
1514
arguments: []
15+
16+
Mooc.shared.EventBus.DomainEventMapping:
17+
class: ../../../../../Contexts/Shared/infrastructure/EventBus/DomainEventMapping
18+
arguments: ['!tagged domainEventSubscriber']
19+
20+
Mooc.shared.EventBus.DomainEventJsonDeserializer:
21+
class: ../../../../../Contexts/Shared/infrastructure/EventBus/DomainEventJsonDeserializer
22+
arguments: ['@Mooc.shared.EventBus.DomainEventMapping']

tests/Contexts/Shared/infrastructure/InMemoryAsyncEventBus.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { InMemoryAsyncEventBus } from '../../../../src/Contexts/Shared/infrastructure/EventBus/InMemoryAsyncEventBus';
2-
import { DomainEventSubscriber } from '../../../../src/Contexts/Shared/domain/DomainEventSubscriber';
31
import { DomainEvent } from '../../../../src/Contexts/Shared/domain/DomainEvent';
2+
import { DomainEventSubscriber } from '../../../../src/Contexts/Shared/domain/DomainEventSubscriber';
43
import { Uuid } from '../../../../src/Contexts/Shared/domain/value-object/Uuid';
4+
import { InMemoryAsyncEventBus } from '../../../../src/Contexts/Shared/infrastructure/EventBus/InMemoryAsyncEventBus';
55

66
describe('InMemoryAsyncEventBus', () => {
77
let subscriber: DomainEventSubscriberDummy;
@@ -35,8 +35,8 @@ class DummyEvent extends DomainEvent {
3535
}
3636

3737
class DomainEventSubscriberDummy implements DomainEventSubscriber<DummyEvent> {
38-
subscribedTo(): string[] {
39-
return [DummyEvent.EVENT_NAME];
38+
subscribedTo(): any[] {
39+
return [DummyEvent];
4040
}
4141

4242
async on(domainEvent: DummyEvent) {
Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
import { Given } from 'cucumber';
22
import container from '../../../../../src/apps/mooc_backend/config/dependency-injection';
33
import { EventBus } from '../../../../../src/Contexts/Shared/domain/EventBus';
4-
import { CourseCreatedDomainEvent } from '../../../../../src/Contexts/Mooc/Courses/domain/CourseCreatedDomainEvent';
4+
import { DomainEventJsonDeserializer } from '../../../../../src/Contexts/Shared/infrastructure/EventBus/DomainEventJsonDeserializer';
55

6-
Given('I send an event to the event bus:', async (event: any) => {
7-
const eventBus = container.get('Mooc.shared.EventBus') as EventBus;
8-
const jsonEvent = JSON.parse(event).data;
6+
const eventBus = container.get('Mooc.shared.EventBus') as EventBus;
7+
const deserializer = container.get('Mooc.shared.EventBus.DomainEventJsonDeserializer') as DomainEventJsonDeserializer;
98

10-
const domainEvent = CourseCreatedDomainEvent.fromPrimitives(
11-
jsonEvent.attributes.id,
12-
jsonEvent.attributes,
13-
jsonEvent.id,
14-
jsonEvent.occurred_on
15-
);
9+
Given('I send an event to the event bus:', async (event: any) => {
10+
const domainEvent = deserializer.deserialize(event);
1611

1712
await eventBus.publish([domainEvent]);
1813
});
19-

0 commit comments

Comments
 (0)