Merge pull request #9263 from kcacademic/es-cqrs

Es cqrs
This commit is contained in:
Josh Cummings 2020-05-19 19:12:31 -06:00 committed by GitHub
commit 3a8df18136
33 changed files with 1091 additions and 7 deletions

30
patterns/cqrs-es/pom.xml Normal file
View File

@ -0,0 +1,30 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cqrs-es</artifactId>
<version>1.0-SNAPSHOT</version>
<name>cqrs-es</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>patterns</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,30 @@
package com.baeldung.patterns.cqrs.aggregates;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.cqrs.repository.UserWriteRepository;
import com.baeldung.patterns.domain.User;
public class UserAggregate {
private UserWriteRepository writeRepository;
public UserAggregate(UserWriteRepository repository) {
this.writeRepository = repository;
}
public User handleCreateUserCommand(CreateUserCommand command) {
User user = new User(command.getUserId(), command.getFirstName(), command.getLastName());
writeRepository.addUser(user.getUserid(), user);
return user;
}
public User handleUpdateUserCommand(UpdateUserCommand command) {
User user = writeRepository.getUser(command.getUserId());
user.setAddresses(command.getAddresses());
user.setContacts(command.getContacts());
writeRepository.addUser(user.getUserid(), user);
return user;
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.patterns.cqrs.commands;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CreateUserCommand {
private String userId;
private String firstName;
private String lastName;
}

View File

@ -0,0 +1,20 @@
package com.baeldung.patterns.cqrs.commands;
import java.util.HashSet;
import java.util.Set;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class UpdateUserCommand {
private String userId;
private Set<Address> addresses = new HashSet<>();
private Set<Contact> contacts = new HashSet<>();
}

View File

@ -0,0 +1,37 @@
package com.baeldung.patterns.cqrs.projections;
import java.util.Set;
import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery;
import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
public class UserProjection {
private UserReadRepository repository;
public UserProjection(UserReadRepository repository) {
this.repository = repository;
}
public Set<Contact> handle(ContactByTypeQuery query) throws Exception {
UserContact userContact = repository.getUserContact(query.getUserId());
if (userContact == null)
throw new Exception("User does not exist.");
return userContact.getContactByType()
.get(query.getContactType());
}
public Set<Address> handle(AddressByRegionQuery query) throws Exception {
UserAddress userAddress = repository.getUserAddress(query.getUserId());
if (userAddress == null)
throw new Exception("User does not exist.");
return userAddress.getAddressByRegion()
.get(query.getState());
}
}

View File

@ -0,0 +1,49 @@
package com.baeldung.patterns.cqrs.projectors;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
public class UserProjector {
UserReadRepository readRepository = new UserReadRepository();
public UserProjector(UserReadRepository readRepository) {
this.readRepository = readRepository;
}
public void project(User user) {
UserContact userContact = Optional.ofNullable(readRepository.getUserContact(user.getUserid()))
.orElse(new UserContact());
Map<String, Set<Contact>> contactByType = new HashMap<>();
for (Contact contact : user.getContacts()) {
Set<Contact> contacts = Optional.ofNullable(contactByType.get(contact.getType()))
.orElse(new HashSet<>());
contacts.add(contact);
contactByType.put(contact.getType(), contacts);
}
userContact.setContactByType(contactByType);
readRepository.addUserContact(user.getUserid(), userContact);
UserAddress userAddress = Optional.ofNullable(readRepository.getUserAddress(user.getUserid()))
.orElse(new UserAddress());
Map<String, Set<Address>> addressByRegion = new HashMap<>();
for (Address address : user.getAddresses()) {
Set<Address> addresses = Optional.ofNullable(addressByRegion.get(address.getState()))
.orElse(new HashSet<>());
addresses.add(address);
addressByRegion.put(address.getState(), addresses);
}
userAddress.setAddressByRegion(addressByRegion);
readRepository.addUserAddress(user.getUserid(), userAddress);
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.patterns.cqrs.queries;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class AddressByRegionQuery {
private String userId;
private String state;
}

View File

@ -0,0 +1,12 @@
package com.baeldung.patterns.cqrs.queries;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ContactByTypeQuery {
private String userId;
private String contactType;
}

View File

@ -0,0 +1,31 @@
package com.baeldung.patterns.cqrs.repository;
import java.util.HashMap;
import java.util.Map;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
public class UserReadRepository {
private Map<String, UserAddress> userAddress = new HashMap<>();
private Map<String, UserContact> userContact = new HashMap<>();
public void addUserAddress(String id, UserAddress user) {
userAddress.put(id, user);
}
public UserAddress getUserAddress(String id) {
return userAddress.get(id);
}
public void addUserContact(String id, UserContact user) {
userContact.put(id, user);
}
public UserContact getUserContact(String id) {
return userContact.get(id);
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.patterns.cqrs.repository;
import java.util.HashMap;
import java.util.Map;
import com.baeldung.patterns.domain.User;
public class UserWriteRepository {
private Map<String, User> store = new HashMap<>();
public void addUser(String id, User user) {
store.put(id, user);
}
public User getUser(String id) {
return store.get(id);
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.patterns.crud.repository;
import java.util.HashMap;
import java.util.Map;
import com.baeldung.patterns.domain.User;
public class UserRepository {
private Map<String, User> store = new HashMap<>();
public void addUser(String id, User user) {
store.put(id, user);
}
public User getUser(String id) {
return store.get(id);
}
}

View File

@ -0,0 +1,55 @@
package com.baeldung.patterns.crud.service;
import java.util.Set;
import java.util.stream.Collectors;
import com.baeldung.patterns.crud.repository.UserRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
public class UserService {
private UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public void createUser(String userId, String firstName, String lastName) {
User user = new User(userId, firstName, lastName);
repository.addUser(userId, user);
}
public void updateUser(String userId, Set<Contact> contacts, Set<Address> addresses) throws Exception {
User user = repository.getUser(userId);
if (user == null)
throw new Exception("User does not exist.");
user.setContacts(contacts);
user.setAddresses(addresses);
repository.addUser(userId, user);
}
public Set<Contact> getContactByType(String userId, String contactType) throws Exception {
User user = repository.getUser(userId);
if (user == null)
throw new Exception("User does not exit.");
Set<Contact> contacts = user.getContacts();
return contacts.stream()
.filter(c -> c.getType()
.equals(contactType))
.collect(Collectors.toSet());
}
public Set<Address> getAddressByRegion(String userId, String state) throws Exception {
User user = repository.getUser(userId);
if (user == null)
throw new Exception("User does not exist.");
Set<Address> addresses = user.getAddresses();
return addresses.stream()
.filter(a -> a.getState()
.equals(state))
.collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.patterns.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Address {
private String city;
private String state;
private String postcode;
}

View File

@ -0,0 +1,13 @@
package com.baeldung.patterns.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Contact {
private String type;
private String detail;
}

View File

@ -0,0 +1,22 @@
package com.baeldung.patterns.domain;
import java.util.HashSet;
import java.util.Set;
import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Data
@RequiredArgsConstructor
public class User {
@NonNull
private String userid;
@NonNull
private String firstname;
@NonNull
private String lastname;
private Set<Contact> contacts = new HashSet<>();
private Set<Address> addresses = new HashSet<>();
}

View File

@ -0,0 +1,14 @@
package com.baeldung.patterns.domain;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.Data;
@Data
public class UserAddress {
private Map<String, Set<Address>> addressByRegion = new HashMap<>();
}

View File

@ -0,0 +1,14 @@
package com.baeldung.patterns.domain;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.Data;
@Data
public class UserContact {
private Map<String, Set<Contact>> contactByType = new HashMap<>();
}

View File

@ -0,0 +1,15 @@
package com.baeldung.patterns.es.events;
import java.util.Date;
import java.util.UUID;
import lombok.ToString;
@ToString
public abstract class Event {
public final UUID id = UUID.randomUUID();
public final Date created = new Date();
}

View File

@ -0,0 +1,16 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserAddressAddedEvent extends Event {
private String city;
private String state;
private String postCode;
}

View File

@ -0,0 +1,16 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserAddressRemovedEvent extends Event {
private String city;
private String state;
private String postCode;
}

View File

@ -0,0 +1,15 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserContactAddedEvent extends Event {
private String contactType;
private String contactDetails;
}

View File

@ -0,0 +1,15 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserContactRemovedEvent extends Event {
private String contactType;
private String contactDetails;
}

View File

@ -0,0 +1,16 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserCreatedEvent extends Event {
private String userId;
private String firstName;
private String lastName;
}

View File

@ -0,0 +1,29 @@
package com.baeldung.patterns.es.repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.baeldung.patterns.es.events.Event;
public class EventStore {
private Map<String, List<Event>> store = new HashMap<>();
public void addEvent(String id, Event event) {
List<Event> events = store.get(id);
if (events == null) {
events = new ArrayList<Event>();
events.add(event);
store.put(id, events);
} else {
events.add(event);
}
}
public List<Event> getEvents(String id) {
return store.get(id);
}
}

View File

@ -0,0 +1,72 @@
package com.baeldung.patterns.es.service;
import java.util.Set;
import java.util.stream.Collectors;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
import com.baeldung.patterns.es.events.UserCreatedEvent;
import com.baeldung.patterns.es.repository.EventStore;
public class UserService {
private EventStore repository;
public UserService(EventStore repository) {
this.repository = repository;
}
public void createUser(String userId, String firstName, String lastName) {
repository.addEvent(userId, new UserCreatedEvent(userId, firstName, lastName));
}
public void updateUser(String userId, Set<Contact> contacts, Set<Address> addresses) throws Exception {
User user = UserUtility.recreateUserState(repository, userId);
if (user == null)
throw new Exception("User does not exist.");
user.getContacts()
.stream()
.filter(c -> !contacts.contains(c))
.forEach(c -> repository.addEvent(userId, new UserContactRemovedEvent(c.getType(), c.getDetail())));
contacts.stream()
.filter(c -> !user.getContacts()
.contains(c))
.forEach(c -> repository.addEvent(userId, new UserContactAddedEvent(c.getType(), c.getDetail())));
user.getAddresses()
.stream()
.filter(a -> !addresses.contains(a))
.forEach(a -> repository.addEvent(userId, new UserAddressRemovedEvent(a.getCity(), a.getState(), a.getPostcode())));
addresses.stream()
.filter(a -> !user.getAddresses()
.contains(a))
.forEach(a -> repository.addEvent(userId, new UserAddressAddedEvent(a.getCity(), a.getState(), a.getPostcode())));
}
public Set<Contact> getContactByType(String userId, String contactType) throws Exception {
User user = UserUtility.recreateUserState(repository, userId);
if (user == null)
throw new Exception("User does not exist.");
return user.getContacts()
.stream()
.filter(c -> c.getType()
.equals(contactType))
.collect(Collectors.toSet());
}
public Set<Address> getAddressByRegion(String userId, String state) throws Exception {
User user = UserUtility.recreateUserState(repository, userId);
if (user == null)
throw new Exception("User does not exist.");
return user.getAddresses()
.stream()
.filter(a -> a.getState()
.equals(state))
.collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,62 @@
package com.baeldung.patterns.es.service;
import java.util.List;
import java.util.UUID;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
import com.baeldung.patterns.es.events.UserCreatedEvent;
import com.baeldung.patterns.es.repository.EventStore;
public class UserUtility {
public static User recreateUserState(EventStore store, String userId) {
User user = null;
List<Event> events = store.getEvents(userId);
for (Event event : events) {
if (event instanceof UserCreatedEvent) {
UserCreatedEvent e = (UserCreatedEvent) event;
user = new User(UUID.randomUUID()
.toString(), e.getFirstName(), e.getLastName());
}
if (event instanceof UserAddressAddedEvent) {
UserAddressAddedEvent e = (UserAddressAddedEvent) event;
Address address = new Address(e.getCity(), e.getState(), e.getPostCode());
if (user != null)
user.getAddresses()
.add(address);
}
if (event instanceof UserAddressRemovedEvent) {
UserAddressRemovedEvent e = (UserAddressRemovedEvent) event;
Address address = new Address(e.getCity(), e.getState(), e.getPostCode());
if (user != null)
user.getAddresses()
.remove(address);
}
if (event instanceof UserContactAddedEvent) {
UserContactAddedEvent e = (UserContactAddedEvent) event;
Contact contact = new Contact(e.getContactType(), e.getContactDetails());
if (user != null)
user.getContacts()
.add(contact);
}
if (event instanceof UserContactRemovedEvent) {
UserContactRemovedEvent e = (UserContactRemovedEvent) event;
Contact contact = new Contact(e.getContactType(), e.getContactDetails());
if (user != null)
user.getContacts()
.remove(contact);
}
}
return user;
}
}

View File

@ -0,0 +1,87 @@
package com.baeldung.patterns.escqrs.aggregates;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
import com.baeldung.patterns.es.events.UserCreatedEvent;
import com.baeldung.patterns.es.repository.EventStore;
import com.baeldung.patterns.es.service.UserUtility;
public class UserAggregate {
private EventStore writeRepository;
public UserAggregate(EventStore repository) {
this.writeRepository = repository;
}
public List<Event> handleCreateUserCommand(CreateUserCommand command) {
UserCreatedEvent event = new UserCreatedEvent(command.getUserId(), command.getFirstName(), command.getLastName());
writeRepository.addEvent(command.getUserId(), event);
return Arrays.asList(event);
}
public List<Event> handleUpdateUserCommand(UpdateUserCommand command) {
User user = UserUtility.recreateUserState(writeRepository, command.getUserId());
List<Event> events = new ArrayList<>();
List<Contact> contactsToRemove = user.getContacts()
.stream()
.filter(c -> !command.getContacts()
.contains(c))
.collect(Collectors.toList());
for (Contact contact : contactsToRemove) {
UserContactRemovedEvent contactRemovedEvent = new UserContactRemovedEvent(contact.getType(), contact.getDetail());
events.add(contactRemovedEvent);
writeRepository.addEvent(command.getUserId(), contactRemovedEvent);
}
List<Contact> contactsToAdd = command.getContacts()
.stream()
.filter(c -> !user.getContacts()
.contains(c))
.collect(Collectors.toList());
for (Contact contact : contactsToAdd) {
UserContactAddedEvent contactAddedEvent = new UserContactAddedEvent(contact.getType(), contact.getDetail());
events.add(contactAddedEvent);
writeRepository.addEvent(command.getUserId(), contactAddedEvent);
}
List<Address> addressesToRemove = user.getAddresses()
.stream()
.filter(a -> !command.getAddresses()
.contains(a))
.collect(Collectors.toList());
for (Address address : addressesToRemove) {
UserAddressRemovedEvent addressRemovedEvent = new UserAddressRemovedEvent(address.getCity(), address.getState(), address.getPostcode());
events.add(addressRemovedEvent);
writeRepository.addEvent(command.getUserId(), addressRemovedEvent);
}
List<Address> addressesToAdd = command.getAddresses()
.stream()
.filter(a -> !user.getAddresses()
.contains(a))
.collect(Collectors.toList());
for (Address address : addressesToAdd) {
UserAddressAddedEvent addressAddedEvent = new UserAddressAddedEvent(address.getCity(), address.getState(), address.getPostcode());
events.add(addressAddedEvent);
writeRepository.addEvent(command.getUserId(), addressAddedEvent);
}
return events;
}
}

View File

@ -0,0 +1,91 @@
package com.baeldung.patterns.escqrs.projectors;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
public class UserProjector {
UserReadRepository readRepository = new UserReadRepository();
public UserProjector(UserReadRepository readRepository) {
this.readRepository = readRepository;
}
public void project(String userId, List<Event> events) {
for (Event event : events) {
if (event instanceof UserAddressAddedEvent)
apply(userId, (UserAddressAddedEvent) event);
if (event instanceof UserAddressRemovedEvent)
apply(userId, (UserAddressRemovedEvent) event);
if (event instanceof UserContactAddedEvent)
apply(userId, (UserContactAddedEvent) event);
if (event instanceof UserContactRemovedEvent)
apply(userId, (UserContactRemovedEvent) event);
}
}
public void apply(String userId, UserAddressAddedEvent event) {
Address address = new Address(event.getCity(), event.getState(), event.getPostCode());
UserAddress userAddress = Optional.ofNullable(readRepository.getUserAddress(userId))
.orElse(new UserAddress());
Set<Address> addresses = Optional.ofNullable(userAddress.getAddressByRegion()
.get(address.getState()))
.orElse(new HashSet<>());
addresses.add(address);
userAddress.getAddressByRegion()
.put(address.getState(), addresses);
readRepository.addUserAddress(userId, userAddress);
}
public void apply(String userId, UserAddressRemovedEvent event) {
Address address = new Address(event.getCity(), event.getState(), event.getPostCode());
UserAddress userAddress = readRepository.getUserAddress(userId);
if (userAddress != null) {
Set<Address> addresses = userAddress.getAddressByRegion()
.get(address.getState());
if (addresses != null)
addresses.remove(address);
readRepository.addUserAddress(userId, userAddress);
}
}
public void apply(String userId, UserContactAddedEvent event) {
Contact contact = new Contact(event.getContactType(), event.getContactDetails());
UserContact userContact = Optional.ofNullable(readRepository.getUserContact(userId))
.orElse(new UserContact());
Set<Contact> contacts = Optional.ofNullable(userContact.getContactByType()
.get(contact.getType()))
.orElse(new HashSet<>());
contacts.add(contact);
userContact.getContactByType()
.put(contact.getType(), contacts);
readRepository.addUserContact(userId, userContact);
}
public void apply(String userId, UserContactRemovedEvent event) {
Contact contact = new Contact(event.getContactType(), event.getContactDetails());
UserContact userContact = readRepository.getUserContact(userId);
if (userContact != null) {
Set<Contact> contacts = userContact.getContactByType()
.get(contact.getType());
if (contacts != null)
contacts.remove(contact);
readRepository.addUserContact(userId, userContact);
}
}
}

View File

@ -0,0 +1,74 @@
package com.baeldung.patterns.cqrs;
import static org.junit.Assert.assertEquals;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.cqrs.aggregates.UserAggregate;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.cqrs.projections.UserProjection;
import com.baeldung.patterns.cqrs.projectors.UserProjector;
import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery;
import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.cqrs.repository.UserWriteRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
public class ApplicationUnitTest {
private UserWriteRepository writeRepository;
private UserReadRepository readRepository;
private UserProjector projector;
private UserAggregate userAggregate;
private UserProjection userProjection;
@Before
public void setUp() {
writeRepository = new UserWriteRepository();
readRepository = new UserReadRepository();
projector = new UserProjector(readRepository);
userAggregate = new UserAggregate(writeRepository);
userProjection = new UserProjection(readRepository);
}
@Test
public void givenCQRSApplication_whenCommandRun_thenQueryShouldReturnResult() throws Exception {
String userId = UUID.randomUUID()
.toString();
User user = null;
CreateUserCommand createUserCommand = new CreateUserCommand(userId, "Tom", "Sawyer");
user = userAggregate.handleCreateUserCommand(createUserCommand);
projector.project(user);
UpdateUserCommand updateUserCommand = new UpdateUserCommand(user.getUserid(), Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"))
.collect(Collectors.toSet()));
user = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(user);
updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()));
user = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(user);
ContactByTypeQuery contactByTypeQuery = new ContactByTypeQuery(userId, "EMAIL");
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), userProjection.handle(contactByTypeQuery));
AddressByRegionQuery addressByRegionQuery = new AddressByRegionQuery(userId, "NY");
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), userProjection.handle(addressByRegionQuery));
}
}

View File

@ -0,0 +1,48 @@
package com.baeldung.patterns.crud;
import static org.junit.Assert.assertEquals;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.crud.repository.UserRepository;
import com.baeldung.patterns.crud.service.UserService;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
public class ApplicationUnitTest {
private UserRepository repository;
@Before
public void setUp() {
repository = new UserRepository();
}
@Test
public void givenCRUDApplication_whenDataCreated_thenDataCanBeFetched() throws Exception {
UserService service = new UserService(repository);
String userId = UUID.randomUUID()
.toString();
service.createUser(userId, "Tom", "Sawyer");
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), service.getContactByType(userId, "EMAIL"));
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), service.getAddressByRegion(userId, "NY"));
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.patterns.es;
import static org.junit.Assert.assertEquals;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.es.repository.EventStore;
import com.baeldung.patterns.es.service.UserService;
public class ApplicationUnitTest {
private EventStore repository;
private UserService service;
@Before
public void setUp() {
repository = new EventStore();
service = new UserService(repository);
}
@Test
public void givenCRUDApplication_whenDataCreated_thenDataCanBeFetched() throws Exception {
String userId = UUID.randomUUID()
.toString();
service.createUser(userId, "Tom", "Sawyer");
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), service.getContactByType(userId, "EMAIL"));
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), service.getAddressByRegion(userId, "NY"));
}
}

