From 0fc5ee8d3f3a174c2195bb7613f463a51728195a Mon Sep 17 00:00:00 2001 From: Pol Pinol Castuera Date: Sat, 31 May 2025 10:29:42 +0200 Subject: [PATCH] Add sonar cloud and linter --- HELP.md | 1 - build.gradle | 79 ++++++++++++------- .../autoinvestor/application/DecisionDTO.java | 7 +- .../application/GetDecisionsQuery.java | 2 +- .../application/GetDecisionsQueryHandler.java | 17 ++-- .../GetDecisionsQueryResponse.java | 7 +- .../application/ReadModelRepository.java | 2 + .../application/RegisterDecisionCommand.java | 6 +- .../RegisterDecisionCommandHandler.java | 44 ++++++----- src/main/java/io/autoinvestor/domain/Id.java | 6 +- .../domain/events/DecisionTakenEvent.java | 41 +++++----- .../events/DecisionTakenEventPayload.java | 11 +-- .../io/autoinvestor/domain/events/Event.java | 3 +- .../autoinvestor/domain/events/EventId.java | 1 - .../domain/events/EventSourcedEntity.java | 1 - .../domain/events/EventStoreRepository.java | 2 +- .../autoinvestor/domain/model/Decision.java | 16 ++-- .../autoinvestor/domain/model/DecisionId.java | 1 - .../domain/model/DecisionState.java | 19 +++-- .../autoinvestor/domain/model/RiskLevel.java | 2 +- .../io/autoinvestor/domain/model/Type.java | 1 - .../event_publishers/EventMessageMapper.java | 16 ++-- .../InMemoryEventPublisher.java | 10 ++- .../PubsubEventPublisher.java | 20 ++--- .../infrastructure/listeners/PubsubEvent.java | 7 +- .../listeners/PubsubEventMapper.java | 6 +- .../listeners/PubsubNewsEventSubscriber.java | 67 ++++++++++------ .../read_models/DecisionDocument.java | 34 ++++---- .../read_models/DecisionMapper.java | 13 +-- .../InMemoryReadModelRepository.java | 25 +++--- .../read_models/MongoReadModelRepository.java | 36 ++++----- .../repositories/EventDocument.java | 50 ++++++------ .../repositories/EventMapper.java | 23 +++--- .../InMemoryEventStoreRepository.java | 12 +-- .../MongoEventStoreRepository.java | 27 +++---- .../ui/GetDecisionsController.java | 32 ++++---- .../io/autoinvestor/ui/GetDecisionsDTO.java | 3 +- 37 files changed, 329 insertions(+), 321 deletions(-) diff --git a/HELP.md b/HELP.md index d70d9a8..3f1b73c 100644 --- a/HELP.md +++ b/HELP.md @@ -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) - diff --git a/build.gradle b/build.gradle index 0a1d60a..ca34fd5 100644 --- a/build.gradle +++ b/build.gradle @@ -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() + } } diff --git a/src/main/java/io/autoinvestor/application/DecisionDTO.java b/src/main/java/io/autoinvestor/application/DecisionDTO.java index 59eb4f6..5c8d3c8 100644 --- a/src/main/java/io/autoinvestor/application/DecisionDTO.java +++ b/src/main/java/io/autoinvestor/application/DecisionDTO.java @@ -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) {} diff --git a/src/main/java/io/autoinvestor/application/GetDecisionsQuery.java b/src/main/java/io/autoinvestor/application/GetDecisionsQuery.java index ee1bc88..0247602 100644 --- a/src/main/java/io/autoinvestor/application/GetDecisionsQuery.java +++ b/src/main/java/io/autoinvestor/application/GetDecisionsQuery.java @@ -1,3 +1,3 @@ package io.autoinvestor.application; -public record GetDecisionsQuery(String assetId, Integer riskLevel) { } +public record GetDecisionsQuery(String assetId, Integer riskLevel) {} diff --git a/src/main/java/io/autoinvestor/application/GetDecisionsQueryHandler.java b/src/main/java/io/autoinvestor/application/GetDecisionsQueryHandler.java index 2e9afd6..1692bf7 100644 --- a/src/main/java/io/autoinvestor/application/GetDecisionsQueryHandler.java +++ b/src/main/java/io/autoinvestor/application/GetDecisionsQueryHandler.java @@ -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 { @@ -15,16 +15,13 @@ public GetDecisionsQueryHandler(ReadModelRepository readModel) { } public List handle(GetDecisionsQuery query) { - List decisions = this.readModel - .get(query.assetId(), query.riskLevel()); + List 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()); } } diff --git a/src/main/java/io/autoinvestor/application/GetDecisionsQueryResponse.java b/src/main/java/io/autoinvestor/application/GetDecisionsQueryResponse.java index 534c132..d886456 100644 --- a/src/main/java/io/autoinvestor/application/GetDecisionsQueryResponse.java +++ b/src/main/java/io/autoinvestor/application/GetDecisionsQueryResponse.java @@ -2,9 +2,4 @@ import java.util.Date; -public record GetDecisionsQueryResponse( - String assetId, - String type, - Date date, - int riskLevel -) { } \ No newline at end of file +public record GetDecisionsQueryResponse(String assetId, String type, Date date, int riskLevel) {} diff --git a/src/main/java/io/autoinvestor/application/ReadModelRepository.java b/src/main/java/io/autoinvestor/application/ReadModelRepository.java index df4f168..6093d5a 100644 --- a/src/main/java/io/autoinvestor/application/ReadModelRepository.java +++ b/src/main/java/io/autoinvestor/application/ReadModelRepository.java @@ -5,6 +5,8 @@ public interface ReadModelRepository { void save(DecisionDTO decisionDTO); + List get(String assetId, int riskLevel); + Optional getOne(String assetId, int riskLevel); } diff --git a/src/main/java/io/autoinvestor/application/RegisterDecisionCommand.java b/src/main/java/io/autoinvestor/application/RegisterDecisionCommand.java index 0f5ca17..57f6645 100644 --- a/src/main/java/io/autoinvestor/application/RegisterDecisionCommand.java +++ b/src/main/java/io/autoinvestor/application/RegisterDecisionCommand.java @@ -1,7 +1,3 @@ package io.autoinvestor.application; - -public record RegisterDecisionCommand( - String assetId, - int feeling -) { } +public record RegisterDecisionCommand(String assetId, int feeling) {} diff --git a/src/main/java/io/autoinvestor/application/RegisterDecisionCommandHandler.java b/src/main/java/io/autoinvestor/application/RegisterDecisionCommandHandler.java index 7e0533d..62164ff 100644 --- a/src/main/java/io/autoinvestor/application/RegisterDecisionCommandHandler.java +++ b/src/main/java/io/autoinvestor/application/RegisterDecisionCommandHandler.java @@ -6,11 +6,12 @@ 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 { @@ -18,7 +19,10 @@ public class RegisterDecisionCommandHandler { 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; @@ -26,33 +30,35 @@ public RegisterDecisionCommandHandler(EventStoreRepository eventStore, ReadModel public void handle(RegisterDecisionCommand command) { for (RiskLevel risklevel : RiskLevel.values()) { - Optional decisionFromReadModel = this.readModel.getOne(command.assetId(), risklevel.value()); + Optional 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> 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); diff --git a/src/main/java/io/autoinvestor/domain/Id.java b/src/main/java/io/autoinvestor/domain/Id.java index 7e541e8..4af1ee3 100644 --- a/src/main/java/io/autoinvestor/domain/Id.java +++ b/src/main/java/io/autoinvestor/domain/Id.java @@ -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); } diff --git a/src/main/java/io/autoinvestor/domain/events/DecisionTakenEvent.java b/src/main/java/io/autoinvestor/domain/events/DecisionTakenEvent.java index e84e2a3..f470eca 100644 --- a/src/main/java/io/autoinvestor/domain/events/DecisionTakenEvent.java +++ b/src/main/java/io/autoinvestor/domain/events/DecisionTakenEvent.java @@ -5,7 +5,6 @@ import java.util.Date; - public class DecisionTakenEvent extends Event { public static final String TYPE = "ASSET_DECISION_TAKEN"; @@ -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); } } diff --git a/src/main/java/io/autoinvestor/domain/events/DecisionTakenEventPayload.java b/src/main/java/io/autoinvestor/domain/events/DecisionTakenEventPayload.java index 3a95440..0f74b0b 100644 --- a/src/main/java/io/autoinvestor/domain/events/DecisionTakenEventPayload.java +++ b/src/main/java/io/autoinvestor/domain/events/DecisionTakenEventPayload.java @@ -3,12 +3,8 @@ 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 asMap() { @@ -16,7 +12,6 @@ public Map asMap() { "assetId", assetId, "date", date, "decision", decision, - "riskLevel", riskLevel - ); + "riskLevel", riskLevel); } } diff --git a/src/main/java/io/autoinvestor/domain/events/Event.java b/src/main/java/io/autoinvestor/domain/events/Event.java index ea579ff..75454c5 100644 --- a/src/main/java/io/autoinvestor/domain/events/Event.java +++ b/src/main/java/io/autoinvestor/domain/events/Event.java @@ -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; diff --git a/src/main/java/io/autoinvestor/domain/events/EventId.java b/src/main/java/io/autoinvestor/domain/events/EventId.java index 04eb658..1b08665 100644 --- a/src/main/java/io/autoinvestor/domain/events/EventId.java +++ b/src/main/java/io/autoinvestor/domain/events/EventId.java @@ -1,6 +1,5 @@ package io.autoinvestor.domain.events; - import io.autoinvestor.domain.Id; public class EventId extends Id { diff --git a/src/main/java/io/autoinvestor/domain/events/EventSourcedEntity.java b/src/main/java/io/autoinvestor/domain/events/EventSourcedEntity.java index abfef71..c592e73 100644 --- a/src/main/java/io/autoinvestor/domain/events/EventSourcedEntity.java +++ b/src/main/java/io/autoinvestor/domain/events/EventSourcedEntity.java @@ -33,4 +33,3 @@ public void markEventsAsCommitted() { appliedEvents.clear(); } } - diff --git a/src/main/java/io/autoinvestor/domain/events/EventStoreRepository.java b/src/main/java/io/autoinvestor/domain/events/EventStoreRepository.java index 1ae3267..ba8ae7f 100644 --- a/src/main/java/io/autoinvestor/domain/events/EventStoreRepository.java +++ b/src/main/java/io/autoinvestor/domain/events/EventStoreRepository.java @@ -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); } diff --git a/src/main/java/io/autoinvestor/domain/model/Decision.java b/src/main/java/io/autoinvestor/domain/model/Decision.java index d3b9f76..a834932 100644 --- a/src/main/java/io/autoinvestor/domain/model/Decision.java +++ b/src/main/java/io/autoinvestor/domain/model/Decision.java @@ -31,14 +31,14 @@ public void takeDecision(String assetId, int feelingInt, RiskLevel riskLevel) { Feeling feeling = Feeling.of(feelingInt); Type type = Type.calculateFromFeelingAndRiskLevel(feeling, riskLevel); - this.apply(DecisionTakenEvent.with( - this.state.decisionId(), - AssetId.of(assetId), - new Date(), - type, - riskLevel, - this.version - )); + this.apply( + DecisionTakenEvent.with( + this.state.decisionId(), + AssetId.of(assetId), + new Date(), + type, + riskLevel, + this.version)); } @Override diff --git a/src/main/java/io/autoinvestor/domain/model/DecisionId.java b/src/main/java/io/autoinvestor/domain/model/DecisionId.java index 9b74bca..b224d9b 100644 --- a/src/main/java/io/autoinvestor/domain/model/DecisionId.java +++ b/src/main/java/io/autoinvestor/domain/model/DecisionId.java @@ -2,7 +2,6 @@ import io.autoinvestor.domain.Id; - public class DecisionId extends Id { DecisionId(String id) { super(id); diff --git a/src/main/java/io/autoinvestor/domain/model/DecisionState.java b/src/main/java/io/autoinvestor/domain/model/DecisionState.java index f789b54..8eae8a6 100644 --- a/src/main/java/io/autoinvestor/domain/model/DecisionState.java +++ b/src/main/java/io/autoinvestor/domain/model/DecisionState.java @@ -11,8 +11,8 @@ public class DecisionState { private final Type type; private final RiskLevel riskLevel; - - private DecisionState(DecisionId decisionId, AssetId assetId, Date date, Type type, RiskLevel riskLevel) { + private DecisionState( + DecisionId decisionId, AssetId assetId, Date date, Type type, RiskLevel riskLevel) { this.decisionId = decisionId; this.assetId = assetId; this.date = date; @@ -21,7 +21,12 @@ private DecisionState(DecisionId decisionId, AssetId assetId, Date date, Type ty } public static DecisionState empty() { - return new DecisionState(DecisionId.generate(), AssetId.generate(), new Date() ,Type.NONE, RiskLevel.empty()); + return new DecisionState( + DecisionId.generate(), + AssetId.generate(), + new Date(), + Type.NONE, + RiskLevel.empty()); } public String assetId() { @@ -53,10 +58,10 @@ public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; DecisionState that = (DecisionState) obj; - return decisionId.equals(that.decisionId) && - assetId.equals(that.assetId) && - type == that.type && - riskLevel.equals(that.riskLevel); + return decisionId.equals(that.decisionId) + && assetId.equals(that.assetId) + && type == that.type + && riskLevel.equals(that.riskLevel); } public DecisionState withDecisionTaken(DecisionTakenEvent event) { diff --git a/src/main/java/io/autoinvestor/domain/model/RiskLevel.java b/src/main/java/io/autoinvestor/domain/model/RiskLevel.java index 8f4f8a5..e8d1959 100644 --- a/src/main/java/io/autoinvestor/domain/model/RiskLevel.java +++ b/src/main/java/io/autoinvestor/domain/model/RiskLevel.java @@ -24,6 +24,6 @@ public static RiskLevel of(int riskLevel) { } public static RiskLevel[] values() { - return new RiskLevel[] { R1, R2, R3, R4 }; + return new RiskLevel[] {R1, R2, R3, R4}; } } diff --git a/src/main/java/io/autoinvestor/domain/model/Type.java b/src/main/java/io/autoinvestor/domain/model/Type.java index 08e19c8..fc63346 100644 --- a/src/main/java/io/autoinvestor/domain/model/Type.java +++ b/src/main/java/io/autoinvestor/domain/model/Type.java @@ -31,5 +31,4 @@ public static Type calculateFromFeelingAndRiskLevel(Feeling feeling, RiskLevel r return HOLD; } - } diff --git a/src/main/java/io/autoinvestor/infrastructure/event_publishers/EventMessageMapper.java b/src/main/java/io/autoinvestor/infrastructure/event_publishers/EventMessageMapper.java index 90fc31c..4bee728 100644 --- a/src/main/java/io/autoinvestor/infrastructure/event_publishers/EventMessageMapper.java +++ b/src/main/java/io/autoinvestor/infrastructure/event_publishers/EventMessageMapper.java @@ -1,9 +1,5 @@ package io.autoinvestor.infrastructure.event_publishers; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.protobuf.ByteString; -import com.google.pubsub.v1.PubsubMessage; import io.autoinvestor.domain.events.Event; import io.autoinvestor.exceptions.InternalErrorException; @@ -11,6 +7,10 @@ import java.util.HashMap; import java.util.Map; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.protobuf.ByteString; +import com.google.pubsub.v1.PubsubMessage; final class EventMessageMapper { @@ -27,14 +27,12 @@ PubsubMessage toMessage(Event event) { envelope.put("eventId", event.getId().value()); envelope.put("type", event.getType()); envelope.put("aggregateId", event.getAggregateId().value()); - envelope.put("occurredAt", - Instant.ofEpochMilli(event.getOccurredAt().getTime()).toString()); + envelope.put( + "occurredAt", Instant.ofEpochMilli(event.getOccurredAt().getTime()).toString()); envelope.put("version", event.getVersion()); String json = objectMapper.writeValueAsString(envelope); - return PubsubMessage.newBuilder() - .setData(ByteString.copyFromUtf8(json)) - .build(); + return PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8(json)).build(); } catch (JsonProcessingException ex) { throw new InternalErrorException("Failed to serialise domain event"); } diff --git a/src/main/java/io/autoinvestor/infrastructure/event_publishers/InMemoryEventPublisher.java b/src/main/java/io/autoinvestor/infrastructure/event_publishers/InMemoryEventPublisher.java index 7048b79..f2e4760 100644 --- a/src/main/java/io/autoinvestor/infrastructure/event_publishers/InMemoryEventPublisher.java +++ b/src/main/java/io/autoinvestor/infrastructure/event_publishers/InMemoryEventPublisher.java @@ -1,10 +1,11 @@ package io.autoinvestor.infrastructure.event_publishers; +import io.autoinvestor.domain.events.Event; +import io.autoinvestor.domain.events.EventPublisher; + import java.util.ArrayList; import java.util.List; -import io.autoinvestor.domain.events.Event; -import io.autoinvestor.domain.events.EventPublisher; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; @@ -28,6 +29,9 @@ public void publish(List> events) { public boolean hasPublishedEvent(String type, String aggregateId) { return publishedEvents.stream() - .anyMatch(event -> event.getType().equals(type) && event.getAggregateId().value().equals(aggregateId)); + .anyMatch( + event -> + event.getType().equals(type) + && event.getAggregateId().value().equals(aggregateId)); } } diff --git a/src/main/java/io/autoinvestor/infrastructure/event_publishers/PubsubEventPublisher.java b/src/main/java/io/autoinvestor/infrastructure/event_publishers/PubsubEventPublisher.java index c44f765..6d0762b 100644 --- a/src/main/java/io/autoinvestor/infrastructure/event_publishers/PubsubEventPublisher.java +++ b/src/main/java/io/autoinvestor/infrastructure/event_publishers/PubsubEventPublisher.java @@ -1,18 +1,20 @@ package io.autoinvestor.infrastructure.event_publishers; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.pubsub.v1.ProjectTopicName; -import com.google.cloud.pubsub.v1.Publisher; import io.autoinvestor.domain.events.Event; import io.autoinvestor.domain.events.EventPublisher; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.concurrent.TimeUnit; + import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.concurrent.TimeUnit; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.cloud.pubsub.v1.Publisher; +import com.google.pubsub.v1.ProjectTopicName; @Slf4j @Component @@ -25,8 +27,8 @@ public class PubsubEventPublisher implements EventPublisher { public PubsubEventPublisher( @Value("${GCP_PROJECT}") String projectId, @Value("${PUBSUB_TOPIC}") String topic, - ObjectMapper objectMapper - ) throws Exception { + ObjectMapper objectMapper) + throws Exception { this.mapper = new EventMessageMapper(objectMapper); ProjectTopicName topicName = ProjectTopicName.of(projectId, topic); this.publisher = Publisher.newBuilder(topicName).build(); @@ -43,9 +45,7 @@ public void publish(List> events) { log.info("Publishing {} domain event(s)", events.size()); - events.stream() - .map(mapper::toMessage) - .forEach(publisher::publish); + events.stream().map(mapper::toMessage).forEach(publisher::publish); } @PreDestroy diff --git a/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEvent.java b/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEvent.java index 41e0dd1..b212c11 100644 --- a/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEvent.java +++ b/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEvent.java @@ -1,6 +1,5 @@ package io.autoinvestor.infrastructure.listeners; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -8,9 +7,13 @@ import java.util.Map; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -@Data @Builder @NoArgsConstructor @AllArgsConstructor +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor public class PubsubEvent { private String aggregateId; private String type; diff --git a/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEventMapper.java b/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEventMapper.java index 3c1384e..5b50853 100644 --- a/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEventMapper.java +++ b/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubEventMapper.java @@ -1,12 +1,12 @@ package io.autoinvestor.infrastructure.listeners; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; import java.util.Map; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; @Component @RequiredArgsConstructor diff --git a/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubNewsEventSubscriber.java b/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubNewsEventSubscriber.java index 65eaf0f..bc6ed34 100644 --- a/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubNewsEventSubscriber.java +++ b/src/main/java/io/autoinvestor/infrastructure/listeners/PubsubNewsEventSubscriber.java @@ -1,24 +1,26 @@ package io.autoinvestor.infrastructure.listeners; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.api.core.ApiService.Listener; -import com.google.api.core.ApiService.State; -import com.google.cloud.pubsub.v1.AckReplyConsumer; -import com.google.cloud.pubsub.v1.MessageReceiver; -import com.google.cloud.pubsub.v1.Subscriber; -import com.google.pubsub.v1.ProjectSubscriptionName; -import com.google.pubsub.v1.PubsubMessage; import io.autoinvestor.application.RegisterDecisionCommand; import io.autoinvestor.application.RegisterDecisionCommandHandler; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; -import java.util.Map; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.api.core.ApiService.Listener; +import com.google.api.core.ApiService.State; +import com.google.cloud.pubsub.v1.AckReplyConsumer; +import com.google.cloud.pubsub.v1.MessageReceiver; +import com.google.cloud.pubsub.v1.Subscriber; +import com.google.pubsub.v1.ProjectSubscriptionName; +import com.google.pubsub.v1.PubsubMessage; @Slf4j @Component @@ -37,8 +39,8 @@ public PubsubNewsEventSubscriber( PubsubEventMapper eventMapper, @Value("${GCP_PROJECT}") String projectId, @Value("${PUBSUB_SUBSCRIPTION_MARKET_FEELING}") String subscriptionId) { - this.commandHandler = commandHandler; - this.eventMapper = eventMapper; + this.commandHandler = commandHandler; + this.eventMapper = eventMapper; this.subscriptionName = ProjectSubscriptionName.of(projectId, subscriptionId); } @@ -49,11 +51,18 @@ public void listen() { MessageReceiver receiver = this::processMessage; this.subscriber = Subscriber.newBuilder(subscriptionName, receiver).build(); - this.subscriber.addListener(new Listener() { - @Override public void failed(State from, Throwable failure) { - log.error("Subscriber failed from state {}: {}", from, failure.toString(), failure); // ERROR - } - }, Runnable::run); + this.subscriber.addListener( + new Listener() { + @Override + public void failed(State from, Throwable failure) { + log.error( + "Subscriber failed from state {}: {}", + from, + failure.toString(), + failure); // ERROR + } + }, + Runnable::run); subscriber.startAsync().awaitRunning(); log.info("Subscriber running"); } @@ -71,7 +80,9 @@ private void processMessage(PubsubMessage message, AckReplyConsumer consumer) { log.debug("Received message msgId={} size={}B", msgId, message.getData().size()); try { - Map raw = objectMapper.readValue(message.getData().toByteArray(), new TypeReference<>() {}); + Map raw = + objectMapper.readValue( + message.getData().toByteArray(), new TypeReference<>() {}); PubsubEvent event = eventMapper.fromMap(raw); log.info("Processing event type={} msgId={}", event.getType(), msgId); @@ -89,19 +100,23 @@ private void processMessage(PubsubMessage message, AckReplyConsumer consumer) { return; } } else { - log.warn("Unexpected feeling type {}; ignoring msgId={}", - rawFeeling == null ? "null" : rawFeeling.getClass(), msgId); + log.warn( + "Unexpected feeling type {}; ignoring msgId={}", + rawFeeling == null ? "null" : rawFeeling.getClass(), + msgId); consumer.ack(); return; } - RegisterDecisionCommand cmd = new RegisterDecisionCommand( - (String) event.getPayload().get("assetId"), - feeling - ); + RegisterDecisionCommand cmd = + new RegisterDecisionCommand( + (String) event.getPayload().get("assetId"), feeling); commandHandler.handle(cmd); - log.info("Decision registered for asset={} feeling={} msgId={}", - cmd.assetId(), cmd.feeling(), msgId); + log.info( + "Decision registered for asset={} feeling={} msgId={}", + cmd.assetId(), + cmd.feeling(), + msgId); } else { log.debug("Ignored unsupported event type={} msgId={}", event.getType(), msgId); } diff --git a/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionDocument.java b/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionDocument.java index 7c086ef..b3cfa2d 100644 --- a/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionDocument.java +++ b/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionDocument.java @@ -2,44 +2,38 @@ import lombok.Getter; import lombok.Setter; + +import java.util.Date; + import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.index.CompoundIndex; import org.springframework.data.mongodb.core.index.CompoundIndexes; import org.springframework.data.mongodb.core.mapping.Document; -import java.util.Date; - @Setter @Getter @Document(collection = "decisions") @CompoundIndexes({ - @CompoundIndex(name = "assetId_riskLevel_idx", - def = "{'assetId': 1, 'riskLevel': 1}") + @CompoundIndex(name = "assetId_riskLevel_idx", def = "{'assetId': 1, 'riskLevel': 1}") }) public class DecisionDocument { - @Id - private String id; + @Id private String id; private String decisionId; private String assetId; - private Date date; + private Date date; private String type; - private int riskLevel; + private int riskLevel; - public DecisionDocument() { } + public DecisionDocument() {} - public DecisionDocument(String id, - String decisionId, - String assetId, - Date date, - String type, - int riskLevel) { - this.id = id; + public DecisionDocument( + String id, String decisionId, String assetId, Date date, String type, int riskLevel) { + this.id = id; this.decisionId = decisionId; - this.assetId = assetId; - this.date = date; - this.type = type; + this.assetId = assetId; + this.date = date; + this.type = type; this.riskLevel = riskLevel; } - } diff --git a/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionMapper.java b/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionMapper.java index ba5fd75..14aa4ed 100644 --- a/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionMapper.java +++ b/src/main/java/io/autoinvestor/infrastructure/read_models/DecisionMapper.java @@ -1,21 +1,15 @@ package io.autoinvestor.infrastructure.read_models; import io.autoinvestor.application.DecisionDTO; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Component; @Component public class DecisionMapper { public DecisionDocument toDocument(DecisionDTO dto) { return new DecisionDocument( - null, - dto.decisionId(), - dto.assetId(), - dto.date(), - dto.type(), - dto.riskLevel() - ); + null, dto.decisionId(), dto.assetId(), dto.date(), dto.type(), dto.riskLevel()); } public DecisionDTO toDTO(DecisionDocument doc) { @@ -24,7 +18,6 @@ public DecisionDTO toDTO(DecisionDocument doc) { doc.getAssetId(), doc.getDate(), doc.getType(), - doc.getRiskLevel() - ); + doc.getRiskLevel()); } } diff --git a/src/main/java/io/autoinvestor/infrastructure/read_models/InMemoryReadModelRepository.java b/src/main/java/io/autoinvestor/infrastructure/read_models/InMemoryReadModelRepository.java index 927b483..58106ae 100644 --- a/src/main/java/io/autoinvestor/infrastructure/read_models/InMemoryReadModelRepository.java +++ b/src/main/java/io/autoinvestor/infrastructure/read_models/InMemoryReadModelRepository.java @@ -2,21 +2,22 @@ import io.autoinvestor.application.DecisionDTO; import io.autoinvestor.application.ReadModelRepository; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Repository; import java.util.Date; import java.util.List; import java.util.Optional; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + @Repository @Profile("local") public class InMemoryReadModelRepository implements ReadModelRepository { - private final List decisions = List.of( - new DecisionDTO("12345", "AAPL", new Date(), "BUY", 1), - new DecisionDTO("54321", "AAPL", new Date(), "SELL", 2), - new DecisionDTO("21345", "GOOGL", new Date(), "BUY", 3) - ); + private final List decisions = + List.of( + new DecisionDTO("12345", "AAPL", new Date(), "BUY", 1), + new DecisionDTO("54321", "AAPL", new Date(), "SELL", 2), + new DecisionDTO("21345", "GOOGL", new Date(), "BUY", 3)); @Override public void save(DecisionDTO decisionDTO) { @@ -26,14 +27,20 @@ public void save(DecisionDTO decisionDTO) { @Override public List get(String assetId, int riskLevel) { return decisions.stream() - .filter(decision -> decision.assetId().equals(assetId) && decision.riskLevel() == riskLevel) + .filter( + decision -> + decision.assetId().equals(assetId) + && decision.riskLevel() == riskLevel) .toList(); } @Override public Optional getOne(String assetId, int riskLevel) { return decisions.stream() - .filter(decision -> decision.assetId().equals(assetId) && decision.riskLevel() == riskLevel) + .filter( + decision -> + decision.assetId().equals(assetId) + && decision.riskLevel() == riskLevel) .findFirst(); } } diff --git a/src/main/java/io/autoinvestor/infrastructure/read_models/MongoReadModelRepository.java b/src/main/java/io/autoinvestor/infrastructure/read_models/MongoReadModelRepository.java index 732f9f6..5c48574 100644 --- a/src/main/java/io/autoinvestor/infrastructure/read_models/MongoReadModelRepository.java +++ b/src/main/java/io/autoinvestor/infrastructure/read_models/MongoReadModelRepository.java @@ -2,6 +2,10 @@ import io.autoinvestor.application.DecisionDTO; import io.autoinvestor.application.ReadModelRepository; + +import java.util.List; +import java.util.Optional; + import org.springframework.context.annotation.Profile; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; @@ -9,13 +13,8 @@ import org.springframework.data.mongodb.core.index.IndexOperations; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - - @Repository @Profile("prod") public class MongoReadModelRepository implements ReadModelRepository { @@ -30,10 +29,11 @@ public MongoReadModelRepository(MongoTemplate template, DecisionMapper mapper) { this.mapper = mapper; IndexOperations indexOps = template.indexOps(COLLECTION); - Index compound = new Index() - .on("assetId", Sort.Direction.ASC) - .on("riskLevel", Sort.Direction.ASC) - .named("assetId_riskLevel_idx"); + Index compound = + new Index() + .on("assetId", Sort.Direction.ASC) + .on("riskLevel", Sort.Direction.ASC) + .named("assetId_riskLevel_idx"); indexOps.ensureIndex(compound); } @@ -44,24 +44,18 @@ public void save(DecisionDTO decisionDTO) { @Override public List get(String assetId, int riskLevel) { - Query query = Query.query( - Criteria.where("assetId").is(assetId) - .and("riskLevel").is(riskLevel) - ); - return template.find(query, DecisionDocument.class, COLLECTION) - .stream() + Query query = + Query.query(Criteria.where("assetId").is(assetId).and("riskLevel").is(riskLevel)); + return template.find(query, DecisionDocument.class, COLLECTION).stream() .map(mapper::toDTO) .toList(); } @Override public Optional getOne(String assetId, int riskLevel) { - Query query = Query.query( - Criteria.where("assetId").is(assetId) - .and("riskLevel").is(riskLevel) - ); + Query query = + Query.query(Criteria.where("assetId").is(assetId).and("riskLevel").is(riskLevel)); DecisionDocument doc = template.findOne(query, DecisionDocument.class, COLLECTION); - return Optional.ofNullable(doc) - .map(mapper::toDTO); + return Optional.ofNullable(doc).map(mapper::toDTO); } } diff --git a/src/main/java/io/autoinvestor/infrastructure/repositories/EventDocument.java b/src/main/java/io/autoinvestor/infrastructure/repositories/EventDocument.java index 8db9923..dbc737a 100644 --- a/src/main/java/io/autoinvestor/infrastructure/repositories/EventDocument.java +++ b/src/main/java/io/autoinvestor/infrastructure/repositories/EventDocument.java @@ -2,49 +2,45 @@ import lombok.Getter; import lombok.Setter; -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; -import org.springframework.data.mongodb.core.mapping.Field; import java.util.Date; import java.util.Map; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + @Getter @Setter @Document(collection = "events") public class EventDocument { - @Id - private String id; + @Id private String id; - @Field - private String aggregateId; + @Field private String aggregateId; - @Field - private String type; + @Field private String type; - @Field - private Map payload; + @Field private Map payload; - @Field - private Date occurredAt; + @Field private Date occurredAt; - @Field - private int version; + @Field private int version; - public EventDocument() { } + public EventDocument() {} - public EventDocument(String id, - String aggregateId, - String type, - Map payload, - Date occurredAt, - int version) { - this.id = id; + public EventDocument( + String id, + String aggregateId, + String type, + Map payload, + Date occurredAt, + int version) { + this.id = id; this.aggregateId = aggregateId; - this.type = type; - this.payload = payload; - this.occurredAt = occurredAt; - this.version = version; + this.type = type; + this.payload = payload; + this.occurredAt = occurredAt; + this.version = version; } } diff --git a/src/main/java/io/autoinvestor/infrastructure/repositories/EventMapper.java b/src/main/java/io/autoinvestor/infrastructure/repositories/EventMapper.java index b03184a..17d1a6e 100644 --- a/src/main/java/io/autoinvestor/infrastructure/repositories/EventMapper.java +++ b/src/main/java/io/autoinvestor/infrastructure/repositories/EventMapper.java @@ -1,14 +1,16 @@ package io.autoinvestor.infrastructure.repositories; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import io.autoinvestor.domain.events.*; import io.autoinvestor.domain.model.DecisionId; -import org.springframework.stereotype.Component; import java.util.Date; import java.util.Map; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + @Component public class EventMapper { @@ -24,15 +26,14 @@ public

EventDocument toDocument(Event

evt) { evt.getType(), payloadMap, evt.getOccurredAt(), - evt.getVersion() - ); + evt.getVersion()); } public Event toDomain(EventDocument doc) { - EventId id = EventId.of(doc.getId()); - DecisionId aggId = DecisionId.from(doc.getAggregateId()); - Date occurred = doc.getOccurredAt(); - int version = doc.getVersion(); + EventId id = EventId.of(doc.getId()); + DecisionId aggId = DecisionId.from(doc.getAggregateId()); + Date occurred = doc.getOccurredAt(); + int version = doc.getVersion(); switch (doc.getType()) { case DecisionTakenEvent.TYPE -> { @@ -42,9 +43,7 @@ public Event toDomain(EventDocument doc) { return DecisionTakenEvent.hydrate(id, aggId, payload, occurred, version); } - default -> throw new IllegalArgumentException( - "Unknown event type: " + doc.getType() - ); + default -> throw new IllegalArgumentException("Unknown event type: " + doc.getType()); } } } diff --git a/src/main/java/io/autoinvestor/infrastructure/repositories/InMemoryEventStoreRepository.java b/src/main/java/io/autoinvestor/infrastructure/repositories/InMemoryEventStoreRepository.java index 316ef6e..c68854d 100644 --- a/src/main/java/io/autoinvestor/infrastructure/repositories/InMemoryEventStoreRepository.java +++ b/src/main/java/io/autoinvestor/infrastructure/repositories/InMemoryEventStoreRepository.java @@ -4,13 +4,14 @@ import io.autoinvestor.domain.events.EventStoreRepository; import io.autoinvestor.domain.model.Decision; import io.autoinvestor.domain.model.DecisionId; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Repository; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + @Repository @Profile("local") public class InMemoryEventStoreRepository implements EventStoreRepository { @@ -23,9 +24,10 @@ public void save(Decision decision) { @Override public Decision get(DecisionId decisionId) { - List> eventsForAggregate = eventStore.stream() - .filter(event -> event.getAggregateId().equals(decisionId)) - .collect(Collectors.toList()); + List> eventsForAggregate = + eventStore.stream() + .filter(event -> event.getAggregateId().equals(decisionId)) + .collect(Collectors.toList()); if (eventsForAggregate.isEmpty()) { return null; diff --git a/src/main/java/io/autoinvestor/infrastructure/repositories/MongoEventStoreRepository.java b/src/main/java/io/autoinvestor/infrastructure/repositories/MongoEventStoreRepository.java index 85f765e..bd2c3af 100644 --- a/src/main/java/io/autoinvestor/infrastructure/repositories/MongoEventStoreRepository.java +++ b/src/main/java/io/autoinvestor/infrastructure/repositories/MongoEventStoreRepository.java @@ -4,6 +4,10 @@ import io.autoinvestor.domain.events.EventStoreRepository; import io.autoinvestor.domain.model.Decision; import io.autoinvestor.domain.model.DecisionId; + +import java.util.List; +import java.util.stream.Collectors; + import org.springframework.context.annotation.Profile; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; @@ -11,9 +15,6 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.stream.Collectors; - @Repository @Profile("prod") public class MongoEventStoreRepository implements EventStoreRepository { @@ -29,20 +30,18 @@ public MongoEventStoreRepository(MongoTemplate template, EventMapper mapper) { @Override public void save(Decision decision) { - List docs = decision.getUncommittedEvents() - .stream() - .map(mapper::toDocument) - .collect(Collectors.toList()); + List docs = + decision.getUncommittedEvents().stream() + .map(mapper::toDocument) + .collect(Collectors.toList()); template.insertAll(docs); } @Override public Decision get(DecisionId decisionId) { - Query q = Query.query( - Criteria.where("aggregateId") - .is(decisionId.value()) - ) - .with(Sort.by("version")); + Query q = + Query.query(Criteria.where("aggregateId").is(decisionId.value())) + .with(Sort.by("version")); List docs = template.find(q, EventDocument.class, COLLECTION); @@ -50,9 +49,7 @@ public Decision get(DecisionId decisionId) { return null; } - List> events = docs.stream() - .map(mapper::toDomain) - .collect(Collectors.toList()); + List> events = docs.stream().map(mapper::toDomain).collect(Collectors.toList()); if (events.isEmpty()) { return Decision.empty(); diff --git a/src/main/java/io/autoinvestor/ui/GetDecisionsController.java b/src/main/java/io/autoinvestor/ui/GetDecisionsController.java index ef5128c..ae62b0b 100644 --- a/src/main/java/io/autoinvestor/ui/GetDecisionsController.java +++ b/src/main/java/io/autoinvestor/ui/GetDecisionsController.java @@ -3,11 +3,12 @@ import io.autoinvestor.application.GetDecisionsQuery; import io.autoinvestor.application.GetDecisionsQueryHandler; import io.autoinvestor.application.GetDecisionsQueryResponse; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; import java.util.List; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + @RestController @RequestMapping("/decisions") public class GetDecisionsController { @@ -20,21 +21,18 @@ public GetDecisionsController(GetDecisionsQueryHandler handler) { @GetMapping public ResponseEntity> getDecisions( - @RequestParam String assetId, - @RequestParam Integer riskLevel) { - - List queryResponse = this.handler.handle( - new GetDecisionsQuery(assetId, riskLevel) - ); - - List dto = queryResponse.stream() - .map(d -> new GetDecisionsDTO( - d.assetId(), - d.type(), - d.date(), - d.riskLevel() - )) - .toList(); + @RequestParam String assetId, @RequestParam Integer riskLevel) { + + List queryResponse = + this.handler.handle(new GetDecisionsQuery(assetId, riskLevel)); + + List dto = + queryResponse.stream() + .map( + d -> + new GetDecisionsDTO( + d.assetId(), d.type(), d.date(), d.riskLevel())) + .toList(); return ResponseEntity.ok(dto); } diff --git a/src/main/java/io/autoinvestor/ui/GetDecisionsDTO.java b/src/main/java/io/autoinvestor/ui/GetDecisionsDTO.java index 06aac60..61be22d 100644 --- a/src/main/java/io/autoinvestor/ui/GetDecisionsDTO.java +++ b/src/main/java/io/autoinvestor/ui/GetDecisionsDTO.java @@ -2,5 +2,4 @@ import java.util.Date; -public record GetDecisionsDTO(String assetId, String type, Date date, int riskLevel) { -} +public record GetDecisionsDTO(String assetId, String type, Date date, int riskLevel) {}