diff --git a/opp/core/pom.xml b/opp/core/pom.xml index a573bc80b75482c62550aff5fb8d734f1fb7a459..810dbca301dc645a127ff9fc953074d03d8f7393 100644 --- a/opp/core/pom.xml +++ b/opp/core/pom.xml @@ -32,6 +32,12 @@ <artifactId>jackson-core</artifactId> <version>2.13.0</version> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> </dependencies> </project> \ No newline at end of file diff --git a/opp/core/src/main/java/Operation.java b/opp/core/src/main/java/Operation.java new file mode 100644 index 0000000000000000000000000000000000000000..ffe0b18e6dc4b565cf194786426f4b00519fd00d --- /dev/null +++ b/opp/core/src/main/java/Operation.java @@ -0,0 +1,49 @@ +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.Optional; + +/** + * Operation class with its attributes, filters and commands. + * @param id unique id of the operation + * @param date the planned date of the operation + * @param startTime the planned starting time of the operation + * @param endTime the planned ending time of the operation + */ +public record Operation( + Id<Operation> id, + LocalDate date, + LocalTime startTime, + LocalTime endTime +) { + + /** + * Operation filter + * @param date filter with date + */ + public static final record Filter( + Optional<LocalDate> date + ) { + public static final Filter NONE = + new Filter( + Optional.empty() + ); + } + + /** + * Operation commands + */ + public static sealed interface Command permits Create { } + + /** + * Create command to create a new Operation + * @param date the date of the new Operation + * @param startTime the starting time of the new Operation + * @param endTime the ending time of the new Operation + */ + public static record Create( + LocalDate date, + LocalTime startTime, + LocalTime endTime + ) implements Command {} + +} diff --git a/opp/core/src/main/java/OperationService.java b/opp/core/src/main/java/OperationService.java new file mode 100644 index 0000000000000000000000000000000000000000..a3cb26389370b4161d380c674f31edffe2caaccb --- /dev/null +++ b/opp/core/src/main/java/OperationService.java @@ -0,0 +1,29 @@ +import java.util.List; +import java.util.Optional; + +/** + * Available Services for Operations + */ +public interface OperationService { + + /** + * Processes the possible commands for an Operation + * @param cmd the command to process + * @return the processed Operation + */ + public Operation process(Operation.Command cmd) throws Exception; + + /** + * Gets the Operation by ID + * @param id the ID of the Operation + * @return the Operation + */ + public Optional<Operation> getOperation(Id<Operation> id); + + /** + * Gets a list of Operations that are matching the filter + * @param filter the filter to match + * @return the matching Operations + */ + public List<Operation> getOperations(Operation.Filter filter); +} diff --git a/opp/core/src/main/java/Person.java b/opp/core/src/main/java/Person.java deleted file mode 100644 index 4f90e7b36c1d640d8ba30540a709b72458f0674d..0000000000000000000000000000000000000000 --- a/opp/core/src/main/java/Person.java +++ /dev/null @@ -1,26 +0,0 @@ -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.time.LocalDate; - -public record Person ( - @JsonProperty - Id<Person> id, - - @JsonProperty - Gender gender, - - @JsonProperty - String givenName, - - @JsonProperty - String familyName, - - @JsonProperty - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") - LocalDate birthDate, - - @JsonProperty - Address address -) { -} diff --git a/opp/core/src/main/java/Repository.java b/opp/core/src/main/java/Repository.java index 145bef94ca2a5ce7ac2be9256e9ac8fc9a4b88c8..b47dd815f98213039e560da3af7b40d0510529ee 100644 --- a/opp/core/src/main/java/Repository.java +++ b/opp/core/src/main/java/Repository.java @@ -1,7 +1,8 @@ +import java.util.List; import java.util.Optional; public interface Repository { - +/* Id<Patient> patientId(); void createPatient(Patient patient) throws Exception; @@ -9,6 +10,33 @@ public interface Repository { Optional<Patient> findPatient(Id<Patient> id); Optional<Patient> deletePatient(Id<Patient> id) throws Exception; - +*/ // Hier dann die restlichen create/edit Methoden rein + + /** + * Return an unused operation ID. + * @return Operation ID + */ + Id<Operation> operationId(); + + /** + * Saves the Operation into the database. + * @param operation the Operation to save into the database + * @throws Exception while saving + */ + void save(Operation operation) throws Exception; + + /** + * Returns the Operation with the given ID. + * @param id the ID to search for + * @return the found Operation + */ + Optional<Operation> findOperation(Id<Operation> id); + + /** + * Returns a list of all operation entries matching the filter. + * @param filter the filter + * @return the matching entries + */ + List<Operation> findOperations(Operation.Filter filter); } diff --git a/opp/jdbc-repo-impl/src/main/java/JDBCRepository.java b/opp/jdbc-repo-impl/src/main/java/JDBCRepository.java index 81fcc8bd04edf9c6a898574e84e9f4e65d8b32c1..9c96037f0a067a3ce8f084f50b277501f907c67a 100644 --- a/opp/jdbc-repo-impl/src/main/java/JDBCRepository.java +++ b/opp/jdbc-repo-impl/src/main/java/JDBCRepository.java @@ -1,11 +1,16 @@ import java.sql.*; import java.time.Instant; import java.time.LocalDate; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import static java.util.UUID.randomUUID; - +/** + * The implemented Repository Interface for SQL-Databases. + */ class JDBCRepository implements Repository { @@ -16,7 +21,10 @@ class JDBCRepository implements Repository } - // Factory method + /** + * Sets up a connection with the repository database via the set url, user and password. + * @return the connected repository + */ static JDBCRepository instance(){ try { var conn = @@ -34,44 +42,39 @@ class JDBCRepository implements Repository throw new RuntimeException(e); } } - - - private static final String CREATE_PATIENT_TABLE = """ - CREATE TABLE IF NOT EXISTS patients( - id VARCHAR(50) PRIMARY KEY, - gender VARCHAR(10) NOT NULL, - givenName VARCHAR(100) NOT NULL, - familyName VARCHAR(100) NOT NULL, - birthDate DATE NOT NULL, - street VARCHAR(50) NOT NULL, - house VARCHAR(50) NOT NULL, - postalCode VARCHAR(50) NOT NULL, - city VARCHAR(50) NOT NULL, - healthInsurance VARCHAR(40) NOT NULL - ); - """; - - // Set up DB tables etc. + /** + * Sets up the database tables. + */ void setup(){ try (var stmt = conn.createStatement()){ - stmt.execute(CREATE_PATIENT_TABLE); + stmt.execute(CREATE_OPERATION_TABLE); } catch (SQLException e){ throw new RuntimeException(e); } } - + /** + * Sets quotes around the given string. + * @param s the string + * @return the quoted string + */ private static String quoted(String s){ return String.format("'%s'",s); } + /** + * Turns a given object into a SQL-value. + * @param obj the object + * @return the SQL-value of the object + */ private static String sqlValue(Object obj){ return switch(obj){ case LocalDate date -> quoted(Date.valueOf(date).toString()); + case LocalTime time -> quoted(Time.valueOf(time).toString()); case Instant t -> quoted(Timestamp.from(t).toString()); case Integer n -> Integer.toString(n); case Long n -> Long.toString(n); @@ -81,6 +84,21 @@ class JDBCRepository implements Repository } + /* + private static final String CREATE_PATIENT_TABLE = """ + CREATE TABLE IF NOT EXISTS patients( + id VARCHAR(50) PRIMARY KEY, + gender VARCHAR(10) NOT NULL, + givenName VARCHAR(100) NOT NULL, + familyName VARCHAR(100) NOT NULL, + birthDate DATE NOT NULL, + street VARCHAR(50) NOT NULL, + house VARCHAR(50) NOT NULL, + postalCode VARCHAR(50) NOT NULL, + city VARCHAR(50) NOT NULL, + healthInsurance VARCHAR(40) NOT NULL + ); + """; private static Patient readPatientFromRow(ResultSet rs) throws SQLException { return new Patient( @@ -134,8 +152,6 @@ class JDBCRepository implements Repository "WHERE id = " + sqlValue(patient.id().value()) + ";"; } - - @Override public Id<Patient> patientId(){ @@ -144,7 +160,6 @@ class JDBCRepository implements Repository return findPatient(id).isEmpty() ? id : patientId(); } - @Override public void createPatient(Patient patient) throws SQLException { @@ -164,7 +179,6 @@ class JDBCRepository implements Repository } - @Override public Optional<Patient> findPatient(Id<Patient> id){ try ( @@ -182,7 +196,6 @@ class JDBCRepository implements Repository } } - @Override public Optional<Patient> deletePatient(Id<Patient> id) throws SQLException { @@ -201,6 +214,154 @@ class JDBCRepository implements Repository return patient; } + */ + + // Hier dann die restlichen create/edit Methoden rein + + /** + * The structure of the operations table. + */ + private static final String CREATE_OPERATION_TABLE = """ + CREATE TABLE IF NOT EXISTS operations( + id VARCHAR(50) PRIMARY KEY, + date DATE NOT NULL, + startTime TIME NOT NULL, + endTime TIME NOT NULL + ); + """; + /** + * Creates the insert statement of the given operation for SQL. + * @param operation the operation to turn into an insert SQL statement + * @return the SQL statement + */ + private static String insertSQL(Operation operation){ + return + "INSERT INTO operations(" + + "id,date,startTime,endTime" + + ") VALUES (" + + sqlValue(operation.id().value()) + "," + + sqlValue(operation.date()) + "," + + sqlValue(operation.startTime()) + "," + + sqlValue(operation.endTime()) + + ");"; + } + + /** + * Creates the update statement of the given operation for SQL. + * @param operation the operation to turn into an update SQL statement + * @return the SQL statement + */ + private static String updateSQL(Operation operation){ + return + "UPDATE operations SET " + + "date = " + sqlValue(operation.date()) + "," + + "startTime = " + sqlValue(operation.startTime()) + "," + + "endTime = " + sqlValue(operation.endTime()) + " " + + "WHERE id = " + sqlValue(operation.id().value()) + ";"; + } + /** + * Returns a new generated ID in the operations-SQLTable + * If the generated ID is already used, generate another one. + * @return Operation ID + */ + @Override + public Id<Operation> operationId() { + + var id = new Id<Operation>(randomUUID().toString()); + + return findOperation(id).isEmpty() ? id : operationId(); + } + + /** + * Connects to the database and checks if the ID of the given Operation is already used. + * If yes, then update existing entry, else insert new entry. + * @param operation the Operation to save into the database + */ + @Override + public void save(Operation operation) { + + try ( + var stmt = conn.createStatement() + ){ + var sql = + findOperation(operation.id()).isPresent() ? + updateSQL(operation) : + insertSQL(operation); + + stmt.executeUpdate(sql); + + } catch (SQLException e){ + throw new RuntimeException(e); + } + + } + + /** + * Reads an Operation from the Operations-SQLTable with the given ID. + * If no Operation with this ID is found, it will return an empty Optional. + * @param id the ID to search for + * @return the found Operation + */ + @Override + public Optional<Operation> findOperation(Id<Operation> id){ + try ( + var result = + conn.createStatement() + .executeQuery("SELECT * FROM operations WHERE id = " + sqlValue(id.value()) + ";") + ){ + return + result.next() ? + Optional.of(readOperationFromRow(result)) : + Optional.empty(); + + } catch (SQLException e){ + throw new RuntimeException(e); + } + } + + /** + * Connects to the database and searches all filter criteria. + * Adds each found Operation to the list. + * @param filter the filter + * @return the matching entries + */ + @Override + public List<Operation> findOperations(Operation.Filter filter) { + + var sql = "SELECT * FROM operations WHERE date = " + filter.date() + ";"; + + try ( + var resultSet = + conn.createStatement().executeQuery(sql) + ){ + + var operations = new ArrayList<Operation>(); + + while(resultSet.next()){ + operations.add(readOperationFromRow(resultSet)); + } + + return operations; + + } catch (SQLException e){ + throw new RuntimeException(e); + } + } + + /** + * Creates an Operation object with the given result of a read SQL-Row. + * @param rs the result of a read SQL-Row + * @return the created operation object + * @throws SQLException Error while reading the SQL-Row + */ + private static Operation readOperationFromRow(ResultSet rs) throws SQLException { + return new Operation( + new Id<>(rs.getString("id")), + rs.getDate("date").toLocalDate(), + rs.getTime("startTime").toLocalTime(), + rs.getTime("endTime").toLocalTime() + ); + } } diff --git a/opp/jdbc-repo-impl/src/main/java/OperationServiceImpl.java b/opp/jdbc-repo-impl/src/main/java/OperationServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a47b50255247c997dad5472da0a75d7d3f26ac45 --- /dev/null +++ b/opp/jdbc-repo-impl/src/main/java/OperationServiceImpl.java @@ -0,0 +1,45 @@ +import java.util.List; +import java.util.Optional; + +/** + * The implemented Services of the Operations + */ +public class OperationServiceImpl implements OperationService { + + private final Repository repo; + + public OperationServiceImpl(Repository repo) { + this.repo = repo; + } + + + @Override + public Operation process(Operation.Command cmd) throws Exception { + return switch (cmd){ + case Operation.Create cr -> create(cr); + }; + } + + @Override + public Optional<Operation> getOperation(Id<Operation> id) { + return repo.findOperation(id); + } + + @Override + public List<Operation> getOperations(Operation.Filter filter) { + return repo.findOperations(filter); + } + + public Operation create(Operation.Create cr) throws Exception { + Operation operation = + new Operation( + repo.operationId(), + cr.date(), + cr.startTime(), + cr.endTime()); + + repo.save(operation); + + return operation; + } +} diff --git a/opp/jdbc-repo-impl/src/test/java/Tests.java b/opp/jdbc-repo-impl/src/test/java/Tests.java index 9c089048e5423e883adb3d061971dcfaaa2aa1af..3229c14d5fc3e5f2c1de68c8f8d665ce59c5d803 100644 --- a/opp/jdbc-repo-impl/src/test/java/Tests.java +++ b/opp/jdbc-repo-impl/src/test/java/Tests.java @@ -2,6 +2,9 @@ import org.junit.BeforeClass; import org.junit.Test; import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; +import java.util.Optional; import static org.junit.Assert.*; import static org.junit.Assert.assertTrue; @@ -12,7 +15,11 @@ public final class Tests private static Repository repo = null; - private static Patient testPatient = null; + private static OperationService opService; + + //private static Patient testPatient = null; + + private static Operation testOperation = null; @BeforeClass public static void init() throws Exception { @@ -23,6 +30,7 @@ public final class Tests repo = JDBCRepository.instance(); + /* testPatient = new Patient( new Id<>("1111"), Gender.MALE, @@ -31,8 +39,18 @@ public final class Tests LocalDate.of(1999, 01, 01), new Address("Musterstraße", "12", "12345", "Beispielhausen"), "AOK"); + */ + + testOperation = new Operation( + new Id<>("1111"), + LocalDate.of(2024, 05, 24), + LocalTime.of(13, 35, 00), + LocalTime.of(14, 00, 00)); + + opService = new OperationServiceImpl(repo); } + /* @Test public void testPatientSave(){ @@ -61,4 +79,31 @@ public final class Tests repo.findPatient(testPatient.id()).isEmpty() ); } + */ + + @Test + public void testOperationSave(){ + + try { + repo.save(testOperation); + } catch (Exception e){ + e.printStackTrace(); + } + + assertTrue( + repo.findOperation(testOperation.id()).isPresent() + ); + } + + @Test + public void testCreateOperation() throws Exception { + Operation.Command createCommand = new Operation.Create( + LocalDate.of(2025, 05, 11), + LocalTime.of(10, 30, 00), + LocalTime.of(11, 00, 00)); + + Operation operation = opService.process(createCommand); + + System.out.println(operation); + } }