View File

@ -0,0 +1,76 @@
package com.baeldung.patterns.escqrs;
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.cqrs.projections.UserProjection;
import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery;
import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.repository.EventStore;
import com.baeldung.patterns.escqrs.aggregates.UserAggregate;
import com.baeldung.patterns.escqrs.projectors.UserProjector;
public class ApplicationUnitTest {
private EventStore writeRepository;
private UserReadRepository readRepository;
private UserProjector projector;
private UserAggregate userAggregate;
private UserProjection userProjection;
@Before
public void setUp() {
writeRepository = new EventStore();
readRepository = new UserReadRepository();
projector = new UserProjector(readRepository);
userAggregate = new UserAggregate(writeRepository);
userProjection = new UserProjection(readRepository);
}
@Test
public void givenCQRSApplication_whenCommandRun_thenQueryShouldReturnResult() throws Exception {
String userId = UUID.randomUUID()
.toString();
List<Event> events = null;
CreateUserCommand createUserCommand = new CreateUserCommand(userId, "Kumar", "Chandrakant");
events = userAggregate.handleCreateUserCommand(createUserCommand);
projector.project(userId, events);
UpdateUserCommand updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"))
.collect(Collectors.toSet()));
events = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(userId, events);
updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()));
events = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(userId, events);
ContactByTypeQuery contactByTypeQuery = new ContactByTypeQuery(userId, "EMAIL");
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), userProjection.handle(contactByTypeQuery));
AddressByRegionQuery addressByRegionQuery = new AddressByRegionQuery(userId, "NY");
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), userProjection.handle(addressByRegionQuery));
}
}

View File

@ -5,13 +5,11 @@
<artifactId>patterns</artifactId>
<name>patterns</name>
<packaging>pom</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modules>
<module>design-patterns-architectural</module>
<module>design-patterns-behavioral</module>
@ -21,11 +19,11 @@
<module>design-patterns-functional</module>
<module>design-patterns-structural</module>
<module>dip</module>
<module>cqrs-es</module>
<module>front-controller</module>
<module>intercepting-filter</module>
<module>solid</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
@ -36,7 +34,6 @@
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
@ -53,9 +50,7 @@
</plugins>
</pluginManagement>
</build>
<properties>
<jetty-maven-plugin.version>9.4.0.v20161208</jetty-maven-plugin.version>
</properties>
</project>
</project>