add CRUD for Activity

master
Joshua Herring 3 weeks ago
parent a7c8ff26ca
commit 63ff9c3fa9

@ -0,0 +1,87 @@
package dbi
import (
"context"
"database/sql"
"fmt"
)
type Activity struct {
UID string `json:"uid"`
Title string `json:"title"`
Description string `json:"description"`
Hyperlink string `json:"hyperlink"`
Status string `json:"status"`
Created string `json:"created"`
Modified string `json:"modified"`
Username string `json:"username"`
}
func CreateActivity(conn *sql.Conn, a *Activity) error {
if a.UID == "" {
a.UID = GenUUID()
}
now := GetNow()
a.Created = now
a.Modified = now
_, err := conn.ExecContext(context.Background(),
`INSERT INTO activities (UID, Title, Description, Hyperlink, Status, Created, Modified, Username)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
a.UID, a.Title, a.Description, a.Hyperlink, a.Status, a.Created, a.Modified, a.Username,
)
return err
}
func GetActivity(conn *sql.Conn, uid string) (Activity, error) {
row := conn.QueryRowContext(context.Background(),
`SELECT UID, Title, Description, Hyperlink, Status, Created, Modified, Username
FROM activities WHERE UID = ?`,
uid,
)
var a Activity
err := row.Scan(&a.UID, &a.Title, &a.Description, &a.Hyperlink, &a.Status, &a.Created, &a.Modified, &a.Username)
if err == sql.ErrNoRows {
return Activity{}, fmt.Errorf("activity %q not found", uid)
}
return a, err
}
func UpdateActivity(conn *sql.Conn, a *Activity) error {
a.Modified = GetNow()
_, err := conn.ExecContext(context.Background(),
`UPDATE activities SET Title = ?, Description = ?, Hyperlink = ?, Status = ?, Modified = ?, Username = ?
WHERE UID = ?`,
a.Title, a.Description, a.Hyperlink, a.Status, a.Modified, a.Username, a.UID,
)
return err
}
func DeleteActivity(conn *sql.Conn, uid string) error {
_, err := conn.ExecContext(context.Background(),
`DELETE FROM activities WHERE UID = ?`,
uid,
)
return err
}
func GetActivitiesForUsername(conn *sql.Conn, username string) ([]Activity, error) {
rows, err := conn.QueryContext(context.Background(),
`SELECT UID, Title, Description, Hyperlink, Status, Created, Modified, Username
FROM activities WHERE Username = ?`,
username,
)
if err != nil {
return nil, err
}
defer rows.Close()
var results []Activity
for rows.Next() {
var a Activity
if err := rows.Scan(&a.UID, &a.Title, &a.Description, &a.Hyperlink, &a.Status, &a.Created, &a.Modified, &a.Username); err != nil {
return nil, err
}
results = append(results, a)
}
return results, rows.Err()
}

@ -0,0 +1,206 @@
package dbi
import (
"testing"
)
func genActivity(username string) Activity {
return Activity{
Title: randString(20),
Description: randString(60),
Hyperlink: "https://" + randString(12) + ".example.com",
Status: "reported",
Username: username,
}
}
func TestCreateActivity(t *testing.T) {
conn := testConn(t, testDB(t))
a := genActivity(randString(10))
if err := CreateActivity(conn, &a); err != nil {
t.Fatalf("CreateActivity: %v", err)
}
if a.UID == "" {
t.Error("expected UID to be set after create")
}
if a.Created == "" {
t.Error("expected Created to be set after create")
}
if a.Modified == "" {
t.Error("expected Modified to be set after create")
}
got, err := GetActivity(conn, a.UID)
if err != nil {
t.Fatalf("GetActivity after create: %v", err)
}
if got != a {
t.Errorf("got %+v, want %+v", got, a)
}
}
func TestCreateActivityPresetUID(t *testing.T) {
conn := testConn(t, testDB(t))
a := genActivity(randString(10))
a.UID = "preset" + randString(10)
presetUID := a.UID
if err := CreateActivity(conn, &a); err != nil {
t.Fatalf("CreateActivity: %v", err)
}
if a.UID != presetUID {
t.Error("CreateActivity should not overwrite a non-empty UID")
}
}
func TestCreateActivityDuplicateUID(t *testing.T) {
conn := testConn(t, testDB(t))
a := genActivity(randString(10))
if err := CreateActivity(conn, &a); err != nil {
t.Fatalf("first CreateActivity: %v", err)
}
a2 := a
if err := CreateActivity(conn, &a2); err == nil {
t.Error("expected error on duplicate UID, got nil")
}
}
func TestGetActivity(t *testing.T) {
conn := testConn(t, testDB(t))
a := genActivity(randString(10))
if err := CreateActivity(conn, &a); err != nil {
t.Fatalf("CreateActivity: %v", err)
}
got, err := GetActivity(conn, a.UID)
if err != nil {
t.Fatalf("GetActivity: %v", err)
}
if got != a {
t.Errorf("got %+v, want %+v", got, a)
}
}
func TestGetActivityNotFound(t *testing.T) {
conn := testConn(t, testDB(t))
_, err := GetActivity(conn, randString(32))
if err == nil {
t.Error("expected error for missing activity, got nil")
}
}
func TestUpdateActivity(t *testing.T) {
conn := testConn(t, testDB(t))
a := genActivity(randString(10))
if err := CreateActivity(conn, &a); err != nil {
t.Fatalf("CreateActivity: %v", err)
}
originalUID := a.UID
originalCreated := a.Created
a.Title = randString(20)
a.Description = randString(60)
a.Hyperlink = "https://" + randString(12) + ".example.com"
a.Status = "posted"
if err := UpdateActivity(conn, &a); err != nil {
t.Fatalf("UpdateActivity: %v", err)
}
got, err := GetActivity(conn, a.UID)
if err != nil {
t.Fatalf("GetActivity 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.Title != a.Title {
t.Errorf("Title not updated: got %q, want %q", got.Title, a.Title)
}
if got.Description != a.Description {
t.Errorf("Description not updated: got %q, want %q", got.Description, a.Description)
}
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 TestDeleteActivity(t *testing.T) {
conn := testConn(t, testDB(t))
a := genActivity(randString(10))
if err := CreateActivity(conn, &a); err != nil {
t.Fatalf("CreateActivity: %v", err)
}
if err := DeleteActivity(conn, a.UID); err != nil {
t.Fatalf("DeleteActivity: %v", err)
}
_, err := GetActivity(conn, a.UID)
if err == nil {
t.Error("expected error after delete, got nil")
}
}
func TestGetActivitiesForUsername(t *testing.T) {
conn := testConn(t, testDB(t))
username := randString(10)
items := make([]Activity, 3)
for i := range items {
items[i] = genActivity(username)
if err := CreateActivity(conn, &items[i]); err != nil {
t.Fatalf("CreateActivity %d: %v", i, err)
}
}
other := genActivity(randString(10))
if err := CreateActivity(conn, &other); err != nil {
t.Fatalf("CreateActivity other: %v", err)
}
got, err := GetActivitiesForUsername(conn, username)
if err != nil {
t.Fatalf("GetActivitiesForUsername: %v", err)
}
if len(got) != 3 {
t.Errorf("got %d activities, want 3", len(got))
}
byUID := make(map[string]Activity)
for _, a := range got {
byUID[a.UID] = a
}
for _, want := range items {
a, ok := byUID[want.UID]
if !ok {
t.Errorf("activity %q missing from results", want.UID)
continue
}
if a != want {
t.Errorf("activity %q: got %+v, want %+v", want.UID, a, want)
}
}
}
func TestGetActivitiesForUsernameEmpty(t *testing.T) {
conn := testConn(t, testDB(t))
got, err := GetActivitiesForUsername(conn, randString(10))
if err != nil {
t.Fatalf("GetActivitiesForUsername: %v", err)
}
if len(got) != 0 {
t.Errorf("expected empty slice, got %d items", len(got))
}
}
Loading…
Cancel
Save