Skip to content

Commit ce78761

Browse files
authored
Merge pull request #58 from CodelyTV/part_three_domain_event_deserializer
Part three domain event deserializer
2 parents a5415f0 + aa9feb7 commit ce78761

File tree

11 files changed

+99
-28
lines changed

11 files changed

+99
-28
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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import { DomainEventClass } from '../../../../Shared/domain/DomainEvent';
12
import { DomainEventSubscriber } from '../../../../Shared/domain/DomainEventSubscriber';
23
import { CourseCreatedDomainEvent } from '../../../Courses/domain/CourseCreatedDomainEvent';
3-
import { CoursesCounterIncrementer } from './CoursesCounterIncrementer';
44
import { CourseId } from '../../../Shared/domain/Courses/CourseId';
5+
import { CoursesCounterIncrementer } from './CoursesCounterIncrementer';
56

67
export class IncrementCoursesCounterOnCourseCreated implements DomainEventSubscriber<CourseCreatedDomainEvent> {
78
constructor(private incrementer: CoursesCounterIncrementer) {}
89

9-
subscribedTo(): string[] {
10-
return [CourseCreatedDomainEvent.EVENT_NAME];
10+
subscribedTo(): DomainEventClass[] {
11+
return [CourseCreatedDomainEvent];
1112
}
1213

1314
async on(domainEvent: CourseCreatedDomainEvent) {

src/Contexts/Shared/domain/DomainEvent.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Uuid } from './value-object/Uuid';
22

33
export abstract class DomainEvent {
4+
static EVENT_NAME: string;
5+
static fromPrimitives: (...args: any[]) => any;
46
readonly aggregateId: string;
57
readonly eventId: string;
68
readonly occurredOn: Date;
@@ -15,3 +17,5 @@ export abstract class DomainEvent {
1517

1618
abstract toPrimitive(): Object;
1719
}
20+
21+
export type DomainEventClass = { EVENT_NAME: string, fromPrimitives(...args: any[]): DomainEvent; };
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { DomainEvent } from './DomainEvent';
1+
import { DomainEvent, DomainEventClass } from './DomainEvent';
22

33
export interface DomainEventSubscriber<T extends DomainEvent> {
4-
subscribedTo(): Array<string>;
4+
subscribedTo(): Array<DomainEventClass>;
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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { DomainEventClass, DomainEvent } from '../../domain/DomainEvent';
2+
import { DomainEventSubscriber } from '../../domain/DomainEventSubscriber';
3+
4+
type Mapping = Map<string, DomainEventClass>;
5+
6+
export class DomainEventMapping {
7+
mapping: Mapping;
8+
9+
constructor(mapping: DomainEventSubscriber<DomainEvent>[]) {
10+
this.mapping = mapping.reduce(this.eventsExtractor(), new Map<string, DomainEventClass>());
11+
}
12+
13+
private eventsExtractor() {
14+
return (map: Mapping, subscriber: DomainEventSubscriber<DomainEvent>) => {
15+
subscriber.subscribedTo().forEach(this.eventNameExtractor(map));
16+
return map;
17+
};
18+
}
19+
20+
private eventNameExtractor(map: Mapping): (domainEvent: DomainEventClass) => void {
21+
return domainEvent => {
22+
const eventName = domainEvent.EVENT_NAME;
23+
map.set(eventName, domainEvent);
24+
};
25+
}
26+
27+
for(name: string): DomainEventClass {
28+
const domainEvent = this.mapping.get(name);
29+
30+
if (!domainEvent) {
31+
throw new Error(`The Domain Event Class for ${name} doesn't exists or have no subscribers`);
32+
}
33+
34+
return domainEvent;
35+
}
36+
}

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: 4 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,9 @@ 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 =>
31+
subscriber.subscribedTo().map(event => this.subscribe(event.EVENT_NAME!, subscriber))
32+
);
3133
}
3234

3335
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) {

0 commit comments

Comments
 (0)