Steven Polley
98f50317be
All checks were successful
continuous-integration/drone/push Build is passing
89 lines
2.7 KiB
Go
89 lines
2.7 KiB
Go
package countersql
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
)
|
|
|
|
// Configuration holds the DSN connection string and a resource Semaphore to limit the number of active connections
|
|
// Note: This is a copied design pattern I've used for other projects which had much more data inside a Configuration struct.
|
|
// Examples include semaphores and persistent connection pools, which I've stripped out for this project.
|
|
type Configuration struct {
|
|
DSN string
|
|
}
|
|
|
|
// Connection represents a single connection to the database, however there may be many instances / connections
|
|
// Note: This is a copied design pattern I've used for other projects which had much more data inside a Connection struct.
|
|
type Connection struct {
|
|
DB *sql.DB
|
|
}
|
|
|
|
// HasIPVisited returns true only if the IP address is present in the database
|
|
func (conn Connection) HasIPVisited(ipAddress string) (bool, error) {
|
|
rows, err := conn.DB.Query(`SELECT id FROM visit WHERE ip_address = ? LIMIT 1;`, ipAddress)
|
|
if err != nil {
|
|
return false, fmt.Errorf("SELECT query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
if !rows.Next() {
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// GetUniqueVisits counts the number of entires in the visits table, representing one unique source IP address per row
|
|
func (conn Connection) GetUniqueVisits() (int, error) {
|
|
rows, err := conn.DB.Query(`SELECT COUNT(*) FROM visit`)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("SELECT query failed: %v", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
if !rows.Next() {
|
|
return 0, nil
|
|
}
|
|
|
|
var uniqueVists int
|
|
if err := rows.Scan(&uniqueVists); err != nil {
|
|
return 0, fmt.Errorf("failed to scan database row: %v", err)
|
|
}
|
|
|
|
return uniqueVists, nil
|
|
}
|
|
|
|
// IncrementVisitor accepts an IP address and updates the row matching that IP address
|
|
// It does not check if the row matching the IP address supplied exists or not
|
|
func (conn Connection) IncrementVisitor(ipAddress string) error {
|
|
_, err := conn.DB.Exec(`UPDATE visit SET visits = visits + 1, last_visited = NOW() WHERE ip_address = ?`, ipAddress)
|
|
if err != nil {
|
|
return fmt.Errorf("UPDATE query failed: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddVisitor accepts an IP address and inserts a new row into the database as this represents a new unique visitor
|
|
func (conn Connection) AddVisitor(ipAddress string) error {
|
|
_, err := conn.DB.Exec(`INSERT INTO visit (ip_address, visits, last_visited) VALUES (?, '0', NOW())`, ipAddress)
|
|
if err != nil {
|
|
return fmt.Errorf("INSERT query failed: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Connect will open a TCP connection to the database with the given DSN configuration
|
|
func (conf Configuration) Connect() (*Connection, error) {
|
|
conn := &Connection{}
|
|
var err error
|
|
|
|
conn.DB, err = sql.Open("mysql", conf.DSN)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open db: %v", err)
|
|
}
|
|
|
|
return conn, nil
|
|
}
|