Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion HELP.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@ For further reference, please consider the following sections:
These additional references should also help you:

* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)

79 changes: 50 additions & 29 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,48 +1,69 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.3'
id 'io.spring.dependency-management' version '1.1.7'
id 'java'
id 'org.springframework.boot' version '3.4.3'
id 'io.spring.dependency-management' version '1.1.7'
id 'com.diffplug.spotless' version '7.0.4'

}

group = 'io.autoinvestor'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation 'com.google.cloud:google-cloud-pubsub:1.123.0'
implementation "com.google.cloud:spring-cloud-gcp-starter-pubsub:6.1.1"
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'org.springframework.integration:spring-integration-core'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:gcloud'

compileOnly 'org.projectlombok:lombok:1.18.38'
annotationProcessor 'org.projectlombok:lombok:1.18.38'

testCompileOnly 'org.projectlombok:lombok:1.18.38'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.38'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation 'com.google.cloud:google-cloud-pubsub:1.123.0'
implementation "com.google.cloud:spring-cloud-gcp-starter-pubsub:6.1.1"
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'org.springframework.integration:spring-integration-core'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:testcontainers'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:gcloud'

compileOnly 'org.projectlombok:lombok:1.18.38'
annotationProcessor 'org.projectlombok:lombok:1.18.38'

testCompileOnly 'org.projectlombok:lombok:1.18.38'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.38'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}

bootBuildImage {
publish = false
publish = false
}

spotless {
java {
googleJavaFormat('1.22.0').aosp()
removeUnusedImports()
trimTrailingWhitespace()
leadingTabsToSpaces()
endWithNewline()
importOrder '', 'java', 'javax', 'org', 'com'
target 'src/**/*.java'
}

format 'misc', {
target '*.gradle', '*.md', '.gitignore'
leadingTabsToSpaces()
trimTrailingWhitespace()
endWithNewline()
}
}
7 changes: 1 addition & 6 deletions src/main/java/io/autoinvestor/application/DecisionDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,4 @@
import java.util.Date;

public record DecisionDTO(
String decisionId,
String assetId,
Date date,
String type,
int riskLevel
) {}
String decisionId, String assetId, Date date, String type, int riskLevel) {}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package io.autoinvestor.application;

public record GetDecisionsQuery(String assetId, Integer riskLevel) { }
public record GetDecisionsQuery(String assetId, Integer riskLevel) {}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.autoinvestor.application;

import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

