Skip to content

Commit db631d4

Browse files
committed
♻️ Unified "entity" storage in patcher
1 parent 269e845 commit db631d4

2 files changed

Lines changed: 40 additions & 43 deletions

File tree

sormas-backend/src/main/java/de/symeda/sormas/backend/patch/BusinessDtoFacade.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ public EntityDto fetchByI18nNameForCreateUpdate(@NotNull String i18nName, CaseDa
193193
.apply(caseDataDto);
194194
}
195195

196+
public Optional<EntityDto> tryFetchByI18nNameForCreateUpdate(@NotNull String i18nName, CaseDataDto caseDataDto) {
197+
return Optional.ofNullable(dtoRetrieverByI18nDictionaryCreateUpdate.get(i18nName))
198+
.map(fct -> fct.apply(caseDataDto));
199+
}
200+
196201
/**
197202
* For displaying purposes what purposes can be retrieved.
198203
*
@@ -219,4 +224,9 @@ public <T extends EntityDto> T save(@NotNull EntityDto entityDto) {
219224
.orElseThrow(() -> new IllegalStateException(String.format("No save function defined for: [%s]", entityDtoClass)))
220225
.apply((T) entityDto);
221226
}
227+
228+
public void save(@NotNull List<EntityDto> entityDtos) {
229+
entityDtos.forEach(this::save);
230+
}
231+
222232
}

sormas-backend/src/main/java/de/symeda/sormas/backend/patch/DataPatcherImpl.java

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,14 @@
1717
import org.slf4j.Logger;
1818
import org.slf4j.LoggerFactory;
1919

20-
import com.google.common.base.Suppliers;
21-
2220
import de.symeda.sormas.api.Disease;
21+
import de.symeda.sormas.api.EntityDto;
2322
import de.symeda.sormas.api.caze.CaseDataDto;
2423
import de.symeda.sormas.api.patch.*;
2524
import de.symeda.sormas.api.patch.mapping.FieldCustomMapper;
2625
import de.symeda.sormas.api.patch.mapping.FieldPatchRequest;
2726
import de.symeda.sormas.api.patch.mapping.ValueMappingResult;
2827
import de.symeda.sormas.api.patch.mapping.ValuePatchRequest;
29-
import de.symeda.sormas.api.person.PersonDto;
3028
import de.symeda.sormas.api.utils.Tuple;
3129
import de.symeda.sormas.api.utils.fieldvisibility.FieldVisibilityCheckers;
3230
import de.symeda.sormas.backend.common.ConfigFacadeEjb;
@@ -40,8 +38,6 @@
4038
@ApplicationScoped
4139
public class DataPatcherImpl implements DataPatcher {
4240

43-
public static final String PERSON_FIELD_NAME_PREFIX = "Person.";
44-
4541
private final static Logger logger = LoggerFactory.getLogger(DataPatcherImpl.class);
4642

4743
@Inject
@@ -93,10 +89,8 @@ public DataPatchResponse patch(CaseDataPatchRequest request) {
9389

9490
Disease disease = caseData.getDisease();
9591

96-
// TODO: modify to make more "agnostic": person is any other entity.
97-
// TODO: only case is different as it is the root.
98-
// make this generic for additional "root"-types
99-
Supplier<PersonDto> personSupplier = Suppliers.memoize(() -> getPersonDto(caseData));
92+
Map<String, EntityDto> entityCache = new HashMap<>();
93+
entityCache.put(CaseDataDto.I18N_PREFIX, caseData);
10094

10195
List<Tuple<String, Tuple<DataPatchFailureCause, Object>>> patchingTuples = computePatchingTuples(request);
10296

@@ -105,7 +99,7 @@ public DataPatchResponse patch(CaseDataPatchRequest request) {
10599
de.symeda.sormas.api.patch.SinglePatchResult singlePatchResult =
106100
new de.symeda.sormas.api.patch.SinglePatchResult().setFieldName(fullFieldName);
107101

108-
Supplier<Object> target = () -> findAppropriateTarget(fullFieldName, caseData, personSupplier);
102+
Supplier<Object> target = () -> findAppropriateTarget(fullFieldName, caseData, entityCache);
109103

110104
try {
111105
return produceSinglePatchResult(request, entry, disease, target);
@@ -130,7 +124,7 @@ public DataPatchResponse patch(CaseDataPatchRequest request) {
130124
return response;
131125
}
132126

133-
saveDTOsIfAppropriate(validPatchDictionary, caseData, personSupplier);
127+
saveDTOsIfAppropriate(entityCache);
134128

135129
logger.debug("dataPatchResponse: [{}]", response);
136130

@@ -148,31 +142,21 @@ public SinglePatchResult produceSinglePatchResult(
148142
.orElseGet(() -> valueMappingResult(entry, disease, request, target));
149143
}
150144

151-
private void saveDTOsIfAppropriate(Map<String, Object> validPatchDictionary, CaseDataDto caseData, Supplier<PersonDto> personSupplier) {
152-
if (anyFieldPatchedWithPrefix(validPatchDictionary, PatchFieldHelper.CASE_DATA_PREFIX)) {
153-
logger.info("CaseData was modified will be applied for: [{}]. Enable debug to see fully patched object", caseData);
154-
155-
if (logger.isDebugEnabled()) {
156-
logger.debug("CaseData: \n{}", ObjectMapperProvider.writeValueAsStringFailSafe(caseData));
157-
}
145+
private void saveDTOsIfAppropriate(Map<String, EntityDto> entityCache) {
146+
List<EntityDto> toSave = new ArrayList<>(entityCache.values());
158147

159-
businessDtoFacade.save(caseData);
148+
if (toSave.isEmpty()) {
149+
return;
160150
}
161151

162-
if (anyFieldPatchedWithPrefix(validPatchDictionary, PatchFieldHelper.PERSON_PREFIX)) {
163-
PersonDto person = personSupplier.get();
164-
logger.info("Person was modified will be applied for: [{}]. Enable debug fully patched object", person);
165-
152+
toSave.forEach(entity -> {
153+
logger.info("{} was modified, will be saved. Enable debug to see fully patched object", entity.getClass().getSimpleName());
166154
if (logger.isDebugEnabled()) {
167-
logger.debug("Person: \n{}", ObjectMapperProvider.writeValueAsStringFailSafe(person));
155+
logger.debug("{}: \n{}", entity.getClass().getSimpleName(), ObjectMapperProvider.writeValueAsStringFailSafe(entity));
168156
}
157+
});
169158

170-
businessDtoFacade.save(person);
171-
}
172-
}
173-
174-
private boolean anyFieldPatchedWithPrefix(Map<String, Object> validPatchDictionary, String caseDataPrefix) {
175-
return validPatchDictionary.keySet().stream().anyMatch(key -> key.startsWith(caseDataPrefix));
159+
businessDtoFacade.save(toSave);
176160
}
177161

178162
private @NotNull <R> Map<String, R> buildDictionaryFor(
@@ -378,16 +362,6 @@ private Tuple<String, Tuple<DataPatchFailureCause, Object>> buildMapTupleEntryFr
378362
return request.getEmptyValueBehavior() == EmptyValueBehavior.REPLACE ? ignored -> true : buildEmptyValuePredicate();
379363
}
380364

381-
private @NotNull PersonDto getPersonDto(CaseDataDto caseData) {
382-
String personUuid = caseData.getPerson().getUuid();
383-
PersonDto person = businessDtoFacade.fetch(PersonDto.class, caseData);
384-
385-
if (person == null) {
386-
throw new IllegalStateException(String.format("No person found for uuid: [%s]", personUuid));
387-
}
388-
return person;
389-
}
390-
391365
private @NotNull CaseDataDto getCaseDataDto(CaseDataPatchRequest request) {
392366
String caseUuid = request.getCaseUuid();
393367
CaseDataDto caseData = businessDtoFacade.getCaseDataDtoNullable(caseUuid);
@@ -398,14 +372,27 @@ private Tuple<String, Tuple<DataPatchFailureCause, Object>> buildMapTupleEntryFr
398372
return caseData;
399373
}
400374

401-
private Object findAppropriateTarget(String fieldName, CaseDataDto caseData, Supplier<PersonDto> person) {
402-
if (fieldName.startsWith(PERSON_FIELD_NAME_PREFIX)) {
403-
return person.get();
375+
private EntityDto findAppropriateTarget(String resolvedPath, CaseDataDto caseData, Map<String, EntityDto> entityCache) {
376+
String prefix = extractPrefix(resolvedPath);
377+
378+
if (entityCache.containsKey(prefix)) {
379+
return entityCache.get(prefix);
380+
}
381+
382+
Optional<EntityDto> fetched = businessDtoFacade.tryFetchByI18nNameForCreateUpdate(prefix, caseData);
383+
if (fetched.isPresent()) {
384+
entityCache.put(prefix, fetched.get());
385+
return fetched.get();
404386
}
405387

406388
return caseData;
407389
}
408390

391+
private String extractPrefix(String fieldName) {
392+
int dotIndex = fieldName.indexOf('.');
393+
return dotIndex == -1 ? fieldName : fieldName.substring(0, dotIndex);
394+
}
395+
409396
private Predicate<Map.Entry<String, Object>> buildEmptyValuePredicate() {
410397

411398
return stringObjectEntry -> {

0 commit comments

Comments
 (0)