Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save chuasonglin1995/95a8ecc510dce6f6e0f7c2e36a761ce5 to your computer and use it in GitHub Desktop.
Save chuasonglin1995/95a8ecc510dce6f6e0f7c2e36a761ce5 to your computer and use it in GitHub Desktop.
Domain Event Publishers
import { DomainEvent } from 'path-to-DomainEvent';
interface DomainEventPublisher {
publish(aggregateType: string, aggregateId: any, domainEvents: DomainEvent[]): void;
}
abstract class AbstractAggregateDomainEventPublisher<A, E extends DomainEvent> {
private idSupplier: (aggregate: A) => any;
private eventPublisher: DomainEventPublisher;
private aggregateType: new () => A;
protected constructor(
eventPublisher: DomainEventPublisher,
aggregateType: new () => A,
idSupplier: (aggregate: A) => any
) {
this.eventPublisher = eventPublisher;
this.aggregateType = aggregateType;
this.idSupplier = idSupplier;
}
public publish(aggregate: A, events: E[]): void {
this.eventPublisher.publish(this.aggregateType, this.idSupplier(aggregate), events as DomainEvent[]);
}
}
export interface IDomainEvent<T> {
queue: string;
idempotencyId: string;
event: string;
data: T;
}
interface IBankingTransactionCompletedData {
userId: string;
amount: number;
currency: string;
}
interface IBankingTransactionFailedData {
userId: string;
failReason: string;
}
interface IBankingTransactionCompletedEvent extends IDomainEvent<IBankingTransactionCompletedData> {}
abstract class AbstractAggregateDomainEventPublisher<E extends IDomainEvent<any>> {
private eventPublisher: EventPublisher;
constructor() {}
public publish(events: E[]): void {
this.eventPublisher.publish(events as IDomainEvent<any>[]);
}
}
###################################################################################
enum BankingDomainEvents {
BankingTransactionCompleted = 'BankingTransactionCompleted',
BankingTransactionFailed = 'BankingTransactionFailed',
// Add more domain events here...
}
import { Transactional } from 'typeorm';
@Transactional()
class OrderService {
private orderRepository: OrderRepository;
private createOrderSagaManager: SagaManager<CreateOrderSagaState, CreateOrderSagaState>;
private reviseOrderSagaManager: SagaManager<ReviseOrderSagaState, ReviseOrderSagaData>;
private orderAggregateEventPublisher: OrderDomainEventPublisher;
constructor(
orderRepository: OrderRepository,
createOrderSagaManager: SagaManager<CreateOrderSagaState, CreateOrderSagaState>,
reviseOrderSagaManager: SagaManager<ReviseOrderSagaState, ReviseOrderSagaData>,
orderAggregateEventPublisher: OrderDomainEventPublisher
) {
this.orderRepository = orderRepository;
this.createOrderSagaManager = createOrderSagaManager;
this.reviseOrderSagaManager = reviseOrderSagaManager;
this.orderAggregateEventPublisher = orderAggregateEventPublisher;
}
public createOrder(orderDetails: OrderDetails): Order {
const restaurant: Restaurant = this.restaurantRepository.findById(restaurantId)
.orElseThrow(() => new RestaurantNotFoundException(restaurantId));
const orderLineItems: OrderLineItem[] = makeOrderLineItems(lineItems, restaurant);
const orderAndEvents: ResultWithDomainEvents<Order, OrderDomainEvent> = Order.createOrder(
consumerId,
restaurant,
orderLineItems
);
const order: Order = orderAndEvents.result;
this.orderRepository.save(order);
this.orderAggregateEventPublisher.publish(order, orderAndEvents.events);
const orderDetails: OrderDetails = new OrderDetails(
consumerId,
restaurantId,
orderLineItems,
order.getOrderTotal()
);
const data: CreateOrderSagaState = new CreateOrderSagaState(order.getId(), orderDetails);
this.createOrderSagaManager.create(data, Order, order.getId());
return order;
}
public reviseOrder(orderId: number, orderRevision: OrderRevision): Order {
const order: Order = this.orderRepository.findById(orderId)
.orElseThrow(() => new OrderNotFoundException(orderId));
const sagaData: ReviseOrderSagaData = new ReviseOrderSagaData(
order.getConsumerId(),
orderId,
null,
orderRevision
);
this.reviseOrderSagaManager.create(sagaData);
return order;
}
}
import { AbstractAggregateDomainEventPublisher } from 'path-to-AbstractAggregateDomainEventPublisher';
import { TicketDomainEvent } from 'path-to-TicketDomainEvent';
import { DomainEventPublisher } from 'path-to-DomainEventPublisher';
import { Ticket } from 'path-to-Ticket';
class TicketDomainEventPublisher extends AbstractAggregateDomainEventPublisher<Ticket, TicketDomainEvent> {
constructor(eventPublisher: DomainEventPublisher) {
super(eventPublisher, Ticket, (ticket: Ticket) => ticket.getId());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment