Implement getElectionResults

This commit is contained in:
2025-01-14 16:52:20 +01:00
parent 13c2693bdb
commit c095e9ae0b
4 changed files with 118 additions and 1 deletions

View File

@ -9,6 +9,7 @@ import (
"encoding/json"
"errors"
"fmt"
"math"
"math/rand"
"net/http"
"slices"
@ -271,5 +272,41 @@ func (app *application) createVotesHandleUnknownVotersElection(w http.ResponseWr
}
func (app *application) GetElectionResults(w http.ResponseWriter, r *http.Request, id int) {
votes, err := app.votes.GetByElection(id)
if err != nil {
if errors.Is(sql.ErrNoRows, err) {
app.clientError(w, http.StatusNotFound, fmt.Sprintf("couldn't find votes for an election with id %v", id))
return
}
app.serverError(w, r, err)
return
}
results := getResultsFromVotes(votes)
response, err := json.Marshal(api.ElectionResultsResponse{Results: &results})
if err != nil {
app.serverError(w, r, err)
return
}
w.Write(response)
}
func getResultsFromVotes(votes *[]models.Vote) []api.VotesForChoice {
votesForChoice := make(map[string]int)
for _, v := range *votes {
votesForChoice[v.ChoiceText] += int(math.Floor(math.Sqrt(float64(v.Tokens))))
}
results := make([]api.VotesForChoice, 0)
for choice, votes := range votesForChoice {
result := api.VotesForChoice{
Choice: choice,
Votes: votes,
}
results = append(results, result)
}
return results
}

View File

@ -124,6 +124,12 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/ElectionResultsResponse"
400:
description: Request malformed
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
404:
description: Election doesn't exist
content:
@ -205,6 +211,22 @@ components:
ElectionResultsResponse:
type: object
properties:
results:
type: array
items:
$ref: "#/components/schemas/VotesForChoice"
VotesForChoice:
type: object
required:
- choice
- votes
properties:
choice:
type: string
votes:
type: integer
ErrorResponse:
type: object

View File

@ -42,7 +42,9 @@ type CreateVotesRequest struct {
}
// ElectionResultsResponse defines model for ElectionResultsResponse.
type ElectionResultsResponse = map[string]interface{}
type ElectionResultsResponse struct {
Results *[]VotesForChoice `json:"results,omitempty"`
}
// ErrorResponse defines model for ErrorResponse.
type ErrorResponse struct {
@ -56,6 +58,12 @@ type ErrorResponse struct {
Message string `json:"message"`
}
// VotesForChoice defines model for VotesForChoice.
type VotesForChoice struct {
Choice string `json:"choice"`
Votes int `json:"votes"`
}
// CreateElectionJSONRequestBody defines body for CreateElection for application/json ContentType.
type CreateElectionJSONRequestBody = CreateElectionRequest

View File

@ -3,17 +3,27 @@ package models
import (
"database/sql"
"errors"
"time"
)
type VoteModelInterface interface {
Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error)
Exists(voterIdentity string, electionID int) (bool, error)
GetByElection(electionID int) (*[]Vote, error)
}
type VoteModel struct {
DB *sql.DB
}
type Vote struct {
VoterIdentity string
ElectionID int
ChoiceText string
Tokens int
CreatedAt time.Time
}
func (v *VoteModel) Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error) {
tx, err := v.DB.Begin()
if err != nil {
@ -55,3 +65,43 @@ func (v *VoteModel) Exists(voterIdentity string, electionID int) (bool, error) {
}
return exists, nil
}
func (v *VoteModel) GetByElection(electionID int) (*[]Vote, error) {
query := `
SELECT voter_identity, election_id, choice_text, tokens, created_at
FROM votes
WHERE election_id = ?
`
rows, err := v.DB.Query(query, electionID)
if err != nil {
return nil, err
}
defer rows.Close()
var votes []Vote
for rows.Next() {
var vote Vote
err := rows.Scan(
&vote.VoterIdentity,
&vote.ElectionID,
&vote.ChoiceText,
&vote.Tokens,
&vote.CreatedAt,
)
if err != nil {
return nil, err
}
votes = append(votes, vote)
}
if err = rows.Err(); err != nil {
return nil, err
}
if len(votes) == 0 {
return nil, sql.ErrNoRows
}
return &votes, nil
}