La mise à jour d'un mélange crée, met à jour et supprime les ingrédients au lieu de tout recréer.
This commit is contained in:
parent
08c6a9db49
commit
50442d7ebc
|
@ -20,7 +20,7 @@ data class MixMaterial(
|
|||
@JoinColumn(name = "material_id")
|
||||
val material: Material,
|
||||
|
||||
val quantity: Float
|
||||
var quantity: Float
|
||||
) : Model {
|
||||
constructor(mix: Mix, material: Material, quantity: Float) : this(null, mix, material, quantity)
|
||||
|
||||
|
|
|
@ -15,8 +15,11 @@ interface MixMaterialService : ModelService<MixMaterial, MixMaterialRepository>
|
|||
/** Creates [MixMaterial]s from the given [map]. The [map] must have the format <Material ID, Quantity>. */
|
||||
fun createFromMap(mix: Mix, map: Map<Long, Float>): Collection<MixMaterial>
|
||||
|
||||
/** Creates a [MixMaterial] from the given [pair]. The [pair] must have the format <Material ID, Quantity>. */
|
||||
fun createFromPair(mix: Mix, pair: Pair<Long, Float>): MixMaterial
|
||||
/** Creates a [MixMaterial] with the material with the given [materialId] and the given [quantity]. */
|
||||
fun create(mix: Mix, materialId: Long, quantity: Float): MixMaterial
|
||||
|
||||
/** Updates the [quantity] of the given [mixMaterial]. */
|
||||
fun updateQuantity(mixMaterial: MixMaterial, quantity: Float): MixMaterial
|
||||
}
|
||||
|
||||
@Service
|
||||
|
@ -26,10 +29,13 @@ class MixMaterialServiceImpl(
|
|||
) : AbstractModelService<MixMaterial, MixMaterialRepository>(mixMaterialRepository), MixMaterialService {
|
||||
override fun existsByMaterial(material: Material): Boolean = repository.existsByMaterial(material)
|
||||
override fun createFromMap(mix: Mix, map: Map<Long, Float>): Collection<MixMaterial> =
|
||||
map.map { createFromPair(mix, it.toPair()) }
|
||||
map.map { create(mix, it.key, it.value) }
|
||||
|
||||
override fun createFromPair(mix: Mix, pair: Pair<Long, Float>): MixMaterial {
|
||||
val material = materialService.getById(pair.first)
|
||||
return mixMaterial(mix = mix, material = material, quantity = pair.second)
|
||||
}
|
||||
override fun create(mix: Mix, materialId: Long, quantity: Float): MixMaterial =
|
||||
mixMaterial(mix = mix, material = materialService.getById(materialId), quantity = quantity)
|
||||
|
||||
override fun updateQuantity(mixMaterial: MixMaterial, quantity: Float) =
|
||||
update(mixMaterial.apply {
|
||||
this.quantity = quantity
|
||||
})
|
||||
}
|
||||
|
|
|
@ -53,7 +53,33 @@ class MixServiceImpl(
|
|||
return mix
|
||||
}
|
||||
|
||||
@Transactional
|
||||
override fun update(entity: MixUpdateDto): Mix {
|
||||
fun updateMixMaterials(mix: Mix, mixMaterialsMap: Map<Long, Float>) {
|
||||
val existingMixMaterialsMaterialIds = mix.mixMaterials.map { it.material.id }
|
||||
val toDelete = mix.mixMaterials
|
||||
|
||||
mix.mixMaterials = mutableListOf(
|
||||
// update existing mix materials
|
||||
*mixMaterialsMap
|
||||
.filter { it.key in existingMixMaterialsMaterialIds }
|
||||
.map { (materialId, quantity) ->
|
||||
val existingMixMaterial = mix.mixMaterials.first { it.material.id == materialId }
|
||||
toDelete.remove(existingMixMaterial)
|
||||
mixMaterialService.updateQuantity(existingMixMaterial, quantity)
|
||||
}
|
||||
.toTypedArray(),
|
||||
// create new mix materials
|
||||
*mixMaterialsMap
|
||||
.filter { it.key !in existingMixMaterialsMaterialIds }
|
||||
.map { (materialId, quantity) -> mixMaterialService.create(mix, materialId, quantity) }
|
||||
.toTypedArray()
|
||||
)
|
||||
|
||||
// delete unused mix materials
|
||||
toDelete.forEach { mixMaterialService.delete(it) }
|
||||
}
|
||||
|
||||
val mix = getById(entity.id)
|
||||
if (entity.name != null || entity.materialTypeId != null) {
|
||||
mix.mixType = if (mixTypeIsShared(mix.mixType)) {
|
||||
|
@ -70,7 +96,7 @@ class MixServiceImpl(
|
|||
}
|
||||
}
|
||||
if (entity.mixMaterials != null) {
|
||||
mix.mixMaterials = mixMaterialService.createFromMap(mix, entity.mixMaterials).toMutableList()
|
||||
updateMixMaterials(mix, entity.mixMaterials)
|
||||
}
|
||||
return update(mix)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.service
|
||||
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.spy
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.Material
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.MixMaterial
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.material
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.mixMaterial
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.*
|
||||
import dev.fyloz.trial.colorrecipesexplorer.repository.MixMaterialRepository
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class MixMaterialServiceTest : AbstractModelServiceTest<MixMaterial, MixMaterialService, MixMaterialRepository>() {
|
||||
|
@ -19,11 +15,12 @@ class MixMaterialServiceTest : AbstractModelServiceTest<MixMaterial, MixMaterial
|
|||
override val service: MixMaterialService = spy(MixMaterialServiceImpl(repository, materialService))
|
||||
|
||||
private val material: Material = material(id = 0L)
|
||||
override val entity: MixMaterial = mixMaterial(id = 0L, material = material)
|
||||
override val entity: MixMaterial = mixMaterial(id = 0L, material = material, quantity = 1000f)
|
||||
override val anotherEntity: MixMaterial = mixMaterial(id = 1L, material = material)
|
||||
|
||||
// existsByMaterial()
|
||||
|
||||
@Test
|
||||
fun `existsByMaterial() returns true when a mix material with the given material exists`() {
|
||||
whenever(repository.existsByMaterial(material)).doReturn(true)
|
||||
|
||||
|
@ -32,6 +29,7 @@ class MixMaterialServiceTest : AbstractModelServiceTest<MixMaterial, MixMaterial
|
|||
assertTrue(found)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `existsByMaterial() returns false when no mix material with the given material exists`() {
|
||||
whenever(repository.existsByMaterial(material)).doReturn(false)
|
||||
|
||||
|
@ -39,4 +37,54 @@ class MixMaterialServiceTest : AbstractModelServiceTest<MixMaterial, MixMaterial
|
|||
|
||||
assertFalse(found)
|
||||
}
|
||||
|
||||
// createFromMap()
|
||||
|
||||
@Test
|
||||
fun `createFromMap() calls create() for each map entry`() {
|
||||
val mix = mix()
|
||||
val map = mapOf(
|
||||
1L to 1000f,
|
||||
2L to 2000f,
|
||||
5L to 5000f
|
||||
)
|
||||
val mixMaterials = map.map { mixMaterial(material = material(id = it.key), quantity = it.value) }
|
||||
|
||||
doAnswer { mixMaterials.first { mixMaterial -> mixMaterial.material.id == it.arguments[1] } }
|
||||
.whenever(service).create(eq(mix), any(), any())
|
||||
|
||||
val found = service.createFromMap(mix, map)
|
||||
|
||||
assertEquals(mixMaterials, found)
|
||||
}
|
||||
|
||||
// create()
|
||||
|
||||
@Test
|
||||
fun `create() creates a mix material with the given mix, material and quantity`() {
|
||||
val mix = mix()
|
||||
val material = material(id = 0L)
|
||||
val quantity = 1000f
|
||||
val mixMaterial = mixMaterial(mix = mix, material = material, quantity = quantity)
|
||||
|
||||
whenever(materialService.getById(material.id!!)).doReturn(material)
|
||||
|
||||
val found = service.create(mix, material.id!!, quantity)
|
||||
|
||||
assertEquals(mixMaterial, found)
|
||||
}
|
||||
|
||||
// updateQuantity()
|
||||
|
||||
@Test
|
||||
fun `updateQuantity() updates the given mix material with the given quantity`() {
|
||||
val quantity = 5000f
|
||||
assertNotEquals(quantity, entity.quantity, message = "Quantities must not be equals for this test to works")
|
||||
|
||||
doAnswer { it.arguments[0] }.whenever(service).update(any())
|
||||
|
||||
val found = service.updateQuantity(entity, quantity)
|
||||
|
||||
assertEquals(found.quantity, quantity)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ package dev.fyloz.trial.colorrecipesexplorer.service
|
|||
import com.nhaarman.mockitokotlin2.*
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.*
|
||||
import dev.fyloz.trial.colorrecipesexplorer.repository.MixRepository
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class MixServiceTest : AbstractExternalModelServiceTest<Mix, MixSaveDto, MixUpdateDto, MixService, MixRepository>() {
|
||||
override val repository: MixRepository = mock()
|
||||
|
@ -75,6 +75,31 @@ class MixServiceTest : AbstractExternalModelServiceTest<Mix, MixSaveDto, MixUpda
|
|||
|
||||
// update()
|
||||
|
||||
private fun mixUpdateDtoTest(
|
||||
scope: MixUpdateDtoTestScope = MixUpdateDtoTestScope(),
|
||||
sharedMixType: Boolean = false,
|
||||
op: MixUpdateDtoTestScope.() -> Unit
|
||||
) {
|
||||
with(scope) {
|
||||
doReturn(true).whenever(service).existsById(mix.id!!)
|
||||
doReturn(mix).whenever(service).getById(mix.id!!)
|
||||
doReturn(sharedMixType).whenever(service).mixTypeIsShared(mix.mixType)
|
||||
doAnswer { it.arguments[0] }.whenever(service).update(any<Mix>())
|
||||
|
||||
if (mixUpdateDto.materialTypeId != null) {
|
||||
whenever(materialTypeService.getById(materialType.id!!)).doReturn(materialType)
|
||||
}
|
||||
|
||||
op()
|
||||
}
|
||||
}
|
||||
|
||||
private fun mixUpdateDtoMixTypeTest(sharedMixType: Boolean = false, op: MixUpdateDtoTestScope.() -> Unit) {
|
||||
with(MixUpdateDtoTestScope(mixUpdateDto = mixUpdateDto(id = 0L, name = "name", materialTypeId = 0L))) {
|
||||
mixUpdateDtoTest(this, sharedMixType, op)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
override fun `update(dto) calls and returns update() with the created entity`() {
|
||||
val mixUpdateDto = spy(mixUpdateDto(id = 0L, name = null, materialTypeId = null))
|
||||
|
@ -91,47 +116,67 @@ class MixServiceTest : AbstractExternalModelServiceTest<Mix, MixSaveDto, MixUpda
|
|||
|
||||
@Test
|
||||
fun `update(dto) calls MixTypeService createForNameAndMaterialType() when mix type is shared`() {
|
||||
val newMixType = mixType(name = "another mix type")
|
||||
val mix = mix(id = 0L, mixType = mixType(name = "mix type"))
|
||||
val materialType = materialType(id = 0L)
|
||||
val mixUpdateDto = spy(mixUpdateDto(id = 0L, name = "mix", materialTypeId = 0L, mixMaterials = null))
|
||||
mixUpdateDtoMixTypeTest(sharedMixType = true) {
|
||||
whenever(mixTypeService.createForNameAndMaterialType(mixUpdateDto.name!!, materialType))
|
||||
.doReturn(newMixType)
|
||||
|
||||
doReturn(true).whenever(service).existsById(mix.id!!)
|
||||
doReturn(mix).whenever(service).getById(mix.id!!)
|
||||
doReturn(true).whenever(service).mixTypeIsShared(mix.mixType)
|
||||
doAnswer { it.arguments[0] }.whenever(service).update(any<Mix>())
|
||||
val found = service.update(mixUpdateDto)
|
||||
|
||||
whenever(materialTypeService.getById(materialType.id!!)).doReturn(materialType)
|
||||
whenever(mixTypeService.createForNameAndMaterialType(mixUpdateDto.name!!, materialType)).doReturn(newMixType)
|
||||
verify(mixTypeService).createForNameAndMaterialType(mixUpdateDto.name!!, materialType)
|
||||
|
||||
val found = service.update(mixUpdateDto)
|
||||
|
||||
verify(mixTypeService).createForNameAndMaterialType(mixUpdateDto.name!!, materialType)
|
||||
|
||||
assertEquals(newMixType, found.mixType)
|
||||
assertEquals(newMixType, found.mixType)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update(dto) calls MixTypeService updateForNameAndMaterialType() when mix type is not shared`() {
|
||||
val mixType = mixType(name = "mix type")
|
||||
val newMixType = mixType(name = "another mix type")
|
||||
val mix = mix(id = 0L, mixType = mixType)
|
||||
val materialType = materialType(id = 0L)
|
||||
val mixUpdateDto = spy(mixUpdateDto(id = 0L, name = "mix", materialTypeId = 0L, mixMaterials = null))
|
||||
mixUpdateDtoMixTypeTest {
|
||||
whenever(mixTypeService.updateForNameAndMaterialType(mixType, mixUpdateDto.name!!, materialType))
|
||||
.doReturn(newMixType)
|
||||
|
||||
doReturn(true).whenever(service).existsById(mix.id!!)
|
||||
doReturn(mix).whenever(service).getById(mix.id!!)
|
||||
doReturn(false).whenever(service).mixTypeIsShared(mix.mixType)
|
||||
doAnswer { it.arguments[0] }.whenever(service).update(any<Mix>())
|
||||
val found = service.update(mixUpdateDto)
|
||||
|
||||
whenever(materialTypeService.getById(materialType.id!!)).doReturn(materialType)
|
||||
whenever(mixTypeService.updateForNameAndMaterialType(mixType, mixUpdateDto.name!!, materialType)).doReturn(newMixType)
|
||||
verify(mixTypeService).updateForNameAndMaterialType(mixType, mixUpdateDto.name!!, materialType)
|
||||
|
||||
val found = service.update(mixUpdateDto)
|
||||
assertEquals(newMixType, found.mixType)
|
||||
}
|
||||
}
|
||||
|
||||
verify(mixTypeService).updateForNameAndMaterialType(mixType, mixUpdateDto.name!!, materialType)
|
||||
@Test
|
||||
fun `update(dto) update, create and delete mix materials according to the given mix materials map`() {
|
||||
mixUpdateDtoTest {
|
||||
// Pairs exists, impairs don't
|
||||
val materials = listOf(
|
||||
material(id = 1L),
|
||||
material(id = 2L),
|
||||
material(id = 3L),
|
||||
material(id = 4L),
|
||||
material(id = 5L),
|
||||
material(id = 6L),
|
||||
)
|
||||
val toDelete = mixMaterial(material = material(id = 7L), quantity = 7000f)
|
||||
val mixMaterialsMap = mapOf(*materials.map { it.id!! to it.id!! * 1000f }.toTypedArray())
|
||||
val allMixMaterials: Collection<MixMaterial> = materials
|
||||
.map { mixMaterial(mix = mix, material = it, quantity = mixMaterialsMap[it.id]!!) }
|
||||
val existingMixMaterials = allMixMaterials.filter { it.material.id!! % 2 == 0L }.toMutableList()
|
||||
existingMixMaterials += toDelete
|
||||
|
||||
assertEquals(newMixType, found.mixType)
|
||||
mix.mixMaterials = existingMixMaterials
|
||||
(mixUpdateDto.mixMaterials as MutableMap<Long, Float>).putAll(mixMaterialsMap)
|
||||
|
||||
doAnswer { allMixMaterials.first { mixMaterial -> mixMaterial.material.id == (it.arguments[0] as MixMaterial).material.id } }
|
||||
.whenever(mixMaterialService).updateQuantity(any(), any())
|
||||
doAnswer { allMixMaterials.first { mixMaterial -> mixMaterial.material.id == it.arguments[1] } }
|
||||
.whenever(mixMaterialService).create(eq(mix), any(), any())
|
||||
|
||||
val found: Mix = service.update(mixUpdateDto)
|
||||
|
||||
assertTrue { found.mixMaterials.containsAll(allMixMaterials) }
|
||||
|
||||
verify(mixMaterialService, times(3)).updateQuantity(argThat { material.id!! % 2 == 0L }, any())
|
||||
verify(mixMaterialService, times(3)).create(eq(mix), any(), any())
|
||||
verify(mixMaterialService).delete(toDelete)
|
||||
}
|
||||
}
|
||||
|
||||
// updateLocation()
|
||||
|
@ -147,3 +192,18 @@ class MixServiceTest : AbstractExternalModelServiceTest<Mix, MixSaveDto, MixUpda
|
|||
verify(service).update(expected)
|
||||
}
|
||||
}
|
||||
|
||||
data class MixUpdateDtoTestScope(
|
||||
val mixType: MixType = mixType(name = "mix type"),
|
||||
val newMixType: MixType = mixType(name = "another mix type"),
|
||||
val materialType: MaterialType = materialType(id = 0L),
|
||||
val mix: Mix = mix(id = 0L, mixType = mixType),
|
||||
val mixUpdateDto: MixUpdateDto = spy(
|
||||
mixUpdateDto(
|
||||
id = 0L,
|
||||
name = null,
|
||||
materialTypeId = null,
|
||||
mixMaterials = mutableMapOf()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue