From 88cab67320067d373e6923fb9bd7be8a689445c0 Mon Sep 17 00:00:00 2001 From: Andrew Courtice Date: Wed, 8 Sep 2021 15:31:05 +1000 Subject: [PATCH] feat(transaction): added transaction triggers and mutator helpers --- extensions/transaction/package.json | 6 +-- extensions/transaction/src/constants.ts | 1 + extensions/transaction/src/index.ts | 69 ++++++++++++++++++------- extensions/transaction/src/types.ts | 15 ++++-- 4 files changed, 63 insertions(+), 28 deletions(-) diff --git a/extensions/transaction/package.json b/extensions/transaction/package.json index b4a0d942..733ad606 100644 --- a/extensions/transaction/package.json +++ b/extensions/transaction/package.json @@ -38,12 +38,12 @@ "build": "tsup", "prepublish": "yarn build" }, + "dependencies": { + "@harlem/extension-snapshot": "^2.0.0-beta.9" + }, "peerDependencies": { "@harlem/core": "^2.0.0-alpha.0" }, - "dependencies": { - "@harlem/utilities": "^2.0.0-beta.9" - }, "devDependencies": { "@harlem/core": "^2.0.0-beta.9" } diff --git a/extensions/transaction/src/constants.ts b/extensions/transaction/src/constants.ts index c065c047..1cdf8cc3 100644 --- a/extensions/transaction/src/constants.ts +++ b/extensions/transaction/src/constants.ts @@ -4,6 +4,7 @@ export const EVENTS = { transaction: { before: 'transaction:before', after: 'transaction:after', + success: 'transaction:success', error: 'transaction:error', }, }; \ No newline at end of file diff --git a/extensions/transaction/src/index.ts b/extensions/transaction/src/index.ts index 7bcfbc3a..3ef4b138 100644 --- a/extensions/transaction/src/index.ts +++ b/extensions/transaction/src/index.ts @@ -1,59 +1,88 @@ +import snapshotExtension from '@harlem/extension-snapshot'; + import { SENDER, EVENTS, } from './constants'; -import { - clone, - overwrite, -} from '@harlem/utilities'; - import { BaseState, + EventPayload, InternalStore, - ReadState, + Mutator, } from '@harlem/core'; import type { Transactor, Transaction, TransactionEventData, + TransactionHookHandler, } from './types'; export * from './types'; export default function transactionExtension() { return (store: InternalStore) => { - function rollback(snapshot: ReadState) { - store.write('$transaction-rollback', SENDER, state => overwrite(state, snapshot)); - } + const { + snapshot, + } = snapshotExtension({ + mutationName: '$transaction-rollback', + })(store); + - function transaction(name: string, transactor: Transactor): Transaction { - return payload => { - const snapshot = clone(store.state) as ReadState; + function transaction(name: string, transactor: Transactor): Transaction { + const mutate = (mutator: Mutator) => store.write(name, SENDER, mutator); - const eventData = { - payload, + return ((payload: TPayload) => { + const snap = snapshot(); + const providedPayload = store.providers.payload(payload) ?? payload; + + const emit = (event: string) => store.emit(event, SENDER, { transaction: name, - } as TransactionEventData; + payload: providedPayload, + } as TransactionEventData); - store.emit(EVENTS.transaction.before, SENDER, eventData); + emit(EVENTS.transaction.before); try { - transactor(payload!); + const providedPayload = store.providers.payload(payload) ?? payload; + + transactor(providedPayload, mutate); + emit(EVENTS.transaction.success); } catch (error) { - rollback(snapshot); - store.emit(EVENTS.transaction.error, SENDER, eventData); + snap.apply(); + emit(EVENTS.transaction.error); throw error; + } finally { + emit(EVENTS.transaction.after); } + }) as Transaction; + } - store.emit(EVENTS.transaction.after, SENDER, eventData); + function getTransactionTrigger(eventName: string) { + return (actionName: string | string[], handler: TransactionHookHandler) => { + const transactions = ([] as string[]).concat(actionName); + + return store.on(eventName, (event?: EventPayload) => { + if (event && transactions.includes(event.data.transaction)) { + handler(event.data); + } + }); }; } + const onBeforeTransaction = getTransactionTrigger(EVENTS.transaction.before); + const onAfterTransaction = getTransactionTrigger(EVENTS.transaction.after); + const onTransactionSuccess = getTransactionTrigger(EVENTS.transaction.success); + const onTransactionError = getTransactionTrigger(EVENTS.transaction.error); + return { transaction, + onBeforeTransaction, + onAfterTransaction, + onTransactionSuccess, + onTransactionError, }; }; } \ No newline at end of file diff --git a/extensions/transaction/src/types.ts b/extensions/transaction/src/types.ts index dbd58349..e2101436 100644 --- a/extensions/transaction/src/types.ts +++ b/extensions/transaction/src/types.ts @@ -1,8 +1,13 @@ -export type Transactor = undefined extends TPayload ? (payload?: TPayload) => void : (payload: TPayload) => void; -export type Transaction = (payload?: TPayload) => void; -export type TransactionRollback = () => void; +import type { + BaseState, + Mutator, +} from '@harlem/core'; -export interface TransactionEventData { +export type Transactor = (payload: TPayload, mutator: (mutate: Mutator) => void) => void; +export type Transaction = undefined extends TPayload ? (payload?: TPayload) => void : (payload: TPayload) => void; +export type TransactionHookHandler = (data: TransactionEventData) => void; + +export interface TransactionEventData { transaction: string; - payload: any; + payload: TPayload; } \ No newline at end of file