Merge commit 'b16039ee5377311aa60f9c71b0a7c1559836b61e' into wip-customer

* commit 'b16039ee5377311aa60f9c71b0a7c1559836b61e':
  - added title and description fields to accountInfo - added GET /accounts?customerId=XXX endpoint - refactored tests
This commit is contained in:
Andrew Revinsky (DART)
2016-03-16 00:29:47 +03:00
21 changed files with 120 additions and 46 deletions

View File

@@ -16,7 +16,7 @@ public class Account extends ReflectiveMutableCommandProcessingAggregate<Account
private BigDecimal balance; private BigDecimal balance;
public List<Event> process(OpenAccountCommand cmd) { public List<Event> process(OpenAccountCommand cmd) {
return EventUtil.events(new AccountOpenedEvent(cmd.getCustomerId(), cmd.getTitle(), cmd.getInitialBalance())); return EventUtil.events(new AccountOpenedEvent(cmd.getCustomerId(), cmd.getTitle(), cmd.getInitialBalance(), cmd.getDescription()));
} }
public List<Event> process(DebitAccountCommand cmd) { public List<Event> process(DebitAccountCommand cmd) {

View File

@@ -14,8 +14,8 @@ public class AccountService {
this.accountRepository = accountRepository; this.accountRepository = accountRepository;
} }
public rx.Observable<EntityWithIdAndVersion<Account>> openAccount(String customerId, String title, BigDecimal initialBalance) { public rx.Observable<EntityWithIdAndVersion<Account>> openAccount(String customerId, String title, BigDecimal initialBalance, String description) {
return accountRepository.save(new OpenAccountCommand(customerId, title, initialBalance)); return accountRepository.save(new OpenAccountCommand(customerId, title, initialBalance, description));
} }
} }

View File

