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" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math"
"math/rand" "math/rand"
"net/http" "net/http"
"slices" "slices"
@ -271,5 +272,41 @@ func (app *application) createVotesHandleUnknownVotersElection(w http.ResponseWr
} }
func (app *application) GetElectionResults(w http.ResponseWriter, r *http.Request, id int) { 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: application/json:
schema: schema:
$ref: "#/components/schemas/ElectionResultsResponse" $ref: "#/components/schemas/ElectionResultsResponse"
400:
description: Request malformed
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
404: 404:
description: Election doesn't exist description: Election doesn't exist
content: content:
@ -205,6 +211,22 @@ components:
ElectionResultsResponse: ElectionResultsResponse:
type: object 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: ErrorResponse:
type: object type: object

View File

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

View File

@ -3,17 +3,27 @@ package models
import ( import (
"database/sql" "database/sql"
"errors" "errors"
"time"
) )
type VoteModelInterface interface { type VoteModelInterface interface {
Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error) Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error)
Exists(voterIdentity string, electionID int) (bool, error) Exists(voterIdentity string, electionID int) (bool, error)
GetByElection(electionID int) (*[]Vote, error)
} }
type VoteModel struct { type VoteModel struct {
DB *sql.DB 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) { func (v *VoteModel) Insert(voterIdentity string, electionId int, choiceText string, tokens int) (int, error) {
tx, err := v.DB.Begin() tx, err := v.DB.Begin()
if err != nil { if err != nil {
@ -55,3 +65,43 @@ func (v *VoteModel) Exists(voterIdentity string, electionID int) (bool, error) {
} }
return exists, nil 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
}