Transaction aggregate implementation
This commit is contained in:
@@ -4,27 +4,8 @@ import com.mz.reactor.ddd.common.api.command.CommandHandler;
|
||||
import com.mz.reactor.ddd.common.api.command.CommandResult;
|
||||
import com.mz.reactor.ddd.reactorddd.account.domain.AccountAggregate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class AccountCommandHandler implements CommandHandler<AccountAggregate, AccountCommand> {
|
||||
|
||||
private final Map<Class, BiFunction> handlers = new HashMap<>();
|
||||
|
||||
public AccountCommandHandler() {
|
||||
addHandler(CreateAccount.class, this::doCreateAccount);
|
||||
addHandler(WithdrawMoney.class, this::doWithdrawMoney);
|
||||
addHandler(DepositMoney.class, this::doDepositMoney);
|
||||
}
|
||||
|
||||
private <K extends AccountCommand> void addHandler(
|
||||
Class<K> kClass,
|
||||
BiFunction<AccountAggregate, K, CommandResult> handler
|
||||
) {
|
||||
this.handlers.put(kClass, handler);
|
||||
}
|
||||
|
||||
private CommandResult doWithdrawMoney(AccountAggregate aggregate, WithdrawMoney command) {
|
||||
return null;
|
||||
}
|
||||
@@ -39,6 +20,14 @@ public class AccountCommandHandler implements CommandHandler<AccountAggregate, A
|
||||
|
||||
@Override
|
||||
public CommandResult execute(AccountAggregate aggregate, AccountCommand command) {
|
||||
return (CommandResult) handlers.get(command.getClass()).apply(aggregate, command);
|
||||
if (command instanceof WithdrawMoney) {
|
||||
return doWithdrawMoney(aggregate, (WithdrawMoney) command);
|
||||
} else if (command instanceof CreateAccount) {
|
||||
return doCreateAccount(aggregate, (CreateAccount) command);
|
||||
} else if (command instanceof DepositMoney) {
|
||||
return doDepositMoney(aggregate, (DepositMoney) command);
|
||||
} else {
|
||||
return CommandResult.badCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,21 +9,6 @@ import java.util.function.BiFunction;
|
||||
|
||||
public class AccountEventApplier implements EventApplier<AccountAggregate, AccountEvent> {
|
||||
|
||||
private final Map<Class, BiFunction> appliers = new HashMap<>();
|
||||
|
||||
public AccountEventApplier() {
|
||||
addApplier(AccountCreated.class, this::applyAccountCreated);
|
||||
addApplier(MoneyWithdrawn.class, this::applyMoneyWithdrawn);
|
||||
addApplier(MoneyDeposited.class, this::applyMoneyDeposited);
|
||||
}
|
||||
|
||||
private <E extends AccountEvent> void addApplier(
|
||||
Class<E> eClass,
|
||||
BiFunction<AccountAggregate, E, AccountAggregate> applier
|
||||
) {
|
||||
appliers.put(eClass, applier);
|
||||
}
|
||||
|
||||
private AccountAggregate applyAccountCreated(AccountAggregate aggregate, AccountCreated event) {
|
||||
return aggregate;
|
||||
}
|
||||
@@ -38,6 +23,14 @@ public class AccountEventApplier implements EventApplier<AccountAggregate, Accou
|
||||
|
||||
@Override
|
||||
public AccountAggregate apply(AccountAggregate aggregate, AccountEvent event) {
|
||||
return (AccountAggregate) appliers.get(event.getClass()).apply(aggregate, event);
|
||||
if (event instanceof AccountCreated) {
|
||||
return applyAccountCreated(aggregate, (AccountCreated) event);
|
||||
} else if (event instanceof MoneyWithdrawn) {
|
||||
return applyMoneyWithdrawn(aggregate, (MoneyWithdrawn) event);
|
||||
} else if (event instanceof MoneyDeposited) {
|
||||
return applyMoneyDeposited(aggregate, (MoneyDeposited) event);
|
||||
} else {
|
||||
return aggregate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package com.mz.reactor.ddd.reactorddd.transaction.domain;
|
||||
|
||||
import com.mz.reactor.ddd.common.api.valueobject.Id;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.command.CreateTransaction;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.command.FinishTransaction;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.event.TransactionCreated;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.event.TransactionFinished;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class TransactionAggregate {
|
||||
|
||||
enum TransactionState {
|
||||
Created,
|
||||
Finished,
|
||||
Failed
|
||||
enum State {
|
||||
INITIALIZED,
|
||||
CREATED,
|
||||
FINISHED,
|
||||
FAILED
|
||||
}
|
||||
|
||||
private Id aggregateId;
|
||||
@@ -20,7 +25,60 @@ public class TransactionAggregate {
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
private State state;
|
||||
|
||||
public TransactionAggregate(String aggregateId) {
|
||||
this.aggregateId = new Id(aggregateId);
|
||||
state = State.INITIALIZED;
|
||||
}
|
||||
|
||||
public TransactionCreated validateCreateTransaction(CreateTransaction command) {
|
||||
if (state == State.INITIALIZED) {
|
||||
Id.validate(command.fromAccountId(), command.toAccountId());
|
||||
if (command.amount().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new RuntimeException(String.format("Amount can't be %s", command.amount()));
|
||||
}
|
||||
|
||||
return TransactionCreated.builder()
|
||||
.aggregateId(this.aggregateId.getValue())
|
||||
.correlationId(command.correlationId())
|
||||
.amount(command.amount())
|
||||
.fromAccountId(command.fromAccountId())
|
||||
.toAccountId(command.toAccountId())
|
||||
.build();
|
||||
} else {
|
||||
throw new RuntimeException(String.format("Can't be applied command %s, aggregate is in state %s",
|
||||
command, this.state));
|
||||
}
|
||||
}
|
||||
|
||||
public TransactionFinished validateFinishTransaction(FinishTransaction command) {
|
||||
if (state == State.CREATED) {
|
||||
return TransactionFinished.builder()
|
||||
.aggregateId(aggregateId.getValue())
|
||||
.correlationId(command.correlationId())
|
||||
.fromAccountId(fromAccount.getValue())
|
||||
.toAccountId(toAccount.getValue())
|
||||
.build();
|
||||
} else {
|
||||
throw new RuntimeException(String.format("Transaction in the state: %s can't be finished!", state));
|
||||
}
|
||||
}
|
||||
|
||||
public TransactionAggregate applyTransactionCreated(TransactionCreated created) {
|
||||
this.fromAccount = new Id(created.fromAccountId());
|
||||
this.toAccount = new Id(created.toAccountId());
|
||||
this.amount = created.amount();
|
||||
this.state = State.CREATED;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TransactionState getState() {
|
||||
return TransactionState.builder()
|
||||
.amount(amount)
|
||||
.fromAccountId(fromAccount.getValue())
|
||||
.toAccountId(toAccount.getValue())
|
||||
.aggregateId(aggregateId.getValue())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.math.BigDecimal;
|
||||
|
||||
@Value.Immutable
|
||||
public interface CreateTransaction extends TransactionCommand {
|
||||
String aggregateId();
|
||||
|
||||
String fromAccountId();
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mz.reactor.ddd.reactorddd.transaction.domain.command;
|
||||
|
||||
import org.immutables.value.Value;
|
||||
|
||||
@Value.Immutable
|
||||
public interface FinishTransaction extends TransactionCommand {
|
||||
|
||||
String fromAccountId();
|
||||
|
||||
String toAccountId();
|
||||
|
||||
static ImmutableFinishTransaction.Builder builder() {
|
||||
return ImmutableFinishTransaction.builder();
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,5 @@ package com.mz.reactor.ddd.reactorddd.transaction.domain.command;
|
||||
import com.mz.reactor.ddd.common.api.command.Command;
|
||||
|
||||
public interface TransactionCommand extends Command {
|
||||
String aggregateId();
|
||||
}
|
||||
|
||||
@@ -2,33 +2,42 @@ package com.mz.reactor.ddd.reactorddd.transaction.domain.command;
|
||||
|
||||
import com.mz.reactor.ddd.common.api.command.CommandHandler;
|
||||
import com.mz.reactor.ddd.common.api.command.CommandResult;
|
||||
import com.mz.reactor.ddd.common.api.command.ImmutableCommandResult;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.TransactionAggregate;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.event.TransactionFailed;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class TransactionCommandHandler implements CommandHandler<TransactionAggregate, TransactionCommand> {
|
||||
|
||||
private final Map<Class, BiFunction> handlers = new HashMap<>();
|
||||
|
||||
public TransactionCommandHandler() {
|
||||
addHandler(CreateTransaction.class, this::doCreateTransaction);
|
||||
}
|
||||
|
||||
private <C extends TransactionCommand> void addHandler(
|
||||
Class<C> kClass,
|
||||
BiFunction<TransactionAggregate, C, CommandResult> handler
|
||||
) {
|
||||
handlers.put(kClass, handler);
|
||||
}
|
||||
|
||||
private CommandResult doCreateTransaction(TransactionAggregate aggregate, CreateTransaction command) {
|
||||
return (CommandResult) handlers.get(command).apply(aggregate, command);
|
||||
try {
|
||||
return Optional.ofNullable(aggregate.validateCreateTransaction(command))
|
||||
.map(e -> CommandResult.builder()
|
||||
.events(List.of(e))
|
||||
.statusCode(CommandResult.StatusCode.OK)
|
||||
.build())
|
||||
.orElseGet(() -> (ImmutableCommandResult) CommandResult.notModified());
|
||||
} catch (RuntimeException e) {
|
||||
return CommandResult.builder()
|
||||
.events(List.of(TransactionFailed.from(command)))
|
||||
.statusCode(CommandResult.StatusCode.FAILED)
|
||||
.error(e)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(TransactionAggregate aggregate, TransactionCommand command) {
|
||||
return null;
|
||||
if (command instanceof CreateTransaction) {
|
||||
return doCreateTransaction(aggregate, (CreateTransaction) command);
|
||||
} else {
|
||||
return CommandResult.badCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.math.BigDecimal;
|
||||
|
||||
@Value.Immutable
|
||||
public interface TransactionCreated extends TransactionEvent {
|
||||
|
||||
|
||||
String fromAccountId();
|
||||
|
||||
String toAccountId();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.mz.reactor.ddd.reactorddd.transaction.domain.event;
|
||||
|
||||
import com.mz.reactor.ddd.common.api.event.EventApplier;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.TransactionAggregate;
|
||||
|
||||
public class TransactionEventApplier implements EventApplier<TransactionAggregate, TransactionEvent> {
|
||||
|
||||
|
||||
@Override
|
||||
public TransactionAggregate apply(TransactionAggregate aggregate, TransactionEvent event) {
|
||||
if (event instanceof TransactionCreated) {
|
||||
return applyTransactionCreated(aggregate, (TransactionCreated) event);
|
||||
} else {
|
||||
return aggregate;
|
||||
}
|
||||
}
|
||||
|
||||
private TransactionAggregate applyTransactionCreated(TransactionAggregate aggregate, TransactionCreated event) {
|
||||
return aggregate.applyTransactionCreated(event);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.mz.reactor.ddd.reactorddd.transaction.domain.event;
|
||||
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.command.CreateTransaction;
|
||||
import org.immutables.value.Value;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -17,4 +18,13 @@ public interface TransactionFailed extends TransactionEvent {
|
||||
return ImmutableTransactionFailed.builder();
|
||||
}
|
||||
|
||||
static TransactionFailed from(CreateTransaction command) {
|
||||
return TransactionFailed.builder()
|
||||
.toAccountId(command.toAccountId())
|
||||
.fromAccountId(command.fromAccountId())
|
||||
.aggregateId(command.aggregateId())
|
||||
.correlationId(command.correlationId())
|
||||
.amount(command.amount())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import org.immutables.value.Value;
|
||||
@Value.Immutable
|
||||
public interface TransactionFinished extends TransactionEvent {
|
||||
|
||||
String fromAccountId();
|
||||
|
||||
String toAccountId();
|
||||
|
||||
static ImmutableTransactionFinished.Builder builder() {
|
||||
return ImmutableTransactionFinished.builder();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.mz.reactor.ddd.reactorddd.transaction.domain;
|
||||
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.command.CreateTransaction;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.command.FinishTransaction;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.event.TransactionCreated;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.event.TransactionFinished;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TransactionAggregateTest {
|
||||
|
||||
@Test
|
||||
void validateCreateTransaction_TransactionCreatedTest() {
|
||||
var aggregateId = UUID.randomUUID().toString();
|
||||
var correlationId = UUID.randomUUID().toString();
|
||||
var toAccountId = UUID.randomUUID().toString();
|
||||
var fromAccountId = UUID.randomUUID().toString();
|
||||
var command = CreateTransaction.builder()
|
||||
.aggregateId(aggregateId)
|
||||
.amount(BigDecimal.ONE)
|
||||
.correlationId(correlationId)
|
||||
.fromAccountId(fromAccountId)
|
||||
.toAccountId(toAccountId)
|
||||
.build();
|
||||
var aggregate = new TransactionAggregate(aggregateId);
|
||||
var result = aggregate.validateCreateTransaction(command);
|
||||
assertTrue(result instanceof TransactionCreated);
|
||||
assertEquals(result.correlationId().get(), correlationId);
|
||||
assertEquals(result.aggregateId(), aggregateId);
|
||||
assertEquals(result.toAccountId(), toAccountId);
|
||||
assertEquals(result.fromAccountId(), fromAccountId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateCreateTransaction_TransactionFailed_amount() {
|
||||
var aggregateId = UUID.randomUUID().toString();
|
||||
var correlationId = UUID.randomUUID().toString();
|
||||
var toAccountId = UUID.randomUUID().toString();
|
||||
var fromAccountId = UUID.randomUUID().toString();
|
||||
var command = CreateTransaction.builder()
|
||||
.aggregateId(aggregateId)
|
||||
.amount(BigDecimal.ZERO)
|
||||
.correlationId(correlationId)
|
||||
.fromAccountId(fromAccountId)
|
||||
.toAccountId(toAccountId)
|
||||
.build();
|
||||
var aggregate = new TransactionAggregate(aggregateId);
|
||||
assertThrows(RuntimeException.class, () -> aggregate.validateCreateTransaction(command));
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyTransactionCreated() {
|
||||
var aggregateId = UUID.randomUUID().toString();
|
||||
var correlationId = UUID.randomUUID().toString();
|
||||
var toAccountId = UUID.randomUUID().toString();
|
||||
var fromAccountId = UUID.randomUUID().toString();
|
||||
|
||||
var event = TransactionCreated.builder()
|
||||
.aggregateId(aggregateId)
|
||||
.correlationId(correlationId)
|
||||
.amount(BigDecimal.TEN)
|
||||
.fromAccountId(fromAccountId)
|
||||
.toAccountId(toAccountId)
|
||||
.build();
|
||||
|
||||
var aggregate = new TransactionAggregate(aggregateId);
|
||||
var state = aggregate.applyTransactionCreated(event).getState();
|
||||
|
||||
assertEquals(state.aggregateId(), aggregateId);
|
||||
assertEquals(state.toAccountId(), toAccountId);
|
||||
assertEquals(state.fromAccountId(), fromAccountId);
|
||||
assertEquals(state.amount(), BigDecimal.TEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateFinishTransaction_OK() {
|
||||
var aggregateId = UUID.randomUUID().toString();
|
||||
var correlationId = UUID.randomUUID().toString();
|
||||
var toAccountId = UUID.randomUUID().toString();
|
||||
var fromAccountId = UUID.randomUUID().toString();
|
||||
|
||||
var event = TransactionCreated.builder()
|
||||
.aggregateId(aggregateId)
|
||||
.correlationId(correlationId)
|
||||
.amount(BigDecimal.TEN)
|
||||
.fromAccountId(fromAccountId)
|
||||
.toAccountId(toAccountId)
|
||||
.build();
|
||||
|
||||
var aggregate = new TransactionAggregate(aggregateId);
|
||||
aggregate.applyTransactionCreated(event);
|
||||
|
||||
var result = aggregate.validateFinishTransaction(FinishTransaction.builder()
|
||||
.toAccountId(toAccountId)
|
||||
.fromAccountId(fromAccountId)
|
||||
.correlationId(correlationId)
|
||||
.aggregateId(aggregateId)
|
||||
.build());
|
||||
|
||||
assertTrue(result instanceof TransactionFinished);
|
||||
assertEquals(result.correlationId().get(), correlationId);
|
||||
assertEquals(result.aggregateId(), aggregateId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateFinishTransaction_FAILED() {
|
||||
var aggregateId = UUID.randomUUID().toString();
|
||||
var correlationId = UUID.randomUUID().toString();
|
||||
var toAccountId = UUID.randomUUID().toString();
|
||||
var fromAccountId = UUID.randomUUID().toString();
|
||||
|
||||
var aggregate = new TransactionAggregate(aggregateId);
|
||||
|
||||
assertThrows(RuntimeException.class, () -> aggregate.validateFinishTransaction(FinishTransaction.builder()
|
||||
.toAccountId(toAccountId)
|
||||
.fromAccountId(fromAccountId)
|
||||
.correlationId(correlationId)
|
||||
.aggregateId(aggregateId)
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.mz.reactor.ddd.reactorddd.transaction.domain.command;
|
||||
|
||||
import com.mz.reactor.ddd.common.api.command.CommandResult;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.TransactionAggregate;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.event.TransactionCreated;
|
||||
import com.mz.reactor.ddd.reactorddd.transaction.domain.event.TransactionFailed;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TransactionCommandHandlerTest {
|
||||
|
||||
TransactionCommandHandler subject = new TransactionCommandHandler();
|
||||
|
||||
@Test
|
||||
void execute_CreateTransaction_OK() {
|
||||
var aggregateId = UUID.randomUUID().toString();
|
||||
var correlationId = UUID.randomUUID().toString();
|
||||
var toAccountId = UUID.randomUUID().toString();
|
||||
var fromAccountId = UUID.randomUUID().toString();
|
||||
var command = CreateTransaction.builder()
|
||||
.aggregateId(aggregateId)
|
||||
.amount(BigDecimal.TEN)
|
||||
.correlationId(correlationId)
|
||||
.fromAccountId(fromAccountId)
|
||||
.toAccountId(toAccountId)
|
||||
.build();
|
||||
var aggregate = new TransactionAggregate(aggregateId);
|
||||
|
||||
var result = subject.execute(aggregate, command);
|
||||
assertEquals(result.statusCode(), CommandResult.StatusCode.OK);
|
||||
assertTrue(result.events().stream().allMatch(e -> e instanceof TransactionCreated));
|
||||
}
|
||||
|
||||
@Test
|
||||
void execute_CreateTransaction_FAILED() {
|
||||
var aggregateId = UUID.randomUUID().toString();
|
||||
var correlationId = UUID.randomUUID().toString();
|
||||
var toAccountId = UUID.randomUUID().toString();
|
||||
var fromAccountId = UUID.randomUUID().toString();
|
||||
var command = CreateTransaction.builder()
|
||||
.aggregateId(aggregateId)
|
||||
.amount(BigDecimal.ZERO)
|
||||
.correlationId(correlationId)
|
||||
.fromAccountId(fromAccountId)
|
||||
.toAccountId(toAccountId)
|
||||
.build();
|
||||
var aggregate = new TransactionAggregate(aggregateId);
|
||||
|
||||
var result = subject.execute(aggregate, command);
|
||||
assertEquals(result.statusCode(), CommandResult.StatusCode.FAILED);
|
||||
assertTrue(result.events().stream().allMatch(e -> e instanceof TransactionFailed));
|
||||
}
|
||||
}
|
||||
11
build.gradle
11
build.gradle
@@ -36,11 +36,15 @@ allprojects {
|
||||
dependencyManagement {
|
||||
imports { mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}") }
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform{
|
||||
includeEngines 'junit-jupiter'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
// apply plugin: 'java'
|
||||
// apply plugin: 'java-library'
|
||||
|
||||
group = 'com.mz.reactor.ddd'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
@@ -48,6 +52,8 @@ subprojects {
|
||||
|
||||
dependencies {
|
||||
annotationProcessor 'org.immutables:value:2.7.5'
|
||||
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.2'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,5 +95,6 @@ project(':bank-account:transaction-domain') {
|
||||
project(':shared-dependencies') {
|
||||
dependencies {
|
||||
api 'org.immutables:value:2.7.5'
|
||||
api group: 'org.apache.commons', name: 'commons-lang3', version: '3.9'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,48 @@
|
||||
package com.mz.reactor.ddd.common.api.command;
|
||||
|
||||
import com.mz.reactor.ddd.common.api.event.DomainEvent;
|
||||
import org.immutables.value.Value;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Value.Immutable
|
||||
public interface CommandResult {
|
||||
|
||||
enum StatusCode {
|
||||
OK,
|
||||
BAD_COMMAND,
|
||||
FAILED,
|
||||
NOT_MODIFIED;
|
||||
}
|
||||
|
||||
StatusCode statusCode();
|
||||
|
||||
List<DomainEvent> events();
|
||||
|
||||
Optional<RuntimeException> error();
|
||||
|
||||
static ImmutableCommandResult.Builder builder() {
|
||||
return ImmutableCommandResult.builder();
|
||||
}
|
||||
|
||||
static CommandResult fromError(RuntimeException error, DomainEvent event) {
|
||||
return builder()
|
||||
.statusCode(StatusCode.BAD_COMMAND)
|
||||
.events(List.of(event))
|
||||
.error(error)
|
||||
.build();
|
||||
}
|
||||
|
||||
static CommandResult badCommand() {
|
||||
return builder()
|
||||
.statusCode(StatusCode.BAD_COMMAND)
|
||||
.build();
|
||||
}
|
||||
|
||||
static CommandResult notModified() {
|
||||
return builder()
|
||||
.statusCode(StatusCode.NOT_MODIFIED)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
package com.mz.reactor.ddd.common.api.valueobject;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class StringValue {
|
||||
private final String value;
|
||||
|
||||
public StringValue(String value) {
|
||||
this.value = Optional.ofNullable(value)
|
||||
.filter(v -> !v.isBlank())
|
||||
.orElseThrow(() -> new RuntimeException("Value can't be null or empty"));
|
||||
this.value = validateValue.apply(value);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Function<String, String> validateValue = value ->
|
||||
Optional.ofNullable(value)
|
||||
.filter(v -> !v.isBlank())
|
||||
.orElseThrow(() -> new RuntimeException("Value can't be null or empty"));
|
||||
|
||||
public static void validate(String... values) {
|
||||
Stream.of(values)
|
||||
.map(validateValue);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user