This repository has been archived by the owner on Jul 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from ralf-ueberfuhr-ars/feature/db
Introduce Persistence Layer.
- Loading branch information
Showing
17 changed files
with
572 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
...mer-api-provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomerEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import jakarta.persistence.*; | ||
import jakarta.validation.constraints.NotNull; | ||
import jakarta.validation.constraints.Size; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
import java.time.LocalDate; | ||
import java.util.UUID; | ||
|
||
@Getter | ||
@Setter | ||
@Entity(name = "Customer") | ||
@Table(name = "CUSTOMERS") | ||
public class CustomerEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.UUID) | ||
private UUID uuid; | ||
@Size(min = 3, max = 100) | ||
@NotNull | ||
private String name; | ||
@Column(name = "DATE_OF_BIRTH") | ||
private LocalDate birthdate; | ||
@NotNull | ||
private Customer.CustomerState state = Customer.CustomerState.ACTIVE; | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
...i-provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomerEntityMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import org.mapstruct.Mapper; | ||
import org.mapstruct.MappingTarget; | ||
|
||
@Mapper(componentModel = "cdi") | ||
public interface CustomerEntityMapper { | ||
|
||
CustomerEntity map(Customer source); | ||
|
||
Customer map(CustomerEntity source); | ||
|
||
void copy(CustomerEntity source, @MappingTarget Customer target); | ||
|
||
} |
10 changes: 10 additions & 0 deletions
10
...ovider/src/main/java/de/schulung/sample/quarkus/persistence/CustomerEntityRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
|
||
import java.util.UUID; | ||
|
||
@ApplicationScoped | ||
public class CustomerEntityRepository implements PanacheRepositoryBase<CustomerEntity, UUID> { | ||
} |
208 changes: 208 additions & 0 deletions
208
...-provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomersSinkJdbcImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import de.schulung.sample.quarkus.domain.Customer.CustomerState; | ||
import de.schulung.sample.quarkus.domain.CustomersSink; | ||
import io.quarkus.arc.properties.IfBuildProperty; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.enterprise.inject.Typed; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.*; | ||
import java.time.LocalDate; | ||
import java.util.Collection; | ||
import java.util.LinkedList; | ||
import java.util.Optional; | ||
import java.util.UUID; | ||
import java.util.stream.Stream; | ||
|
||
@ApplicationScoped | ||
@Typed(CustomersSink.class) | ||
@RequiredArgsConstructor | ||
@IfBuildProperty( | ||
name = "persistence.sink.implementation", | ||
stringValue = "jdbc" | ||
) | ||
public class CustomersSinkJdbcImpl implements CustomersSink { | ||
|
||
private final DataSource ds; | ||
|
||
/* ******************************************************* * | ||
* Converter methods - could be converter objects instead * | ||
* ******************************************************* */ | ||
|
||
private static UUID convertUuid(String uuid) { | ||
return Optional.ofNullable(uuid) | ||
.map(UUID::fromString) | ||
.orElse(null); | ||
} | ||
|
||
private static String convertUuid(UUID uuid) { | ||
return Optional.ofNullable(uuid) | ||
.map(UUID::toString) | ||
.orElse(null); | ||
} | ||
|
||
private static LocalDate convertDate(Date date) { | ||
return Optional.ofNullable(date) | ||
.map(Date::toLocalDate) | ||
.orElse(null); | ||
} | ||
|
||
private static Date convertDate(LocalDate date) { | ||
return Optional.ofNullable(date) | ||
.map(Date::valueOf) | ||
.orElse(null); | ||
} | ||
|
||
private static CustomerState convertState(int value) { | ||
return CustomerState.values()[value]; | ||
} | ||
|
||
private static int convertState(CustomerState value) { | ||
return Optional.ofNullable(value) | ||
.map(CustomerState::ordinal) | ||
.orElse(0); | ||
|
||
} | ||
|
||
/* ******************************************************* * | ||
* Row Mapping - could be a RowMapper object instead * | ||
* ******************************************************* */ | ||
|
||
private static Customer readSingle(ResultSet rs) throws SQLException { | ||
return Customer.builder() | ||
.uuid(convertUuid(rs.getString("UUID"))) | ||
.birthdate(convertDate(rs.getDate("DATE_OF_BIRTH"))) | ||
.name(rs.getString("NAME")) | ||
.state(convertState(rs.getInt("STATE"))) | ||
.build(); | ||
} | ||
|
||
private static Stream<Customer> readAll(ResultSet rs) throws SQLException { | ||
Collection<Customer> result = new LinkedList<>(); | ||
while (rs.next()) { | ||
result.add(readSingle(rs)); | ||
} | ||
return result.stream(); | ||
} | ||
|
||
/* ******************************************************* * | ||
* CustomersSink implementation * | ||
* ******************************************************* */ | ||
|
||
@Override | ||
public Stream<Customer> findAll() { | ||
try (Connection con = ds.getConnection(); | ||
Statement stmt = con.createStatement(); | ||
ResultSet rs = stmt.executeQuery( | ||
"select * from CUSTOMERS" | ||
)) { | ||
|
||
return readAll(rs); | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public Stream<Customer> findByState(CustomerState state) { | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"select * from CUSTOMERS where STATE=?" | ||
)) { | ||
|
||
stmt.setInt(1, convertState(state)); | ||
|
||
try (ResultSet rs = stmt.executeQuery()) { | ||
return readAll(rs); | ||
} | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public Optional<Customer> findByUuid(UUID uuid) { | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"select * from CUSTOMERS where UUID=?" | ||
)) { | ||
|
||
stmt.setString(1, convertUuid(uuid)); | ||
|
||
try (ResultSet rs = stmt.executeQuery()) { | ||
if (!rs.next()) { | ||
return Optional.empty(); | ||
} | ||
return Optional.of(readSingle(rs)); | ||
} | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public void save(Customer customer) { | ||
// TODO only insert, we need an update too, if the UUID is already set | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"insert into CUSTOMERS(UUID,NAME,DATE_OF_BIRTH,STATE) values(?,?,?,?)", | ||
Statement.RETURN_GENERATED_KEYS | ||
)) { | ||
|
||
stmt.setString(1, convertUuid(customer.getUuid())); | ||
stmt.setString(2, customer.getName()); | ||
stmt.setDate(3, convertDate(customer.getBirthdate())); | ||
stmt.setInt(4, convertState(customer.getState())); | ||
stmt.executeUpdate(); | ||
|
||
try (ResultSet rs = stmt.getGeneratedKeys()) { | ||
if (!rs.next()) { | ||
throw new RuntimeException("not expected"); // bessere Exception | ||
} | ||
customer.setUuid(convertUuid(rs.getString(1))); | ||
} | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public boolean delete(UUID uuid) { | ||
try (Connection con = ds.getConnection(); | ||
PreparedStatement stmt = con.prepareStatement( | ||
"delete from CUSTOMERS where UUID=?" | ||
)) { | ||
|
||
stmt.setString(1, convertUuid(uuid)); | ||
return stmt.executeUpdate() > 0; | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
|
||
@Override | ||
public long count() { | ||
try (Connection con = ds.getConnection(); | ||
Statement stmt = con.createStatement(); | ||
ResultSet rs = stmt.executeQuery( | ||
"select count(uuid) from CUSTOMERS" | ||
)) { | ||
|
||
if (!rs.next()) { | ||
return 0; | ||
} | ||
return rs.getLong(1); | ||
|
||
} catch (SQLException e) { | ||
throw new RuntimeException(e); // eigene Exception? | ||
} | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
...i-provider/src/main/java/de/schulung/sample/quarkus/persistence/CustomersSinkJpaImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package de.schulung.sample.quarkus.persistence; | ||
|
||
import de.schulung.sample.quarkus.domain.Customer; | ||
import de.schulung.sample.quarkus.domain.CustomersSink; | ||
import io.quarkus.arc.properties.IfBuildProperty; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.enterprise.inject.Typed; | ||
import jakarta.persistence.EntityManager; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import java.util.Optional; | ||
import java.util.UUID; | ||
import java.util.stream.Stream; | ||
|
||
@ApplicationScoped | ||
@Typed(CustomersSink.class) | ||
@RequiredArgsConstructor | ||
@IfBuildProperty( | ||
name = "persistence.sink.implementation", | ||
stringValue = "jpa" | ||
) | ||
public class CustomersSinkJpaImpl implements CustomersSink { | ||
|
||
private final CustomerEntityMapper mapper; | ||
private final EntityManager em; | ||
|
||
@Override | ||
public Stream<Customer> findAll() { | ||
return em.createQuery( | ||
"select c from Customer c", | ||
CustomerEntity.class | ||
) | ||
.getResultList() | ||
.stream() | ||
.map(mapper::map); | ||
} | ||
|
||
@Override | ||
public Stream<Customer> findByState(Customer.CustomerState state) { | ||
return em.createQuery( | ||
"select c from Customer c where c.state = :state", | ||
CustomerEntity.class | ||
) | ||
.setParameter("state", state) | ||
.getResultList() | ||
.stream() | ||
.map(mapper::map); | ||
} | ||
|
||
@Override | ||
public Optional<Customer> findByUuid(UUID uuid) { | ||
return Optional | ||
.ofNullable(em.find(CustomerEntity.class, uuid)) | ||
.map(mapper::map); | ||
} | ||
|
||
@Override | ||
public void save(Customer customer) { | ||
var entity = this.mapper.map(customer); | ||
em.persist(entity); | ||
//customer.setUuid(entity.getUuid()); | ||
mapper.copy(entity, customer); | ||
} | ||
|
||
@Override | ||
public boolean delete(UUID uuid) { | ||
var found = em.find(CustomerEntity.class, uuid); | ||
if(found == null) { | ||
return false; | ||
} | ||
em.remove(found); | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean exists(UUID uuid) { | ||
var found = em.find(CustomerEntity.class, uuid); | ||
return found != null; | ||
} | ||
|
||
@Override | ||
public long count() { | ||
return 0; // TODO ?? | ||
} | ||
} |
Oops, something went wrong.