event-store-adapter-js 1.0.2-snapshot.21 → 1.0.2-snapshot.23
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 +107 -0
- package/README.md +91 -0
- package/package.json +1 -1
- package/src/event-store.ts +57 -2
- package/src/internal/test/user-account-repository.test.ts +4 -8
package/README.ja.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# event-store-adapter-js
|
|
2
|
+
|
|
3
|
+
このライブラリは、DynamoDBをEvent Sourcing用のEvent Storeにするためのものです。
|
|
4
|
+
|
|
5
|
+
[English](./README.md)
|
|
6
|
+
|
|
7
|
+
# 導入方法
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
$ npm i event-store-adapter-js
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
# 使い方
|
|
14
|
+
|
|
15
|
+
EventStoreを使えば、Event Sourcing対応リポジトリを簡単に実装できます。
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
class UserAccountRepository {
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly eventStore: EventStore<
|
|
21
|
+
UserAccountId,
|
|
22
|
+
UserAccount,
|
|
23
|
+
UserAccountEvent
|
|
24
|
+
>,
|
|
25
|
+
) {}
|
|
26
|
+
|
|
27
|
+
async storeEvent(event: UserAccountEvent, version: number) {
|
|
28
|
+
await this.eventStore.persistEvent(event, version);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async storeEventAndSnapshot(event: UserAccountEvent, snapshot: UserAccount) {
|
|
32
|
+
await this.eventStore.persistEventAndSnapshot(event, snapshot);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async findById(id: UserAccountId): Promise<UserAccount | undefined> {
|
|
36
|
+
const snapshot = await this.eventStore.getLatestSnapshotById(
|
|
37
|
+
id,
|
|
38
|
+
convertJSONToUserAccount,
|
|
39
|
+
);
|
|
40
|
+
if (snapshot === undefined) {
|
|
41
|
+
return undefined;
|
|
42
|
+
} else {
|
|
43
|
+
const events = await this.eventStore.getEventsByIdSinceSequenceNumber(
|
|
44
|
+
id,
|
|
45
|
+
snapshot.sequenceNumber + 1,
|
|
46
|
+
convertJSONtoUserAccountEvent,
|
|
47
|
+
);
|
|
48
|
+
return UserAccount.replay(events, snapshot);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
以下はリポジトリの使用例です。
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const eventStore = EventStoreFactory.ofDynamoDB<
|
|
58
|
+
UserAccountId,
|
|
59
|
+
UserAccount,
|
|
60
|
+
UserAccountEvent
|
|
61
|
+
>(
|
|
62
|
+
dynamodbClient,
|
|
63
|
+
JOURNAL_TABLE_NAME,
|
|
64
|
+
SNAPSHOT_TABLE_NAME,
|
|
65
|
+
JOURNAL_AID_INDEX_NAME,
|
|
66
|
+
SNAPSHOTS_AID_INDEX_NAME,
|
|
67
|
+
32,
|
|
68
|
+
);
|
|
69
|
+
const userAccountRepository = new UserAccountRepository(eventStore);
|
|
70
|
+
|
|
71
|
+
const id = new UserAccountId(ulid());
|
|
72
|
+
const name = "Alice";
|
|
73
|
+
const [userAccount1, created] = UserAccount.create(id, name);
|
|
74
|
+
|
|
75
|
+
await userAccountRepository.storeEventAndSnapshot(created, userAccount1);
|
|
76
|
+
|
|
77
|
+
const [userAccount2, renamed] = userAccount1.rename("Bob");
|
|
78
|
+
|
|
79
|
+
await userAccountRepository.storeEvent(renamed, userAccount2.version);
|
|
80
|
+
|
|
81
|
+
const userAccount3 = await userAccountRepository.findById(id);
|
|
82
|
+
if (userAccount3 === undefined) {
|
|
83
|
+
throw new Error("userAccount3 is undefined");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
expect(userAccount3.id).toEqual(id);
|
|
87
|
+
expect(userAccount3.name).toEqual("Bob");
|
|
88
|
+
expect(userAccount3.sequenceNumber).toEqual(2);
|
|
89
|
+
expect(userAccount3.version).toEqual(2);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## テーブル仕様
|
|
93
|
+
|
|
94
|
+
[docs/DATABASE_SCHEMA.ja.md](docs/DATABASE_SCHEMA.ja.md)を参照してください。
|
|
95
|
+
|
|
96
|
+
## ライセンス
|
|
97
|
+
|
|
98
|
+
MITライセンスです。詳細は[LICENSE](LICENSE)を参照してください。
|
|
99
|
+
|
|
100
|
+
## 他の言語のための実装
|
|
101
|
+
|
|
102
|
+
- [for Java](https://github.com/j5ik2o/event-store-adapter-java)
|
|
103
|
+
- [for Scala](https://github.com/j5ik2o/event-store-adapter-scala)
|
|
104
|
+
- [for Kotlin](https://github.com/j5ik2o/event-store-adapter-kotlin)
|
|
105
|
+
- [for Rust](https://github.com/j5ik2o/event-store-adapter-rs)
|
|
106
|
+
- [for Go](https://github.com/j5ik2o/event-store-adapter-go)
|
|
107
|
+
- [for JavaScript/TypeScript](https://github.com/j5ik2o/event-store-adapter-js)
|
package/README.md
CHANGED
|
@@ -2,6 +2,97 @@
|
|
|
2
2
|
|
|
3
3
|
This library is designed to turn DynamoDB into an Event Store for Event Sourcing.
|
|
4
4
|
|
|
5
|
+
[日本語](./README.ja.md)
|
|
6
|
+
|
|
7
|
+
# Installation
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
$ npm i event-store-adapter-js
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
# Usage
|
|
14
|
+
|
|
15
|
+
You can easily implement an Event Sourcing-enabled repository using EventStore.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
class UserAccountRepository {
|
|
19
|
+
constructor(
|
|
20
|
+
private readonly eventStore: EventStore<
|
|
21
|
+
UserAccountId,
|
|
22
|
+
UserAccount,
|
|
23
|
+
UserAccountEvent
|
|
24
|
+
>,
|
|
25
|
+
) {}
|
|
26
|
+
|
|
27
|
+
async storeEvent(event: UserAccountEvent, version: number) {
|
|
28
|
+
await this.eventStore.persistEvent(event, version);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async storeEventAndSnapshot(event: UserAccountEvent, snapshot: UserAccount) {
|
|
32
|
+
await this.eventStore.persistEventAndSnapshot(event, snapshot);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async findById(id: UserAccountId): Promise<UserAccount | undefined> {
|
|
36
|
+
const snapshot = await this.eventStore.getLatestSnapshotById(
|
|
37
|
+
id,
|
|
38
|
+
convertJSONToUserAccount,
|
|
39
|
+
);
|
|
40
|
+
if (snapshot === undefined) {
|
|
41
|
+
return undefined;
|
|
42
|
+
} else {
|
|
43
|
+
const events = await this.eventStore.getEventsByIdSinceSequenceNumber(
|
|
44
|
+
id,
|
|
45
|
+
snapshot.sequenceNumber + 1,
|
|
46
|
+
convertJSONtoUserAccountEvent,
|
|
47
|
+
);
|
|
48
|
+
return UserAccount.replay(events, snapshot);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The following is an example of the repository usage.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const eventStore = EventStoreFactory.ofDynamoDB<
|
|
58
|
+
UserAccountId,
|
|
59
|
+
UserAccount,
|
|
60
|
+
UserAccountEvent
|
|
61
|
+
>(
|
|
62
|
+
dynamodbClient,
|
|
63
|
+
JOURNAL_TABLE_NAME,
|
|
64
|
+
SNAPSHOT_TABLE_NAME,
|
|
65
|
+
JOURNAL_AID_INDEX_NAME,
|
|
66
|
+
SNAPSHOTS_AID_INDEX_NAME,
|
|
67
|
+
32,
|
|
68
|
+
);
|
|
69
|
+
const userAccountRepository = new UserAccountRepository(eventStore);
|
|
70
|
+
|
|
71
|
+
const id = new UserAccountId(ulid());
|
|
72
|
+
const name = "Alice";
|
|
73
|
+
const [userAccount1, created] = UserAccount.create(id, name);
|
|
74
|
+
|
|
75
|
+
await userAccountRepository.storeEventAndSnapshot(created, userAccount1);
|
|
76
|
+
|
|
77
|
+
const [userAccount2, renamed] = userAccount1.rename("Bob");
|
|
78
|
+
|
|
79
|
+
await userAccountRepository.storeEvent(renamed, userAccount2.version);
|
|
80
|
+
|
|
81
|
+
const userAccount3 = await userAccountRepository.findById(id);
|
|
82
|
+
if (userAccount3 === undefined) {
|
|
83
|
+
throw new Error("userAccount3 is undefined");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
expect(userAccount3.id).toEqual(id);
|
|
87
|
+
expect(userAccount3.name).toEqual("Bob");
|
|
88
|
+
expect(userAccount3.sequenceNumber).toEqual(2);
|
|
89
|
+
expect(userAccount3.version).toEqual(2);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Table Specifications
|
|
93
|
+
|
|
94
|
+
See [docs/DATABASE_SCHEMA.md](docs/DATABASE_SCHEMA.md).
|
|
95
|
+
|
|
5
96
|
## License.
|
|
6
97
|
|
|
7
98
|
MIT License. See [LICENSE](LICENSE) for details.
|
package/package.json
CHANGED
package/src/event-store.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Aggregate,
|
|
3
|
+
AggregateId,
|
|
4
|
+
Event,
|
|
5
|
+
EventSerializer,
|
|
6
|
+
KeyResolver,
|
|
7
|
+
SnapshotSerializer,
|
|
8
|
+
} from "./types";
|
|
2
9
|
import { EventStoreOptions } from "./event-store-options";
|
|
10
|
+
import { EventStoreForDynamoDB } from "./internal/event-store-for-dynamodb";
|
|
11
|
+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
12
|
+
import * as moment from "moment";
|
|
13
|
+
import { DefaultKeyResolver } from "./internal/default-key-resolver";
|
|
14
|
+
import {
|
|
15
|
+
JsonEventSerializer,
|
|
16
|
+
JsonSnapshotSerializer,
|
|
17
|
+
} from "./internal/default-serializer";
|
|
3
18
|
|
|
4
19
|
interface EventStore<
|
|
5
20
|
AID extends AggregateId,
|
|
@@ -19,4 +34,44 @@ interface EventStore<
|
|
|
19
34
|
): Promise<A | undefined>;
|
|
20
35
|
}
|
|
21
36
|
|
|
22
|
-
|
|
37
|
+
class EventStoreFactory {
|
|
38
|
+
static ofDynamoDB<
|
|
39
|
+
AID extends AggregateId,
|
|
40
|
+
A extends Aggregate<A, AID>,
|
|
41
|
+
E extends Event<AID>,
|
|
42
|
+
>(
|
|
43
|
+
dynamodbClient: DynamoDBClient,
|
|
44
|
+
journalTableName: string,
|
|
45
|
+
snapshotTableName: string,
|
|
46
|
+
journalAidIndexName: string,
|
|
47
|
+
snapshotAidIndexName: string,
|
|
48
|
+
shardCount: number,
|
|
49
|
+
keepSnapshotCount: number | undefined = undefined,
|
|
50
|
+
deleteTtl: moment.Duration | undefined = undefined,
|
|
51
|
+
keyResolver: KeyResolver<AID> = new DefaultKeyResolver(),
|
|
52
|
+
eventSerializer: EventSerializer<AID, E> = new JsonEventSerializer<
|
|
53
|
+
AID,
|
|
54
|
+
E
|
|
55
|
+
>(),
|
|
56
|
+
snapshotSerializer: SnapshotSerializer<AID, A> = new JsonSnapshotSerializer<
|
|
57
|
+
AID,
|
|
58
|
+
A
|
|
59
|
+
>(),
|
|
60
|
+
) {
|
|
61
|
+
return new EventStoreForDynamoDB<AID, A, E>(
|
|
62
|
+
dynamodbClient,
|
|
63
|
+
journalTableName,
|
|
64
|
+
snapshotTableName,
|
|
65
|
+
journalAidIndexName,
|
|
66
|
+
snapshotAidIndexName,
|
|
67
|
+
shardCount,
|
|
68
|
+
keepSnapshotCount,
|
|
69
|
+
deleteTtl,
|
|
70
|
+
keyResolver,
|
|
71
|
+
eventSerializer,
|
|
72
|
+
snapshotSerializer,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { EventStore, EventStoreFactory };
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
TestContainer,
|
|
6
6
|
Wait,
|
|
7
7
|
} from "testcontainers";
|
|
8
|
-
import { EventStoreForDynamoDB } from "../event-store-for-dynamodb";
|
|
9
8
|
import { UserAccountId } from "./user-account-id";
|
|
10
9
|
import { UserAccount } from "./user-account";
|
|
11
10
|
import { UserAccountEvent } from "./user-account-event";
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
} from "./dynamodb-utils";
|
|
18
17
|
import { ulid } from "ulid";
|
|
19
18
|
import { UserAccountRepository } from "./user-account-repository";
|
|
19
|
+
import { EventStore, EventStoreFactory } from "../../event-store";
|
|
20
20
|
|
|
21
21
|
afterEach(() => {
|
|
22
22
|
jest.useRealTimers();
|
|
@@ -29,11 +29,7 @@ describe("UserAccountRepository", () => {
|
|
|
29
29
|
|
|
30
30
|
let container: TestContainer;
|
|
31
31
|
let startedContainer: StartedTestContainer;
|
|
32
|
-
let eventStore:
|
|
33
|
-
UserAccountId,
|
|
34
|
-
UserAccount,
|
|
35
|
-
UserAccountEvent
|
|
36
|
-
>;
|
|
32
|
+
let eventStore: EventStore<UserAccountId, UserAccount, UserAccountEvent>;
|
|
37
33
|
|
|
38
34
|
const JOURNAL_TABLE_NAME = "journal";
|
|
39
35
|
const SNAPSHOT_TABLE_NAME = "snapshot";
|
|
@@ -42,8 +38,8 @@ describe("UserAccountRepository", () => {
|
|
|
42
38
|
|
|
43
39
|
function createEventStore(
|
|
44
40
|
dynamodbClient: DynamoDBClient,
|
|
45
|
-
):
|
|
46
|
-
return
|
|
41
|
+
): EventStore<UserAccountId, UserAccount, UserAccountEvent> {
|
|
42
|
+
return EventStoreFactory.ofDynamoDB<
|
|
47
43
|
UserAccountId,
|
|
48
44
|
UserAccount,
|
|
49
45
|
UserAccountEvent
|