Implemented optimizations

This commit is contained in:
2023-07-10 22:15:15 +02:00
parent ed9da5ef79
commit e4fd4629a9
10 changed files with 122 additions and 35 deletions
@@ -1,6 +1,6 @@
package de.twomartens.wahlrecht.model.db; package de.twomartens.wahlrecht.model.db;
import java.util.Date; import java.time.Instant;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
@@ -28,12 +28,15 @@ import org.springframework.data.mongodb.core.mapping.Document;
@AllArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Candidate { public class Candidate {
@EqualsAndHashCode.Exclude
@Id @Id
ObjectId id; ObjectId id;
@EqualsAndHashCode.Exclude
@CreatedDate @CreatedDate
Date created; Instant created;
@EqualsAndHashCode.Exclude
@LastModifiedDate @LastModifiedDate
Date lastModified; Instant lastModified;
@Indexed @Indexed
String name; String name;
@@ -29,10 +29,13 @@ import org.springframework.data.mongodb.core.mapping.Document;
@CompoundIndex(def = "{'number': 1, 'electionName': 1}") @CompoundIndex(def = "{'number': 1, 'electionName': 1}")
public class Constituency { public class Constituency {
@EqualsAndHashCode.Exclude
@Id @Id
ObjectId id; ObjectId id;
@EqualsAndHashCode.Exclude
@CreatedDate @CreatedDate
Instant created; Instant created;
@EqualsAndHashCode.Exclude
@LastModifiedDate @LastModifiedDate
Instant lastModified; Instant lastModified;
@@ -1,9 +1,9 @@
package de.twomartens.wahlrecht.model.db; package de.twomartens.wahlrecht.model.db;
import de.twomartens.wahlrecht.model.dto.v1.VotingThreshold; import de.twomartens.wahlrecht.model.dto.v1.VotingThreshold;
import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
@@ -31,12 +31,15 @@ import org.springframework.data.mongodb.core.mapping.Document;
@AllArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Election { public class Election {
@EqualsAndHashCode.Exclude
@Id @Id
ObjectId id; ObjectId id;
@EqualsAndHashCode.Exclude
@CreatedDate @CreatedDate
Date created; Instant created;
@EqualsAndHashCode.Exclude
@LastModifiedDate @LastModifiedDate
Date lastModified; Instant lastModified;
@Indexed(unique = true) @Indexed(unique = true)
String name; String name;
@@ -1,7 +1,7 @@
package de.twomartens.wahlrecht.model.db; package de.twomartens.wahlrecht.model.db;
import java.time.Instant;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
@@ -30,12 +30,15 @@ import org.springframework.data.mongodb.core.mapping.Document;
@CompoundIndex(def = "{'name': 1, 'partyAbbreviation': 1, 'electionName': 1}") @CompoundIndex(def = "{'name': 1, 'partyAbbreviation': 1, 'electionName': 1}")
public class Nomination { public class Nomination {
@EqualsAndHashCode.Exclude
@Id @Id
ObjectId id; ObjectId id;
@EqualsAndHashCode.Exclude
@CreatedDate @CreatedDate
Date created; Instant created;
@EqualsAndHashCode.Exclude
@LastModifiedDate @LastModifiedDate
Date lastModified; Instant lastModified;
String name; String name;
String partyAbbreviation; String partyAbbreviation;
@@ -1,6 +1,6 @@
package de.twomartens.wahlrecht.model.db; package de.twomartens.wahlrecht.model.db;
import java.util.Date; import java.time.Instant;
import java.util.Map; import java.util.Map;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -30,12 +30,15 @@ import org.springframework.data.mongodb.core.mapping.Document;
@CompoundIndex(def = "{'abbreviation': 1, 'electionName': 1}") @CompoundIndex(def = "{'abbreviation': 1, 'electionName': 1}")
public class PartyInElection { public class PartyInElection {
@EqualsAndHashCode.Exclude
@Id @Id
ObjectId id; ObjectId id;
@EqualsAndHashCode.Exclude
@CreatedDate @CreatedDate
Date created; Instant created;
@EqualsAndHashCode.Exclude
@LastModifiedDate @LastModifiedDate
Date lastModified; Instant lastModified;
String abbreviation; String abbreviation;
String electionName; String electionName;
@@ -0,0 +1,5 @@
package de.twomartens.wahlrecht.model.internal;
public record NominationId(String electionName, String partyAbbreviation, String name) {
}
@@ -0,0 +1,5 @@
package de.twomartens.wahlrecht.model.internal;
public record PartyId(String electionName, String abbreviation) {
}
@@ -2,7 +2,9 @@ package de.twomartens.wahlrecht.service;
import de.twomartens.wahlrecht.model.db.Candidate; import de.twomartens.wahlrecht.model.db.Candidate;
import de.twomartens.wahlrecht.repository.CandidateRepository; import de.twomartens.wahlrecht.repository.CandidateRepository;
import java.util.Optional; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -12,16 +14,30 @@ import org.springframework.stereotype.Service;
public class CandidateService { public class CandidateService {
private final CandidateRepository repository; private final CandidateRepository repository;
private Map<String, Candidate> candidates;
public Candidate storeCandidate(@NonNull Candidate candidate) { public Candidate storeCandidate(@NonNull Candidate candidate) {
Optional<Candidate> foundOptional = repository.findByName(candidate.getName()); if (candidates == null) {
fetchCandidates();
if (foundOptional.isPresent()) {
Candidate found = foundOptional.get();
found.setProfession(candidate.getProfession());
return repository.save(found);
} else {
return repository.save(candidate);
} }
Candidate existing = candidates.get(candidate.getName());
boolean needsUpdate = !candidate.equals(existing);
if (!needsUpdate) {
return existing;
}
if (existing != null) {
existing.setProfession(candidate.getProfession());
candidate = existing;
}
candidate = repository.save(candidate);
candidates.put(candidate.getName(), candidate);
return candidate;
}
private void fetchCandidates() {
candidates = repository.findAll().stream()
.collect(Collectors.toMap(Candidate::getName, Function.identity()));
} }
} }
@@ -2,10 +2,13 @@ package de.twomartens.wahlrecht.service;
import de.twomartens.wahlrecht.model.db.Candidate; import de.twomartens.wahlrecht.model.db.Candidate;
import de.twomartens.wahlrecht.model.db.Nomination; import de.twomartens.wahlrecht.model.db.Nomination;
import de.twomartens.wahlrecht.model.internal.NominationId;
import de.twomartens.wahlrecht.repository.NominationRepository; import de.twomartens.wahlrecht.repository.NominationRepository;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Optional; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -15,22 +18,43 @@ public class NominationService {
private final NominationRepository repository; private final NominationRepository repository;
private final CandidateService candidateService; private final CandidateService candidateService;
private Map<NominationId, Nomination> nominations;
public Nomination storeNomination(Nomination nomination) { public Nomination storeNomination(Nomination nomination) {
if (nomination == null) { if (nomination == null) {
return null; return null;
} }
Optional<Nomination> existingOptional = repository if (nominations == null) {
.findByNameAndElectionNameAndPartyAbbreviation(nomination.getName(), fetchNominations();
nomination.getElectionName(), nomination.getPartyAbbreviation()); }
NominationId nominationId = new NominationId(nomination.getElectionName(),
nomination.getPartyAbbreviation(), nomination.getName());
Nomination existing = nominations.get(nominationId);
boolean needsUpdate = !nomination.equals(existing);
if (!needsUpdate) {
return existing;
}
Collection<Candidate> candidates = new ArrayList<>(); Collection<Candidate> candidates = new ArrayList<>();
nomination.getCandidates() nomination.getCandidates()
.forEach(candidate -> candidates.add(candidateService.storeCandidate(candidate))); .forEach(candidate -> candidates.add(candidateService.storeCandidate(candidate)));
if (existingOptional.isPresent()) { if (existing != null) {
nomination = existingOptional.get(); nomination = existing;
} }
nomination.setCandidates(candidates); nomination.setCandidates(candidates);
return repository.save(nomination); nomination = repository.save(nomination);
nominations.put(nominationId, nomination);
return nomination;
}
private void fetchNominations() {
nominations = repository.findAll().stream()
.collect(Collectors.toMap(
n -> new NominationId(n.getElectionName(), n.getPartyAbbreviation(), n.getName()),
Function.identity()));
} }
} }
@@ -2,11 +2,15 @@ package de.twomartens.wahlrecht.service;
import de.twomartens.wahlrecht.model.db.Nomination; import de.twomartens.wahlrecht.model.db.Nomination;
import de.twomartens.wahlrecht.model.db.PartyInElection; import de.twomartens.wahlrecht.model.db.PartyInElection;
import de.twomartens.wahlrecht.model.internal.PartyId;
import de.twomartens.wahlrecht.repository.PartyRepository; import de.twomartens.wahlrecht.repository.PartyRepository;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -18,6 +22,7 @@ public class PartyService {
private final PartyRepository partyRepository; private final PartyRepository partyRepository;
private final NominationService nominationService; private final NominationService nominationService;
private Map<PartyId, PartyInElection> parties = null;
public Collection<PartyInElection> getPartiesByElectionName(String electionName) { public Collection<PartyInElection> getPartiesByElectionName(String electionName) {
Collection<PartyInElection> parties = partyRepository.findByElectionName(electionName); Collection<PartyInElection> parties = partyRepository.findByElectionName(electionName);
@@ -34,22 +39,30 @@ public class PartyService {
abbreviation, electionName); abbreviation, electionName);
if (optionalParty.isEmpty()) { if (optionalParty.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, throw new ResponseStatusException(HttpStatus.NOT_FOUND,
"no party found for %s and %s".formatted(electionName, abbreviation)); "no party found for %s and %s" .formatted(electionName, abbreviation));
} }
return optionalParty.get(); return optionalParty.get();
} }
public boolean storeParty(PartyInElection partyInElection) { public boolean storeParty(PartyInElection partyInElection) {
if (parties == null) {
fetchParties();
}
boolean createdNew = true; boolean createdNew = true;
Optional<PartyInElection> existingOptional = partyRepository PartyId partyId = new PartyId(partyInElection.getElectionName(),
.findByAbbreviationAndElectionName(partyInElection.getAbbreviation(), partyInElection.getAbbreviation());
partyInElection.getElectionName()); PartyInElection existing = parties.get(partyId);
boolean needsUpdate = !partyInElection.equals(existing);
if (!needsUpdate) {
return false;
}
Map<Integer, Nomination> constituencyNominations = new HashMap<>(); Map<Integer, Nomination> constituencyNominations = new HashMap<>();
partyInElection.getConstituencyNominations() partyInElection.getConstituencyNominations()
.forEach((key, value) -> constituencyNominations.put(key, .forEach((key, value) -> constituencyNominations.put(key,
nominationService.storeNomination(value))); nominationService.storeNomination(value)));
if (existingOptional.isPresent()) { if (existing != null) {
PartyInElection existing = existingOptional.get();
existing.setName(partyInElection.getName()); existing.setName(partyInElection.getName());
if (constituencyNominations.isEmpty()) { if (constituencyNominations.isEmpty()) {
constituencyNominations.putAll(existing.getConstituencyNominations()); constituencyNominations.putAll(existing.getConstituencyNominations());
@@ -60,8 +73,17 @@ public class PartyService {
partyInElection.setConstituencyNominations(constituencyNominations); partyInElection.setConstituencyNominations(constituencyNominations);
partyInElection.setOverallNomination( partyInElection.setOverallNomination(
nominationService.storeNomination(partyInElection.getOverallNomination())); nominationService.storeNomination(partyInElection.getOverallNomination()));
partyRepository.save(partyInElection); partyInElection = partyRepository.save(partyInElection);
parties.put(partyId, partyInElection);
return createdNew; return createdNew;
} }
private void fetchParties() {
List<PartyInElection> allParties = partyRepository.findAll();
parties = allParties.stream()
.collect(Collectors.toMap(
p -> new PartyId(p.getElectionName(), p.getAbbreviation()),
Function.identity()));
}
} }