@eventualize/dynamodb-storage-adapter 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DynamoDbClient.d.ts +15 -2
- package/dist/DynamoDbClient.js +10 -19
- package/dist/DynamoDbClient.js.map +1 -1
- package/dist/EvDBDynamoDBAdmin.d.ts +10 -5
- package/dist/EvDBDynamoDBAdmin.js +16 -14
- package/dist/EvDBDynamoDBAdmin.js.map +1 -1
- package/dist/EvDbDynamoDbStorageAdapter.d.ts +30 -42
- package/dist/EvDbDynamoDbStorageAdapter.js +45 -55
- package/dist/EvDbDynamoDbStorageAdapter.js.map +1 -1
- package/dist/EvDbDynamoDbStorageAdapterQueries.d.ts +9 -7
- package/dist/EvDbDynamoDbStorageAdapterQueries.js +31 -31
- package/dist/EvDbDynamoDbStorageAdapterQueries.js.map +1 -1
- package/package.json +17 -2
- package/models/events-table-schema.json +0 -50
- package/models/messages-table-schema.json +0 -24
- package/models/snapshots-table-schema.json +0 -24
- package/src/DynamoDbClient.ts +0 -32
- package/src/EvDBDynamoDBAdmin.ts +0 -115
- package/src/EvDbDynamoDbStorageAdapter.ts +0 -250
- package/src/EvDbDynamoDbStorageAdapterQueries.ts +0 -210
- package/src/dbModel.json +0 -215
- package/tsconfig.json +0 -21
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import { unmarshall } from "@aws-sdk/util-dynamodb";
|
|
2
|
-
|
|
3
|
-
import { IEvDbPayloadData } from '@eventualize/types/IEvDbEventPayload';
|
|
4
|
-
import IEvDbEventMetadata from '@eventualize/types/IEvDbEventMetadata';
|
|
5
|
-
import EvDbStreamCursor from '@eventualize/types/EvDbStreamCursor';
|
|
6
|
-
import EvDbMessage from '@eventualize/types/EvDbMessage';
|
|
7
|
-
import IEvDbStorageSnapshotAdapter from '@eventualize/types/IEvDbStorageSnapshotAdapter';
|
|
8
|
-
import IEvDbStorageStreamAdapter from '@eventualize/types/IEvDbStorageStreamAdapter';
|
|
9
|
-
import EvDbStreamAddress from '@eventualize/types/EvDbStreamAddress';
|
|
10
|
-
import EvDbViewAddress from '@eventualize/types/EvDbViewAddress';
|
|
11
|
-
import { EvDbStoredSnapshotResultRaw } from '@eventualize/types/EvDbStoredSnapshotResult';
|
|
12
|
-
import { EvDbStoredSnapshotData } from '@eventualize/types/EvDbStoredSnapshotData';
|
|
13
|
-
import EvDbEvent from '@eventualize/types/EvDbEvent';
|
|
14
|
-
import StreamStoreAffected from '@eventualize/types/StreamStoreAffected';
|
|
15
|
-
import EvDbContinuousFetchOptions from '@eventualize/types/EvDbContinuousFetchOptions';
|
|
16
|
-
import EvDbMessageFilter from '@eventualize/types/EvDbMessageFilter';
|
|
17
|
-
import { EvDbShardName } from '@eventualize/types/primitiveTypes';
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
import { createDynamoDBClient, listTables } from './DynamoDbClient.js';
|
|
21
|
-
import QueryProvider, { deserializeStreamAddress, EventRecord, MessageRecord } from './EvDbDynamoDbStorageAdapterQueries.js'
|
|
22
|
-
import { DynamoDBClient, TransactionCanceledException, TransactWriteItemsCommand } from '@aws-sdk/client-dynamodb';
|
|
23
|
-
|
|
24
|
-
// Type definitions for records
|
|
25
|
-
export interface EvDbEventRecord extends IEvDbEventMetadata {
|
|
26
|
-
id: string;
|
|
27
|
-
payload: IEvDbPayloadData;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface EvDbSnapshotRecord {
|
|
31
|
-
id: string;
|
|
32
|
-
streamType: string;
|
|
33
|
-
streamId: string;
|
|
34
|
-
viewName: string;
|
|
35
|
-
offset: bigint;
|
|
36
|
-
state: IEvDbPayloadData;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface IEvDbOutboxTransformer {
|
|
40
|
-
transform(message: EvDbMessage): EvDbMessage;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface EvDbStorageContext {
|
|
44
|
-
schema?: string;
|
|
45
|
-
shortId: string;
|
|
46
|
-
id: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const serializePayload = (payload: IEvDbPayloadData) => Buffer.from(JSON.stringify(payload), 'utf-8');
|
|
50
|
-
const deserializePayload = (payload: any): IEvDbPayloadData => {
|
|
51
|
-
if (!!payload && typeof payload == 'object') {
|
|
52
|
-
return payload;
|
|
53
|
-
}
|
|
54
|
-
return {};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Prisma-based storage adapter for EvDb
|
|
59
|
-
* Replaces SQL Server-specific adapter with database-agnostic Prisma implementation
|
|
60
|
-
*/
|
|
61
|
-
export default class EvDbDynamoDbStorageAdapter implements IEvDbStorageSnapshotAdapter, IEvDbStorageStreamAdapter {
|
|
62
|
-
constructor(private dynamoDbClient: DynamoDBClient = createDynamoDBClient()) {
|
|
63
|
-
}
|
|
64
|
-
getFromOutbox(filter: EvDbMessageFilter, options?: EvDbContinuousFetchOptions | null): Promise<AsyncIterable<EvDbMessage>> {
|
|
65
|
-
throw new Error('Method not implemented.');
|
|
66
|
-
}
|
|
67
|
-
getFromOutboxAsync(shard: EvDbShardName, filter: EvDbMessageFilter, options?: EvDbContinuousFetchOptions | null, cancellation?: AbortSignal): AsyncIterable<EvDbMessage> {
|
|
68
|
-
throw new Error('Method not implemented.');
|
|
69
|
-
}
|
|
70
|
-
getRecordsFromOutboxAsync(filter: EvDbMessageFilter, options?: EvDbContinuousFetchOptions | null, cancellation?: AbortSignal): AsyncIterable<EvDbMessage>;
|
|
71
|
-
getRecordsFromOutboxAsync(shard: EvDbShardName, filter: EvDbMessageFilter, options?: EvDbContinuousFetchOptions | null, cancellation?: AbortSignal): AsyncIterable<EvDbMessage>;
|
|
72
|
-
getRecordsFromOutboxAsync(shard: unknown, filter?: unknown, options?: unknown, cancellation?: unknown): AsyncIterable<EvDbMessage> {
|
|
73
|
-
throw new Error('Method not implemented.');
|
|
74
|
-
}
|
|
75
|
-
subscribeToMessageAsync(handler: (message: EvDbMessage) => Promise<void>, filter: EvDbMessageFilter, options?: EvDbContinuousFetchOptions | null): Promise<void>;
|
|
76
|
-
subscribeToMessageAsync(handler: (message: EvDbMessage) => Promise<void>, shard: EvDbShardName, filter: EvDbMessageFilter, options?: EvDbContinuousFetchOptions | null): Promise<void>;
|
|
77
|
-
subscribeToMessageAsync(handler: unknown, shard: unknown, filter?: unknown, options?: unknown): Promise<void> {
|
|
78
|
-
throw new Error('Method not implemented.');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Store stream events in a transaction
|
|
83
|
-
*/
|
|
84
|
-
async storeStreamAsync(
|
|
85
|
-
events: ReadonlyArray<EvDbEvent>,
|
|
86
|
-
messages: ReadonlyArray<EvDbMessage>,
|
|
87
|
-
): Promise<StreamStoreAffected> {
|
|
88
|
-
try {
|
|
89
|
-
await listTables(this.dynamoDbClient);
|
|
90
|
-
const eventsToInsert: EventRecord[] = events.map((event) =>
|
|
91
|
-
EventRecord.createFromEvent(event));
|
|
92
|
-
|
|
93
|
-
const messagesToInsert: MessageRecord[] = messages.map(message => {
|
|
94
|
-
return {
|
|
95
|
-
id: crypto.randomUUID(),
|
|
96
|
-
stream_cursor: message.streamCursor,
|
|
97
|
-
channel: message.channel,
|
|
98
|
-
message_type: message.messageType,
|
|
99
|
-
event_type: message.eventType,
|
|
100
|
-
captured_by: message.capturedBy,
|
|
101
|
-
captured_at: message.capturedAt,
|
|
102
|
-
payload: message.payload,
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
const storeEventsQuery = QueryProvider.saveEvents(eventsToInsert);
|
|
107
|
-
const storeMessagesQuery = QueryProvider.saveMessages(messagesToInsert);
|
|
108
|
-
|
|
109
|
-
const transactItems = { TransactItems: [...storeEventsQuery, ...storeMessagesQuery] };
|
|
110
|
-
|
|
111
|
-
const command = new TransactWriteItemsCommand(transactItems)
|
|
112
|
-
await this.dynamoDbClient.send(command);
|
|
113
|
-
|
|
114
|
-
const numEvents = eventsToInsert.length;
|
|
115
|
-
const numMessages = messagesToInsert
|
|
116
|
-
.reduce((prev, { message_type: t }) =>
|
|
117
|
-
Object.assign(prev, { [t]: (prev[t] ?? 0) + 1 }), {} as Record<string, number>);
|
|
118
|
-
return new StreamStoreAffected(numEvents, new Map(Object.entries(numMessages)));
|
|
119
|
-
} catch (error) {
|
|
120
|
-
if (this.isOccException(error)) {
|
|
121
|
-
throw new Error('OPTIMISTIC_CONCURRENCY_VIOLATION');
|
|
122
|
-
}
|
|
123
|
-
throw error;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Store outbox messages in a transaction
|
|
129
|
-
*/
|
|
130
|
-
async storeOutboxMessagesAsync(
|
|
131
|
-
shardName: EvDbShardName,
|
|
132
|
-
records: EvDbMessage[],
|
|
133
|
-
): Promise<number> {
|
|
134
|
-
throw new Error('Method not implemented.');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Get the last offset for a stream
|
|
139
|
-
*/
|
|
140
|
-
async getLastOffsetAsync(
|
|
141
|
-
streamAddress: EvDbStreamAddress
|
|
142
|
-
): Promise<number> {
|
|
143
|
-
const query = QueryProvider.getLastOffset(streamAddress);
|
|
144
|
-
const response = await this.dynamoDbClient.send(query);
|
|
145
|
-
if (!response.Items) {
|
|
146
|
-
return -1;
|
|
147
|
-
}
|
|
148
|
-
return parseInt(response.Items[0]?.offset.N ?? '-1', 10);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Get events for a stream since a specific offset
|
|
153
|
-
*/
|
|
154
|
-
async *getEventsAsync(
|
|
155
|
-
streamCursor: EvDbStreamCursor,
|
|
156
|
-
pageSize: number = 100
|
|
157
|
-
): AsyncGenerator<EvDbEvent, void, undefined> {
|
|
158
|
-
let queryCursor: Record<string, any> | undefined = undefined;
|
|
159
|
-
|
|
160
|
-
do {
|
|
161
|
-
const getEventsCommand = QueryProvider.getEvents(streamCursor);
|
|
162
|
-
const response = await this.dynamoDbClient.send(getEventsCommand);
|
|
163
|
-
|
|
164
|
-
if (response.Items && response.Items.length > 0) {
|
|
165
|
-
for (const item of response.Items) {
|
|
166
|
-
const res = unmarshall(item);
|
|
167
|
-
const streamAddress = deserializeStreamAddress(res.stream_address)
|
|
168
|
-
const r: EventRecord = new EventRecord(
|
|
169
|
-
crypto.randomUUID(),
|
|
170
|
-
new EvDbStreamCursor(streamAddress.streamType, streamAddress.streamId, res.offset),
|
|
171
|
-
res.event_type,
|
|
172
|
-
res.captured_by,
|
|
173
|
-
new Date(res.captured_at),
|
|
174
|
-
res.payload,
|
|
175
|
-
new Date(res.stored_at)
|
|
176
|
-
);
|
|
177
|
-
yield r.toEvDbEvent();
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
queryCursor = response.LastEvaluatedKey;
|
|
182
|
-
|
|
183
|
-
} while (queryCursor)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Get snapshot for a stream view
|
|
188
|
-
*/
|
|
189
|
-
async getSnapshotAsync(
|
|
190
|
-
viewAddress: EvDbViewAddress
|
|
191
|
-
): Promise<EvDbStoredSnapshotResultRaw> {
|
|
192
|
-
const { streamType, streamId, viewName } = viewAddress;
|
|
193
|
-
try {
|
|
194
|
-
const query = QueryProvider.getSnapshot(viewAddress);
|
|
195
|
-
const response = await this.dynamoDbClient.send(query);
|
|
196
|
-
|
|
197
|
-
if (!response.Items) {
|
|
198
|
-
return EvDbStoredSnapshotResultRaw.Empty;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const snapshot = unmarshall(response.Items[0]);
|
|
202
|
-
|
|
203
|
-
return new EvDbStoredSnapshotResultRaw(
|
|
204
|
-
snapshot.offset,
|
|
205
|
-
new Date(Number(snapshot.stored_at)),
|
|
206
|
-
snapshot.state,
|
|
207
|
-
);
|
|
208
|
-
} catch (error) {
|
|
209
|
-
throw error;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Save a snapshot
|
|
215
|
-
*/
|
|
216
|
-
async storeSnapshotAsync(record: EvDbStoredSnapshotData): Promise<void> {
|
|
217
|
-
try {
|
|
218
|
-
const command = QueryProvider.saveSnapshot(record);
|
|
219
|
-
await this.dynamoDbClient.send(command);
|
|
220
|
-
|
|
221
|
-
} catch (error) {
|
|
222
|
-
throw error;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Check if an exception is an optimistic concurrency conflict
|
|
228
|
-
*/
|
|
229
|
-
private isOccException(error: unknown): boolean {
|
|
230
|
-
if (!(error instanceof TransactionCanceledException)) {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
return !!(error as TransactionCanceledException)
|
|
234
|
-
.CancellationReasons?.some(({ Code }) => Code === 'ConditionalCheckFailed')
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Get table name for shard
|
|
239
|
-
*/
|
|
240
|
-
private getTableNameForShard(shardName: EvDbShardName): string {
|
|
241
|
-
throw new Error('Method not implemented.');
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Close the database connection
|
|
246
|
-
*/
|
|
247
|
-
async close(): Promise<void> {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import IEvDbEventPayload, { IEvDbPayloadData } from "@eventualize/types/IEvDbEventPayload"
|
|
2
|
-
import { AttributeValue, GetItemCommandInput, PutItemCommand, PutItemCommandInput, QueryCommand, QueryCommandInput, TransactWriteItem } from "@aws-sdk/client-dynamodb";
|
|
3
|
-
import EvDbStreamCursor from "@eventualize/types/EvDbStreamCursor";
|
|
4
|
-
import EvDbStreamAddress from "@eventualize/types/EvDbStreamAddress";
|
|
5
|
-
import EvDbEvent from "@eventualize/types/EvDbEvent";
|
|
6
|
-
import EvDbViewAddress from "@eventualize/types/EvDbViewAddress";
|
|
7
|
-
import { EvDbStoredSnapshotData } from "@eventualize/types/EvDbStoredSnapshotData";
|
|
8
|
-
import { marshall } from "@aws-sdk/util-dynamodb";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export class EventRecord {
|
|
12
|
-
constructor(
|
|
13
|
-
public readonly id: string,
|
|
14
|
-
public readonly stream_cursor: EvDbStreamCursor,
|
|
15
|
-
public readonly event_type: string,
|
|
16
|
-
public readonly captured_by: string,
|
|
17
|
-
public readonly captured_at: Date,
|
|
18
|
-
public readonly payload: IEvDbEventPayload,
|
|
19
|
-
public readonly stored_at?: Date,
|
|
20
|
-
) { }
|
|
21
|
-
|
|
22
|
-
public static createFromEvent(e: EvDbEvent): EventRecord {
|
|
23
|
-
return new EventRecord(
|
|
24
|
-
crypto.randomUUID(),
|
|
25
|
-
e.streamCursor,
|
|
26
|
-
e.eventType,
|
|
27
|
-
e.capturedBy,
|
|
28
|
-
e.capturedAt,
|
|
29
|
-
e.payload,
|
|
30
|
-
e.storedAt)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public toEvDbEvent(): EvDbEvent {
|
|
34
|
-
return new EvDbEvent(
|
|
35
|
-
this.event_type,
|
|
36
|
-
this.stream_cursor,
|
|
37
|
-
this.payload,
|
|
38
|
-
this.captured_at,
|
|
39
|
-
this.captured_by,
|
|
40
|
-
new Date(Number(this.stored_at))
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export type MessageRecord = {
|
|
46
|
-
id: string
|
|
47
|
-
stream_cursor: EvDbStreamCursor
|
|
48
|
-
channel: string
|
|
49
|
-
message_type: string
|
|
50
|
-
event_type: string
|
|
51
|
-
captured_by: string
|
|
52
|
-
captured_at: Date
|
|
53
|
-
payload: IEvDbPayloadData
|
|
54
|
-
stored_at?: Date
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const serializeStreamAddress = (streamAddress: EvDbStreamAddress) => {
|
|
58
|
-
return `${streamAddress.streamType}::${streamAddress.streamId}`;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export const deserializeStreamAddress = (streamAddressStr: string): EvDbStreamAddress => {
|
|
62
|
-
const [streamType, streamId] = streamAddressStr.split('::');
|
|
63
|
-
return new EvDbStreamAddress(streamType, streamId);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const serializeMessageAddress = (m: MessageRecord) => {
|
|
67
|
-
return `${m.channel}::${m.message_type}`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const serializeViewAddress = (viewAddress: EvDbViewAddress) => {
|
|
71
|
-
return `${serializeStreamAddress(viewAddress)}::${viewAddress.viewName}`;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export default class EvDbDynamoDbStorageAdapterQueries {
|
|
75
|
-
|
|
76
|
-
public static saveEvents(events: EventRecord[]): TransactWriteItem[] {
|
|
77
|
-
const TransactItems = events.map(e => ({
|
|
78
|
-
Put: {
|
|
79
|
-
TableName: "events",
|
|
80
|
-
Item: {
|
|
81
|
-
stream_address: { S: serializeStreamAddress(e.stream_cursor) } as AttributeValue,
|
|
82
|
-
offset: { N: e.stream_cursor.offset.toString() },
|
|
83
|
-
event_type: { S: e.event_type },
|
|
84
|
-
captured_by: { S: e.captured_by },
|
|
85
|
-
captured_at: { S: e.captured_at.getTime().toString() },
|
|
86
|
-
payload: {
|
|
87
|
-
M: marshall(e.payload, {
|
|
88
|
-
convertClassInstanceToMap: true,
|
|
89
|
-
removeUndefinedValues: true
|
|
90
|
-
})
|
|
91
|
-
},
|
|
92
|
-
stored_at: { S: Date.now().toString() }
|
|
93
|
-
},
|
|
94
|
-
ConditionExpression: "(attribute_not_exists(#sa)) Or (attribute_exists(#sa) And attribute_not_exists(#offset))",
|
|
95
|
-
ExpressionAttributeNames: {
|
|
96
|
-
"#sa": "stream_address",
|
|
97
|
-
"#offset": "offset"
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}));
|
|
101
|
-
|
|
102
|
-
return TransactItems;
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public static saveMessages(messages: MessageRecord[]): TransactWriteItem[] {
|
|
107
|
-
const TransactItems = messages.map(m => ({
|
|
108
|
-
Put: {
|
|
109
|
-
TableName: "messages",
|
|
110
|
-
Item: {
|
|
111
|
-
message_address: { S: serializeMessageAddress(m) },
|
|
112
|
-
stream_address: { S: serializeStreamAddress(m.stream_cursor) },
|
|
113
|
-
offset: { N: m.stream_cursor.offset.toString() },
|
|
114
|
-
event_type: { S: m.event_type },
|
|
115
|
-
captured_by: { S: m.captured_by },
|
|
116
|
-
captured_at: { S: `${m.captured_at.getTime().toString()}::${crypto.randomUUID()}` },
|
|
117
|
-
payload: {
|
|
118
|
-
M: marshall(m.payload, {
|
|
119
|
-
convertClassInstanceToMap: true,
|
|
120
|
-
removeUndefinedValues: true
|
|
121
|
-
})
|
|
122
|
-
},
|
|
123
|
-
stored_at: { S: Date.now().toString() }
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}));
|
|
127
|
-
|
|
128
|
-
return TransactItems;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
public static getLastOffset(streamAddress: EvDbStreamAddress): QueryCommand {
|
|
132
|
-
const queryParams = {
|
|
133
|
-
TableName: "events",
|
|
134
|
-
KeyConditionExpression: "stream_address = :pk",
|
|
135
|
-
ExpressionAttributeValues: {
|
|
136
|
-
":pk": { S: serializeStreamAddress(streamAddress) }
|
|
137
|
-
},
|
|
138
|
-
ScanIndexForward: false,
|
|
139
|
-
Limit: 1
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return new QueryCommand(queryParams);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
public static getEvents(streamCursor: EvDbStreamCursor, queryCursor: Record<string, any> | undefined = undefined, pageSize: number = 100) {
|
|
146
|
-
const queryParams = {
|
|
147
|
-
TableName: "events",
|
|
148
|
-
KeyConditionExpression: "#sa = :sa AND #o >= :offsetValue",
|
|
149
|
-
ExpressionAttributeNames: {
|
|
150
|
-
"#o": "offset",
|
|
151
|
-
"#sa": "stream_address",
|
|
152
|
-
"#cb": "captured_by"
|
|
153
|
-
},
|
|
154
|
-
ExpressionAttributeValues: {
|
|
155
|
-
":sa": { S: serializeStreamAddress(streamCursor) },
|
|
156
|
-
":offsetValue": { N: streamCursor.offset.toString() }
|
|
157
|
-
},
|
|
158
|
-
ProjectionExpression: '#sa, #o, id, event_type, captured_at, #cb, stored_at, payload',
|
|
159
|
-
Limit: pageSize,
|
|
160
|
-
ExclusiveStartKey: queryCursor
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return new QueryCommand(queryParams);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
public static getSnapshot(viewAddress: EvDbViewAddress) {
|
|
167
|
-
const queryParams = {
|
|
168
|
-
TableName: "snapshots",
|
|
169
|
-
KeyConditionExpression: "view_address = :sa",
|
|
170
|
-
|
|
171
|
-
ExpressionAttributeValues: {
|
|
172
|
-
":sa": { S: serializeViewAddress(viewAddress) },
|
|
173
|
-
},
|
|
174
|
-
ProjectionExpression: '#o, #s, stored_at',
|
|
175
|
-
ExpressionAttributeNames: {
|
|
176
|
-
"#o": "offset",
|
|
177
|
-
"#s": "state"
|
|
178
|
-
},
|
|
179
|
-
ScanIndexForward: false, // false = descending order
|
|
180
|
-
Limit: 1
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return new QueryCommand(queryParams);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
public static saveSnapshot(snapshot: EvDbStoredSnapshotData): PutItemCommand {
|
|
187
|
-
const viewAddress = new EvDbViewAddress(snapshot.streamType, snapshot.streamId, snapshot.viewName);
|
|
188
|
-
const queryParams: PutItemCommandInput = {
|
|
189
|
-
TableName: "snapshots",
|
|
190
|
-
Item: {
|
|
191
|
-
view_address: { S: serializeViewAddress(viewAddress) },
|
|
192
|
-
offset: { N: snapshot.offset.toString() },
|
|
193
|
-
state: {
|
|
194
|
-
M: marshall(snapshot.state, {
|
|
195
|
-
convertClassInstanceToMap: true,
|
|
196
|
-
removeUndefinedValues: true
|
|
197
|
-
})
|
|
198
|
-
},
|
|
199
|
-
stored_at: { S: Date.now().toString() }
|
|
200
|
-
},
|
|
201
|
-
ConditionExpression: "(attribute_not_exists(#va)) Or (attribute_exists(#va) And attribute_not_exists(#offset))",
|
|
202
|
-
ExpressionAttributeNames: {
|
|
203
|
-
"#va": "view_address",
|
|
204
|
-
"#offset": "offset"
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
return new PutItemCommand(queryParams);
|
|
209
|
-
}
|
|
210
|
-
}
|
package/src/dbModel.json
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"ModelName": "Eventualize Events Table",
|
|
3
|
-
"ModelMetadata": {
|
|
4
|
-
"Author": "",
|
|
5
|
-
"DateCreated": "Dec 12, 2025, 02:20 AM",
|
|
6
|
-
"DateLastModified": "Dec 12, 2025, 02:33 AM",
|
|
7
|
-
"Description": "",
|
|
8
|
-
"AWSService": "Amazon DynamoDB",
|
|
9
|
-
"Version": "3.0"
|
|
10
|
-
},
|
|
11
|
-
"DataModel": [
|
|
12
|
-
{
|
|
13
|
-
"TableName": "events",
|
|
14
|
-
"KeyAttributes": {
|
|
15
|
-
"PartitionKey": {
|
|
16
|
-
"AttributeName": "stream_address",
|
|
17
|
-
"AttributeType": "S"
|
|
18
|
-
},
|
|
19
|
-
"SortKey": {
|
|
20
|
-
"AttributeName": "offset",
|
|
21
|
-
"AttributeType": "N"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
"NonKeyAttributes": [
|
|
25
|
-
{
|
|
26
|
-
"AttributeName": "id",
|
|
27
|
-
"AttributeType": "S"
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
"AttributeName": "event_type",
|
|
31
|
-
"AttributeType": "S"
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"AttributeName": "captured_at",
|
|
35
|
-
"AttributeType": "S"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"AttributeName": "captured_by",
|
|
39
|
-
"AttributeType": "S"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"AttributeName": "stored_at",
|
|
43
|
-
"AttributeType": "S"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"AttributeName": "payload",
|
|
47
|
-
"AttributeType": "M"
|
|
48
|
-
}
|
|
49
|
-
],
|
|
50
|
-
"TableFacets": [],
|
|
51
|
-
"GlobalSecondaryIndexes": [
|
|
52
|
-
{
|
|
53
|
-
"IndexName": "event_type__captured_at",
|
|
54
|
-
"KeyAttributes": {
|
|
55
|
-
"PartitionKey": {
|
|
56
|
-
"AttributeName": "event_type",
|
|
57
|
-
"AttributeType": "S"
|
|
58
|
-
},
|
|
59
|
-
"SortKey": {
|
|
60
|
-
"AttributeName": "captured_at",
|
|
61
|
-
"AttributeType": "S"
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
"Projection": {
|
|
65
|
-
"ProjectionType": "ALL"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
],
|
|
69
|
-
"TableData": [],
|
|
70
|
-
"DataAccess": {
|
|
71
|
-
"MySql": {}
|
|
72
|
-
},
|
|
73
|
-
"SampleDataFormats": {
|
|
74
|
-
"offset": [
|
|
75
|
-
"Int"
|
|
76
|
-
],
|
|
77
|
-
"id": [
|
|
78
|
-
"identifiers",
|
|
79
|
-
"UUID"
|
|
80
|
-
],
|
|
81
|
-
"event_type": [
|
|
82
|
-
"dataTypes",
|
|
83
|
-
"String"
|
|
84
|
-
],
|
|
85
|
-
"captured_at": [
|
|
86
|
-
"date",
|
|
87
|
-
"Epoc/Unix date format"
|
|
88
|
-
],
|
|
89
|
-
"captured_by": [
|
|
90
|
-
"identifiers",
|
|
91
|
-
"Domain"
|
|
92
|
-
],
|
|
93
|
-
"stored_at": [
|
|
94
|
-
"date",
|
|
95
|
-
"Epoc/Unix date format"
|
|
96
|
-
]
|
|
97
|
-
},
|
|
98
|
-
"BillingMode": "PAY_PER_REQUEST"
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"TableName": "snapshots",
|
|
102
|
-
"KeyAttributes": {
|
|
103
|
-
"PartitionKey": {
|
|
104
|
-
"AttributeName": "view_address",
|
|
105
|
-
"AttributeType": "S"
|
|
106
|
-
},
|
|
107
|
-
"SortKey": {
|
|
108
|
-
"AttributeName": "offset",
|
|
109
|
-
"AttributeType": "N"
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
"NonKeyAttributes": [
|
|
113
|
-
{
|
|
114
|
-
"AttributeName": "stored_at",
|
|
115
|
-
"AttributeType": "S"
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"AttributeName": "state",
|
|
119
|
-
"AttributeType": "M"
|
|
120
|
-
}
|
|
121
|
-
],
|
|
122
|
-
"TableFacets": [],
|
|
123
|
-
"GlobalSecondaryIndexes": [],
|
|
124
|
-
"TableData": [],
|
|
125
|
-
"DataAccess": {
|
|
126
|
-
"MySql": {}
|
|
127
|
-
},
|
|
128
|
-
"SampleDataFormats": {
|
|
129
|
-
"offset": [
|
|
130
|
-
"Int"
|
|
131
|
-
],
|
|
132
|
-
"view_address": [
|
|
133
|
-
"dataTypes",
|
|
134
|
-
"String"
|
|
135
|
-
],
|
|
136
|
-
"stored_at": [
|
|
137
|
-
"date",
|
|
138
|
-
"Epoc/Unix date format"
|
|
139
|
-
]
|
|
140
|
-
},
|
|
141
|
-
"BillingMode": "PAY_PER_REQUEST"
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
"TableName": "messages",
|
|
145
|
-
"KeyAttributes": {
|
|
146
|
-
"PartitionKey": {
|
|
147
|
-
"AttributeName": "message_addres",
|
|
148
|
-
"AttributeType": "S"
|
|
149
|
-
},
|
|
150
|
-
"SortKey": {
|
|
151
|
-
"AttributeName": "captured_at",
|
|
152
|
-
"AttributeType": "S"
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
"NonKeyAttributes": [
|
|
156
|
-
{
|
|
157
|
-
"AttributeName": "event_type",
|
|
158
|
-
"AttributeType": "S"
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
"AttributeName": "offset",
|
|
162
|
-
"AttributeType": "N"
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
"AttributeName": "stored_at",
|
|
166
|
-
"AttributeType": "S"
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
"AttributeName": "captured_by",
|
|
170
|
-
"AttributeType": "S"
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
"AttributeName": "payload",
|
|
174
|
-
"AttributeType": "M"
|
|
175
|
-
}
|
|
176
|
-
],
|
|
177
|
-
"TableFacets": [],
|
|
178
|
-
"GlobalSecondaryIndexes": [],
|
|
179
|
-
"TableData": [],
|
|
180
|
-
"DataAccess": {
|
|
181
|
-
"MySql": {}
|
|
182
|
-
},
|
|
183
|
-
"SampleDataFormats": {
|
|
184
|
-
"message_addres": [
|
|
185
|
-
"dataTypes",
|
|
186
|
-
"String"
|
|
187
|
-
],
|
|
188
|
-
"captured_at": [
|
|
189
|
-
"date",
|
|
190
|
-
"Epoc/Unix date format"
|
|
191
|
-
],
|
|
192
|
-
"event_type": [
|
|
193
|
-
"dataTypes",
|
|
194
|
-
"String"
|
|
195
|
-
],
|
|
196
|
-
"offset": [
|
|
197
|
-
"Int"
|
|
198
|
-
],
|
|
199
|
-
"channel": [
|
|
200
|
-
"dataTypes",
|
|
201
|
-
"String"
|
|
202
|
-
],
|
|
203
|
-
"stored_at": [
|
|
204
|
-
"date",
|
|
205
|
-
"Epoc/Unix date format"
|
|
206
|
-
],
|
|
207
|
-
"captured_by": [
|
|
208
|
-
"identifiers",
|
|
209
|
-
"Domain"
|
|
210
|
-
]
|
|
211
|
-
},
|
|
212
|
-
"BillingMode": "PAY_PER_REQUEST"
|
|
213
|
-
}
|
|
214
|
-
]
|
|
215
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "./dist",
|
|
5
|
-
"rootDir": "./src",
|
|
6
|
-
"moduleResolution": "node",
|
|
7
|
-
"module": "es2020",
|
|
8
|
-
"target": "es2020",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
},
|
|
12
|
-
"references": [
|
|
13
|
-
{
|
|
14
|
-
"path": "../types"
|
|
15
|
-
}
|
|
16
|
-
],
|
|
17
|
-
"include": [
|
|
18
|
-
"src/**/*.ts",
|
|
19
|
-
"../prisma.config.ts",
|
|
20
|
-
]
|
|
21
|
-
}
|