@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.
Files changed (82) hide show
  1. package/dist/commandHandling/handleCommand.d.mts +6 -3
  2. package/dist/commandHandling/handleCommand.d.ts +6 -3
  3. package/dist/commandHandling/handleCommand.js +33 -29
  4. package/dist/commandHandling/handleCommand.js.map +1 -1
  5. package/dist/commandHandling/handleCommand.mjs +4 -2
  6. package/dist/commandHandling/handleCommand.mjs.map +1 -1
  7. package/dist/commandHandling/handleCommand.unit.spec.js +83 -0
  8. package/dist/commandHandling/handleCommand.unit.spec.js.map +1 -0
  9. package/dist/commandHandling/handleCommand.unit.spec.mjs +93 -0
  10. package/dist/commandHandling/handleCommand.unit.spec.mjs.map +1 -0
  11. package/dist/commandHandling/handleCommandWithDecider.d.mts +3 -2
  12. package/dist/commandHandling/handleCommandWithDecider.d.ts +3 -2
  13. package/dist/commandHandling/handleCommandWithDecider.js +4 -13
  14. package/dist/commandHandling/handleCommandWithDecider.js.map +1 -1
  15. package/dist/commandHandling/index.d.mts +1 -1
  16. package/dist/commandHandling/index.d.ts +1 -1
  17. package/dist/commandHandling/index.js +2 -2
  18. package/dist/commandHandling/index.js.map +1 -1
  19. package/dist/errors/index.js +67 -51
  20. package/dist/errors/index.js.map +1 -1
  21. package/dist/eventStore/eventStore.js +2 -1
  22. package/dist/eventStore/eventStore.js.map +1 -1
  23. package/dist/eventStore/expectedVersion.js +22 -29
  24. package/dist/eventStore/expectedVersion.js.map +1 -1
  25. package/dist/eventStore/expectedVersion.unit.spec.js +48 -60
  26. package/dist/eventStore/expectedVersion.unit.spec.js.map +1 -1
  27. package/dist/eventStore/inMemoryEventStore.js +65 -64
  28. package/dist/eventStore/inMemoryEventStore.js.map +1 -1
  29. package/dist/eventStore/inMemoryEventStore.mjs +6 -1
  30. package/dist/eventStore/inMemoryEventStore.mjs.map +1 -1
  31. package/dist/eventStore/inMemoryEventStore.unit.spec.d.mts +2 -0
  32. package/dist/eventStore/inMemoryEventStore.unit.spec.d.ts +2 -0
  33. package/dist/eventStore/inMemoryEventStore.unit.spec.js +85 -0
  34. package/dist/eventStore/inMemoryEventStore.unit.spec.js.map +1 -0
  35. package/dist/eventStore/inMemoryEventStore.unit.spec.mjs +81 -0
  36. package/dist/eventStore/inMemoryEventStore.unit.spec.mjs.map +1 -0
  37. package/dist/eventStore/index.js +3 -3
  38. package/dist/eventStore/index.js.map +1 -1
  39. package/dist/index.d.mts +1 -1
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.js +8 -8
  42. package/dist/index.js.map +1 -1
  43. package/dist/serialization/index.js +1 -1
  44. package/dist/serialization/index.js.map +1 -1
  45. package/dist/serialization/json/JSONParser.js +16 -20
  46. package/dist/serialization/json/JSONParser.js.map +1 -1
  47. package/dist/serialization/json/index.js +1 -1
  48. package/dist/serialization/json/index.js.map +1 -1
  49. package/dist/testing/assertions.js +12 -24
  50. package/dist/testing/assertions.js.map +1 -1
  51. package/dist/testing/deciderSpecification.js +40 -39
  52. package/dist/testing/deciderSpecification.js.map +1 -1
  53. package/dist/testing/index.js +2 -2
  54. package/dist/testing/index.js.map +1 -1
  55. package/dist/typing/command.js +2 -1
  56. package/dist/typing/command.js.map +1 -1
  57. package/dist/typing/decider.js +2 -1
  58. package/dist/typing/decider.js.map +1 -1
  59. package/dist/typing/event.js +2 -1
  60. package/dist/typing/event.js.map +1 -1
  61. package/dist/typing/index.js +4 -4
  62. package/dist/typing/index.js.map +1 -1
  63. package/dist/typing/workflow.d.ts +57 -1
  64. package/dist/typing/workflow.js +45 -55
  65. package/dist/typing/workflow.js.map +1 -1
  66. package/dist/utils/index.js +3 -6
  67. package/dist/utils/index.js.map +1 -1
  68. package/dist/utils/iterators.js +8 -10
  69. package/dist/utils/iterators.js.map +1 -1
  70. package/dist/utils/merge.js +27 -21
  71. package/dist/utils/merge.js.map +1 -1
  72. package/dist/validation/index.js +25 -33
  73. package/dist/validation/index.js.map +1 -1
  74. package/dist/validation/validation.spec.js +14 -10
  75. package/dist/validation/validation.spec.js.map +1 -1
  76. package/package.json +1 -1
  77. package/dist/testing/placeholder.e2e.spec.js +0 -8
  78. package/dist/testing/placeholder.e2e.spec.js.map +0 -1
  79. package/dist/testing/placeholder.e2e.spec.mjs +0 -8
  80. package/dist/testing/placeholder.e2e.spec.mjs.map +0 -1
  81. /package/dist/{testing/placeholder.e2e.spec.d.mts → commandHandling/handleCommand.unit.spec.d.mts} +0 -0
  82. /package/dist/{testing/placeholder.e2e.spec.d.ts → commandHandling/handleCommand.unit.spec.d.ts} +0 -0
