add CRUD for Scholarship
parent
86ebe6bb90
commit
694a246957
@ -0,0 +1,90 @@
|
|||||||
|
package dbi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Scholarship struct {
|
||||||
|
UID string `json:"uid"`
|
||||||
|
Citation string `json:"citation"`
|
||||||
|
Hyperlink string `json:"hyperlink"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Created string `json:"created"`
|
||||||
|
Modified string `json:"modified"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateScholarship(conn *sql.Conn, s *Scholarship) error {
|
||||||
|
if s.UID == "" {
|
||||||
|
s.UID = strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||||
|
}
|
||||||
|
now := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
s.Created = now
|
||||||
|
s.Modified = now
|
||||||
|
_, err := conn.ExecContext(context.Background(),
|
||||||
|
`INSERT INTO scholarship (UID, Citation, Hyperlink, Status, Created, Modified, Username)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
s.UID, s.Citation, s.Hyperlink, s.Status, s.Created, s.Modified, s.Username,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetScholarship(conn *sql.Conn, uid string) (Scholarship, error) {
|
||||||
|
row := conn.QueryRowContext(context.Background(),
|
||||||
|
`SELECT UID, Citation, Hyperlink, Status, Created, Modified, Username
|
||||||
|
FROM scholarship WHERE UID = ?`,
|
||||||
|
uid,
|
||||||
|
)
|
||||||
|
var s Scholarship
|
||||||
|
err := row.Scan(&s.UID, &s.Citation, &s.Hyperlink, &s.Status, &s.Created, &s.Modified, &s.Username)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return Scholarship{}, fmt.Errorf("scholarship %q not found", uid)
|
||||||
|
}
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateScholarship(conn *sql.Conn, s *Scholarship) error {
|
||||||
|
s.Modified = time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
_, err := conn.ExecContext(context.Background(),
|
||||||
|
`UPDATE scholarship SET Citation = ?, Hyperlink = ?, Status = ?, Modified = ?, Username = ?
|
||||||
|
WHERE UID = ?`,
|
||||||
|
s.Citation, s.Hyperlink, s.Status, s.Modified, s.Username, s.UID,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteScholarship(conn *sql.Conn, uid string) error {
|
||||||
|
_, err := conn.ExecContext(context.Background(),
|
||||||
|
`DELETE FROM scholarship WHERE UID = ?`,
|
||||||
|
uid,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetScholarshipsForUsername(conn *sql.Conn, username string) ([]Scholarship, error) {
|
||||||
|
rows, err := conn.QueryContext(context.Background(),
|
||||||
|
`SELECT UID, Citation, Hyperlink, Status, Created, Modified, Username
|
||||||
|
FROM scholarship WHERE Username = ?`,
|
||||||
|
username,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var results []Scholarship
|
||||||
|
for rows.Next() {
|
||||||
|
var s Scholarship
|
||||||
|
if err := rows.Scan(&s.UID, &s.Citation, &s.Hyperlink, &s.Status, &s.Created, &s.Modified, &s.Username); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
results = append(results, s)
|
||||||
|
}
|
||||||
|
return results, rows.Err()
|
||||||
|
}
|
||||||
@ -0,0 +1,210 @@
|
|||||||
|
package dbi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func genScholarship(username string) Scholarship {
|
||||||
|
return Scholarship{
|
||||||
|
Citation: randString(40),
|
||||||
|
Hyperlink: "https://" + randString(12) + ".example.com",
|
||||||
|
Status: "reported",
|
||||||
|
Username: username,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateScholarship(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
s := genScholarship(randString(10))
|
||||||
|
|
||||||
|
if err := CreateScholarship(conn, &s); err != nil {
|
||||||
|
t.Fatalf("CreateScholarship: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.UID == "" {
|
||||||
|
t.Error("expected UID to be set after create")
|
||||||
|
}
|
||||||
|
if s.Created == "" {
|
||||||
|
t.Error("expected Created to be set after create")
|
||||||
|
}
|
||||||
|
if s.Modified == "" {
|
||||||
|
t.Error("expected Modified to be set after create")
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := GetScholarship(conn, s.UID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetScholarship after create: %v", err)
|
||||||
|
}
|
||||||
|
if got != s {
|
||||||
|
t.Errorf("got %+v, want %+v", got, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateScholarshipPresetUID(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
s := genScholarship(randString(10))
|
||||||
|
s.UID = "preset" + randString(10)
|
||||||
|
|
||||||
|
if err := CreateScholarship(conn, &s); err != nil {
|
||||||
|
t.Fatalf("CreateScholarship: %v", err)
|
||||||
|
}
|
||||||
|
if s.UID != "preset"+s.UID[6:] {
|
||||||
|
t.Error("CreateScholarship should not overwrite a non-empty UID")
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := GetScholarship(conn, s.UID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetScholarship: %v", err)
|
||||||
|
}
|
||||||
|
if got.UID != s.UID {
|
||||||
|
t.Errorf("got UID %q, want %q", got.UID, s.UID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateScholarshipDuplicateUID(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
s := genScholarship(randString(10))
|
||||||
|
|
||||||
|
if err := CreateScholarship(conn, &s); err != nil {
|
||||||
|
t.Fatalf("first CreateScholarship: %v", err)
|
||||||
|
}
|
||||||
|
s2 := s
|
||||||
|
if err := CreateScholarship(conn, &s2); err == nil {
|
||||||
|
t.Error("expected error on duplicate UID, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetScholarship(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
s := genScholarship(randString(10))
|
||||||
|
|
||||||
|
if err := CreateScholarship(conn, &s); err != nil {
|
||||||
|
t.Fatalf("CreateScholarship: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := GetScholarship(conn, s.UID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetScholarship: %v", err)
|
||||||
|
}
|
||||||
|
if got != s {
|
||||||
|
t.Errorf("got %+v, want %+v", got, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetScholarshipNotFound(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
|
||||||
|
_, err := GetScholarship(conn, randString(32))
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error for missing scholarship, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateScholarship(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
s := genScholarship(randString(10))
|
||||||
|
|
||||||
|
if err := CreateScholarship(conn, &s); err != nil {
|
||||||
|
t.Fatalf("CreateScholarship: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
originalUID := s.UID
|
||||||
|
originalCreated := s.Created
|
||||||
|
s.Citation = randString(40)
|
||||||
|
s.Hyperlink = "https://" + randString(12) + ".example.com"
|
||||||
|
s.Status = "posted"
|
||||||
|
|
||||||
|
if err := UpdateScholarship(conn, &s); err != nil {
|
||||||
|
t.Fatalf("UpdateScholarship: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := GetScholarship(conn, s.UID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetScholarship after update: %v", err)
|
||||||
|
}
|
||||||
|
if got.UID != originalUID {
|
||||||
|
t.Errorf("UID changed: got %q, want %q", got.UID, originalUID)
|
||||||
|
}
|
||||||
|
if got.Created != originalCreated {
|
||||||
|
t.Errorf("Created changed: got %q, want %q", got.Created, originalCreated)
|
||||||
|
}
|
||||||
|
if got.Citation != s.Citation {
|
||||||
|
t.Errorf("Citation not updated: got %q, want %q", got.Citation, s.Citation)
|
||||||
|
}
|
||||||
|
if got.Status != "posted" {
|
||||||
|
t.Errorf("Status not updated: got %q", got.Status)
|
||||||
|
}
|
||||||
|
if got.Modified == "" {
|
||||||
|
t.Error("Modified should be set after update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteScholarship(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
s := genScholarship(randString(10))
|
||||||
|
|
||||||
|
if err := CreateScholarship(conn, &s); err != nil {
|
||||||
|
t.Fatalf("CreateScholarship: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DeleteScholarship(conn, s.UID); err != nil {
|
||||||
|
t.Fatalf("DeleteScholarship: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := GetScholarship(conn, s.UID)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error after delete, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetScholarshipsForUsername(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
username := randString(10)
|
||||||
|
|
||||||
|
items := make([]Scholarship, 3)
|
||||||
|
for i := range items {
|
||||||
|
items[i] = genScholarship(username)
|
||||||
|
if err := CreateScholarship(conn, &items[i]); err != nil {
|
||||||
|
t.Fatalf("CreateScholarship %d: %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// extra item belonging to a different user
|
||||||
|
other := genScholarship(randString(10))
|
||||||
|
if err := CreateScholarship(conn, &other); err != nil {
|
||||||
|
t.Fatalf("CreateScholarship other: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := GetScholarshipsForUsername(conn, username)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetScholarshipsForUsername: %v", err)
|
||||||
|
}
|
||||||
|
if len(got) != 3 {
|
||||||
|
t.Errorf("got %d scholarships, want 3", len(got))
|
||||||
|
}
|
||||||
|
byUID := make(map[string]Scholarship)
|
||||||
|
for _, s := range got {
|
||||||
|
byUID[s.UID] = s
|
||||||
|
}
|
||||||
|
for _, want := range items {
|
||||||
|
s, ok := byUID[want.UID]
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("scholarship %q missing from results", want.UID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s != want {
|
||||||
|
t.Errorf("scholarship %q: got %+v, want %+v", want.UID, s, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetScholarshipsForUsernameEmpty(t *testing.T) {
|
||||||
|
conn := testConn(t, testDB(t))
|
||||||
|
|
||||||
|
got, err := GetScholarshipsForUsername(conn, randString(10))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetScholarshipsForUsername: %v", err)
|
||||||
|
}
|
||||||
|
if len(got) != 0 {
|
||||||
|
t.Errorf("expected empty slice, got %d items", len(got))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue