Introduced NominationId as key for maps

This commit is contained in:
2023-07-13 19:44:51 +02:00
parent b2fee57f9e
commit aa533f6c72
16 changed files with 176 additions and 72 deletions
@@ -1,10 +1,12 @@
package de.twomartens.wahlrecht.mapper.v1;
import de.twomartens.wahlrecht.model.dto.v1.ElectedCandidate;
import de.twomartens.wahlrecht.model.dto.v1.VotingResult;
import de.twomartens.wahlrecht.model.dto.v1.NominationId;
import de.twomartens.wahlrecht.model.internal.ElectedResult;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.NullValueCheckStrategy;
@@ -17,19 +19,19 @@ public interface ElectedResultMapper {
de.twomartens.wahlrecht.model.dto.v1.ElectedResult mapToExternal(ElectedResult result);
Map<VotingResult, Collection<ElectedCandidate>> mapToExternal(
Map<de.twomartens.wahlrecht.model.internal.VotingResult,
Map<NominationId, Collection<ElectedCandidate>> mapToExternal(
Map<de.twomartens.wahlrecht.model.internal.NominationId,
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> value);
Collection<ElectedCandidate> mapToExternal(
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate> value);
ElectedResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.ElectedResult result);
default Map<de.twomartens.wahlrecht.model.internal.NominationId,
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> map(
Map<de.twomartens.wahlrecht.model.internal.VotingResult,
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> value) {
return value.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getNominationId(), Entry::getValue));
}
Map<de.twomartens.wahlrecht.model.internal.VotingResult,
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate>> mapToInternal(
Map<VotingResult, Collection<ElectedCandidate>> value);
Collection<de.twomartens.wahlrecht.model.internal.ElectedCandidate> mapToInternal(
Collection<ElectedCandidate> value);
}
@@ -0,0 +1,14 @@
package de.twomartens.wahlrecht.mapper.v1;
import de.twomartens.wahlrecht.model.dto.v1.NominationId;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.ReportingPolicy;
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface NominationIdMapper {
NominationId mapToExternal(de.twomartens.wahlrecht.model.internal.NominationId id);
}
@@ -2,6 +2,7 @@ package de.twomartens.wahlrecht.mapper.v1;
import de.twomartens.wahlrecht.model.db.Nomination;
import de.twomartens.wahlrecht.model.internal.Candidate;
import de.twomartens.wahlrecht.model.internal.NominationId;
import java.util.Collection;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper;
@@ -16,15 +17,35 @@ public interface NominationMapper {
de.twomartens.wahlrecht.model.dto.v1.Nomination mapToExternal(Nomination nomination);
de.twomartens.wahlrecht.model.internal.Nomination mapToInternal(
de.twomartens.wahlrecht.model.dto.v1.Nomination nomination);
default de.twomartens.wahlrecht.model.internal.Nomination mapToInternal(
de.twomartens.wahlrecht.model.dto.v1.Nomination nomination) {
de.twomartens.wahlrecht.model.internal.Nomination result =
new de.twomartens.wahlrecht.model.internal.Nomination(
new NominationId(nomination.getElectionName(), nomination.getPartyAbbreviation(),
nomination.getName()),
nomination.isSupportVotesOnNomination()
);
result.addCandidates(mapFromDto(nomination.getCandidates()));
return result;
}
de.twomartens.wahlrecht.model.internal.Nomination mapToInternal(Nomination nomination);
default de.twomartens.wahlrecht.model.internal.Nomination mapToInternal(Nomination nomination) {
de.twomartens.wahlrecht.model.internal.Nomination result =
new de.twomartens.wahlrecht.model.internal.Nomination(
new NominationId(nomination.getElectionName(), nomination.getPartyAbbreviation(),
nomination.getName()),
nomination.isSupportVotesOnNomination()
);
result.addCandidates(mapFromDb(nomination.getCandidates()));
return result;
}
@Mapping(target = "id", ignore = true)
@Mapping(target = "created", ignore = true)
@Mapping(target = "lastModified", ignore = true)
Nomination mapToDB(de.twomartens.wahlrecht.model.dto.v1.Nomination nomination);
Collection<Candidate> map(Collection<de.twomartens.wahlrecht.model.db.Candidate> candidates);
Collection<Candidate> mapFromDb(Collection<de.twomartens.wahlrecht.model.db.Candidate> candidates);
Collection<Candidate> mapFromDto(Collection<de.twomartens.wahlrecht.model.dto.v1.Candidate> candidates);
}
@@ -1,5 +1,6 @@
package de.twomartens.wahlrecht.mapper.v1;
import de.twomartens.wahlrecht.model.internal.NominationId;
import de.twomartens.wahlrecht.model.internal.VotingResult;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper;
@@ -11,7 +12,24 @@ import org.mapstruct.ReportingPolicy;
unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface VotingResultMapper {
de.twomartens.wahlrecht.model.dto.v1.VotingResult mapToExternal(VotingResult result);
default de.twomartens.wahlrecht.model.dto.v1.VotingResult mapToExternal(VotingResult result) {
return new de.twomartens.wahlrecht.model.dto.v1.VotingResult(
result.getNominationId().electionName(),
result.getNominationId().partyAbbreviation(),
result.getNominationId().name(),
result.getVotesOnNomination(),
result.getVotesThroughHealing(),
result.getVotesPerPosition()
);
}
VotingResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.VotingResult result);
default VotingResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.VotingResult result) {
return new VotingResult(
new NominationId(result.electionName(), result.partyAbbreviation(),
result.nominationName()),
result.votesOnNomination(),
result.votesThroughHealing(),
result.votesPerPosition()
);
}
}
@@ -1,12 +1,13 @@
package de.twomartens.wahlrecht.model.dto.v1;
import de.twomartens.wahlrecht.model.internal.NominationId;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import lombok.Builder;
@Builder
public record ElectedResult(Map<VotingResult, Collection<ElectedCandidate>> electedCandidates,
public record ElectedResult(Map<NominationId, Collection<ElectedCandidate>> electedCandidates,
LinkedList<Double> usedElectionNumbers) {
}
@@ -0,0 +1,5 @@
package de.twomartens.wahlrecht.model.dto.v1;
public record NominationId(String electionName, String partyAbbreviation, String name) {
}
@@ -17,11 +17,12 @@ import org.springframework.lang.NonNull;
@ToString(onlyExplicitlyIncluded = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class PartyInElection {
String electionName;
@Include
String abbreviation;
String name;
Nomination overallNomination;
@NonNull
Map<Integer, Nomination> constituencyNominations = new HashMap<>();
String electionName;
@Include
String abbreviation;
String name;
Nomination overallNomination;
@NonNull
Map<Integer, Nomination> constituencyNominations = new HashMap<>();
}
@@ -2,7 +2,8 @@ package de.twomartens.wahlrecht.model.dto.v1;
import java.util.Map;
public record VotingResult(int votesOnNomination, int votesThroughHealing, Integer totalVotes,
Map<Integer, Integer> votesPerPosition, String nominationName) {
public record VotingResult(String electionName, String partyAbbreviation, String nominationName,
int votesOnNomination, int votesThroughHealing,
Map<Integer, Integer> votesPerPosition) {
}
@@ -11,9 +11,9 @@ import lombok.Builder;
public record ElectedResult(Map<VotingResult, Collection<ElectedCandidate>> electedCandidates,
LinkedList<Double> usedElectionNumbers) {
public Map<Nomination, Collection<ElectedCandidate>> electedCandidatesByNomination() {
public Map<NominationId, Collection<ElectedCandidate>> electedCandidatesByNomination() {
return electedCandidates.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getNomination(), Entry::getValue));
.collect(Collectors.toMap(entry -> entry.getKey().getNominationId(), Entry::getValue));
}
}
@@ -6,18 +6,13 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.ToString.Include;
@RequiredArgsConstructor
@ToString(onlyExplicitlyIncluded = true)
public class Nomination {
private final String electionName;
private final String partyAbbreviation;
@Include
private final String name;
@Getter
private final NominationId id;
private final boolean supportVotesOnNomination;
private final List<Candidate> candidates = new ArrayList<>();
private final Map<Candidate, Integer> candidateToPosition = new HashMap<>();
@@ -52,4 +47,9 @@ public class Nomination {
public boolean supportsVotesOnNomination() {
return supportVotesOnNomination;
}
@Override
public String toString() {
return id.name();
}
}
@@ -10,8 +10,8 @@ import lombok.Builder;
public record SeatResult(Map<VotingResult, Integer> seatsPerResult,
LinkedList<Double> usedElectionNumbers) {
public Map<Nomination, Integer> seatsPerNomination() {
public Map<NominationId, Integer> seatsPerNomination() {
return seatsPerResult.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getNomination(), Entry::getValue));
.collect(Collectors.toMap(entry -> entry.getKey().getNominationId(), Entry::getValue));
}
}
@@ -7,19 +7,19 @@ import lombok.Getter;
@Getter
public class VotingResult {
private final NominationId nominationId;
private final int votesOnNomination;
private final int votesThroughHealing;
private final Map<Integer, Integer> votesPerPosition;
private final Nomination nomination;
private Integer totalVotes = null;
@Builder
public VotingResult(int votesOnNomination, int votesThroughHealing,
Map<Integer, Integer> votesPerPosition, Nomination nomination) {
public VotingResult(NominationId nominationId, int votesOnNomination, int votesThroughHealing,
Map<Integer, Integer> votesPerPosition) {
this.votesOnNomination = votesOnNomination;
this.votesThroughHealing = votesThroughHealing;
this.votesPerPosition = votesPerPosition;
this.nomination = nomination;
this.nominationId = nominationId;
}
public int getTotalVotes() {
@@ -7,6 +7,7 @@ import de.twomartens.wahlrecht.model.internal.ElectedCandidate;
import de.twomartens.wahlrecht.model.internal.ElectedResult;
import de.twomartens.wahlrecht.model.internal.Election;
import de.twomartens.wahlrecht.model.internal.Nomination;
import de.twomartens.wahlrecht.model.internal.NominationId;
import de.twomartens.wahlrecht.model.internal.SeatResult;
import de.twomartens.wahlrecht.model.internal.VotingResult;
import java.util.ArrayList;
@@ -20,14 +21,20 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Service
public class CalculationService {
private final NominationService nominationService;
private final LinkedList<Double> electionNumberHistory = new LinkedList<>();
public ElectedResult calculateConstituency(@NonNull Constituency constituency,
@NonNull Collection<VotingResult> votingResults) {
electionNumberHistory.clear();
@@ -127,7 +134,8 @@ public class CalculationService {
Map<Candidate, ElectedCandidate> electedCandidateMap = alreadyElectedCandidates.stream()
.collect(Collectors.toMap(ElectedCandidate::candidate, Function.identity()));
Nomination nomination = votingResult.getNomination();
NominationId nominationId = votingResult.getNominationId();
Nomination nomination = nominationService.getNominationInternal(nominationId);
if (nomination.supportsVotesOnNomination()) {
int seatsByNomination = calculateSeatsByNominationOrder(votingResult, numberOfSeats);
seatsByVoteOrder = numberOfSeats - seatsByNomination;
@@ -1,5 +1,6 @@
package de.twomartens.wahlrecht.service;
import de.twomartens.wahlrecht.mapper.v1.NominationMapper;
import de.twomartens.wahlrecht.model.db.Candidate;
import de.twomartens.wahlrecht.model.db.Nomination;
import de.twomartens.wahlrecht.model.internal.NominationId;
@@ -10,16 +11,29 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.mapstruct.factory.Mappers;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Service
public class NominationService {
private final NominationMapper mapper = Mappers.getMapper(NominationMapper.class);
private final NominationRepository repository;
private final CandidateService candidateService;
private Map<NominationId, Nomination> nominations;
public Nomination getNomination(NominationId id) {
if (nominations == null) {
fetchNominations();
}
return nominations.get(id);
}
public de.twomartens.wahlrecht.model.internal.Nomination getNominationInternal(NominationId id) {
return mapper.mapToInternal(getNomination(id));
}
public Nomination storeNomination(Nomination nomination) {
if (nomination == null) {
return null;
@@ -39,7 +39,7 @@ 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();
}