Skip to content

Commit 9b6a93d

Browse files
author
Swain Molster
committed
feat!: introduce DynamoStreamHandler
1 parent 0e64df6 commit 9b6a93d

File tree

7 files changed

+978
-8
lines changed

7 files changed

+978
-8
lines changed

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,83 @@ process AWS data streams.
66
```bash
77
yarn add @lifeomic/delta
88
```
9+
10+
### `DynamoStreamHandler`
11+
12+
This helper provides an abstraction over a DynamoDB Stream Lambda handler.
13+
14+
```typescript
15+
const stream = new DynamoStreamHandler({
16+
logger,
17+
unmarshall: (object) => {
18+
/* ... unmarshall from unknown stream format -> your custom type ... */
19+
return { id: object.id };
20+
},
21+
createRunContext: () => {
22+
/* ... create the "context", e.g. data sources ... */
23+
return { doSomething: () => null };
24+
},
25+
})
26+
.onInsert(async (ctx, entity) => {
27+
// INSERT actions receive a single strongly typed new entities
28+
// (entities are typed based on the `unmarshall` function)
29+
entity.id;
30+
31+
// `ctx` contains the nice result of `createRunContext`
32+
await ctx.dataSources.doSomething();
33+
34+
// `ctx` contains a logger by default, which already includes niceties like
35+
// the AWS request id
36+
ctx.logger.info('blah blah');
37+
})
38+
// The API is chainable to help with readability
39+
.onModify(async (ctx, oldEntity, newEntity) => {
40+
// MODIFY actions receive strongly typed old + new entities
41+
oldEntity.id;
42+
newEntity.id;
43+
})
44+
.onRemove(async (ctx, oldEntity) => {
45+
// REMOVE actions receive a single strongly typed old entity
46+
oldEntity.id;
47+
48+
ctx.logger.info('first remove action');
49+
})
50+
// When multiple actions have been added for the same event (e.g. two `onRemove` calls),
51+
// they are executed in.order.
52+
.onRemove(async (ctx, oldEntity) => {
53+
ctx.logger.info('second remove action');
54+
});
55+
56+
// Provides a dead-simple API for creating the Lambda.
57+
export const handler = stream.lambda();
58+
```
59+
60+
`DynamoStreamHelper` also comes with a nice helper for testing: `harness(...)`
61+
62+
```typescript
63+
const harness = stream.harness({
64+
marshall: () => {
65+
/* marshall from your custom type -> stream format */
66+
},
67+
/* optionally override the logger */
68+
logger,
69+
createRunContext: () => {
70+
/* optionally override the context, to mock e.g. data sources */
71+
}
72+
})
73+
74+
test('something', async () => {
75+
// Provides a simple `sendEvent` function
76+
await harness.sendEvent({
77+
records: [
78+
// Simplified, strongly-typed event types for readability
79+
{ type: 'remove', entity: ... },
80+
{ type: 'insert', entity: ... },
81+
{ type: 'modify', oldEntity: ..., newEntity: ... },
82+
]
83+
})
84+
85+
// Also provides access to the underlying run context for assertions + mocking
86+
expect(harness.context.dataSources.doSomething).toHaveBeenCalled()
87+
})
88+
```

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,22 @@
2626
"devDependencies": {
2727
"@lifeomic/eslint-config-standards": "^2.1.1",
2828
"@lifeomic/jest-config": "^1.1.2",
29+
"@lifeomic/logging": "^4.0.0",
2930
"@lifeomic/typescript-config": "^1.0.3",
3031
"@types/jest": "^27.4.1",
32+
"@types/uuid": "^8.3.4",
3133
"eslint": "^8.9.0",
3234
"eslint-config-prettier": "^8.4.0",
3335
"jest": "^27.5.1",
3436
"prettier": "^2.5.1",
3537
"ts-jest": "^27.1.3",
36-
"typescript": "^4.5.5"
38+
"typescript": "^4.5.5",
39+
"uuid": "^8.3.2"
40+
},
41+
"dependencies": {
42+
"@types/aws-lambda": "^8.10.92"
43+
},
44+
"peerDependencies": {
45+
"@lifeomic/logging": "*"
3746
}
3847
}

0 commit comments

Comments
 (0)