refactor: extract ModificationManager for modification creation
Move create/batchCreate transactional logic from ModificationService into a dedicated ModificationManager. Both ModificationService and WebhookService delegate to the manager, respecting the Controller -> Service -> Manager layering rule.
This commit is contained in:
@@ -0,0 +1,115 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.manager;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Accessory;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Firearm;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Tuning;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.AccessoryRequest;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.ModificationRequest;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.ModificationResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.TuningRequest;
|
||||||
|
import com.onixbyte.deltaforceguide.repository.FirearmRepository;
|
||||||
|
import com.onixbyte.deltaforceguide.repository.ModificationRepository;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ModificationManager {
|
||||||
|
|
||||||
|
private final ModificationRepository modificationRepository;
|
||||||
|
private final FirearmRepository firearmRepository;
|
||||||
|
|
||||||
|
public ModificationManager(
|
||||||
|
ModificationRepository modificationRepository,
|
||||||
|
FirearmRepository firearmRepository
|
||||||
|
) {
|
||||||
|
this.modificationRepository = modificationRepository;
|
||||||
|
this.firearmRepository = firearmRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public ModificationResponse create(ModificationRequest request) {
|
||||||
|
var firearm = firearmRepository.findById(request.firearmId())
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
|
||||||
|
"Firearm not found: " + request.firearmId()));
|
||||||
|
var modification = toEntity(request, firearm);
|
||||||
|
return ModificationResponse.from(modificationRepository.save(modification));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<ModificationResponse> batchCreate(List<ModificationRequest> requests) {
|
||||||
|
var firearmIds = requests.stream()
|
||||||
|
.map(ModificationRequest::firearmId)
|
||||||
|
.collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
|
||||||
|
Map<Long, Firearm> firearmMap = new HashMap<>();
|
||||||
|
firearmRepository.findAllById(firearmIds)
|
||||||
|
.forEach(firearm -> firearmMap.put(firearm.getId(), firearm));
|
||||||
|
|
||||||
|
if (firearmMap.size() != firearmIds.size()) {
|
||||||
|
var missing = firearmIds.stream()
|
||||||
|
.filter((id) -> !firearmMap.containsKey(id))
|
||||||
|
.toList();
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
|
||||||
|
"Firearm not found: " + missing);
|
||||||
|
}
|
||||||
|
|
||||||
|
var modifications = requests.stream()
|
||||||
|
.map(req -> toEntity(req, firearmMap.get(req.firearmId())))
|
||||||
|
.toList();
|
||||||
|
return modificationRepository.saveAll(modifications)
|
||||||
|
.stream()
|
||||||
|
.map(ModificationResponse::from)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Modification toEntity(ModificationRequest request, Firearm firearm) {
|
||||||
|
return Modification.builder()
|
||||||
|
.firearm(firearm)
|
||||||
|
.name(request.name())
|
||||||
|
.code(request.code())
|
||||||
|
.tags(request.tags())
|
||||||
|
.accessories(toAccessories(request.accessories()))
|
||||||
|
.note(request.note())
|
||||||
|
.author(request.author())
|
||||||
|
.videoUrl(request.videoUrl())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Accessory> toAccessories(List<AccessoryRequest> requests) {
|
||||||
|
if (requests == null) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return requests.stream().map(this::toAccessory).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Accessory toAccessory(AccessoryRequest request) {
|
||||||
|
var accessory = new Accessory();
|
||||||
|
accessory.setSlotName(request.slotName());
|
||||||
|
accessory.setAccessoryName(request.accessoryName());
|
||||||
|
accessory.setTunings(toTunings(request.tunings()));
|
||||||
|
return accessory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Tuning> toTunings(List<TuningRequest> requests) {
|
||||||
|
if (requests == null) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return requests.stream().map(this::toTuning).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tuning toTuning(TuningRequest request) {
|
||||||
|
var tuning = new Tuning();
|
||||||
|
tuning.setTuningName(request.tuningName());
|
||||||
|
tuning.setTuningValue(request.tuningValue());
|
||||||
|
return tuning;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import com.onixbyte.deltaforceguide.domain.entity.Accessory;
|
|||||||
import com.onixbyte.deltaforceguide.domain.entity.Firearm;
|
import com.onixbyte.deltaforceguide.domain.entity.Firearm;
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.Tuning;
|
import com.onixbyte.deltaforceguide.domain.entity.Tuning;
|
||||||
|
import com.onixbyte.deltaforceguide.manager.ModificationManager;
|
||||||
import com.onixbyte.deltaforceguide.repository.FirearmRepository;
|
import com.onixbyte.deltaforceguide.repository.FirearmRepository;
|
||||||
import com.onixbyte.deltaforceguide.repository.ModificationRepository;
|
import com.onixbyte.deltaforceguide.repository.ModificationRepository;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
@@ -21,10 +22,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -32,15 +31,18 @@ public class ModificationService {
|
|||||||
|
|
||||||
private final ModificationRepository modificationRepository;
|
private final ModificationRepository modificationRepository;
|
||||||
private final FirearmRepository firearmRepository;
|
private final FirearmRepository firearmRepository;
|
||||||
|
private final ModificationManager modificationManager;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
public ModificationService(
|
public ModificationService(
|
||||||
ModificationRepository modificationRepository,
|
ModificationRepository modificationRepository,
|
||||||
FirearmRepository firearmRepository,
|
FirearmRepository firearmRepository,
|
||||||
|
ModificationManager modificationManager,
|
||||||
ObjectMapper objectMapper
|
ObjectMapper objectMapper
|
||||||
) {
|
) {
|
||||||
this.modificationRepository = modificationRepository;
|
this.modificationRepository = modificationRepository;
|
||||||
this.firearmRepository = firearmRepository;
|
this.firearmRepository = firearmRepository;
|
||||||
|
this.modificationManager = modificationManager;
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,36 +81,12 @@ public class ModificationService {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public ModificationResponse create(ModificationRequest request) {
|
public ModificationResponse create(ModificationRequest request) {
|
||||||
Firearm firearm = firearmRepository.findById(request.firearmId())
|
return modificationManager.create(request);
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Firearm not found: " + request.firearmId()));
|
|
||||||
|
|
||||||
Modification modification = toEntity(request, firearm);
|
|
||||||
return ModificationResponse.from(modificationRepository.save(modification));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<ModificationResponse> batchCreate(List<ModificationRequest> requests) {
|
public List<ModificationResponse> batchCreate(List<ModificationRequest> requests) {
|
||||||
Set<Long> firearmIds = requests.stream()
|
return modificationManager.batchCreate(requests);
|
||||||
.map(ModificationRequest::firearmId)
|
|
||||||
.collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new));
|
|
||||||
|
|
||||||
Map<Long, Firearm> firearmMap = new HashMap<>();
|
|
||||||
firearmRepository.findAllById(firearmIds).forEach(firearm -> firearmMap.put(firearm.getId(), firearm));
|
|
||||||
|
|
||||||
if (firearmMap.size() != firearmIds.size()) {
|
|
||||||
List<Long> missingFirearmIds = firearmIds.stream()
|
|
||||||
.filter(id -> !firearmMap.containsKey(id))
|
|
||||||
.toList();
|
|
||||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Firearm not found: " + missingFirearmIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Modification> modifications = requests.stream()
|
|
||||||
.map(request -> toEntity(request, firearmMap.get(request.firearmId())))
|
|
||||||
.toList();
|
|
||||||
return modificationRepository.saveAll(modifications)
|
|
||||||
.stream()
|
|
||||||
.map(ModificationResponse::from)
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -155,19 +133,6 @@ public class ModificationService {
|
|||||||
modificationRepository.deleteAllInBatch(modifications);
|
modificationRepository.deleteAllInBatch(modifications);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Modification toEntity(ModificationRequest request, Firearm firearm) {
|
|
||||||
return Modification.builder()
|
|
||||||
.firearm(firearm)
|
|
||||||
.name(request.name())
|
|
||||||
.code(request.code())
|
|
||||||
.tags(safeTags(request.tags()))
|
|
||||||
.accessories(toAccessories(request.accessories()))
|
|
||||||
.note(request.note())
|
|
||||||
.author(request.author())
|
|
||||||
.videoUrl(request.videoUrl())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> safeTags(List<String> tags) {
|
private List<String> safeTags(List<String> tags) {
|
||||||
return tags == null ? new ArrayList<>() : tags;
|
return tags == null ? new ArrayList<>() : tags;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user