@@ -8,11 +8,13 @@ public class OpenAccountCommand implements AccountCommand {
private String customerId; private String customerId;
private String title; private String title;
private BigDecimal initialBalance; private BigDecimal initialBalance;
private String description;
public OpenAccountCommand(String customerId, String title, BigDecimal initialBalance) { public OpenAccountCommand(String customerId, String title, BigDecimal initialBalance, String description) {
this.customerId = customerId; this.customerId = customerId;
this.title = title; this.title = title;
this.initialBalance = initialBalance; this.initialBalance = initialBalance;
this.description = description;
} }
public BigDecimal getInitialBalance() { public BigDecimal getInitialBalance() {
@@ -26,4 +28,8 @@ public class OpenAccountCommand implements AccountCommand {
public String getTitle() { public String getTitle() {
return title; return title;
} }
public String getDescription() {
return description;
}
} }

View File

@@ -17,7 +17,7 @@ public class AccountTest {
String title = "My Account"; String title = "My Account";
String customerId = "00000000-00000000"; String customerId = "00000000-00000000";
BigDecimal initialBalance = new BigDecimal(512); BigDecimal initialBalance = new BigDecimal(512);
List<Event> events = CommandProcessingAggregates.processToList(account, (AccountCommand)new OpenAccountCommand(customerId, title, initialBalance)); List<Event> events = CommandProcessingAggregates.processToList(account, (AccountCommand)new OpenAccountCommand(customerId, title, initialBalance, ""));
Assert.assertEquals(1, events.size()); Assert.assertEquals(1, events.size());
Assert.assertEquals(AccountOpenedEvent.class, events.get(0).getClass()); Assert.assertEquals(AccountOpenedEvent.class, events.get(0).getClass());

View File

@@ -40,10 +40,10 @@ public class AccountsCommandSideServiceIntegrationTest {
String customerId = "00000000-00000000"; String customerId = "00000000-00000000";
String title = "My Account"; String title = "My Account";
final CreateAccountResponse fromAccount = restTemplate.postForEntity(baseUrl("/accounts"), new CreateAccountRequest(customerId, title, initialFromAccountBalance), CreateAccountResponse.class).getBody(); final CreateAccountResponse fromAccount = restTemplate.postForEntity(baseUrl("/accounts"), new CreateAccountRequest(customerId, title, "", initialFromAccountBalance), CreateAccountResponse.class).getBody();
final String fromAccountId = fromAccount.getAccountId(); final String fromAccountId = fromAccount.getAccountId();
CreateAccountResponse toAccount = restTemplate.postForEntity(baseUrl("/accounts"), new CreateAccountRequest(customerId, title, initialToAccountBalance), CreateAccountResponse.class).getBody(); CreateAccountResponse toAccount = restTemplate.postForEntity(baseUrl("/accounts"), new CreateAccountRequest(customerId, title, "", initialToAccountBalance), CreateAccountResponse.class).getBody();
String toAccountId = toAccount.getAccountId(); String toAccountId = toAccount.getAccountId();
Assert.assertNotNull(fromAccountId); Assert.assertNotNull(fromAccountId);

View File

@@ -22,7 +22,7 @@ public class AccountController {
@RequestMapping(method = RequestMethod.POST) @RequestMapping(method = RequestMethod.POST)
public Observable<CreateAccountResponse> createAccount(@Validated @RequestBody CreateAccountRequest request) { public Observable<CreateAccountResponse> createAccount(@Validated @RequestBody CreateAccountRequest request) {
return accountService.openAccount(request.getCustomerId(), request.getTitle(), request.getInitialBalance()) return accountService.openAccount(request.getCustomerId(), request.getTitle(), request.getInitialBalance(), request.getDescription())
.map(entityAndEventInfo -> new CreateAccountResponse(entityAndEventInfo.getEntityIdentifier().getId())); .map(entityAndEventInfo -> new CreateAccountResponse(entityAndEventInfo.getEntityIdentifier().getId()));
} }
} }

View File

@@ -12,6 +12,8 @@ public class CreateAccountRequest {
private String title; private String title;
private String description;
@NotNull @NotNull
@DecimalMin("0") @DecimalMin("0")
private BigDecimal initialBalance; private BigDecimal initialBalance;
@@ -19,9 +21,10 @@ public class CreateAccountRequest {
public CreateAccountRequest() { public CreateAccountRequest() {
} }
public CreateAccountRequest(String customerId, String title, BigDecimal initialBalance) { public CreateAccountRequest(String customerId, String title, String description, BigDecimal initialBalance) {
this.customerId = customerId; this.customerId = customerId;
this.title = title; this.title = title;
this.description = description;
this.initialBalance = initialBalance; this.initialBalance = initialBalance;
} }
@@ -48,4 +51,12 @@ public class CreateAccountRequest {
public void setTitle(String title) { public void setTitle(String title) {
this.title = title; this.title = title;
} }
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
} }

View File

@@ -10,6 +10,7 @@ public class AccountInfo {
private String id; private String id;
private String customerId; private String customerId;
private String title; private String title;
private String description;
private long balance; private long balance;
private List<AccountChangeInfo> changes; private List<AccountChangeInfo> changes;
private List<AccountTransactionInfo> transactions; private List<AccountTransactionInfo> transactions;
@@ -18,11 +19,12 @@ public class AccountInfo {
private AccountInfo() { private AccountInfo() {
} }
public AccountInfo(String id, String customerId, String title, long balance, List<AccountChangeInfo> changes, List<AccountTransactionInfo> transactions, String version) { public AccountInfo(String id, String customerId, String title, String description, long balance, List<AccountChangeInfo> changes, List<AccountTransactionInfo> transactions, String version) {
this.id = id; this.id = id;
this.customerId = customerId; this.customerId = customerId;
this.title = title; this.title = title;
this.description = description;
this.balance = balance; this.balance = balance;
this.changes = changes; this.changes = changes;
this.transactions = transactions; this.transactions = transactions;
@@ -41,6 +43,10 @@ public class AccountInfo {
return title; return title;
} }
public String getDescription() {
return description;
}
public long getBalance() { public long getBalance() {
return balance; return balance;
} }

View File

@@ -2,5 +2,9 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.ac
import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
interface AccountInfoRepository extends MongoRepository<AccountInfo, String> { interface AccountInfoRepository extends MongoRepository<AccountInfo, String> {
List<AccountInfo> findByCustomerId(String customerId);
} }

View File

@@ -26,12 +26,13 @@ public class AccountInfoUpdateService {
public void create(String accountId, String customerId, String title, BigDecimal initialBalance, String version) { public void create(String accountId, String customerId, String title, BigDecimal initialBalance, String description, String version) {
try { try {
accountInfoRepository.save(new AccountInfo( accountInfoRepository.save(new AccountInfo(
accountId, accountId,
customerId, customerId,
title, title,
description,
toIntegerRepr(initialBalance), toIntegerRepr(initialBalance),
Collections.<AccountChangeInfo>emptyList(), Collections.<AccountChangeInfo>emptyList(),
Collections.<AccountTransactionInfo>emptyList(), Collections.<AccountTransactionInfo>emptyList(),

View File

@@ -3,8 +3,11 @@ package net.chrisrichardson.eventstore.javaexamples.banking.backend.queryside.ac
import net.chrisrichardson.eventstore.Aggregate; import net.chrisrichardson.eventstore.Aggregate;
import net.chrisrichardson.eventstore.EntityIdentifier; import net.chrisrichardson.eventstore.EntityIdentifier;
import net.chrisrichardson.eventstore.EntityNotFoundException; import net.chrisrichardson.eventstore.EntityNotFoundException;
import org.springframework.dao.EmptyResultDataAccessException;
import rx.Observable; import rx.Observable;
import java.util.List;
public class AccountQueryService { public class AccountQueryService {
private AccountInfoRepository accountInfoRepository; private AccountInfoRepository accountInfoRepository;
@@ -20,4 +23,12 @@ public class AccountQueryService {
else else
return Observable.just(account); return Observable.just(account);
} }
public Observable<List<AccountInfo>> findByCustomerId(String customerId) {
List<AccountInfo> result = accountInfoRepository.findByCustomerId(customerId);
if(result.isEmpty())
return Observable.error(new EmptyResultDataAccessException(1));
else
return Observable.just(result);
}
} }

View File

@@ -39,7 +39,8 @@ public class AccountQueryWorkflow implements CompoundEventHandler {
BigDecimal initialBalance = event.getInitialBalance(); BigDecimal initialBalance = event.getInitialBalance();
String customerId = event.getCustomerId(); String customerId = event.getCustomerId();
String title = event.getTitle(); String title = event.getTitle();
accountInfoUpdateService.create(id, customerId, title, initialBalance, eventId); String description = event.getDescription();
accountInfoUpdateService.create(id, customerId, title, initialBalance, description, eventId);
return Observable.just(null); return Observable.just(null);
} }

View File

@@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.*;
import rx.Observable; import rx.Observable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
@RestController @RestController
public class AccountQueryController { public class AccountQueryController {
@@ -23,7 +25,13 @@ public class AccountQueryController {
@RequestMapping(value="/accounts/{accountId}", method = RequestMethod.GET) @RequestMapping(value="/accounts/{accountId}", method = RequestMethod.GET)
public Observable<GetAccountResponse> get(@PathVariable String accountId) { public Observable<GetAccountResponse> get(@PathVariable String accountId) {
return accountInfoQueryService.findByAccountId(new EntityIdentifier(accountId)) return accountInfoQueryService.findByAccountId(new EntityIdentifier(accountId))
.map(accountInfo -> new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()))); .map(accountInfo -> new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription()));
}
@RequestMapping(value = "/accounts", method = RequestMethod.GET)
public Observable<List<GetAccountResponse>> getAccountsForCustomer(@RequestParam("customerId") String customerId) {
return accountInfoQueryService.findByCustomerId(customerId)
.map(accountInfoList -> accountInfoList.stream().map(accountInfo -> new GetAccountResponse(accountInfo.getId(), new BigDecimal(accountInfo.getBalance()), accountInfo.getTitle(), accountInfo.getDescription())).collect(Collectors.toList()));
} }
@ResponseStatus(value= HttpStatus.NOT_FOUND, reason="account not found") @ResponseStatus(value= HttpStatus.NOT_FOUND, reason="account not found")

View File

@@ -4,30 +4,50 @@ import java.math.BigDecimal;
public class GetAccountResponse { public class GetAccountResponse {
private String accountId; private String accountId;
private BigDecimal balance; private BigDecimal balance;
private String title;
private String description;
public GetAccountResponse() { public GetAccountResponse() {
} }
public GetAccountResponse(String accountId, BigDecimal balance) { public GetAccountResponse(String accountId, BigDecimal balance, String title, String description) {
this.accountId = accountId; this.accountId = accountId;
this.balance = balance; this.balance = balance;
} this.title = title;
this.description = description;
}
public void setBalance(BigDecimal balance) { public void setBalance(BigDecimal balance) {
this.balance = balance; this.balance = balance;
} }
public void setAccountId(String accountId) { public void setAccountId(String accountId) {
this.accountId = accountId; this.accountId = accountId;
} }
public String getAccountId() { public String getAccountId() {
return accountId; return accountId;
} }
public BigDecimal getBalance() { public BigDecimal getBalance() {
return balance; return balance;
} }
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
} }

View File

@@ -43,9 +43,9 @@ public class MoneyTransferIntegrationTest {
@Test @Test
public void shouldTransferMoney() { public void shouldTransferMoney() {
final EntityWithIdAndVersion<Account> fromAccount= await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150))); final EntityWithIdAndVersion<Account> fromAccount= await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150), ""));
final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300))); final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300), ""));
final EntityWithIdAndVersion<MoneyTransfer> transaction = await( final EntityWithIdAndVersion<MoneyTransfer> transaction = await(
moneyTransferService.transferMoney(new TransferDetails(fromAccount.getEntityIdentifier(), moneyTransferService.transferMoney(new TransferDetails(fromAccount.getEntityIdentifier(),
@@ -98,9 +98,9 @@ public class MoneyTransferIntegrationTest {
@Test @Test
public void shouldFailDueToInsufficientFunds() { public void shouldFailDueToInsufficientFunds() {
final EntityWithIdAndVersion<Account> fromAccount= await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150))); final EntityWithIdAndVersion<Account> fromAccount= await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150), ""));
final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300))); final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300), ""));
final EntityWithIdAndVersion<MoneyTransfer> transaction = await( final EntityWithIdAndVersion<MoneyTransfer> transaction = await(
moneyTransferService.transferMoney(new TransferDetails(fromAccount.getEntityIdentifier(), moneyTransferService.transferMoney(new TransferDetails(fromAccount.getEntityIdentifier(),

View File

@@ -45,9 +45,9 @@ public class AccountQuerySideIntegrationTest {
@Test @Test
public void shouldUpdateQuerySide() throws Exception { public void shouldUpdateQuerySide() throws Exception {
final EntityWithIdAndVersion<Account> fromAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150))); final EntityWithIdAndVersion<Account> fromAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(150), ""));
final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300))); final EntityWithIdAndVersion<Account> toAccount = await(accountService.openAccount("00000000-00000000", "My Account", new BigDecimal(300), ""));
final EntityWithIdAndVersion<MoneyTransfer> transaction = await( final EntityWithIdAndVersion<MoneyTransfer> transaction = await(
moneyTransferService.transferMoney(new TransferDetails(fromAccount.getEntityIdentifier(), moneyTransferService.transferMoney(new TransferDetails(fromAccount.getEntityIdentifier(),

View File

@@ -10,14 +10,16 @@ public class AccountOpenedEvent implements Event {
private String customerId; private String customerId;
private String title; private String title;
private BigDecimal initialBalance; private BigDecimal initialBalance;
private String description;
private AccountOpenedEvent() { private AccountOpenedEvent() {
} }
public AccountOpenedEvent(String customerId, String title, BigDecimal initialBalance) { public AccountOpenedEvent(String customerId, String title, BigDecimal initialBalance, String description) {
this.customerId = customerId; this.customerId = customerId;
this.title = title; this.title = title;
this.initialBalance = initialBalance; this.initialBalance = initialBalance;
this.description = description;
} }
public String getCustomerId() { public String getCustomerId() {
@@ -31,4 +33,8 @@ public class AccountOpenedEvent implements Event {
public BigDecimal getInitialBalance() { public BigDecimal getInitialBalance() {
return initialBalance; return initialBalance;
} }
public String getDescription() {
return description;
}
} }

View File

@@ -13,7 +13,7 @@ public class AccountOpenEventSerializationTest {
@Test @Test
public void shouldSerde() { public void shouldSerde() {
AccountOpenedEvent event = new AccountOpenedEvent("00000000-00000000", "My Account", new BigDecimal(55)); AccountOpenedEvent event = new AccountOpenedEvent("00000000-00000000", "My Account", new BigDecimal(55), "");
String json = JSonMapper.toJson(event, EventStoreCommonObjectMapping.getObjectMapper()); String json = JSonMapper.toJson(event, EventStoreCommonObjectMapping.getObjectMapper());
System.out.println("json=" + json); System.out.println("json=" + json);

View File

@@ -46,7 +46,7 @@ accountsqueryside:
working_dir: /app working_dir: /app
volumes: volumes:
- ./accounts-query-side-service/build/libs:/app - ./accounts-query-side-service/build/libs:/app
command: java -jar /app/accounts-query-side-service.jar command: java -jar /app/accounts-query-side-service.jar
ports: ports:
- "8081:8080" - "8081:8080"
links: links:

View File

@@ -91,7 +91,7 @@ public class EndToEndTest {
accountsCommandSideBaseUrl("/accounts"), accountsCommandSideBaseUrl("/accounts"),
HttpMethod.POST, HttpMethod.POST,
CreateAccountResponse.class, CreateAccountResponse.class,
new CreateAccountRequest(customerId, "My #1 Account", initialFromAccountBalance) new CreateAccountRequest(customerId, "My #1 Account", "", initialFromAccountBalance)
); );
final String fromAccountId = fromAccount.getAccountId(); final String fromAccountId = fromAccount.getAccountId();
@@ -99,7 +99,7 @@ public class EndToEndTest {
accountsCommandSideBaseUrl("/accounts"), accountsCommandSideBaseUrl("/accounts"),
HttpMethod.POST, HttpMethod.POST,
CreateAccountResponse.class, CreateAccountResponse.class,
new CreateAccountRequest(customerId, "My #2 Account", initialToAccountBalance) new CreateAccountRequest(customerId, "My #2 Account", "", initialToAccountBalance)
); );
String toAccountId = toAccount.getAccountId(); String toAccountId = toAccount.getAccountId();

View File

@@ -67,7 +67,7 @@ public class BankingWebIntegrationTest {
baseUrl("/accounts"), baseUrl("/accounts"),
HttpMethod.POST, HttpMethod.POST,
CreateAccountResponse.class, CreateAccountResponse.class,
new CreateAccountRequest("00000000-00000000", "My 1 Account", initialFromAccountBalance) new CreateAccountRequest("00000000-00000000", "My 1 Account", "", initialFromAccountBalance)
); );
final String fromAccountId = fromAccount.getAccountId(); final String fromAccountId = fromAccount.getAccountId();
@@ -75,7 +75,7 @@ public class BankingWebIntegrationTest {
baseUrl("/accounts"), baseUrl("/accounts"),
HttpMethod.POST, HttpMethod.POST,
CreateAccountResponse.class, CreateAccountResponse.class,
new CreateAccountRequest("00000000-00000000", "My 2 Account", initialToAccountBalance) new CreateAccountRequest("00000000-00000000", "My 2 Account", "", initialToAccountBalance)
); );
String toAccountId = toAccount.getAccountId(); String toAccountId = toAccount.getAccountId();