diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/model/MixType.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/model/MixType.java deleted file mode 100644 index 30811e0..0000000 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/model/MixType.java +++ /dev/null @@ -1,50 +0,0 @@ -package dev.fyloz.trial.colorrecipesexplorer.model; - -import lombok.*; -import org.jetbrains.annotations.Nullable; - -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import java.util.Objects; - -@Entity -@Data -@NoArgsConstructor -@RequiredArgsConstructor -@AllArgsConstructor -public class MixType implements Model { - - public static final String IDENTIFIER_MATERIAL_NAME = "material"; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) - private Long id; - - @NonNull - @NotNull - private String name; - - @NonNull - @NotNull - @ManyToOne(cascade = CascadeType.ALL) - private Material material; - - public void setName(String name, boolean editMaterial) { - this.name = name; - if (editMaterial) this.material.setName(name); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MixType mixType = (MixType) o; - return Objects.equals(name, mixType.name) && - Objects.equals(material, mixType.material); - } - - @Override - public int hashCode() { - return Objects.hash(name, material); - } -} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/repository/MixTypeRepository.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/repository/MixTypeRepository.java deleted file mode 100644 index e88ed7d..0000000 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/repository/MixTypeRepository.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.fyloz.trial.colorrecipesexplorer.repository; - -import dev.fyloz.trial.colorrecipesexplorer.model.Material; -import dev.fyloz.trial.colorrecipesexplorer.model.MixType; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public interface MixTypeRepository extends JpaRepository { - - boolean existsByName(String name); - - Optional findByName(String name); - - Optional findByMaterial(Material material); -} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixService.java index 1f54ac5..a07175c 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixService.java @@ -2,10 +2,7 @@ package dev.fyloz.trial.colorrecipesexplorer.service.model; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsException; import dev.fyloz.trial.colorrecipesexplorer.exception.model.ModelException; -import dev.fyloz.trial.colorrecipesexplorer.model.Material; -import dev.fyloz.trial.colorrecipesexplorer.model.Mix; -import dev.fyloz.trial.colorrecipesexplorer.model.MixType; -import dev.fyloz.trial.colorrecipesexplorer.model.Recipe; +import dev.fyloz.trial.colorrecipesexplorer.model.*; import dev.fyloz.trial.colorrecipesexplorer.model.dto.MixFormDto; import dev.fyloz.trial.colorrecipesexplorer.service.AbstractJavaService; import dev.fyloz.trial.colorrecipesexplorer.utils.MixBuilder; @@ -23,7 +20,7 @@ public class MixService extends AbstractJavaService { private MaterialJavaService materialService; private MixMaterialJavaService mixQuantityService; - private MixTypeService mixTypeService; + private MixTypeJavaService mixTypeService; public MixService() { super(Mix.class); @@ -45,7 +42,7 @@ public class MixService extends AbstractJavaService { } @Autowired - public void setMixTypeService(MixTypeService mixTypeService) { + public void setMixTypeService(MixTypeJavaService mixTypeService) { this.mixTypeService = mixTypeService; } @@ -118,7 +115,7 @@ public class MixService extends AbstractJavaService { throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, Mix.IDENTIFIER_MIX_TYPE_NAME, mix.getMixType().getName()); if (materialService.existsByName(mixType.getName()) && !materialService.getByName(mixType.getName()).isMixType()) - throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, MixType.IDENTIFIER_MATERIAL_NAME, mixType.getName()); + throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, MixTypeKt.IDENTIFIER_MATERIAL_NAME, mixType.getName()); mixTypeService.update(mixType); update(mix); diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixTypeService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixTypeJavaService.java similarity index 85% rename from src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixTypeService.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixTypeJavaService.java index ab9cf12..7a5e050 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixTypeService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixTypeJavaService.java @@ -4,10 +4,11 @@ import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsE import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundException; import dev.fyloz.trial.colorrecipesexplorer.exception.model.ModelException; import dev.fyloz.trial.colorrecipesexplorer.model.Material; -import dev.fyloz.trial.colorrecipesexplorer.model.MixType; import dev.fyloz.trial.colorrecipesexplorer.model.MaterialType; -import dev.fyloz.trial.colorrecipesexplorer.service.AbstractJavaService; +import dev.fyloz.trial.colorrecipesexplorer.model.MixType; +import dev.fyloz.trial.colorrecipesexplorer.model.MixTypeKt; import dev.fyloz.trial.colorrecipesexplorer.repository.MixTypeRepository; +import dev.fyloz.trial.colorrecipesexplorer.service.AbstractJavaService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,11 +16,11 @@ import javax.validation.constraints.NotNull; import java.util.Optional; @Service -public class MixTypeService extends AbstractJavaService { +public class MixTypeJavaService extends AbstractJavaService { private MaterialJavaService materialService; - public MixTypeService() { + public MixTypeJavaService() { super(MixType.class); } @@ -50,7 +51,7 @@ public class MixTypeService extends AbstractJavaService found = repository.findByName(name); + Optional found = findOptional(repository.findByName(name)); if (found.isEmpty()) throw new EntityNotFoundException(type, ModelException.IdentifierType.NAME, name); return found.get(); @@ -63,9 +64,9 @@ public class MixTypeService extends AbstractJavaService found = repository.findByMaterial(material); + Optional found = findOptional(repository.findByMaterial(material)); if (found.isEmpty()) - throw new EntityNotFoundException(type, ModelException.IdentifierType.OTHER, MixType.IDENTIFIER_MATERIAL_NAME, material); + throw new EntityNotFoundException(type, ModelException.IdentifierType.OTHER, MixTypeKt.IDENTIFIER_MATERIAL_NAME, material); return found.get(); } @@ -85,7 +86,7 @@ public class MixTypeService extends AbstractJavaService quantities = new LinkedHashMap<>(); - public MixBuilder(MixTypeService mixTypeService, MaterialJavaService materialService) { + public MixBuilder(MixTypeJavaService mixTypeService, MaterialJavaService materialService) { this.mixTypeService = mixTypeService; this.materialService = materialService; } @@ -45,10 +45,11 @@ public class MixBuilder { this.mixType = new MixType(this.mixType.getId(), this.mixType.getName(), this.mixType.getMaterial()); if (materialService.existsByName(mixTypeName)) { - this.mixType.setName(mixTypeName, false); + this.mixType.setName(mixTypeName); this.mixType.setMaterial(materialService.getByName(mixTypeName)); } else { - this.mixType.setName(mixTypeName, true); + this.mixType.setName(mixTypeName); + this.mixType.getMaterial().setName(mixTypeName); } this.mixType.getMaterial().setMaterialType(dto.getMaterialType()); diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java index e86e9a4..3795998 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java @@ -2,11 +2,11 @@ package dev.fyloz.trial.colorrecipesexplorer.web.controller.thymeleaf.creators; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsException; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundException; +import dev.fyloz.trial.colorrecipesexplorer.model.MixTypeKt; import dev.fyloz.trial.colorrecipesexplorer.web.response.ModelResponseBuilder; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseCode; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseDataType; import dev.fyloz.trial.colorrecipesexplorer.model.Mix; -import dev.fyloz.trial.colorrecipesexplorer.model.MixType; import dev.fyloz.trial.colorrecipesexplorer.model.Recipe; import dev.fyloz.trial.colorrecipesexplorer.model.dto.MixFormDto; import dev.fyloz.trial.colorrecipesexplorer.service.ServiceKt; @@ -35,7 +35,7 @@ public class MixCreatorController { private MaterialTypeJavaService materialTypeService; @Autowired - public MixCreatorController(MixService mixService, RecipeService recipeService, MaterialJavaService materialService, MixTypeService mixTypeService, MaterialTypeJavaService materialTypeService) { + public MixCreatorController(MixService mixService, RecipeService recipeService, MaterialJavaService materialService, MixTypeJavaService mixTypeService, MaterialTypeJavaService materialTypeService) { this.mixService = mixService; this.recipeService = recipeService; this.materialService = materialService; @@ -80,7 +80,7 @@ public class MixCreatorController { } catch (EntityAlreadyExistsException ex) { if (ex.getIdentifierName().equals(Mix.IDENTIFIER_MIX_TYPE_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, ex.getRequestedId()); - else if (ex.getIdentifierName().equals(MixType.IDENTIFIER_MATERIAL_NAME)) + else if (ex.getIdentifierName().equals(MixTypeKt.IDENTIFIER_MATERIAL_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_AND_MIX_TYPE_CANNOT_HAVE_SAME_NAME); } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java index 1517d4b..5ba7e2b 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java @@ -2,11 +2,11 @@ package dev.fyloz.trial.colorrecipesexplorer.web.controller.thymeleaf.editors; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsException; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundException; +import dev.fyloz.trial.colorrecipesexplorer.model.MixTypeKt; import dev.fyloz.trial.colorrecipesexplorer.web.response.ModelResponseBuilder; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseCode; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseDataType; import dev.fyloz.trial.colorrecipesexplorer.model.Mix; -import dev.fyloz.trial.colorrecipesexplorer.model.MixType; import dev.fyloz.trial.colorrecipesexplorer.model.dto.MixFormDto; import dev.fyloz.trial.colorrecipesexplorer.service.model.MaterialJavaService; import dev.fyloz.trial.colorrecipesexplorer.service.model.MaterialTypeJavaService; @@ -72,7 +72,7 @@ public class MixEditorController { } catch (EntityNotFoundException ex) { modelResponseBuilder.addResponseCode(ResponseCode.MIX_NOT_FOUND, id).build(); } catch (EntityAlreadyExistsException ex) { - if (ex.getIdentifierName().equals(MixType.IDENTIFIER_MATERIAL_NAME)) + if (ex.getIdentifierName().equals(MixTypeKt.IDENTIFIER_MATERIAL_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_AND_MIX_TYPE_CANNOT_HAVE_SAME_NAME); else if (ex.getIdentifierName().equals(Mix.IDENTIFIER_MIX_TYPE_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, ex.getRequestedId()); diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/MixMaterial.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/MixMaterial.kt index 4cc18fc..5acf2cb 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/MixMaterial.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/MixMaterial.kt @@ -29,7 +29,7 @@ data class MixMaterial( // ==== DSL ==== fun mixMaterial( - id: Long? = 0L, + id: Long? = null, mix: Mix = TODO(), material: Material = material(), quantity: Float = 0f, diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/MixType.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/MixType.kt new file mode 100644 index 0000000..b683050 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/MixType.kt @@ -0,0 +1,41 @@ +package dev.fyloz.trial.colorrecipesexplorer.model + +import java.util.* +import javax.persistence.* + +const val IDENTIFIER_MATERIAL_NAME = "material" + +@Entity +data class MixType( + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + override val id: Long?, + + @Column(unique = true) + override var name: String, + + @ManyToOne + var material: Material? +) : NamedModel { + constructor(name: String, material: Material) : this(null, name, material) + + override fun equals(other: Any?): Boolean = other is MixType && other.name == name && other.material == material + override fun hashCode(): Int = Objects.hash(name, material) +} + +// ==== DSL ==== +fun mixType( + id: Long? = null, + name: String = "name", + material: Material = material(), + op: MixType.() -> Unit = {} +) = MixType(id, name, material).apply(op) + +fun mixType( + name: String = "name", + materialType: MaterialType = materialType(), + op: MixType.() -> Unit = {} +) = MixType( + name, + material(name = name, inventoryQuantity = 0f, isMixType = true, materialType = materialType) +).apply(op) diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/repository/MixTypeRepository.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/repository/MixTypeRepository.kt new file mode 100644 index 0000000..0ae4ccc --- /dev/null +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/repository/MixTypeRepository.kt @@ -0,0 +1,11 @@ +package dev.fyloz.trial.colorrecipesexplorer.repository + +import dev.fyloz.trial.colorrecipesexplorer.model.Material +import dev.fyloz.trial.colorrecipesexplorer.model.MixType +import org.springframework.stereotype.Repository + +@Repository +interface MixTypeRepository : NamedJpaRepository { + /** Gets the mix type with the given [material]. */ + fun findByMaterial(material: Material): MixType? +} diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt index 0a96442..95b45d7 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/InventoryService.kt @@ -10,7 +10,7 @@ import org.springframework.stereotype.Service const val minimumQuantity = 100.0f // TODO quantity stored in database @Service -class InventoryService(val materialService: MaterialServiceImpl) { +class InventoryService(val materialService: MaterialService) { fun getAllMaterials(): Collection { return materialService.getAllNotMixType().map { it.toInventoryMaterial(minimumQuantity) } } diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt index c04accf..3fd19f3 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MaterialService.kt @@ -3,7 +3,6 @@ package dev.fyloz.trial.colorrecipesexplorer.service import dev.fyloz.trial.colorrecipesexplorer.model.* import dev.fyloz.trial.colorrecipesexplorer.repository.MaterialRepository import dev.fyloz.trial.colorrecipesexplorer.service.files.SimdutService -import dev.fyloz.trial.colorrecipesexplorer.service.model.MixMaterialJavaService import io.jsonwebtoken.lang.Assert import org.springframework.stereotype.Service diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixTypeService.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixTypeService.kt new file mode 100644 index 0000000..076da23 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixTypeService.kt @@ -0,0 +1,26 @@ +package dev.fyloz.trial.colorrecipesexplorer.service + +import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsRestException +import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundRestException +import dev.fyloz.trial.colorrecipesexplorer.model.Material +import dev.fyloz.trial.colorrecipesexplorer.model.MixType +import dev.fyloz.trial.colorrecipesexplorer.repository.MixTypeRepository +import org.springframework.stereotype.Service + +interface MixTypeService : NamedModelService { + /** Gets the mix type with the given [material]. */ + fun getByMaterial(material: Material): MixType +} + +@Service +class MixTypeServiceImpl(mixTypeRepository: MixTypeRepository, private val materialService: MaterialService) : + AbstractNamedModelService(mixTypeRepository), MixTypeService { + override fun getByMaterial(material: Material): MixType = + repository.findByMaterial(material) ?: throw EntityNotFoundRestException(material.name) + + override fun save(entity: MixType): MixType { + if (materialService.existsByName(entity.name)) + throw EntityAlreadyExistsRestException(entity.name) + return super.save(entity) + } +} diff --git a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixTypeServiceTest.kt b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixTypeServiceTest.kt new file mode 100644 index 0000000..b673e9b --- /dev/null +++ b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixTypeServiceTest.kt @@ -0,0 +1,63 @@ +package dev.fyloz.trial.colorrecipesexplorer.service + +import com.nhaarman.mockitokotlin2.* +import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsRestException +import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundRestException +import dev.fyloz.trial.colorrecipesexplorer.model.Material +import dev.fyloz.trial.colorrecipesexplorer.model.MixType +import dev.fyloz.trial.colorrecipesexplorer.model.material +import dev.fyloz.trial.colorrecipesexplorer.model.mixType +import dev.fyloz.trial.colorrecipesexplorer.repository.MixTypeRepository +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import kotlin.test.assertEquals + +class MixTypeServiceTest : AbstractNamedModelServiceTest() { + override val repository: MixTypeRepository = mock() + private val materialService: MaterialService = mock() + override val service: MixTypeService = spy(MixTypeServiceImpl(repository, materialService)) + + private val material: Material = material(id = 0L) + override val entity: MixType = mixType(id = 0L, name = "mix type", material = material) + override val anotherEntity: MixType = mixType(id = 1L, name = "another mix type") + override val entityWithEntityName: MixType = mixType(id = 2L, name = entity.name) + + @AfterEach + override fun afterEach() { + reset(materialService) + super.afterEach() + } + + @Nested + inner class GetByMaterial { + @Test + fun `returns the mix type with the given material`() { + whenever(repository.findByMaterial(material)).doReturn(entity) + + val found = service.getByMaterial(material) + + assertEquals(entity, found) + } + + @Test + fun `throws EntityNotFoundRestException when no mix type with the given material exists`() { + whenever(repository.findByMaterial(material)).doReturn(null) + + val exception = assertThrows { service.getByMaterial(material) } + assertEquals(material.name, exception.value) + } + } + + @Nested + inner class SaveMixType { + @Test + fun `throws EntityAlreadyExistsRestException when a material with the name of the new mix type exists`() { + whenever(materialService.existsByName(entity.name)).doReturn(true) + + val exception = assertThrows { service.save(entity) } + assertEquals(entity.name, exception.value) + } + } +}