From c4e4f744bc1e6c3ad7c90994677ec4d34c44e16c Mon Sep 17 00:00:00 2001 From: Kevin <kghisalberti@takima.fr> Date: Thu, 27 Feb 2025 10:44:41 +0100 Subject: [PATCH] feat: api finished --- README.md | 28 ++++++-- docker/docker-compose.yml | 4 +- examples.http | 43 ++++++++++++ .../features/block/entity/Block.java | 2 +- .../features/block/mapper/BlockMapper.java | 6 +- .../block/model/BlockCreationDTO.java | 6 ++ .../block/model/BlockCreationRequest.java | 6 -- .../block/service/SupplyBlockService.java | 14 ++-- .../offer/controller/OfferController.java | 6 +- ...tionRequest.java => OfferCreationDTO.java} | 8 ++- .../repository/OfferCustomRepository.java | 8 +-- .../offer/repository/OfferRepository.java | 1 - .../features/offer/service/OfferService.java | 31 +++------ .../controller/PowerPlantController.java | 4 +- .../powerplant/mapper/PowerPlantMapper.java | 11 +-- .../model/PowerPlantCreationDTO.java | 4 ++ .../model/PowerPlantCreationRequest.java | 4 -- .../powerplant/model/PowerPlantDTO.java | 2 +- .../powerplant/model/PowerPlantOfferDTO.java | 2 +- .../powerplant/model/PowerPlantType.java | 26 ++++++- .../powerplant/service/PowerPlantService.java | 8 +-- src/main/resources/application.yml | 4 +- .../example/agregiokata/data/TestData.java | 56 --------------- .../repository/OfferCustomRepositoryTest.java | 69 +++++++++++++++++++ ...st.java => PowerPlantRepositoryITest.java} | 32 +++------ src/test/resources/application.yml | 6 +- 26 files changed, 231 insertions(+), 160 deletions(-) create mode 100644 src/main/java/takima/example/agregiokata/features/block/model/BlockCreationDTO.java delete mode 100644 src/main/java/takima/example/agregiokata/features/block/model/BlockCreationRequest.java rename src/main/java/takima/example/agregiokata/features/offer/model/{OfferCreationRequest.java => OfferCreationDTO.java} (52%) create mode 100644 src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationDTO.java delete mode 100644 src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationRequest.java delete mode 100644 src/test/java/takima/example/agregiokata/data/TestData.java create mode 100644 src/test/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepositoryTest.java rename src/test/java/takima/example/agregiokata/features/powerplant/repository/{PowerPlantRepositoryTest.java => PowerPlantRepositoryITest.java} (82%) diff --git a/README.md b/README.md index f8b2e81..d24a9b5 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,18 @@ ##### - SpringBoot version 3.4.3 -##### - Maven +##### - Maven version 3.9 ##### - PostgresSQL version 15.7 +##### - Flyway version 10.20.1 + +##### - AssertJ/Junit5 + +##### - Mockito version 5.12.2 + +##### - Lombok + ### L'objectif Une API fonctionnelle avec des endpoints qui permettent de: @@ -37,7 +45,7 @@ L'API est principalement composée en trois domaines : Pour lancer la database, vous devez utilisez la commande au niveau de la racine du projet: ``` -cd db +cd docker docker compose up -d ``` @@ -56,21 +64,27 @@ mvn spring-boot:run Il est possible de visualiser les endpoints via cette URL: http://localhost:8080/swagger-ui/index.html +Un fichier exemple.http est également fourni pour essayer les endpoints + ### Le reste à faire et évolutions envisageables En reste à faire: -- Mettre des tests d'intégrations sur les repository qui n'en ont pas. -- Faire un test end-to-end avec un MockMVC +- Augmenter la couverture de test notamment en mettant en place des tests end-to-end pour m'assurer des retours + des endpoints en s'aidant d'outils comme MockMVC -Évolution possible: +Évolutions métiers: -- Donner la possibilité au bloc d'être associé à plusieurs parcs pour une attribution plus fine et complète de l' - énergie. +- Donner la possibilité au bloc d'être associé à plusieurs parcs pour une attribution plus fine et complète de + l'énergie. - Mettre un prix à l'énergie produit par un parc et rajouter ainsi une contrainte d'attribution d'énergie qui ne peut descendre en dessous du prix plancher du bloc. - Mettre en place de la logique concernant le temps sur les blocs d'une même offre (pour éviter que 2 blocs puissent se chevaucher sur une même période) + +Évolutions techniques pour une MEP: + - Mettre en place une sécurité sur les endpoints et ce que ça implique avec (système de rôle et de permission, utilisation d'outils comme Keycloak, etc...) +- Mise en place de variable d'environnement et de secrets - Création d'une CI/CD pour faciliter le déploiement et s'assurer de la qualité du code. diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 2f515d1..12569e5 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.9" - networks: agregio-network: @@ -9,7 +7,7 @@ services: image: agregio_db container_name: agregio_db networks: - - game + - agregio-network restart: always ports: - "5432:5432" diff --git a/examples.http b/examples.http index e69de29..d3145ec 100644 --- a/examples.http +++ b/examples.http @@ -0,0 +1,43 @@ +### Create a powerplant +POST http://localhost:8080/powerplants +Content-Type: application/json + +{ + "name": "SolarPark1", + "type": "SOLAR", + "capacityProduction": 750 +} + +### Create an offer +POST http://localhost:8080/offers +Content-Type: application/json + +{ + "market": "Réserve Primaire", + "blocks": [ + { + "startTime": "00:00", + "endTime": "03:00", + "production": 500.0, + "floorPrice": 30.0 + }, + { + "startTime": "03:00", + "endTime": "06:00", + "production": 50.0, + "floorPrice": 28.0 + } + ] +} + +### Get a powerplant by his ID +GET http://localhost:8080/powerplants/1 + +### Get all powerplants from a market +GET http://localhost:8080/powerplants?market=Réserve Primaire + +### Get an offer by his ID +GET http://localhost:8080/offers/1 + +### Get all offers of a market +GET http://localhost:8080/offers?market=Réserve Secondaire \ No newline at end of file diff --git a/src/main/java/takima/example/agregiokata/features/block/entity/Block.java b/src/main/java/takima/example/agregiokata/features/block/entity/Block.java index db7938a..e3ba1e7 100644 --- a/src/main/java/takima/example/agregiokata/features/block/entity/Block.java +++ b/src/main/java/takima/example/agregiokata/features/block/entity/Block.java @@ -46,7 +46,7 @@ public class Block { @ManyToOne(fetch = FetchType.LAZY) private Offer offer; - @ManyToOne(fetch = FetchType.EAGER) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "powerplant_id") @ToString.Exclude private PowerPlant plant; diff --git a/src/main/java/takima/example/agregiokata/features/block/mapper/BlockMapper.java b/src/main/java/takima/example/agregiokata/features/block/mapper/BlockMapper.java index acb8341..1264c63 100644 --- a/src/main/java/takima/example/agregiokata/features/block/mapper/BlockMapper.java +++ b/src/main/java/takima/example/agregiokata/features/block/mapper/BlockMapper.java @@ -2,7 +2,7 @@ package takima.example.agregiokata.features.block.mapper; import org.springframework.stereotype.Component; import takima.example.agregiokata.features.block.entity.Block; -import takima.example.agregiokata.features.block.model.BlockCreationRequest; +import takima.example.agregiokata.features.block.model.BlockCreationDTO; import takima.example.agregiokata.features.block.model.BlockDTO; import takima.example.agregiokata.features.powerplant.mapper.PowerPlantMapper; @@ -28,7 +28,7 @@ public class BlockMapper { ); } - public Block toEntity(BlockCreationRequest request) { + public Block toEntity(BlockCreationDTO request) { return Block.builder() .startTime(request.startTime()) .endTime(request.endTime()) @@ -37,7 +37,7 @@ public class BlockMapper { .build(); } - public List<Block> toEntities(List<BlockCreationRequest> requests) { + public List<Block> toEntities(List<BlockCreationDTO> requests) { return requests.stream().map(this::toEntity).toList(); } } diff --git a/src/main/java/takima/example/agregiokata/features/block/model/BlockCreationDTO.java b/src/main/java/takima/example/agregiokata/features/block/model/BlockCreationDTO.java new file mode 100644 index 0000000..7b91280 --- /dev/null +++ b/src/main/java/takima/example/agregiokata/features/block/model/BlockCreationDTO.java @@ -0,0 +1,6 @@ +package takima.example.agregiokata.features.block.model; + +import java.time.LocalTime; + +public record BlockCreationDTO(LocalTime startTime, LocalTime endTime, double production, double floorPrice) { +} diff --git a/src/main/java/takima/example/agregiokata/features/block/model/BlockCreationRequest.java b/src/main/java/takima/example/agregiokata/features/block/model/BlockCreationRequest.java deleted file mode 100644 index 261df5e..0000000 --- a/src/main/java/takima/example/agregiokata/features/block/model/BlockCreationRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -package takima.example.agregiokata.features.block.model; - -import java.time.LocalTime; - -public record BlockCreationRequest(LocalTime startTime, LocalTime endTime, double production, double floorPrice) { -} diff --git a/src/main/java/takima/example/agregiokata/features/block/service/SupplyBlockService.java b/src/main/java/takima/example/agregiokata/features/block/service/SupplyBlockService.java index 924a34e..fbcd7fb 100644 --- a/src/main/java/takima/example/agregiokata/features/block/service/SupplyBlockService.java +++ b/src/main/java/takima/example/agregiokata/features/block/service/SupplyBlockService.java @@ -1,6 +1,5 @@ package takima.example.agregiokata.features.block.service; -import lombok.val; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import takima.example.agregiokata.features.block.entity.Block; @@ -24,22 +23,22 @@ public class SupplyBlockService { @Transactional public void plantsSupplyBlocks(List<Block> blocks) { - val powerPlants = powerPlantRepository.availablePowerPlant(); + var powerPlants = powerPlantRepository.availablePowerPlant(); if (powerPlants.isEmpty()) { throw badRequest("There is no or not enough power plants available for the offer", new InsufficientResourcesException()); } - val sortedBlocks = blocks.stream() + var sortedBlocks = blocks.stream() .sorted(Comparator.comparingDouble(Block::getProduction).reversed()) .toList(); - val sortedPowerPlants = powerPlants.stream() + var sortedPowerPlants = powerPlants.stream() .sorted(Comparator.comparingDouble(PowerPlant::getCapacityProduction).reversed()) .toList(); sortedBlocks.forEach(block -> { - val plantToSupply = sortedPowerPlants.stream().filter(filterByAvailablePowerplant(block.getProduction())) + var plantToSupply = sortedPowerPlants.stream().filter(filterByAvailablePowerplant(block.getProduction())) .findFirst() .orElseThrow(() -> badRequest("There is no or not enough power plants available for the offer", new InsufficientResourcesException())); block.setPlant(plantToSupply); @@ -48,15 +47,14 @@ public class SupplyBlockService { plantToSupply.setBlocks(plantBlocks); } ); - System.out.println("t"); } - private static Predicate<PowerPlant> filterByAvailablePowerplant(Double powerToAdd) { + private Predicate<PowerPlant> filterByAvailablePowerplant(Double powerToAdd) { return plant -> plant.getCapacityProduction() >= getCurrentlySuppliedPlantPowerProduction(plant) + powerToAdd; } - private static double getCurrentlySuppliedPlantPowerProduction(PowerPlant plant) { + private double getCurrentlySuppliedPlantPowerProduction(PowerPlant plant) { if (plant.getBlocks().isEmpty()) { return 0.0; } diff --git a/src/main/java/takima/example/agregiokata/features/offer/controller/OfferController.java b/src/main/java/takima/example/agregiokata/features/offer/controller/OfferController.java index 0237633..af519cc 100644 --- a/src/main/java/takima/example/agregiokata/features/offer/controller/OfferController.java +++ b/src/main/java/takima/example/agregiokata/features/offer/controller/OfferController.java @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import takima.example.agregiokata.features.offer.model.OfferCreationRequest; +import takima.example.agregiokata.features.offer.model.OfferCreationDTO; import takima.example.agregiokata.features.offer.model.OfferDTO; import takima.example.agregiokata.features.offer.service.OfferService; @@ -38,8 +38,8 @@ public class OfferController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public OfferDTO create(@RequestBody OfferCreationRequest request) { - return offerService.create(request); + public OfferDTO create(@RequestBody OfferCreationDTO offerCreationDTO) { + return offerService.create(offerCreationDTO); } @DeleteMapping("/{id}") diff --git a/src/main/java/takima/example/agregiokata/features/offer/model/OfferCreationRequest.java b/src/main/java/takima/example/agregiokata/features/offer/model/OfferCreationDTO.java similarity index 52% rename from src/main/java/takima/example/agregiokata/features/offer/model/OfferCreationRequest.java rename to src/main/java/takima/example/agregiokata/features/offer/model/OfferCreationDTO.java index 250bad3..4ea32e0 100644 --- a/src/main/java/takima/example/agregiokata/features/offer/model/OfferCreationRequest.java +++ b/src/main/java/takima/example/agregiokata/features/offer/model/OfferCreationDTO.java @@ -1,9 +1,11 @@ package takima.example.agregiokata.features.offer.model; -import takima.example.agregiokata.features.block.model.BlockCreationRequest; +import takima.example.agregiokata.features.block.model.BlockCreationDTO; import java.util.List; -public record OfferCreationRequest(String market, - List<BlockCreationRequest> blocks) { +public record OfferCreationDTO( + String market, + List<BlockCreationDTO> blocks +) { } diff --git a/src/main/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepository.java b/src/main/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepository.java index 1207faa..cf90127 100644 --- a/src/main/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepository.java +++ b/src/main/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepository.java @@ -17,13 +17,13 @@ public interface OfferCustomRepository { join fetch b.plant where o.id = :id """) - public Optional<Offer> searchById(Long id); + Optional<Offer> searchById(Long id); @Query(""" select o from Offer o - join fetch o.blocks b - join fetch b.plant + left join fetch o.blocks b + left join fetch b.plant where o.market = :market """) - public List<Offer> findAllByMarket(Market market); + List<Offer> findAllByMarket(Market market); } diff --git a/src/main/java/takima/example/agregiokata/features/offer/repository/OfferRepository.java b/src/main/java/takima/example/agregiokata/features/offer/repository/OfferRepository.java index da075c5..c43eb79 100644 --- a/src/main/java/takima/example/agregiokata/features/offer/repository/OfferRepository.java +++ b/src/main/java/takima/example/agregiokata/features/offer/repository/OfferRepository.java @@ -4,7 +4,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import takima.example.agregiokata.features.offer.entity.Offer; -//TODO créer une interface pour bouger les findbyID, findAll que je redéfini et extends ici @Repository public interface OfferRepository extends JpaRepository<Offer, Long>, OfferCustomRepository { } diff --git a/src/main/java/takima/example/agregiokata/features/offer/service/OfferService.java b/src/main/java/takima/example/agregiokata/features/offer/service/OfferService.java index 8d5b164..697199e 100644 --- a/src/main/java/takima/example/agregiokata/features/offer/service/OfferService.java +++ b/src/main/java/takima/example/agregiokata/features/offer/service/OfferService.java @@ -4,15 +4,14 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import takima.example.agregiokata.features.block.entity.Block; import takima.example.agregiokata.features.block.mapper.BlockMapper; -import takima.example.agregiokata.features.block.model.BlockCreationRequest; +import takima.example.agregiokata.features.block.model.BlockCreationDTO; import takima.example.agregiokata.features.block.service.SupplyBlockService; import takima.example.agregiokata.features.market.model.Market; import takima.example.agregiokata.features.offer.entity.Offer; import takima.example.agregiokata.features.offer.mapper.OfferMapper; -import takima.example.agregiokata.features.offer.model.OfferCreationRequest; +import takima.example.agregiokata.features.offer.model.OfferCreationDTO; import takima.example.agregiokata.features.offer.model.OfferDTO; import takima.example.agregiokata.features.offer.repository.OfferRepository; -import takima.example.agregiokata.features.powerplant.repository.PowerPlantRepository; import java.util.List; @@ -24,15 +23,13 @@ public class OfferService { private final OfferRepository offerRepository; private final OfferMapper offerMapper; private final BlockMapper blockMapper; - private final PowerPlantRepository powerPlantRepository; private final SupplyBlockService supplyBlockService; public OfferService(OfferRepository offerRepository, OfferMapper offerMapper, BlockMapper blockMapper, - PowerPlantRepository powerPlantRepository, SupplyBlockService supplyBlockService) { + SupplyBlockService supplyBlockService) { this.offerRepository = offerRepository; this.offerMapper = offerMapper; this.blockMapper = blockMapper; - this.powerPlantRepository = powerPlantRepository; this.supplyBlockService = supplyBlockService; } @@ -40,18 +37,13 @@ public class OfferService { public OfferDTO getById(Long id) { return offerRepository.searchById(id) .map(offerMapper::toDTO) - .orElseThrow(() -> notFound("Power plant with id " + id + " not found")); + .orElseThrow(() -> notFound("Offer with id " + id + " not found")); } @Transactional(readOnly = true) public List<OfferDTO> search(String search) { var market = Market.fromString(search); - List<Offer> offers; - if (market == null) { - offers = offerRepository.findAll(); - } else { - offers = offerRepository.findAllByMarket(market); - } + List<Offer> offers = market == null ? offerRepository.findAll() : offerRepository.findAllByMarket(market); return offers .stream() .map(offerMapper::toDTO) @@ -59,27 +51,24 @@ public class OfferService { } @Transactional - public OfferDTO create(OfferCreationRequest request) { + public OfferDTO create(OfferCreationDTO offerCreationDTO) { var offer = Offer.builder() - .market(Market.fromString(request.market())) + .market(Market.fromString(offerCreationDTO.market())) .build(); - var blocks = createBlocksWithPowerPlant(request.blocks()); + var blocks = createBlocksWithPowerPlant(offerCreationDTO.blocks()); offer.setBlocks(blocks); - blocks.forEach(block -> { - block.setOffer(offer); - }); + blocks.forEach(block -> block.setOffer(offer)); var offerSaved = offerRepository.save(offer); return offerMapper.toDTO(offerSaved); } @Transactional - public List<Block> createBlocksWithPowerPlant(List<BlockCreationRequest> requests) { + public List<Block> createBlocksWithPowerPlant(List<BlockCreationDTO> requests) { var blocks = blockMapper.toEntities(requests); supplyBlockService.plantsSupplyBlocks(blocks); return blocks; } - @Transactional public void delete(Long id) { offerRepository.deleteById(id); diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/controller/PowerPlantController.java b/src/main/java/takima/example/agregiokata/features/powerplant/controller/PowerPlantController.java index a968358..fa278c2 100644 --- a/src/main/java/takima/example/agregiokata/features/powerplant/controller/PowerPlantController.java +++ b/src/main/java/takima/example/agregiokata/features/powerplant/controller/PowerPlantController.java @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import takima.example.agregiokata.features.powerplant.model.PowerPlantCreationRequest; +import takima.example.agregiokata.features.powerplant.model.PowerPlantCreationDTO; import takima.example.agregiokata.features.powerplant.model.PowerPlantDTO; import takima.example.agregiokata.features.powerplant.service.PowerPlantService; @@ -37,7 +37,7 @@ public class PowerPlantController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - public PowerPlantDTO create(@RequestBody PowerPlantCreationRequest request) { + public PowerPlantDTO create(@RequestBody PowerPlantCreationDTO request) { return powerPlantService.create(request); } diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/mapper/PowerPlantMapper.java b/src/main/java/takima/example/agregiokata/features/powerplant/mapper/PowerPlantMapper.java index ed1960c..b1d1694 100644 --- a/src/main/java/takima/example/agregiokata/features/powerplant/mapper/PowerPlantMapper.java +++ b/src/main/java/takima/example/agregiokata/features/powerplant/mapper/PowerPlantMapper.java @@ -2,9 +2,10 @@ package takima.example.agregiokata.features.powerplant.mapper; import org.springframework.stereotype.Component; import takima.example.agregiokata.features.powerplant.entity.PowerPlant; -import takima.example.agregiokata.features.powerplant.model.PowerPlantCreationRequest; +import takima.example.agregiokata.features.powerplant.model.PowerPlantCreationDTO; import takima.example.agregiokata.features.powerplant.model.PowerPlantDTO; import takima.example.agregiokata.features.powerplant.model.PowerPlantOfferDTO; +import takima.example.agregiokata.features.powerplant.model.PowerPlantType; import java.util.List; @@ -14,7 +15,7 @@ public class PowerPlantMapper { return new PowerPlantDTO( powerPlant.getId(), powerPlant.getName(), - powerPlant.getType(), + powerPlant.getType().getLabel(), powerPlant.getCapacityProduction() ); } @@ -23,14 +24,14 @@ public class PowerPlantMapper { return new PowerPlantOfferDTO( powerPlant.getId(), powerPlant.getName(), - powerPlant.getType() + powerPlant.getType().getLabel() ); } - public PowerPlant toEntity(PowerPlantCreationRequest request) { + public PowerPlant toEntity(PowerPlantCreationDTO request) { return PowerPlant.builder() .name(request.name()) - .type(request.type()) + .type(PowerPlantType.fromString(request.type())) .capacityProduction(request.capacityProduction()) .build(); } diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationDTO.java b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationDTO.java new file mode 100644 index 0000000..b4bd772 --- /dev/null +++ b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationDTO.java @@ -0,0 +1,4 @@ +package takima.example.agregiokata.features.powerplant.model; + +public record PowerPlantCreationDTO(String name, String type, double capacityProduction) { +} diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationRequest.java b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationRequest.java deleted file mode 100644 index c30b98a..0000000 --- a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantCreationRequest.java +++ /dev/null @@ -1,4 +0,0 @@ -package takima.example.agregiokata.features.powerplant.model; - -public record PowerPlantCreationRequest(String name, PowerPlantType type, double capacityProduction) { -} diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantDTO.java b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantDTO.java index f6f35b5..371050f 100644 --- a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantDTO.java +++ b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantDTO.java @@ -1,5 +1,5 @@ package takima.example.agregiokata.features.powerplant.model; -public record PowerPlantDTO(Long id, String name, PowerPlantType type, double capacityProduction) { +public record PowerPlantDTO(Long id, String name, String type, double capacityProduction) { } \ No newline at end of file diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantOfferDTO.java b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantOfferDTO.java index dac87e6..ab2fd82 100644 --- a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantOfferDTO.java +++ b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantOfferDTO.java @@ -1,4 +1,4 @@ package takima.example.agregiokata.features.powerplant.model; -public record PowerPlantOfferDTO(Long id, String name, PowerPlantType type) { +public record PowerPlantOfferDTO(Long id, String name, String type) { } diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantType.java b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantType.java index c5598cb..c6b6b71 100644 --- a/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantType.java +++ b/src/main/java/takima/example/agregiokata/features/powerplant/model/PowerPlantType.java @@ -1,7 +1,27 @@ package takima.example.agregiokata.features.powerplant.model; +import lombok.Getter; + +import java.util.Arrays; + +import static takima.example.agregiokata.core.exception.ErrorFactory.badRequest; + +@Getter public enum PowerPlantType { - SOLAR, - WIND, - HYDRO + SOLAR("Solaire"), + WIND("Éolien"), + HYDRO("Hydraulique"); + + private final String label; + + PowerPlantType(String label) { + this.label = label; + } + + public static PowerPlantType fromString(String value) { + return Arrays.stream(values()) + .filter(type -> type.name().equalsIgnoreCase(value) || type.label.equalsIgnoreCase(value)) + .findFirst() + .orElseThrow(() -> badRequest("Valeur de type de parc est invalide", new IllegalArgumentException("Valeur de type de parc est invalide : " + value))); + } } diff --git a/src/main/java/takima/example/agregiokata/features/powerplant/service/PowerPlantService.java b/src/main/java/takima/example/agregiokata/features/powerplant/service/PowerPlantService.java index d0a5e09..c628afb 100644 --- a/src/main/java/takima/example/agregiokata/features/powerplant/service/PowerPlantService.java +++ b/src/main/java/takima/example/agregiokata/features/powerplant/service/PowerPlantService.java @@ -5,7 +5,7 @@ import org.springframework.transaction.annotation.Transactional; import takima.example.agregiokata.features.market.model.Market; import takima.example.agregiokata.features.powerplant.entity.PowerPlant; import takima.example.agregiokata.features.powerplant.mapper.PowerPlantMapper; -import takima.example.agregiokata.features.powerplant.model.PowerPlantCreationRequest; +import takima.example.agregiokata.features.powerplant.model.PowerPlantCreationDTO; import takima.example.agregiokata.features.powerplant.model.PowerPlantDTO; import takima.example.agregiokata.features.powerplant.repository.PowerPlantRepository; @@ -27,10 +27,10 @@ public class PowerPlantService { public List<PowerPlantDTO> search(String searchMarket) { var market = Market.fromString(searchMarket); var result = powerPlantRepository.findAllByMarket(market); - if(result.isEmpty()) { + if (result.isEmpty()) { return List.of(); } - return result.stream().map(powerPlantMapper::toDTO).toList(); + return powerPlantMapper.toDTOs(result); } @Transactional(readOnly = true) @@ -41,7 +41,7 @@ public class PowerPlantService { } @Transactional - public PowerPlantDTO create(PowerPlantCreationRequest request) { + public PowerPlantDTO create(PowerPlantCreationDTO request) { PowerPlant powerPlant = powerPlantMapper.toEntity(request); return powerPlantMapper.toDTO(powerPlantRepository.save(powerPlant)); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2c44b0f..9932a97 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -12,7 +12,7 @@ spring: open-in-view: false flyway: schemas: public - logging: level: - sql: debug \ No newline at end of file + org.hibernate.SQL: info + org.hibernate.orm.jdbc.bind: info \ No newline at end of file diff --git a/src/test/java/takima/example/agregiokata/data/TestData.java b/src/test/java/takima/example/agregiokata/data/TestData.java deleted file mode 100644 index 937d786..0000000 --- a/src/test/java/takima/example/agregiokata/data/TestData.java +++ /dev/null @@ -1,56 +0,0 @@ -package takima.example.agregiokata.data; - -import takima.example.agregiokata.features.block.entity.Block; -import takima.example.agregiokata.features.powerplant.entity.PowerPlant; -import takima.example.agregiokata.features.powerplant.model.PowerPlantType; - -import java.time.LocalTime; -import java.util.ArrayList; - -public class TestData { - - public static final Block blockPlantless1 = Block.builder() - .startTime(LocalTime.of(8, 0)) - .endTime(LocalTime.of(9, 0)) - .floorPrice(100.0) - .production(300.0) - .build(); - - public static final Block blockPlantless2 = Block.builder() - .startTime(LocalTime.of(9, 0)) - .endTime(LocalTime.of(12, 0)) - .floorPrice(300.0) - .production(400.0) - .build(); - - public static final Block blockPlantless3 = Block.builder() - .startTime(LocalTime.of(12, 0)) - .endTime(LocalTime.of(15, 0)) - .floorPrice(50.0) - .production(100.0) - .build(); - - public static PowerPlant solarPlant = PowerPlant.builder() - .id(1L) - .name("Solar Plant") - .type(PowerPlantType.SOLAR) - .capacityProduction(500.0) - .blocks(new ArrayList<>()) - .build(); - - public static final PowerPlant windPlant = PowerPlant.builder() - .id(2L) - .name("Wind Plant") - .type(PowerPlantType.WIND) - .capacityProduction(400.0) - .blocks(new ArrayList<>()) - .build(); - - public static PowerPlant hydroPlant = PowerPlant.builder() - .name("Hydro Plant") - .type(PowerPlantType.HYDRO) - .capacityProduction(500.0) - .blocks(new ArrayList<>()) - .build(); - -} diff --git a/src/test/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepositoryTest.java b/src/test/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepositoryTest.java new file mode 100644 index 0000000..0dc1de8 --- /dev/null +++ b/src/test/java/takima/example/agregiokata/features/offer/repository/OfferCustomRepositoryTest.java @@ -0,0 +1,69 @@ +package takima.example.agregiokata.features.offer.repository; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.jdbc.Sql; +import org.testcontainers.utility.TestcontainersConfiguration; +import takima.example.agregiokata.features.market.model.Market; +import takima.example.agregiokata.features.offer.entity.Offer; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@Import(TestcontainersConfiguration.class) +@Sql(statements = "TRUNCATE TABLE powerplant, block, offer RESTART IDENTITY CASCADE; ", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +class OfferCustomRepositoryITest { + @Autowired + private OfferRepository offerRepository; + + private Offer offer; + private Offer offer2; + private Offer offer3; + + @BeforeEach + void setUp() { + offer = new Offer().toBuilder() + .market(Market.FAST_RESERVE) + .build(); + + offer2 = new Offer().toBuilder() + .market(Market.SECONDARY_RESERVE) + .build(); + + offer3 = new Offer().toBuilder() + .market(Market.FAST_RESERVE) + .build(); + } + + @Test + void searchById() { + offerRepository.save(offer); + + Optional<Offer> offerRequested = offerRepository.findById(1L); + + assertThat(offerRequested).isNotEmpty(); + assertThat(offerRequested.get().getId()).isEqualTo(1L); + assertThat(offerRequested.get().getMarket()).isEqualTo(Market.FAST_RESERVE); + } + + @Test + void findAllByMarket() { + offerRepository.save(offer); + offerRepository.save(offer2); + offerRepository.save(offer3); + + List<Offer> offersActual = offerRepository.findAllByMarket(Market.FAST_RESERVE); + + assertThat(offersActual).isNotEmpty(); + assertThat(offersActual).extracting(Offer::getId) + .containsExactlyInAnyOrder(1L, 3L); + assertThat(offersActual).extracting(Offer::getMarket) + .allMatch(Market.FAST_RESERVE::equals); + } +} \ No newline at end of file diff --git a/src/test/java/takima/example/agregiokata/features/powerplant/repository/PowerPlantRepositoryTest.java b/src/test/java/takima/example/agregiokata/features/powerplant/repository/PowerPlantRepositoryITest.java similarity index 82% rename from src/test/java/takima/example/agregiokata/features/powerplant/repository/PowerPlantRepositoryTest.java rename to src/test/java/takima/example/agregiokata/features/powerplant/repository/PowerPlantRepositoryITest.java index 33bf50a..d7cd485 100644 --- a/src/test/java/takima/example/agregiokata/features/powerplant/repository/PowerPlantRepositoryTest.java +++ b/src/test/java/takima/example/agregiokata/features/powerplant/repository/PowerPlantRepositoryITest.java @@ -27,7 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat; "ALTER SEQUENCE powerplant_id_seq RESTART WITH 1; " + "ALTER SEQUENCE block_id_seq RESTART WITH 1 ;" + "ALTER SEQUENCE offer_id_seq RESTART WITH 1;", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) -class PowerPlantRepositoryTest { +class PowerPlantRepositoryITest { @Autowired private PowerPlantRepository powerPlantRepository; @@ -39,10 +39,6 @@ class PowerPlantRepositoryTest { private PowerPlant hydroPlant; private PowerPlant solarPlant; - private Block blockPlantless1; - private Block blockPlantless3; - private Block blockPlantless2; - private Offer offer; private Offer offer2; @@ -57,7 +53,7 @@ class PowerPlantRepositoryTest { .market(Market.SECONDARY_RESERVE) .build(); - blockPlantless1 = Block.builder() + Block blockPlantless1 = Block.builder() .startTime(LocalTime.of(8, 0)) .endTime(LocalTime.of(9, 0)) .floorPrice(100.0) @@ -65,7 +61,7 @@ class PowerPlantRepositoryTest { .offer(offer) .build(); - blockPlantless2 = Block.builder() + Block blockPlantless2 = Block.builder() .startTime(LocalTime.of(9, 0)) .endTime(LocalTime.of(12, 0)) .floorPrice(300.0) @@ -73,7 +69,7 @@ class PowerPlantRepositoryTest { .offer(offer2) .build(); - blockPlantless3 = Block.builder() + Block blockPlantless3 = Block.builder() .startTime(LocalTime.of(12, 0)) .endTime(LocalTime.of(15, 0)) .floorPrice(50.0) @@ -107,11 +103,9 @@ class PowerPlantRepositoryTest { @DisplayName("should return all plant that still that have not production completely supplied") void availablePowerPlant() { offerRepository.save(offer); - var plantAvailable = powerPlantRepository.save(hydroPlant); - plantNotAvailable.getBlocks().forEach(block -> { - block.setPlant(plantNotAvailable); - }); - var plantAllSupplied = powerPlantRepository.save(plantNotAvailable); + powerPlantRepository.save(hydroPlant); + plantNotAvailable.getBlocks().forEach(block -> block.setPlant(plantNotAvailable)); + powerPlantRepository.save(plantNotAvailable); List<PowerPlant> availablePlants = powerPlantRepository.availablePowerPlant(); @@ -126,15 +120,11 @@ class PowerPlantRepositoryTest { offerRepository.save(offer); offerRepository.save(offer2); - solarPlant.getBlocks().forEach(block -> { - block.setPlant(solarPlant); - }); - var solarPlantSaved = powerPlantRepository.save(solarPlant); + solarPlant.getBlocks().forEach(block -> block.setPlant(solarPlant)); + powerPlantRepository.save(solarPlant); - plantNotAvailable.getBlocks().forEach(block -> { - block.setPlant(plantNotAvailable); - }); - var plantNotAvailableSaved = powerPlantRepository.save(plantNotAvailable); + plantNotAvailable.getBlocks().forEach(block -> block.setPlant(plantNotAvailable)); + powerPlantRepository.save(plantNotAvailable); List<PowerPlant> plantsByMarket = powerPlantRepository.findAllByMarket(Market.FAST_RESERVE); diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 621329a..fe58629 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -2,4 +2,8 @@ spring: datasource: url: jdbc:tc:postgresql:15.7:///agregio-db username: takima - password: takima \ No newline at end of file + password: takima +logging: + level: + org.hibernate.SQL: info + org.hibernate.orm.jdbc.bind: info \ No newline at end of file -- GitLab