package com.github.daggerok.eventsourcing.user; import com.github.daggerok.eventsourcing.user.event.DomainEvent; import com.github.daggerok.eventsourcing.user.event.UserActivated; import com.github.daggerok.eventsourcing.user.event.UserCreated; import com.github.daggerok.eventsourcing.user.event.UserDeactivated; import io.vavr.API; import lombok.*; import java.util.Collection; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Function; import static io.vavr.API.$; import static io.vavr.API.Case; import static io.vavr.Predicates.instanceOf; /** * Created user can be: * - activated * - deactivated *

* Activated user can be: * - deactivated * Activated user cannot be: * - activated *

* Deactivated user can be: * - activated * Deactivated user cannot be: * - deactivated */ @Getter @ToString @NoArgsConstructor public class User implements Function { private UUID userId; private UserStatus state; private final Collection eventStream = new CopyOnWriteArrayList<>(); public void flushEvents() { eventStream.clear(); } public User(UUID userId) { create(userId); } public void create(UUID userId) { onCreate(new UserCreated(userId)); } // cmd 0: create public void create() { create(UUID.randomUUID()); } // evt: 0 private User onCreate(UserCreated event) { eventStream.add(event); this.userId = event.getAggregateId(); state = UserStatus.PENDING; return this; } // cmd 1: activate public void activate() { if (state == UserStatus.ACTIVE) throw new IllegalStateException("user is already active"); onActivate(new UserActivated(userId)); } // evt: 1 private User onActivate(UserActivated event) { eventStream.add(event); state = UserStatus.ACTIVE; return this; } // cmd 2: deactivate public void deactivate() { if (state == UserStatus.SUSPENDED) throw new IllegalStateException("user is already suspended"); onDeactivate(new UserDeactivated(userId)); } // evt: 2 private User onDeactivate(UserDeactivated event) { eventStream.add(event); state = UserStatus.SUSPENDED; return this; } /* es */ public static User recreate(UUID userId, Collection domainEvents) { User snapshot = new User(userId); return io.vavr.collection.List.ofAll(domainEvents) .foldLeft(snapshot, User::apply); } @Override public User apply(DomainEvent domainEvent) { return API.Match(domainEvent).of( Case($(instanceOf(UserCreated.class)), this::onCreate), Case($(instanceOf(UserActivated.class)), this::onActivate), Case($(instanceOf(UserDeactivated.class)), this::onDeactivate) ); } }