import {Aggregate, EventWithMetadata, KeySchema} from '@ddes/core' import {randomBytes} from 'crypto'
class BankAccount extends Aggregate { static eventstore = myStore static keySchema = new KeySchema([ { name: 'id', value(props: {id: string}) { return props.id || randomBytes(8).toString('base64') }, }, ])
static stateReducer(state: any, event: EventWithMetadata) { switch (event.type) { case 'Opened': { const {id, name} = event.properties return {...state, id, name, balance: 0} }
case 'MoneyDeposited': { return {...state, balance: state.balance + event.properties.amount} }
case 'MoneyWithdrawn': { return {...state, balance: state.balance - event.properties.amount} }
case 'Frozen': { return {...state, frozen: true, freezeReason: event.properties.reason} }
case 'Unfrozen': { const {freezeReason, ...restState} = state return {...restState, frozen: false} }
case 'ForceDeleted': { return null }
default: return state } }
async create(props: {id: string; name: string}) { const {id, name} = props
if (!name) { throw new Error('You must specify a name!') }
if (this.state) { throw new Error('Account already exists') }
return await this.commit({ type: 'Opened', properties: { id, name, }, }) }
async withdraw(amount: number) { if (this.state.frozen) throw new Error( `Cannot withdraw money from a frozen account: ${ this.state.freezeReason }` )
if (amount <= 0) throw new Error('The deposit amount must be more than 0')
if (this.state.balance < amount) throw new Error('Not enough moneys')
return await this.commit({type: 'MoneyWithdrawn', properties: {amount}}) }
async deposit(amount: number) { if (this.state.frozen) throw new Error( `Cannot deposit money to a frozen account: ${this.state.freezeReason}` )
if (amount <= 0) throw new Error('The deposit amount must be more than 0')
return await this.commit({type: 'MoneyDeposited', properties: {amount}}) }
async freeze(reason: string) { if (this.state.frozen && this.state.freezeReason === reason) return
return await this.commit({type: 'Frozen', properties: {reason}}) }
async unfreeze() { if (!this.state.frozen) return
return await this.commit({type: 'Unfrozen'}) }
async forceDelete() { return await this.commit({type: 'ForceDeleted'}) } }
|