From d3a2b86fe3c1d350e707dd07cc3864efeb8f884b Mon Sep 17 00:00:00 2001 From: MichalLuzyna Date: Fri, 11 Apr 2025 00:16:20 +0200 Subject: [PATCH 01/22] Adding Appointment end date to enable searching for conflicts --- .../dataaccess/entity/AppointmentEntity.java | 3 ++ src/main/resources/application.properties | 4 +- .../db/migration/1.0/V0001__Create_schema.sql | 5 ++- .../migration/1.0/V0002__Create_mockdata.sql | 40 +++++++++---------- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java index 28e888f..8bb65d7 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java @@ -38,6 +38,9 @@ public class AppointmentEntity extends BaseEntity { @Column(name = "DATE_TIME") private Instant dateTime; + @Column(name = "END_DATE_TIME") + private Instant endsAt; + @Enumerated(EnumType.STRING) private AppointmentStatus status; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b4e3d67..135094d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,7 @@ spring.application.name=appointment-booking-app spring.h2.console.enabled=true -spring.datasource.url=jdbc:h2:mem:appointmentbooking +spring.datasource.url=jdbc:h2:mem:appointmentbooking; spring.datasource.username=sa spring.datasource.password=password @@ -13,3 +13,5 @@ management.endpoints.web.exposure.include=* spring.flyway.locations=classpath:db/migration spring.flyway.enabled=true spring.flyway.clean-on-validation-error=true + +spring.jpa.hibernate.ddl-auto=none \ No newline at end of file diff --git a/src/main/resources/db/migration/1.0/V0001__Create_schema.sql b/src/main/resources/db/migration/1.0/V0001__Create_schema.sql index cea91c1..b3ed7d7 100644 --- a/src/main/resources/db/migration/1.0/V0001__Create_schema.sql +++ b/src/main/resources/db/migration/1.0/V0001__Create_schema.sql @@ -49,6 +49,7 @@ CREATE TABLE APPOINTMENT ( ID NUMBER(19,0) NOT NULL, VERSION INTEGER NOT NULL, DATE_TIME TIMESTAMP NOT NULL, + END_DATE_TIME TIMESTAMP NOT NULL, STATUS VARCHAR(128) NOT NULL DEFAULT 'SCHEDULED', CLIENT_ID NUMBER(19,0) NOT NULL, TREATMENT_ID NUMBER(19,0) NOT NULL, @@ -69,6 +70,6 @@ CREATE SEQUENCE APPOINTMENT_SEQ START WITH 1 INCREMENT BY 100 NOCYCLE; -- CREATING INDEX CREATE INDEX IDX_CLIENT_USER ON CLIENT(USER_ID); CREATE INDEX IDX_SPECIAL_USER ON SPECIALIST(USER_ID); -CREATE INDEX IDX_TREATM_SPECIAL ON TREATMENT(SPECIALIST_ID); +CREATE INDEX IDX_TREATM_SPECIAL ON TREATMENT(SPECIALIST_ID, ID); CREATE INDEX IDX_APPOINT_CLIENT ON APPOINTMENT(CLIENT_ID); -CREATE INDEX IDX_APPOINT_TREATM ON APPOINTMENT(TREATMENT_ID); \ No newline at end of file +CREATE INDEX IDX_APPOINT_TREATM ON APPOINTMENT(TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS); \ No newline at end of file diff --git a/src/main/resources/db/migration/1.0/V0002__Create_mockdata.sql b/src/main/resources/db/migration/1.0/V0002__Create_mockdata.sql index 24c169f..ffe8296 100644 --- a/src/main/resources/db/migration/1.0/V0002__Create_mockdata.sql +++ b/src/main/resources/db/migration/1.0/V0002__Create_mockdata.sql @@ -37,23 +37,23 @@ INSERT INTO TREATMENT(ID, VERSION, NAME, DESCRIPTION, DURATION_MINUTES, SPECIALI INSERT INTO TREATMENT(ID, VERSION, NAME, DESCRIPTION, DURATION_MINUTES, SPECIALIST_ID, CREATED, LAST_UPDATED) VALUES (-12, 0, 'Rekonstrukcja więzadła ACL', 'Rekonstrukcją więzadła krzyżowego przedniego (ACL) z zastąpieniem uszkodzonego więzadła nowym więzadłem ze ścięgien pacjenta.', 180, -4, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -- APPOINTMENTS -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-1, 0, -1, -1, '2024-03-01 09:00:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-2, 0, -2, -3, '2024-03-02 10:30:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-3, 0, -3, -5, '2024-03-03 14:00:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-4, 0, -4, -10, '2024-03-04 08:15:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-5, 0, -1, -2, '2024-03-05 11:45:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-6, 0, -2, -4, '2024-03-06 16:30:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-7, 0, -3, -6, '2024-03-07 09:30:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-8, 0, -4, -11, '2024-03-08 13:45:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-9, 0, -1, -7, '2024-03-09 10:00:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-10, 0, -2, -8, '2024-03-10 12:30:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-11, 0, -3, -9, '2024-03-11 15:00:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-12, 0, -4, -12, '2024-03-12 17:15:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-13, 0, -1, -1, '2024-03-13 08:30:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-14, 0, -2, -3, '2024-03-14 11:00:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-15, 0, -3, -5, '2024-03-15 13:00:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-16, 0, -4, -10, '2024-03-16 09:15:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-17, 0, -1, -2, '2024-03-17 14:45:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-18, 0, -2, -4, '2024-03-18 16:00:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-19, 0, -3, -6, '2024-03-19 10:45:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-20, 0, -4, -11, '2024-03-20 12:15:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); \ No newline at end of file +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-1, 0, -1, -1, '2024-03-01 09:00:00', '2024-03-01 09:15:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-2, 0, -2, -3, '2024-03-02 10:30:00', '2024-03-02 10:45:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-3, 0, -3, -5, '2024-03-03 14:00:00', '2024-03-03 14:15:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-4, 0, -4, -10, '2024-03-04 08:15:00', '2024-03-04 08:30:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-5, 0, -1, -2, '2024-03-05 11:45:00', '2024-03-05 12:00:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-6, 0, -2, -4, '2024-03-06 16:30:00', '2024-03-06 16:45:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-7, 0, -3, -6, '2024-03-07 09:30:00', '2024-03-07 09:45:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-8, 0, -4, -11, '2024-03-08 13:45:00', '2024-03-08 14:00:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-9, 0, -1, -7, '2024-03-09 10:00:00', '2024-03-09 10:15:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-10, 0, -2, -8, '2024-03-10 12:30:00', '2024-03-10 12:45:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-11, 0, -3, -9, '2024-03-11 15:00:00', '2024-03-11 15:15:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-12, 0, -4, -12,'2024-03-12 17:15:00', '2024-03-12 17:30:00','SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-13, 0, -1, -1, '2024-03-13 08:30:00', '2024-03-13 08:45:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-14, 0, -2, -3, '2024-03-14 11:00:00', '2024-03-14 11:15:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-15, 0, -3, -5, '2024-03-15 13:00:00', '2024-03-15 13:15:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-16, 0, -4, -10,'2024-03-16 09:15:00', '2024-03-16 09:30:00','SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-17, 0, -1, -2, '2024-03-17 14:45:00', '2024-03-17 15:00:00', 'COMPLETED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-18, 0, -2, -4, '2024-03-18 16:00:00', '2024-03-18 16:15:00', 'SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-19, 0, -3, -6, '2024-03-19 10:45:00', '2024-03-19 11:00:00', 'CANCELLED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO APPOINTMENT(ID, VERSION, CLIENT_ID, TREATMENT_ID, DATE_TIME, END_DATE_TIME, STATUS, CREATED, LAST_UPDATED) VALUES (-20, 0, -4, -11,'2024-03-20 12:15:00', '2024-03-20 12:30:00','SCHEDULED', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); \ No newline at end of file From e12fc684541ed890f8900d7fc0793177234fba12 Mon Sep 17 00:00:00 2001 From: MichalLuzyna Date: Fri, 11 Apr 2025 13:45:55 +0200 Subject: [PATCH 02/22] Fixing review comments --- .../dataaccess/entity/AppointmentEntity.java | 21 +++++++++++++++++++ src/main/resources/application.properties | 6 ++++-- src/main/resources/banner/jbf_banner.txt | 8 +++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/banner/jbf_banner.txt diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java index 8bb65d7..ae6a2bb 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java @@ -1,6 +1,7 @@ package com.capgemini.training.appointmentbooking.dataaccess.entity; import java.time.Instant; +import java.util.Objects; import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; @@ -44,4 +45,24 @@ public class AppointmentEntity extends BaseEntity { @Enumerated(EnumType.STRING) private AppointmentStatus status; + @Override + public void prePersist() { + super.prePersist(); + validateDates(); + } + + @Override + public void preUpdate() { + super.preUpdate(); + validateDates(); + } + + private void validateDates() { + Objects.requireNonNull(this.dateTime); + Objects.requireNonNull(this.endsAt); + if(!this.endsAt.isAfter(this.dateTime)) + { + throw new IllegalStateException(String.format("Starting date: %s must be before end date: %s", this.dateTime, this.endsAt)); + } + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 135094d..141d23b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,7 @@ spring.application.name=appointment-booking-app spring.h2.console.enabled=true -spring.datasource.url=jdbc:h2:mem:appointmentbooking; +spring.datasource.url=jdbc:h2:mem:appointmentbooking spring.datasource.username=sa spring.datasource.password=password @@ -14,4 +14,6 @@ spring.flyway.locations=classpath:db/migration spring.flyway.enabled=true spring.flyway.clean-on-validation-error=true -spring.jpa.hibernate.ddl-auto=none \ No newline at end of file +spring.jpa.hibernate.ddl-auto=none + +spring.banner.location=classpath:/banner/jbf_banner.txt diff --git a/src/main/resources/banner/jbf_banner.txt b/src/main/resources/banner/jbf_banner.txt new file mode 100644 index 0000000..a39f9ef --- /dev/null +++ b/src/main/resources/banner/jbf_banner.txt @@ -0,0 +1,8 @@ + ,--. ,-----. ,--. ,--. ,------. ,--. ,--. ,--. + | | ,--,--.,--. ,--.,--,--. | |) /_ ,--,--.,---.| |,-. ,---. ,--,--, ,-| | | .---',--.,--.,--,--, ,-| | ,--,--.,-' '-.`--' ,---. ,--,--, +,--. | |' ,-. | \ `' /' ,-. | | .-. \' ,-. | .--'| /| .-. :| \' .-. | | `--, | || || \' .-. |' ,-. |'-. .-',--.| .-. || \ +| '-' /\ '-' | \ / \ '-' | | '--' /\ '-' \ `--.| \ \\ --.| || |\ `-' | | |` ' '' '| || |\ `-' |\ '-' | | | | |' '-' '| || | + `-----' `--`--' `--' `--`--' `------' `--`--'`---'`--'`--'`----'`--''--' `---' `--' `----' `--''--' `---' `--`--' `--' `--' `---' `--''--' + +${application.title} ${application.version} +Powered by Spring Boot ${spring-boot.version} \ No newline at end of file From 7c94e8a3c38364aa915c141ebc1a8d266f824741 Mon Sep 17 00:00:00 2001 From: MichalLuzyna Date: Fri, 11 Apr 2025 13:50:22 +0200 Subject: [PATCH 03/22] spotless --- .../AppointmentBookingAppApplication.java | 26 ++-- .../common/datatype/AppointmentStatus.java | 10 +- .../common/datatype/Specialization.java | 54 +++---- .../converter/SpecializationConverter.java | 50 +++---- .../dataaccess/entity/AppointmentEntity.java | 136 +++++++++--------- .../dataaccess/entity/BaseEntity.java | 76 +++++----- .../dataaccess/entity/ClientEntity.java | 72 +++++----- .../dataaccess/entity/SpecialistEntity.java | 84 +++++------ .../dataaccess/entity/TreatmentEntity.java | 72 +++++----- .../dataaccess/entity/UserEntity.java | 70 ++++----- .../AppointmentBookingAppApplicationIT.java | 26 ++-- .../dataaccess/entity/EntitySmokeIT.java | 74 +++++----- 12 files changed, 375 insertions(+), 375 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java index 1639ccf..e1516cc 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java @@ -1,13 +1,13 @@ -package com.capgemini.training.appointmentbooking; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class AppointmentBookingAppApplication { - - public static void main(String[] args) { - SpringApplication.run(AppointmentBookingAppApplication.class, args); - } - -} +package com.capgemini.training.appointmentbooking; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AppointmentBookingAppApplication { + + public static void main(String[] args) { + SpringApplication.run(AppointmentBookingAppApplication.class, args); + } + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java index e6bca11..65aa5c2 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java @@ -1,5 +1,5 @@ -package com.capgemini.training.appointmentbooking.common.datatype; - -public enum AppointmentStatus { - SCHEDULED, CANCELLED, COMPLETED -} +package com.capgemini.training.appointmentbooking.common.datatype; + +public enum AppointmentStatus { + SCHEDULED, CANCELLED, COMPLETED +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java index b83b85e..0d8f0ab 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java @@ -1,27 +1,27 @@ -package com.capgemini.training.appointmentbooking.common.datatype; - -import lombok.Getter; - -@Getter -public enum Specialization { - - DENTIST("Dentist"), CARDIOLOGIST("Cardiologist"), PEDIATRICIAN("Pediatrician"), UROLOGIST("Urologist"), NEUROLOGIST( - "Neurologist"), ORTHOPAEDIST("Orthopaedist"); - - private final String name; - - Specialization(String name) { - this.name = name; - } - - public static Specialization getByName(String name) { - - for (Specialization s : Specialization.values()) { - if (s.getName().equals(name)) { - return s; - } - } - return null; - } - -} +package com.capgemini.training.appointmentbooking.common.datatype; + +import lombok.Getter; + +@Getter +public enum Specialization { + + DENTIST("Dentist"), CARDIOLOGIST("Cardiologist"), PEDIATRICIAN("Pediatrician"), UROLOGIST("Urologist"), NEUROLOGIST( + "Neurologist"), ORTHOPAEDIST("Orthopaedist"); + + private final String name; + + Specialization(String name) { + this.name = name; + } + + public static Specialization getByName(String name) { + + for (Specialization s : Specialization.values()) { + if (s.getName().equals(name)) { + return s; + } + } + return null; + } + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java index 7a24dc0..4d68d76 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java @@ -1,25 +1,25 @@ -package com.capgemini.training.appointmentbooking.dataaccess.converter; -import com.capgemini.training.appointmentbooking.common.datatype.Specialization; - -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.Converter; - -@Converter -public class SpecializationConverter implements AttributeConverter { - - @Override - public String convertToDatabaseColumn(Specialization specialization) { - - return specialization != null ? specialization.getName() : null; - - } - - @Override - public Specialization convertToEntityAttribute(String dbData) { - if (dbData == null) { - return null; - } - return Specialization.getByName(dbData); - } - -} +package com.capgemini.training.appointmentbooking.dataaccess.converter; +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter +public class SpecializationConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(Specialization specialization) { + + return specialization != null ? specialization.getName() : null; + + } + + @Override + public Specialization convertToEntityAttribute(String dbData) { + if (dbData == null) { + return null; + } + return Specialization.getByName(dbData); + } + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java index ae6a2bb..dbe5a88 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java @@ -1,68 +1,68 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.time.Instant; -import java.util.Objects; - -import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "APPOINTMENT") -@Getter -@Setter -public class AppointmentEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "APPOINTMENT_SEQ_GEN") - @SequenceGenerator(sequenceName = "APPOINTMENT_SEQ", name = "APPOINTMENT_SEQ_GEN", allocationSize = 100) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - private ClientEntity client; - - @ManyToOne(fetch = FetchType.LAZY) - private TreatmentEntity treatment; - - @Column(name = "DATE_TIME") - private Instant dateTime; - - @Column(name = "END_DATE_TIME") - private Instant endsAt; - - @Enumerated(EnumType.STRING) - private AppointmentStatus status; - - @Override - public void prePersist() { - super.prePersist(); - validateDates(); - } - - @Override - public void preUpdate() { - super.preUpdate(); - validateDates(); - } - - private void validateDates() { - Objects.requireNonNull(this.dateTime); - Objects.requireNonNull(this.endsAt); - if(!this.endsAt.isAfter(this.dateTime)) - { - throw new IllegalStateException(String.format("Starting date: %s must be before end date: %s", this.dateTime, this.endsAt)); - } - } -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.time.Instant; +import java.util.Objects; + +import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "APPOINTMENT") +@Getter +@Setter +public class AppointmentEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "APPOINTMENT_SEQ_GEN") + @SequenceGenerator(sequenceName = "APPOINTMENT_SEQ", name = "APPOINTMENT_SEQ_GEN", allocationSize = 100) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private ClientEntity client; + + @ManyToOne(fetch = FetchType.LAZY) + private TreatmentEntity treatment; + + @Column(name = "DATE_TIME") + private Instant dateTime; + + @Column(name = "END_DATE_TIME") + private Instant endsAt; + + @Enumerated(EnumType.STRING) + private AppointmentStatus status; + + @Override + public void prePersist() { + super.prePersist(); + validateDates(); + } + + @Override + public void preUpdate() { + super.preUpdate(); + validateDates(); + } + + private void validateDates() { + Objects.requireNonNull(this.dateTime); + Objects.requireNonNull(this.endsAt); + if (!this.endsAt.isAfter(this.dateTime)) { + throw new IllegalStateException( + String.format("Starting date: %s must be before end date: %s", this.dateTime, this.endsAt)); + } + } +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java index 0f2a645..d7b4587 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java @@ -1,38 +1,38 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.time.Instant; - -import jakarta.persistence.Column; -import jakarta.persistence.MappedSuperclass; -import jakarta.persistence.PrePersist; -import jakarta.persistence.PreUpdate; -import jakarta.persistence.Version; -import lombok.Getter; -import lombok.Setter; - -@MappedSuperclass -@Getter -public class BaseEntity { - - @Version - @Setter - private int version; - - @Column(updatable = false) - private Instant created; - - @Column(name = "LAST_UPDATED") - private Instant lastUpdated; - - @PrePersist - public void prePersist() { - Instant now = Instant.now(); - this.created = now; - this.lastUpdated = now; - } - - @PreUpdate - public void preUpdate() { - this.lastUpdated = Instant.now(); - } -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.time.Instant; + +import jakarta.persistence.Column; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Version; +import lombok.Getter; +import lombok.Setter; + +@MappedSuperclass +@Getter +public class BaseEntity { + + @Version + @Setter + private int version; + + @Column(updatable = false) + private Instant created; + + @Column(name = "LAST_UPDATED") + private Instant lastUpdated; + + @PrePersist + public void prePersist() { + Instant now = Instant.now(); + this.created = now; + this.lastUpdated = now; + } + + @PreUpdate + public void preUpdate() { + this.lastUpdated = Instant.now(); + } +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java index d20c99e..a592b26 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java @@ -1,36 +1,36 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.util.List; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "CLIENT") -@Getter -@Setter -public class ClientEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLIENT_SEQ_GEN") - @SequenceGenerator(sequenceName = "CLIENT_SEQ", name = "CLIENT_SEQ_GEN", allocationSize = 100) - private Long id; - - @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) - private UserEntity user; - - @OneToMany(mappedBy = "client", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, - CascadeType.REMOVE}) - private List appointments; - -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.util.List; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "CLIENT") +@Getter +@Setter +public class ClientEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLIENT_SEQ_GEN") + @SequenceGenerator(sequenceName = "CLIENT_SEQ", name = "CLIENT_SEQ_GEN", allocationSize = 100) + private Long id; + + @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) + private UserEntity user; + + @OneToMany(mappedBy = "client", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, + CascadeType.REMOVE}) + private List appointments; + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java index 63f8ead..d5d3878 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java @@ -1,42 +1,42 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.util.List; - -import com.capgemini.training.appointmentbooking.common.datatype.Specialization; -import com.capgemini.training.appointmentbooking.dataaccess.converter.SpecializationConverter; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Convert; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "SPECIALIST") -@Getter -@Setter -public class SpecialistEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SPECIALIST_SEQ_GEN") - @SequenceGenerator(sequenceName = "SPECIALIST_SEQ", name = "SPECIALIST_SEQ_GEN", allocationSize = 100) - private Long id; - - @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) - private UserEntity user; - - @Convert(converter = SpecializationConverter.class) - private Specialization specialization; - - @OneToMany(mappedBy = "specialist", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, - CascadeType.REMOVE}) - private List treatments; -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.util.List; + +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import com.capgemini.training.appointmentbooking.dataaccess.converter.SpecializationConverter; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "SPECIALIST") +@Getter +@Setter +public class SpecialistEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SPECIALIST_SEQ_GEN") + @SequenceGenerator(sequenceName = "SPECIALIST_SEQ", name = "SPECIALIST_SEQ_GEN", allocationSize = 100) + private Long id; + + @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) + private UserEntity user; + + @Convert(converter = SpecializationConverter.class) + private Specialization specialization; + + @OneToMany(mappedBy = "specialist", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, + CascadeType.REMOVE}) + private List treatments; +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java index 25239cd..4deff0e 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java @@ -1,36 +1,36 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "TREATMENT") -@Getter -@Setter -public class TreatmentEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TREATMENT_SEQ_GEN") - @SequenceGenerator(sequenceName = "TREATMENT_SEQ", name = "TREATMENT_SEQ_GEN", allocationSize = 100) - private Long id; - - private String name; - - private String description; - - @Column(name = "DURATION_MINUTES") - private int durationMinutes; - - @ManyToOne(fetch = FetchType.LAZY) - private SpecialistEntity specialist; - -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "TREATMENT") +@Getter +@Setter +public class TreatmentEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TREATMENT_SEQ_GEN") + @SequenceGenerator(sequenceName = "TREATMENT_SEQ", name = "TREATMENT_SEQ_GEN", allocationSize = 100) + private Long id; + + private String name; + + private String description; + + @Column(name = "DURATION_MINUTES") + private int durationMinutes; + + @ManyToOne(fetch = FetchType.LAZY) + private SpecialistEntity specialist; + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java index 7bd50bc..def78fa 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java @@ -1,35 +1,35 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "USER_TABLE") -@Getter -@Setter -public class UserEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GEN") - @SequenceGenerator(sequenceName = "USER_SEQ", name = "USER_SEQ_GEN", allocationSize = 100) - private Long id; - - private String email; - - @Column(name = "PASSWORD_HASH") - private String passwordHash; - - @Column(name = "FIRST_NAME") - private String firstname; - - @Column(name = "LAST_NAME") - private String lastname; - -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "USER_TABLE") +@Getter +@Setter +public class UserEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GEN") + @SequenceGenerator(sequenceName = "USER_SEQ", name = "USER_SEQ_GEN", allocationSize = 100) + private Long id; + + private String email; + + @Column(name = "PASSWORD_HASH") + private String passwordHash; + + @Column(name = "FIRST_NAME") + private String firstname; + + @Column(name = "LAST_NAME") + private String lastname; + +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java b/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java index ffa63a4..36cfd39 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java @@ -1,13 +1,13 @@ -package com.capgemini.training.appointmentbooking; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class AppointmentBookingAppApplicationIT { - - @Test - void contextLoads() { - } - -} +package com.capgemini.training.appointmentbooking; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class AppointmentBookingAppApplicationIT { + + @Test + void contextLoads() { + } + +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java index 3b7a4a9..bdced7a 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java @@ -1,37 +1,37 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; - -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; - -@DataJpaTest -public class EntitySmokeIT { - - @PersistenceContext - private EntityManager em; - - @Test - void loadAllClasses() { - - // given - Map, Integer> classMap = Map.of( // - UserEntity.class, 8, // - ClientEntity.class, 4, // - SpecialistEntity.class, 4, // - TreatmentEntity.class, 12, // - AppointmentEntity.class, 20); - - // when //then - classMap.forEach((entityType, - expectedCount) -> assertThat( - (List) em.createQuery("from " + entityType.getSimpleName()).getResultList()) - .hasSize(expectedCount)); - } -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +@DataJpaTest +public class EntitySmokeIT { + + @PersistenceContext + private EntityManager em; + + @Test + void loadAllClasses() { + + // given + Map, Integer> classMap = Map.of( // + UserEntity.class, 8, // + ClientEntity.class, 4, // + SpecialistEntity.class, 4, // + TreatmentEntity.class, 12, // + AppointmentEntity.class, 20); + + // when //then + classMap.forEach((entityType, + expectedCount) -> assertThat( + (List) em.createQuery("from " + entityType.getSimpleName()).getResultList()) + .hasSize(expectedCount)); + } +} From 02fc98d77d8e01d5702b432eab40f5505cc2b34f Mon Sep 17 00:00:00 2001 From: MichalLuzyna Date: Fri, 11 Apr 2025 14:13:43 +0200 Subject: [PATCH 04/22] Line endings --- .gitattributes | 7 + .../AppointmentBookingAppApplication.java | 26 ++-- .../common/datatype/AppointmentStatus.java | 10 +- .../common/datatype/Specialization.java | 54 +++---- .../converter/SpecializationConverter.java | 50 +++---- .../dataaccess/entity/AppointmentEntity.java | 136 +++++++++--------- .../dataaccess/entity/BaseEntity.java | 76 +++++----- .../dataaccess/entity/ClientEntity.java | 72 +++++----- .../dataaccess/entity/SpecialistEntity.java | 84 +++++------ .../dataaccess/entity/TreatmentEntity.java | 72 +++++----- .../dataaccess/entity/UserEntity.java | 70 ++++----- .../AppointmentBookingAppApplicationIT.java | 26 ++-- .../dataaccess/entity/EntitySmokeIT.java | 74 +++++----- 13 files changed, 382 insertions(+), 375 deletions(-) diff --git a/.gitattributes b/.gitattributes index 3b41682..44153cd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,9 @@ /mvnw text eol=lf *.cmd text eol=crlf +* text eol=lf +*.bat eol=crlf +*.htm text diff=html +*.html text diff=html +*.xhtml text diff=html +*.java text diff=java +*.css text diff=css \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java index e1516cc..1639ccf 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java @@ -1,13 +1,13 @@ -package com.capgemini.training.appointmentbooking; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class AppointmentBookingAppApplication { - - public static void main(String[] args) { - SpringApplication.run(AppointmentBookingAppApplication.class, args); - } - -} +package com.capgemini.training.appointmentbooking; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AppointmentBookingAppApplication { + + public static void main(String[] args) { + SpringApplication.run(AppointmentBookingAppApplication.class, args); + } + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java index 65aa5c2..e6bca11 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/AppointmentStatus.java @@ -1,5 +1,5 @@ -package com.capgemini.training.appointmentbooking.common.datatype; - -public enum AppointmentStatus { - SCHEDULED, CANCELLED, COMPLETED -} +package com.capgemini.training.appointmentbooking.common.datatype; + +public enum AppointmentStatus { + SCHEDULED, CANCELLED, COMPLETED +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java index 0d8f0ab..b83b85e 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/common/datatype/Specialization.java @@ -1,27 +1,27 @@ -package com.capgemini.training.appointmentbooking.common.datatype; - -import lombok.Getter; - -@Getter -public enum Specialization { - - DENTIST("Dentist"), CARDIOLOGIST("Cardiologist"), PEDIATRICIAN("Pediatrician"), UROLOGIST("Urologist"), NEUROLOGIST( - "Neurologist"), ORTHOPAEDIST("Orthopaedist"); - - private final String name; - - Specialization(String name) { - this.name = name; - } - - public static Specialization getByName(String name) { - - for (Specialization s : Specialization.values()) { - if (s.getName().equals(name)) { - return s; - } - } - return null; - } - -} +package com.capgemini.training.appointmentbooking.common.datatype; + +import lombok.Getter; + +@Getter +public enum Specialization { + + DENTIST("Dentist"), CARDIOLOGIST("Cardiologist"), PEDIATRICIAN("Pediatrician"), UROLOGIST("Urologist"), NEUROLOGIST( + "Neurologist"), ORTHOPAEDIST("Orthopaedist"); + + private final String name; + + Specialization(String name) { + this.name = name; + } + + public static Specialization getByName(String name) { + + for (Specialization s : Specialization.values()) { + if (s.getName().equals(name)) { + return s; + } + } + return null; + } + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java index 4d68d76..7a24dc0 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/converter/SpecializationConverter.java @@ -1,25 +1,25 @@ -package com.capgemini.training.appointmentbooking.dataaccess.converter; -import com.capgemini.training.appointmentbooking.common.datatype.Specialization; - -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.Converter; - -@Converter -public class SpecializationConverter implements AttributeConverter { - - @Override - public String convertToDatabaseColumn(Specialization specialization) { - - return specialization != null ? specialization.getName() : null; - - } - - @Override - public Specialization convertToEntityAttribute(String dbData) { - if (dbData == null) { - return null; - } - return Specialization.getByName(dbData); - } - -} +package com.capgemini.training.appointmentbooking.dataaccess.converter; +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter +public class SpecializationConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(Specialization specialization) { + + return specialization != null ? specialization.getName() : null; + + } + + @Override + public Specialization convertToEntityAttribute(String dbData) { + if (dbData == null) { + return null; + } + return Specialization.getByName(dbData); + } + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java index dbe5a88..12eeb0c 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/AppointmentEntity.java @@ -1,68 +1,68 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.time.Instant; -import java.util.Objects; - -import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "APPOINTMENT") -@Getter -@Setter -public class AppointmentEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "APPOINTMENT_SEQ_GEN") - @SequenceGenerator(sequenceName = "APPOINTMENT_SEQ", name = "APPOINTMENT_SEQ_GEN", allocationSize = 100) - private Long id; - - @ManyToOne(fetch = FetchType.LAZY) - private ClientEntity client; - - @ManyToOne(fetch = FetchType.LAZY) - private TreatmentEntity treatment; - - @Column(name = "DATE_TIME") - private Instant dateTime; - - @Column(name = "END_DATE_TIME") - private Instant endsAt; - - @Enumerated(EnumType.STRING) - private AppointmentStatus status; - - @Override - public void prePersist() { - super.prePersist(); - validateDates(); - } - - @Override - public void preUpdate() { - super.preUpdate(); - validateDates(); - } - - private void validateDates() { - Objects.requireNonNull(this.dateTime); - Objects.requireNonNull(this.endsAt); - if (!this.endsAt.isAfter(this.dateTime)) { - throw new IllegalStateException( - String.format("Starting date: %s must be before end date: %s", this.dateTime, this.endsAt)); - } - } -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.time.Instant; +import java.util.Objects; + +import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "APPOINTMENT") +@Getter +@Setter +public class AppointmentEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "APPOINTMENT_SEQ_GEN") + @SequenceGenerator(sequenceName = "APPOINTMENT_SEQ", name = "APPOINTMENT_SEQ_GEN", allocationSize = 100) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private ClientEntity client; + + @ManyToOne(fetch = FetchType.LAZY) + private TreatmentEntity treatment; + + @Column(name = "DATE_TIME") + private Instant dateTime; + + @Column(name = "END_DATE_TIME") + private Instant endsAt; + + @Enumerated(EnumType.STRING) + private AppointmentStatus status; + + @Override + public void prePersist() { + super.prePersist(); + validateDates(); + } + + @Override + public void preUpdate() { + super.preUpdate(); + validateDates(); + } + + private void validateDates() { + Objects.requireNonNull(this.dateTime); + Objects.requireNonNull(this.endsAt); + if (!this.endsAt.isAfter(this.dateTime)) { + throw new IllegalStateException( + String.format("Starting date: %s must be before end date: %s", this.dateTime, this.endsAt)); + } + } +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java index d7b4587..0f2a645 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/BaseEntity.java @@ -1,38 +1,38 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.time.Instant; - -import jakarta.persistence.Column; -import jakarta.persistence.MappedSuperclass; -import jakarta.persistence.PrePersist; -import jakarta.persistence.PreUpdate; -import jakarta.persistence.Version; -import lombok.Getter; -import lombok.Setter; - -@MappedSuperclass -@Getter -public class BaseEntity { - - @Version - @Setter - private int version; - - @Column(updatable = false) - private Instant created; - - @Column(name = "LAST_UPDATED") - private Instant lastUpdated; - - @PrePersist - public void prePersist() { - Instant now = Instant.now(); - this.created = now; - this.lastUpdated = now; - } - - @PreUpdate - public void preUpdate() { - this.lastUpdated = Instant.now(); - } -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.time.Instant; + +import jakarta.persistence.Column; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Version; +import lombok.Getter; +import lombok.Setter; + +@MappedSuperclass +@Getter +public class BaseEntity { + + @Version + @Setter + private int version; + + @Column(updatable = false) + private Instant created; + + @Column(name = "LAST_UPDATED") + private Instant lastUpdated; + + @PrePersist + public void prePersist() { + Instant now = Instant.now(); + this.created = now; + this.lastUpdated = now; + } + + @PreUpdate + public void preUpdate() { + this.lastUpdated = Instant.now(); + } +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java index a592b26..d20c99e 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/ClientEntity.java @@ -1,36 +1,36 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.util.List; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "CLIENT") -@Getter -@Setter -public class ClientEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLIENT_SEQ_GEN") - @SequenceGenerator(sequenceName = "CLIENT_SEQ", name = "CLIENT_SEQ_GEN", allocationSize = 100) - private Long id; - - @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) - private UserEntity user; - - @OneToMany(mappedBy = "client", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, - CascadeType.REMOVE}) - private List appointments; - -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.util.List; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "CLIENT") +@Getter +@Setter +public class ClientEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CLIENT_SEQ_GEN") + @SequenceGenerator(sequenceName = "CLIENT_SEQ", name = "CLIENT_SEQ_GEN", allocationSize = 100) + private Long id; + + @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) + private UserEntity user; + + @OneToMany(mappedBy = "client", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, + CascadeType.REMOVE}) + private List appointments; + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java index d5d3878..63f8ead 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java @@ -1,42 +1,42 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import java.util.List; - -import com.capgemini.training.appointmentbooking.common.datatype.Specialization; -import com.capgemini.training.appointmentbooking.dataaccess.converter.SpecializationConverter; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Convert; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "SPECIALIST") -@Getter -@Setter -public class SpecialistEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SPECIALIST_SEQ_GEN") - @SequenceGenerator(sequenceName = "SPECIALIST_SEQ", name = "SPECIALIST_SEQ_GEN", allocationSize = 100) - private Long id; - - @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) - private UserEntity user; - - @Convert(converter = SpecializationConverter.class) - private Specialization specialization; - - @OneToMany(mappedBy = "specialist", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, - CascadeType.REMOVE}) - private List treatments; -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import java.util.List; + +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import com.capgemini.training.appointmentbooking.dataaccess.converter.SpecializationConverter; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "SPECIALIST") +@Getter +@Setter +public class SpecialistEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SPECIALIST_SEQ_GEN") + @SequenceGenerator(sequenceName = "SPECIALIST_SEQ", name = "SPECIALIST_SEQ_GEN", allocationSize = 100) + private Long id; + + @OneToOne(optional = false, fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST}) + private UserEntity user; + + @Convert(converter = SpecializationConverter.class) + private Specialization specialization; + + @OneToMany(mappedBy = "specialist", fetch = FetchType.LAZY, orphanRemoval = true, cascade = {CascadeType.PERSIST, + CascadeType.REMOVE}) + private List treatments; +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java index 4deff0e..25239cd 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java @@ -1,36 +1,36 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "TREATMENT") -@Getter -@Setter -public class TreatmentEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TREATMENT_SEQ_GEN") - @SequenceGenerator(sequenceName = "TREATMENT_SEQ", name = "TREATMENT_SEQ_GEN", allocationSize = 100) - private Long id; - - private String name; - - private String description; - - @Column(name = "DURATION_MINUTES") - private int durationMinutes; - - @ManyToOne(fetch = FetchType.LAZY) - private SpecialistEntity specialist; - -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "TREATMENT") +@Getter +@Setter +public class TreatmentEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TREATMENT_SEQ_GEN") + @SequenceGenerator(sequenceName = "TREATMENT_SEQ", name = "TREATMENT_SEQ_GEN", allocationSize = 100) + private Long id; + + private String name; + + private String description; + + @Column(name = "DURATION_MINUTES") + private int durationMinutes; + + @ManyToOne(fetch = FetchType.LAZY) + private SpecialistEntity specialist; + +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java index def78fa..7bd50bc 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/UserEntity.java @@ -1,35 +1,35 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; - -@Entity -@Table(name = "USER_TABLE") -@Getter -@Setter -public class UserEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GEN") - @SequenceGenerator(sequenceName = "USER_SEQ", name = "USER_SEQ_GEN", allocationSize = 100) - private Long id; - - private String email; - - @Column(name = "PASSWORD_HASH") - private String passwordHash; - - @Column(name = "FIRST_NAME") - private String firstname; - - @Column(name = "LAST_NAME") - private String lastname; - -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "USER_TABLE") +@Getter +@Setter +public class UserEntity extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GEN") + @SequenceGenerator(sequenceName = "USER_SEQ", name = "USER_SEQ_GEN", allocationSize = 100) + private Long id; + + private String email; + + @Column(name = "PASSWORD_HASH") + private String passwordHash; + + @Column(name = "FIRST_NAME") + private String firstname; + + @Column(name = "LAST_NAME") + private String lastname; + +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java b/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java index 36cfd39..ffa63a4 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplicationIT.java @@ -1,13 +1,13 @@ -package com.capgemini.training.appointmentbooking; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class AppointmentBookingAppApplicationIT { - - @Test - void contextLoads() { - } - -} +package com.capgemini.training.appointmentbooking; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class AppointmentBookingAppApplicationIT { + + @Test + void contextLoads() { + } + +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java index bdced7a..3b7a4a9 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java @@ -1,37 +1,37 @@ -package com.capgemini.training.appointmentbooking.dataaccess.entity; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; - -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; - -@DataJpaTest -public class EntitySmokeIT { - - @PersistenceContext - private EntityManager em; - - @Test - void loadAllClasses() { - - // given - Map, Integer> classMap = Map.of( // - UserEntity.class, 8, // - ClientEntity.class, 4, // - SpecialistEntity.class, 4, // - TreatmentEntity.class, 12, // - AppointmentEntity.class, 20); - - // when //then - classMap.forEach((entityType, - expectedCount) -> assertThat( - (List) em.createQuery("from " + entityType.getSimpleName()).getResultList()) - .hasSize(expectedCount)); - } -} +package com.capgemini.training.appointmentbooking.dataaccess.entity; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +@DataJpaTest +public class EntitySmokeIT { + + @PersistenceContext + private EntityManager em; + + @Test + void loadAllClasses() { + + // given + Map, Integer> classMap = Map.of( // + UserEntity.class, 8, // + ClientEntity.class, 4, // + SpecialistEntity.class, 4, // + TreatmentEntity.class, 12, // + AppointmentEntity.class, 20); + + // when //then + classMap.forEach((entityType, + expectedCount) -> assertThat( + (List) em.createQuery("from " + entityType.getSimpleName()).getResultList()) + .hasSize(expectedCount)); + } +} From c40b1342985e67274e98b552cc580970e22c3545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Mon, 10 Mar 2025 11:00:31 +0100 Subject: [PATCH 05/22] add repositories (v1) --- pom.xml | 54 +++++-- .../dataaccess/entity/SpecialistEntity.java | 18 +-- .../repository/AppointmentRepository.java | 72 +++++++++ .../repository/ClientRepository.java | 29 ++++ .../repository/CustomUserRepository.java | 10 ++ .../repository/SpecialistRepository.java | 14 ++ .../repository/TreatmentRepository.java | 41 ++++++ .../dataaccess/repository/UserRepository.java | 7 + .../criteria/AppointmentCriteria.java | 8 + .../criteria/TreatmentCriteria.java | 4 + .../impl/CustomUserRepositoryImpl.java | 34 +++++ .../repository/AppointmentRepositoryTest.java | 137 ++++++++++++++++++ .../repository/ClientRepositoryTest.java | 41 ++++++ .../repository/SpecialistRepositoryTest.java | 34 +++++ .../repository/TreatmentRepositoryTest.java | 126 ++++++++++++++++ .../repository/UserRepositoryTest.java | 29 ++++ 16 files changed, 630 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java create mode 100644 src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java create mode 100644 src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java create mode 100644 src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java create mode 100644 src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java create mode 100644 src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java diff --git a/pom.xml b/pom.xml index 2b97fb0..142059b 100644 --- a/pom.xml +++ b/pom.xml @@ -55,29 +55,30 @@ org.projectlombok lombok - true + provided org.springframework.boot spring-boot-starter-test test + + com.querydsl + querydsl-apt + 5.0.0 + jakarta + provided + + + com.querydsl + querydsl-jpa + jakarta + 5.0.0 + - - org.apache.maven.plugins - maven-compiler-plugin - - - - org.projectlombok - lombok - - - - org.springframework.boot spring-boot-maven-plugin @@ -90,6 +91,32 @@ + + org.flywaydb + flyway-maven-plugin + + sa + password + jdbc:h2:mem:todoapp + false + + + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + + process + + + target/generated-sources/java + com.mysema.query.apt.jpa.JPAAnnotationProcessor + + + + org.apache.maven.plugins maven-surefire-plugin @@ -144,5 +171,4 @@ - diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java index 63f8ead..4281a83 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/SpecialistEntity.java @@ -1,28 +1,18 @@ package com.capgemini.training.appointmentbooking.dataaccess.entity; -import java.util.List; - import com.capgemini.training.appointmentbooking.common.datatype.Specialization; import com.capgemini.training.appointmentbooking.dataaccess.converter.SpecializationConverter; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Convert; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.OneToOne; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Entity @Table(name = "SPECIALIST") @Getter @Setter +@NamedQuery(name = "SpecialistEntity.findBySpecialization", query = "select s from SpecialistEntity s where specialization =:specialization") public class SpecialistEntity extends BaseEntity { @Id diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java new file mode 100644 index 0000000..91794d5 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -0,0 +1,72 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; +import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.*; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + + +@Repository +public interface AppointmentRepository extends JpaRepository { + + default List findByCriteria(AppointmentCriteria c, EntityManager em) { + Objects.requireNonNull(c, "SearchCriteria cannot be null"); + + CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery(AppointmentEntity.class); + Root root = criteriaQuery.from(AppointmentEntity.class); + List predicateList = new ArrayList<>(); + + if (c.treatmentName() != null) { + Join treatmentJoin = root.join("treatment", JoinType.LEFT); + predicateList.add(builder.like(treatmentJoin.get("name"), c.treatmentName())); + } + + if (c.dateTime() != null) { + java.util.Date dateTime = java.util.Date.from(c.dateTime().atZone(ZoneOffset.UTC).toInstant()); + predicateList.add(builder.equal(root.get("dateTime"), dateTime)); + } + + if (c.status() != null) { + predicateList.add(builder.like(root.get("status"), c.status().name())); + } + + Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); + criteriaQuery.where(predicateArray); + TypedQuery query = em.createQuery(criteriaQuery); + return query.getResultList(); + } + + @Query("SELECT a FROM AppointmentEntity a " + + "JOIN a.treatment t " + + "WHERE t.specialist.id = :specialistId " + + "AND a.dateTime < :currentTime " + + "ORDER BY a.dateTime DESC") + List findPastAppointmentsBySpecialist( + @Param("specialistId") Long specialistId, + @Param("currentTime") Instant currentTime); + + @Query("SELECT COUNT(a) > 0 FROM AppointmentEntity a " + + "JOIN a.treatment t " + + "WHERE t.specialist.id = :specialistId " + + "AND a.dateTime = :currentTime") + boolean isConflictedAppointment(@Param("specialistId") Long specialistId, @Param("currentTime") Instant date); + + @Modifying + @Query("UPDATE AppointmentEntity a SET a.status = :status WHERE a.id = :id") + int updateStatus(Long id, AppointmentStatus status); +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java new file mode 100644 index 0000000..e38bf94 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java @@ -0,0 +1,29 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.QClientEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.QUserEntity; +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ClientRepository extends JpaRepository { + + default List findClientsByName(String firstName, String lastName, EntityManager entityManager) { + JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager); + + QClientEntity client = QClientEntity.clientEntity; + QUserEntity user = QUserEntity.userEntity; + + return queryFactory + .selectFrom(client) + .leftJoin(client.user, user) + .where(user.firstname.eq(firstName) + .and(user.lastname.eq(lastName))) + .fetch(); + } +} \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java new file mode 100644 index 0000000..84696dd --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java @@ -0,0 +1,10 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; +import org.springframework.stereotype.Repository; + +@Repository +public interface CustomUserRepository { + + UserEntity findByEmail(String email); +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java new file mode 100644 index 0000000..cdacf2d --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java @@ -0,0 +1,14 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface SpecialistRepository extends JpaRepository { + + List findBySpecialization(Specialization specialization); +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java new file mode 100644 index 0000000..7a1a7f4 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -0,0 +1,41 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.*; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Repository +public interface TreatmentRepository extends JpaRepository { + + default List findByCriteria(TreatmentCriteria c, EntityManager em) { + Objects.requireNonNull(c, "SearchCriteria cannot be null"); + + CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery(TreatmentEntity.class); + Root root = criteriaQuery.from(TreatmentEntity.class); + List predicateList = new ArrayList<>(); + + if (c.treatmentName() != null) { + predicateList.add(builder.like(root.get("name"), c.treatmentName())); + } + + if (c.specialization() != null) { + Join specialistJoin = root.join("specialist", JoinType.LEFT); + predicateList.add(builder.like(specialistJoin.get("specialization"), c.specialization())); + } + + Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); + criteriaQuery.where(predicateArray); + TypedQuery query = em.createQuery(criteriaQuery); + return query.getResultList(); + } +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java new file mode 100644 index 0000000..b167473 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java @@ -0,0 +1,7 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository, CustomUserRepository { +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java new file mode 100644 index 0000000..9b9e02b --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java @@ -0,0 +1,8 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository.criteria; + +import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; + +import java.time.Instant; + +public record AppointmentCriteria(String treatmentName, Instant dateTime, AppointmentStatus status) { +} \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java new file mode 100644 index 0000000..84e61a7 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java @@ -0,0 +1,4 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository.criteria; + +public record TreatmentCriteria(String treatmentName, String specialization) { +} \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java new file mode 100644 index 0000000..a37dc7b --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java @@ -0,0 +1,34 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository.impl; + +import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; +import com.capgemini.training.appointmentbooking.dataaccess.repository.CustomUserRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; + +public class CustomUserRepositoryImpl implements CustomUserRepository { + + @PersistenceContext + private EntityManager entityManager; + + + @Override + public UserEntity findByEmail(String email) { + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); + Root userRoot = criteriaQuery.from(UserEntity.class); + + Predicate emailPredicate = criteriaBuilder.equal(userRoot.get("email"), email); + criteriaQuery.where(emailPredicate); + + try { + return entityManager.createQuery(criteriaQuery).getSingleResult(); + } catch (NoResultException e) { + return null; + } + } +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java new file mode 100644 index 0000000..d8db04d --- /dev/null +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -0,0 +1,137 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; +import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +@DataJpaTest +public class AppointmentRepositoryTest { + + @Autowired + private AppointmentRepository appointmentRepository; + + @PersistenceContext + private EntityManager em; + + @Test + void testFindByCriteria_findAvailableTreatments() { + // given + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null); + // when + List result = appointmentRepository.findByCriteria(criteria, em); + // then + assertThat(result).isNotEmpty().hasSize(2); + } + + @Test + void testFindByCriteria_findAvailableTreatments2() { + // given + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null); + // when + List result = appointmentRepository.findByCriteria(criteria, em); + // then + assertThat(result).isNotEmpty().hasSize(1); + } + + @Test + void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { + // given + + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, AppointmentStatus.CANCELLED); + // when + List result = appointmentRepository.findByCriteria(criteria, em); + // then + assertThat(result).isNotEmpty().hasSize(2); + } + + + @Test + void testFindById() { + // given + // when + Optional result = appointmentRepository.findById(-1L); + + // then + assertTrue(result.isPresent(), "AppointmentEntity should be present"); + + AppointmentEntity appointment = result.get(); + assertNotNull(appointment); + assertEquals(-1L, appointment.getId()); + assertEquals(AppointmentStatus.SCHEDULED, appointment.getStatus()); + assertNotNull(appointment.getClient()); + assertNotNull(appointment.getTreatment()); + assertEquals(toInstant("2024-03-01 09:00:00"), appointment.getDateTime()); + } + + private Instant toInstant(String date) { + return DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.of("Europe/Warsaw")) + .parse(date, ZonedDateTime::from) // Parse into ZonedDateTime first + .toInstant(); + } + + @Test + void testUpdateStatus() { + // given + Optional appointment = appointmentRepository.findById(-1L); + assertTrue(appointment.isPresent(), "AppointmentEntity should be present"); + assertEquals(AppointmentStatus.SCHEDULED, appointment.get().getStatus()); + + // when + appointmentRepository.updateStatus(appointment.get().getId(), AppointmentStatus.COMPLETED); + em.flush(); + em.clear(); + + // then + appointment = appointmentRepository.findById(-1L); + assertTrue(appointment.isPresent(), "AppointmentEntity should be present"); + assertEquals(AppointmentStatus.COMPLETED, appointment.get().getStatus()); + } + + @Test + void testFindPastAppointments() { + // Given + Long specialistId = -1L; + Instant date = toInstant("2024-03-12 09:00:00"); + + // When + List appointments = appointmentRepository.findPastAppointmentsBySpecialist(specialistId, date); + + // Then + assertNotNull(appointments, "Appointments list should not be null"); + assertEquals(2, appointments.size(), "Expected 4 past appointments"); + appointments.forEach(a -> { + assertEquals(specialistId, a.getTreatment().getSpecialist().getId(), "Appointment belongs to correct specialist"); + assertTrue(a.getDateTime().isBefore(date), "Appointment should be in the past"); + }); + } + + @Test + void testFindConflictedAppointments() { + // Given + Long specialistId = -1L; + Instant date = toInstant("2024-03-05 11:45:00"); + + // When + boolean conflict = appointmentRepository.isConflictedAppointment(specialistId, date); + + // Then + assertTrue(conflict, "Should find conflicted appointments"); + } +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java new file mode 100644 index 0000000..9efb5e1 --- /dev/null +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java @@ -0,0 +1,41 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@DataJpaTest +public class ClientRepositoryTest { + + @Autowired + private ClientRepository clientRepository; + + @PersistenceContext + private EntityManager em; + + @Test + void testFindByQueryDSL_testFindClientsByName() { + // given + String firstName = "Stefan"; + String lastName = "Kowalski"; + + // when + List clients = clientRepository.findClientsByName(firstName, lastName, em); + + // then + assertThat(clients).isNotEmpty().hasSize(1); + ClientEntity client = clients.getFirst(); + assertNotNull(client.getUser(), "Expected client to have an associated user"); + assertEquals(firstName, client.getUser().getFirstname(), "Expected client to have the specified first name"); + assertEquals(lastName, client.getUser().getLastname(), "Expected client to have the specified last name"); + } +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java new file mode 100644 index 0000000..2bdb068 --- /dev/null +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java @@ -0,0 +1,34 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +public class SpecialistRepositoryTest { + + @Autowired + private SpecialistRepository specialistRepository; + + @Test + void testFindBySpecialization() { + // given + Specialization specialization = Specialization.DENTIST; + + // when + List specialists = specialistRepository.findBySpecialization(specialization); + + // then + assertThat(specialists) + .isNotEmpty() + .hasSize(1) + .allMatch(specialist -> specialist.getSpecialization() == specialization, + "Specialists should all have specialization " + specialization); + } +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java new file mode 100644 index 0000000..fc7b94c --- /dev/null +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java @@ -0,0 +1,126 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +@DataJpaTest +public class TreatmentRepositoryTest { + + @Autowired + private TreatmentRepository treatmentRepository; + + @Autowired + private SpecialistRepository specialistRepository; + + @PersistenceContext + private EntityManager em; + + @Test + void testFindByCriteria_findAllDentists() { + // given + TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja dentystyczna", "Dentist"); + // when + List result = treatmentRepository.findByCriteria(criteria, em); + // then + assertThat(result).isNotEmpty().hasSize(1); + } + + @Test + void testFindByCriteria_findBySpecifiedTreatmentName() { + // given + TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja kardiologiczna", null); + // when + List result = treatmentRepository.findByCriteria(criteria, em); + // then + assertThat(result).isNotEmpty().hasSize(1); + } + + @Test + void testFindByCriteria_findAllPediatricians() { + // given + TreatmentCriteria criteria = new TreatmentCriteria(null, "Pediatrician"); + // when + List result = treatmentRepository.findByCriteria(criteria, em); + // then + assertThat(result).isNotEmpty().hasSize(5); + } + + @Test + void testFindByCriteria_findAvailableTreatments() { + // given + TreatmentCriteria criteria = new TreatmentCriteria(null, null); + // when + List result = treatmentRepository.findByCriteria(criteria, em); + // then + assertThat(result).isNotEmpty().hasSize(12); + } + + @Test + void testFindById() { + // given + // when + Optional result = treatmentRepository.findById(-1L); + + // then + assertTrue(result.isPresent(), "TreatmentEntity should be present"); + + TreatmentEntity treatment = result.get(); + assertNotNull(treatment); + assertEquals(-1L, treatment.getId()); + assertEquals("Konsultacja dentystyczna", treatment.getName()); + assertEquals("Konsultacja dentystyczna z diagnostyką i planem leczenia", treatment.getDescription()); + assertEquals(30, treatment.getDurationMinutes()); + + SpecialistEntity specialist = treatment.getSpecialist(); + assertNotNull(specialist, "Specialist should not be null"); + assertEquals(-1L, specialist.getId()); + assertNotNull(specialist.getUser(), "User should not be null"); + assertEquals(Specialization.DENTIST, specialist.getSpecialization()); + assertNotNull(specialist.getTreatments(), "Specialist treatments should not be null"); + } + + @Test + void testSaveTreatment() { + // given + Optional optionalSpecialist = specialistRepository.findById(-1L); + assertTrue(optionalSpecialist.isPresent(), "SpecialistEntity should be present"); + + SpecialistEntity specialist = optionalSpecialist.get(); + + TreatmentEntity treatmentEntity = new TreatmentEntity(); + treatmentEntity.setName("Wypełnienie ubytku"); + treatmentEntity.setDescription("Usunięcie próchnicy i wypełnienie zęba kompozytem"); + treatmentEntity.setDurationMinutes(45); + treatmentEntity.setSpecialist(specialist); + + // when + TreatmentEntity result = treatmentRepository.save(treatmentEntity); + + // then + assertNotNull(result); + assertNotNull(result.getId(), "Saved entity should have an ID"); + assertEquals("Wypełnienie ubytku", result.getName()); + assertEquals("Usunięcie próchnicy i wypełnienie zęba kompozytem", result.getDescription()); + assertEquals(45, result.getDurationMinutes()); + + SpecialistEntity savedSpecialist = result.getSpecialist(); + assertNotNull(savedSpecialist, "Specialist should not be null"); + assertEquals(specialist.getId(), savedSpecialist.getId()); + assertNotNull(savedSpecialist.getUser(), "User should not be null"); + assertEquals(Specialization.DENTIST, savedSpecialist.getSpecialization()); + assertNotNull(savedSpecialist.getTreatments(), "Specialist treatments should not be null"); + } +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java new file mode 100644 index 0000000..c3d9b3c --- /dev/null +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java @@ -0,0 +1,29 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@DataJpaTest +public class UserRepositoryTest { + + @Autowired + private UserRepository userRepository; + + @Test + void testFindByEmail() { + // given + String email = "stefan.kowalski@gmail.com"; + + // when + UserEntity user = userRepository.findByEmail(email); + + // then + assertNotNull(user, "Expected user to be found"); + assertEquals(email, user.getEmail(), "Expected user to have the specified email"); + } +} From 96bd5e0a6d872f2eb32a91631d7b190409168d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Mon, 10 Mar 2025 11:36:33 +0100 Subject: [PATCH 06/22] fix zone issue --- .../dataaccess/repository/AppointmentRepositoryTest.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index d8db04d..2497acf 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -10,8 +10,8 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import java.time.Instant; +import java.time.LocalDateTime; import java.time.ZoneId; -import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; @@ -79,10 +79,8 @@ void testFindById() { } private Instant toInstant(String date) { - return DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss") - .withZone(ZoneId.of("Europe/Warsaw")) - .parse(date, ZonedDateTime::from) // Parse into ZonedDateTime first + return LocalDateTime.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + .atZone(ZoneId.of("Europe/Warsaw")) .toInstant(); } From fe0c439e0c9dca8f68fe242644e18440182798a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Mon, 10 Mar 2025 21:03:41 +0100 Subject: [PATCH 07/22] add exercises related part --- .../dataaccess/entity/TreatmentEntity.java | 2 + .../repository/AppointmentRepository.java | 11 ++--- .../repository/ClientRepository.java | 2 +- .../repository/CustomUserRepository.java | 7 +++- .../repository/SpecialistRepository.java | 18 ++++++++- .../repository/TreatmentRepository.java | 4 ++ .../dataaccess/repository/UserRepository.java | 6 ++- .../repository/criteria/UserCriteria.java | 4 ++ .../impl/CustomUserRepositoryImpl.java | 40 +++++++++++++++++-- .../repository/AppointmentRepositoryTest.java | 28 ++++++++++++- .../repository/ClientRepositoryTest.java | 2 +- .../repository/SpecialistRepositoryTest.java | 24 +++++++++++ .../repository/TreatmentRepositoryTest.java | 20 ++++++++++ 13 files changed, 150 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java index 25239cd..0cc936c 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/entity/TreatmentEntity.java @@ -7,6 +7,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQuery; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; import lombok.Getter; @@ -16,6 +17,7 @@ @Table(name = "TREATMENT") @Getter @Setter +@NamedQuery(name = "TreatmentEntity.findByNameNamedQuery", query = "select t from TreatmentEntity t where name =:name") public class TreatmentEntity extends BaseEntity { @Id diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index 91794d5..6f269f4 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -4,8 +4,7 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; -import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; +import jakarta.persistence.*; import jakarta.persistence.criteria.*; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -51,14 +50,16 @@ default List findByCriteria(AppointmentCriteria c, EntityMana return query.getResultList(); } + List findByDateTimeBetweenAndStatus(Instant start, Instant end, AppointmentStatus status); + @Query("SELECT a FROM AppointmentEntity a " + "JOIN a.treatment t " + "WHERE t.specialist.id = :specialistId " + - "AND a.dateTime < :currentTime " + + "AND a.dateTime < :dateTime " + "ORDER BY a.dateTime DESC") List findPastAppointmentsBySpecialist( @Param("specialistId") Long specialistId, - @Param("currentTime") Instant currentTime); + @Param("dateTime") Instant dateTime); @Query("SELECT COUNT(a) > 0 FROM AppointmentEntity a " + "JOIN a.treatment t " + @@ -68,5 +69,5 @@ List findPastAppointmentsBySpecialist( @Modifying @Query("UPDATE AppointmentEntity a SET a.status = :status WHERE a.id = :id") - int updateStatus(Long id, AppointmentStatus status); + void updateStatus(Long id, AppointmentStatus status); } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java index e38bf94..4793dd8 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java @@ -13,7 +13,7 @@ @Repository public interface ClientRepository extends JpaRepository { - default List findClientsByName(String firstName, String lastName, EntityManager entityManager) { + default List findByName(String firstName, String lastName, EntityManager entityManager) { JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager); QClientEntity client = QClientEntity.clientEntity; diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java index 84696dd..382134f 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java @@ -1,10 +1,13 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; -import org.springframework.stereotype.Repository; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; + +import java.util.List; -@Repository public interface CustomUserRepository { UserEntity findByEmail(String email); + + List findByCriteria(UserCriteria c); } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java index cdacf2d..6f38f1c 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java @@ -1,7 +1,9 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; -import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.*; +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -11,4 +13,18 @@ public interface SpecialistRepository extends JpaRepository { List findBySpecialization(Specialization specialization); + + default List findSpecialistByName(String firstName, String lastName, EntityManager entityManager) { + JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager); + + QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; + QUserEntity user = QUserEntity.userEntity; + + return queryFactory + .selectFrom(specialist) + .leftJoin(specialist.user, user) + .where(user.firstname.eq(firstName) + .and(user.lastname.eq(lastName))) + .fetch(); + } } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java index 7a1a7f4..8296c19 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -16,6 +16,10 @@ @Repository public interface TreatmentRepository extends JpaRepository { + List findAllByName(String name); + + List findByNameNamedQuery(String name); + default List findByCriteria(TreatmentCriteria c, EntityManager em) { Objects.requireNonNull(c, "SearchCriteria cannot be null"); diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java index b167473..bb9f41b 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java @@ -1,7 +1,9 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; -import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; -public interface UserRepository extends JpaRepository, CustomUserRepository { +@Repository +public interface UserRepository extends JpaRepository, CustomUserRepository { } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java new file mode 100644 index 0000000..d605b19 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java @@ -0,0 +1,4 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository.criteria; + +public record UserCriteria(String firstName, String lastName, String email) { +} \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java index a37dc7b..947e807 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java @@ -2,23 +2,28 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.CustomUserRepository; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; import jakarta.persistence.EntityManager; import jakarta.persistence.NoResultException; import jakarta.persistence.PersistenceContext; +import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + public class CustomUserRepositoryImpl implements CustomUserRepository { @PersistenceContext - private EntityManager entityManager; - + private EntityManager em; @Override public UserEntity findByEmail(String email) { - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); Root userRoot = criteriaQuery.from(UserEntity.class); @@ -26,9 +31,36 @@ public UserEntity findByEmail(String email) { criteriaQuery.where(emailPredicate); try { - return entityManager.createQuery(criteriaQuery).getSingleResult(); + return em.createQuery(criteriaQuery).getSingleResult(); } catch (NoResultException e) { return null; } } + + @Override + public List findByCriteria(UserCriteria c) { + Objects.requireNonNull(c, "Criteria cannot be null"); + + CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery(UserEntity.class); + Root root = criteriaQuery.from(UserEntity.class); + List predicateList = new ArrayList<>(); + + if (c.firstName() != null) { + predicateList.add(builder.like(root.get("firstName"), c.firstName())); + } + + if (c.lastName() != null) { + predicateList.add(builder.like(root.get("lastName"), c.lastName())); + } + + if (c.email() != null) { + predicateList.add(builder.like(root.get("email"), c.email())); + } + + Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); + criteriaQuery.where(predicateArray); + TypedQuery query = em.createQuery(criteriaQuery); + return query.getResultList(); + } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index 2497acf..97e86a9 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -29,7 +29,20 @@ public class AppointmentRepositoryTest { private EntityManager em; @Test - void testFindByCriteria_findAvailableTreatments() { + void testFindAll() { + //given when + List result = appointmentRepository.findAll(); + + //then + assertThat(result).isNotEmpty(); + assertThat(result).hasSize(20); + // Notice, that the number of objects are equal to entities inserted by mockdata script launched by flyway. + // We could also define separate test/resources migration scripts, but we won't do that! + // (let's spare the time, you can google it if you want) + } + + @Test + void testFindByCriteria_findAppointmentsByTreatmentName() { // given AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null); // when @@ -39,7 +52,7 @@ void testFindByCriteria_findAvailableTreatments() { } @Test - void testFindByCriteria_findAvailableTreatments2() { + void testFindByCriteria_findAppointmentsByTreatmentNameAndDate() { // given AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null); // when @@ -59,6 +72,17 @@ void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { assertThat(result).isNotEmpty().hasSize(2); } + @Test + void testFindByDateTimeBetweenAndStatus() { + Instant startDate = toInstant("2024-03-10 00:00:00"); + Instant endDate = toInstant("2024-03-14 23:59:59"); + AppointmentStatus status = AppointmentStatus.SCHEDULED; + // when + List result = appointmentRepository.findByDateTimeBetweenAndStatus(startDate, endDate, status); + // then + assertThat(result).isNotEmpty().hasSize(3); + assertThat(result).extracting(AppointmentEntity::getStatus).containsOnly(status); + }; @Test void testFindById() { diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java index 9efb5e1..b887929 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java @@ -29,7 +29,7 @@ void testFindByQueryDSL_testFindClientsByName() { String lastName = "Kowalski"; // when - List clients = clientRepository.findClientsByName(firstName, lastName, em); + List clients = clientRepository.findByName(firstName, lastName, em); // then assertThat(clients).isNotEmpty().hasSize(1); diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java index 2bdb068..8175dc9 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java @@ -2,6 +2,8 @@ import com.capgemini.training.appointmentbooking.common.datatype.Specialization; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @@ -9,6 +11,8 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; @DataJpaTest public class SpecialistRepositoryTest { @@ -16,6 +20,9 @@ public class SpecialistRepositoryTest { @Autowired private SpecialistRepository specialistRepository; + @PersistenceContext + private EntityManager em; + @Test void testFindBySpecialization() { // given @@ -31,4 +38,21 @@ void testFindBySpecialization() { .allMatch(specialist -> specialist.getSpecialization() == specialization, "Specialists should all have specialization " + specialization); } + + @Test + void testFindSpecialistByName() { + // given + String firstName = "Dobromir"; + String lastName = "Zegula"; + + // when + List specialists = specialistRepository.findSpecialistByName(firstName, lastName, em); + + // then + assertThat(specialists).isNotEmpty().hasSize(1); + SpecialistEntity specialist = specialists.getFirst(); + assertNotNull(specialist.getUser(), "Expected specialist to have an associated user"); + assertEquals(firstName, specialist.getUser().getFirstname(), "Expected specialist to have the specified first name"); + assertEquals(lastName, specialist.getUser().getLastname(), "Expected specialist to have the specified last name"); + } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java index fc7b94c..a59d574 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java @@ -28,6 +28,26 @@ public class TreatmentRepositoryTest { @PersistenceContext private EntityManager em; + @Test + void testFindAllByName() { + // given + String treatmentName = "Konsultacja dentystyczna"; + // when + List result = treatmentRepository.findAllByName(treatmentName); + // then + assertThat(result).isNotEmpty().hasSize(1); + } + + @Test + void testFindByNameNamedQuery() { + // given + String treatmentName = "Konsultacja dentystyczna"; + // when + List result = treatmentRepository.findByNameNamedQuery(treatmentName); + // then + assertThat(result).isNotEmpty().hasSize(1); + } + @Test void testFindByCriteria_findAllDentists() { // given From 39b642c0933d77a31fb2ac5c4c87299262314c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Tue, 11 Mar 2025 13:12:57 +0100 Subject: [PATCH 08/22] fix tests --- .../dataaccess/repository/AppointmentRepositoryTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index 97e86a9..36327aa 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -12,6 +12,7 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; @@ -82,7 +83,7 @@ void testFindByDateTimeBetweenAndStatus() { // then assertThat(result).isNotEmpty().hasSize(3); assertThat(result).extracting(AppointmentEntity::getStatus).containsOnly(status); - }; + } @Test void testFindById() { @@ -103,9 +104,9 @@ void testFindById() { } private Instant toInstant(String date) { - return LocalDateTime.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) - .atZone(ZoneId.of("Europe/Warsaw")) - .toInstant(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + ZonedDateTime zonedDateTime = LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()); + return zonedDateTime.toInstant(); } @Test From 62404924fc6797848ac9d38c58e543bbc2b2b76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Tue, 11 Mar 2025 14:52:40 +0100 Subject: [PATCH 09/22] refactoring --- .../repository/AppointmentRepository.java | 33 +++++------ .../repository/CustomUserRepository.java | 2 +- .../repository/TreatmentRepository.java | 16 +++--- .../criteria/AppointmentCriteria.java | 2 +- .../impl/CustomUserRepositoryImpl.java | 26 ++++----- .../repository/AppointmentRepositoryTest.java | 56 ++++++++++--------- .../repository/ClientRepositoryTest.java | 4 +- .../repository/SpecialistRepositoryTest.java | 4 +- .../repository/TreatmentRepositoryTest.java | 31 +++++++--- 9 files changed, 96 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index 6f269f4..79539e7 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -4,7 +4,8 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; -import jakarta.persistence.*; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.*; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -13,7 +14,6 @@ import org.springframework.stereotype.Repository; import java.time.Instant; -import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -22,31 +22,30 @@ @Repository public interface AppointmentRepository extends JpaRepository { - default List findByCriteria(AppointmentCriteria c, EntityManager em) { - Objects.requireNonNull(c, "SearchCriteria cannot be null"); + default List findByCriteria(AppointmentCriteria appointmentCriteria, EntityManager entityManager) { + Objects.requireNonNull(appointmentCriteria, "SearchCriteria cannot be null"); - CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery criteriaQuery = builder.createQuery(AppointmentEntity.class); Root root = criteriaQuery.from(AppointmentEntity.class); List predicateList = new ArrayList<>(); - if (c.treatmentName() != null) { + if (appointmentCriteria.treatmentName() != null) { Join treatmentJoin = root.join("treatment", JoinType.LEFT); - predicateList.add(builder.like(treatmentJoin.get("name"), c.treatmentName())); + predicateList.add(builder.like(treatmentJoin.get("name"), appointmentCriteria.treatmentName())); } - if (c.dateTime() != null) { - java.util.Date dateTime = java.util.Date.from(c.dateTime().atZone(ZoneOffset.UTC).toInstant()); - predicateList.add(builder.equal(root.get("dateTime"), dateTime)); + if (appointmentCriteria.date() != null) { + predicateList.add(builder.equal(root.get("dateTime"), appointmentCriteria.date())); } - if (c.status() != null) { - predicateList.add(builder.like(root.get("status"), c.status().name())); + if (appointmentCriteria.status() != null) { + predicateList.add(builder.like(root.get("status"), appointmentCriteria.status().name())); } Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); criteriaQuery.where(predicateArray); - TypedQuery query = em.createQuery(criteriaQuery); + TypedQuery query = entityManager.createQuery(criteriaQuery); return query.getResultList(); } @@ -55,17 +54,15 @@ default List findByCriteria(AppointmentCriteria c, EntityMana @Query("SELECT a FROM AppointmentEntity a " + "JOIN a.treatment t " + "WHERE t.specialist.id = :specialistId " + - "AND a.dateTime < :dateTime " + + "AND a.dateTime < :date " + "ORDER BY a.dateTime DESC") - List findPastAppointmentsBySpecialist( - @Param("specialistId") Long specialistId, - @Param("dateTime") Instant dateTime); + List findAppointmentsBySpecialistIdBeforeDate(@Param("specialistId") Long specialistId, @Param("date") Instant date); @Query("SELECT COUNT(a) > 0 FROM AppointmentEntity a " + "JOIN a.treatment t " + "WHERE t.specialist.id = :specialistId " + "AND a.dateTime = :currentTime") - boolean isConflictedAppointment(@Param("specialistId") Long specialistId, @Param("currentTime") Instant date); + boolean hasConflictingAppointmentBySpecialistIdAndDateTime(@Param("specialistId") Long specialistId, @Param("currentTime") Instant date); @Modifying @Query("UPDATE AppointmentEntity a SET a.status = :status WHERE a.id = :id") diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java index 382134f..4e79be3 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java @@ -9,5 +9,5 @@ public interface CustomUserRepository { UserEntity findByEmail(String email); - List findByCriteria(UserCriteria c); + List findByCriteria(UserCriteria userCriteria); } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java index 8296c19..d8c312d 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -20,26 +20,26 @@ public interface TreatmentRepository extends JpaRepository findByNameNamedQuery(String name); - default List findByCriteria(TreatmentCriteria c, EntityManager em) { - Objects.requireNonNull(c, "SearchCriteria cannot be null"); + default List findByCriteria(TreatmentCriteria treatmentCriteria, EntityManager entityManager) { + Objects.requireNonNull(treatmentCriteria, "SearchCriteria cannot be null"); - CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery criteriaQuery = builder.createQuery(TreatmentEntity.class); Root root = criteriaQuery.from(TreatmentEntity.class); List predicateList = new ArrayList<>(); - if (c.treatmentName() != null) { - predicateList.add(builder.like(root.get("name"), c.treatmentName())); + if (treatmentCriteria.treatmentName() != null) { + predicateList.add(builder.like(root.get("name"), treatmentCriteria.treatmentName())); } - if (c.specialization() != null) { + if (treatmentCriteria.specialization() != null) { Join specialistJoin = root.join("specialist", JoinType.LEFT); - predicateList.add(builder.like(specialistJoin.get("specialization"), c.specialization())); + predicateList.add(builder.like(specialistJoin.get("specialization"), treatmentCriteria.specialization())); } Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); criteriaQuery.where(predicateArray); - TypedQuery query = em.createQuery(criteriaQuery); + TypedQuery query = entityManager.createQuery(criteriaQuery); return query.getResultList(); } } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java index 9b9e02b..a27e5d8 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java @@ -4,5 +4,5 @@ import java.time.Instant; -public record AppointmentCriteria(String treatmentName, Instant dateTime, AppointmentStatus status) { +public record AppointmentCriteria(String treatmentName, Instant date, AppointmentStatus status) { } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java index 947e807..356d814 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java @@ -19,11 +19,11 @@ public class CustomUserRepositoryImpl implements CustomUserRepository { @PersistenceContext - private EntityManager em; + private EntityManager entityManager; @Override public UserEntity findByEmail(String email) { - CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); Root userRoot = criteriaQuery.from(UserEntity.class); @@ -31,36 +31,36 @@ public UserEntity findByEmail(String email) { criteriaQuery.where(emailPredicate); try { - return em.createQuery(criteriaQuery).getSingleResult(); + return entityManager.createQuery(criteriaQuery).getSingleResult(); } catch (NoResultException e) { return null; } } @Override - public List findByCriteria(UserCriteria c) { - Objects.requireNonNull(c, "Criteria cannot be null"); + public List findByCriteria(UserCriteria userCriteria) { + Objects.requireNonNull(userCriteria, "Criteria cannot be null"); - CriteriaBuilder builder = em.getCriteriaBuilder(); + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery criteriaQuery = builder.createQuery(UserEntity.class); Root root = criteriaQuery.from(UserEntity.class); List predicateList = new ArrayList<>(); - if (c.firstName() != null) { - predicateList.add(builder.like(root.get("firstName"), c.firstName())); + if (userCriteria.firstName() != null) { + predicateList.add(builder.like(root.get("firstName"), userCriteria.firstName())); } - if (c.lastName() != null) { - predicateList.add(builder.like(root.get("lastName"), c.lastName())); + if (userCriteria.lastName() != null) { + predicateList.add(builder.like(root.get("lastName"), userCriteria.lastName())); } - if (c.email() != null) { - predicateList.add(builder.like(root.get("email"), c.email())); + if (userCriteria.email() != null) { + predicateList.add(builder.like(root.get("email"), userCriteria.email())); } Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); criteriaQuery.where(predicateArray); - TypedQuery query = em.createQuery(criteriaQuery); + TypedQuery query = entityManager.createQuery(criteriaQuery); return query.getResultList(); } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index 36327aa..9471133 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -12,7 +12,6 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; -import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; @@ -27,27 +26,27 @@ public class AppointmentRepositoryTest { private AppointmentRepository appointmentRepository; @PersistenceContext - private EntityManager em; + private EntityManager entityManager; @Test void testFindAll() { - //given when + // given + // when List result = appointmentRepository.findAll(); - //then + // then assertThat(result).isNotEmpty(); assertThat(result).hasSize(20); - // Notice, that the number of objects are equal to entities inserted by mockdata script launched by flyway. - // We could also define separate test/resources migration scripts, but we won't do that! - // (let's spare the time, you can google it if you want) } @Test void testFindByCriteria_findAppointmentsByTreatmentName() { // given AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null); + // when - List result = appointmentRepository.findByCriteria(criteria, em); + List result = appointmentRepository.findByCriteria(criteria, entityManager); + // then assertThat(result).isNotEmpty().hasSize(2); } @@ -56,30 +55,41 @@ void testFindByCriteria_findAppointmentsByTreatmentName() { void testFindByCriteria_findAppointmentsByTreatmentNameAndDate() { // given AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null); + // when - List result = appointmentRepository.findByCriteria(criteria, em); + List result = appointmentRepository.findByCriteria(criteria, entityManager); + // then assertThat(result).isNotEmpty().hasSize(1); } + private Instant toInstant(String date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()).toInstant(); + } + @Test void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, AppointmentStatus.CANCELLED); + // when - List result = appointmentRepository.findByCriteria(criteria, em); + List result = appointmentRepository.findByCriteria(criteria, entityManager); + // then assertThat(result).isNotEmpty().hasSize(2); } @Test void testFindByDateTimeBetweenAndStatus() { + // given Instant startDate = toInstant("2024-03-10 00:00:00"); Instant endDate = toInstant("2024-03-14 23:59:59"); AppointmentStatus status = AppointmentStatus.SCHEDULED; + // when List result = appointmentRepository.findByDateTimeBetweenAndStatus(startDate, endDate, status); + // then assertThat(result).isNotEmpty().hasSize(3); assertThat(result).extracting(AppointmentEntity::getStatus).containsOnly(status); @@ -88,27 +98,23 @@ void testFindByDateTimeBetweenAndStatus() { @Test void testFindById() { // given + Long appointmentId = -1L; + // when - Optional result = appointmentRepository.findById(-1L); + Optional result = appointmentRepository.findById(appointmentId); // then assertTrue(result.isPresent(), "AppointmentEntity should be present"); AppointmentEntity appointment = result.get(); assertNotNull(appointment); - assertEquals(-1L, appointment.getId()); + assertEquals(appointmentId, appointment.getId()); assertEquals(AppointmentStatus.SCHEDULED, appointment.getStatus()); assertNotNull(appointment.getClient()); assertNotNull(appointment.getTreatment()); assertEquals(toInstant("2024-03-01 09:00:00"), appointment.getDateTime()); } - private Instant toInstant(String date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - ZonedDateTime zonedDateTime = LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()); - return zonedDateTime.toInstant(); - } - @Test void testUpdateStatus() { // given @@ -118,8 +124,8 @@ void testUpdateStatus() { // when appointmentRepository.updateStatus(appointment.get().getId(), AppointmentStatus.COMPLETED); - em.flush(); - em.clear(); + entityManager.flush(); + entityManager.clear(); // then appointment = appointmentRepository.findById(-1L); @@ -128,17 +134,17 @@ void testUpdateStatus() { } @Test - void testFindPastAppointments() { + void testFindAppointmentsBySpecialistIdBeforeDate() { // Given Long specialistId = -1L; Instant date = toInstant("2024-03-12 09:00:00"); // When - List appointments = appointmentRepository.findPastAppointmentsBySpecialist(specialistId, date); + List appointments = appointmentRepository.findAppointmentsBySpecialistIdBeforeDate(specialistId, date); // Then assertNotNull(appointments, "Appointments list should not be null"); - assertEquals(2, appointments.size(), "Expected 4 past appointments"); + assertEquals(2, appointments.size(), "Expected 2 past appointments"); appointments.forEach(a -> { assertEquals(specialistId, a.getTreatment().getSpecialist().getId(), "Appointment belongs to correct specialist"); assertTrue(a.getDateTime().isBefore(date), "Appointment should be in the past"); @@ -152,7 +158,7 @@ void testFindConflictedAppointments() { Instant date = toInstant("2024-03-05 11:45:00"); // When - boolean conflict = appointmentRepository.isConflictedAppointment(specialistId, date); + boolean conflict = appointmentRepository.hasConflictingAppointmentBySpecialistIdAndDateTime(specialistId, date); // Then assertTrue(conflict, "Should find conflicted appointments"); diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java index b887929..3451560 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java @@ -20,7 +20,7 @@ public class ClientRepositoryTest { private ClientRepository clientRepository; @PersistenceContext - private EntityManager em; + private EntityManager entityManager; @Test void testFindByQueryDSL_testFindClientsByName() { @@ -29,7 +29,7 @@ void testFindByQueryDSL_testFindClientsByName() { String lastName = "Kowalski"; // when - List clients = clientRepository.findByName(firstName, lastName, em); + List clients = clientRepository.findByName(firstName, lastName, entityManager); // then assertThat(clients).isNotEmpty().hasSize(1); diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java index 8175dc9..f483128 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java @@ -21,7 +21,7 @@ public class SpecialistRepositoryTest { private SpecialistRepository specialistRepository; @PersistenceContext - private EntityManager em; + private EntityManager entityManager; @Test void testFindBySpecialization() { @@ -46,7 +46,7 @@ void testFindSpecialistByName() { String lastName = "Zegula"; // when - List specialists = specialistRepository.findSpecialistByName(firstName, lastName, em); + List specialists = specialistRepository.findSpecialistByName(firstName, lastName, entityManager); // then assertThat(specialists).isNotEmpty().hasSize(1); diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java index a59d574..56afe9e 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java @@ -26,14 +26,16 @@ public class TreatmentRepositoryTest { private SpecialistRepository specialistRepository; @PersistenceContext - private EntityManager em; + private EntityManager entityManager; @Test void testFindAllByName() { // given String treatmentName = "Konsultacja dentystyczna"; + // when List result = treatmentRepository.findAllByName(treatmentName); + // then assertThat(result).isNotEmpty().hasSize(1); } @@ -42,8 +44,10 @@ void testFindAllByName() { void testFindByNameNamedQuery() { // given String treatmentName = "Konsultacja dentystyczna"; + // when List result = treatmentRepository.findByNameNamedQuery(treatmentName); + // then assertThat(result).isNotEmpty().hasSize(1); } @@ -52,8 +56,10 @@ void testFindByNameNamedQuery() { void testFindByCriteria_findAllDentists() { // given TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja dentystyczna", "Dentist"); + // when - List result = treatmentRepository.findByCriteria(criteria, em); + List result = treatmentRepository.findByCriteria(criteria, entityManager); + // then assertThat(result).isNotEmpty().hasSize(1); } @@ -62,8 +68,10 @@ void testFindByCriteria_findAllDentists() { void testFindByCriteria_findBySpecifiedTreatmentName() { // given TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja kardiologiczna", null); + // when - List result = treatmentRepository.findByCriteria(criteria, em); + List result = treatmentRepository.findByCriteria(criteria, entityManager); + // then assertThat(result).isNotEmpty().hasSize(1); } @@ -72,8 +80,10 @@ void testFindByCriteria_findBySpecifiedTreatmentName() { void testFindByCriteria_findAllPediatricians() { // given TreatmentCriteria criteria = new TreatmentCriteria(null, "Pediatrician"); + // when - List result = treatmentRepository.findByCriteria(criteria, em); + List result = treatmentRepository.findByCriteria(criteria, entityManager); + // then assertThat(result).isNotEmpty().hasSize(5); } @@ -82,8 +92,10 @@ void testFindByCriteria_findAllPediatricians() { void testFindByCriteria_findAvailableTreatments() { // given TreatmentCriteria criteria = new TreatmentCriteria(null, null); + // when - List result = treatmentRepository.findByCriteria(criteria, em); + List result = treatmentRepository.findByCriteria(criteria, entityManager); + // then assertThat(result).isNotEmpty().hasSize(12); } @@ -91,15 +103,17 @@ void testFindByCriteria_findAvailableTreatments() { @Test void testFindById() { // given + Long treatmentId = -1L; + // when - Optional result = treatmentRepository.findById(-1L); + Optional result = treatmentRepository.findById(treatmentId); // then assertTrue(result.isPresent(), "TreatmentEntity should be present"); TreatmentEntity treatment = result.get(); assertNotNull(treatment); - assertEquals(-1L, treatment.getId()); + assertEquals(treatmentId, treatment.getId()); assertEquals("Konsultacja dentystyczna", treatment.getName()); assertEquals("Konsultacja dentystyczna z diagnostyką i planem leczenia", treatment.getDescription()); assertEquals(30, treatment.getDurationMinutes()); @@ -115,7 +129,8 @@ void testFindById() { @Test void testSaveTreatment() { // given - Optional optionalSpecialist = specialistRepository.findById(-1L); + Long treatmentId = -1L; + Optional optionalSpecialist = specialistRepository.findById(treatmentId); assertTrue(optionalSpecialist.isPresent(), "SpecialistEntity should be present"); SpecialistEntity specialist = optionalSpecialist.get(); From 6a88f986530fe84f1c989a1d8744801680610c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Tue, 11 Mar 2025 19:37:25 +0100 Subject: [PATCH 10/22] refactoring --- .../repository/AppointmentRepository.java | 86 +++++++++++-------- .../criteria/AppointmentCriteria.java | 3 +- .../impl/CustomUserRepositoryImpl.java | 23 +++-- .../repository/AppointmentRepositoryTest.java | 55 +++++++----- 4 files changed, 96 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index 79539e7..7f68f9a 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -2,13 +2,13 @@ import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.*; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -17,54 +17,68 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; @Repository public interface AppointmentRepository extends JpaRepository { default List findByCriteria(AppointmentCriteria appointmentCriteria, EntityManager entityManager) { - Objects.requireNonNull(appointmentCriteria, "SearchCriteria cannot be null"); + Objects.requireNonNull(appointmentCriteria, "appointmentCriteria must not be null"); - CriteriaBuilder builder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = builder.createQuery(AppointmentEntity.class); - Root root = criteriaQuery.from(AppointmentEntity.class); - List predicateList = new ArrayList<>(); + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(AppointmentEntity.class); + Root root = cq.from(AppointmentEntity.class); + List predicates = new ArrayList<>(); - if (appointmentCriteria.treatmentName() != null) { - Join treatmentJoin = root.join("treatment", JoinType.LEFT); - predicateList.add(builder.like(treatmentJoin.get("name"), appointmentCriteria.treatmentName())); - } + Optional.ofNullable(appointmentCriteria.treatmentName()) + .map(String::trim) + .filter(name -> !name.isEmpty()) + .ifPresent(name -> { + Join treatmentJoin = root.join("treatment", JoinType.LEFT); + predicates.add(cb.like(cb.lower(treatmentJoin.get("name")), "%" + name.toLowerCase() + "%")); + }); - if (appointmentCriteria.date() != null) { - predicateList.add(builder.equal(root.get("dateTime"), appointmentCriteria.date())); - } + Optional.ofNullable(appointmentCriteria.date()) + .ifPresent(date -> predicates.add(cb.equal(root.get("dateTime"), date))); - if (appointmentCriteria.status() != null) { - predicateList.add(builder.like(root.get("status"), appointmentCriteria.status().name())); - } + Optional.ofNullable(appointmentCriteria.status()) + .ifPresent(status -> predicates.add(cb.equal(root.get("status"), status))); - Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); - criteriaQuery.where(predicateArray); - TypedQuery query = entityManager.createQuery(criteriaQuery); - return query.getResultList(); + Optional.ofNullable(appointmentCriteria.clientId()) + .ifPresent(clientId -> { + Join clientJoin = root.join("client", JoinType.LEFT); + predicates.add(cb.equal(clientJoin.get("id"), clientId)); + }); + + Optional.ofNullable(appointmentCriteria.specialistId()) + .ifPresent(specialistId -> { + Join treatmentJoin = root.join("treatment", JoinType.LEFT); + Join specialistJoin = treatmentJoin.join("specialist", JoinType.LEFT); + predicates.add(cb.equal(specialistJoin.get("id"), specialistId)); + }); + + cq.where(predicates.toArray(new Predicate[0])); + return entityManager.createQuery(cq).getResultList(); } List findByDateTimeBetweenAndStatus(Instant start, Instant end, AppointmentStatus status); - @Query("SELECT a FROM AppointmentEntity a " + - "JOIN a.treatment t " + - "WHERE t.specialist.id = :specialistId " + - "AND a.dateTime < :date " + - "ORDER BY a.dateTime DESC") + @Query(""" + SELECT a FROM AppointmentEntity a + JOIN a.treatment t + WHERE t.specialist.id = :specialistId + AND a.dateTime < :date + ORDER BY a.dateTime DESC + """) List findAppointmentsBySpecialistIdBeforeDate(@Param("specialistId") Long specialistId, @Param("date") Instant date); - @Query("SELECT COUNT(a) > 0 FROM AppointmentEntity a " + - "JOIN a.treatment t " + - "WHERE t.specialist.id = :specialistId " + - "AND a.dateTime = :currentTime") - boolean hasConflictingAppointmentBySpecialistIdAndDateTime(@Param("specialistId") Long specialistId, @Param("currentTime") Instant date); - - @Modifying - @Query("UPDATE AppointmentEntity a SET a.status = :status WHERE a.id = :id") - void updateStatus(Long id, AppointmentStatus status); -} + @Query(""" + SELECT CASE WHEN COUNT(a) > 0 THEN TRUE ELSE FALSE END + FROM AppointmentEntity a + JOIN a.treatment t + WHERE t.specialist.id = :specialistId + AND a.dateTime = :date + """) + boolean hasConflictingAppointmentBySpecialistIdAndDateTime(@Param("specialistId") Long specialistId, @Param("date") Instant date); +} \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java index a27e5d8..bde5371 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java @@ -4,5 +4,6 @@ import java.time.Instant; -public record AppointmentCriteria(String treatmentName, Instant date, AppointmentStatus status) { +public record AppointmentCriteria(String treatmentName, Instant date, AppointmentStatus status, Long clientId, + Long specialistId) { } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java index 356d814..5117d43 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java @@ -6,7 +6,6 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.NoResultException; import jakarta.persistence.PersistenceContext; -import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Predicate; @@ -39,28 +38,26 @@ public UserEntity findByEmail(String email) { @Override public List findByCriteria(UserCriteria userCriteria) { - Objects.requireNonNull(userCriteria, "Criteria cannot be null"); + Objects.requireNonNull(userCriteria, "userCriteria must not be null"); - CriteriaBuilder builder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = builder.createQuery(UserEntity.class); - Root root = criteriaQuery.from(UserEntity.class); - List predicateList = new ArrayList<>(); + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(UserEntity.class); + Root root = cq.from(UserEntity.class); + List predicates = new ArrayList<>(); if (userCriteria.firstName() != null) { - predicateList.add(builder.like(root.get("firstName"), userCriteria.firstName())); + predicates.add(cb.like(root.get("firstName"), userCriteria.firstName())); } if (userCriteria.lastName() != null) { - predicateList.add(builder.like(root.get("lastName"), userCriteria.lastName())); + predicates.add(cb.like(root.get("lastName"), userCriteria.lastName())); } if (userCriteria.email() != null) { - predicateList.add(builder.like(root.get("email"), userCriteria.email())); + predicates.add(cb.like(root.get("email"), userCriteria.email())); } - Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); - criteriaQuery.where(predicateArray); - TypedQuery query = entityManager.createQuery(criteriaQuery); - return query.getResultList(); + cq.where(predicates.toArray(new Predicate[0])); + return entityManager.createQuery(cq).getResultList(); } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index 9471133..5f923f7 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -2,6 +2,9 @@ import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; @@ -42,7 +45,7 @@ void testFindAll() { @Test void testFindByCriteria_findAppointmentsByTreatmentName() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null); + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null, null, null); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); @@ -54,7 +57,7 @@ void testFindByCriteria_findAppointmentsByTreatmentName() { @Test void testFindByCriteria_findAppointmentsByTreatmentNameAndDate() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null); + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null, null, null); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); @@ -71,7 +74,7 @@ private Instant toInstant(String date) { @Test void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, AppointmentStatus.CANCELLED); + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, AppointmentStatus.CANCELLED, null, null); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); @@ -80,6 +83,34 @@ void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { assertThat(result).isNotEmpty().hasSize(2); } + @Test + void testFindByCriteria_findAppointmentsByClientId() { + // given + Long clientId = -1L; + AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, clientId, null); + + // when + List result = appointmentRepository.findByCriteria(criteria, entityManager); + + // then + assertThat(result).isNotEmpty().hasSize(5); + assertThat(result).extracting(AppointmentEntity::getClient).extracting(ClientEntity::getId).containsOnly(clientId); + } + + @Test + void testFindByCriteria_findAppointmentsBySpecialistId() { + // given + Long specialistId = -1L; + AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, null, specialistId); + + // when + List result = appointmentRepository.findByCriteria(criteria, entityManager); + + // then + assertThat(result).isNotEmpty().hasSize(4); + assertThat(result).extracting(AppointmentEntity::getTreatment).extracting(TreatmentEntity::getSpecialist).extracting(SpecialistEntity::getId).containsOnly(specialistId); + } + @Test void testFindByDateTimeBetweenAndStatus() { // given @@ -115,24 +146,6 @@ void testFindById() { assertEquals(toInstant("2024-03-01 09:00:00"), appointment.getDateTime()); } - @Test - void testUpdateStatus() { - // given - Optional appointment = appointmentRepository.findById(-1L); - assertTrue(appointment.isPresent(), "AppointmentEntity should be present"); - assertEquals(AppointmentStatus.SCHEDULED, appointment.get().getStatus()); - - // when - appointmentRepository.updateStatus(appointment.get().getId(), AppointmentStatus.COMPLETED); - entityManager.flush(); - entityManager.clear(); - - // then - appointment = appointmentRepository.findById(-1L); - assertTrue(appointment.isPresent(), "AppointmentEntity should be present"); - assertEquals(AppointmentStatus.COMPLETED, appointment.get().getStatus()); - } - @Test void testFindAppointmentsBySpecialistIdBeforeDate() { // Given From afe32e0bff10bb83ecdd2906b182b37fdab85c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Tue, 11 Mar 2025 20:14:05 +0100 Subject: [PATCH 11/22] refactoring --- .../repository/AppointmentRepository.java | 11 ++++++-- .../repository/CustomUserRepository.java | 2 -- .../criteria/AppointmentCriteria.java | 4 +-- .../impl/CustomUserRepositoryImpl.java | 21 ++------------- .../repository/AppointmentRepositoryTest.java | 26 ++++++++++++++----- .../repository/UserRepositoryTest.java | 18 ++++++++++--- 6 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index 7f68f9a..8f3ad00 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -39,8 +39,15 @@ default List findByCriteria(AppointmentCriteria appointmentCr predicates.add(cb.like(cb.lower(treatmentJoin.get("name")), "%" + name.toLowerCase() + "%")); }); - Optional.ofNullable(appointmentCriteria.date()) - .ifPresent(date -> predicates.add(cb.equal(root.get("dateTime"), date))); + Optional.ofNullable(appointmentCriteria.startDate()) + .ifPresent(startDate -> { + predicates.add(cb.greaterThanOrEqualTo(root.get("dateTime"), startDate)); + }); + + Optional.ofNullable(appointmentCriteria.endDate()) + .ifPresent(endDate -> { + predicates.add(cb.lessThanOrEqualTo(root.get("dateTime"), endDate)); + }); Optional.ofNullable(appointmentCriteria.status()) .ifPresent(status -> predicates.add(cb.equal(root.get("status"), status))); diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java index 4e79be3..05e31cb 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java @@ -7,7 +7,5 @@ public interface CustomUserRepository { - UserEntity findByEmail(String email); - List findByCriteria(UserCriteria userCriteria); } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java index bde5371..9d9068c 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java @@ -4,6 +4,6 @@ import java.time.Instant; -public record AppointmentCriteria(String treatmentName, Instant date, AppointmentStatus status, Long clientId, - Long specialistId) { +public record AppointmentCriteria(String treatmentName, Instant startDate, Instant endDate, AppointmentStatus status, + Long clientId, Long specialistId) { } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java index 5117d43..e3e1517 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java @@ -4,7 +4,6 @@ import com.capgemini.training.appointmentbooking.dataaccess.repository.CustomUserRepository; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; import jakarta.persistence.EntityManager; -import jakarta.persistence.NoResultException; import jakarta.persistence.PersistenceContext; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; @@ -20,22 +19,6 @@ public class CustomUserRepositoryImpl implements CustomUserRepository { @PersistenceContext private EntityManager entityManager; - @Override - public UserEntity findByEmail(String email) { - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); - Root userRoot = criteriaQuery.from(UserEntity.class); - - Predicate emailPredicate = criteriaBuilder.equal(userRoot.get("email"), email); - criteriaQuery.where(emailPredicate); - - try { - return entityManager.createQuery(criteriaQuery).getSingleResult(); - } catch (NoResultException e) { - return null; - } - } - @Override public List findByCriteria(UserCriteria userCriteria) { Objects.requireNonNull(userCriteria, "userCriteria must not be null"); @@ -46,11 +29,11 @@ public List findByCriteria(UserCriteria userCriteria) { List predicates = new ArrayList<>(); if (userCriteria.firstName() != null) { - predicates.add(cb.like(root.get("firstName"), userCriteria.firstName())); + predicates.add(cb.like(root.get("firstname"), userCriteria.firstName())); } if (userCriteria.lastName() != null) { - predicates.add(cb.like(root.get("lastName"), userCriteria.lastName())); + predicates.add(cb.like(root.get("lastname"), userCriteria.lastName())); } if (userCriteria.email() != null) { diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index 5f923f7..4d6c93e 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -45,7 +45,7 @@ void testFindAll() { @Test void testFindByCriteria_findAppointmentsByTreatmentName() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null, null, null); + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null, null, null, null); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); @@ -55,15 +55,15 @@ void testFindByCriteria_findAppointmentsByTreatmentName() { } @Test - void testFindByCriteria_findAppointmentsByTreatmentNameAndDate() { + void testFindByCriteria_findAppointmentsByTreatmentNameAndStartDate() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null, null, null); + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null, null, null, null); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(1); + assertThat(result).isNotEmpty().hasSize(2); } private Instant toInstant(String date) { @@ -71,10 +71,22 @@ private Instant toInstant(String date) { return LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()).toInstant(); } + @Test + void testFindByCriteria_findAppointmentsByTreatmentNameAndBetweenStartDateAndEndDate() { + // given + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), toInstant("2024-03-03 15:00:00"), null, null, null); + + // when + List result = appointmentRepository.findByCriteria(criteria, entityManager); + + // then + assertThat(result).isNotEmpty().hasSize(1); + } + @Test void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, AppointmentStatus.CANCELLED, null, null); + AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null, AppointmentStatus.CANCELLED, null, null); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); @@ -87,7 +99,7 @@ void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { void testFindByCriteria_findAppointmentsByClientId() { // given Long clientId = -1L; - AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, clientId, null); + AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, null, clientId, null); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); @@ -101,7 +113,7 @@ void testFindByCriteria_findAppointmentsByClientId() { void testFindByCriteria_findAppointmentsBySpecialistId() { // given Long specialistId = -1L; - AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, null, specialistId); + AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, null, null, specialistId); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java index c3d9b3c..d0c059a 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java @@ -1,10 +1,14 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -15,15 +19,21 @@ public class UserRepositoryTest { private UserRepository userRepository; @Test - void testFindByEmail() { + void testFindByCriteria() { // given + String firstName = "Stefan"; + String lastName = "Kowalski"; String email = "stefan.kowalski@gmail.com"; + UserCriteria userCriteria = new UserCriteria(firstName, lastName, email); // when - UserEntity user = userRepository.findByEmail(email); + List users = userRepository.findByCriteria(userCriteria); // then - assertNotNull(user, "Expected user to be found"); - assertEquals(email, user.getEmail(), "Expected user to have the specified email"); + assertThat(users).isNotEmpty().hasSize(1); + UserEntity user = users.getFirst(); + assertNotNull(user, "Expected client to have an associated user"); + assertEquals(firstName, user.getFirstname(), "Expected user to have the specified first name"); + assertEquals(lastName, user.getLastname(), "Expected user to have the specified last name"); } } From b6e33879ef98a285c6711cb9838d14fed69317bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Tue, 11 Mar 2025 22:07:05 +0100 Subject: [PATCH 12/22] refactoring --- .../repository/TreatmentRepository.java | 35 ++++++++++--------- .../criteria/TreatmentCriteria.java | 4 ++- .../repository/TreatmentRepositoryTest.java | 4 +-- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java index d8c312d..3d049f5 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -1,15 +1,15 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; -import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.QSpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.QTreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQuery; import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; -import jakarta.persistence.criteria.*; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -21,25 +21,26 @@ public interface TreatmentRepository extends JpaRepository findByNameNamedQuery(String name); default List findByCriteria(TreatmentCriteria treatmentCriteria, EntityManager entityManager) { - Objects.requireNonNull(treatmentCriteria, "SearchCriteria cannot be null"); + Objects.requireNonNull(treatmentCriteria, "treatmentCriteria cannot be null"); - CriteriaBuilder builder = entityManager.getCriteriaBuilder(); - CriteriaQuery criteriaQuery = builder.createQuery(TreatmentEntity.class); - Root root = criteriaQuery.from(TreatmentEntity.class); - List predicateList = new ArrayList<>(); + QTreatmentEntity treatment = QTreatmentEntity.treatmentEntity; + QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; - if (treatmentCriteria.treatmentName() != null) { - predicateList.add(builder.like(root.get("name"), treatmentCriteria.treatmentName())); + JPAQuery query = new JPAQuery<>(entityManager); + BooleanExpression predicate = treatment.isNotNull(); + + if (treatmentCriteria.name() != null) { + predicate = predicate.and(treatment.name.like(treatmentCriteria.name())); } if (treatmentCriteria.specialization() != null) { - Join specialistJoin = root.join("specialist", JoinType.LEFT); - predicateList.add(builder.like(specialistJoin.get("specialization"), treatmentCriteria.specialization())); + predicate = predicate.and(specialist.specialization.eq(treatmentCriteria.specialization())); } - Predicate[] predicateArray = predicateList.toArray(new Predicate[0]); - criteriaQuery.where(predicateArray); - TypedQuery query = entityManager.createQuery(criteriaQuery); - return query.getResultList(); + return query.select(treatment) + .from(treatment) + .leftJoin(treatment.specialist, specialist) // Join with specialist + .where(predicate) + .fetch(); } } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java index 84e61a7..84dae40 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java @@ -1,4 +1,6 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository.criteria; -public record TreatmentCriteria(String treatmentName, String specialization) { +import com.capgemini.training.appointmentbooking.common.datatype.Specialization; + +public record TreatmentCriteria(String name, Specialization specialization) { } \ No newline at end of file diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java index 56afe9e..718f410 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java @@ -55,7 +55,7 @@ void testFindByNameNamedQuery() { @Test void testFindByCriteria_findAllDentists() { // given - TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja dentystyczna", "Dentist"); + TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja dentystyczna", Specialization.DENTIST); // when List result = treatmentRepository.findByCriteria(criteria, entityManager); @@ -79,7 +79,7 @@ void testFindByCriteria_findBySpecifiedTreatmentName() { @Test void testFindByCriteria_findAllPediatricians() { // given - TreatmentCriteria criteria = new TreatmentCriteria(null, "Pediatrician"); + TreatmentCriteria criteria = new TreatmentCriteria(null, Specialization.PEDIATRICIAN); // when List result = treatmentRepository.findByCriteria(criteria, entityManager); From 02d651feba0ba1c805d6c17ccfdd9315d537bffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Sat, 15 Mar 2025 15:09:51 +0100 Subject: [PATCH 13/22] add code review adjustments --- .../criteria/AppointmentCriteria.java | 2 + .../criteria/TreatmentCriteria.java | 2 + .../repository/criteria/UserCriteria.java | 3 + .../appointmentbooking/common/BaseTest.java | 6 + .../repository/AppointmentRepositoryTest.java | 119 ++++++++------- .../repository/ClientRepositoryTest.java | 21 ++- .../repository/SpecialistRepositoryTest.java | 24 ++-- .../repository/TreatmentRepositoryTest.java | 136 ++++++++++-------- .../repository/UserRepositoryTest.java | 28 ++-- 9 files changed, 192 insertions(+), 149 deletions(-) create mode 100644 src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java index 9d9068c..be9b96d 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java @@ -1,9 +1,11 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository.criteria; import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; +import lombok.Builder; import java.time.Instant; +@Builder public record AppointmentCriteria(String treatmentName, Instant startDate, Instant endDate, AppointmentStatus status, Long clientId, Long specialistId) { } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java index 84dae40..032a97f 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/TreatmentCriteria.java @@ -1,6 +1,8 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository.criteria; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import lombok.Builder; +@Builder public record TreatmentCriteria(String name, Specialization specialization) { } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java index d605b19..cdd1638 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/UserCriteria.java @@ -1,4 +1,7 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository.criteria; +import lombok.Builder; + +@Builder public record UserCriteria(String firstName, String lastName, String email) { } \ No newline at end of file diff --git a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java new file mode 100644 index 0000000..ee99d99 --- /dev/null +++ b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java @@ -0,0 +1,6 @@ +package com.capgemini.training.appointmentbooking.common; + +import org.assertj.core.api.WithAssertions; + +public class BaseTest implements WithAssertions { +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index 4d6c93e..31b89ba 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -1,5 +1,6 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; +import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; @@ -19,11 +20,8 @@ import java.util.List; import java.util.Optional; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; - @DataJpaTest -public class AppointmentRepositoryTest { +public class AppointmentRepositoryTest extends BaseTest { @Autowired private AppointmentRepository appointmentRepository; @@ -32,38 +30,44 @@ public class AppointmentRepositoryTest { private EntityManager entityManager; @Test - void testFindAll() { + void shouldFindAll() { // given // when List result = appointmentRepository.findAll(); // then - assertThat(result).isNotEmpty(); assertThat(result).hasSize(20); } @Test - void testFindByCriteria_findAppointmentsByTreatmentName() { + void shouldFindAppointmentsByTreatmentName() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null, null, null, null); + AppointmentCriteria criteria = AppointmentCriteria + .builder() + .treatmentName("Konsultacja pediatryczna") + .build(); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(2); + assertThat(result).hasSize(2); } @Test - void testFindByCriteria_findAppointmentsByTreatmentNameAndStartDate() { + void shouldFindAppointmentsByTreatmentNameAndStartDate() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), null, null, null, null); + AppointmentCriteria criteria = AppointmentCriteria + .builder() + .treatmentName("Konsultacja pediatryczna") + .startDate(toInstant("2024-03-03 14:00:00")) + .build(); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(2); + assertThat(result).hasSize(2); } private Instant toInstant(String date) { @@ -72,59 +76,74 @@ private Instant toInstant(String date) { } @Test - void testFindByCriteria_findAppointmentsByTreatmentNameAndBetweenStartDateAndEndDate() { + void shouldFindAppointmentsByTreatmentNameAndBetweenStartDateAndEndDate() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", toInstant("2024-03-03 14:00:00"), toInstant("2024-03-03 15:00:00"), null, null, null); + AppointmentCriteria criteria = AppointmentCriteria + .builder() + .treatmentName("Konsultacja pediatryczna") + .startDate(toInstant("2024-03-03 14:00:00")) + .endDate(toInstant("2024-03-03 15:00:00")) + .build(); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(1); + assertThat(result).hasSize(1); } @Test - void testFindByCriteria_findAppointmentsByTreatmentNameAndAppointmentStatus() { + void shouldFindAppointmentsByTreatmentNameAndAppointmentStatus() { // given - AppointmentCriteria criteria = new AppointmentCriteria("Konsultacja pediatryczna", null, null, AppointmentStatus.CANCELLED, null, null); + AppointmentCriteria criteria = AppointmentCriteria + .builder() + .treatmentName("Konsultacja pediatryczna") + .status(AppointmentStatus.CANCELLED) + .build(); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(2); + assertThat(result).hasSize(2); } @Test - void testFindByCriteria_findAppointmentsByClientId() { + void shouldFindAppointmentsByClientId() { // given Long clientId = -1L; - AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, null, clientId, null); + AppointmentCriteria criteria = AppointmentCriteria + .builder() + .clientId(clientId) + .build(); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(5); + assertThat(result).hasSize(5); assertThat(result).extracting(AppointmentEntity::getClient).extracting(ClientEntity::getId).containsOnly(clientId); } @Test - void testFindByCriteria_findAppointmentsBySpecialistId() { + void shouldFindAppointmentsBySpecialistId() { // given Long specialistId = -1L; - AppointmentCriteria criteria = new AppointmentCriteria(null, null, null, null, null, specialistId); + AppointmentCriteria criteria = AppointmentCriteria + .builder() + .specialistId(specialistId) + .build(); // when List result = appointmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(4); + assertThat(result).hasSize(4); assertThat(result).extracting(AppointmentEntity::getTreatment).extracting(TreatmentEntity::getSpecialist).extracting(SpecialistEntity::getId).containsOnly(specialistId); } @Test - void testFindByDateTimeBetweenAndStatus() { + void shouldFindAppointmentsByDateTimeBetweenAndStatus() { // given Instant startDate = toInstant("2024-03-10 00:00:00"); Instant endDate = toInstant("2024-03-14 23:59:59"); @@ -134,12 +153,12 @@ void testFindByDateTimeBetweenAndStatus() { List result = appointmentRepository.findByDateTimeBetweenAndStatus(startDate, endDate, status); // then - assertThat(result).isNotEmpty().hasSize(3); + assertThat(result).hasSize(3); assertThat(result).extracting(AppointmentEntity::getStatus).containsOnly(status); } @Test - void testFindById() { + void shouldFindAppointmentById() { // given Long appointmentId = -1L; @@ -147,45 +166,43 @@ void testFindById() { Optional result = appointmentRepository.findById(appointmentId); // then - assertTrue(result.isPresent(), "AppointmentEntity should be present"); - - AppointmentEntity appointment = result.get(); - assertNotNull(appointment); - assertEquals(appointmentId, appointment.getId()); - assertEquals(AppointmentStatus.SCHEDULED, appointment.getStatus()); - assertNotNull(appointment.getClient()); - assertNotNull(appointment.getTreatment()); - assertEquals(toInstant("2024-03-01 09:00:00"), appointment.getDateTime()); + assertThat(result).isPresent().hasValueSatisfying(appointment -> { + assertThat(appointment.getId()).isEqualTo(appointmentId); + assertThat(appointment.getStatus()).isEqualTo(AppointmentStatus.SCHEDULED); + assertThat(appointment.getClient()).isNotNull(); + assertThat(appointment.getTreatment()).isNotNull(); + assertThat(appointment.getDateTime()).isEqualTo(toInstant("2024-03-01 09:00:00")); + }); } @Test - void testFindAppointmentsBySpecialistIdBeforeDate() { - // Given + void shouldFindAppointmentsBySpecialistIdBeforeDate() { + // given Long specialistId = -1L; Instant date = toInstant("2024-03-12 09:00:00"); - // When + // when List appointments = appointmentRepository.findAppointmentsBySpecialistIdBeforeDate(specialistId, date); - // Then - assertNotNull(appointments, "Appointments list should not be null"); - assertEquals(2, appointments.size(), "Expected 2 past appointments"); - appointments.forEach(a -> { - assertEquals(specialistId, a.getTreatment().getSpecialist().getId(), "Appointment belongs to correct specialist"); - assertTrue(a.getDateTime().isBefore(date), "Appointment should be in the past"); - }); + // then + assertThat(appointments) + .hasSize(2) + .allMatch(a -> a.getTreatment().getSpecialist().getId().equals(specialistId), + "All appointments belong to the correct specialist") + .allMatch(a -> a.getDateTime().isBefore(date), + "All appointments should be before the given date"); } @Test - void testFindConflictedAppointments() { - // Given + void shouldFindConflictedAppointment() { + // given Long specialistId = -1L; Instant date = toInstant("2024-03-05 11:45:00"); - // When + // when boolean conflict = appointmentRepository.hasConflictingAppointmentBySpecialistIdAndDateTime(specialistId, date); - // Then - assertTrue(conflict, "Should find conflicted appointments"); + // then + assertThat(conflict).isTrue(); } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java index 3451560..e30cece 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java @@ -1,5 +1,6 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; +import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; @@ -9,12 +10,8 @@ import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - @DataJpaTest -public class ClientRepositoryTest { +public class ClientRepositoryTest extends BaseTest { @Autowired private ClientRepository clientRepository; @@ -23,7 +20,7 @@ public class ClientRepositoryTest { private EntityManager entityManager; @Test - void testFindByQueryDSL_testFindClientsByName() { + void shouldFindClientsByName() { // given String firstName = "Stefan"; String lastName = "Kowalski"; @@ -32,10 +29,12 @@ void testFindByQueryDSL_testFindClientsByName() { List clients = clientRepository.findByName(firstName, lastName, entityManager); // then - assertThat(clients).isNotEmpty().hasSize(1); - ClientEntity client = clients.getFirst(); - assertNotNull(client.getUser(), "Expected client to have an associated user"); - assertEquals(firstName, client.getUser().getFirstname(), "Expected client to have the specified first name"); - assertEquals(lastName, client.getUser().getLastname(), "Expected client to have the specified last name"); + assertThat(clients) + .hasSize(1) + .first() + .satisfies(client -> { + assertThat(client.getUser().getFirstname()).isEqualTo(firstName).as("Expected client to have the specified first name"); + assertThat(client.getUser().getLastname()).isEqualTo(lastName).as("Expected client to have the specified last name"); + }); } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java index f483128..304452f 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java @@ -1,5 +1,6 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; +import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import jakarta.persistence.EntityManager; @@ -10,12 +11,8 @@ import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - @DataJpaTest -public class SpecialistRepositoryTest { +public class SpecialistRepositoryTest extends BaseTest { @Autowired private SpecialistRepository specialistRepository; @@ -24,7 +21,7 @@ public class SpecialistRepositoryTest { private EntityManager entityManager; @Test - void testFindBySpecialization() { + void shouldFindSpecialistsBySpecialization() { // given Specialization specialization = Specialization.DENTIST; @@ -33,14 +30,13 @@ void testFindBySpecialization() { // then assertThat(specialists) - .isNotEmpty() .hasSize(1) .allMatch(specialist -> specialist.getSpecialization() == specialization, "Specialists should all have specialization " + specialization); } @Test - void testFindSpecialistByName() { + void shouldFindSpecialistsByName() { // given String firstName = "Dobromir"; String lastName = "Zegula"; @@ -49,10 +45,12 @@ void testFindSpecialistByName() { List specialists = specialistRepository.findSpecialistByName(firstName, lastName, entityManager); // then - assertThat(specialists).isNotEmpty().hasSize(1); - SpecialistEntity specialist = specialists.getFirst(); - assertNotNull(specialist.getUser(), "Expected specialist to have an associated user"); - assertEquals(firstName, specialist.getUser().getFirstname(), "Expected specialist to have the specified first name"); - assertEquals(lastName, specialist.getUser().getLastname(), "Expected specialist to have the specified last name"); + assertThat(specialists) + .hasSize(1) + .first() + .satisfies(specialist -> { + assertThat(specialist.getUser().getFirstname()).isEqualTo(firstName).as("Expected specialist to have the specified first name"); + assertThat(specialist.getUser().getLastname()).isEqualTo(lastName).as("Expected specialist to have the specified last name"); + }); } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java index 718f410..517bcce 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java @@ -1,5 +1,6 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; +import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; @@ -13,11 +14,8 @@ import java.util.List; import java.util.Optional; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; - @DataJpaTest -public class TreatmentRepositoryTest { +public class TreatmentRepositoryTest extends BaseTest { @Autowired private TreatmentRepository treatmentRepository; @@ -29,7 +27,7 @@ public class TreatmentRepositoryTest { private EntityManager entityManager; @Test - void testFindAllByName() { + void shouldFindTreatmentsByName() { // given String treatmentName = "Konsultacja dentystyczna"; @@ -37,11 +35,11 @@ void testFindAllByName() { List result = treatmentRepository.findAllByName(treatmentName); // then - assertThat(result).isNotEmpty().hasSize(1); + assertThat(result).hasSize(1); } @Test - void testFindByNameNamedQuery() { + void shouldFindTreatmentsByNameNamedQuery() { // given String treatmentName = "Konsultacja dentystyczna"; @@ -49,59 +47,71 @@ void testFindByNameNamedQuery() { List result = treatmentRepository.findByNameNamedQuery(treatmentName); // then - assertThat(result).isNotEmpty().hasSize(1); + assertThat(result).hasSize(1); } @Test - void testFindByCriteria_findAllDentists() { + void shouldFindTreatmentsByNameQueryDSL() { // given - TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja dentystyczna", Specialization.DENTIST); + TreatmentCriteria criteria = TreatmentCriteria + .builder() + .name("Konsultacja kardiologiczna") + .build(); // when List result = treatmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(1); + assertThat(result).hasSize(1); } @Test - void testFindByCriteria_findBySpecifiedTreatmentName() { + void shouldFindTreatmentsByNameAndSpecialization() { // given - TreatmentCriteria criteria = new TreatmentCriteria("Konsultacja kardiologiczna", null); + TreatmentCriteria criteria = TreatmentCriteria + .builder() + .name("Konsultacja dentystyczna") + .specialization(Specialization.DENTIST) + .build(); // when List result = treatmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(1); + assertThat(result).hasSize(1); } @Test - void testFindByCriteria_findAllPediatricians() { + void shouldFindTreatmentsBySpecialization() { // given - TreatmentCriteria criteria = new TreatmentCriteria(null, Specialization.PEDIATRICIAN); + TreatmentCriteria criteria = TreatmentCriteria + .builder() + .specialization(Specialization.PEDIATRICIAN) + .build(); // when List result = treatmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(5); + assertThat(result).hasSize(5); } @Test - void testFindByCriteria_findAvailableTreatments() { + void shouldFindAllTreatments() { // given - TreatmentCriteria criteria = new TreatmentCriteria(null, null); + TreatmentCriteria criteria = TreatmentCriteria + .builder() + .build(); // when List result = treatmentRepository.findByCriteria(criteria, entityManager); // then - assertThat(result).isNotEmpty().hasSize(12); + assertThat(result).hasSize(12); } @Test - void testFindById() { + void shouldFindTreatmentById() { // given Long treatmentId = -1L; @@ -109,53 +119,55 @@ void testFindById() { Optional result = treatmentRepository.findById(treatmentId); // then - assertTrue(result.isPresent(), "TreatmentEntity should be present"); - - TreatmentEntity treatment = result.get(); - assertNotNull(treatment); - assertEquals(treatmentId, treatment.getId()); - assertEquals("Konsultacja dentystyczna", treatment.getName()); - assertEquals("Konsultacja dentystyczna z diagnostyką i planem leczenia", treatment.getDescription()); - assertEquals(30, treatment.getDurationMinutes()); - - SpecialistEntity specialist = treatment.getSpecialist(); - assertNotNull(specialist, "Specialist should not be null"); - assertEquals(-1L, specialist.getId()); - assertNotNull(specialist.getUser(), "User should not be null"); - assertEquals(Specialization.DENTIST, specialist.getSpecialization()); - assertNotNull(specialist.getTreatments(), "Specialist treatments should not be null"); + assertThat(result) + .isPresent() + .hasValueSatisfying(treatment -> { + assertThat(treatment.getId()).isEqualTo(treatmentId); + assertThat(treatment.getName()).isEqualTo("Konsultacja dentystyczna"); + assertThat(treatment.getDescription()).isEqualTo("Konsultacja dentystyczna z diagnostyką i planem leczenia"); + assertThat(treatment.getDurationMinutes()).isEqualTo(30); + + SpecialistEntity specialist = treatment.getSpecialist(); + assertThat(specialist.getId()).isEqualTo(-1L); + assertThat(specialist.getUser()).isNotNull(); + assertThat(specialist.getSpecialization()).isEqualTo(Specialization.DENTIST); + assertThat(specialist.getTreatments()).isNotNull(); + }); } @Test - void testSaveTreatment() { + void shouldSaveTreatment() { // given Long treatmentId = -1L; Optional optionalSpecialist = specialistRepository.findById(treatmentId); - assertTrue(optionalSpecialist.isPresent(), "SpecialistEntity should be present"); - - SpecialistEntity specialist = optionalSpecialist.get(); - - TreatmentEntity treatmentEntity = new TreatmentEntity(); - treatmentEntity.setName("Wypełnienie ubytku"); - treatmentEntity.setDescription("Usunięcie próchnicy i wypełnienie zęba kompozytem"); - treatmentEntity.setDurationMinutes(45); - treatmentEntity.setSpecialist(specialist); - // when - TreatmentEntity result = treatmentRepository.save(treatmentEntity); - - // then - assertNotNull(result); - assertNotNull(result.getId(), "Saved entity should have an ID"); - assertEquals("Wypełnienie ubytku", result.getName()); - assertEquals("Usunięcie próchnicy i wypełnienie zęba kompozytem", result.getDescription()); - assertEquals(45, result.getDurationMinutes()); - - SpecialistEntity savedSpecialist = result.getSpecialist(); - assertNotNull(savedSpecialist, "Specialist should not be null"); - assertEquals(specialist.getId(), savedSpecialist.getId()); - assertNotNull(savedSpecialist.getUser(), "User should not be null"); - assertEquals(Specialization.DENTIST, savedSpecialist.getSpecialization()); - assertNotNull(savedSpecialist.getTreatments(), "Specialist treatments should not be null"); + assertThat(optionalSpecialist) + .isPresent() + .hasValueSatisfying(specialist -> { + TreatmentEntity treatmentEntity = new TreatmentEntity(); + treatmentEntity.setName("Wypełnienie ubytku"); + treatmentEntity.setDescription("Usunięcie próchnicy i wypełnienie zęba kompozytem"); + treatmentEntity.setDurationMinutes(45); + treatmentEntity.setSpecialist(specialist); + + // when + TreatmentEntity result = treatmentRepository.save(treatmentEntity); + + // then + assertThat(result.getId()).isEqualTo(1L); + assertThat(result.getName()).isEqualTo("Wypełnienie ubytku"); + assertThat(result.getDescription()).isEqualTo("Usunięcie próchnicy i wypełnienie zęba kompozytem"); + assertThat(result.getDurationMinutes()).isEqualTo(45); + + SpecialistEntity savedSpecialist = result.getSpecialist(); + assertThat(savedSpecialist) + .isNotNull() + .extracting(SpecialistEntity::getId) + .isEqualTo(specialist.getId()); + + assertThat(savedSpecialist.getUser()).isNotNull(); + assertThat(savedSpecialist.getSpecialization()).isEqualTo(Specialization.DENTIST); + assertThat(savedSpecialist.getTreatments()).isNotNull(); + }); } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java index d0c059a..82f5b92 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java @@ -1,5 +1,6 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; +import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; import org.junit.jupiter.api.Test; @@ -8,32 +9,35 @@ import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - @DataJpaTest -public class UserRepositoryTest { +public class UserRepositoryTest extends BaseTest { @Autowired private UserRepository userRepository; @Test - void testFindByCriteria() { + void shouldFindUsersByCriteria() { // given String firstName = "Stefan"; String lastName = "Kowalski"; String email = "stefan.kowalski@gmail.com"; - UserCriteria userCriteria = new UserCriteria(firstName, lastName, email); + UserCriteria userCriteria = UserCriteria + .builder() + .firstName(firstName) + .lastName(lastName) + .email(email) + .build(); // when List users = userRepository.findByCriteria(userCriteria); // then - assertThat(users).isNotEmpty().hasSize(1); - UserEntity user = users.getFirst(); - assertNotNull(user, "Expected client to have an associated user"); - assertEquals(firstName, user.getFirstname(), "Expected user to have the specified first name"); - assertEquals(lastName, user.getLastname(), "Expected user to have the specified last name"); + assertThat(users) + .hasSize(1) + .first() + .satisfies(user -> { + assertThat(user.getFirstname()).isEqualTo(firstName).as("Expected user to have the specified first name"); + assertThat(user.getLastname()).isEqualTo(lastName).as("Expected user to have the specified last name"); + }); } } From 125bbf69f88acf84bd9a4fddbb33bd0a8b6fcd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Sat, 15 Mar 2025 18:19:44 +0100 Subject: [PATCH 14/22] add toInstant in BaseTest --- .../training/appointmentbooking/common/BaseTest.java | 11 +++++++++++ .../repository/AppointmentRepositoryTest.java | 5 ----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java index ee99d99..41eabb7 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java @@ -2,5 +2,16 @@ import org.assertj.core.api.WithAssertions; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; + public class BaseTest implements WithAssertions { + + protected Instant toInstant(String date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()).toInstant(); + } + } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index 31b89ba..c023daa 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -70,11 +70,6 @@ void shouldFindAppointmentsByTreatmentNameAndStartDate() { assertThat(result).hasSize(2); } - private Instant toInstant(String date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - return LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()).toInstant(); - } - @Test void shouldFindAppointmentsByTreatmentNameAndBetweenStartDateAndEndDate() { // given From 116dc9ece9b34fdb52f4478b80174a7c7563296f Mon Sep 17 00:00:00 2001 From: MichalLuzyna Date: Sun, 16 Mar 2025 08:01:57 +0100 Subject: [PATCH 15/22] Introduced Base class for JPA repositories --- .../AppointmentBookingAppApplication.java | 3 +++ .../repository/AppointmentRepository.java | 19 ++++++---------- .../repository/BaseJpaRepository.java | 11 ++++++++++ .../repository/ClientRepository.java | 6 ++--- .../repository/SpecialistRepository.java | 14 +++++++----- .../repository/TreatmentRepository.java | 7 +++--- .../impl/BaseJpaRepositoryImpl.java | 22 +++++++++++++++++++ .../repository/AppointmentRepositoryTest.java | 19 +++++----------- .../repository/ClientRepositoryTest.java | 7 +----- .../repository/SpecialistRepositoryTest.java | 7 +----- .../repository/TreatmentRepositoryTest.java | 13 ++++------- 11 files changed, 69 insertions(+), 59 deletions(-) create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java diff --git a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java index 1639ccf..147a512 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java @@ -1,9 +1,12 @@ package com.capgemini.training.appointmentbooking; +import com.capgemini.training.appointmentbooking.dataaccess.repository.impl.BaseJpaRepositoryImpl; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication +@EnableJpaRepositories(repositoryBaseClass = BaseJpaRepositoryImpl.class) public class AppointmentBookingAppApplication { public static void main(String[] args) { diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index 8f3ad00..e06ba34 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -6,9 +6,7 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; -import jakarta.persistence.EntityManager; import jakarta.persistence.criteria.*; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -21,12 +19,12 @@ @Repository -public interface AppointmentRepository extends JpaRepository { +public interface AppointmentRepository extends BaseJpaRepository { - default List findByCriteria(AppointmentCriteria appointmentCriteria, EntityManager entityManager) { + default List findByCriteria(AppointmentCriteria appointmentCriteria) { Objects.requireNonNull(appointmentCriteria, "appointmentCriteria must not be null"); - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(AppointmentEntity.class); Root root = cq.from(AppointmentEntity.class); List predicates = new ArrayList<>(); @@ -40,14 +38,11 @@ default List findByCriteria(AppointmentCriteria appointmentCr }); Optional.ofNullable(appointmentCriteria.startDate()) - .ifPresent(startDate -> { - predicates.add(cb.greaterThanOrEqualTo(root.get("dateTime"), startDate)); - }); + .ifPresent(startDate -> predicates.add(cb.greaterThanOrEqualTo(root.get("dateTime"), startDate)) + ); Optional.ofNullable(appointmentCriteria.endDate()) - .ifPresent(endDate -> { - predicates.add(cb.lessThanOrEqualTo(root.get("dateTime"), endDate)); - }); + .ifPresent(endDate -> predicates.add(cb.lessThanOrEqualTo(root.get("dateTime"), endDate))); Optional.ofNullable(appointmentCriteria.status()) .ifPresent(status -> predicates.add(cb.equal(root.get("status"), status))); @@ -66,7 +61,7 @@ default List findByCriteria(AppointmentCriteria appointmentCr }); cq.where(predicates.toArray(new Predicate[0])); - return entityManager.createQuery(cq).getResultList(); + return getEntityManager().createQuery(cq).getResultList(); } List findByDateTimeBetweenAndStatus(Instant start, Instant end, AppointmentStatus status); diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java new file mode 100644 index 0000000..49cbc86 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java @@ -0,0 +1,11 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import jakarta.persistence.EntityManager; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation; +import org.springframework.data.repository.NoRepositoryBean; + +@NoRepositoryBean +public interface BaseJpaRepository extends JpaRepositoryImplementation { + EntityManager getEntityManager(); +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java index 4793dd8..d7e5817 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java @@ -11,10 +11,10 @@ import java.util.List; @Repository -public interface ClientRepository extends JpaRepository { +public interface ClientRepository extends BaseJpaRepository { - default List findByName(String firstName, String lastName, EntityManager entityManager) { - JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager); + default List findByName(String firstName, String lastName) { + JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager()); QClientEntity client = QClientEntity.clientEntity; QUserEntity user = QUserEntity.userEntity; diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java index 6f38f1c..bfb085e 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java @@ -1,21 +1,22 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; -import com.capgemini.training.appointmentbooking.dataaccess.entity.*; +import com.capgemini.training.appointmentbooking.dataaccess.entity.QSpecialistEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.QUserEntity; +import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.EntityManager; -import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.stereotype.Repository; import java.util.List; @Repository -public interface SpecialistRepository extends JpaRepository { +public interface SpecialistRepository extends BaseJpaRepository, QuerydslPredicateExecutor { List findBySpecialization(Specialization specialization); - default List findSpecialistByName(String firstName, String lastName, EntityManager entityManager) { - JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager); + default List findSpecialistByName(String firstName, String lastName) { + JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager()); QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; QUserEntity user = QUserEntity.userEntity; @@ -26,5 +27,6 @@ default List findSpecialistByName(String firstName, String las .where(user.firstname.eq(firstName) .and(user.lastname.eq(lastName))) .fetch(); + } } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java index 3d049f5..23aa44f 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -7,26 +7,25 @@ import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; import jakarta.persistence.EntityManager; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.List; import java.util.Objects; @Repository -public interface TreatmentRepository extends JpaRepository { +public interface TreatmentRepository extends BaseJpaRepository { List findAllByName(String name); List findByNameNamedQuery(String name); - default List findByCriteria(TreatmentCriteria treatmentCriteria, EntityManager entityManager) { + default List findByCriteria(TreatmentCriteria treatmentCriteria) { Objects.requireNonNull(treatmentCriteria, "treatmentCriteria cannot be null"); QTreatmentEntity treatment = QTreatmentEntity.treatmentEntity; QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; - JPAQuery query = new JPAQuery<>(entityManager); + JPAQuery query = new JPAQuery<>(getEntityManager()); BooleanExpression predicate = treatment.isNotNull(); if (treatmentCriteria.name() != null) { diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java new file mode 100644 index 0000000..8d55b04 --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java @@ -0,0 +1,22 @@ +package com.capgemini.training.appointmentbooking.dataaccess.repository.impl; + +import com.capgemini.training.appointmentbooking.dataaccess.repository.BaseJpaRepository; +import jakarta.persistence.EntityManager; +import org.springframework.data.jpa.repository.support.JpaEntityInformation; +import org.springframework.data.jpa.repository.support.SimpleJpaRepository; +import org.springframework.stereotype.Repository; + +public class BaseJpaRepositoryImpl extends SimpleJpaRepository implements BaseJpaRepository { + + private final EntityManager entityManager; + + BaseJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { + super(entityInformation, entityManager); + this.entityManager = entityManager; + } + + @Override + public EntityManager getEntityManager(){ + return this.entityManager; + } +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java index c023daa..3e2ea5d 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java @@ -7,16 +7,11 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; @@ -26,8 +21,6 @@ public class AppointmentRepositoryTest extends BaseTest { @Autowired private AppointmentRepository appointmentRepository; - @PersistenceContext - private EntityManager entityManager; @Test void shouldFindAll() { @@ -48,7 +41,7 @@ void shouldFindAppointmentsByTreatmentName() { .build(); // when - List result = appointmentRepository.findByCriteria(criteria, entityManager); + List result = appointmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(2); @@ -64,7 +57,7 @@ void shouldFindAppointmentsByTreatmentNameAndStartDate() { .build(); // when - List result = appointmentRepository.findByCriteria(criteria, entityManager); + List result = appointmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(2); @@ -81,7 +74,7 @@ void shouldFindAppointmentsByTreatmentNameAndBetweenStartDateAndEndDate() { .build(); // when - List result = appointmentRepository.findByCriteria(criteria, entityManager); + List result = appointmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(1); @@ -97,7 +90,7 @@ void shouldFindAppointmentsByTreatmentNameAndAppointmentStatus() { .build(); // when - List result = appointmentRepository.findByCriteria(criteria, entityManager); + List result = appointmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(2); @@ -113,7 +106,7 @@ void shouldFindAppointmentsByClientId() { .build(); // when - List result = appointmentRepository.findByCriteria(criteria, entityManager); + List result = appointmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(5); @@ -130,7 +123,7 @@ void shouldFindAppointmentsBySpecialistId() { .build(); // when - List result = appointmentRepository.findByCriteria(criteria, entityManager); + List result = appointmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(4); diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java index e30cece..6a4c9fc 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java @@ -2,8 +2,6 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @@ -16,9 +14,6 @@ public class ClientRepositoryTest extends BaseTest { @Autowired private ClientRepository clientRepository; - @PersistenceContext - private EntityManager entityManager; - @Test void shouldFindClientsByName() { // given @@ -26,7 +21,7 @@ void shouldFindClientsByName() { String lastName = "Kowalski"; // when - List clients = clientRepository.findByName(firstName, lastName, entityManager); + List clients = clientRepository.findByName(firstName, lastName); // then assertThat(clients) diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java index 304452f..2c15ec8 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java @@ -3,8 +3,6 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @@ -17,9 +15,6 @@ public class SpecialistRepositoryTest extends BaseTest { @Autowired private SpecialistRepository specialistRepository; - @PersistenceContext - private EntityManager entityManager; - @Test void shouldFindSpecialistsBySpecialization() { // given @@ -42,7 +37,7 @@ void shouldFindSpecialistsByName() { String lastName = "Zegula"; // when - List specialists = specialistRepository.findSpecialistByName(firstName, lastName, entityManager); + List specialists = specialistRepository.findSpecialistByName(firstName, lastName); // then assertThat(specialists) diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java index 517bcce..07cbdcd 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java @@ -5,8 +5,6 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @@ -23,9 +21,6 @@ public class TreatmentRepositoryTest extends BaseTest { @Autowired private SpecialistRepository specialistRepository; - @PersistenceContext - private EntityManager entityManager; - @Test void shouldFindTreatmentsByName() { // given @@ -59,7 +54,7 @@ void shouldFindTreatmentsByNameQueryDSL() { .build(); // when - List result = treatmentRepository.findByCriteria(criteria, entityManager); + List result = treatmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(1); @@ -75,7 +70,7 @@ void shouldFindTreatmentsByNameAndSpecialization() { .build(); // when - List result = treatmentRepository.findByCriteria(criteria, entityManager); + List result = treatmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(1); @@ -90,7 +85,7 @@ void shouldFindTreatmentsBySpecialization() { .build(); // when - List result = treatmentRepository.findByCriteria(criteria, entityManager); + List result = treatmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(5); @@ -104,7 +99,7 @@ void shouldFindAllTreatments() { .build(); // when - List result = treatmentRepository.findByCriteria(criteria, entityManager); + List result = treatmentRepository.findByCriteria(criteria); // then assertThat(result).hasSize(12); From 6242eb9879780e4f39c6e596176bc1baf5feb2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Sun, 16 Mar 2025 12:27:23 +0100 Subject: [PATCH 16/22] add code review adjustments --- .../repository/BaseJpaRepository.java | 22 +++++----- .../impl/BaseJpaRepositoryImpl.java | 44 +++++++++---------- src/main/resources/banner/jbf_banner.txt | 14 +++--- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java index 49cbc86..8399712 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java @@ -1,11 +1,11 @@ -package com.capgemini.training.appointmentbooking.dataaccess.repository; - -import jakarta.persistence.EntityManager; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation; -import org.springframework.data.repository.NoRepositoryBean; - -@NoRepositoryBean -public interface BaseJpaRepository extends JpaRepositoryImplementation { - EntityManager getEntityManager(); -} +package com.capgemini.training.appointmentbooking.dataaccess.repository; + +import jakarta.persistence.EntityManager; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation; +import org.springframework.data.repository.NoRepositoryBean; + +@NoRepositoryBean +public interface BaseJpaRepository extends JpaRepositoryImplementation { + EntityManager getEntityManager(); +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java index 8d55b04..d9f97dc 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java @@ -1,22 +1,22 @@ -package com.capgemini.training.appointmentbooking.dataaccess.repository.impl; - -import com.capgemini.training.appointmentbooking.dataaccess.repository.BaseJpaRepository; -import jakarta.persistence.EntityManager; -import org.springframework.data.jpa.repository.support.JpaEntityInformation; -import org.springframework.data.jpa.repository.support.SimpleJpaRepository; -import org.springframework.stereotype.Repository; - -public class BaseJpaRepositoryImpl extends SimpleJpaRepository implements BaseJpaRepository { - - private final EntityManager entityManager; - - BaseJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { - super(entityInformation, entityManager); - this.entityManager = entityManager; - } - - @Override - public EntityManager getEntityManager(){ - return this.entityManager; - } -} +package com.capgemini.training.appointmentbooking.dataaccess.repository.impl; + +import com.capgemini.training.appointmentbooking.dataaccess.repository.BaseJpaRepository; +import jakarta.persistence.EntityManager; +import org.springframework.data.jpa.repository.support.JpaEntityInformation; +import org.springframework.data.jpa.repository.support.SimpleJpaRepository; +import org.springframework.stereotype.Repository; + +public class BaseJpaRepositoryImpl extends SimpleJpaRepository implements BaseJpaRepository { + + private final EntityManager entityManager; + + BaseJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { + super(entityInformation, entityManager); + this.entityManager = entityManager; + } + + @Override + public EntityManager getEntityManager(){ + return this.entityManager; + } +} diff --git a/src/main/resources/banner/jbf_banner.txt b/src/main/resources/banner/jbf_banner.txt index a39f9ef..32241af 100644 --- a/src/main/resources/banner/jbf_banner.txt +++ b/src/main/resources/banner/jbf_banner.txt @@ -1,8 +1,8 @@ - ,--. ,-----. ,--. ,--. ,------. ,--. ,--. ,--. - | | ,--,--.,--. ,--.,--,--. | |) /_ ,--,--.,---.| |,-. ,---. ,--,--, ,-| | | .---',--.,--.,--,--, ,-| | ,--,--.,-' '-.`--' ,---. ,--,--, -,--. | |' ,-. | \ `' /' ,-. | | .-. \' ,-. | .--'| /| .-. :| \' .-. | | `--, | || || \' .-. |' ,-. |'-. .-',--.| .-. || \ -| '-' /\ '-' | \ / \ '-' | | '--' /\ '-' \ `--.| \ \\ --.| || |\ `-' | | |` ' '' '| || |\ `-' |\ '-' | | | | |' '-' '| || | - `-----' `--`--' `--' `--`--' `------' `--`--'`---'`--'`--'`----'`--''--' `---' `--' `----' `--''--' `---' `--`--' `--' `--' `---' `--''--' - -${application.title} ${application.version} + ,--. ,-----. ,--. ,--. ,------. ,--. ,--. ,--. + | | ,--,--.,--. ,--.,--,--. | |) /_ ,--,--.,---.| |,-. ,---. ,--,--, ,-| | | .---',--.,--.,--,--, ,-| | ,--,--.,-' '-.`--' ,---. ,--,--, +,--. | |' ,-. | \ `' /' ,-. | | .-. \' ,-. | .--'| /| .-. :| \' .-. | | `--, | || || \' .-. |' ,-. |'-. .-',--.| .-. || \ +| '-' /\ '-' | \ / \ '-' | | '--' /\ '-' \ `--.| \ \\ --.| || |\ `-' | | |` ' '' '| || |\ `-' |\ '-' | | | | |' '-' '| || | + `-----' `--`--' `--' `--`--' `------' `--`--'`---'`--'`--'`----'`--''--' `---' `--' `----' `--''--' `---' `--`--' `--' `--' `---' `--''--' + +${application.title} ${application.version} Powered by Spring Boot ${spring-boot.version} \ No newline at end of file From cef2c50d4e77ce11cf1552bc2a88e969dc82e493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Sun, 16 Mar 2025 12:27:23 +0100 Subject: [PATCH 17/22] add code review adjustments --- .../repository/AppointmentRepository.java | 63 +++++++++---------- .../repository/BaseJpaRepository.java | 4 +- .../repository/ClientRepository.java | 3 +- .../repository/CustomUserRepository.java | 11 ---- .../repository/SpecialistRepository.java | 1 + .../repository/TreatmentRepository.java | 2 +- .../dataaccess/repository/UserRepository.java | 39 +++++++++++- .../impl/BaseJpaRepositoryImpl.java | 8 +-- .../impl/CustomUserRepositoryImpl.java | 46 -------------- 9 files changed, 77 insertions(+), 100 deletions(-) delete mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java delete mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index e06ba34..53927f1 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -15,50 +15,46 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Optional; @Repository public interface AppointmentRepository extends BaseJpaRepository { - default List findByCriteria(AppointmentCriteria appointmentCriteria) { - Objects.requireNonNull(appointmentCriteria, "appointmentCriteria must not be null"); + default List findByCriteria(AppointmentCriteria criteria) { + Objects.requireNonNull(criteria, "criteria must not be null"); CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(AppointmentEntity.class); Root root = cq.from(AppointmentEntity.class); List predicates = new ArrayList<>(); - Optional.ofNullable(appointmentCriteria.treatmentName()) - .map(String::trim) - .filter(name -> !name.isEmpty()) - .ifPresent(name -> { - Join treatmentJoin = root.join("treatment", JoinType.LEFT); - predicates.add(cb.like(cb.lower(treatmentJoin.get("name")), "%" + name.toLowerCase() + "%")); - }); - - Optional.ofNullable(appointmentCriteria.startDate()) - .ifPresent(startDate -> predicates.add(cb.greaterThanOrEqualTo(root.get("dateTime"), startDate)) - ); - - Optional.ofNullable(appointmentCriteria.endDate()) - .ifPresent(endDate -> predicates.add(cb.lessThanOrEqualTo(root.get("dateTime"), endDate))); - - Optional.ofNullable(appointmentCriteria.status()) - .ifPresent(status -> predicates.add(cb.equal(root.get("status"), status))); - - Optional.ofNullable(appointmentCriteria.clientId()) - .ifPresent(clientId -> { - Join clientJoin = root.join("client", JoinType.LEFT); - predicates.add(cb.equal(clientJoin.get("id"), clientId)); - }); - - Optional.ofNullable(appointmentCriteria.specialistId()) - .ifPresent(specialistId -> { - Join treatmentJoin = root.join("treatment", JoinType.LEFT); - Join specialistJoin = treatmentJoin.join("specialist", JoinType.LEFT); - predicates.add(cb.equal(specialistJoin.get("id"), specialistId)); - }); + if (criteria.treatmentName() != null && !criteria.treatmentName().trim().isEmpty()) { + Join treatmentJoin = root.join("treatment", JoinType.LEFT); + predicates.add(cb.like(cb.lower(treatmentJoin.get("name")), "%" + criteria.treatmentName().trim().toLowerCase() + "%")); + } + + if (criteria.startDate() != null) { + predicates.add(cb.greaterThanOrEqualTo(root.get("dateTime"), criteria.startDate())); + } + + if (criteria.endDate() != null) { + predicates.add(cb.lessThanOrEqualTo(root.get("dateTime"), criteria.endDate())); + } + + if (criteria.status() != null) { + predicates.add(cb.equal(root.get("status"), criteria.status())); + } + + if (criteria.clientId() != null) { + Join clientJoin = root.join("client", JoinType.LEFT); + predicates.add(cb.equal(clientJoin.get("id"), criteria.clientId())); + } + + if (criteria.specialistId() != null) { + Join treatmentJoin = root.join("treatment", JoinType.LEFT); + Join specialistJoin = treatmentJoin.join("specialist", JoinType.LEFT); + predicates.add(cb.equal(specialistJoin.get("id"), criteria.specialistId())); + } cq.where(predicates.toArray(new Predicate[0])); return getEntityManager().createQuery(cq).getResultList(); @@ -83,4 +79,5 @@ SELECT CASE WHEN COUNT(a) > 0 THEN TRUE ELSE FALSE END AND a.dateTime = :date """) boolean hasConflictingAppointmentBySpecialistIdAndDateTime(@Param("specialistId") Long specialistId, @Param("date") Instant date); + } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java index 8399712..bf056a4 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java @@ -7,5 +7,7 @@ @NoRepositoryBean public interface BaseJpaRepository extends JpaRepositoryImplementation { + EntityManager getEntityManager(); -} + +} \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java index d7e5817..14140ac 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java @@ -4,8 +4,6 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.QClientEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.QUserEntity; import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.EntityManager; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.List; @@ -26,4 +24,5 @@ default List findByName(String firstName, String lastName) { .and(user.lastname.eq(lastName))) .fetch(); } + } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java deleted file mode 100644 index 05e31cb..0000000 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/CustomUserRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.capgemini.training.appointmentbooking.dataaccess.repository; - -import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; -import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; - -import java.util.List; - -public interface CustomUserRepository { - - List findByCriteria(UserCriteria userCriteria); -} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java index bfb085e..86925ef 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java @@ -29,4 +29,5 @@ default List findSpecialistByName(String firstName, String las .fetch(); } + } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java index 23aa44f..8479256 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -6,7 +6,6 @@ import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; -import jakarta.persistence.EntityManager; import org.springframework.stereotype.Repository; import java.util.List; @@ -42,4 +41,5 @@ default List findByCriteria(TreatmentCriteria treatmentCriteria .where(predicate) .fetch(); } + } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java index bb9f41b..75d3412 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java @@ -1,9 +1,44 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; -import org.springframework.data.jpa.repository.JpaRepository; +import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; +import jakarta.persistence.EntityManager; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import org.springframework.stereotype.Repository; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + @Repository -public interface UserRepository extends JpaRepository, CustomUserRepository { +public interface UserRepository extends BaseJpaRepository { + + default List findByCriteria(UserCriteria criteria) { + Objects.requireNonNull(criteria, "criteria must not be null"); + + EntityManager entityManager = getEntityManager(); + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(UserEntity.class); + Root root = cq.from(UserEntity.class); + List predicates = new ArrayList<>(); + + if (criteria.firstName() != null) { + predicates.add(cb.like(root.get("firstname"), criteria.firstName())); + } + + if (criteria.lastName() != null) { + predicates.add(cb.like(root.get("lastname"), criteria.lastName())); + } + + if (criteria.email() != null) { + predicates.add(cb.like(root.get("email"), criteria.email())); + } + + cq.where(predicates.toArray(new Predicate[0])); + return entityManager.createQuery(cq).getResultList(); + } + } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java index d9f97dc..4cf6f71 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java @@ -4,9 +4,8 @@ import jakarta.persistence.EntityManager; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.SimpleJpaRepository; -import org.springframework.stereotype.Repository; -public class BaseJpaRepositoryImpl extends SimpleJpaRepository implements BaseJpaRepository { +public class BaseJpaRepositoryImpl extends SimpleJpaRepository implements BaseJpaRepository { private final EntityManager entityManager; @@ -16,7 +15,8 @@ public class BaseJpaRepositoryImpl extends SimpleJpaRepository i } @Override - public EntityManager getEntityManager(){ + public EntityManager getEntityManager() { return this.entityManager; } -} + +} \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java deleted file mode 100644 index e3e1517..0000000 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/CustomUserRepositoryImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.capgemini.training.appointmentbooking.dataaccess.repository.impl; - -import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; -import com.capgemini.training.appointmentbooking.dataaccess.repository.CustomUserRepository; -import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Predicate; -import jakarta.persistence.criteria.Root; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class CustomUserRepositoryImpl implements CustomUserRepository { - - @PersistenceContext - private EntityManager entityManager; - - @Override - public List findByCriteria(UserCriteria userCriteria) { - Objects.requireNonNull(userCriteria, "userCriteria must not be null"); - - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(UserEntity.class); - Root root = cq.from(UserEntity.class); - List predicates = new ArrayList<>(); - - if (userCriteria.firstName() != null) { - predicates.add(cb.like(root.get("firstname"), userCriteria.firstName())); - } - - if (userCriteria.lastName() != null) { - predicates.add(cb.like(root.get("lastname"), userCriteria.lastName())); - } - - if (userCriteria.email() != null) { - predicates.add(cb.like(root.get("email"), userCriteria.email())); - } - - cq.where(predicates.toArray(new Predicate[0])); - return entityManager.createQuery(cq).getResultList(); - } -} From 727b37238a86699014b29b456fa65ab6c8a7ae4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Mon, 17 Mar 2025 10:04:11 +0100 Subject: [PATCH 18/22] add @Inject, update pom.xml --- pom.xml | 34 +++++++++++++++++++ ....java => AppointmentRepositoryTestIT.java} | 6 ++-- ...yTest.java => ClientRepositoryTestIT.java} | 6 ++-- ...t.java => SpecialistRepositoryTestIT.java} | 6 ++-- ...st.java => TreatmentRepositoryTestIT.java} | 8 ++--- ...oryTest.java => UserRepositoryTestIT.java} | 6 ++-- 6 files changed, 50 insertions(+), 16 deletions(-) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{AppointmentRepositoryTest.java => AppointmentRepositoryTestIT.java} (97%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{ClientRepositoryTest.java => ClientRepositoryTestIT.java} (89%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{SpecialistRepositoryTest.java => SpecialistRepositoryTestIT.java} (92%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{TreatmentRepositoryTest.java => TreatmentRepositoryTestIT.java} (97%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{UserRepositoryTest.java => UserRepositoryTestIT.java} (91%) diff --git a/pom.xml b/pom.xml index 142059b..9694756 100644 --- a/pom.xml +++ b/pom.xml @@ -101,6 +101,40 @@ false + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.5.2 + + + + integration-test + verify + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.5.2 + + + verify + + report-only + + + + + true + + com.mysema.maven apt-maven-plugin diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java similarity index 97% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java index 3e2ea5d..e9d2e3a 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java @@ -7,8 +7,8 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; +import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import java.time.Instant; @@ -16,9 +16,9 @@ import java.util.Optional; @DataJpaTest -public class AppointmentRepositoryTest extends BaseTest { +public class AppointmentRepositoryTestIT extends BaseTest { - @Autowired + @Inject private AppointmentRepository appointmentRepository; diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java similarity index 89% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java index 6a4c9fc..22e1777 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java @@ -2,16 +2,16 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; +import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import java.util.List; @DataJpaTest -public class ClientRepositoryTest extends BaseTest { +public class ClientRepositoryTestIT extends BaseTest { - @Autowired + @Inject private ClientRepository clientRepository; @Test diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java similarity index 92% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java index 2c15ec8..b5aec30 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java @@ -3,16 +3,16 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; +import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import java.util.List; @DataJpaTest -public class SpecialistRepositoryTest extends BaseTest { +public class SpecialistRepositoryTestIT extends BaseTest { - @Autowired + @Inject private SpecialistRepository specialistRepository; @Test diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java similarity index 97% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java index 07cbdcd..fc53725 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java @@ -5,20 +5,20 @@ import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; +import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import java.util.List; import java.util.Optional; @DataJpaTest -public class TreatmentRepositoryTest extends BaseTest { +public class TreatmentRepositoryTestIT extends BaseTest { - @Autowired + @Inject private TreatmentRepository treatmentRepository; - @Autowired + @Inject private SpecialistRepository specialistRepository; @Test diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java similarity index 91% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java index 82f5b92..58483aa 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java @@ -3,16 +3,16 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; +import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import java.util.List; @DataJpaTest -public class UserRepositoryTest extends BaseTest { +public class UserRepositoryTestIT extends BaseTest { - @Autowired + @Inject private UserRepository userRepository; @Test From 21873dbeedef339495d73472d95689a758ca8183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Machaj?= Date: Mon, 17 Mar 2025 20:53:48 +0100 Subject: [PATCH 19/22] add tests isolation --- .../dataaccess/repository/SpecialistRepository.java | 1 - .../dataaccess/repository/AppointmentRepositoryTestIT.java | 3 +++ .../dataaccess/repository/ClientRepositoryTestIT.java | 3 +++ .../dataaccess/repository/SpecialistRepositoryTestIT.java | 3 +++ .../dataaccess/repository/TreatmentRepositoryTestIT.java | 3 +++ .../dataaccess/repository/UserRepositoryTestIT.java | 3 +++ 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java index 86925ef..b5473e4 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java @@ -27,7 +27,6 @@ default List findSpecialistByName(String firstName, String las .where(user.firstname.eq(firstName) .and(user.lastname.eq(lastName))) .fetch(); - } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java index e9d2e3a..2394673 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java @@ -10,11 +10,14 @@ import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.transaction.annotation.Transactional; import java.time.Instant; import java.util.List; import java.util.Optional; + +@Transactional @DataJpaTest public class AppointmentRepositoryTestIT extends BaseTest { diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java index 22e1777..6db7dcc 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java @@ -5,9 +5,12 @@ import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.transaction.annotation.Transactional; import java.util.List; + +@Transactional @DataJpaTest public class ClientRepositoryTestIT extends BaseTest { diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java index b5aec30..0aadcef 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java @@ -6,9 +6,12 @@ import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.transaction.annotation.Transactional; import java.util.List; + +@Transactional @DataJpaTest public class SpecialistRepositoryTestIT extends BaseTest { diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java index fc53725..86933ff 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java @@ -8,10 +8,13 @@ import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Optional; + +@Transactional @DataJpaTest public class TreatmentRepositoryTestIT extends BaseTest { diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java index 58483aa..53f444a 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java @@ -6,9 +6,12 @@ import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.transaction.annotation.Transactional; import java.util.List; + +@Transactional @DataJpaTest public class UserRepositoryTestIT extends BaseTest { From 9808bb4bf9ebe780ab0c4820d7c5d504a2f2272c Mon Sep 17 00:00:00 2001 From: Krzysztof Sobkowiak Date: Tue, 1 Apr 2025 00:11:05 +0200 Subject: [PATCH 20/22] Extract @EnableJpaRepositories annotation to separate configuration --- .../AppointmentBookingAppApplication.java | 3 --- .../dataaccess/config/DataaccessConfiguration.java | 11 +++++++++++ .../dataaccess/entity/EntitySmokeIT.java | 4 ++++ .../repository/AppointmentRepositoryTestIT.java | 3 +++ .../dataaccess/repository/ClientRepositoryTestIT.java | 3 +++ .../repository/SpecialistRepositoryTestIT.java | 3 +++ .../repository/TreatmentRepositoryTestIT.java | 3 +++ .../dataaccess/repository/UserRepositoryTestIT.java | 3 +++ 8 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java diff --git a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java index 147a512..1639ccf 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/AppointmentBookingAppApplication.java @@ -1,12 +1,9 @@ package com.capgemini.training.appointmentbooking; -import com.capgemini.training.appointmentbooking.dataaccess.repository.impl.BaseJpaRepositoryImpl; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication -@EnableJpaRepositories(repositoryBaseClass = BaseJpaRepositoryImpl.class) public class AppointmentBookingAppApplication { public static void main(String[] args) { diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java new file mode 100644 index 0000000..9fbaceb --- /dev/null +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java @@ -0,0 +1,11 @@ +package com.capgemini.training.appointmentbooking.dataaccess.config; + +import com.capgemini.training.appointmentbooking.dataaccess.repository.impl.BaseJpaRepositoryImpl; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@Configuration +@EnableJpaRepositories( + repositoryBaseClass = BaseJpaRepositoryImpl.class, + basePackages = "com.capgemini.training.appointmentbooking.dataaccess.repository") +public class DataaccessConfiguration {} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java index 3b7a4a9..eefdda5 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java @@ -7,11 +7,15 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; @DataJpaTest +@Import(DataaccessConfiguration.class) public class EntitySmokeIT { @PersistenceContext diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java index 2394673..becab6f 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java @@ -2,6 +2,7 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; +import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; @@ -10,6 +11,7 @@ import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.Transactional; import java.time.Instant; @@ -19,6 +21,7 @@ @Transactional @DataJpaTest +@Import(DataaccessConfiguration.class) public class AppointmentRepositoryTestIT extends BaseTest { @Inject diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java index 6db7dcc..ce34fba 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java @@ -1,10 +1,12 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; import com.capgemini.training.appointmentbooking.common.BaseTest; +import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -12,6 +14,7 @@ @Transactional @DataJpaTest +@Import(DataaccessConfiguration.class) public class ClientRepositoryTestIT extends BaseTest { @Inject diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java index 0aadcef..6fdd6e9 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java @@ -2,10 +2,12 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -13,6 +15,7 @@ @Transactional @DataJpaTest +@Import(DataaccessConfiguration.class) public class SpecialistRepositoryTestIT extends BaseTest { @Inject diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java index 86933ff..e69e804 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java @@ -2,12 +2,14 @@ import com.capgemini.training.appointmentbooking.common.BaseTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; +import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -16,6 +18,7 @@ @Transactional @DataJpaTest +@Import(DataaccessConfiguration.class) public class TreatmentRepositoryTestIT extends BaseTest { @Inject diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java index 53f444a..f00e8f1 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java @@ -1,11 +1,13 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; import com.capgemini.training.appointmentbooking.common.BaseTest; +import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -13,6 +15,7 @@ @Transactional @DataJpaTest +@Import(DataaccessConfiguration.class) public class UserRepositoryTestIT extends BaseTest { @Inject From 5eb43dfbdeeb9716e93e39c53bd73eec2d67f6ce Mon Sep 17 00:00:00 2001 From: mluzyna <63474538+mluzyna@users.noreply.github.com> Date: Tue, 8 Apr 2025 16:20:55 +0200 Subject: [PATCH 21/22] Feature/2 dataacess repositories review (#12) * Review changes - sync with documentation * name correction for EntitySmoke integration test --------- Co-authored-by: MichalLuzyna --- .../repository/AppointmentRepository.java | 1 + .../dataaccess/repository/BaseJpaRepository.java | 3 +-- .../repository/TreatmentRepository.java | 2 +- .../dataaccess/repository/UserRepository.java | 2 +- .../common/BaseDataJpaTest.java | 11 +++++++++++ .../dataaccess/entity/EntitySmokeIT.java | 7 ++----- ...ryTestIT.java => AppointmentRepositoryIT.java} | 12 +++--------- ...ositoryTestIT.java => ClientRepositoryIT.java} | 12 +++--------- ...oryTestIT.java => SpecialistRepositoryIT.java} | 11 ++--------- ...toryTestIT.java => TreatmentRepositoryIT.java} | 15 ++++----------- ...epositoryTestIT.java => UserRepositoryIT.java} | 11 ++--------- 11 files changed, 31 insertions(+), 56 deletions(-) create mode 100644 src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{AppointmentRepositoryTestIT.java => AppointmentRepositoryIT.java} (93%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{ClientRepositoryTestIT.java => ClientRepositoryIT.java} (67%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{SpecialistRepositoryTestIT.java => SpecialistRepositoryIT.java} (77%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{TreatmentRepositoryTestIT.java => TreatmentRepositoryIT.java} (91%) rename src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/{UserRepositoryTestIT.java => UserRepositoryIT.java} (73%) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index 53927f1..9426b3c 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -77,6 +77,7 @@ SELECT CASE WHEN COUNT(a) > 0 THEN TRUE ELSE FALSE END JOIN a.treatment t WHERE t.specialist.id = :specialistId AND a.dateTime = :date + AND a.status <> com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus.CANCELLED """) boolean hasConflictingAppointmentBySpecialistIdAndDateTime(@Param("specialistId") Long specialistId, @Param("date") Instant date); diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java index bf056a4..652b805 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java @@ -2,11 +2,10 @@ import jakarta.persistence.EntityManager; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation; import org.springframework.data.repository.NoRepositoryBean; @NoRepositoryBean -public interface BaseJpaRepository extends JpaRepositoryImplementation { +public interface BaseJpaRepository extends JpaRepository { EntityManager getEntityManager(); diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java index 8479256..5eab402 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -14,7 +14,7 @@ @Repository public interface TreatmentRepository extends BaseJpaRepository { - List findAllByName(String name); + List findAllByNameStartingWithIgnoringCase(String name); List findByNameNamedQuery(String name); diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java index 75d3412..52b8b87 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java @@ -15,7 +15,6 @@ @Repository public interface UserRepository extends BaseJpaRepository { - default List findByCriteria(UserCriteria criteria) { Objects.requireNonNull(criteria, "criteria must not be null"); @@ -41,4 +40,5 @@ default List findByCriteria(UserCriteria criteria) { return entityManager.createQuery(cq).getResultList(); } + } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java new file mode 100644 index 0000000..fb8a924 --- /dev/null +++ b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java @@ -0,0 +1,11 @@ +package com.capgemini.training.appointmentbooking.common; + +import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.transaction.annotation.Transactional; + +@DataJpaTest +@Import(DataaccessConfiguration.class) +public class BaseDataJpaTest extends BaseTest{ +} diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java index eefdda5..b6ad16f 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/entity/EntitySmokeIT.java @@ -7,15 +7,12 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; - -import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; +import org.springframework.data.repository.config.BootstrapMode; -@DataJpaTest -@Import(DataaccessConfiguration.class) +@DataJpaTest(bootstrapMode = BootstrapMode.LAZY) public class EntitySmokeIT { @PersistenceContext diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryIT.java similarity index 93% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryIT.java index becab6f..b1aa168 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryIT.java @@ -1,8 +1,7 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; -import com.capgemini.training.appointmentbooking.common.BaseTest; +import com.capgemini.training.appointmentbooking.common.BaseDataJpaTest; import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus; -import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.AppointmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; @@ -10,19 +9,14 @@ import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.transaction.annotation.Transactional; import java.time.Instant; import java.util.List; import java.util.Optional; -@Transactional -@DataJpaTest -@Import(DataaccessConfiguration.class) -public class AppointmentRepositoryTestIT extends BaseTest { + +public class AppointmentRepositoryIT extends BaseDataJpaTest { @Inject private AppointmentRepository appointmentRepository; diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryIT.java similarity index 67% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryIT.java index ce34fba..4a2538f 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryIT.java @@ -1,21 +1,15 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; -import com.capgemini.training.appointmentbooking.common.BaseTest; -import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; +import com.capgemini.training.appointmentbooking.common.BaseDataJpaTest; import com.capgemini.training.appointmentbooking.dataaccess.entity.ClientEntity; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.transaction.annotation.Transactional; import java.util.List; -@Transactional -@DataJpaTest -@Import(DataaccessConfiguration.class) -public class ClientRepositoryTestIT extends BaseTest { + +public class ClientRepositoryIT extends BaseDataJpaTest { @Inject private ClientRepository clientRepository; diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryIT.java similarity index 77% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryIT.java index 6fdd6e9..c1ba94f 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryIT.java @@ -1,22 +1,15 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; -import com.capgemini.training.appointmentbooking.common.BaseTest; +import com.capgemini.training.appointmentbooking.common.BaseDataJpaTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; -import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.transaction.annotation.Transactional; import java.util.List; -@Transactional -@DataJpaTest -@Import(DataaccessConfiguration.class) -public class SpecialistRepositoryTestIT extends BaseTest { +public class SpecialistRepositoryIT extends BaseDataJpaTest { @Inject private SpecialistRepository specialistRepository; diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryIT.java similarity index 91% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryIT.java index e69e804..f2ddbf9 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryIT.java @@ -1,25 +1,18 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; -import com.capgemini.training.appointmentbooking.common.BaseTest; +import com.capgemini.training.appointmentbooking.common.BaseDataJpaTest; import com.capgemini.training.appointmentbooking.common.datatype.Specialization; -import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import com.capgemini.training.appointmentbooking.dataaccess.entity.SpecialistEntity; import com.capgemini.training.appointmentbooking.dataaccess.entity.TreatmentEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.TreatmentCriteria; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Optional; -@Transactional -@DataJpaTest -@Import(DataaccessConfiguration.class) -public class TreatmentRepositoryTestIT extends BaseTest { +public class TreatmentRepositoryIT extends BaseDataJpaTest { @Inject private TreatmentRepository treatmentRepository; @@ -30,10 +23,10 @@ public class TreatmentRepositoryTestIT extends BaseTest { @Test void shouldFindTreatmentsByName() { // given - String treatmentName = "Konsultacja dentystyczna"; + String treatmentName = "konsUltacja de"; // when - List result = treatmentRepository.findAllByName(treatmentName); + List result = treatmentRepository.findAllByNameStartingWithIgnoringCase(treatmentName); // then assertThat(result).hasSize(1); diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryIT.java similarity index 73% rename from src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java rename to src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryIT.java index f00e8f1..561ed8e 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryTestIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryIT.java @@ -1,22 +1,15 @@ package com.capgemini.training.appointmentbooking.dataaccess.repository; -import com.capgemini.training.appointmentbooking.common.BaseTest; -import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; +import com.capgemini.training.appointmentbooking.common.BaseDataJpaTest; import com.capgemini.training.appointmentbooking.dataaccess.entity.UserEntity; import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.UserCriteria; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import org.springframework.transaction.annotation.Transactional; import java.util.List; -@Transactional -@DataJpaTest -@Import(DataaccessConfiguration.class) -public class UserRepositoryTestIT extends BaseTest { +public class UserRepositoryIT extends BaseDataJpaTest { @Inject private UserRepository userRepository; From b4e8042d103cc461d392cb2cf5ea86078b38d92f Mon Sep 17 00:00:00 2001 From: Piotr Kubicki Date: Thu, 10 Apr 2025 21:50:57 +0200 Subject: [PATCH 22/22] fix: spotless apply --- .../config/DataaccessConfiguration.java | 7 +- .../repository/AppointmentRepository.java | 124 +++---- .../repository/BaseJpaRepository.java | 2 +- .../repository/ClientRepository.java | 18 +- .../repository/SpecialistRepository.java | 25 +- .../repository/TreatmentRepository.java | 38 +- .../dataaccess/repository/UserRepository.java | 49 ++- .../criteria/AppointmentCriteria.java | 2 +- .../impl/BaseJpaRepositoryImpl.java | 18 +- .../common/BaseDataJpaTest.java | 3 +- .../appointmentbooking/common/BaseTest.java | 8 +- .../repository/AppointmentRepositoryIT.java | 334 ++++++++---------- .../repository/ClientRepositoryIT.java | 43 ++- .../repository/SpecialistRepositoryIT.java | 70 ++-- .../repository/TreatmentRepositoryIT.java | 284 +++++++-------- .../repository/UserRepositoryIT.java | 49 ++- 16 files changed, 506 insertions(+), 568 deletions(-) diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java index 9fbaceb..429151b 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/config/DataaccessConfiguration.java @@ -5,7 +5,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @Configuration -@EnableJpaRepositories( - repositoryBaseClass = BaseJpaRepositoryImpl.class, - basePackages = "com.capgemini.training.appointmentbooking.dataaccess.repository") -public class DataaccessConfiguration {} +@EnableJpaRepositories(repositoryBaseClass = BaseJpaRepositoryImpl.class, basePackages = "com.capgemini.training.appointmentbooking.dataaccess.repository") +public class DataaccessConfiguration { +} diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java index 9426b3c..03541a8 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepository.java @@ -16,69 +16,71 @@ import java.util.List; import java.util.Objects; - @Repository public interface AppointmentRepository extends BaseJpaRepository { - default List findByCriteria(AppointmentCriteria criteria) { - Objects.requireNonNull(criteria, "criteria must not be null"); - - CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(AppointmentEntity.class); - Root root = cq.from(AppointmentEntity.class); - List predicates = new ArrayList<>(); - - if (criteria.treatmentName() != null && !criteria.treatmentName().trim().isEmpty()) { - Join treatmentJoin = root.join("treatment", JoinType.LEFT); - predicates.add(cb.like(cb.lower(treatmentJoin.get("name")), "%" + criteria.treatmentName().trim().toLowerCase() + "%")); - } - - if (criteria.startDate() != null) { - predicates.add(cb.greaterThanOrEqualTo(root.get("dateTime"), criteria.startDate())); - } - - if (criteria.endDate() != null) { - predicates.add(cb.lessThanOrEqualTo(root.get("dateTime"), criteria.endDate())); - } - - if (criteria.status() != null) { - predicates.add(cb.equal(root.get("status"), criteria.status())); - } - - if (criteria.clientId() != null) { - Join clientJoin = root.join("client", JoinType.LEFT); - predicates.add(cb.equal(clientJoin.get("id"), criteria.clientId())); - } - - if (criteria.specialistId() != null) { - Join treatmentJoin = root.join("treatment", JoinType.LEFT); - Join specialistJoin = treatmentJoin.join("specialist", JoinType.LEFT); - predicates.add(cb.equal(specialistJoin.get("id"), criteria.specialistId())); - } - - cq.where(predicates.toArray(new Predicate[0])); - return getEntityManager().createQuery(cq).getResultList(); - } - - List findByDateTimeBetweenAndStatus(Instant start, Instant end, AppointmentStatus status); - - @Query(""" - SELECT a FROM AppointmentEntity a - JOIN a.treatment t - WHERE t.specialist.id = :specialistId - AND a.dateTime < :date - ORDER BY a.dateTime DESC - """) - List findAppointmentsBySpecialistIdBeforeDate(@Param("specialistId") Long specialistId, @Param("date") Instant date); - - @Query(""" - SELECT CASE WHEN COUNT(a) > 0 THEN TRUE ELSE FALSE END - FROM AppointmentEntity a - JOIN a.treatment t - WHERE t.specialist.id = :specialistId - AND a.dateTime = :date - AND a.status <> com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus.CANCELLED - """) - boolean hasConflictingAppointmentBySpecialistIdAndDateTime(@Param("specialistId") Long specialistId, @Param("date") Instant date); + default List findByCriteria(AppointmentCriteria criteria) { + Objects.requireNonNull(criteria, "criteria must not be null"); + + CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(AppointmentEntity.class); + Root root = cq.from(AppointmentEntity.class); + List predicates = new ArrayList<>(); + + if (criteria.treatmentName() != null && !criteria.treatmentName().trim().isEmpty()) { + Join treatmentJoin = root.join("treatment", JoinType.LEFT); + predicates.add(cb.like(cb.lower(treatmentJoin.get("name")), + "%" + criteria.treatmentName().trim().toLowerCase() + "%")); + } + + if (criteria.startDate() != null) { + predicates.add(cb.greaterThanOrEqualTo(root.get("dateTime"), criteria.startDate())); + } + + if (criteria.endDate() != null) { + predicates.add(cb.lessThanOrEqualTo(root.get("dateTime"), criteria.endDate())); + } + + if (criteria.status() != null) { + predicates.add(cb.equal(root.get("status"), criteria.status())); + } + + if (criteria.clientId() != null) { + Join clientJoin = root.join("client", JoinType.LEFT); + predicates.add(cb.equal(clientJoin.get("id"), criteria.clientId())); + } + + if (criteria.specialistId() != null) { + Join treatmentJoin = root.join("treatment", JoinType.LEFT); + Join specialistJoin = treatmentJoin.join("specialist", JoinType.LEFT); + predicates.add(cb.equal(specialistJoin.get("id"), criteria.specialistId())); + } + + cq.where(predicates.toArray(new Predicate[0])); + return getEntityManager().createQuery(cq).getResultList(); + } + + List findByDateTimeBetweenAndStatus(Instant start, Instant end, AppointmentStatus status); + + @Query(""" + SELECT a FROM AppointmentEntity a + JOIN a.treatment t + WHERE t.specialist.id = :specialistId + AND a.dateTime < :date + ORDER BY a.dateTime DESC + """) + List findAppointmentsBySpecialistIdBeforeDate(@Param("specialistId") Long specialistId, + @Param("date") Instant date); + + @Query(""" + SELECT CASE WHEN COUNT(a) > 0 THEN TRUE ELSE FALSE END + FROM AppointmentEntity a + JOIN a.treatment t + WHERE t.specialist.id = :specialistId + AND a.dateTime = :date + AND a.status <> com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus.CANCELLED + """) + boolean hasConflictingAppointmentBySpecialistIdAndDateTime(@Param("specialistId") Long specialistId, + @Param("date") Instant date); } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java index 652b805..9acca13 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/BaseJpaRepository.java @@ -7,6 +7,6 @@ @NoRepositoryBean public interface BaseJpaRepository extends JpaRepository { - EntityManager getEntityManager(); + EntityManager getEntityManager(); } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java index 14140ac..550b5b3 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepository.java @@ -11,18 +11,14 @@ @Repository public interface ClientRepository extends BaseJpaRepository { - default List findByName(String firstName, String lastName) { - JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager()); + default List findByName(String firstName, String lastName) { + JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager()); - QClientEntity client = QClientEntity.clientEntity; - QUserEntity user = QUserEntity.userEntity; + QClientEntity client = QClientEntity.clientEntity; + QUserEntity user = QUserEntity.userEntity; - return queryFactory - .selectFrom(client) - .leftJoin(client.user, user) - .where(user.firstname.eq(firstName) - .and(user.lastname.eq(lastName))) - .fetch(); - } + return queryFactory.selectFrom(client).leftJoin(client.user, user) + .where(user.firstname.eq(firstName).and(user.lastname.eq(lastName))).fetch(); + } } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java index b5473e4..bd0efb7 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepository.java @@ -11,22 +11,21 @@ import java.util.List; @Repository -public interface SpecialistRepository extends BaseJpaRepository, QuerydslPredicateExecutor { +public interface SpecialistRepository + extends + BaseJpaRepository, + QuerydslPredicateExecutor { - List findBySpecialization(Specialization specialization); + List findBySpecialization(Specialization specialization); - default List findSpecialistByName(String firstName, String lastName) { - JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager()); + default List findSpecialistByName(String firstName, String lastName) { + JPAQueryFactory queryFactory = new JPAQueryFactory(getEntityManager()); - QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; - QUserEntity user = QUserEntity.userEntity; + QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; + QUserEntity user = QUserEntity.userEntity; - return queryFactory - .selectFrom(specialist) - .leftJoin(specialist.user, user) - .where(user.firstname.eq(firstName) - .and(user.lastname.eq(lastName))) - .fetch(); - } + return queryFactory.selectFrom(specialist).leftJoin(specialist.user, user) + .where(user.firstname.eq(firstName).and(user.lastname.eq(lastName))).fetch(); + } } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java index 5eab402..9911a91 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepository.java @@ -14,32 +14,30 @@ @Repository public interface TreatmentRepository extends BaseJpaRepository { - List findAllByNameStartingWithIgnoringCase(String name); + List findAllByNameStartingWithIgnoringCase(String name); - List findByNameNamedQuery(String name); + List findByNameNamedQuery(String name); - default List findByCriteria(TreatmentCriteria treatmentCriteria) { - Objects.requireNonNull(treatmentCriteria, "treatmentCriteria cannot be null"); + default List findByCriteria(TreatmentCriteria treatmentCriteria) { + Objects.requireNonNull(treatmentCriteria, "treatmentCriteria cannot be null"); - QTreatmentEntity treatment = QTreatmentEntity.treatmentEntity; - QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; + QTreatmentEntity treatment = QTreatmentEntity.treatmentEntity; + QSpecialistEntity specialist = QSpecialistEntity.specialistEntity; - JPAQuery query = new JPAQuery<>(getEntityManager()); - BooleanExpression predicate = treatment.isNotNull(); + JPAQuery query = new JPAQuery<>(getEntityManager()); + BooleanExpression predicate = treatment.isNotNull(); - if (treatmentCriteria.name() != null) { - predicate = predicate.and(treatment.name.like(treatmentCriteria.name())); - } + if (treatmentCriteria.name() != null) { + predicate = predicate.and(treatment.name.like(treatmentCriteria.name())); + } - if (treatmentCriteria.specialization() != null) { - predicate = predicate.and(specialist.specialization.eq(treatmentCriteria.specialization())); - } + if (treatmentCriteria.specialization() != null) { + predicate = predicate.and(specialist.specialization.eq(treatmentCriteria.specialization())); + } - return query.select(treatment) - .from(treatment) - .leftJoin(treatment.specialist, specialist) // Join with specialist - .where(predicate) - .fetch(); - } + return query.select(treatment).from(treatment).leftJoin(treatment.specialist, specialist) // Join with + // specialist + .where(predicate).fetch(); + } } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java index 52b8b87..be8eeb6 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepository.java @@ -15,30 +15,29 @@ @Repository public interface UserRepository extends BaseJpaRepository { - default List findByCriteria(UserCriteria criteria) { - Objects.requireNonNull(criteria, "criteria must not be null"); - - EntityManager entityManager = getEntityManager(); - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(UserEntity.class); - Root root = cq.from(UserEntity.class); - List predicates = new ArrayList<>(); - - if (criteria.firstName() != null) { - predicates.add(cb.like(root.get("firstname"), criteria.firstName())); - } - - if (criteria.lastName() != null) { - predicates.add(cb.like(root.get("lastname"), criteria.lastName())); - } - - if (criteria.email() != null) { - predicates.add(cb.like(root.get("email"), criteria.email())); - } - - cq.where(predicates.toArray(new Predicate[0])); - return entityManager.createQuery(cq).getResultList(); - } - + default List findByCriteria(UserCriteria criteria) { + Objects.requireNonNull(criteria, "criteria must not be null"); + + EntityManager entityManager = getEntityManager(); + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(UserEntity.class); + Root root = cq.from(UserEntity.class); + List predicates = new ArrayList<>(); + + if (criteria.firstName() != null) { + predicates.add(cb.like(root.get("firstname"), criteria.firstName())); + } + + if (criteria.lastName() != null) { + predicates.add(cb.like(root.get("lastname"), criteria.lastName())); + } + + if (criteria.email() != null) { + predicates.add(cb.like(root.get("email"), criteria.email())); + } + + cq.where(predicates.toArray(new Predicate[0])); + return entityManager.createQuery(cq).getResultList(); + } } diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java index be9b96d..17ae7ef 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/criteria/AppointmentCriteria.java @@ -7,5 +7,5 @@ @Builder public record AppointmentCriteria(String treatmentName, Instant startDate, Instant endDate, AppointmentStatus status, - Long clientId, Long specialistId) { + Long clientId, Long specialistId) { } \ No newline at end of file diff --git a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java index 4cf6f71..32a2270 100644 --- a/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java +++ b/src/main/java/com/capgemini/training/appointmentbooking/dataaccess/repository/impl/BaseJpaRepositoryImpl.java @@ -7,16 +7,16 @@ public class BaseJpaRepositoryImpl extends SimpleJpaRepository implements BaseJpaRepository { - private final EntityManager entityManager; + private final EntityManager entityManager; - BaseJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { - super(entityInformation, entityManager); - this.entityManager = entityManager; - } + BaseJpaRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { + super(entityInformation, entityManager); + this.entityManager = entityManager; + } - @Override - public EntityManager getEntityManager() { - return this.entityManager; - } + @Override + public EntityManager getEntityManager() { + return this.entityManager; + } } \ No newline at end of file diff --git a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java index fb8a924..aebe70e 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseDataJpaTest.java @@ -3,9 +3,8 @@ import com.capgemini.training.appointmentbooking.dataaccess.config.DataaccessConfiguration; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; -import org.springframework.transaction.annotation.Transactional; @DataJpaTest @Import(DataaccessConfiguration.class) -public class BaseDataJpaTest extends BaseTest{ +public class BaseDataJpaTest extends BaseTest { } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java index 41eabb7..a6a0e2a 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/common/BaseTest.java @@ -9,9 +9,9 @@ public class BaseTest implements WithAssertions { - protected Instant toInstant(String date) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - return LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()).toInstant(); - } + protected Instant toInstant(String date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return LocalDateTime.parse(date, formatter).atZone(ZoneId.systemDefault()).toInstant(); + } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryIT.java index b1aa168..eaf926a 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/AppointmentRepositoryIT.java @@ -14,183 +14,163 @@ import java.util.List; import java.util.Optional; - - public class AppointmentRepositoryIT extends BaseDataJpaTest { - @Inject - private AppointmentRepository appointmentRepository; - - - @Test - void shouldFindAll() { - // given - // when - List result = appointmentRepository.findAll(); - - // then - assertThat(result).hasSize(20); - } - - @Test - void shouldFindAppointmentsByTreatmentName() { - // given - AppointmentCriteria criteria = AppointmentCriteria - .builder() - .treatmentName("Konsultacja pediatryczna") - .build(); - - // when - List result = appointmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(2); - } - - @Test - void shouldFindAppointmentsByTreatmentNameAndStartDate() { - // given - AppointmentCriteria criteria = AppointmentCriteria - .builder() - .treatmentName("Konsultacja pediatryczna") - .startDate(toInstant("2024-03-03 14:00:00")) - .build(); - - // when - List result = appointmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(2); - } - - @Test - void shouldFindAppointmentsByTreatmentNameAndBetweenStartDateAndEndDate() { - // given - AppointmentCriteria criteria = AppointmentCriteria - .builder() - .treatmentName("Konsultacja pediatryczna") - .startDate(toInstant("2024-03-03 14:00:00")) - .endDate(toInstant("2024-03-03 15:00:00")) - .build(); - - // when - List result = appointmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(1); - } - - @Test - void shouldFindAppointmentsByTreatmentNameAndAppointmentStatus() { - // given - AppointmentCriteria criteria = AppointmentCriteria - .builder() - .treatmentName("Konsultacja pediatryczna") - .status(AppointmentStatus.CANCELLED) - .build(); - - // when - List result = appointmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(2); - } - - @Test - void shouldFindAppointmentsByClientId() { - // given - Long clientId = -1L; - AppointmentCriteria criteria = AppointmentCriteria - .builder() - .clientId(clientId) - .build(); - - // when - List result = appointmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(5); - assertThat(result).extracting(AppointmentEntity::getClient).extracting(ClientEntity::getId).containsOnly(clientId); - } - - @Test - void shouldFindAppointmentsBySpecialistId() { - // given - Long specialistId = -1L; - AppointmentCriteria criteria = AppointmentCriteria - .builder() - .specialistId(specialistId) - .build(); - - // when - List result = appointmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(4); - assertThat(result).extracting(AppointmentEntity::getTreatment).extracting(TreatmentEntity::getSpecialist).extracting(SpecialistEntity::getId).containsOnly(specialistId); - } - - @Test - void shouldFindAppointmentsByDateTimeBetweenAndStatus() { - // given - Instant startDate = toInstant("2024-03-10 00:00:00"); - Instant endDate = toInstant("2024-03-14 23:59:59"); - AppointmentStatus status = AppointmentStatus.SCHEDULED; - - // when - List result = appointmentRepository.findByDateTimeBetweenAndStatus(startDate, endDate, status); - - // then - assertThat(result).hasSize(3); - assertThat(result).extracting(AppointmentEntity::getStatus).containsOnly(status); - } - - @Test - void shouldFindAppointmentById() { - // given - Long appointmentId = -1L; - - // when - Optional result = appointmentRepository.findById(appointmentId); - - // then - assertThat(result).isPresent().hasValueSatisfying(appointment -> { - assertThat(appointment.getId()).isEqualTo(appointmentId); - assertThat(appointment.getStatus()).isEqualTo(AppointmentStatus.SCHEDULED); - assertThat(appointment.getClient()).isNotNull(); - assertThat(appointment.getTreatment()).isNotNull(); - assertThat(appointment.getDateTime()).isEqualTo(toInstant("2024-03-01 09:00:00")); - }); - } - - @Test - void shouldFindAppointmentsBySpecialistIdBeforeDate() { - // given - Long specialistId = -1L; - Instant date = toInstant("2024-03-12 09:00:00"); - - // when - List appointments = appointmentRepository.findAppointmentsBySpecialistIdBeforeDate(specialistId, date); - - // then - assertThat(appointments) - .hasSize(2) - .allMatch(a -> a.getTreatment().getSpecialist().getId().equals(specialistId), - "All appointments belong to the correct specialist") - .allMatch(a -> a.getDateTime().isBefore(date), - "All appointments should be before the given date"); - } - - @Test - void shouldFindConflictedAppointment() { - // given - Long specialistId = -1L; - Instant date = toInstant("2024-03-05 11:45:00"); - - // when - boolean conflict = appointmentRepository.hasConflictingAppointmentBySpecialistIdAndDateTime(specialistId, date); - - // then - assertThat(conflict).isTrue(); - } + @Inject + private AppointmentRepository appointmentRepository; + + @Test + void shouldFindAll() { + // given + // when + List result = appointmentRepository.findAll(); + + // then + assertThat(result).hasSize(20); + } + + @Test + void shouldFindAppointmentsByTreatmentName() { + // given + AppointmentCriteria criteria = AppointmentCriteria.builder().treatmentName("Konsultacja pediatryczna").build(); + + // when + List result = appointmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(2); + } + + @Test + void shouldFindAppointmentsByTreatmentNameAndStartDate() { + // given + AppointmentCriteria criteria = AppointmentCriteria.builder().treatmentName("Konsultacja pediatryczna") + .startDate(toInstant("2024-03-03 14:00:00")).build(); + + // when + List result = appointmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(2); + } + + @Test + void shouldFindAppointmentsByTreatmentNameAndBetweenStartDateAndEndDate() { + // given + AppointmentCriteria criteria = AppointmentCriteria.builder().treatmentName("Konsultacja pediatryczna") + .startDate(toInstant("2024-03-03 14:00:00")).endDate(toInstant("2024-03-03 15:00:00")).build(); + + // when + List result = appointmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(1); + } + + @Test + void shouldFindAppointmentsByTreatmentNameAndAppointmentStatus() { + // given + AppointmentCriteria criteria = AppointmentCriteria.builder().treatmentName("Konsultacja pediatryczna") + .status(AppointmentStatus.CANCELLED).build(); + + // when + List result = appointmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(2); + } + + @Test + void shouldFindAppointmentsByClientId() { + // given + Long clientId = -1L; + AppointmentCriteria criteria = AppointmentCriteria.builder().clientId(clientId).build(); + + // when + List result = appointmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(5); + assertThat(result).extracting(AppointmentEntity::getClient).extracting(ClientEntity::getId) + .containsOnly(clientId); + } + + @Test + void shouldFindAppointmentsBySpecialistId() { + // given + Long specialistId = -1L; + AppointmentCriteria criteria = AppointmentCriteria.builder().specialistId(specialistId).build(); + + // when + List result = appointmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(4); + assertThat(result).extracting(AppointmentEntity::getTreatment).extracting(TreatmentEntity::getSpecialist) + .extracting(SpecialistEntity::getId).containsOnly(specialistId); + } + + @Test + void shouldFindAppointmentsByDateTimeBetweenAndStatus() { + // given + Instant startDate = toInstant("2024-03-10 00:00:00"); + Instant endDate = toInstant("2024-03-14 23:59:59"); + AppointmentStatus status = AppointmentStatus.SCHEDULED; + + // when + List result = appointmentRepository.findByDateTimeBetweenAndStatus(startDate, endDate, + status); + + // then + assertThat(result).hasSize(3); + assertThat(result).extracting(AppointmentEntity::getStatus).containsOnly(status); + } + + @Test + void shouldFindAppointmentById() { + // given + Long appointmentId = -1L; + + // when + Optional result = appointmentRepository.findById(appointmentId); + + // then + assertThat(result).hasValueSatisfying(appointment -> { + assertThat(appointment.getId()).isEqualTo(appointmentId); + assertThat(appointment.getStatus()).isEqualTo(AppointmentStatus.SCHEDULED); + assertThat(appointment.getClient()).isNotNull(); + assertThat(appointment.getTreatment()).isNotNull(); + assertThat(appointment.getDateTime()).isEqualTo(toInstant("2024-03-01 09:00:00")); + }); + } + + @Test + void shouldFindAppointmentsBySpecialistIdBeforeDate() { + // given + Long specialistId = -1L; + Instant date = toInstant("2024-03-12 09:00:00"); + + // when + List appointments = appointmentRepository + .findAppointmentsBySpecialistIdBeforeDate(specialistId, date); + + // then + assertThat(appointments).hasSize(2) + .allMatch(a -> a.getTreatment().getSpecialist().getId().equals(specialistId), + "All appointments belong to the correct specialist") + .allMatch(a -> a.getDateTime().isBefore(date), "All appointments should be before the given date"); + } + + @Test + void shouldFindConflictedAppointment() { + // given + Long specialistId = -1L; + Instant date = toInstant("2024-03-05 11:45:00"); + + // when + boolean conflict = appointmentRepository.hasConflictingAppointmentBySpecialistIdAndDateTime(specialistId, date); + + // then + assertThat(conflict).isTrue(); + } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryIT.java index 4a2538f..2340b77 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/ClientRepositoryIT.java @@ -7,29 +7,26 @@ import java.util.List; - - public class ClientRepositoryIT extends BaseDataJpaTest { - @Inject - private ClientRepository clientRepository; - - @Test - void shouldFindClientsByName() { - // given - String firstName = "Stefan"; - String lastName = "Kowalski"; - - // when - List clients = clientRepository.findByName(firstName, lastName); - - // then - assertThat(clients) - .hasSize(1) - .first() - .satisfies(client -> { - assertThat(client.getUser().getFirstname()).isEqualTo(firstName).as("Expected client to have the specified first name"); - assertThat(client.getUser().getLastname()).isEqualTo(lastName).as("Expected client to have the specified last name"); - }); - } + @Inject + private ClientRepository clientRepository; + + @Test + void shouldFindClientsByName() { + // given + String firstName = "Stefan"; + String lastName = "Kowalski"; + + // when + List clients = clientRepository.findByName(firstName, lastName); + + // then + assertThat(clients).hasSize(1).first().satisfies(client -> { + assertThat(client.getUser().getFirstname()).isEqualTo(firstName) + .as("Expected client to have the specified first name"); + assertThat(client.getUser().getLastname()).isEqualTo(lastName) + .as("Expected client to have the specified last name"); + }); + } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryIT.java index c1ba94f..7b88e04 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/SpecialistRepositoryIT.java @@ -8,43 +8,39 @@ import java.util.List; - public class SpecialistRepositoryIT extends BaseDataJpaTest { - @Inject - private SpecialistRepository specialistRepository; - - @Test - void shouldFindSpecialistsBySpecialization() { - // given - Specialization specialization = Specialization.DENTIST; - - // when - List specialists = specialistRepository.findBySpecialization(specialization); - - // then - assertThat(specialists) - .hasSize(1) - .allMatch(specialist -> specialist.getSpecialization() == specialization, - "Specialists should all have specialization " + specialization); - } - - @Test - void shouldFindSpecialistsByName() { - // given - String firstName = "Dobromir"; - String lastName = "Zegula"; - - // when - List specialists = specialistRepository.findSpecialistByName(firstName, lastName); - - // then - assertThat(specialists) - .hasSize(1) - .first() - .satisfies(specialist -> { - assertThat(specialist.getUser().getFirstname()).isEqualTo(firstName).as("Expected specialist to have the specified first name"); - assertThat(specialist.getUser().getLastname()).isEqualTo(lastName).as("Expected specialist to have the specified last name"); - }); - } + @Inject + private SpecialistRepository specialistRepository; + + @Test + void shouldFindSpecialistsBySpecialization() { + // given + Specialization specialization = Specialization.DENTIST; + + // when + List specialists = specialistRepository.findBySpecialization(specialization); + + // then + assertThat(specialists).hasSize(1).allMatch(specialist -> specialist.getSpecialization() == specialization, + "Specialists should all have specialization " + specialization); + } + + @Test + void shouldFindSpecialistsByName() { + // given + String firstName = "Dobromir"; + String lastName = "Zegula"; + + // when + List specialists = specialistRepository.findSpecialistByName(firstName, lastName); + + // then + assertThat(specialists).hasSize(1).first().satisfies(specialist -> { + assertThat(specialist.getUser().getFirstname()).isEqualTo(firstName) + .as("Expected specialist to have the specified first name"); + assertThat(specialist.getUser().getLastname()).isEqualTo(lastName) + .as("Expected specialist to have the specified last name"); + }); + } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryIT.java index f2ddbf9..9d4f7bb 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/TreatmentRepositoryIT.java @@ -11,157 +11,139 @@ import java.util.List; import java.util.Optional; - public class TreatmentRepositoryIT extends BaseDataJpaTest { - @Inject - private TreatmentRepository treatmentRepository; - - @Inject - private SpecialistRepository specialistRepository; - - @Test - void shouldFindTreatmentsByName() { - // given - String treatmentName = "konsUltacja de"; - - // when - List result = treatmentRepository.findAllByNameStartingWithIgnoringCase(treatmentName); - - // then - assertThat(result).hasSize(1); - } - - @Test - void shouldFindTreatmentsByNameNamedQuery() { - // given - String treatmentName = "Konsultacja dentystyczna"; - - // when - List result = treatmentRepository.findByNameNamedQuery(treatmentName); - - // then - assertThat(result).hasSize(1); - } - - @Test - void shouldFindTreatmentsByNameQueryDSL() { - // given - TreatmentCriteria criteria = TreatmentCriteria - .builder() - .name("Konsultacja kardiologiczna") - .build(); - - // when - List result = treatmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(1); - } - - @Test - void shouldFindTreatmentsByNameAndSpecialization() { - // given - TreatmentCriteria criteria = TreatmentCriteria - .builder() - .name("Konsultacja dentystyczna") - .specialization(Specialization.DENTIST) - .build(); - - // when - List result = treatmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(1); - } - - @Test - void shouldFindTreatmentsBySpecialization() { - // given - TreatmentCriteria criteria = TreatmentCriteria - .builder() - .specialization(Specialization.PEDIATRICIAN) - .build(); - - // when - List result = treatmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(5); - } - - @Test - void shouldFindAllTreatments() { - // given - TreatmentCriteria criteria = TreatmentCriteria - .builder() - .build(); - - // when - List result = treatmentRepository.findByCriteria(criteria); - - // then - assertThat(result).hasSize(12); - } - - @Test - void shouldFindTreatmentById() { - // given - Long treatmentId = -1L; - - // when - Optional result = treatmentRepository.findById(treatmentId); - - // then - assertThat(result) - .isPresent() - .hasValueSatisfying(treatment -> { - assertThat(treatment.getId()).isEqualTo(treatmentId); - assertThat(treatment.getName()).isEqualTo("Konsultacja dentystyczna"); - assertThat(treatment.getDescription()).isEqualTo("Konsultacja dentystyczna z diagnostyką i planem leczenia"); - assertThat(treatment.getDurationMinutes()).isEqualTo(30); - - SpecialistEntity specialist = treatment.getSpecialist(); - assertThat(specialist.getId()).isEqualTo(-1L); - assertThat(specialist.getUser()).isNotNull(); - assertThat(specialist.getSpecialization()).isEqualTo(Specialization.DENTIST); - assertThat(specialist.getTreatments()).isNotNull(); - }); - } - - @Test - void shouldSaveTreatment() { - // given - Long treatmentId = -1L; - Optional optionalSpecialist = specialistRepository.findById(treatmentId); - - assertThat(optionalSpecialist) - .isPresent() - .hasValueSatisfying(specialist -> { - TreatmentEntity treatmentEntity = new TreatmentEntity(); - treatmentEntity.setName("Wypełnienie ubytku"); - treatmentEntity.setDescription("Usunięcie próchnicy i wypełnienie zęba kompozytem"); - treatmentEntity.setDurationMinutes(45); - treatmentEntity.setSpecialist(specialist); - - // when - TreatmentEntity result = treatmentRepository.save(treatmentEntity); - - // then - assertThat(result.getId()).isEqualTo(1L); - assertThat(result.getName()).isEqualTo("Wypełnienie ubytku"); - assertThat(result.getDescription()).isEqualTo("Usunięcie próchnicy i wypełnienie zęba kompozytem"); - assertThat(result.getDurationMinutes()).isEqualTo(45); - - SpecialistEntity savedSpecialist = result.getSpecialist(); - assertThat(savedSpecialist) - .isNotNull() - .extracting(SpecialistEntity::getId) - .isEqualTo(specialist.getId()); - - assertThat(savedSpecialist.getUser()).isNotNull(); - assertThat(savedSpecialist.getSpecialization()).isEqualTo(Specialization.DENTIST); - assertThat(savedSpecialist.getTreatments()).isNotNull(); - }); - } + @Inject + private TreatmentRepository treatmentRepository; + + @Inject + private SpecialistRepository specialistRepository; + + @Test + void shouldFindTreatmentsByName() { + // given + String treatmentName = "konsUltacja de"; + + // when + List result = treatmentRepository.findAllByNameStartingWithIgnoringCase(treatmentName); + + // then + assertThat(result).hasSize(1); + } + + @Test + void shouldFindTreatmentsByNameNamedQuery() { + // given + String treatmentName = "Konsultacja dentystyczna"; + + // when + List result = treatmentRepository.findByNameNamedQuery(treatmentName); + + // then + assertThat(result).hasSize(1); + } + + @Test + void shouldFindTreatmentsByNameQueryDSL() { + // given + TreatmentCriteria criteria = TreatmentCriteria.builder().name("Konsultacja kardiologiczna").build(); + + // when + List result = treatmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(1); + } + + @Test + void shouldFindTreatmentsByNameAndSpecialization() { + // given + TreatmentCriteria criteria = TreatmentCriteria.builder().name("Konsultacja dentystyczna") + .specialization(Specialization.DENTIST).build(); + + // when + List result = treatmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(1); + } + + @Test + void shouldFindTreatmentsBySpecialization() { + // given + TreatmentCriteria criteria = TreatmentCriteria.builder().specialization(Specialization.PEDIATRICIAN).build(); + + // when + List result = treatmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(5); + } + + @Test + void shouldFindAllTreatments() { + // given + TreatmentCriteria criteria = TreatmentCriteria.builder().build(); + + // when + List result = treatmentRepository.findByCriteria(criteria); + + // then + assertThat(result).hasSize(12); + } + + @Test + void shouldFindTreatmentById() { + // given + Long treatmentId = -1L; + + // when + Optional result = treatmentRepository.findById(treatmentId); + + // then + assertThat(result).hasValueSatisfying(treatment -> { + assertThat(treatment.getId()).isEqualTo(treatmentId); + assertThat(treatment.getName()).isEqualTo("Konsultacja dentystyczna"); + assertThat(treatment.getDescription()) + .isEqualTo("Konsultacja dentystyczna z diagnostyką i planem leczenia"); + assertThat(treatment.getDurationMinutes()).isEqualTo(30); + + SpecialistEntity specialist = treatment.getSpecialist(); + assertThat(specialist.getId()).isEqualTo(-1L); + assertThat(specialist.getUser()).isNotNull(); + assertThat(specialist.getSpecialization()).isEqualTo(Specialization.DENTIST); + assertThat(specialist.getTreatments()).isNotNull(); + }); + } + + @Test + void shouldSaveTreatment() { + // given + Long treatmentId = -1L; + Optional optionalSpecialist = specialistRepository.findById(treatmentId); + + assertThat(optionalSpecialist).hasValueSatisfying(specialist -> { + TreatmentEntity treatmentEntity = new TreatmentEntity(); + treatmentEntity.setName("Wypełnienie ubytku"); + treatmentEntity.setDescription("Usunięcie próchnicy i wypełnienie zęba kompozytem"); + treatmentEntity.setDurationMinutes(45); + treatmentEntity.setSpecialist(specialist); + + // when + TreatmentEntity result = treatmentRepository.save(treatmentEntity); + + // then + assertThat(result.getId()).isOne(); + assertThat(result.getName()).isEqualTo("Wypełnienie ubytku"); + assertThat(result.getDescription()).isEqualTo("Usunięcie próchnicy i wypełnienie zęba kompozytem"); + assertThat(result.getDurationMinutes()).isEqualTo(45); + + SpecialistEntity savedSpecialist = result.getSpecialist(); + assertThat(savedSpecialist).isNotNull().extracting(SpecialistEntity::getId).isEqualTo(specialist.getId()); + + assertThat(savedSpecialist.getUser()).isNotNull(); + assertThat(savedSpecialist.getSpecialization()).isEqualTo(Specialization.DENTIST); + assertThat(savedSpecialist.getTreatments()).isNotNull(); + }); + } } diff --git a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryIT.java b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryIT.java index 561ed8e..3edbdb1 100644 --- a/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryIT.java +++ b/src/test/java/com/capgemini/training/appointmentbooking/dataaccess/repository/UserRepositoryIT.java @@ -8,35 +8,26 @@ import java.util.List; - public class UserRepositoryIT extends BaseDataJpaTest { - @Inject - private UserRepository userRepository; - - @Test - void shouldFindUsersByCriteria() { - // given - String firstName = "Stefan"; - String lastName = "Kowalski"; - String email = "stefan.kowalski@gmail.com"; - UserCriteria userCriteria = UserCriteria - .builder() - .firstName(firstName) - .lastName(lastName) - .email(email) - .build(); - - // when - List users = userRepository.findByCriteria(userCriteria); - - // then - assertThat(users) - .hasSize(1) - .first() - .satisfies(user -> { - assertThat(user.getFirstname()).isEqualTo(firstName).as("Expected user to have the specified first name"); - assertThat(user.getLastname()).isEqualTo(lastName).as("Expected user to have the specified last name"); - }); - } + @Inject + private UserRepository userRepository; + + @Test + void shouldFindUsersByCriteria() { + // given + String firstName = "Stefan"; + String lastName = "Kowalski"; + String email = "stefan.kowalski@gmail.com"; + UserCriteria userCriteria = UserCriteria.builder().firstName(firstName).lastName(lastName).email(email).build(); + + // when + List users = userRepository.findByCriteria(userCriteria); + + // then + assertThat(users).hasSize(1).first().satisfies(user -> { + assertThat(user.getFirstname()).isEqualTo(firstName).as("Expected user to have the specified first name"); + assertThat(user.getLastname()).isEqualTo(lastName).as("Expected user to have the specified last name"); + }); + } }