Last active
September 6, 2023 04:07
-
-
Save aleixmorgadas/be30c6030db2fd9b560ac31cb873f68c to your computer and use it in GitHub Desktop.
Aggregate with MongoDB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.aleixmorgadas.eventsourcedmongo.domain; | |
import org.springframework.data.annotation.Id; | |
import org.springframework.data.annotation.PersistenceCreator; | |
import org.springframework.data.annotation.Transient; | |
import org.springframework.data.mongodb.core.mapping.Document; | |
import java.util.*; | |
@Document | |
public class Profile { | |
@Id | |
String id; | |
@Transient | |
final State state = new State(); | |
final List<Event> events = new ArrayList<>(); | |
public Profile(String id, String name) { | |
apply(new Event.Created(id, name)); | |
} | |
@PersistenceCreator | |
Profile(String id, List<Event> events) { | |
this.id = id; | |
events.forEach(this::apply); | |
} | |
void apply(Event event) { | |
events.add(event); | |
// update with pattern matching in Java 21 | |
if (event instanceof Event.Created created) { | |
on(created); | |
} else if (event instanceof Event.AgeUpdated ageUpdated) { | |
on(ageUpdated); | |
} | |
} | |
void on(Event.Created created) { | |
id = created.id; | |
state.name = created.name; | |
} | |
void on(Event.AgeUpdated ageUpdated) { | |
state.age = ageUpdated.age(); | |
} | |
String name() { | |
return state.name; | |
} | |
public static Profile of(String name) { | |
return new Profile(UUID.randomUUID().toString(), name); | |
} | |
public int age() { | |
return state.age; | |
} | |
public void withAge(int age) { | |
apply(new Event.AgeUpdated(age)); | |
} | |
static class State { | |
String name; | |
int age; | |
} | |
sealed interface Event { | |
record Created(String id, String name) implements Event {} | |
record AgeUpdated(int age) implements Event {} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.aleixmorgadas.eventsourcedmongo.domain; | |
import org.junit.jupiter.api.Test; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest; | |
import org.springframework.boot.testcontainers.service.connection.ServiceConnection; | |
import org.testcontainers.containers.MongoDBContainer; | |
import org.testcontainers.junit.jupiter.Container; | |
import org.testcontainers.junit.jupiter.Testcontainers; | |
import org.testcontainers.utility.DockerImageName; | |
import static org.assertj.core.api.Assertions.assertThat; | |
@DataMongoTest | |
@Testcontainers | |
public class ProfileRepositoryTest { | |
@Container | |
@ServiceConnection | |
static MongoDBContainer mongo = new MongoDBContainer(DockerImageName.parse("mongo:6.0.7")); | |
@Autowired | |
ProfileRepository repository; | |
@Test | |
void savesProfileIntoDB() { | |
var profile = Profile.of("Aleix"); | |
profile.withAge(30); | |
repository.save(profile); | |
var id = profile.id; | |
var savedProfile = repository.findById(id).orElseThrow(); | |
assertThat(savedProfile.events).hasSize(2); | |
assertThat(savedProfile.name()).isEqualTo("Aleix"); | |
assertThat(savedProfile.age()).isEqualTo(30); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.aleixmorgadas.eventsourcedmongo.domain; | |
import org.junit.jupiter.api.Test; | |
import static org.assertj.core.api.Assertions.assertThat; | |
public class ProfileTest { | |
@Test | |
void createsAProfile() { | |
var profile = Profile.of("Aleix"); | |
assertThat(profile.name()).isEqualTo("Aleix"); | |
assertThat(profile.events).hasSize(1); | |
} | |
@Test | |
void addsAge() { | |
var profile = Profile.of("Aleix"); | |
profile.withAge(30); | |
assertThat(profile.age()).isEqualTo(30); | |
assertThat(profile.events).hasSize(2); | |
assertThat(profile.events.get(1)).isInstanceOf(Profile.Event.AgeUpdated.class); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment