@event-driven-io/emmett 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commandHandling/handleCommand.d.mts +6 -3
- package/dist/commandHandling/handleCommand.d.ts +6 -3
- package/dist/commandHandling/handleCommand.js +33 -29
- package/dist/commandHandling/handleCommand.js.map +1 -1
- package/dist/commandHandling/handleCommand.mjs +4 -2
- package/dist/commandHandling/handleCommand.mjs.map +1 -1
- package/dist/commandHandling/handleCommand.unit.spec.js +83 -0
- package/dist/commandHandling/handleCommand.unit.spec.js.map +1 -0
- package/dist/commandHandling/handleCommand.unit.spec.mjs +93 -0
- package/dist/commandHandling/handleCommand.unit.spec.mjs.map +1 -0
- package/dist/commandHandling/handleCommandWithDecider.d.mts +3 -2
- package/dist/commandHandling/handleCommandWithDecider.d.ts +3 -2
- package/dist/commandHandling/handleCommandWithDecider.js +4 -13
- package/dist/commandHandling/handleCommandWithDecider.js.map +1 -1
- package/dist/commandHandling/index.d.mts +1 -1
- package/dist/commandHandling/index.d.ts +1 -1
- package/dist/commandHandling/index.js +2 -2
- package/dist/commandHandling/index.js.map +1 -1
- package/dist/errors/index.js +67 -51
- package/dist/errors/index.js.map +1 -1
- package/dist/eventStore/eventStore.js +2 -1
- package/dist/eventStore/eventStore.js.map +1 -1
- package/dist/eventStore/expectedVersion.js +22 -29
- package/dist/eventStore/expectedVersion.js.map +1 -1
- package/dist/eventStore/expectedVersion.unit.spec.js +48 -60
- package/dist/eventStore/expectedVersion.unit.spec.js.map +1 -1
- package/dist/eventStore/inMemoryEventStore.js +65 -64
- package/dist/eventStore/inMemoryEventStore.js.map +1 -1
- package/dist/eventStore/inMemoryEventStore.mjs +6 -1
- package/dist/eventStore/inMemoryEventStore.mjs.map +1 -1
- package/dist/eventStore/inMemoryEventStore.unit.spec.d.mts +2 -0
- package/dist/eventStore/inMemoryEventStore.unit.spec.d.ts +2 -0
- package/dist/eventStore/inMemoryEventStore.unit.spec.js +85 -0
- package/dist/eventStore/inMemoryEventStore.unit.spec.js.map +1 -0
- package/dist/eventStore/inMemoryEventStore.unit.spec.mjs +81 -0
- package/dist/eventStore/inMemoryEventStore.unit.spec.mjs.map +1 -0
- package/dist/eventStore/index.js +3 -3
- package/dist/eventStore/index.js.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/serialization/index.js +1 -1
- package/dist/serialization/index.js.map +1 -1
- package/dist/serialization/json/JSONParser.js +16 -20
- package/dist/serialization/json/JSONParser.js.map +1 -1
- package/dist/serialization/json/index.js +1 -1
- package/dist/serialization/json/index.js.map +1 -1
- package/dist/testing/assertions.js +12 -24
- package/dist/testing/assertions.js.map +1 -1
- package/dist/testing/deciderSpecification.js +40 -39
- package/dist/testing/deciderSpecification.js.map +1 -1
- package/dist/testing/index.js +2 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/typing/command.js +2 -1
- package/dist/typing/command.js.map +1 -1
- package/dist/typing/decider.js +2 -1
- package/dist/typing/decider.js.map +1 -1
- package/dist/typing/event.js +2 -1
- package/dist/typing/event.js.map +1 -1
- package/dist/typing/index.js +4 -4
- package/dist/typing/index.js.map +1 -1
- package/dist/typing/workflow.d.ts +57 -1
- package/dist/typing/workflow.js +45 -55
- package/dist/typing/workflow.js.map +1 -1
- package/dist/utils/index.js +3 -6
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/iterators.js +8 -10
- package/dist/utils/iterators.js.map +1 -1
- package/dist/utils/merge.js +27 -21
- package/dist/utils/merge.js.map +1 -1
- package/dist/validation/index.js +25 -33
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/validation.spec.js +14 -10
- package/dist/validation/validation.spec.js.map +1 -1
- package/package.json +1 -1
- package/dist/testing/placeholder.e2e.spec.js +0 -8
- package/dist/testing/placeholder.e2e.spec.js.map +0 -1
- package/dist/testing/placeholder.e2e.spec.mjs +0 -8
- package/dist/testing/placeholder.e2e.spec.mjs.map +0 -1
- /package/dist/{testing/placeholder.e2e.spec.d.mts → commandHandling/handleCommand.unit.spec.d.mts} +0 -0
- /package/dist/{testing/placeholder.e2e.spec.d.ts → commandHandling/handleCommand.unit.spec.d.ts} +0 -0
|
@@ -1,33 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
const STREAM_EXISTS =
|
|
3
|
-
const STREAM_DOES_NOT_EXIST =
|
|
4
|
-
const NO_CONCURRENCY_CHECK =
|
|
5
|
-
const matchesExpectedVersion = (current, expected) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { ConcurrencyError } from '../errors';
|
|
2
|
+
export const STREAM_EXISTS = 'STREAM_EXISTS';
|
|
3
|
+
export const STREAM_DOES_NOT_EXIST = 'STREAM_DOES_NOT_EXIST';
|
|
4
|
+
export const NO_CONCURRENCY_CHECK = 'NO_CONCURRENCY_CHECK';
|
|
5
|
+
export const matchesExpectedVersion = (current, expected) => {
|
|
6
|
+
if (expected === NO_CONCURRENCY_CHECK)
|
|
7
|
+
return true;
|
|
8
|
+
if (expected == STREAM_DOES_NOT_EXIST)
|
|
9
|
+
return current === undefined;
|
|
10
|
+
if (expected == STREAM_EXISTS)
|
|
11
|
+
return current !== undefined;
|
|
12
|
+
return current === expected;
|
|
13
13
|
};
|
|
14
|
-
const assertExpectedVersionMatchesCurrent = (current, expected) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
export const assertExpectedVersionMatchesCurrent = (current, expected) => {
|
|
15
|
+
expected ??= NO_CONCURRENCY_CHECK;
|
|
16
|
+
if (!matchesExpectedVersion(current, expected))
|
|
17
|
+
throw new ExpectedVersionConflictError(current, expected);
|
|
18
18
|
};
|
|
19
|
-
class ExpectedVersionConflictError extends
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
export class ExpectedVersionConflictError extends ConcurrencyError {
|
|
20
|
+
constructor(current, expected) {
|
|
21
|
+
super(current?.toString(), expected?.toString());
|
|
22
|
+
// 👇️ because we are extending a built-in class
|
|
23
|
+
Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);
|
|
24
|
+
}
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
exports.ExpectedVersionConflictError = ExpectedVersionConflictError; exports.NO_CONCURRENCY_CHECK = NO_CONCURRENCY_CHECK; exports.STREAM_DOES_NOT_EXIST = STREAM_DOES_NOT_EXIST; exports.STREAM_EXISTS = STREAM_EXISTS; exports.assertExpectedVersionMatchesCurrent = assertExpectedVersionMatchesCurrent; exports.matchesExpectedVersion = matchesExpectedVersion;
|
|
33
26
|
//# sourceMappingURL=expectedVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/eventStore/expectedVersion.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"expectedVersion.js","sourceRoot":"","sources":["../../src/eventStore/expectedVersion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAiB7C,MAAM,CAAC,MAAM,aAAa,GAAG,eAA+C,CAAC;AAC7E,MAAM,CAAC,MAAM,qBAAqB,GAChC,uBAAuD,CAAC;AAC1D,MAAM,CAAC,MAAM,oBAAoB,GAC/B,sBAAsD,CAAC;AAEzD,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAGpC,OAAkC,EAClC,QAA8C,EACrC,EAAE;IACX,IAAI,QAAQ,KAAK,oBAAoB;QAAE,OAAO,IAAI,CAAC;IAEnD,IAAI,QAAQ,IAAI,qBAAqB;QAAE,OAAO,OAAO,KAAK,SAAS,CAAC;IAEpE,IAAI,QAAQ,IAAI,aAAa;QAAE,OAAO,OAAO,KAAK,SAAS,CAAC;IAE5D,OAAO,OAAO,KAAK,QAAQ,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAGjD,OAAkC,EAClC,QAA0D,EACpD,EAAE;IACR,QAAQ,KAAK,oBAAoB,CAAC;IAElC,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC;QAC5C,MAAM,IAAI,4BAA4B,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF,MAAM,OAAO,4BAEX,SAAQ,gBAAgB;IACxB,YACE,OAAgC,EAChC,QAA4C;QAE5C,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEjD,gDAAgD;QAChD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,4BAA4B,CAAC,SAAS,CAAC,CAAC;IACtE,CAAC;CACF"}
|
|
@@ -1,62 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
for
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{ current: -1, expected: 1 },
|
|
50
|
-
{ current: 0, expected: 100 },
|
|
51
|
-
{ current: "", expected: "random" },
|
|
52
|
-
{ current: "random", expected: "" }
|
|
53
|
-
];
|
|
54
|
-
for (const streamVersion of definedStreamVersion) {
|
|
55
|
-
_strict2.default.equal(
|
|
56
|
-
_expectedVersion.matchesExpectedVersion.call(void 0, streamVersion.current, streamVersion.expected),
|
|
57
|
-
false
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-floating-promises */
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { describe, it } from 'node:test';
|
|
4
|
+
import { NO_CONCURRENCY_CHECK, STREAM_DOES_NOT_EXIST, STREAM_EXISTS, matchesExpectedVersion, } from './expectedVersion';
|
|
5
|
+
describe('matchesExpectedVersion', () => {
|
|
6
|
+
it('When NO_CONCURRENCY_CHECK provided returns `true` for any current version', () => {
|
|
7
|
+
const allCurrentVersions = [undefined, 0, -1, 1, 100, 'random', ''];
|
|
8
|
+
for (const currentStreamVersion of allCurrentVersions) {
|
|
9
|
+
assert.ok(matchesExpectedVersion(currentStreamVersion, NO_CONCURRENCY_CHECK));
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
it('When STREAM_DOES_NOT_EXIST provided returns `true` for current equals `undefined`', () => {
|
|
13
|
+
assert.ok(matchesExpectedVersion(undefined, STREAM_DOES_NOT_EXIST));
|
|
14
|
+
});
|
|
15
|
+
it('When STREAM_DOES_NOT_EXIST provided returns `false` for current different than `undefined`', () => {
|
|
16
|
+
const definedStreamVersion = [0, -1, 1, 100, 'random', ''];
|
|
17
|
+
for (const currentStreamVersion of definedStreamVersion) {
|
|
18
|
+
assert.equal(matchesExpectedVersion(currentStreamVersion, STREAM_DOES_NOT_EXIST), false);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
it('When STREAM_EXISTS provided returns `true` for current different than `undefined`', () => {
|
|
22
|
+
const definedStreamVersion = [0, -1, 1, 100, 'random', ''];
|
|
23
|
+
for (const currentStreamVersion of definedStreamVersion) {
|
|
24
|
+
assert.ok(matchesExpectedVersion(currentStreamVersion, STREAM_EXISTS));
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
it('When STREAM_EXISTS provided returns `false` for current equals `undefined`', () => {
|
|
28
|
+
assert.equal(matchesExpectedVersion(undefined, STREAM_EXISTS), false);
|
|
29
|
+
});
|
|
30
|
+
it('When value provided returns `true` for current matching expected value', () => {
|
|
31
|
+
const definedStreamVersion = [0, -1, 1, 100, 'random', ''];
|
|
32
|
+
for (const streamVersion of definedStreamVersion) {
|
|
33
|
+
assert.ok(matchesExpectedVersion(streamVersion, streamVersion));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it('When value provided returns `false` for current notmatching expected value', () => {
|
|
37
|
+
const definedStreamVersion = [
|
|
38
|
+
{ current: 100, expected: 0 },
|
|
39
|
+
{ current: 0, expected: -1 },
|
|
40
|
+
{ current: -1, expected: 1 },
|
|
41
|
+
{ current: 0, expected: 100 },
|
|
42
|
+
{ current: '', expected: 'random' },
|
|
43
|
+
{ current: 'random', expected: '' },
|
|
44
|
+
];
|
|
45
|
+
for (const streamVersion of definedStreamVersion) {
|
|
46
|
+
assert.equal(matchesExpectedVersion(streamVersion.current, streamVersion.expected), false);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
61
49
|
});
|
|
62
50
|
//# sourceMappingURL=expectedVersion.unit.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/eventStore/expectedVersion.unit.spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"expectedVersion.unit.spec.js","sourceRoot":"","sources":["../../src/eventStore/expectedVersion.unit.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,66 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
1
|
+
import { v4 as uuid } from 'uuid';
|
|
2
|
+
import {} from './eventStore';
|
|
3
|
+
import { assertExpectedVersionMatchesCurrent } from './expectedVersion';
|
|
4
|
+
export const getInMemoryEventStore = () => {
|
|
5
|
+
const streams = new Map();
|
|
6
|
+
const getAllEventsCount = () => {
|
|
7
|
+
return Array.from(streams.values())
|
|
8
|
+
.map((s) => s.length)
|
|
9
|
+
.reduce((p, c) => p + c, 0);
|
|
10
|
+
};
|
|
11
|
+
return {
|
|
12
|
+
async aggregateStream(streamName, options) {
|
|
13
|
+
const { evolve, getInitialState, read } = options;
|
|
14
|
+
const result = await this.readStream(streamName, read);
|
|
15
|
+
if (!result)
|
|
16
|
+
return null;
|
|
17
|
+
const events = result?.events ?? [];
|
|
18
|
+
return {
|
|
19
|
+
currentStreamVersion: BigInt(events.length),
|
|
20
|
+
state: events.reduce(evolve, getInitialState()),
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
readStream: (streamName, options) => {
|
|
24
|
+
const events = streams.get(streamName);
|
|
25
|
+
const currentStreamVersion = events ? BigInt(events.length) : undefined;
|
|
26
|
+
assertExpectedVersionMatchesCurrent(currentStreamVersion, options?.expectedStreamVersion);
|
|
27
|
+
const from = Number(options && 'from' in options ? options.from : 0);
|
|
28
|
+
const to = Number(options && 'to' in options
|
|
29
|
+
? options.to
|
|
30
|
+
: options && 'maxCount' in options && options.maxCount
|
|
31
|
+
? options.from + options.maxCount
|
|
32
|
+
: events?.length ?? 1);
|
|
33
|
+
const resultEvents = events && events.length > 0
|
|
34
|
+
? events.map((e) => e.event).slice(from, to)
|
|
35
|
+
: [];
|
|
36
|
+
const result = events && events.length > 0
|
|
37
|
+
? {
|
|
38
|
+
currentStreamVersion: currentStreamVersion,
|
|
39
|
+
events: resultEvents,
|
|
40
|
+
}
|
|
41
|
+
: null;
|
|
42
|
+
return Promise.resolve(result);
|
|
43
|
+
},
|
|
44
|
+
appendToStream: (streamName, events, options) => {
|
|
45
|
+
const currentEvents = streams.get(streamName) ?? [];
|
|
46
|
+
const currentStreamVersion = currentEvents.length > 0 ? BigInt(currentEvents.length) : undefined;
|
|
47
|
+
assertExpectedVersionMatchesCurrent(currentStreamVersion, options?.expectedStreamVersion);
|
|
48
|
+
const eventEnvelopes = events.map((event, index) => {
|
|
49
|
+
return {
|
|
50
|
+
event,
|
|
51
|
+
metadata: {
|
|
52
|
+
eventId: uuid(),
|
|
53
|
+
streamPosition: currentEvents.length + index + 1,
|
|
54
|
+
logPosition: BigInt(getAllEventsCount() + index + 1),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
const positionOfLastEventInTheStream = BigInt(eventEnvelopes.slice(-1)[0].metadata.streamPosition);
|
|
59
|
+
streams.set(streamName, [...currentEvents, ...eventEnvelopes]);
|
|
60
|
+
const result = {
|
|
61
|
+
nextExpectedStreamVersion: positionOfLastEventInTheStream,
|
|
62
|
+
};
|
|
63
|
+
return Promise.resolve(result);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
62
66
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
exports.getInMemoryEventStore = getInMemoryEventStore;
|
|
66
67
|
//# sourceMappingURL=inMemoryEventStore.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/eventStore/inMemoryEventStore.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"inMemoryEventStore.js","sourceRoot":"","sources":["../../src/eventStore/inMemoryEventStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,9 +26,14 @@ const getInMemoryEventStore = () => {
|
|
|
26
26
|
currentStreamVersion,
|
|
27
27
|
options?.expectedStreamVersion
|
|
28
28
|
);
|
|
29
|
+
const from = Number(options && "from" in options ? options.from : 0);
|
|
30
|
+
const to = Number(
|
|
31
|
+
options && "to" in options ? options.to : options && "maxCount" in options && options.maxCount ? options.from + options.maxCount : events?.length ?? 1
|
|
32
|
+
);
|
|
33
|
+
const resultEvents = events && events.length > 0 ? events.map((e) => e.event).slice(from, to) : [];
|
|
29
34
|
const result = events && events.length > 0 ? {
|
|
30
35
|
currentStreamVersion,
|
|
31
|
-
events:
|
|
36
|
+
events: resultEvents
|
|
32
37
|
} : null;
|
|
33
38
|
return Promise.resolve(result);
|
|
34
39
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/eventStore/inMemoryEventStore.ts"],"sourcesContent":["import { v4 as uuid } from 'uuid';\nimport type { Event } from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventMetadata = Readonly<{\n eventId: string;\n streamPosition: number;\n logPosition: bigint;\n}>;\n\nexport type EventEnvelope<E extends Event = Event> = {\n event: E;\n metadata: EventMetadata;\n};\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: EventEnvelope<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore => {\n const streams = new Map<string, EventEnvelope[]>();\n\n const getAllEventsCount = () => {\n return Array.from<EventEnvelope[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, getInitialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, getInitialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const result: ReadStreamResult<EventType> =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events:
|
|
1
|
+
{"version":3,"sources":["../../src/eventStore/inMemoryEventStore.ts"],"sourcesContent":["import { v4 as uuid } from 'uuid';\nimport type { Event } from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventMetadata = Readonly<{\n eventId: string;\n streamPosition: number;\n logPosition: bigint;\n}>;\n\nexport type EventEnvelope<E extends Event = Event> = {\n event: E;\n metadata: EventMetadata;\n};\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: EventEnvelope<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore => {\n const streams = new Map<string, EventEnvelope[]>();\n\n const getAllEventsCount = () => {\n return Array.from<EventEnvelope[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, getInitialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, getInitialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const from = Number(options && 'from' in options ? options.from : 0);\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : events?.length ?? 1,\n );\n\n const resultEvents =\n events && events.length > 0\n ? events.map((e) => e.event as EventType).slice(from, to)\n : [];\n\n const result: ReadStreamResult<EventType> =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events: resultEvents,\n }\n : null;\n\n return Promise.resolve(result);\n },\n\n appendToStream: <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n const currentEvents = streams.get(streamName) ?? [];\n const currentStreamVersion =\n currentEvents.length > 0 ? BigInt(currentEvents.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const eventEnvelopes: EventEnvelope[] = events.map((event, index) => {\n return {\n event,\n metadata: {\n eventId: uuid(),\n streamPosition: currentEvents.length + index + 1,\n logPosition: BigInt(getAllEventsCount() + index + 1),\n },\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n eventEnvelopes.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [...currentEvents, ...eventEnvelopes]);\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n };\n\n return Promise.resolve(result);\n },\n };\n};\n"],"mappings":"AAAA,SAAS,MAAM,YAAY;AAE3B;AAAA,OAQO;AACP,SAAS,2CAA2C;AAiB7C,MAAM,wBAAwB,MAAkB;AACrD,QAAM,UAAU,oBAAI,IAA6B;AAEjD,QAAM,oBAAoB,MAAM;AAC9B,WAAO,MAAM,KAAsB,QAAQ,OAAO,CAAC,EAChD,IAAI,CAAC,MAAM,EAAE,MAAM,EACnB,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL,MAAM,gBACJ,YACA,SAC8C;AAC9C,YAAM,EAAE,QAAQ,iBAAiB,KAAK,IAAI;AAE1C,YAAM,SAAS,MAAM,KAAK,WAAsB,YAAY,IAAI;AAEhE,UAAI,CAAC;AAAQ,eAAO;AAEpB,YAAM,SAAS,QAAQ,UAAU,CAAC;AAElC,aAAO;AAAA,QACL,sBAAsB,OAAO,OAAO,MAAM;AAAA,QAC1C,OAAO,OAAO,OAAO,QAAQ,gBAAgB,CAAC;AAAA,MAChD;AAAA,IACF;AAAA,IAEA,YAAY,CACV,YACA,YACyC;AACzC,YAAM,SAAS,QAAQ,IAAI,UAAU;AACrC,YAAM,uBAAuB,SAAS,OAAO,OAAO,MAAM,IAAI;AAE9D;AAAA,QACE;AAAA,QACA,SAAS;AAAA,MACX;AAEA,YAAM,OAAO,OAAO,WAAW,UAAU,UAAU,QAAQ,OAAO,CAAC;AACnE,YAAM,KAAK;AAAA,QACT,WAAW,QAAQ,UACf,QAAQ,KACR,WAAW,cAAc,WAAW,QAAQ,WAC1C,QAAQ,OAAO,QAAQ,WACvB,QAAQ,UAAU;AAAA,MAC1B;AAEA,YAAM,eACJ,UAAU,OAAO,SAAS,IACtB,OAAO,IAAI,CAAC,MAAM,EAAE,KAAkB,EAAE,MAAM,MAAM,EAAE,IACtD,CAAC;AAEP,YAAM,SACJ,UAAU,OAAO,SAAS,IACtB;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,MACV,IACA;AAEN,aAAO,QAAQ,QAAQ,MAAM;AAAA,IAC/B;AAAA,IAEA,gBAAgB,CACd,YACA,QACA,YACkC;AAClC,YAAM,gBAAgB,QAAQ,IAAI,UAAU,KAAK,CAAC;AAClD,YAAM,uBACJ,cAAc,SAAS,IAAI,OAAO,cAAc,MAAM,IAAI;AAE5D;AAAA,QACE;AAAA,QACA,SAAS;AAAA,MACX;AAEA,YAAM,iBAAkC,OAAO,IAAI,CAAC,OAAO,UAAU;AACnE,eAAO;AAAA,UACL;AAAA,UACA,UAAU;AAAA,YACR,SAAS,KAAK;AAAA,YACd,gBAAgB,cAAc,SAAS,QAAQ;AAAA,YAC/C,aAAa,OAAO,kBAAkB,IAAI,QAAQ,CAAC;AAAA,UACrD;AAAA,QACF;AAAA,MACF,CAAC;AAED,YAAM,iCAAiC;AAAA,QACrC,eAAe,MAAM,EAAE,EAAE,CAAC,EAAG,SAAS;AAAA,MACxC;AAEA,cAAQ,IAAI,YAAY,CAAC,GAAG,eAAe,GAAG,cAAc,CAAC;AAE7D,YAAM,SAA+B;AAAA,QACnC,2BAA2B;AAAA,MAC7B;AAEA,aAAO,QAAQ,QAAQ,MAAM;AAAA,IAC/B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-floating-promises */
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import { getInMemoryEventStore } from '../eventStore';
|
|
6
|
+
import {} from '../typing';
|
|
7
|
+
const evolve = (state, { type, data }) => {
|
|
8
|
+
switch (type) {
|
|
9
|
+
case 'ProductItemAdded': {
|
|
10
|
+
const productItem = data.productItem;
|
|
11
|
+
return {
|
|
12
|
+
productItems: [...state.productItems, productItem],
|
|
13
|
+
totalAmount: state.totalAmount + productItem.price * productItem.quantity,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
case 'DiscountApplied':
|
|
17
|
+
return {
|
|
18
|
+
...state,
|
|
19
|
+
totalAmount: state.totalAmount * (1 - data.percent),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const getInitialState = () => {
|
|
24
|
+
return { productItems: [], totalAmount: 0 };
|
|
25
|
+
};
|
|
26
|
+
describe('InMemoryEventStore', () => {
|
|
27
|
+
const eventStore = getInMemoryEventStore();
|
|
28
|
+
describe('aggregateStream', () => {
|
|
29
|
+
it('When called with `to` allows time travelling', async () => {
|
|
30
|
+
// Given
|
|
31
|
+
const productItem = {
|
|
32
|
+
productId: '123',
|
|
33
|
+
quantity: 10,
|
|
34
|
+
price: 3,
|
|
35
|
+
};
|
|
36
|
+
const discount = 10;
|
|
37
|
+
const shoppingCartId = randomUUID();
|
|
38
|
+
await eventStore.appendToStream(shoppingCartId, [
|
|
39
|
+
{ type: 'ProductItemAdded', data: { productItem } },
|
|
40
|
+
]);
|
|
41
|
+
await eventStore.appendToStream(shoppingCartId, [
|
|
42
|
+
{ type: 'ProductItemAdded', data: { productItem } },
|
|
43
|
+
]);
|
|
44
|
+
await eventStore.appendToStream(shoppingCartId, [
|
|
45
|
+
{ type: 'DiscountApplied', data: { percent: discount } },
|
|
46
|
+
]);
|
|
47
|
+
// when
|
|
48
|
+
const resultAt1 = await eventStore.aggregateStream(shoppingCartId, {
|
|
49
|
+
evolve,
|
|
50
|
+
getInitialState,
|
|
51
|
+
read: { to: 1n },
|
|
52
|
+
});
|
|
53
|
+
const resultAt2 = await eventStore.aggregateStream(shoppingCartId, {
|
|
54
|
+
evolve,
|
|
55
|
+
getInitialState,
|
|
56
|
+
read: { to: 2n },
|
|
57
|
+
});
|
|
58
|
+
const resultAt3 = await eventStore.aggregateStream(shoppingCartId, {
|
|
59
|
+
evolve,
|
|
60
|
+
getInitialState,
|
|
61
|
+
read: { to: 3n },
|
|
62
|
+
});
|
|
63
|
+
// then
|
|
64
|
+
assert.ok(resultAt1);
|
|
65
|
+
assert.ok(resultAt2);
|
|
66
|
+
assert.ok(resultAt3);
|
|
67
|
+
assert.equal(resultAt1.currentStreamVersion, 1);
|
|
68
|
+
assert.deepEqual(resultAt1.state, {
|
|
69
|
+
productItems: [productItem],
|
|
70
|
+
totalAmount: productItem.price * productItem.quantity,
|
|
71
|
+
});
|
|
72
|
+
assert.equal(resultAt2.currentStreamVersion, 2);
|
|
73
|
+
assert.deepEqual(resultAt2.state, {
|
|
74
|
+
productItems: [productItem, productItem],
|
|
75
|
+
totalAmount: productItem.price * productItem.quantity * 2,
|
|
76
|
+
});
|
|
77
|
+
assert.equal(resultAt3.currentStreamVersion, 3);
|
|
78
|
+
assert.deepEqual(resultAt3.state, {
|
|
79
|
+
productItems: [productItem, productItem],
|
|
80
|
+
totalAmount: productItem.price * productItem.quantity * 2 * (1 - discount),
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=inMemoryEventStore.unit.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inMemoryEventStore.unit.spec.js","sourceRoot":"","sources":["../../src/eventStore/inMemoryEventStore.unit.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { describe, it } from "node:test";
|
|
4
|
+
import { getInMemoryEventStore } from "../eventStore";
|
|
5
|
+
import {} from "../typing";
|
|
6
|
+
const evolve = (state, { type, data }) => {
|
|
7
|
+
switch (type) {
|
|
8
|
+
case "ProductItemAdded": {
|
|
9
|
+
const productItem = data.productItem;
|
|
10
|
+
return {
|
|
11
|
+
productItems: [...state.productItems, productItem],
|
|
12
|
+
totalAmount: state.totalAmount + productItem.price * productItem.quantity
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
case "DiscountApplied":
|
|
16
|
+
return {
|
|
17
|
+
...state,
|
|
18
|
+
totalAmount: state.totalAmount * (1 - data.percent)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const getInitialState = () => {
|
|
23
|
+
return { productItems: [], totalAmount: 0 };
|
|
24
|
+
};
|
|
25
|
+
describe("InMemoryEventStore", () => {
|
|
26
|
+
const eventStore = getInMemoryEventStore();
|
|
27
|
+
describe("aggregateStream", () => {
|
|
28
|
+
it("When called with `to` allows time travelling", async () => {
|
|
29
|
+
const productItem = {
|
|
30
|
+
productId: "123",
|
|
31
|
+
quantity: 10,
|
|
32
|
+
price: 3
|
|
33
|
+
};
|
|
34
|
+
const discount = 10;
|
|
35
|
+
const shoppingCartId = randomUUID();
|
|
36
|
+
await eventStore.appendToStream(shoppingCartId, [
|
|
37
|
+
{ type: "ProductItemAdded", data: { productItem } }
|
|
38
|
+
]);
|
|
39
|
+
await eventStore.appendToStream(shoppingCartId, [
|
|
40
|
+
{ type: "ProductItemAdded", data: { productItem } }
|
|
41
|
+
]);
|
|
42
|
+
await eventStore.appendToStream(shoppingCartId, [
|
|
43
|
+
{ type: "DiscountApplied", data: { percent: discount } }
|
|
44
|
+
]);
|
|
45
|
+
const resultAt1 = await eventStore.aggregateStream(shoppingCartId, {
|
|
46
|
+
evolve,
|
|
47
|
+
getInitialState,
|
|
48
|
+
read: { to: 1n }
|
|
49
|
+
});
|
|
50
|
+
const resultAt2 = await eventStore.aggregateStream(shoppingCartId, {
|
|
51
|
+
evolve,
|
|
52
|
+
getInitialState,
|
|
53
|
+
read: { to: 2n }
|
|
54
|
+
});
|
|
55
|
+
const resultAt3 = await eventStore.aggregateStream(shoppingCartId, {
|
|
56
|
+
evolve,
|
|
57
|
+
getInitialState,
|
|
58
|
+
read: { to: 3n }
|
|
59
|
+
});
|
|
60
|
+
assert.ok(resultAt1);
|
|
61
|
+
assert.ok(resultAt2);
|
|
62
|
+
assert.ok(resultAt3);
|
|
63
|
+
assert.equal(resultAt1.currentStreamVersion, 1);
|
|
64
|
+
assert.deepEqual(resultAt1.state, {
|
|
65
|
+
productItems: [productItem],
|
|
66
|
+
totalAmount: productItem.price * productItem.quantity
|
|
67
|
+
});
|
|
68
|
+
assert.equal(resultAt2.currentStreamVersion, 2);
|
|
69
|
+
assert.deepEqual(resultAt2.state, {
|
|
70
|
+
productItems: [productItem, productItem],
|
|
71
|
+
totalAmount: productItem.price * productItem.quantity * 2
|
|
72
|
+
});
|
|
73
|
+
assert.equal(resultAt3.currentStreamVersion, 3);
|
|
74
|
+
assert.deepEqual(resultAt3.state, {
|
|
75
|
+
productItems: [productItem, productItem],
|
|
76
|
+
totalAmount: productItem.price * productItem.quantity * 2 * (1 - discount)
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=inMemoryEventStore.unit.spec.mjs.map
|