From 27bf0402fc4d6570cbf98f0a148e66e5a2250944 Mon Sep 17 00:00:00 2001 From: GieniuG Date: Sat, 18 Apr 2026 20:06:11 +0200 Subject: [PATCH 1/5] add CRUD for location --- .../location/Location.java | 20 +++++++++++ .../location/LocationController.java | 34 +++++++++++++++++++ .../location/LocationRepository.java | 9 +++++ .../location/LocationService.java | 30 ++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java new file mode 100644 index 0000000..656d1a0 --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java @@ -0,0 +1,20 @@ +package pl.milosnicyit.codewarehousebackend.location; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "locations") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Location { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long idLokalizacji; + + @Column(nullable = false, unique = true) + private String nazwaLokalizacji; +} diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java new file mode 100644 index 0000000..7b3fa63 --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java @@ -0,0 +1,34 @@ +package pl.milosnicyit.codewarehousebackend.location; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.List; + +@RestController +@RequestMapping("/api/locations") +public class LocationController { + + private final LocationService locationService; + + public LocationController(LocationService locationService) { + this.locationService = locationService; + } + + @GetMapping + public ResponseEntity> getLocations() { + return ResponseEntity.ok(locationService.getAllLocations()); + } + @PostMapping + public ResponseEntity createLocation(@RequestBody Location location) { + return ResponseEntity.ok(locationService.addLocation(location)); + } + @PatchMapping("/{id}") + public ResponseEntity updateLocation(@PathVariable Long id, @RequestBody String newName) { + return ResponseEntity.ok(locationService.updateLocationName(id, newName)); + } + @DeleteMapping("/{id}") + public ResponseEntity deleteLocation(@PathVariable Long id) { + locationService.deleteLocation(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java new file mode 100644 index 0000000..719a43b --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java @@ -0,0 +1,9 @@ +package pl.milosnicyit.codewarehousebackend.location; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface LocationRepository extends JpaRepository { +} + diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java new file mode 100644 index 0000000..5664820 --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java @@ -0,0 +1,30 @@ +package pl.milosnicyit.codewarehousebackend.location; + +import org.springframework.stereotype.Service; +import java.util.List; + +@Service +public class LocationService { + + private final LocationRepository locationRepository; + + public LocationService(LocationRepository locationRepository) { + this.locationRepository = locationRepository; + } + public List getAllLocations() { + return locationRepository.findAll(); + } + public Location addLocation(Location location) { + return locationRepository.save(location); + } + public Location updateLocationName(Long id, String newName) { + Location existingLocation = locationRepository.findById(id) + .orElseThrow(() -> new RuntimeException("Lokalizacja nie istnieje")); + existingLocation.setNazwaLokalizacji(newName); + return locationRepository.save(existingLocation); + } + + public void deleteLocation(Long id) { + locationRepository.deleteById(id); + } +} From c49c0cc64e8b762baf2adae9516a365e4f191b6a Mon Sep 17 00:00:00 2001 From: GieniuG Date: Mon, 20 Apr 2026 19:21:20 +0200 Subject: [PATCH 2/5] Task 9 location module CRUD, clean architecture setup, tests --- .../location/Location.java | 4 +- .../location/LocationConfiguration.java | 16 ++++++ .../location/LocationController.java | 49 ++++++++++--------- .../location/LocationJpaRepository.java | 9 ++++ .../location/LocationRepository.java | 15 +++--- .../location/LocationRepositoryAdapter.java | 33 +++++++++++++ .../location/LocationService.java | 32 +++--------- .../location/LocationServiceImpl.java | 38 ++++++++++++++ .../LocationServiceSpecificationTest.java | 49 +++++++++++++++++++ 9 files changed, 189 insertions(+), 56 deletions(-) create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationJpaRepository.java create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepositoryAdapter.java create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java create mode 100644 src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java index 656d1a0..969769f 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java @@ -13,8 +13,8 @@ public class Location { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long idLokalizacji; + private Long id; @Column(nullable = false, unique = true) - private String nazwaLokalizacji; + private String name; } diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java new file mode 100644 index 0000000..e092791 --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java @@ -0,0 +1,16 @@ +package pl.milosnicyit.codewarehousebackend.location.adapter; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import pl.milosnicyit.codewarehousebackend.location.LocationRepository; +import pl.milosnicyit.codewarehousebackend.location.LocationService; +import pl.milosnicyit.codewarehousebackend.location.LocationServiceImpl; + +@Configuration +public class LocationConfiguration { + + @Bean + public LocationService locationService(LocationRepository locationRepository) { + return new LocationServiceImpl(locationRepository); + } +} \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java index 7b3fa63..a29de40 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java @@ -1,34 +1,39 @@ package pl.milosnicyit.codewarehousebackend.location; +import java.util.List; + +import org.jspecify.annotations.NonNull; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; @RestController @RequestMapping("/api/locations") public class LocationController { - private final LocationService locationService; + private final LocationService locationService; - public LocationController(LocationService locationService) { - this.locationService = locationService; - } + public LocationController(LocationService locationService) { + this.locationService = locationService; + } - @GetMapping - public ResponseEntity> getLocations() { - return ResponseEntity.ok(locationService.getAllLocations()); - } - @PostMapping - public ResponseEntity createLocation(@RequestBody Location location) { - return ResponseEntity.ok(locationService.addLocation(location)); - } - @PatchMapping("/{id}") - public ResponseEntity updateLocation(@PathVariable Long id, @RequestBody String newName) { - return ResponseEntity.ok(locationService.updateLocationName(id, newName)); - } - @DeleteMapping("/{id}") - public ResponseEntity deleteLocation(@PathVariable Long id) { - locationService.deleteLocation(id); - return ResponseEntity.noContent().build(); - } + @GetMapping + public ResponseEntity> getLocations() { + return ResponseEntity.ok(locationService.getAllLocations()); + } + @PostMapping + public ResponseEntity + createLocation(@RequestBody Location location) { + return ResponseEntity.ok(locationService.createLocation(location)); + } + @PatchMapping("/{id}") + public ResponseEntity + updateLocation(@PathVariable Long id, @RequestBody @NonNull Location locationUpdate) { + return ResponseEntity.ok( + locationService.updateLocationName(id, locationUpdate.getName())); + } + @DeleteMapping("/{id}") + public ResponseEntity deleteLocation(@PathVariable Long id) { + locationService.deleteLocation(id); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationJpaRepository.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationJpaRepository.java new file mode 100644 index 0000000..f669299 --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationJpaRepository.java @@ -0,0 +1,9 @@ +package pl.milosnicyit.codewarehousebackend.location.adapter; + +import org.springframework.data.jpa.repository.JpaRepository; +import pl.milosnicyit.codewarehousebackend.location.Location; +import java.util.Optional; + +public interface LocationJpaRepository extends JpaRepository { + Optional findByName(String name); +} \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java index 719a43b..3e0f191 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepository.java @@ -1,9 +1,12 @@ package pl.milosnicyit.codewarehousebackend.location; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface LocationRepository extends JpaRepository { -} +import java.util.List; +import java.util.Optional; +public interface LocationRepository { + List findAll(); + Optional findById(Long id); + Optional findByName(String name); + Location save(Location location); + void deleteById(Long id); +} \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepositoryAdapter.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepositoryAdapter.java new file mode 100644 index 0000000..b3c5bcd --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepositoryAdapter.java @@ -0,0 +1,33 @@ +package pl.milosnicyit.codewarehousebackend.location.adapter; + +import org.springframework.stereotype.Repository; +import pl.milosnicyit.codewarehousebackend.location.Location; +import pl.milosnicyit.codewarehousebackend.location.LocationRepository; + +import java.util.List; +import java.util.Optional; + +@Repository +public class LocationRepositoryAdapter implements LocationRepository { + + private final LocationJpaRepository jpaRepository; + + public LocationRepositoryAdapter(LocationJpaRepository jpaRepository) { + this.jpaRepository = jpaRepository; + } + + @Override + public List findAll() { return jpaRepository.findAll(); } + + @Override + public Optional findById(Long id) { return jpaRepository.findById(id); } + + @Override + public Optional findByName(String name) { return jpaRepository.findByName(name); } + + @Override + public Location save(Location location) { return jpaRepository.save(location); } + + @Override + public void deleteById(Long id) { jpaRepository.deleteById(id); } +} \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java index 5664820..1f45bef 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationService.java @@ -1,30 +1,10 @@ package pl.milosnicyit.codewarehousebackend.location; -import org.springframework.stereotype.Service; import java.util.List; -@Service -public class LocationService { - - private final LocationRepository locationRepository; - - public LocationService(LocationRepository locationRepository) { - this.locationRepository = locationRepository; - } - public List getAllLocations() { - return locationRepository.findAll(); - } - public Location addLocation(Location location) { - return locationRepository.save(location); - } - public Location updateLocationName(Long id, String newName) { - Location existingLocation = locationRepository.findById(id) - .orElseThrow(() -> new RuntimeException("Lokalizacja nie istnieje")); - existingLocation.setNazwaLokalizacji(newName); - return locationRepository.save(existingLocation); - } - - public void deleteLocation(Long id) { - locationRepository.deleteById(id); - } -} +public interface LocationService { + List getAllLocations(); + Location createLocation(Location location); + Location updateLocationName(Long id, String newName); + void deleteLocation(Long id); +} \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java new file mode 100644 index 0000000..4365446 --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java @@ -0,0 +1,38 @@ +package pl.milosnicyit.codewarehousebackend.location; + +import java.util.List; + +public class LocationServiceImpl implements LocationService { + + private final LocationRepository locationRepository; + + public LocationServiceImpl(LocationRepository locationRepository) { + this.locationRepository = locationRepository; + } + + @Override + public List getAllLocations() { + return locationRepository.findAll(); + } + + @Override + public Location createLocation(Location location) { + if (locationRepository.findByName(location.getName()).isPresent()) { + throw new IllegalArgumentException("Location with this name already exists"); + } + return locationRepository.save(location); + } + + @Override + public Location updateLocationName(Long id, String newName) { + Location existingLocation = locationRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Location not found")); + existingLocation.setName(newName); + return locationRepository.save(existingLocation); + } + + @Override + public void deleteLocation(Long id) { + locationRepository.deleteById(id); + } +} \ No newline at end of file diff --git a/src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java b/src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java new file mode 100644 index 0000000..3a8d2d3 --- /dev/null +++ b/src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java @@ -0,0 +1,49 @@ +package pl.milosnicyit.codewarehousebackend.location; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class LocationServiceSpecificationTest { + + @Mock + private LocationRepository locationRepository; + + private LocationService locationService; + + @BeforeEach + void setUp() { + locationService = new LocationServiceImpl(locationRepository); + } + + @Test + void shouldCreateLocationWhenNameIsUnique() { + Location location = new Location(1L, "Magazyn"); + when(locationRepository.findByName("Magazyn")).thenReturn(Optional.empty()); + when(locationRepository.save(any(Location.class))).thenReturn(location); + + Location result = locationService.createLocation(location); + + assertEquals("Magazyn", result.getName()); + verify(locationRepository).save(location); + } + + @Test + void shouldThrowExceptionWhenLocationNameExists() { + Location location = new Location(1L, "Magazyn"); + when(locationRepository.findByName("Magazyn")).thenReturn(Optional.of(location)); + + assertThrows(IllegalArgumentException.class, () -> locationService.createLocation(location)); + } +} \ No newline at end of file From fad4415713cadc469de869cb13953073ce7b4282 Mon Sep 17 00:00:00 2001 From: GieniuG Date: Mon, 20 Apr 2026 19:40:57 +0200 Subject: [PATCH 3/5] Task 9 remove unnecessary public --- .../v1}/location/LocationController.java | 16 +++++++++------- .../location/LocationConfiguration.java | 2 +- .../wrapper}/LocationJpaRepository.java | 4 ++-- .../wrapper/LocationRepositoryWrapper.java} | 6 +++--- 4 files changed, 15 insertions(+), 13 deletions(-) rename src/main/java/pl/milosnicyit/codewarehousebackend/{ => controllers/v1}/location/LocationController.java (66%) rename src/main/java/pl/milosnicyit/codewarehousebackend/location/{ => database/wrapper}/LocationJpaRepository.java (58%) rename src/main/java/pl/milosnicyit/codewarehousebackend/location/{LocationRepositoryAdapter.java => database/wrapper/LocationRepositoryWrapper.java} (81%) diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java b/src/main/java/pl/milosnicyit/codewarehousebackend/controllers/v1/location/LocationController.java similarity index 66% rename from src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java rename to src/main/java/pl/milosnicyit/codewarehousebackend/controllers/v1/location/LocationController.java index a29de40..bc70010 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationController.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/controllers/v1/location/LocationController.java @@ -1,38 +1,40 @@ -package pl.milosnicyit.codewarehousebackend.location; +package pl.milosnicyit.codewarehousebackend.controllers.v1.location; import java.util.List; import org.jspecify.annotations.NonNull; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import pl.milosnicyit.codewarehousebackend.location.Location; +import pl.milosnicyit.codewarehousebackend.location.LocationService; @RestController @RequestMapping("/api/locations") -public class LocationController { +class LocationController { private final LocationService locationService; - public LocationController(LocationService locationService) { + LocationController(LocationService locationService) { this.locationService = locationService; } @GetMapping - public ResponseEntity> getLocations() { + ResponseEntity> getLocations() { return ResponseEntity.ok(locationService.getAllLocations()); } @PostMapping - public ResponseEntity + ResponseEntity createLocation(@RequestBody Location location) { return ResponseEntity.ok(locationService.createLocation(location)); } @PatchMapping("/{id}") - public ResponseEntity + ResponseEntity updateLocation(@PathVariable Long id, @RequestBody @NonNull Location locationUpdate) { return ResponseEntity.ok( locationService.updateLocationName(id, locationUpdate.getName())); } @DeleteMapping("/{id}") - public ResponseEntity deleteLocation(@PathVariable Long id) { + ResponseEntity deleteLocation(@PathVariable Long id) { locationService.deleteLocation(id); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java index e092791..9625676 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationConfiguration.java @@ -7,7 +7,7 @@ import pl.milosnicyit.codewarehousebackend.location.LocationServiceImpl; @Configuration -public class LocationConfiguration { +class LocationConfiguration { @Bean public LocationService locationService(LocationRepository locationRepository) { diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationJpaRepository.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationJpaRepository.java similarity index 58% rename from src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationJpaRepository.java rename to src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationJpaRepository.java index f669299..2bf5874 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationJpaRepository.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationJpaRepository.java @@ -1,9 +1,9 @@ -package pl.milosnicyit.codewarehousebackend.location.adapter; +package pl.milosnicyit.codewarehousebackend.location.database.wrapper; import org.springframework.data.jpa.repository.JpaRepository; import pl.milosnicyit.codewarehousebackend.location.Location; import java.util.Optional; -public interface LocationJpaRepository extends JpaRepository { +interface LocationJpaRepository extends JpaRepository { Optional findByName(String name); } \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepositoryAdapter.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationRepositoryWrapper.java similarity index 81% rename from src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepositoryAdapter.java rename to src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationRepositoryWrapper.java index b3c5bcd..9ce83c5 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationRepositoryAdapter.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationRepositoryWrapper.java @@ -1,4 +1,4 @@ -package pl.milosnicyit.codewarehousebackend.location.adapter; +package pl.milosnicyit.codewarehousebackend.location.database.wrapper; import org.springframework.stereotype.Repository; import pl.milosnicyit.codewarehousebackend.location.Location; @@ -8,11 +8,11 @@ import java.util.Optional; @Repository -public class LocationRepositoryAdapter implements LocationRepository { +class LocationRepositoryWrapper implements LocationRepository { private final LocationJpaRepository jpaRepository; - public LocationRepositoryAdapter(LocationJpaRepository jpaRepository) { + public LocationRepositoryWrapper(LocationJpaRepository jpaRepository) { this.jpaRepository = jpaRepository; } From f94f022e50dd410f391489bf8f31450a623a2556 Mon Sep 17 00:00:00 2001 From: GieniuG Date: Mon, 20 Apr 2026 19:40:57 +0200 Subject: [PATCH 4/5] Task 9 remove unnecessary public --- .../location/Location.java | 11 +--- .../location/database/LocationEntity.java | 30 +++++++++++ .../wrapper/LocationJpaRepository.java | 8 +-- .../wrapper/LocationRepositoryWrapper.java | 28 ++++++++--- .../location/LocationControllerE2ETest.java | 50 +++++++++++++++++++ 5 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java create mode 100644 src/test/java/pl/milosnicyit/codewarehousebackend/controllers/v1/location/LocationControllerE2ETest.java diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java index 969769f..ac28103 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java @@ -1,20 +1,13 @@ package pl.milosnicyit.codewarehousebackend.location; -import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -@Entity -@Table(name = "locations") -@Data +@Data @NoArgsConstructor @AllArgsConstructor public class Location { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - - @Column(nullable = false, unique = true) private String name; -} +} \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java new file mode 100644 index 0000000..0a5afae --- /dev/null +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java @@ -0,0 +1,30 @@ +package pl.milosnicyit.codewarehousebackend.location.database; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import pl.milosnicyit.codewarehousebackend.location.Location; + +@Entity +@Table(name = "locations") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class LocationEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, unique = true) + private String name; + + public static LocationEntity fromDomain(Location location) { + return new LocationEntity(location.getId(), location.getName()); + } + + public Location toDomain() { + return new Location(id, name); + } +} \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationJpaRepository.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationJpaRepository.java index 2bf5874..16936e4 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationJpaRepository.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationJpaRepository.java @@ -1,9 +1,11 @@ package pl.milosnicyit.codewarehousebackend.location.database.wrapper; import org.springframework.data.jpa.repository.JpaRepository; -import pl.milosnicyit.codewarehousebackend.location.Location; + +import pl.milosnicyit.codewarehousebackend.location.database.LocationEntity; + import java.util.Optional; -interface LocationJpaRepository extends JpaRepository { - Optional findByName(String name); +interface LocationJpaRepository extends JpaRepository { + Optional findByName(String name); } \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationRepositoryWrapper.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationRepositoryWrapper.java index 9ce83c5..ed17c72 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationRepositoryWrapper.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/wrapper/LocationRepositoryWrapper.java @@ -3,31 +3,47 @@ import org.springframework.stereotype.Repository; import pl.milosnicyit.codewarehousebackend.location.Location; import pl.milosnicyit.codewarehousebackend.location.LocationRepository; +import pl.milosnicyit.codewarehousebackend.location.database.LocationEntity; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Repository class LocationRepositoryWrapper implements LocationRepository { private final LocationJpaRepository jpaRepository; - public LocationRepositoryWrapper(LocationJpaRepository jpaRepository) { + LocationRepositoryWrapper(LocationJpaRepository jpaRepository) { this.jpaRepository = jpaRepository; } @Override - public List findAll() { return jpaRepository.findAll(); } + public List findAll() { + return jpaRepository.findAll().stream() + .map(LocationEntity::toDomain) + .collect(Collectors.toList()); + } @Override - public Optional findById(Long id) { return jpaRepository.findById(id); } + public Optional findById(Long id) { + return jpaRepository.findById(id).map(LocationEntity::toDomain); + } @Override - public Optional findByName(String name) { return jpaRepository.findByName(name); } + public Optional findByName(String name) { + return jpaRepository.findByName(name).map(LocationEntity::toDomain); + } @Override - public Location save(Location location) { return jpaRepository.save(location); } + public Location save(Location location) { + LocationEntity entity = LocationEntity.fromDomain(location); + LocationEntity savedEntity = jpaRepository.save(entity); + return savedEntity.toDomain(); + } @Override - public void deleteById(Long id) { jpaRepository.deleteById(id); } + public void deleteById(Long id) { + jpaRepository.deleteById(id); + } } \ No newline at end of file diff --git a/src/test/java/pl/milosnicyit/codewarehousebackend/controllers/v1/location/LocationControllerE2ETest.java b/src/test/java/pl/milosnicyit/codewarehousebackend/controllers/v1/location/LocationControllerE2ETest.java new file mode 100644 index 0000000..951bda8 --- /dev/null +++ b/src/test/java/pl/milosnicyit/codewarehousebackend/controllers/v1/location/LocationControllerE2ETest.java @@ -0,0 +1,50 @@ +package pl.milosnicyit.codewarehousebackend.controllers.v1.location; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import pl.milosnicyit.codewarehousebackend.location.Location; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static pl.milosnicyit.codewarehousebackend.helpers.JsonHelper.toJson; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class LocationControllerE2ETest { + + private static final String LOCATION_ENDPOINT = "/api/locations"; + + @Autowired + private MockMvc mockMvc; + + @Test + @WithMockUser + void shouldCreateLocationEndToEnd() throws Exception { + Location location = new Location(); + location.setName("Magazyn E2E"); + + mockMvc.perform(post(LOCATION_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON) + .content(toJson(location))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").isNotEmpty()) + .andExpect(jsonPath("$.name").value("Magazyn E2E")); + } + + @Test + @WithMockUser + void shouldGetAllLocationsEndToEnd() throws Exception { + mockMvc.perform(get(LOCATION_ENDPOINT)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$").isArray()); + } +} \ No newline at end of file From 526aaae0afb56a3f2a9e0c208c987d8c75b3a1a9 Mon Sep 17 00:00:00 2001 From: GieniuG Date: Tue, 28 Apr 2026 18:30:07 +0200 Subject: [PATCH 5/5] Task 9 implement soft delete and non-empty business rules for locations --- .../location/Location.java | 16 ++++++++++++ .../location/LocationServiceImpl.java | 11 ++++++-- .../location/database/LocationEntity.java | 15 +++++++++-- .../LocationServiceSpecificationTest.java | 25 +++++++++++-------- 4 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java index ac28103..fcd0f8a 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/Location.java @@ -10,4 +10,20 @@ public class Location { private Long id; private String name; + private boolean active = true; + private boolean empty = true; + + public Location(Long id, String name) { + this.id = id; + this.name = name; + this.active = true; + this.empty = true; + } + + void deactivate() { + if (!this.empty) { + throw new IllegalStateException("Cannot delete location: it is not empty"); + } + this.active = false; + } } \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java index 4365446..20c7b44 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceImpl.java @@ -1,6 +1,7 @@ package pl.milosnicyit.codewarehousebackend.location; import java.util.List; +import java.util.stream.Collectors; public class LocationServiceImpl implements LocationService { @@ -12,7 +13,9 @@ public LocationServiceImpl(LocationRepository locationRepository) { @Override public List getAllLocations() { - return locationRepository.findAll(); + return locationRepository.findAll().stream() + .filter(Location::isActive) + .collect(Collectors.toList()); } @Override @@ -33,6 +36,10 @@ public Location updateLocationName(Long id, String newName) { @Override public void deleteLocation(Long id) { - locationRepository.deleteById(id); + Location location = locationRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Location not found")); + + location.deactivate(); + locationRepository.save(location); } } \ No newline at end of file diff --git a/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java index 0a5afae..e4ea28f 100644 --- a/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java +++ b/src/main/java/pl/milosnicyit/codewarehousebackend/location/database/LocationEntity.java @@ -20,11 +20,22 @@ public class LocationEntity { @Column(nullable = false, unique = true) private String name; + @Column(nullable = false) + private boolean active = true; + + @Column(nullable = false) + private boolean empty = true; + public static LocationEntity fromDomain(Location location) { - return new LocationEntity(location.getId(), location.getName()); + return new LocationEntity( + location.getId(), + location.getName(), + location.isActive(), + location.isEmpty() + ); } public Location toDomain() { - return new Location(id, name); + return new Location(id, name, active, empty); } } \ No newline at end of file diff --git a/src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java b/src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java index 3a8d2d3..0a91324 100644 --- a/src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java +++ b/src/test/java/pl/milosnicyit/codewarehousebackend/location/LocationServiceSpecificationTest.java @@ -9,6 +9,7 @@ import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; @@ -28,22 +29,26 @@ void setUp() { } @Test - void shouldCreateLocationWhenNameIsUnique() { - Location location = new Location(1L, "Magazyn"); - when(locationRepository.findByName("Magazyn")).thenReturn(Optional.empty()); - when(locationRepository.save(any(Location.class))).thenReturn(location); + void shouldDeactivateLocationWhenEmpty() { + // given (empty = true) + Location location = new Location(1L, "Magazyn", true, true); + when(locationRepository.findById(1L)).thenReturn(Optional.of(location)); - Location result = locationService.createLocation(location); + // when + locationService.deleteLocation(1L); - assertEquals("Magazyn", result.getName()); + // then + assertFalse(location.isActive()); verify(locationRepository).save(location); } @Test - void shouldThrowExceptionWhenLocationNameExists() { - Location location = new Location(1L, "Magazyn"); - when(locationRepository.findByName("Magazyn")).thenReturn(Optional.of(location)); + void shouldThrowExceptionWhenDeletingNonEmptyLocation() { + // given (empty = false) + Location location = new Location(1L, "Magazyn", true, false); + when(locationRepository.findById(1L)).thenReturn(Optional.of(location)); - assertThrows(IllegalArgumentException.class, () -> locationService.createLocation(location)); + // when / then + assertThrows(IllegalStateException.class, () -> locationService.deleteLocation(1L)); } } \ No newline at end of file