Skip to content

Commit

Permalink
Add transaction-API classic scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
pablo gonzalez granados committed Jan 27, 2023
1 parent b8a56a0 commit 509d491
Show file tree
Hide file tree
Showing 36 changed files with 1,208 additions and 0 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,13 @@ Base application is reduced to two REST resources:
Tests cover the supported functionality of `rest-data-panache`: CRUD operations, `json` and `hal+json` data types,
invalid input, filtering, sorting, pagination.

### `sql-db/narayana-transactions`

Verifies Quarkus transaction programmatic API.
Base application contains REST resource `TransferResource` and three main services: `TransferTransactionService`, `TransferWithdrawalService`
and `TransferTopUpService` which implement various bank transactions. The main scenario is implemented in `TransactionGeneralUsageIT`
and checks whether transactions and rollbacks always done in full.

### `security/basic`

Verifies the simplest way of doing authn/authz.
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@
<module>sql-db/hibernate-reactive</module>
<module>sql-db/reactive-vanilla</module>
<module>sql-db/hibernate-fulltext-search</module>
<module>sql-db/narayana-transactions</module>
</modules>
</profile>
<profile>
Expand Down
108 changes: 108 additions & 0 deletions sql-db/narayana-transactions/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.quarkus.ts.qe</groupId>
<artifactId>parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../..</relativePath>
</parent>
<artifactId>narayana-transactions</artifactId>
<packaging>jar</packaging>
<name>Quarkus QE TS: SQL Database: Narayana-transactions</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mariadb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mssql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mysql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-oracle</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
</dependency>
<!-- Swagger documentation -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<!-- Tracing extensions -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
<!-- Metrics extensions -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
<!-- test extensions -->
<dependency>
<groupId>io.quarkus.qe</groupId>
<artifactId>quarkus-test-service-database</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus.qe</groupId>
<artifactId>quarkus-test-service-jaeger</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
</profile>
<!-- Skipped on Windows as does not support Linux Containers / Testcontainers -->
<profile>
<id>skip-tests-on-windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package io.quarkus.ts.transactions;

import java.sql.Timestamp;
import java.util.List;
import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.Entity;

import io.quarkus.hibernate.orm.panache.PanacheEntity;
import io.quarkus.panache.common.Parameters;
import io.quarkus.panache.common.Sort;

@Entity(name = "account")
public class AccountEntity extends PanacheEntity {
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String lastName;
@Column(unique = true, nullable = false)
private String accountNumber;
@Column(precision = 10, scale = 2, nullable = false)
private int amount;
private Timestamp updatedAt;
@Column(nullable = false)
private Timestamp createdAt;

public static boolean exist(String accountNumber) {
return Objects.nonNull(findAccount(accountNumber));
}

public static AccountEntity findAccount(String accountNumber) {
return find("accountNumber", accountNumber).firstResult();
}

public static int updateAmount(String accountNumber, int amount) {
Timestamp currentTime = new Timestamp(System.currentTimeMillis());
int updatedRecordsAmount = update("amount = :amount, updatedAt = :updatedAt where accountNumber = :account",
Parameters.with("amount", amount)
.and("updatedAt", currentTime)
.and("account", accountNumber));
flush();
return updatedRecordsAmount;
}

public static List<AccountEntity> getAllAccountsRecords() {
return findAll(Sort.by("createdAt").descending()).list();
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public int getAmount() {
return amount;
}

public void setAmount(int amount) {
this.amount = amount;
}

public Timestamp getUpdatedAt() {
return updatedAt;
}

public void setUpdatedAt(Timestamp updatedAt) {
this.updatedAt = updatedAt;
}

public Timestamp getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Timestamp createdAt) {
this.createdAt = createdAt;
}

public String getAccountNumber() {
return accountNumber;
}

public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.quarkus.ts.transactions;

import static io.quarkus.ts.transactions.AccountEntity.exist;

import java.util.List;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException;

import org.jboss.logging.Logger;

@ApplicationScoped
public class AccountService {

private static final Logger LOG = Logger.getLogger(AccountService.class);

public boolean isPresent(String accountNumber) {
if (!exist(accountNumber)) {
String msg = String.format("Account %s doesn't exist", accountNumber);
LOG.warn(msg);
throw new NotFoundException(msg);
}

return true;
}

public int increaseBalance(String account, int amount) {
AccountEntity accountEntity = AccountEntity.findAccount(account);
int updatedAmount = accountEntity.getAmount() + amount;
AccountEntity.updateAmount(account, updatedAmount);
return AccountEntity.findAccount(account).getAmount();
}

public int decreaseBalance(String account, int amount) {
AccountEntity accountEntity = AccountEntity.findAccount(account);
int updatedAmount = accountEntity.getAmount() - amount;
if (updatedAmount < 0) {
String msg = String.format("Account %s Not enough balance.", account);
LOG.warn(msg);
throw new BadRequestException(msg);
}
AccountEntity.updateAmount(account, updatedAmount);
return updatedAmount;
}

public List<AccountEntity> getAllAccounts() {
return AccountEntity.getAllAccountsRecords();
}

public AccountEntity getAccount(String accountNumber) {
return AccountEntity.findAccount(accountNumber);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.quarkus.ts.transactions;

import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;

import io.quarkus.hibernate.orm.panache.PanacheEntity;
import io.quarkus.panache.common.Parameters;
import io.quarkus.panache.common.Sort;

@Entity(name = "journal")
public class JournalEntity extends PanacheEntity {

@Column(nullable = false)
private String annotation;
@Column(nullable = false)
private String accountTo;
@Column(nullable = false)
private String accountFrom;
@Column(nullable = false)
private int amount;
@Column(nullable = false)
private Timestamp createdAt;

public JournalEntity() {
}

public JournalEntity(String accountFrom, String accountTo, String annotation, int amount) {
this.accountFrom = accountFrom;
this.accountTo = accountTo;
this.annotation = annotation;
this.amount = amount;
this.createdAt = new Timestamp(System.currentTimeMillis());
}

public JournalEntity addLog() {
persistAndFlush();
return this;
}

public static JournalEntity getLatestJournalRecord(String accountNumber) {
return find("accountFrom = :accountFrom",
Sort.by("createdAt").descending(),
Parameters.with("accountFrom", accountNumber))
.firstResult();
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getAnnotation() {
return annotation;
}

public void setAnnotation(String annotation) {
this.annotation = annotation;
}

public String getAccountTo() {
return accountTo;
}

public void setAccountTo(String accountTo) {
this.accountTo = accountTo;
}

public String getAccountFrom() {
return accountFrom;
}

public void setAccountFrom(String accountFrom) {
this.accountFrom = accountFrom;
}

public int getAmount() {
return amount;
}

public void setAmount(int amount) {
this.amount = amount;
}

public Timestamp getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Timestamp createdAt) {
this.createdAt = createdAt;
}
}
Loading

0 comments on commit 509d491

Please sign in to comment.