@Service
public class GetDecisionsQueryHandler {

Expand All @@ -15,16 +15,13 @@ public GetDecisionsQueryHandler(ReadModelRepository readModel) {
}

public List<GetDecisionsQueryResponse> handle(GetDecisionsQuery query) {
List<DecisionDTO> decisions = this.readModel
.get(query.assetId(), query.riskLevel());
List<DecisionDTO> decisions = this.readModel.get(query.assetId(), query.riskLevel());

return decisions.stream()
.map(d -> new GetDecisionsQueryResponse(
d.assetId(),
d.type(),
d.date(),
d.riskLevel()
))
.map(
d ->
new GetDecisionsQueryResponse(
d.assetId(), d.type(), d.date(), d.riskLevel()))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,4 @@

import java.util.Date;

public record GetDecisionsQueryResponse(
String assetId,
String type,
Date date,
int riskLevel
) { }
public record GetDecisionsQueryResponse(String assetId, String type, Date date, int riskLevel) {}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

public interface ReadModelRepository {
void save(DecisionDTO decisionDTO);

List<DecisionDTO> get(String assetId, int riskLevel);

Optional<DecisionDTO> getOne(String assetId, int riskLevel);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
package io.autoinvestor.application;


public record RegisterDecisionCommand(
String assetId,
int feeling
) { }
public record RegisterDecisionCommand(String assetId, int feeling) {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,59 @@
import io.autoinvestor.domain.model.Decision;
import io.autoinvestor.domain.model.DecisionId;
import io.autoinvestor.domain.model.RiskLevel;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Service;

@Service
public class RegisterDecisionCommandHandler {

private final EventStoreRepository eventStore;
private final ReadModelRepository readModel;
private final EventPublisher eventPublisher;

public RegisterDecisionCommandHandler(EventStoreRepository eventStore, ReadModelRepository readModel, EventPublisher eventPublisher) {
public RegisterDecisionCommandHandler(
EventStoreRepository eventStore,
ReadModelRepository readModel,
EventPublisher eventPublisher) {
this.eventStore = eventStore;
this.readModel = readModel;
this.eventPublisher = eventPublisher;
}

public void handle(RegisterDecisionCommand command) {
for (RiskLevel risklevel : RiskLevel.values()) {
Optional<DecisionDTO> decisionFromReadModel = this.readModel.getOne(command.assetId(), risklevel.value());
Optional<DecisionDTO> decisionFromReadModel =
this.readModel.getOne(command.assetId(), risklevel.value());

Decision decision = decisionFromReadModel.isEmpty()
? Decision.empty()
: this.eventStore.get(DecisionId.from(decisionFromReadModel.get().decisionId()));
Decision decision =
decisionFromReadModel.isEmpty()
? Decision.empty()
: this.eventStore.get(
DecisionId.from(decisionFromReadModel.get().decisionId()));

if (decision == null) {
throw new IllegalStateException("Decision not found for ID: " + command.assetId() + " when it should be present.");
throw new IllegalStateException(
"Decision not found for ID: "
+ command.assetId()
+ " when it should be present.");
}

decision.takeDecision(
command.assetId(),
command.feeling(),
risklevel
);
decision.takeDecision(command.assetId(), command.feeling(), risklevel);

List<Event<?>> events = decision.getUncommittedEvents();

this.eventStore.save(decision);

DecisionDTO dto = new DecisionDTO(
decision.getState().decisionId().value(),
command.assetId(),
decision.getState().date(),
decision.getState().decision(),
risklevel.value()
);
DecisionDTO dto =
new DecisionDTO(
decision.getState().decisionId().value(),
command.assetId(),
decision.getState().date(),
decision.getState().decision(),
risklevel.value());
this.readModel.save(dto);

this.eventPublisher.publish(events);
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/io/autoinvestor/domain/Id.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ protected static String generateId() {

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Id that))
return false;
if (this == o) return true;
if (!(o instanceof Id that)) return false;
return id.equals(that.id);
}

Expand Down
41 changes: 22 additions & 19 deletions src/main/java/io/autoinvestor/domain/events/DecisionTakenEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import java.util.Date;


public class DecisionTakenEvent extends Event<DecisionTakenEventPayload> {

public static final String TYPE = "ASSET_DECISION_TAKEN";
Expand All @@ -14,30 +13,34 @@ private DecisionTakenEvent(Id aggregateId, DecisionTakenEventPayload payload, in
super(aggregateId, TYPE, payload, version);
}

protected DecisionTakenEvent(EventId id,
DecisionId decisionId,
DecisionTakenEventPayload payload,
Date occurredAt,
int version) {
protected DecisionTakenEvent(
EventId id,
DecisionId decisionId,
DecisionTakenEventPayload payload,
Date occurredAt,
int version) {
super(id, decisionId, TYPE, payload, occurredAt, version);
}

public static DecisionTakenEvent with(DecisionId decisionId, AssetId assetId, Date date, Type type,
RiskLevel riskLevel, int version) {
DecisionTakenEventPayload payload = new DecisionTakenEventPayload(
assetId.value(),
date,
type.name(),
riskLevel.value()
);
public static DecisionTakenEvent with(
DecisionId decisionId,
AssetId assetId,
Date date,
Type type,
RiskLevel riskLevel,
int version) {
DecisionTakenEventPayload payload =
new DecisionTakenEventPayload(
assetId.value(), date, type.name(), riskLevel.value());
return new DecisionTakenEvent(decisionId, payload, version);
}

public static DecisionTakenEvent hydrate(EventId id,
DecisionId decisionId,
DecisionTakenEventPayload payload,
Date occurredAt,
int version) {
public static DecisionTakenEvent hydrate(
EventId id,
DecisionId decisionId,
DecisionTakenEventPayload payload,
Date occurredAt,
int version) {
return new DecisionTakenEvent(id, decisionId, payload, occurredAt, version);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,15 @@
import java.util.Date;
import java.util.Map;

public record DecisionTakenEventPayload(
String assetId,
Date date,
String decision,
int riskLevel
) implements EventPayload {
public record DecisionTakenEventPayload(String assetId, Date date, String decision, int riskLevel)
implements EventPayload {

@Override
public Map<String, Object> asMap() {
return Map.of(
"assetId", assetId,
"date", date,
"decision", decision,
"riskLevel", riskLevel
);
"riskLevel", riskLevel);
}
}
3 changes: 2 additions & 1 deletion src/main/java/io/autoinvestor/domain/events/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ protected Event(Id aggregateId, String type, P payload, int version) {
this.version = version;
}

protected Event(EventId id, Id aggregateId, String type, P payload, Date occurredAt, int version) {
protected Event(
EventId id, Id aggregateId, String type, P payload, Date occurredAt, int version) {
this.id = id;
this.aggregateId = aggregateId;
this.type = type;
Expand Down
1 change: 0 additions & 1 deletion src/main/java/io/autoinvestor/domain/events/EventId.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.autoinvestor.domain.events;


import io.autoinvestor.domain.Id;

public class EventId extends Id {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,3 @@ public void markEventsAsCommitted() {
appliedEvents.clear();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import io.autoinvestor.domain.model.Decision;
import io.autoinvestor.domain.model.DecisionId;


public interface EventStoreRepository {
Decision get(DecisionId decisionId);

void save(Decision decision);
}
Loading