UNPKG

4.35 kBJavaScriptView Raw
1'use strict';
2
3const uuid = require('uuid/v4');
4const formats = require('formats');
5
6const MESSAGE_TYPE = 'event';
7
8const EVENT_TYPES = {
9 CRUD: 'crud',
10 DOMAIN: 'domain',
11 DENORMALIZER: 'denormalizer',
12 SYSTEM: 'system',
13};
14
15const reversedEventType = Object.entries(EVENT_TYPES).reduce((rev, [, value]) => {
16 rev[value] = true;
17 return rev;
18}, {});
19
20const fullNameGenerator = {
21 [EVENT_TYPES.DOMAIN]: e => `${EVENT_TYPES.DOMAIN}.${e.context}.${e.aggregate.name}.${e.name}`,
22 [EVENT_TYPES.DENORMALIZER]: e => `${EVENT_TYPES.DENORMALIZER}.${e.readmodel.collection}.${e.name}`,
23 [EVENT_TYPES.SYSTEM]: e => `${EVENT_TYPES.SYSTEM}.${e.name}`,
24 [EVENT_TYPES.CRUD]: e => `${EVENT_TYPES.CRUD}.${e.context}.${e.readmodel.collection}.${e.name}`,
25};
26
27class Event {
28 constructor({
29 type,
30 id,
31 context,
32 aggregate,
33 event,
34 command,
35 name,
36 readmodel = {},
37 payload = {},
38 metadata = {},
39 }) {
40 if (!type || !reversedEventType[type])
41 throw new Error('Invalid event type');
42
43 if (!formats.isAlphanumeric(name, { minLength: 1 }))
44 throw new Error('Command name is missing.');
45
46 if (!formats.isObject(payload))
47 throw new Error('Payload must be an object.');
48
49 if (!formats.isObject(metadata))
50 throw new Error('Metadata must be an object.');
51
52 this.type = type;
53 this.id = id || uuid();
54 this.name = name;
55 this.payload = payload;
56 this.metadata = metadata;
57 this.command = command;
58
59 if (type === EVENT_TYPES.CRUD) {
60 if (!formats.isAlphanumeric(context, { minLength: 1 }))
61 throw new Error('Invalid context.');
62
63 if (!formats.isObject(readmodel))
64 throw new Error('Invalid readmodel.');
65
66 if (!formats.isAlphanumeric(readmodel.collection, { minLength: 1 }))
67 throw new Error('Readmodel collection is missing.');
68
69 this.context = context;
70 this.readmodel = readmodel;
71 }
72
73 if (type === EVENT_TYPES.DENORMALIZER || type === EVENT_TYPES.DOMAIN) {
74 if (!formats.isAlphanumeric(context, { minLength: 1 }))
75 throw new Error('Invalid context.');
76
77 if (!formats.isObject(aggregate))
78 throw new Error('Invalid aggregate.');
79
80 if (!formats.isAlphanumeric(aggregate.name, { minLength: 1 }))
81 throw new Error('Aggregate name is missing.');
82
83 if (!formats.isString(aggregate.id, { minLength: 1 }))
84 throw new Error('Aggregate id is missing.');
85
86 this.context = context;
87 this.aggregate = { name: aggregate.name, id: aggregate.id, revision: aggregate.revision };
88
89 if (type === EVENT_TYPES.DENORMALIZER) {
90 if (!formats.isObject(event))
91 throw new Error('Invalid event.');
92
93 if (!formats.isAlphanumeric(event.name, { minLength: 1 }))
94 throw new Error('Event name is missing.');
95
96 if (!formats.isString(event.id, { minLength: 1 }))
97 throw new Error('Event id is missing.');
98
99 if (!formats.isObject(readmodel))
100 throw new Error('Invalid readmodel.');
101
102 if (!formats.isAlphanumeric(readmodel.collection, { minLength: 1 }))
103 throw new Error('Readmodel collection is missing.');
104
105 this.event = { name: event.name, id: event.id };
106 this.readmodel = readmodel;
107 }
108 }
109 this.fullname = fullNameGenerator[type](this);
110 this.routingKey = `event.${this.fullname}`;
111 }
112
113 get messageType() { // eslint-disable-line
114 return MESSAGE_TYPE;
115 }
116
117 static get fullNameGenerator() {
118 return fullNameGenerator;
119 }
120
121 serialize() {
122 return JSON.parse(JSON.stringify(this));
123 }
124
125 setCorrelationId(v) {
126 this.metadata.correlationId = v;
127 return this;
128 }
129
130 static deserialize({
131 type,
132 id,
133 context,
134 aggregate,
135 event,
136 name,
137 readmodel,
138 payload,
139 metadata,
140 command,
141 }) {
142 return new Event({
143 type,
144 id,
145 context,
146 aggregate,
147 event,
148 name,
149 readmodel,
150 payload,
151 metadata,
152 command,
153 });
154 }
155
156 static definition() {
157 return {
158 id: 'id', // uniquie id of the notification type uid
159 context: 'context', // context name type String
160
161 // aggregate info
162 aggregateId: 'aggregate.id',
163 aggregate: 'aggregate.name',
164 revision: 'aggregate.revision',
165
166 // event
167 event: 'event.name', // event
168 eventId: 'event.id', // event
169
170 // readmodel
171 collection: 'readmodel.collection',
172
173 // name
174 name: 'name', // create, update, delete
175
176 payload: 'payload',
177
178 // metadata
179 meta: 'metadata',
180 correlationId: 'metadata.correlationId',
181 };
182 }
183
184 static get EVENT_TYPES() {
185 return EVENT_TYPES;
186 }
187}
188
189module.exports = Event;