0.17.0
🚀 What's New
1. Added idempotence check tests for PostgreSQL projections. Now you can simulate retries, ensuring that your projection handling is idempotent. You can do it by specifying when
options, passing the number of times, e.g. { numberOfTimes: 2 }
See full example:
void test('with idempotency check', () => {
const couponId = uuid();
return given(
eventsInStream<ProductItemAdded>(shoppingCartId, [
{
type: 'ProductItemAdded',
data: {
productItem: { price: 100, productId: 'shoes', quantity: 100 },
},
},
]),
)
.when(
newEventsInStream(shoppingCartId, [
{
type: 'DiscountApplied',
data: { percent: 10, couponId },
},
]),
{ numberOfTimes: 2 },
)
.then(
expectPongoDocuments
.fromCollection<ShoppingCartShortInfo>(
shoppingCartShortInfoCollectionName,
)
.withId(shoppingCartId)
.toBeEqual({
productItemsCount: 100,
totalAmount: 9000,
appliedDiscounts: [couponId],
}),
);
})
Note: This is not needed for inline projections as they will be either applied or not, but it will be more apt for async projections.
by @oskardudycz in 106
2. Added initialState
option to Pongo projections to allow getting a non-nullable state
It's optional, but you can do it by:
const shoppingCartShortInfoProjection = pongoSingleStreamProjection({
collectionName: shoppingCartShortInfoCollectionName,
evolve,
canHandle: ['ProductItemAdded', 'DiscountApplied'],
initialState: () => ({
productItemsCount: 0,
totalAmount: 0,
appliedDiscounts: [],
}),
});
Then your evolve function will require to have the signature taking non-nullable state, e.g.:
const evolve = (
document: ShoppingCartShortInfo,
{ type, data: event }: ProductItemAdded | DiscountApplied,
): ShoppingCartShortInfo => {
switch (type) {
case 'ProductItemAdded':
return {
...document,
totalAmount:
document.totalAmount +
event.productItem.price * event.productItem.quantity,
productItemsCount:
document.productItemsCount + event.productItem.quantity,
};
case 'DiscountApplied':
// idempotence check
if (document.appliedDiscounts.includes(event.couponId)) return document;
return {
...document,
totalAmount: (document.totalAmount * (100 - event.percent)) / 100,
appliedDiscounts: [...document.appliedDiscounts, event.couponId],
};
}
};
by @oskardudycz in 106
3. Extended typing for PostgreSQL projections to include global store position in event metadata
PostgreSQL event store maintains the global position, so it's worth reflecting that through the metadata.
Full Changelog: 0.16.0...0.17.0