@@ -1,33 +1,26 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _errors = require('../errors');
2
- const STREAM_EXISTS = "STREAM_EXISTS";
3
- const STREAM_DOES_NOT_EXIST = "STREAM_DOES_NOT_EXIST";
4
- const NO_CONCURRENCY_CHECK = "NO_CONCURRENCY_CHECK";
5
- const matchesExpectedVersion = (current, expected) => {
6
- if (expected === NO_CONCURRENCY_CHECK)
7
- return true;
8
- if (expected == STREAM_DOES_NOT_EXIST)
9
- return current === void 0;
10
- if (expected == STREAM_EXISTS)
11
- return current !== void 0;
12
- return current === expected;
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
- expected ??= NO_CONCURRENCY_CHECK;
16
- if (!matchesExpectedVersion(current, expected))
17
- throw new ExpectedVersionConflictError(current, expected);
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 _errors.ConcurrencyError {
20
- constructor(current, expected) {
21
- super(_optionalChain([current, 'optionalAccess', _ => _.toString, 'call', _2 => _2()]), _optionalChain([expected, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]));
22
- Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);
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,SAAS,wBAAwB;AAiB1B,MAAM,gBAAgB;AACtB,MAAM,wBACX;AACK,MAAM,uBACX;AAEK,MAAM,yBAAyB,CAGpC,SACA,aACY;AACZ,MAAI,aAAa;AAAsB,WAAO;AAE9C,MAAI,YAAY;AAAuB,WAAO,YAAY;AAE1D,MAAI,YAAY;AAAe,WAAO,YAAY;AAElD,SAAO,YAAY;AACrB;AAEO,MAAM,sCAAsC,CAGjD,SACA,aACS;AACT,eAAa;AAEb,MAAI,CAAC,uBAAuB,SAAS,QAAQ;AAC3C,UAAM,IAAI,6BAA6B,SAAS,QAAQ;AAC5D;AAEO,MAAM,qCAEH,iBAAiB;AAAA,EACzB,YACE,SACA,UACA;AACA,UAAM,SAAS,SAAS,GAAG,UAAU,SAAS,CAAC;AAG/C,WAAO,eAAe,MAAM,6BAA6B,SAAS;AAAA,EACpE;AACF","sourcesContent":["import { ConcurrencyError } from '../errors';\nimport type { Flavour } from '../typing';\nimport type { DefaultStreamVersionType } from './eventStore';\n\nexport type ExpectedStreamVersion<VersionType = DefaultStreamVersionType> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<\n VersionType = DefaultStreamVersionType,\n> = Flavour<VersionType, 'StreamVersion'>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError<\n VersionType = DefaultStreamVersionType,\n> extends ConcurrencyError {\n constructor(\n current: VersionType | undefined,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n"]}
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
- "use strict"; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var _strict = require('node:assert/strict'); var _strict2 = _interopRequireDefault(_strict);
2
- var _nodetest = require('node:test');
3
-
4
-
5
-
6
-
7
-
8
- var _expectedVersion = require('./expectedVersion');
9
- _nodetest.describe.call(void 0, "matchesExpectedVersion", () => {
10
- _nodetest.it.call(void 0, "When NO_CONCURRENCY_CHECK provided returns `true` for any current version", () => {
11
- const allCurrentVersions = [void 0, 0, -1, 1, 100, "random", ""];
12
- for (const currentStreamVersion of allCurrentVersions) {
13
- _strict2.default.ok(
14
- _expectedVersion.matchesExpectedVersion.call(void 0, currentStreamVersion, _expectedVersion.NO_CONCURRENCY_CHECK)
15
- );
16
- }
17
- });
18
- _nodetest.it.call(void 0, "When STREAM_DOES_NOT_EXIST provided returns `true` for current equals `undefined`", () => {
19
- _strict2.default.ok(_expectedVersion.matchesExpectedVersion.call(void 0, void 0, _expectedVersion.STREAM_DOES_NOT_EXIST));
20
- });
21
- _nodetest.it.call(void 0, "When STREAM_DOES_NOT_EXIST provided returns `false` for current different than `undefined`", () => {
22
- const definedStreamVersion = [0, -1, 1, 100, "random", ""];
23
- for (const currentStreamVersion of definedStreamVersion) {
24
- _strict2.default.equal(
25
- _expectedVersion.matchesExpectedVersion.call(void 0, currentStreamVersion, _expectedVersion.STREAM_DOES_NOT_EXIST),
26
- false
27
- );
28
- }
29
- });
30
- _nodetest.it.call(void 0, "When STREAM_EXISTS provided returns `true` for current different than `undefined`", () => {
31
- const definedStreamVersion = [0, -1, 1, 100, "random", ""];
32
- for (const currentStreamVersion of definedStreamVersion) {
33
- _strict2.default.ok(_expectedVersion.matchesExpectedVersion.call(void 0, currentStreamVersion, _expectedVersion.STREAM_EXISTS));
34
- }
35
- });
36
- _nodetest.it.call(void 0, "When STREAM_EXISTS provided returns `false` for current equals `undefined`", () => {
37
- _strict2.default.equal(_expectedVersion.matchesExpectedVersion.call(void 0, void 0, _expectedVersion.STREAM_EXISTS), false);
38
- });
39
- _nodetest.it.call(void 0, "When value provided returns `true` for current matching expected value", () => {
40
- const definedStreamVersion = [0, -1, 1, 100, "random", ""];
41
- for (const streamVersion of definedStreamVersion) {
42
- _strict2.default.ok(_expectedVersion.matchesExpectedVersion.call(void 0, streamVersion, streamVersion));
43
- }
44
- });
45
- _nodetest.it.call(void 0, "When value provided returns `false` for current notmatching expected value", () => {
46
- const definedStreamVersion = [
47
- { current: 100, expected: 0 },
48
- { current: 0, expected: -1 },
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":"AACA,OAAO,YAAY;AACnB,SAAS,UAAU,UAAU;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,0BAA0B,MAAM;AACvC,KAAG,6EAA6E,MAAM;AACpF,UAAM,qBAAqB,CAAC,QAAW,GAAG,IAAI,GAAG,KAAK,UAAU,EAAE;AAElE,eAAW,wBAAwB,oBAAoB;AACrD,aAAO;AAAA,QACL,uBAAuB,sBAAsB,oBAAoB;AAAA,MACnE;AAAA,IACF;AAAA,EACF,CAAC;AAED,KAAG,qFAAqF,MAAM;AAC5F,WAAO,GAAG,uBAAuB,QAAW,qBAAqB,CAAC;AAAA,EACpE,CAAC;AAED,KAAG,8FAA8F,MAAM;AACrG,UAAM,uBAAuB,CAAC,GAAG,IAAI,GAAG,KAAK,UAAU,EAAE;AAEzD,eAAW,wBAAwB,sBAAsB;AACvD,aAAO;AAAA,QACL,uBAAuB,sBAAsB,qBAAqB;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,KAAG,qFAAqF,MAAM;AAC5F,UAAM,uBAAuB,CAAC,GAAG,IAAI,GAAG,KAAK,UAAU,EAAE;AAEzD,eAAW,wBAAwB,sBAAsB;AACvD,aAAO,GAAG,uBAAuB,sBAAsB,aAAa,CAAC;AAAA,IACvE;AAAA,EACF,CAAC;AAED,KAAG,8EAA8E,MAAM;AACrF,WAAO,MAAM,uBAAuB,QAAW,aAAa,GAAG,KAAK;AAAA,EACtE,CAAC;AAED,KAAG,0EAA0E,MAAM;AACjF,UAAM,uBAAuB,CAAC,GAAG,IAAI,GAAG,KAAK,UAAU,EAAE;AAEzD,eAAW,iBAAiB,sBAAsB;AAChD,aAAO,GAAG,uBAAuB,eAAe,aAAa,CAAC;AAAA,IAChE;AAAA,EACF,CAAC;AAED,KAAG,8EAA8E,MAAM;AACrF,UAAM,uBAAuB;AAAA,MAC3B,EAAE,SAAS,KAAK,UAAU,EAAE;AAAA,MAC5B,EAAE,SAAS,GAAG,UAAU,GAAG;AAAA,MAC3B,EAAE,SAAS,IAAI,UAAU,EAAE;AAAA,MAC3B,EAAE,SAAS,GAAG,UAAU,IAAI;AAAA,MAC5B,EAAE,SAAS,IAAI,UAAU,SAAS;AAAA,MAClC,EAAE,SAAS,UAAU,UAAU,GAAG;AAAA,IACpC;AAEA,eAAW,iBAAiB,sBAAsB;AAChD,aAAO;AAAA,QACL,uBAAuB,cAAc,SAAS,cAAc,QAAQ;AAAA,QACpE;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-floating-promises */\nimport assert from 'node:assert/strict';\nimport { describe, it } from 'node:test';\nimport {\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n matchesExpectedVersion,\n} from './expectedVersion';\n\ndescribe('matchesExpectedVersion', () => {\n it('When NO_CONCURRENCY_CHECK provided returns `true` for any current version', () => {\n const allCurrentVersions = [undefined, 0, -1, 1, 100, 'random', ''];\n\n for (const currentStreamVersion of allCurrentVersions) {\n assert.ok(\n matchesExpectedVersion(currentStreamVersion, NO_CONCURRENCY_CHECK),\n );\n }\n });\n\n it('When STREAM_DOES_NOT_EXIST provided returns `true` for current equals `undefined`', () => {\n assert.ok(matchesExpectedVersion(undefined, STREAM_DOES_NOT_EXIST));\n });\n\n it('When STREAM_DOES_NOT_EXIST provided returns `false` for current different than `undefined`', () => {\n const definedStreamVersion = [0, -1, 1, 100, 'random', ''];\n\n for (const currentStreamVersion of definedStreamVersion) {\n assert.equal(\n matchesExpectedVersion(currentStreamVersion, STREAM_DOES_NOT_EXIST),\n false,\n );\n }\n });\n\n it('When STREAM_EXISTS provided returns `true` for current different than `undefined`', () => {\n const definedStreamVersion = [0, -1, 1, 100, 'random', ''];\n\n for (const currentStreamVersion of definedStreamVersion) {\n assert.ok(matchesExpectedVersion(currentStreamVersion, STREAM_EXISTS));\n }\n });\n\n it('When STREAM_EXISTS provided returns `false` for current equals `undefined`', () => {\n assert.equal(matchesExpectedVersion(undefined, STREAM_EXISTS), false);\n });\n\n it('When value provided returns `true` for current matching expected value', () => {\n const definedStreamVersion = [0, -1, 1, 100, 'random', ''];\n\n for (const streamVersion of definedStreamVersion) {\n assert.ok(matchesExpectedVersion(streamVersion, streamVersion));\n }\n });\n\n it('When value provided returns `false` for current notmatching expected value', () => {\n const definedStreamVersion = [\n { current: 100, expected: 0 },\n { current: 0, expected: -1 },\n { current: -1, expected: 1 },\n { current: 0, expected: 100 },\n { current: '', expected: 'random' },\n { current: 'random', expected: '' },\n ];\n\n for (const streamVersion of definedStreamVersion) {\n assert.equal(\n matchesExpectedVersion(streamVersion.current, streamVersion.expected),\n false,\n );\n }\n });\n});\n"]}
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
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _uuid = require('uuid');
2
-
3
- require('./eventStore');
4
- var _expectedVersion = require('./expectedVersion');
5
- const getInMemoryEventStore = () => {
6
- const streams = /* @__PURE__ */ new Map();
7
- const getAllEventsCount = () => {
8
- return Array.from(streams.values()).map((s) => s.length).reduce((p, c) => p + c, 0);
9
- };
10
- return {
11
- async aggregateStream(streamName, options) {
12
- const { evolve, getInitialState, read } = options;
13
- const result = await this.readStream(streamName, read);
14
- if (!result)
15
- return null;
16
- const events = _nullishCoalesce(_optionalChain([result, 'optionalAccess', _ => _.events]), () => ( []));
17
- return {
18
- currentStreamVersion: BigInt(events.length),
19
- state: events.reduce(evolve, getInitialState())
20
- };
21
- },
22
- readStream: (streamName, options) => {
23
- const events = streams.get(streamName);
24
- const currentStreamVersion = events ? BigInt(events.length) : void 0;
25
- _expectedVersion.assertExpectedVersionMatchesCurrent.call(void 0,
26
- currentStreamVersion,
27
- _optionalChain([options, 'optionalAccess', _2 => _2.expectedStreamVersion])
28
- );
29
- const result = events && events.length > 0 ? {
30
- currentStreamVersion,
31
- events: events.map((e) => e.event)
32
- } : null;
33
- return Promise.resolve(result);
34
- },
35
- appendToStream: (streamName, events, options) => {
36
- const currentEvents = _nullishCoalesce(streams.get(streamName), () => ( []));
37
- const currentStreamVersion = currentEvents.length > 0 ? BigInt(currentEvents.length) : void 0;
38
- _expectedVersion.assertExpectedVersionMatchesCurrent.call(void 0,
39
- currentStreamVersion,
40
- _optionalChain([options, 'optionalAccess', _3 => _3.expectedStreamVersion])
41
- );
42
- const eventEnvelopes = events.map((event, index) => {
43
- return {
44
- event,
45
- metadata: {
46
- eventId: _uuid.v4.call(void 0, ),
47
- streamPosition: currentEvents.length + index + 1,
48
- logPosition: BigInt(getAllEventsCount() + index + 1)
49
- }
50
- };
51
- });
52
- const positionOfLastEventInTheStream = BigInt(
53
- eventEnvelopes.slice(-1)[0].metadata.streamPosition
54
- );
55
- streams.set(streamName, [...currentEvents, ...eventEnvelopes]);
56
- const result = {
57
- nextExpectedStreamVersion: positionOfLastEventInTheStream
58
- };
59
- return Promise.resolve(result);
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,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,SACJ,UAAU,OAAO,SAAS,IACtB;AAAA,QACE;AAAA,QACA,QAAQ,OAAO,IAAI,CAAC,MAAM,EAAE,KAAkB;AAAA,MAChD,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","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: events.map((e) => e.event as EventType),\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"]}
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: events.map((e) => e.event)
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: events.map((e) => e.event as EventType),\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,SACJ,UAAU,OAAO,SAAS,IACtB;AAAA,QACE;AAAA,QACA,QAAQ,OAAO,IAAI,CAAC,MAAM,EAAE,KAAkB;AAAA,MAChD,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":[]}
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,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -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