event-store-adapter-js 3.0.1 → 3.0.2-snapshot.2
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/README.ja.md +83 -39
- package/README.md +83 -39
- package/dist/aggregate-id.d.ts +3 -4
- package/dist/aggregate.d.ts +2 -2
- package/dist/dynamodb-event-store-input.d.ts +2 -2
- package/dist/event-serializer.d.ts +2 -2
- package/dist/event-store-error.d.ts +25 -0
- package/dist/event-store-error.js +43 -0
- package/dist/event-store.d.ts +9 -11
- package/dist/event-store.js +16 -11
- package/dist/event.d.ts +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/internal/default-serializer.d.ts +5 -5
- package/dist/internal/default-serializer.js +32 -29
- package/dist/internal/default-shard-selector.d.ts +3 -7
- package/dist/internal/default-shard-selector.js +24 -25
- package/dist/internal/dynamodb-aggregate-key.d.ts +10 -10
- package/dist/internal/dynamodb-aggregate-key.js +12 -19
- package/dist/internal/dynamodb-event-store.d.ts +2 -33
- package/dist/internal/dynamodb-event-store.js +230 -198
- package/dist/internal/dynamodb-snapshot-retention-executor.d.ts +4 -25
- package/dist/internal/dynamodb-snapshot-retention-executor.js +48 -53
- package/dist/internal/event-store-assertions.d.ts +3 -2
- package/dist/internal/event-store-assertions.js +8 -1
- package/dist/internal/json-converter.js +10 -7
- package/dist/internal/memory-event-store.d.ts +2 -14
- package/dist/internal/memory-event-store.js +91 -102
- package/dist/internal/spanner-aggregate-key.d.ts +9 -9
- package/dist/internal/spanner-aggregate-key.js +9 -16
- package/dist/internal/spanner-event-store.d.ts +2 -43
- package/dist/internal/spanner-event-store.js +229 -176
- package/dist/logger.d.ts +2 -2
- package/dist/memory-event-store-input.d.ts +2 -2
- package/dist/result.d.ts +11 -0
- package/dist/result.js +21 -0
- package/dist/shard-count.d.ts +5 -4
- package/dist/shard-count.js +11 -6
- package/dist/shard-id.d.ts +5 -4
- package/dist/shard-id.js +11 -6
- package/dist/shard-selector.d.ts +2 -2
- package/dist/snapshot-serializer.d.ts +2 -2
- package/dist/spanner-event-store-input.d.ts +2 -2
- package/dist/types.d.ts +4 -3
- package/dist/types.js +17 -7
- package/docs/GCP_EVENT_INTEGRATION.ja.md +3 -3
- package/docs/MIGRATION_GUIDE_3.0.ja.md +12 -6
- package/docs/MIGRATION_GUIDE_3.0.md +12 -6
- package/docs/MIGRATION_GUIDE_4.0.ja.md +141 -0
- package/docs/MIGRATION_GUIDE_4.0.md +141 -0
- package/docs/SPANNER_DATABASE_SCHEMA.ja.md +1 -1
- package/docs/SPANNER_DATABASE_SCHEMA.md +1 -1
- package/package.json +1 -1
- package/dist/aggregate-id-value.d.ts +0 -7
- package/dist/aggregate-id-value.js +0 -9
- package/dist/optimistic-lock-error.d.ts +0 -4
- package/dist/optimistic-lock-error.js +0 -10
package/README.ja.md
CHANGED
|
@@ -21,44 +21,33 @@ npm install event-store-adapter-js
|
|
|
21
21
|
EventStoreを使えば、Event Sourcing対応リポジトリを簡単に実装できます。
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
UserAccountEvent
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (snapshot === undefined) {
|
|
46
|
-
return undefined;
|
|
47
|
-
} else {
|
|
48
|
-
const events = await this.eventStore.getEventsByIdSinceSequenceNumber(
|
|
49
|
-
id,
|
|
50
|
-
snapshot.sequenceNumber + 1,
|
|
51
|
-
);
|
|
52
|
-
return UserAccount.replay(events, snapshot);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
24
|
+
const UserAccountRepository = Object.freeze({
|
|
25
|
+
create(eventStore: EventStore<UserAccountId, UserAccount, UserAccountEvent>) {
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
storeEvent: (event: UserAccountEvent, version: number) =>
|
|
28
|
+
eventStore.persistEvent(event, version),
|
|
29
|
+
storeEventAndSnapshot: (event: UserAccountEvent, snapshot: UserAccount) =>
|
|
30
|
+
eventStore.persistEventAndSnapshot(event, snapshot),
|
|
31
|
+
async findById(id: UserAccountId): Promise<UserAccount | undefined> {
|
|
32
|
+
const snapshot = await eventStore.getLatestSnapshotById(id);
|
|
33
|
+
if (snapshot === undefined) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const events = await eventStore.getEventsByIdSinceSequenceNumber(
|
|
37
|
+
id,
|
|
38
|
+
snapshot.sequenceNumber + 1,
|
|
39
|
+
);
|
|
40
|
+
return UserAccount.replay(events, snapshot);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
});
|
|
56
45
|
```
|
|
57
46
|
|
|
58
47
|
以下はリポジトリの使用例です。
|
|
59
48
|
|
|
60
49
|
```typescript
|
|
61
|
-
const eventStore = EventStore.
|
|
50
|
+
const eventStore = EventStore.createDynamoDB<
|
|
62
51
|
UserAccountId,
|
|
63
52
|
UserAccount,
|
|
64
53
|
UserAccountEvent
|
|
@@ -74,9 +63,9 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
74
63
|
snapshotConverter: convertJSONToUserAccount,
|
|
75
64
|
});
|
|
76
65
|
// if you want to use in-memory event store, use the following code.
|
|
77
|
-
// const eventStore = EventStore.
|
|
66
|
+
// const eventStore = EventStore.createMemory<UserAccountId, UserAccount, UserAccountEvent>({});
|
|
78
67
|
// Cloud Spannerを使う場合は、呼び出し側で管理するDatabaseを渡します。
|
|
79
|
-
// const eventStore = EventStore.
|
|
68
|
+
// const eventStore = EventStore.createSpanner<UserAccountId, UserAccount, UserAccountEvent>({
|
|
80
69
|
// database: spannerDatabase,
|
|
81
70
|
// journalTableName: "journal",
|
|
82
71
|
// snapshotTableName: "snapshot",
|
|
@@ -85,17 +74,23 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
85
74
|
// snapshotConverter: convertJSONToUserAccount,
|
|
86
75
|
// });
|
|
87
76
|
|
|
88
|
-
const userAccountRepository =
|
|
77
|
+
const userAccountRepository = UserAccountRepository.create(eventStore);
|
|
89
78
|
|
|
90
|
-
const id =
|
|
79
|
+
const id = UserAccountId.create(ulid());
|
|
91
80
|
const name = "Alice";
|
|
92
81
|
const [userAccount1, created] = UserAccount.create(id, name);
|
|
93
82
|
|
|
94
|
-
await userAccountRepository.storeEventAndSnapshot(created, userAccount1);
|
|
83
|
+
const createdResult = await userAccountRepository.storeEventAndSnapshot(created, userAccount1);
|
|
84
|
+
if (createdResult.type === "err") {
|
|
85
|
+
throw new Error(createdResult.error.message);
|
|
86
|
+
}
|
|
95
87
|
|
|
96
88
|
const [userAccount2, renamed] = userAccount1.rename("Bob");
|
|
97
89
|
|
|
98
|
-
await userAccountRepository.storeEvent(renamed, userAccount2.version);
|
|
90
|
+
const renamedResult = await userAccountRepository.storeEvent(renamed, userAccount2.version);
|
|
91
|
+
if (renamedResult.type === "err") {
|
|
92
|
+
throw new Error(renamedResult.error.message);
|
|
93
|
+
}
|
|
99
94
|
|
|
100
95
|
const userAccount3 = await userAccountRepository.findById(id);
|
|
101
96
|
if (userAccount3 === undefined) {
|
|
@@ -108,6 +103,55 @@ expect(userAccount3.sequenceNumber).toEqual(2);
|
|
|
108
103
|
expect(userAccount3.version).toEqual(2);
|
|
109
104
|
```
|
|
110
105
|
|
|
106
|
+
## runtime brand と JSON 変換
|
|
107
|
+
|
|
108
|
+
サンプルのドメイン値は module-private な `unique symbol` brand を使い、
|
|
109
|
+
プロセス内で factory が生成した値と plain object を区別します。`typeName`
|
|
110
|
+
は JSON 境界の discriminant として残し、symbol brand は serialize されない
|
|
111
|
+
ため factory で復元します。
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const USER_ACCOUNT_ID_BRAND: unique symbol = Symbol("UserAccountId");
|
|
115
|
+
|
|
116
|
+
type UserAccountId = AggregateId & {
|
|
117
|
+
typeName: "user-account";
|
|
118
|
+
readonly [USER_ACCOUNT_ID_BRAND]: true;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
namespace UserAccountId {
|
|
122
|
+
export function create(value: string): UserAccountId {
|
|
123
|
+
return Object.freeze({
|
|
124
|
+
[USER_ACCOUNT_ID_BRAND]: true,
|
|
125
|
+
typeName: "user-account",
|
|
126
|
+
value,
|
|
127
|
+
asString: () => `user-account-${value}`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function is(value: unknown): value is UserAccountId {
|
|
132
|
+
return (
|
|
133
|
+
typeof value === "object" &&
|
|
134
|
+
value !== null &&
|
|
135
|
+
(value as Partial<UserAccountId>)[USER_ACCOUNT_ID_BRAND] === true
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function toJSON(value: UserAccountId) {
|
|
140
|
+
return { typeName: value.typeName, value: value.value };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function fromJSON(json: { typeName: "user-account"; value: string }) {
|
|
144
|
+
return create(json.value);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`JSON.stringify(...)` 後は symbol brand が消えます。EventStore の converter
|
|
150
|
+
ではドメイン側の `fromJSON(...)` を呼び、deserialize した event / snapshot
|
|
151
|
+
を再び branded value にしてください。`EventSerializer` と
|
|
152
|
+
`SnapshotSerializer` の API は変更せず、`deserialize(bytes, converter)` の
|
|
153
|
+
契約どおり converter にドメイン復元を委ねます。
|
|
154
|
+
|
|
111
155
|
## 開発
|
|
112
156
|
|
|
113
157
|
このリポジトリは pnpm workspace を使います。ライブラリパッケージは
|
package/README.md
CHANGED
|
@@ -22,44 +22,33 @@ npm install event-store-adapter-js
|
|
|
22
22
|
You can easily implement an Event Sourcing-enabled repository using EventStore.
|
|
23
23
|
|
|
24
24
|
```typescript
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
UserAccountEvent
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (snapshot === undefined) {
|
|
47
|
-
return undefined;
|
|
48
|
-
} else {
|
|
49
|
-
const events = await this.eventStore.getEventsByIdSinceSequenceNumber(
|
|
50
|
-
id,
|
|
51
|
-
snapshot.sequenceNumber + 1,
|
|
52
|
-
);
|
|
53
|
-
return UserAccount.replay(events, snapshot);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
25
|
+
const UserAccountRepository = Object.freeze({
|
|
26
|
+
create(eventStore: EventStore<UserAccountId, UserAccount, UserAccountEvent>) {
|
|
27
|
+
return Object.freeze({
|
|
28
|
+
storeEvent: (event: UserAccountEvent, version: number) =>
|
|
29
|
+
eventStore.persistEvent(event, version),
|
|
30
|
+
storeEventAndSnapshot: (event: UserAccountEvent, snapshot: UserAccount) =>
|
|
31
|
+
eventStore.persistEventAndSnapshot(event, snapshot),
|
|
32
|
+
async findById(id: UserAccountId): Promise<UserAccount | undefined> {
|
|
33
|
+
const snapshot = await eventStore.getLatestSnapshotById(id);
|
|
34
|
+
if (snapshot === undefined) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const events = await eventStore.getEventsByIdSinceSequenceNumber(
|
|
38
|
+
id,
|
|
39
|
+
snapshot.sequenceNumber + 1,
|
|
40
|
+
);
|
|
41
|
+
return UserAccount.replay(events, snapshot);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
});
|
|
57
46
|
```
|
|
58
47
|
|
|
59
48
|
The following is an example of the repository usage.
|
|
60
49
|
|
|
61
50
|
```typescript
|
|
62
|
-
const eventStore = EventStore.
|
|
51
|
+
const eventStore = EventStore.createDynamoDB<
|
|
63
52
|
UserAccountId,
|
|
64
53
|
UserAccount,
|
|
65
54
|
UserAccountEvent
|
|
@@ -75,9 +64,9 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
75
64
|
snapshotConverter: convertJSONToUserAccount,
|
|
76
65
|
});
|
|
77
66
|
// if you want to use in-memory event store, use the following code.
|
|
78
|
-
// const eventStore = EventStore.
|
|
67
|
+
// const eventStore = EventStore.createMemory<UserAccountId, UserAccount, UserAccountEvent>({});
|
|
79
68
|
// if you want to use Cloud Spanner, pass a caller-managed Database.
|
|
80
|
-
// const eventStore = EventStore.
|
|
69
|
+
// const eventStore = EventStore.createSpanner<UserAccountId, UserAccount, UserAccountEvent>({
|
|
81
70
|
// database: spannerDatabase,
|
|
82
71
|
// journalTableName: "journal",
|
|
83
72
|
// snapshotTableName: "snapshot",
|
|
@@ -86,17 +75,23 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
86
75
|
// snapshotConverter: convertJSONToUserAccount,
|
|
87
76
|
// });
|
|
88
77
|
|
|
89
|
-
const userAccountRepository =
|
|
78
|
+
const userAccountRepository = UserAccountRepository.create(eventStore);
|
|
90
79
|
|
|
91
|
-
const id =
|
|
80
|
+
const id = UserAccountId.create(ulid());
|
|
92
81
|
const name = "Alice";
|
|
93
82
|
const [userAccount1, created] = UserAccount.create(id, name);
|
|
94
83
|
|
|
95
|
-
await userAccountRepository.storeEventAndSnapshot(created, userAccount1);
|
|
84
|
+
const createdResult = await userAccountRepository.storeEventAndSnapshot(created, userAccount1);
|
|
85
|
+
if (createdResult.type === "err") {
|
|
86
|
+
throw new Error(createdResult.error.message);
|
|
87
|
+
}
|
|
96
88
|
|
|
97
89
|
const [userAccount2, renamed] = userAccount1.rename("Bob");
|
|
98
90
|
|
|
99
|
-
await userAccountRepository.storeEvent(renamed, userAccount2.version);
|
|
91
|
+
const renamedResult = await userAccountRepository.storeEvent(renamed, userAccount2.version);
|
|
92
|
+
if (renamedResult.type === "err") {
|
|
93
|
+
throw new Error(renamedResult.error.message);
|
|
94
|
+
}
|
|
100
95
|
|
|
101
96
|
const userAccount3 = await userAccountRepository.findById(id);
|
|
102
97
|
if (userAccount3 === undefined) {
|
|
@@ -109,6 +104,55 @@ expect(userAccount3.sequenceNumber).toEqual(2);
|
|
|
109
104
|
expect(userAccount3.version).toEqual(2);
|
|
110
105
|
```
|
|
111
106
|
|
|
107
|
+
## Runtime brands and JSON conversion
|
|
108
|
+
|
|
109
|
+
The sample domain values use module-private `unique symbol` brands to tell
|
|
110
|
+
factory-created values apart from plain objects inside the current process.
|
|
111
|
+
`typeName` remains the JSON boundary discriminant; the symbol brand is not
|
|
112
|
+
serialized and must be restored by a factory.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const USER_ACCOUNT_ID_BRAND: unique symbol = Symbol("UserAccountId");
|
|
116
|
+
|
|
117
|
+
type UserAccountId = AggregateId & {
|
|
118
|
+
typeName: "user-account";
|
|
119
|
+
readonly [USER_ACCOUNT_ID_BRAND]: true;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
namespace UserAccountId {
|
|
123
|
+
export function create(value: string): UserAccountId {
|
|
124
|
+
return Object.freeze({
|
|
125
|
+
[USER_ACCOUNT_ID_BRAND]: true,
|
|
126
|
+
typeName: "user-account",
|
|
127
|
+
value,
|
|
128
|
+
asString: () => `user-account-${value}`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function is(value: unknown): value is UserAccountId {
|
|
133
|
+
return (
|
|
134
|
+
typeof value === "object" &&
|
|
135
|
+
value !== null &&
|
|
136
|
+
(value as Partial<UserAccountId>)[USER_ACCOUNT_ID_BRAND] === true
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function toJSON(value: UserAccountId) {
|
|
141
|
+
return { typeName: value.typeName, value: value.value };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function fromJSON(json: { typeName: "user-account"; value: string }) {
|
|
145
|
+
return create(json.value);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`JSON.stringify(...)` drops the symbol brand. In EventStore converters, call the
|
|
151
|
+
domain `fromJSON(...)` function so deserialized events and snapshots become
|
|
152
|
+
branded values again. The `EventSerializer` and `SnapshotSerializer` APIs stay
|
|
153
|
+
unchanged; their `deserialize(bytes, converter)` contract still delegates
|
|
154
|
+
domain reconstruction to the converter.
|
|
155
|
+
|
|
112
156
|
## Development
|
|
113
157
|
|
|
114
158
|
This repository uses pnpm workspaces. The library package is located at
|
package/dist/aggregate-id.d.ts
CHANGED
package/dist/aggregate.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { AggregateId } from "./aggregate-id";
|
|
2
|
-
|
|
2
|
+
type Aggregate<This extends Aggregate<This, AID>, AID extends AggregateId> = {
|
|
3
3
|
typeName: string;
|
|
4
4
|
id: AID;
|
|
5
5
|
sequenceNumber: number;
|
|
6
6
|
version: number;
|
|
7
7
|
withVersion(version: number): This;
|
|
8
8
|
updateVersion(version: (value: number) => number): This;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
export type { Aggregate };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
2
2
|
import type { Aggregate, AggregateId, Event, EventSerializer, Logger, ShardSelector, SnapshotSerializer } from "./types";
|
|
3
|
-
|
|
3
|
+
type DynamoDBEventStoreInput<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>> = {
|
|
4
4
|
client: DynamoDBClient;
|
|
5
5
|
journalTableName: string;
|
|
6
6
|
snapshotTableName: string;
|
|
@@ -18,5 +18,5 @@ interface DynamoDBEventStoreInput<AID extends AggregateId, A extends Aggregate<A
|
|
|
18
18
|
eventSerializer?: EventSerializer<AID, E>;
|
|
19
19
|
snapshotSerializer?: SnapshotSerializer<AID, A>;
|
|
20
20
|
logger?: Logger;
|
|
21
|
-
}
|
|
21
|
+
};
|
|
22
22
|
export type { DynamoDBEventStoreInput };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AggregateId } from "./aggregate-id";
|
|
2
2
|
import type { Event } from "./event";
|
|
3
|
-
|
|
3
|
+
type EventSerializer<AID extends AggregateId, E extends Event<AID>> = {
|
|
4
4
|
serialize(event: E): Uint8Array;
|
|
5
5
|
deserialize(bytes: Uint8Array, converter: (json: unknown) => E): E;
|
|
6
|
-
}
|
|
6
|
+
};
|
|
7
7
|
export type { EventSerializer };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type EventStoreError = {
|
|
2
|
+
type: "optimistic-lock-conflict";
|
|
3
|
+
message: string;
|
|
4
|
+
cause?: unknown;
|
|
5
|
+
} | {
|
|
6
|
+
type: "configuration-error";
|
|
7
|
+
fieldName: string;
|
|
8
|
+
message: string;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
} | {
|
|
11
|
+
type: "serialization-error";
|
|
12
|
+
operation: "serialize" | "deserialize";
|
|
13
|
+
message: string;
|
|
14
|
+
cause?: unknown;
|
|
15
|
+
} | {
|
|
16
|
+
type: "storage-error";
|
|
17
|
+
message: string;
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
};
|
|
20
|
+
export declare namespace EventStoreError {
|
|
21
|
+
function optimisticLockConflict(message?: string, cause?: unknown): EventStoreError;
|
|
22
|
+
function configuration(fieldName: string, message: string, cause?: unknown): EventStoreError;
|
|
23
|
+
function serialization(operation: "serialize" | "deserialize", message: string, cause?: unknown): EventStoreError;
|
|
24
|
+
function storage(message: string, cause?: unknown): EventStoreError;
|
|
25
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventStoreError = void 0;
|
|
4
|
+
var EventStoreError;
|
|
5
|
+
(function (EventStoreError) {
|
|
6
|
+
function optimisticLockConflict(message = "Optimistic locking failed", cause) {
|
|
7
|
+
return Object.freeze({
|
|
8
|
+
type: "optimistic-lock-conflict",
|
|
9
|
+
message,
|
|
10
|
+
cause,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
EventStoreError.optimisticLockConflict = optimisticLockConflict;
|
|
14
|
+
function configuration(fieldName, message, cause) {
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
type: "configuration-error",
|
|
17
|
+
fieldName,
|
|
18
|
+
message,
|
|
19
|
+
cause,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
EventStoreError.configuration = configuration;
|
|
23
|
+
function serialization(operation, message, cause) {
|
|
24
|
+
return Object.freeze({
|
|
25
|
+
type: "serialization-error",
|
|
26
|
+
operation,
|
|
27
|
+
message,
|
|
28
|
+
cause,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
EventStoreError.serialization = serialization;
|
|
32
|
+
function storage(message, cause) {
|
|
33
|
+
return Object.freeze({
|
|
34
|
+
type: "storage-error",
|
|
35
|
+
message,
|
|
36
|
+
cause,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
EventStoreError.storage = storage;
|
|
40
|
+
})(EventStoreError || (exports.EventStoreError = EventStoreError = {}));
|
|
41
|
+
// Object.freeze mutates the existing EventStoreError namespace object in place;
|
|
42
|
+
// the returned reference is intentionally ignored to preserve the public binding.
|
|
43
|
+
Object.freeze(EventStoreError);
|
package/dist/event-store.d.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import type { DynamoDBEventStoreInput } from "./dynamodb-event-store-input";
|
|
2
2
|
import type { MemoryEventStoreInput } from "./memory-event-store-input";
|
|
3
3
|
import type { SpannerEventStoreInput } from "./spanner-event-store-input";
|
|
4
|
-
import type { Aggregate, AggregateId, Event } from "./types";
|
|
5
|
-
export
|
|
6
|
-
persistEvent(event: E, expectedVersion: number): Promise<void
|
|
7
|
-
persistEventAndSnapshot(event: E, aggregate: A): Promise<void
|
|
4
|
+
import type { Aggregate, AggregateId, Event, EventStoreError, Result } from "./types";
|
|
5
|
+
export type EventStore<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>> = {
|
|
6
|
+
persistEvent(event: E, expectedVersion: number): Promise<Result<void, EventStoreError>>;
|
|
7
|
+
persistEventAndSnapshot(event: E, aggregate: A): Promise<Result<void, EventStoreError>>;
|
|
8
8
|
getEventsByIdSinceSequenceNumber(id: AID, sequenceNumber: number): Promise<E[]>;
|
|
9
9
|
getLatestSnapshotById(id: AID): Promise<A | undefined>;
|
|
10
|
+
};
|
|
11
|
+
export declare namespace EventStore {
|
|
12
|
+
function createDynamoDB<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>>(input: DynamoDBEventStoreInput<AID, A, E>): EventStore<AID, A, E>;
|
|
13
|
+
function createMemory<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>>(input?: MemoryEventStoreInput<AID, A, E>): EventStore<AID, A, E>;
|
|
14
|
+
function createSpanner<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>>(input: SpannerEventStoreInput<AID, A, E>): EventStore<AID, A, E>;
|
|
10
15
|
}
|
|
11
|
-
type EventStoreConstructors = Readonly<{
|
|
12
|
-
ofDynamoDB<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>>(input: DynamoDBEventStoreInput<AID, A, E>): EventStore<AID, A, E>;
|
|
13
|
-
ofMemory<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>>(input?: MemoryEventStoreInput<AID, A, E>): EventStore<AID, A, E>;
|
|
14
|
-
ofSpanner<AID extends AggregateId, A extends Aggregate<A, AID>, E extends Event<AID>>(input: SpannerEventStoreInput<AID, A, E>): EventStore<AID, A, E>;
|
|
15
|
-
}>;
|
|
16
|
-
export declare const EventStore: EventStoreConstructors;
|
|
17
|
-
export {};
|
package/dist/event-store.js
CHANGED
|
@@ -4,14 +4,19 @@ exports.EventStore = void 0;
|
|
|
4
4
|
const dynamodb_event_store_1 = require("./internal/dynamodb-event-store");
|
|
5
5
|
const memory_event_store_1 = require("./internal/memory-event-store");
|
|
6
6
|
const spanner_event_store_1 = require("./internal/spanner-event-store");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
var EventStore;
|
|
8
|
+
(function (EventStore) {
|
|
9
|
+
function createDynamoDB(input) {
|
|
10
|
+
return (0, dynamodb_event_store_1.createDynamoDBEventStore)(input);
|
|
11
|
+
}
|
|
12
|
+
EventStore.createDynamoDB = createDynamoDB;
|
|
13
|
+
function createMemory(input) {
|
|
14
|
+
return (0, memory_event_store_1.createMemoryEventStore)(input !== null && input !== void 0 ? input : {});
|
|
15
|
+
}
|
|
16
|
+
EventStore.createMemory = createMemory;
|
|
17
|
+
function createSpanner(input) {
|
|
18
|
+
return (0, spanner_event_store_1.createSpannerEventStore)(input);
|
|
19
|
+
}
|
|
20
|
+
EventStore.createSpanner = createSpanner;
|
|
21
|
+
})(EventStore || (exports.EventStore = EventStore = {}));
|
|
22
|
+
Object.freeze(EventStore);
|
package/dist/event.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { AggregateId } from "./aggregate-id";
|
|
2
|
-
|
|
2
|
+
type Event<AID extends AggregateId> = {
|
|
3
3
|
typeName: string;
|
|
4
4
|
id: string;
|
|
5
5
|
aggregateId: AID;
|
|
6
6
|
sequenceNumber: number;
|
|
7
7
|
occurredAt: Date;
|
|
8
8
|
isCreated: boolean;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
export type { Event };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from "./dynamodb-event-store-input";
|
|
2
2
|
export * from "./event-store";
|
|
3
|
+
export * from "./event-store-error";
|
|
3
4
|
export * from "./memory-event-store-input";
|
|
5
|
+
export * from "./result";
|
|
4
6
|
export * from "./shard-id";
|
|
5
7
|
export * from "./spanner-event-store-input";
|
|
6
8
|
export * from "./types";
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./dynamodb-event-store-input"), exports);
|
|
18
18
|
__exportStar(require("./event-store"), exports);
|
|
19
|
+
__exportStar(require("./event-store-error"), exports);
|
|
19
20
|
__exportStar(require("./memory-event-store-input"), exports);
|
|
21
|
+
__exportStar(require("./result"), exports);
|
|
20
22
|
__exportStar(require("./shard-id"), exports);
|
|
21
23
|
__exportStar(require("./spanner-event-store-input"), exports);
|
|
22
24
|
__exportStar(require("./types"), exports);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Aggregate, AggregateId, Event } from "../types";
|
|
2
|
-
declare
|
|
2
|
+
declare function createJsonEventSerializer(): Readonly<{
|
|
3
3
|
deserialize<E>(bytes: Uint8Array, converter: (json: unknown) => E): E;
|
|
4
4
|
serialize<AID extends AggregateId, E extends Event<AID>>(event: E): Uint8Array;
|
|
5
|
-
}
|
|
6
|
-
declare
|
|
5
|
+
}>;
|
|
6
|
+
declare function createJsonSnapshotSerializer(): Readonly<{
|
|
7
7
|
deserialize<A>(bytes: Uint8Array, converter: (json: unknown) => A): A;
|
|
8
8
|
serialize<AID extends AggregateId, A extends Aggregate<A, AID>>(aggregate: A): Uint8Array;
|
|
9
|
-
}
|
|
10
|
-
export {
|
|
9
|
+
}>;
|
|
10
|
+
export { createJsonEventSerializer, createJsonSnapshotSerializer };
|
|
@@ -1,35 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.createJsonEventSerializer = createJsonEventSerializer;
|
|
4
|
+
exports.createJsonSnapshotSerializer = createJsonSnapshotSerializer;
|
|
4
5
|
const encoder = new TextEncoder();
|
|
5
6
|
const decoder = new TextDecoder();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
function createJsonEventSerializer() {
|
|
8
|
+
return Object.freeze({
|
|
9
|
+
deserialize(bytes, converter) {
|
|
10
|
+
const jsonString = decoder.decode(bytes);
|
|
11
|
+
const json = JSON.parse(jsonString);
|
|
12
|
+
return converter(json);
|
|
13
|
+
},
|
|
14
|
+
serialize(event) {
|
|
15
|
+
const jsonString = JSON.stringify({
|
|
16
|
+
type: event.typeName,
|
|
17
|
+
data: event,
|
|
18
|
+
});
|
|
19
|
+
return encoder.encode(jsonString);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
function createJsonSnapshotSerializer() {
|
|
24
|
+
return Object.freeze({
|
|
25
|
+
deserialize(bytes, converter) {
|
|
26
|
+
const jsonString = decoder.decode(bytes);
|
|
27
|
+
const obj = JSON.parse(jsonString);
|
|
28
|
+
return converter(obj);
|
|
29
|
+
},
|
|
30
|
+
serialize(aggregate) {
|
|
31
|
+
const jsonString = JSON.stringify({
|
|
32
|
+
type: aggregate.typeName,
|
|
33
|
+
data: aggregate,
|
|
34
|
+
});
|
|
35
|
+
return encoder.encode(jsonString);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
|
-
exports.JsonSnapshotSerializer = JsonSnapshotSerializer;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
selectShardId(aggregateId: AID, shardCount: ShardCount): ShardId;
|
|
5
|
-
private hashString;
|
|
6
|
-
}
|
|
7
|
-
export { DefaultShardSelector };
|
|
1
|
+
import type { AggregateId, ShardSelector } from "../types";
|
|
2
|
+
declare function createDefaultShardSelector<AID extends AggregateId>(): ShardSelector<AID>;
|
|
3
|
+
export { createDefaultShardSelector };
|