From f947dd29122bb1b0ce708f5e5cc15ce5e1d4fb25 Mon Sep 17 00:00:00 2001 From: Deepak Date: Sun, 27 Dec 2020 19:14:27 -0600 Subject: [PATCH] Adds additional models, slightly more tests --- .../000001_create_action_table.down.sql | 1 + .../000001_create_action_table.up.sql | 24 +++++-- db/postgres.go | 15 +++- go.mod | 1 + go.sum | 1 + main.go | 27 +++----- models/action.go | 8 +-- models/models.go | 13 ++-- models/models_test.go | 43 ++++++++++++ models/plan.go | 14 ++++ util/snake.go | 18 +++++ util/snake_test.go | 69 +++++++++++++++++++ 12 files changed, 199 insertions(+), 35 deletions(-) create mode 100644 models/models_test.go create mode 100644 models/plan.go create mode 100644 util/snake.go create mode 100644 util/snake_test.go diff --git a/db/migrations/000001_create_action_table.down.sql b/db/migrations/000001_create_action_table.down.sql index 48d368f..0b978f2 100644 --- a/db/migrations/000001_create_action_table.down.sql +++ b/db/migrations/000001_create_action_table.down.sql @@ -1,3 +1,4 @@ DROP TABLE IF EXISTS actions; +DROP TABLE IF EXISTS plans; DROP FUNCTION IF EXISTS trigger_set_timestamp; diff --git a/db/migrations/000001_create_action_table.up.sql b/db/migrations/000001_create_action_table.up.sql index d7539f5..3fce461 100644 --- a/db/migrations/000001_create_action_table.up.sql +++ b/db/migrations/000001_create_action_table.up.sql @@ -1,8 +1,19 @@ +CREATE TABLE IF NOT EXISTS plans( + plan_id serial PRIMARY KEY, + plan_date DATE NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL +); + CREATE TABLE IF NOT EXISTS actions( - id serial PRIMARY KEY, - description VARCHAR (500), - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP + action_id serial PRIMARY KEY, + action_description VARCHAR (500) NOT NULL, + estimated_chunks SMALLINT, + completed_chunks SMALLINT, + completed_on TIMESTAMP WITH TIME ZONE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, + plan int REFERENCES plans(plan_id) ); @@ -18,3 +29,8 @@ CREATE TRIGGER set_updated BEFORE UPDATE ON actions FOR EACH ROW EXECUTE PROCEDURE trigger_set_timestamp(); + +CREATE TRIGGER set_updated +BEFORE UPDATE ON plans +FOR EACH ROW +EXECUTE PROCEDURE trigger_set_timestamp(); diff --git a/db/postgres.go b/db/postgres.go index 1340092..1fe4413 100644 --- a/db/postgres.go +++ b/db/postgres.go @@ -8,11 +8,12 @@ import ( "os" "gitea.deepak.science/deepak/gogmagog/config" + "gitea.deepak.science/deepak/gogmagog/models" + "gitea.deepak.science/deepak/gogmagog/util" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/database/postgres" _ "github.com/golang-migrate/migrate/v4/source/file" _ "github.com/jackc/pgx/v4/stdlib" - "gitea.deepak.science/deepak/gogmagog/models" ) type postgresStore struct { @@ -56,14 +57,24 @@ func GetStore() *postgresStore { if err := m.Up(); err != nil && err != migrate.ErrNoChange { log.Fatalf("An error occurred while syncing the database.. %v", err) } + db.MapperFunc(util.ToSnake) return &postgresStore{db: db} } func (store *postgresStore) SelectActions() ([]*models.Action, error) { actions := make([]*models.Action, 0) - err := store.db.Select(&actions, "SELECT id, description, created_at AS createdat, updated_at AS updatedat FROM actions") + err := store.db.Select(&actions, "SELECT action_id, action_description, created_at, updated_at FROM actions") if err != nil { return nil, err } return actions, nil } + +func (store *postgresStore) SelectPlans() ([]*models.Plan, error) { + plans := make([]*models.Plan, 0) + err := store.db.Select(&plans, "SELECT plan_id, plan_date FROM plans") + if err != nil { + return nil, err + } + return plans, nil +} diff --git a/go.mod b/go.mod index 136fd5d..77125dd 100644 --- a/go.mod +++ b/go.mod @@ -7,4 +7,5 @@ require ( github.com/jackc/pgx/v4 v4.10.1 github.com/jmoiron/sqlx v1.2.0 github.com/spf13/viper v1.7.1 + github.com/stretchr/testify v1.5.1 ) diff --git a/go.sum b/go.sum index 08071d8..6ab229f 100644 --- a/go.sum +++ b/go.sum @@ -399,6 +399,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= diff --git a/main.go b/main.go index cee505d..3c2374a 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,6 @@ import ( "gitea.deepak.science/deepak/gogmagog/db" "gitea.deepak.science/deepak/gogmagog/models" "log" - "net/http" ) func main() { @@ -28,26 +27,16 @@ func main() { log.Print("created model") } - http.Handle("/static/", http.FileServer(http.Dir("public"))) - - http.HandleFunc("/actions/", HandleAction) - - log.Fatal(http.ListenAndServe(":"+port, nil)) -} - -func ShowCompleteActions(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(r.URL.Path)) -} - -func HandleAction(w http.ResponseWriter, r *http.Request) { - var message string - id := r.URL.Path[len("/actions/"):] - if r.Method == "GET" { - message = "Get the action " + id + acts, acterr := m.Actions() + if acterr != nil { + log.Fatal("whoopsies", acterr) } else { - message = r.Method + " the action " + id + log.Printf("Got %d actions", len(acts)) + for i, act := range acts { + log.Printf("%d: %v", i, act) + } } - w.Write([]byte(message)) + } func Hello() string { diff --git a/models/action.go b/models/action.go index 8ab87bc..e45e6c7 100644 --- a/models/action.go +++ b/models/action.go @@ -5,10 +5,10 @@ import ( ) type Action struct { - ID int64 - Description string - CreatedAt time.Time - UpdatedAt time.Time + ActionID int64 + ActionDescription string + CreatedAt time.Time + UpdatedAt time.Time } func (m *Model) Actions() ([]*Action, error) { diff --git a/models/models.go b/models/models.go index d0d0cb9..68cf2c5 100644 --- a/models/models.go +++ b/models/models.go @@ -1,13 +1,14 @@ package models -type store interface { - SelectActions() ([]*Action, error) +type store interface { + SelectActions() ([]*Action, error) + SelectPlans() ([]*Plan, error) } type Model struct { store } - -func New(store store) *Model { - return &Model{store: store} -} + +func New(store store) *Model { + return &Model{store: store} +} diff --git a/models/models_test.go b/models/models_test.go new file mode 100644 index 0000000..ee5e1e6 --- /dev/null +++ b/models/models_test.go @@ -0,0 +1,43 @@ +package models_test + +import ( + "gitea.deepak.science/deepak/gogmagog/models" + "github.com/stretchr/testify/assert" + "testing" +) + +type store interface { + SelectActions() ([]*models.Action, error) + SelectPlans() ([]*models.Plan, error) +} +type multiStore struct { + actions []*models.Action + plans []*models.Plan +} + +func (ms *multiStore) SelectActions() ([]*models.Action, error) { + return ms.actions, nil +} + +func (ms *multiStore) SelectPlans() ([]*models.Plan, error) { + return ms.plans, nil +} + +func TestModelActions(t *testing.T) { + assert := assert.New(t) + a1 := &models.Action{ActionID: 3} + a2 := &models.Action{ActionID: 4} + p := &models.Plan{PlanID: 6} + ss := &multiStore{ + []*models.Action{a1, a2}, + []*models.Plan{p}} + m := models.New(ss) + + actions, err := m.Actions() + assert.Nil(err) + assert.Equal(2, len(actions)) + + plans, err := m.Plans() + assert.Nil(err) + assert.Equal(1, len(plans)) +} diff --git a/models/plan.go b/models/plan.go new file mode 100644 index 0000000..9080663 --- /dev/null +++ b/models/plan.go @@ -0,0 +1,14 @@ +package models + +import ( + "time" +) + +type Plan struct { + PlanID int64 + PlanDate time.Time +} + +func (m *Model) Plans() ([]*Plan, error) { + return m.SelectPlans() +} diff --git a/util/snake.go b/util/snake.go new file mode 100644 index 0000000..cb368bf --- /dev/null +++ b/util/snake.go @@ -0,0 +1,18 @@ +package util + +import "unicode" + +func ToSnake(in string) string { + runes := []rune(in) + length := len(runes) + + var out []rune + for i := 0; i < length; i++ { + if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) { + out = append(out, '_') + } + out = append(out, unicode.ToLower(runes[i])) + } + + return string(out) +} diff --git a/util/snake_test.go b/util/snake_test.go new file mode 100644 index 0000000..06b91c6 --- /dev/null +++ b/util/snake_test.go @@ -0,0 +1,69 @@ +package util_test + +import ( + "strings" + "testing" + + "gitea.deepak.science/deepak/gogmagog/util" +) + +// from https://github.com/paultyng/snake + +type SnakeTest struct { + input string + output string +} + +var tests = []SnakeTest{ + {"a", "a"}, + {"snake", "snake"}, + {"A", "a"}, + {"ID", "id"}, + {"MOTD", "motd"}, + {"Snake", "snake"}, + {"SnakeTest", "snake_test"}, + {"SnakeID", "snake_id"}, + {"SnakeIDGoogle", "snake_id_google"}, + {"LinuxMOTD", "linux_motd"}, + {"OMGWTFBBQ", "omgwtfbbq"}, + {"omg_wtf_bbq", "omg_wtf_bbq"}, + {"APIResponse", "api_response"}, +} + +func TestToSnake(t *testing.T) { + for _, test := range tests { + if util.ToSnake(test.input) != test.output { + t.Errorf(`ToSnake("%s"), wanted "%s", got \%s"`, test.input, test.output, util.ToSnake(test.input)) + } + } +} + +var benchmarks = []string{ + "a", + "snake", + "A", + "Snake", + "SnakeTest", + "SnakeID", + "SnakeIDGoogle", + "LinuxMOTD", + "OMGWTFBBQ", + "omg_wtf_bbq", + "APIResponse", +} + +func BenchmarkToSnake(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, input := range benchmarks { + util.ToSnake(input) + } + } +} + +func BenchmarkToLower(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, input := range benchmarks { + strings.ToLower(input) + } + } +}