From d133e9eeeab569cc7550673c7d8a9c01a960ef60 Mon Sep 17 00:00:00 2001 From: bedroomghost Date: Mon, 21 Apr 2025 19:41:53 +0200 Subject: [PATCH 1/6] refactor: move price business logic from repository to service --- .../ports/out/PriceRepositoryPort.java | 6 +-- .../application/services/PriceService.java | 13 ++++- .../services/PriceServiceTest.java | 52 ++++++++++++++----- .../PriceEntityJPARepository.java | 11 +--- .../adapters/PriceRepositoryAdapter.java | 10 ++-- .../mappers/PriceEntityMapper.java | 6 +-- .../adapters/PriceRepositoryAdapterTest.java | 46 ++++++++-------- 7 files changed, 85 insertions(+), 59 deletions(-) diff --git a/application/src/main/java/com/techivw/webprice/application/ports/out/PriceRepositoryPort.java b/application/src/main/java/com/techivw/webprice/application/ports/out/PriceRepositoryPort.java index b785a12..6e75ca5 100644 --- a/application/src/main/java/com/techivw/webprice/application/ports/out/PriceRepositoryPort.java +++ b/application/src/main/java/com/techivw/webprice/application/ports/out/PriceRepositoryPort.java @@ -2,11 +2,9 @@ package com.techivw.webprice.application.ports.out; import com.techivw.webprice.domain.Price; -import java.time.LocalDateTime; -import java.util.Optional; +import java.util.List; public interface PriceRepositoryPort { - Optional findHighestPriorityPriceByDateTimeAndProductIdAndBrandId(LocalDateTime dateTime, Long productId, Long brandId); - + List findPricesByProductIdAndBrandId(Long productId, Long brandId); } diff --git a/application/src/main/java/com/techivw/webprice/application/services/PriceService.java b/application/src/main/java/com/techivw/webprice/application/services/PriceService.java index eee1d41..ae5ae4d 100644 --- a/application/src/main/java/com/techivw/webprice/application/services/PriceService.java +++ b/application/src/main/java/com/techivw/webprice/application/services/PriceService.java @@ -8,6 +8,9 @@ import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import java.time.LocalDateTime; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; @Service @AllArgsConstructor @@ -17,8 +20,14 @@ public class PriceService implements PriceServicePort { @Override public Price getPriceWithHighestPriorityByDateTimeAndProductIdAndBrandId(LocalDateTime dateTime, Long productId, Long brandId) { - return priceRepositoryPort.findHighestPriorityPriceByDateTimeAndProductIdAndBrandId(dateTime, productId, brandId) - .orElseThrow(() -> + + List prices = priceRepositoryPort.findPricesByProductIdAndBrandId(productId, brandId); + + Optional maxPriorityPrice = prices.stream() + .filter(price -> !dateTime.isBefore(price.getStartDate()) && !dateTime.isAfter(price.getEndDate())) + .max(Comparator.comparing(Price::getPriority)); + + return maxPriorityPrice.orElseThrow(() -> new NotFoundException(String.format( "Price for product %d of brand %d not found for date %s", productId, brandId, dateTime))); } diff --git a/application/src/test/java/com/techivw/webprice/application/services/PriceServiceTest.java b/application/src/test/java/com/techivw/webprice/application/services/PriceServiceTest.java index 2a61a80..7952aa7 100644 --- a/application/src/test/java/com/techivw/webprice/application/services/PriceServiceTest.java +++ b/application/src/test/java/com/techivw/webprice/application/services/PriceServiceTest.java @@ -7,7 +7,9 @@ import com.techivw.webprice.domain.Price; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.Optional; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,31 +40,55 @@ class PriceServiceTest { @Test void shouldReturnPriceWhenPriceExists() { - Price expectedPrice = createPrice(); - when(priceRepositoryPort.findHighestPriorityPriceByDateTimeAndProductIdAndBrandId( - eq(TEST_DATE), eq(TEST_PRODUCT_ID), eq(TEST_BRAND_ID))) - .thenReturn(Optional.of(expectedPrice)); + Price lowPriorityPrice = createPrice(0); + Price highPriorityPrice = createPrice(2); + List prices = Arrays.asList(lowPriorityPrice, highPriorityPrice); + + when(priceRepositoryPort.findPricesByProductIdAndBrandId( + eq(TEST_PRODUCT_ID), eq(TEST_BRAND_ID))) + .thenReturn(prices); Price result = priceService.getPriceWithHighestPriorityByDateTimeAndProductIdAndBrandId( TEST_DATE, TEST_PRODUCT_ID, TEST_BRAND_ID); assertNotNull(result); - assertEquals(expectedPrice.getProductId(), result.getProductId()); - assertEquals(expectedPrice.getPrice(), result.getPrice()); + assertEquals(highPriorityPrice, result); } @Test - void shouldThrowNotFoundExceptionWhenPriceDoesNotExist() { - when(priceRepositoryPort.findHighestPriorityPriceByDateTimeAndProductIdAndBrandId( - any(LocalDateTime.class), anyLong(), anyLong())) - .thenReturn(Optional.empty()); + void shouldThrowNotFoundExceptionWhenPriceListIsEmpty() { + when(priceRepositoryPort.findPricesByProductIdAndBrandId( + eq(TEST_PRODUCT_ID), eq(TEST_BRAND_ID))) + .thenReturn(Collections.emptyList()); assertThrows(NotFoundException.class, () -> priceService.getPriceWithHighestPriorityByDateTimeAndProductIdAndBrandId( TEST_DATE, TEST_PRODUCT_ID, TEST_BRAND_ID)); } - private Price createPrice() { + @Test + void shouldThrowNotFoundExceptionWhenNoPriceInDateRange() { + Price price = Price.builder() + .brandId(TEST_BRAND_ID) + .productId(TEST_PRODUCT_ID) + .startDate(TEST_DATE.plusDays(1)) + .endDate(TEST_DATE.plusDays(2)) + .priceList(1L) + .price(BigDecimal.valueOf(35.50)) + .priority(1) + .currency("EUR") + .build(); + + when(priceRepositoryPort.findPricesByProductIdAndBrandId( + eq(TEST_PRODUCT_ID), eq(TEST_BRAND_ID))) + .thenReturn(Collections.singletonList(price)); + + assertThrows(NotFoundException.class, () -> + priceService.getPriceWithHighestPriorityByDateTimeAndProductIdAndBrandId( + TEST_DATE, TEST_PRODUCT_ID, TEST_BRAND_ID)); + } + + private Price createPrice(int priority) { return Price.builder() .brandId(TEST_BRAND_ID) .productId(TEST_PRODUCT_ID) @@ -70,7 +96,7 @@ class PriceServiceTest { .endDate(TEST_DATE.plusDays(1)) .priceList(1L) .price(BigDecimal.valueOf(35.50)) - .priority(1) + .priority(priority) .currency("EUR") .build(); } diff --git a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/PriceEntityJPARepository.java b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/PriceEntityJPARepository.java index f265993..b03c5da 100644 --- a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/PriceEntityJPARepository.java +++ b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/PriceEntityJPARepository.java @@ -2,19 +2,12 @@ package com.techivw.webprice.infrastructure.repositories; import com.techivw.webprice.infrastructure.repositories.model.PriceEntity; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; -import java.time.LocalDateTime; -import java.util.Optional; +import java.util.List; @Repository public interface PriceEntityJPARepository extends JpaRepository { - @Query("SELECT p FROM PriceEntity p WHERE " + - "p.productId = :productId " + - "AND p.brandId = :brandId " + - "AND :dateTime BETWEEN p.startDate AND p.endDate " + - "ORDER BY p.priority DESC LIMIT 1") - Optional findPriceByDateTimeAndProductIdAndBrandId(LocalDateTime dateTime, Long productId, Long brandId); + List findPricesByProductIdAndBrandId(Long productId, Long brandId); } diff --git a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapter.java b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapter.java index a30b161..4d9984e 100644 --- a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapter.java +++ b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapter.java @@ -8,8 +8,7 @@ import com.techivw.webprice.infrastructure.repositories.model.PriceEntity; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; -import java.time.LocalDateTime; -import java.util.Optional; +import java.util.List; @Service @AllArgsConstructor @@ -18,11 +17,10 @@ public class PriceRepositoryAdapter implements PriceRepositoryPort { private final PriceEntityJPARepository repository; @Override - public Optional findHighestPriorityPriceByDateTimeAndProductIdAndBrandId(LocalDateTime dateTime, Long productId, Long brandId) { + public List findPricesByProductIdAndBrandId(Long productId, Long brandId) { - Optional priceEntity = - repository.findPriceByDateTimeAndProductIdAndBrandId(dateTime, productId, brandId); + List priceEntityList = repository.findPricesByProductIdAndBrandId(productId, brandId); - return PriceEntityMapper.toOptionalPrice(priceEntity); + return PriceEntityMapper.toPriceList(priceEntityList); } } diff --git a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/mappers/PriceEntityMapper.java b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/mappers/PriceEntityMapper.java index 7445cd9..bd52b06 100644 --- a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/mappers/PriceEntityMapper.java +++ b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/mappers/PriceEntityMapper.java @@ -3,7 +3,7 @@ package com.techivw.webprice.infrastructure.repositories.mappers; import com.techivw.webprice.domain.Price; import com.techivw.webprice.infrastructure.repositories.model.PriceEntity; -import java.util.Optional; +import java.util.List; public class PriceEntityMapper { @@ -21,8 +21,8 @@ public class PriceEntityMapper { .build(); } - public static Optional toOptionalPrice(Optional priceEntity) { - return priceEntity.map(PriceEntityMapper::toPrice); + public static List toPriceList(List priceEntityList) { + return priceEntityList.stream().map(PriceEntityMapper::toPrice).toList(); } } diff --git a/infrastructure/out/sql-repository/src/test/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapterTest.java b/infrastructure/out/sql-repository/src/test/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapterTest.java index a260ca5..21e4d5f 100644 --- a/infrastructure/out/sql-repository/src/test/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapterTest.java +++ b/infrastructure/out/sql-repository/src/test/java/com/techivw/webprice/infrastructure/repositories/adapters/PriceRepositoryAdapterTest.java @@ -11,7 +11,9 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.Optional; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; @@ -35,35 +37,35 @@ class PriceRepositoryAdapterTest { } @Test - void shouldReturnPriceWhenPriceEntityExists() { - PriceEntity priceEntity = createSamplePriceEntity(); - when(repository.findPriceByDateTimeAndProductIdAndBrandId( - eq(TEST_DATE), eq(TEST_PRODUCT_ID), eq(TEST_BRAND_ID))) - .thenReturn(Optional.of(priceEntity)); + void shouldReturnPricesWhenPriceEntitiesExist() { + List priceEntities = Arrays.asList( + createPriceEntity(1), + createPriceEntity(2) + ); - Optional result = adapter.findHighestPriorityPriceByDateTimeAndProductIdAndBrandId( - TEST_DATE, TEST_PRODUCT_ID, TEST_BRAND_ID); + when(repository.findPricesByProductIdAndBrandId( + eq(TEST_PRODUCT_ID), eq(TEST_BRAND_ID))) + .thenReturn(priceEntities); - assertTrue(result.isPresent()); - Price price = result.get(); - assertEquals(TEST_PRODUCT_ID, price.getProductId()); - assertEquals(TEST_BRAND_ID, price.getBrandId()); - assertEquals(BigDecimal.valueOf(35.50), price.getPrice()); + List result = adapter.findPricesByProductIdAndBrandId( + TEST_PRODUCT_ID, TEST_BRAND_ID); + + assertEquals(2, result.size()); } @Test - void shouldReturnEmptyOptionalWhenPriceEntityDoesNotExist() { - when(repository.findPriceByDateTimeAndProductIdAndBrandId( - any(LocalDateTime.class), anyLong(), anyLong())) - .thenReturn(Optional.empty()); + void shouldReturnEmptyListWhenNoPriceEntitiesExist() { + when(repository.findPricesByProductIdAndBrandId( + eq(TEST_PRODUCT_ID), eq(TEST_BRAND_ID))) + .thenReturn(Collections.emptyList()); - Optional result = adapter.findHighestPriorityPriceByDateTimeAndProductIdAndBrandId( - TEST_DATE, TEST_PRODUCT_ID, TEST_BRAND_ID); + List result = adapter.findPricesByProductIdAndBrandId( + TEST_PRODUCT_ID, TEST_BRAND_ID); - assertFalse(result.isPresent()); + assertTrue(result.isEmpty()); } - private PriceEntity createSamplePriceEntity() { + private PriceEntity createPriceEntity(int priority) { PriceEntity entity = new PriceEntity(); entity.setBrandId(TEST_BRAND_ID); entity.setProductId(TEST_PRODUCT_ID); @@ -71,7 +73,7 @@ class PriceRepositoryAdapterTest { entity.setEndDate(TEST_DATE.plusDays(1)); entity.setPriceList(1L); entity.setPrice(BigDecimal.valueOf(35.50)); - entity.setPriority(1); + entity.setPriority(priority); entity.setCurrency("EUR"); return entity; } From 0258f2b5d1e8d85d0ff57113c51d963086f685ee Mon Sep 17 00:00:00 2001 From: bedroomghost Date: Mon, 21 Apr 2025 19:52:04 +0200 Subject: [PATCH 2/6] feat: Add exception handling for request parameter validation in rest-api --- .../handlers/AdapterExceptionHandler.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/infrastructure/in/rest-api/src/main/java/com/techivw/webprice/infrastructure/in/controllers/handlers/AdapterExceptionHandler.java b/infrastructure/in/rest-api/src/main/java/com/techivw/webprice/infrastructure/in/controllers/handlers/AdapterExceptionHandler.java index 50b1daa..9cf0ec0 100644 --- a/infrastructure/in/rest-api/src/main/java/com/techivw/webprice/infrastructure/in/controllers/handlers/AdapterExceptionHandler.java +++ b/infrastructure/in/rest-api/src/main/java/com/techivw/webprice/infrastructure/in/controllers/handlers/AdapterExceptionHandler.java @@ -2,13 +2,16 @@ package com.techivw.webprice.infrastructure.in.controllers.handlers; import com.techivw.webprice.application.exceptions.NotFoundException; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import java.util.Date; import java.util.HashMap; import java.util.Map; +import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.NOT_FOUND; @RestControllerAdvice @@ -24,4 +27,27 @@ public class AdapterExceptionHandler { return new ResponseEntity<>(body, NOT_FOUND); } + + @ExceptionHandler(MissingServletRequestParameterException.class) + public ResponseEntity> handleMissingParamException(MissingServletRequestParameterException ex) { + Map body = new HashMap<>(); + body.put("timestamp", new Date()); + body.put("status", BAD_REQUEST.value()); + body.put("error", "Bad Request"); + body.put("message", "Required parameter '" + ex.getParameterName() + "' is missing"); + + return new ResponseEntity<>(body, BAD_REQUEST); + } + + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public ResponseEntity> handleTypeMismatchException(MethodArgumentTypeMismatchException ex) { + Map body = new HashMap<>(); + body.put("timestamp", new Date()); + body.put("status", BAD_REQUEST.value()); + body.put("error", "Bad Request"); + body.put("message", "Parameter '" + ex.getName() + "' has invalid format."); + + return new ResponseEntity<>(body, BAD_REQUEST); + } + } From 11b9f698dd7fb87ba268b42967c809a04c056663 Mon Sep 17 00:00:00 2001 From: bedroomghost Date: Mon, 21 Apr 2025 20:13:44 +0200 Subject: [PATCH 3/6] test: Add error handling tests for PriceControllerAdapter --- .../adapters/PriceControllerAdapterTest.java | 72 ++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/infrastructure/in/rest-api/src/test/java/com/techivw/webprice/infrastructure/in/controllers/adapters/PriceControllerAdapterTest.java b/infrastructure/in/rest-api/src/test/java/com/techivw/webprice/infrastructure/in/controllers/adapters/PriceControllerAdapterTest.java index d2b6079..64acfb7 100644 --- a/infrastructure/in/rest-api/src/test/java/com/techivw/webprice/infrastructure/in/controllers/adapters/PriceControllerAdapterTest.java +++ b/infrastructure/in/rest-api/src/test/java/com/techivw/webprice/infrastructure/in/controllers/adapters/PriceControllerAdapterTest.java @@ -1,12 +1,16 @@ package com.techivw.webprice.infrastructure.in.controllers.adapters; +import com.techivw.webprice.application.exceptions.NotFoundException; import com.techivw.webprice.application.ports.in.PriceServicePort; import com.techivw.webprice.domain.Price; +import com.techivw.webprice.infrastructure.in.controllers.handlers.AdapterExceptionHandler; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.bean.override.mockito.MockitoBean; @@ -23,6 +27,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @WebMvcTest @ContextConfiguration(classes = PriceControllerAdapter.class) +@Import(AdapterExceptionHandler.class) @ActiveProfiles("test") public class PriceControllerAdapterTest { @@ -35,8 +40,71 @@ public class PriceControllerAdapterTest { private static final Long PRODUCT_ID = 35455L; private static final Long BRAND_ID = 1L; + @Test + void testNotFound() throws Exception { + LocalDateTime date = LocalDateTime.parse("2020-06-14T10:00:00"); + + when(priceServicePort.getPriceWithHighestPriorityByDateTimeAndProductIdAndBrandId(date, PRODUCT_ID, BRAND_ID)) + .thenThrow(new NotFoundException("")); + + mockMvc.perform(get("/price") + .param("dateTime", date.toString()) + .param("productId", String.valueOf(PRODUCT_ID)) + .param("brandId", String.valueOf(BRAND_ID))) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.status").value(404)) + .andExpect(jsonPath("$.error").value("Not Found")); + } + + @Test + void testMissingParameter() throws Exception { + mockMvc.perform(get("/price") + .param("productId", String.valueOf(PRODUCT_ID)) + .param("brandId", String.valueOf(BRAND_ID))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.status").value(400)) + .andExpect(jsonPath("$.error").value("Bad Request")) + .andExpect(jsonPath("$.message").value("Required parameter 'dateTime' is missing")); + } + + @Test + void testInvalidDateFormat() throws Exception { + mockMvc.perform(get("/price") + .param("dateTime", "2020-06T17:00") + .param("productId", String.valueOf(PRODUCT_ID)) + .param("brandId", String.valueOf(BRAND_ID))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.status").value(400)) + .andExpect(jsonPath("$.error").value("Bad Request")) + .andExpect(jsonPath("$.message").value("Parameter 'dateTime' has invalid format.")); + } + + @Test + void testInvalidProductIdFormat() throws Exception { + mockMvc.perform(get("/price") + .param("dateTime", "2020-06-14T10:00:00") + .param("productId", "testNaN") + .param("brandId", String.valueOf(BRAND_ID))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.status").value(400)) + .andExpect(jsonPath("$.error").value("Bad Request")) + .andExpect(jsonPath("$.message").value("Parameter 'productId' has invalid format.")); + } + + @Test + void testInvalidBrandIdFormat() throws Exception { + mockMvc.perform(get("/price") + .param("dateTime", "2020-06-14T10:00:00") + .param("productId", String.valueOf(PRODUCT_ID)) + .param("brandId", "not-a-number")) // Invalid brandId format + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.status").value(400)) + .andExpect(jsonPath("$.error").value("Bad Request")) + .andExpect(jsonPath("$.message").value("Parameter 'brandId' has invalid format.")); + } + @ParameterizedTest - @MethodSource("testCases") + @MethodSource("successfulTestCases") void testGetPrice(String testName, String dateTime, double expectedPrice) throws Exception { LocalDateTime date = LocalDateTime.parse(dateTime); @@ -52,7 +120,7 @@ public class PriceControllerAdapterTest { .andExpect(jsonPath("$.price").value(expectedPrice)); } - private static Stream testCases() { + private static Stream successfulTestCases() { return Stream.of( Arguments.of("Test 1", "2020-06-14T10:00:00", 35.50), Arguments.of("Test 2", "2020-06-14T16:00:00", 25.45), From 2aca2950f423d6b4444e56533b4de05992c1da89 Mon Sep 17 00:00:00 2001 From: bedroomghost Date: Mon, 21 Apr 2025 20:30:21 +0200 Subject: [PATCH 4/6] fix: Properly added relative paths to application and boot poms --- application/pom.xml | 2 +- boot/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 6487922..8f7a77b 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -12,7 +12,7 @@ com.techivw web-price 1.0-RELEASE - + ../pom.xml diff --git a/boot/pom.xml b/boot/pom.xml index a27a6b9..aaf3daf 100644 --- a/boot/pom.xml +++ b/boot/pom.xml @@ -8,7 +8,7 @@ com.techivw web-price 1.0-RELEASE - + ../pom.xml boot From 9caff32574d25fa4ecc18bcc4d671207a39bf034 Mon Sep 17 00:00:00 2001 From: bedroomghost Date: Mon, 21 Apr 2025 21:32:05 +0200 Subject: [PATCH 5/6] fix: Flyway migrations now working when run from the command line --- boot/src/main/resources/application.properties | 5 +++-- .../infrastructure/repositories/model/PriceEntity.java | 7 +++++++ .../sql/migration/V1__create_prices_table.sql | 4 +++- .../sql/migration/V2__insert_prices_data.sql | 10 +++++----- 4 files changed, 18 insertions(+), 8 deletions(-) rename infrastructure/out/sql-repository/{ => src/main/resources}/sql/migration/V1__create_prices_table.sql (77%) rename infrastructure/out/sql-repository/{ => src/main/resources}/sql/migration/V2__insert_prices_data.sql (55%) diff --git a/boot/src/main/resources/application.properties b/boot/src/main/resources/application.properties index 1da086d..29f2bd1 100644 --- a/boot/src/main/resources/application.properties +++ b/boot/src/main/resources/application.properties @@ -13,5 +13,6 @@ spring.h2.console.path=/h2-console # Flyway spring.flyway.enabled=true -spring.flyway.locations=filesystem:infrastructure/out/sql-repository/sql/migration -spring.flyway.baseline-on-migrate=true \ No newline at end of file +spring.flyway.locations=filesystem:../infrastructure/out/sql-repository/src/main/resources/sql/migration +spring.flyway.baseline-on-migrate=true +spring.flyway.fail-on-missing-locations=true \ No newline at end of file diff --git a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/model/PriceEntity.java b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/model/PriceEntity.java index cba0dc6..2f6a5db 100644 --- a/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/model/PriceEntity.java +++ b/infrastructure/out/sql-repository/src/main/java/com/techivw/webprice/infrastructure/repositories/model/PriceEntity.java @@ -44,4 +44,11 @@ public class PriceEntity { @Column(name = "currency") private String currency; + @Column(name = "last_update") + @Temporal(TemporalType.TIMESTAMP) + private LocalDateTime lastUpdate; + + @Column(name = "last_update_by") + private String lastUpdateBy; + } diff --git a/infrastructure/out/sql-repository/sql/migration/V1__create_prices_table.sql b/infrastructure/out/sql-repository/src/main/resources/sql/migration/V1__create_prices_table.sql similarity index 77% rename from infrastructure/out/sql-repository/sql/migration/V1__create_prices_table.sql rename to infrastructure/out/sql-repository/src/main/resources/sql/migration/V1__create_prices_table.sql index 301a730..e4be084 100644 --- a/infrastructure/out/sql-repository/sql/migration/V1__create_prices_table.sql +++ b/infrastructure/out/sql-repository/src/main/resources/sql/migration/V1__create_prices_table.sql @@ -7,5 +7,7 @@ CREATE TABLE prices ( product_id BIGINT NOT NULL, priority BIGINT NOT NULL, price DECIMAL(10, 2) NOT NULL, - currency VARCHAR(3) + currency VARCHAR(3), + last_update TIMESTAMP, + last_update_by VARCHAR(255) ); \ No newline at end of file diff --git a/infrastructure/out/sql-repository/sql/migration/V2__insert_prices_data.sql b/infrastructure/out/sql-repository/src/main/resources/sql/migration/V2__insert_prices_data.sql similarity index 55% rename from infrastructure/out/sql-repository/sql/migration/V2__insert_prices_data.sql rename to infrastructure/out/sql-repository/src/main/resources/sql/migration/V2__insert_prices_data.sql index 5ad9204..b3989c7 100644 --- a/infrastructure/out/sql-repository/sql/migration/V2__insert_prices_data.sql +++ b/infrastructure/out/sql-repository/src/main/resources/sql/migration/V2__insert_prices_data.sql @@ -1,6 +1,6 @@ -INSERT INTO prices (brand_id, start_date, end_date, price_list, product_id, priority, price, currency) +INSERT INTO prices (brand_id, start_date, end_date, price_list, product_id, priority, price, currency, last_update, last_update_by) VALUES - (1, '2020-06-14 00:00:00', '2020-12-31 23:59:59', 1, 35455, 0, 35.50, 'EUR'), - (1, '2020-06-14 15:00:00', '2020-06-14 18:30:00', 2, 35455, 1, 25.45, 'EUR'), - (1, '2020-06-15 00:00:00', '2020-06-15 11:00:00', 3, 35455, 1, 30.50, 'EUR'), - (1, '2020-06-15 16:00:00', '2020-12-31 23:59:59', 4, 35455, 1, 38.95, 'EUR'); \ No newline at end of file + (1, '2020-06-14 00:00:00', '2020-12-31 23:59:59', 1, 35455, 0, 35.50, 'EUR', '2020-03-26 14:49:07', 'user1'), + (1, '2020-06-14 15:00:00', '2020-06-14 18:30:00', 2, 35455, 1, 25.45, 'EUR', '2020-05-26 15:38:22', 'user1'), + (1, '2020-06-15 00:00:00', '2020-06-15 11:00:00', 3, 35455, 1, 30.50, 'EUR', '2020-05-26 15:39:22', 'user2'), + (1, '2020-06-15 16:00:00', '2020-12-31 23:59:59', 4, 35455, 1, 38.95, 'EUR', '2020-06-02 10:14:00', 'user1') \ No newline at end of file From 730ca59e1c50db384b4e2a6d040e527602ad6da9 Mon Sep 17 00:00:00 2001 From: bedroomghost Date: Mon, 21 Apr 2025 21:39:08 +0200 Subject: [PATCH 6/6] chore(release): v1.1 --- application/pom.xml | 4 ++-- boot/pom.xml | 10 +++++----- domain/pom.xml | 2 +- infrastructure/in/rest-api/pom.xml | 6 +++--- infrastructure/out/sql-repository/pom.xml | 6 +++--- pom.xml | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 8f7a77b..1b736da 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -11,7 +11,7 @@ com.techivw web-price - 1.0-RELEASE + 1.1-RELEASE ../pom.xml @@ -19,7 +19,7 @@ com.techivw domain - 1.0-RELEASE + 1.1-RELEASE diff --git a/boot/pom.xml b/boot/pom.xml index aaf3daf..de1276e 100644 --- a/boot/pom.xml +++ b/boot/pom.xml @@ -7,7 +7,7 @@ com.techivw web-price - 1.0-RELEASE + 1.1-RELEASE ../pom.xml @@ -20,22 +20,22 @@ com.techivw domain - 1.0-RELEASE + 1.1-RELEASE com.techivw application - 1.0-RELEASE + 1.1-RELEASE com.techivw rest-api - 1.0-RELEASE + 1.1-RELEASE com.techivw sql-repository - 1.0-RELEASE + 1.1-RELEASE diff --git a/domain/pom.xml b/domain/pom.xml index ab35c2d..6f92192 100644 --- a/domain/pom.xml +++ b/domain/pom.xml @@ -11,6 +11,6 @@ com.techivw web-price - 1.0-RELEASE + 1.1-RELEASE diff --git a/infrastructure/in/rest-api/pom.xml b/infrastructure/in/rest-api/pom.xml index 5826199..cc3fa87 100644 --- a/infrastructure/in/rest-api/pom.xml +++ b/infrastructure/in/rest-api/pom.xml @@ -7,7 +7,7 @@ com.techivw web-price - 1.0-RELEASE + 1.1-RELEASE ../../../pom.xml @@ -19,12 +19,12 @@ com.techivw domain - 1.0-RELEASE + 1.1-RELEASE com.techivw application - 1.0-RELEASE + 1.1-RELEASE diff --git a/infrastructure/out/sql-repository/pom.xml b/infrastructure/out/sql-repository/pom.xml index 9b9a268..806d137 100644 --- a/infrastructure/out/sql-repository/pom.xml +++ b/infrastructure/out/sql-repository/pom.xml @@ -11,7 +11,7 @@ com.techivw web-price - 1.0-RELEASE + 1.1-RELEASE ../../../pom.xml @@ -19,12 +19,12 @@ com.techivw domain - 1.0-RELEASE + 1.1-RELEASE com.techivw application - 1.0-RELEASE + 1.1-RELEASE org.flywaydb diff --git a/pom.xml b/pom.xml index dd1734c..e1ee433 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ com.techivw web-price - 1.0-RELEASE + 1.1-RELEASE pom web-price