Adds additional models, slightly more tests
This commit is contained in:
parent
2c5e84d836
commit
f947dd2912
@ -1,3 +1,4 @@
|
|||||||
DROP TABLE IF EXISTS actions;
|
DROP TABLE IF EXISTS actions;
|
||||||
|
DROP TABLE IF EXISTS plans;
|
||||||
|
|
||||||
DROP FUNCTION IF EXISTS trigger_set_timestamp;
|
DROP FUNCTION IF EXISTS trigger_set_timestamp;
|
||||||
|
@ -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(
|
CREATE TABLE IF NOT EXISTS actions(
|
||||||
id serial PRIMARY KEY,
|
action_id serial PRIMARY KEY,
|
||||||
description VARCHAR (500),
|
action_description VARCHAR (500) NOT NULL,
|
||||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
estimated_chunks SMALLINT,
|
||||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
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
|
BEFORE UPDATE ON actions
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE trigger_set_timestamp();
|
EXECUTE PROCEDURE trigger_set_timestamp();
|
||||||
|
|
||||||
|
CREATE TRIGGER set_updated
|
||||||
|
BEFORE UPDATE ON plans
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE trigger_set_timestamp();
|
||||||
|
@ -8,11 +8,12 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"gitea.deepak.science/deepak/gogmagog/config"
|
"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"
|
||||||
"github.com/golang-migrate/migrate/v4/database/postgres"
|
"github.com/golang-migrate/migrate/v4/database/postgres"
|
||||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||||
_ "github.com/jackc/pgx/v4/stdlib"
|
_ "github.com/jackc/pgx/v4/stdlib"
|
||||||
"gitea.deepak.science/deepak/gogmagog/models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type postgresStore struct {
|
type postgresStore struct {
|
||||||
@ -56,14 +57,24 @@ func GetStore() *postgresStore {
|
|||||||
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
|
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
|
||||||
log.Fatalf("An error occurred while syncing the database.. %v", err)
|
log.Fatalf("An error occurred while syncing the database.. %v", err)
|
||||||
}
|
}
|
||||||
|
db.MapperFunc(util.ToSnake)
|
||||||
return &postgresStore{db: db}
|
return &postgresStore{db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *postgresStore) SelectActions() ([]*models.Action, error) {
|
func (store *postgresStore) SelectActions() ([]*models.Action, error) {
|
||||||
actions := make([]*models.Action, 0)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return actions, nil
|
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
|
||||||
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -7,4 +7,5 @@ require (
|
|||||||
github.com/jackc/pgx/v4 v4.10.1
|
github.com/jackc/pgx/v4 v4.10.1
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
|
github.com/stretchr/testify v1.5.1
|
||||||
)
|
)
|
||||||
|
1
go.sum
1
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 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
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.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/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 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
|
27
main.go
27
main.go
@ -5,7 +5,6 @@ import (
|
|||||||
"gitea.deepak.science/deepak/gogmagog/db"
|
"gitea.deepak.science/deepak/gogmagog/db"
|
||||||
"gitea.deepak.science/deepak/gogmagog/models"
|
"gitea.deepak.science/deepak/gogmagog/models"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -28,26 +27,16 @@ func main() {
|
|||||||
log.Print("created model")
|
log.Print("created model")
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Handle("/static/", http.FileServer(http.Dir("public")))
|
acts, acterr := m.Actions()
|
||||||
|
if acterr != nil {
|
||||||
http.HandleFunc("/actions/", HandleAction)
|
log.Fatal("whoopsies", acterr)
|
||||||
|
|
||||||
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
|
|
||||||
} else {
|
} 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 {
|
func Hello() string {
|
||||||
|
@ -5,10 +5,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Action struct {
|
type Action struct {
|
||||||
ID int64
|
ActionID int64
|
||||||
Description string
|
ActionDescription string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Actions() ([]*Action, error) {
|
func (m *Model) Actions() ([]*Action, error) {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
type store interface {
|
type store interface {
|
||||||
SelectActions() ([]*Action, error)
|
SelectActions() ([]*Action, error)
|
||||||
|
SelectPlans() ([]*Plan, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
store
|
store
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(store store) *Model {
|
func New(store store) *Model {
|
||||||
return &Model{store: store}
|
return &Model{store: store}
|
||||||
}
|
}
|
||||||
|
43
models/models_test.go
Normal file
43
models/models_test.go
Normal file
@ -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))
|
||||||
|
}
|
14
models/plan.go
Normal file
14
models/plan.go
Normal file
@ -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()
|
||||||
|
}
|
18
util/snake.go
Normal file
18
util/snake.go
Normal file
@ -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)
|
||||||
|
}
|
69
util/snake_test.go
Normal file
69
util/snake_test.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user