package models import ( "database/sql" "errors" ) type VoterModelInterface interface { InsertMultiple(identities []string, electionID int) ([]int, error) CountByElection(electionID int) (int, error) Exists(voterIdentity string, electionID int) (bool, error) } type VoterModel struct { DB *sql.DB } func (v *VoterModel) InsertMultiple(identities []string, electionID int) ([]int, error) { tx, err := v.DB.Begin() if err != nil { return nil, err } defer tx.Rollback() stmt, err := tx.Prepare(` INSERT INTO voters (identity, election_id) VALUES (?, ?)`) if err != nil { return nil, err } defer stmt.Close() voterIDs := make([]int, 0, len(identities)) for _, identity := range identities { result, err := stmt.Exec(identity, electionID) if err != nil { return nil, err } voterID, err := result.LastInsertId() if err != nil { return nil, err } voterIDs = append(voterIDs, int(voterID)) } if err = tx.Commit(); err != nil { return nil, err } return voterIDs, nil } func (v *VoterModel) CountByElection(electionID int) (int, error) { // use a transaction to prevent race conditions tx, err := v.DB.Begin() if err != nil { return 0, err } defer tx.Rollback() query := ` SELECT COUNT(identity) FROM voters WHERE election_id = ? GROUP BY election_id; ` row := tx.QueryRow(query, electionID) var voterCount int err = row.Scan(&voterCount) if err != nil { return 0, err } tx.Commit() return voterCount, nil } func (v *VoterModel) Exists(voterIdentity string, electionID int) (bool, error) { query := ` SELECT EXISTS ( SELECT 1 FROM voters WHERE identity = ? AND election_id = ? ) ` var exists bool err := v.DB.QueryRow(query, voterIdentity, electionID).Scan(&exists) if err != nil { if errors.Is(sql.ErrNoRows, err) { return false, nil } return false, err } return exists, nil }