From e4fd4629a95241326a50e8aaf8137396bdfdb144 Mon Sep 17 00:00:00 2001 From: Jim Martens Date: Mon, 10 Jul 2023 22:15:15 +0200 Subject: [PATCH] Implemented optimizations --- .../wahlrecht/model/db/Candidate.java | 9 +++-- .../wahlrecht/model/db/Constituency.java | 3 ++ .../wahlrecht/model/db/Election.java | 9 +++-- .../wahlrecht/model/db/Nomination.java | 9 +++-- .../wahlrecht/model/db/PartyInElection.java | 9 +++-- .../model/internal/NominationId.java | 5 +++ .../wahlrecht/model/internal/PartyId.java | 5 +++ .../wahlrecht/service/CandidateService.java | 34 ++++++++++++----- .../wahlrecht/service/NominationService.java | 38 +++++++++++++++---- .../wahlrecht/service/PartyService.java | 36 ++++++++++++++---- 10 files changed, 122 insertions(+), 35 deletions(-) create mode 100644 module-server/src/main/java/de/twomartens/wahlrecht/model/internal/NominationId.java create mode 100644 module-server/src/main/java/de/twomartens/wahlrecht/model/internal/PartyId.java diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Candidate.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Candidate.java index 343e45e..bf67741 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Candidate.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Candidate.java @@ -1,6 +1,6 @@ package de.twomartens.wahlrecht.model.db; -import java.util.Date; +import java.time.Instant; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -28,12 +28,15 @@ import org.springframework.data.mongodb.core.mapping.Document; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Candidate { + @EqualsAndHashCode.Exclude @Id ObjectId id; + @EqualsAndHashCode.Exclude @CreatedDate - Date created; + Instant created; + @EqualsAndHashCode.Exclude @LastModifiedDate - Date lastModified; + Instant lastModified; @Indexed String name; diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Constituency.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Constituency.java index ddc7685..9ddc7e8 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Constituency.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Constituency.java @@ -29,10 +29,13 @@ import org.springframework.data.mongodb.core.mapping.Document; @CompoundIndex(def = "{'number': 1, 'electionName': 1}") public class Constituency { + @EqualsAndHashCode.Exclude @Id ObjectId id; + @EqualsAndHashCode.Exclude @CreatedDate Instant created; + @EqualsAndHashCode.Exclude @LastModifiedDate Instant lastModified; diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Election.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Election.java index ffabe9c..d0d1be2 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Election.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Election.java @@ -1,9 +1,9 @@ package de.twomartens.wahlrecht.model.db; import de.twomartens.wahlrecht.model.dto.v1.VotingThreshold; +import java.time.Instant; import java.time.LocalDate; import java.util.Collection; -import java.util.Date; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -31,12 +31,15 @@ import org.springframework.data.mongodb.core.mapping.Document; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Election { + @EqualsAndHashCode.Exclude @Id ObjectId id; + @EqualsAndHashCode.Exclude @CreatedDate - Date created; + Instant created; + @EqualsAndHashCode.Exclude @LastModifiedDate - Date lastModified; + Instant lastModified; @Indexed(unique = true) String name; diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Nomination.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Nomination.java index 7bda16c..e0fec68 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Nomination.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/Nomination.java @@ -1,7 +1,7 @@ package de.twomartens.wahlrecht.model.db; +import java.time.Instant; import java.util.Collection; -import java.util.Date; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -30,12 +30,15 @@ import org.springframework.data.mongodb.core.mapping.Document; @CompoundIndex(def = "{'name': 1, 'partyAbbreviation': 1, 'electionName': 1}") public class Nomination { + @EqualsAndHashCode.Exclude @Id ObjectId id; + @EqualsAndHashCode.Exclude @CreatedDate - Date created; + Instant created; + @EqualsAndHashCode.Exclude @LastModifiedDate - Date lastModified; + Instant lastModified; String name; String partyAbbreviation; diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/PartyInElection.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/PartyInElection.java index ecb0aa6..3e667df 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/model/db/PartyInElection.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/db/PartyInElection.java @@ -1,6 +1,6 @@ package de.twomartens.wahlrecht.model.db; -import java.util.Date; +import java.time.Instant; import java.util.Map; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -30,12 +30,15 @@ import org.springframework.data.mongodb.core.mapping.Document; @CompoundIndex(def = "{'abbreviation': 1, 'electionName': 1}") public class PartyInElection { + @EqualsAndHashCode.Exclude @Id ObjectId id; + @EqualsAndHashCode.Exclude @CreatedDate - Date created; + Instant created; + @EqualsAndHashCode.Exclude @LastModifiedDate - Date lastModified; + Instant lastModified; String abbreviation; String electionName; diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/internal/NominationId.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/internal/NominationId.java new file mode 100644 index 0000000..a6c1177 --- /dev/null +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/internal/NominationId.java @@ -0,0 +1,5 @@ +package de.twomartens.wahlrecht.model.internal; + +public record NominationId(String electionName, String partyAbbreviation, String name) { + +} diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/model/internal/PartyId.java b/module-server/src/main/java/de/twomartens/wahlrecht/model/internal/PartyId.java new file mode 100644 index 0000000..d991119 --- /dev/null +++ b/module-server/src/main/java/de/twomartens/wahlrecht/model/internal/PartyId.java @@ -0,0 +1,5 @@ +package de.twomartens.wahlrecht.model.internal; + +public record PartyId(String electionName, String abbreviation) { + +} diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/service/CandidateService.java b/module-server/src/main/java/de/twomartens/wahlrecht/service/CandidateService.java index 63dde6a..b42212b 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/service/CandidateService.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/service/CandidateService.java @@ -2,7 +2,9 @@ package de.twomartens.wahlrecht.service; import de.twomartens.wahlrecht.model.db.Candidate; 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 org.springframework.lang.NonNull; import org.springframework.stereotype.Service; @@ -12,16 +14,30 @@ import org.springframework.stereotype.Service; public class CandidateService { private final CandidateRepository repository; + private Map candidates; public Candidate storeCandidate(@NonNull Candidate candidate) { - Optional foundOptional = repository.findByName(candidate.getName()); - - if (foundOptional.isPresent()) { - Candidate found = foundOptional.get(); - found.setProfession(candidate.getProfession()); - return repository.save(found); - } else { - return repository.save(candidate); + if (candidates == null) { + fetchCandidates(); } + 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())); } } diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/service/NominationService.java b/module-server/src/main/java/de/twomartens/wahlrecht/service/NominationService.java index db61bf0..d0b6945 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/service/NominationService.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/service/NominationService.java @@ -2,10 +2,13 @@ package de.twomartens.wahlrecht.service; import de.twomartens.wahlrecht.model.db.Candidate; import de.twomartens.wahlrecht.model.db.Nomination; +import de.twomartens.wahlrecht.model.internal.NominationId; import de.twomartens.wahlrecht.repository.NominationRepository; import java.util.ArrayList; 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 org.springframework.stereotype.Service; @@ -15,22 +18,43 @@ public class NominationService { private final NominationRepository repository; private final CandidateService candidateService; + private Map nominations; public Nomination storeNomination(Nomination nomination) { if (nomination == null) { return null; } - Optional existingOptional = repository - .findByNameAndElectionNameAndPartyAbbreviation(nomination.getName(), - nomination.getElectionName(), nomination.getPartyAbbreviation()); + if (nominations == null) { + fetchNominations(); + } + + 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 candidates = new ArrayList<>(); nomination.getCandidates() .forEach(candidate -> candidates.add(candidateService.storeCandidate(candidate))); - if (existingOptional.isPresent()) { - nomination = existingOptional.get(); + if (existing != null) { + nomination = existing; } 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())); } } diff --git a/module-server/src/main/java/de/twomartens/wahlrecht/service/PartyService.java b/module-server/src/main/java/de/twomartens/wahlrecht/service/PartyService.java index 58db41f..b8bdbc5 100644 --- a/module-server/src/main/java/de/twomartens/wahlrecht/service/PartyService.java +++ b/module-server/src/main/java/de/twomartens/wahlrecht/service/PartyService.java @@ -2,11 +2,15 @@ package de.twomartens.wahlrecht.service; import de.twomartens.wahlrecht.model.db.Nomination; import de.twomartens.wahlrecht.model.db.PartyInElection; +import de.twomartens.wahlrecht.model.internal.PartyId; import de.twomartens.wahlrecht.repository.PartyRepository; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -18,6 +22,7 @@ public class PartyService { private final PartyRepository partyRepository; private final NominationService nominationService; + private Map parties = null; public Collection getPartiesByElectionName(String electionName) { Collection parties = partyRepository.findByElectionName(electionName); @@ -34,22 +39,30 @@ public class PartyService { abbreviation, electionName); if (optionalParty.isEmpty()) { 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(); } public boolean storeParty(PartyInElection partyInElection) { + if (parties == null) { + fetchParties(); + } + boolean createdNew = true; - Optional existingOptional = partyRepository - .findByAbbreviationAndElectionName(partyInElection.getAbbreviation(), - partyInElection.getElectionName()); + PartyId partyId = new PartyId(partyInElection.getElectionName(), + partyInElection.getAbbreviation()); + PartyInElection existing = parties.get(partyId); + boolean needsUpdate = !partyInElection.equals(existing); + if (!needsUpdate) { + return false; + } + Map constituencyNominations = new HashMap<>(); partyInElection.getConstituencyNominations() .forEach((key, value) -> constituencyNominations.put(key, nominationService.storeNomination(value))); - if (existingOptional.isPresent()) { - PartyInElection existing = existingOptional.get(); + if (existing != null) { existing.setName(partyInElection.getName()); if (constituencyNominations.isEmpty()) { constituencyNominations.putAll(existing.getConstituencyNominations()); @@ -60,8 +73,17 @@ public class PartyService { partyInElection.setConstituencyNominations(constituencyNominations); partyInElection.setOverallNomination( nominationService.storeNomination(partyInElection.getOverallNomination())); - partyRepository.save(partyInElection); + partyInElection = partyRepository.save(partyInElection); + parties.put(partyId, partyInElection); return createdNew; } + + private void fetchParties() { + List allParties = partyRepository.findAll(); + parties = allParties.stream() + .collect(Collectors.toMap( + p -> new PartyId(p.getElectionName(), p.getAbbreviation()), + Function.identity())); + } }