event-store-adapter-js 3.0.0 → 3.0.1-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 +9 -6
- package/README.md +9 -8
- package/docs/DATABASE_SCHEMA.ja.md +10 -9
- package/docs/DATABASE_SCHEMA.md +10 -9
- package/docs/GCP_EVENT_INTEGRATION.ja.md +5 -5
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -67,10 +67,10 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
67
67
|
journalTableName: JOURNAL_TABLE_NAME,
|
|
68
68
|
snapshotTableName: SNAPSHOT_TABLE_NAME,
|
|
69
69
|
journalAidIndexName: JOURNAL_AID_INDEX_NAME,
|
|
70
|
-
snapshotAidIndexName:
|
|
71
|
-
snapshotActiveTtlIndexName:
|
|
70
|
+
snapshotAidIndexName: SNAPSHOT_AID_INDEX_NAME,
|
|
71
|
+
snapshotActiveTtlIndexName: SNAPSHOT_ACTIVE_TTL_INDEX_NAME,
|
|
72
72
|
shardCount: 32,
|
|
73
|
-
eventConverter:
|
|
73
|
+
eventConverter: convertJSONToUserAccountEvent,
|
|
74
74
|
snapshotConverter: convertJSONToUserAccount,
|
|
75
75
|
});
|
|
76
76
|
// if you want to use in-memory event store, use the following code.
|
|
@@ -81,7 +81,7 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
81
81
|
// journalTableName: "journal",
|
|
82
82
|
// snapshotTableName: "snapshot",
|
|
83
83
|
// shardCount: 32,
|
|
84
|
-
// eventConverter:
|
|
84
|
+
// eventConverter: convertJSONToUserAccountEvent,
|
|
85
85
|
// snapshotConverter: convertJSONToUserAccount,
|
|
86
86
|
// });
|
|
87
87
|
|
|
@@ -111,8 +111,8 @@ expect(userAccount3.version).toEqual(2);
|
|
|
111
111
|
## 開発
|
|
112
112
|
|
|
113
113
|
このリポジトリは pnpm workspace を使います。ライブラリパッケージは
|
|
114
|
-
`packages/library`
|
|
115
|
-
`packages/
|
|
114
|
+
`packages/library` に配置しています。実行可能な example は `packages/examples` にあり、
|
|
115
|
+
`packages/tests` は今後の e2e test package の追加先として予約しています。
|
|
116
116
|
|
|
117
117
|
```shell
|
|
118
118
|
pnpm install
|
|
@@ -120,6 +120,9 @@ pnpm run lint
|
|
|
120
120
|
pnpm run build
|
|
121
121
|
pnpm run test
|
|
122
122
|
pnpm run coverage
|
|
123
|
+
pnpm run example:memory
|
|
124
|
+
pnpm run example:dynamodb
|
|
125
|
+
pnpm run example:spanner
|
|
123
126
|
```
|
|
124
127
|
|
|
125
128
|
## テーブル仕様
|
package/README.md
CHANGED
|
@@ -42,7 +42,6 @@ class UserAccountRepository {
|
|
|
42
42
|
async findById(id: UserAccountId): Promise<UserAccount | undefined> {
|
|
43
43
|
const snapshot = await this.eventStore.getLatestSnapshotById(
|
|
44
44
|
id,
|
|
45
|
-
convertJSONToUserAccount,
|
|
46
45
|
);
|
|
47
46
|
if (snapshot === undefined) {
|
|
48
47
|
return undefined;
|
|
@@ -50,7 +49,6 @@ class UserAccountRepository {
|
|
|
50
49
|
const events = await this.eventStore.getEventsByIdSinceSequenceNumber(
|
|
51
50
|
id,
|
|
52
51
|
snapshot.sequenceNumber + 1,
|
|
53
|
-
convertJSONtoUserAccountEvent,
|
|
54
52
|
);
|
|
55
53
|
return UserAccount.replay(events, snapshot);
|
|
56
54
|
}
|
|
@@ -70,10 +68,10 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
70
68
|
journalTableName: JOURNAL_TABLE_NAME,
|
|
71
69
|
snapshotTableName: SNAPSHOT_TABLE_NAME,
|
|
72
70
|
journalAidIndexName: JOURNAL_AID_INDEX_NAME,
|
|
73
|
-
snapshotAidIndexName:
|
|
74
|
-
snapshotActiveTtlIndexName:
|
|
71
|
+
snapshotAidIndexName: SNAPSHOT_AID_INDEX_NAME,
|
|
72
|
+
snapshotActiveTtlIndexName: SNAPSHOT_ACTIVE_TTL_INDEX_NAME,
|
|
75
73
|
shardCount: 32,
|
|
76
|
-
eventConverter:
|
|
74
|
+
eventConverter: convertJSONToUserAccountEvent,
|
|
77
75
|
snapshotConverter: convertJSONToUserAccount,
|
|
78
76
|
});
|
|
79
77
|
// if you want to use in-memory event store, use the following code.
|
|
@@ -84,7 +82,7 @@ const eventStore = EventStore.ofDynamoDB<
|
|
|
84
82
|
// journalTableName: "journal",
|
|
85
83
|
// snapshotTableName: "snapshot",
|
|
86
84
|
// shardCount: 32,
|
|
87
|
-
// eventConverter:
|
|
85
|
+
// eventConverter: convertJSONToUserAccountEvent,
|
|
88
86
|
// snapshotConverter: convertJSONToUserAccount,
|
|
89
87
|
// });
|
|
90
88
|
|
|
@@ -114,8 +112,8 @@ expect(userAccount3.version).toEqual(2);
|
|
|
114
112
|
## Development
|
|
115
113
|
|
|
116
114
|
This repository uses pnpm workspaces. The library package is located at
|
|
117
|
-
`packages/library
|
|
118
|
-
future
|
|
115
|
+
`packages/library`. Runnable examples are located at `packages/examples`, and
|
|
116
|
+
`packages/tests` is reserved for future e2e test packages.
|
|
119
117
|
|
|
120
118
|
```shell
|
|
121
119
|
pnpm install
|
|
@@ -123,6 +121,9 @@ pnpm run lint
|
|
|
123
121
|
pnpm run build
|
|
124
122
|
pnpm run test
|
|
125
123
|
pnpm run coverage
|
|
124
|
+
pnpm run example:memory
|
|
125
|
+
pnpm run example:dynamodb
|
|
126
|
+
pnpm run example:spanner
|
|
126
127
|
```
|
|
127
128
|
|
|
128
129
|
## Table Specifications
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- Journal
|
|
4
4
|
- Snapshot
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
いずれのテーブルも、選択された shard id によって書き込みを分散させます。デフォルトでは集約 ID から shard id を選択し、呼び出し側は独自の `ShardSelector` も指定できます。
|
|
7
7
|
|
|
8
8
|
### Journalテーブル
|
|
9
9
|
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
|
|
12
12
|
| キー名 | 説明 | 具体的な値 | 備考 |
|
|
13
13
|
|:------------|:--------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---|
|
|
14
|
-
| pkey |
|
|
14
|
+
| pkey | パーティションキー(`${aggregate.typeName}-${shardId}`) | user-account-1 | |
|
|
15
15
|
| skey | ソートキー(集約種別名-集約IDの値部分-シーケンス番号) | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z-12345 | |
|
|
16
16
|
| aid | 集約ID | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z | |
|
|
17
|
-
|
|
|
18
|
-
| payload |
|
|
19
|
-
| occurred_at |
|
|
17
|
+
| seq_nr | シーケンス番号(開始番号は1) | 12345 | |
|
|
18
|
+
| payload | シリアライズされたイベント payload | {"type":"UserAccountCreated","data":{"typeName":"UserAccountCreated","isCreated":true,"id":"01H42KBHCW1BZG504J4ZXKA2F2","aggregateId":{"typeName":"user-account","value":"01H42K4ABWQ5V2XQEP3A48VE0Z"},"name":"Alice","sequenceNumber":1,"occurredAt":"2026-05-24T00:00:00.000Z"}} | デフォルト JSON serializer の例 |
|
|
19
|
+
| occurred_at | `event.occurredAt` の UTC millisecond component | 0 | DynamoDB number として保存 |
|
|
20
20
|
|
|
21
21
|
aidとseq_nrはGSIが適用されており、リプレイ時はこのインデックスを利用されます。
|
|
22
22
|
|
|
@@ -26,16 +26,17 @@ aidとseq_nrはGSIが適用されており、リプレイ時はこのインデ
|
|
|
26
26
|
|
|
27
27
|
| キー名 | 説明 | 具体的な値 | 備考 |
|
|
28
28
|
|:--------|:-----------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---|
|
|
29
|
-
| pkey |
|
|
29
|
+
| pkey | パーティションキー(`${aggregate.typeName}-${shardId}`) | user-account-1 | |
|
|
30
30
|
| skey | ソートキー(集約種別名-集約IDの値部分-シーケンス番号), 最新のスナップショットはシーケンス番号=0として読み書きされます。 | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z-12345 | |
|
|
31
|
-
| payload |
|
|
31
|
+
| payload | シリアライズされた集約 snapshot | {"type":"UserAccount","data":{"typeName":"UserAccount","id":{"typeName":"user-account","value":"01H42K4ABWQ5V2XQEP3A48VE0Z"},"name":"Alice","sequenceNumber":1,"version":1}} | デフォルト JSON serializer の例 |
|
|
32
32
|
| aid | 集約ID | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z | |
|
|
33
|
-
|
|
|
33
|
+
| seq_nr | シーケンス番号(開始番号は1) | 12345 | |
|
|
34
34
|
| active_ttl_seq_nr | TTL削除対象としてマークされていない間だけ射影されるシーケンス番号 | 12345 | |
|
|
35
35
|
| ttl | 削除のためのTTL(秒) | 1624980000 | |
|
|
36
36
|
| version | バージョン(楽観的ロック用)(開始番号は1) | 1 | |
|
|
37
|
+
| last_updated_at | `event.occurredAt` の UTC millisecond component | 0 | DynamoDB number として保存 |
|
|
37
38
|
|
|
38
|
-
-
|
|
39
|
+
- retained snapshot が無効な場合は seq_nr=0 に最新スナップショットだけを保存します。`keepSnapshotCount` を設定した場合は、seq_nr=0 に加えて seq_nr=event.sequenceNumber の retained snapshot を保存します。上限を超えた場合は古い retained snapshot から削除されます。デフォルトではクライアント主導で削除されますが、`deleteTtlMillis` を使って DynamoDB TTL 削除対象としてマークすることもできます。
|
|
39
40
|
- aidとseq_nrはGSIが適用されており、リプレイ時とハードデリート方式の保持処理でこのインデックスを利用されます。
|
|
40
41
|
- aidとactive_ttl_seq_nrにはスパースGSIが適用されており、TTL方式の保持処理で、まだTTL削除対象としてマークされていないスナップショットだけを読み取るために利用されます。TTLが設定されると、active_ttl_seq_nrはアイテムから削除されます。
|
|
41
42
|
|
package/docs/DATABASE_SCHEMA.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- Journal
|
|
4
4
|
- Snapshot
|
|
5
5
|
|
|
6
|
-
The key design assumption for both tables is that writes are distributed
|
|
6
|
+
The key design assumption for both tables is that writes are distributed by the selected shard id. By default, shard ids are selected from the aggregate id, and callers may provide a custom `ShardSelector`.
|
|
7
7
|
|
|
8
8
|
### Journal table
|
|
9
9
|
|
|
@@ -11,12 +11,12 @@ The table used to store events that have occurred in an aggregate. In principle,
|
|
|
11
11
|
|
|
12
12
|
| key name | description | example | remarks |
|
|
13
13
|
|:------------|:---------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|
|
|
14
|
-
| pkey | Partition key(
|
|
14
|
+
| pkey | Partition key(`${aggregate.typeName}-${shardId}`) | user-account-1 | |
|
|
15
15
|
| skey | Sort Key(${aggregate type name}-${aid.value}-${seq_nr}) | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z-12345 | |
|
|
16
16
|
| aid | Aggregate ID | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z | |
|
|
17
|
-
|
|
|
18
|
-
| payload |
|
|
19
|
-
| occurred_at |
|
|
17
|
+
| seq_nr | Sequence Number(origin=1) | 12345 | |
|
|
18
|
+
| payload | Serialized event payload bytes | {"type":"UserAccountCreated","data":{"typeName":"UserAccountCreated","isCreated":true,"id":"01H42KBHCW1BZG504J4ZXKA2F2","aggregateId":{"typeName":"user-account","value":"01H42K4ABWQ5V2XQEP3A48VE0Z"},"name":"Alice","sequenceNumber":1,"occurredAt":"2026-05-24T00:00:00.000Z"}} | Default JSON serializer example |
|
|
19
|
+
| occurred_at | UTC millisecond component from `event.occurredAt` | 0 | Stored as a DynamoDB number |
|
|
20
20
|
|
|
21
21
|
GSI is applied to aid and seq_nr, and this index is used during replay.
|
|
22
22
|
|
|
@@ -26,16 +26,17 @@ This table is used to store aggregate state and to speed up replay of aggregates
|
|
|
26
26
|
|
|
27
27
|
| column name | description | example | remarks |
|
|
28
28
|
|:------------|:----------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|
|
|
29
|
-
| pkey | Partition key(
|
|
29
|
+
| pkey | Partition key(`${aggregate.typeName}-${shardId}`) | user-account-1 | |
|
|
30
30
|
| skey | Sort Key(${aggregate type name}-${aid.value}-${seq_nr}), The latest snapshot is read/written as seq_nr=0. | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z-12345 | |
|
|
31
|
-
| payload |
|
|
31
|
+
| payload | Serialized aggregate snapshot bytes | {"type":"UserAccount","data":{"typeName":"UserAccount","id":{"typeName":"user-account","value":"01H42K4ABWQ5V2XQEP3A48VE0Z"},"name":"Alice","sequenceNumber":1,"version":1}} | Default JSON serializer example |
|
|
32
32
|
| aid | Aggregate ID | user-account-01H42K4ABWQ5V2XQEP3A48VE0Z | |
|
|
33
|
-
|
|
|
33
|
+
| seq_nr | Sequence Number(origin=1) | 12345 | |
|
|
34
34
|
| active_ttl_seq_nr | Sequence number projected only while the snapshot is not marked for TTL deletion | 12345 | |
|
|
35
35
|
| ttl | TTL for deletion(seconds) | 1624980000 | |
|
|
36
36
|
| version | Version for optimistic lock(origin=1) | 1 | |
|
|
37
|
+
| last_updated_at | UTC millisecond component from `event.occurredAt` | 0 | Stored as a DynamoDB number |
|
|
37
38
|
|
|
38
|
-
- When
|
|
39
|
+
- When retained snapshots are disabled, only a snapshot is stored at seq_nr=0. When `keepSnapshotCount` is set, retained snapshots are stored at seq_nr=event.sequenceNumber in addition to seq_nr=0. If the upper limit is exceeded, older retained snapshots are deleted first. By default, deletion is client-initiated; `deleteTtlMillis` can also be used to mark older retained snapshots for DynamoDB TTL deletion.
|
|
39
40
|
- GSI is applied to aid and seq_nr, and this index is used during replay and hard-delete retention.
|
|
40
41
|
- A sparse GSI is applied to aid and active_ttl_seq_nr. This index is used by TTL-based retention to read only snapshots that have not already been marked for TTL deletion. When TTL is set, active_ttl_seq_nr is removed from the item.
|
|
41
42
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# GCPにおけるイベント駆動連携の選択肢
|
|
2
2
|
|
|
3
|
-
このドキュメントは、`DynamoDB Streams + Lambda` に近い後段処理を GCP
|
|
4
|
-
対象日時は `2026-03-12`
|
|
3
|
+
このドキュメントは、`DynamoDB Streams + Lambda` に近い後段処理を GCP 上で実現する場合の選択肢を整理した設計メモです。
|
|
4
|
+
対象日時は `2026-03-12` 時点です。現在のライブラリには `EventStore.ofSpanner(...)` が実装済みで、Firestore adapter は未実装です。
|
|
5
5
|
|
|
6
6
|
## 結論
|
|
7
7
|
|
|
@@ -133,12 +133,12 @@
|
|
|
133
133
|
|
|
134
134
|
## このライブラリに対する示唆
|
|
135
135
|
|
|
136
|
-
GCP
|
|
136
|
+
GCP 対応の検討では、候補は次の 2 つでした。現在は Spanner adapter が `EventStore.ofSpanner(...)` として実装済みです。
|
|
137
137
|
|
|
138
138
|
| 候補 | 判断 |
|
|
139
139
|
|:--|:--|
|
|
140
|
-
|
|
|
141
|
-
| `
|
|
140
|
+
| Firestore adapter | 実装量優先なら候補。現在は未実装 |
|
|
141
|
+
| `EventStore.ofSpanner(...)` | `DynamoDB Streams` に近い構成を重視する候補。現在は実装済み |
|
|
142
142
|
|
|
143
143
|
`Bigtable` 向けアダプタは、少なくとも最初の GCP 対応としては推奨しません。
|
|
144
144
|
|