diff --git a/api/handler.go b/api/handler.go index ab7bbc7..2275bcd 100644 --- a/api/handler.go +++ b/api/handler.go @@ -60,6 +60,7 @@ func Handler() *mux.Router { m.Get(router.DeleteTextMeasurementType).Handler(handler(serveDeleteTextMeasurementType)) m.Get(router.UnitType).Handler(handler(serveUnitType)) + m.Get(router.CreateUnitType).Handler(handler(serveCreateUnitType)) return m } diff --git a/api/unit_types.go b/api/unit_types.go index ea1fe54..65c2e5e 100644 --- a/api/unit_types.go +++ b/api/unit_types.go @@ -1,10 +1,12 @@ package api import ( + "encoding/json" "net/http" "strconv" "github.com/gorilla/mux" + "github.com/thermokarst/bactdb/models" ) func serveUnitType(w http.ResponseWriter, r *http.Request) error { @@ -20,3 +22,21 @@ func serveUnitType(w http.ResponseWriter, r *http.Request) error { return writeJSON(w, unit_type) } + +func serveCreateUnitType(w http.ResponseWriter, r *http.Request) error { + var unit_type models.UnitType + err := json.NewDecoder(r.Body).Decode(&unit_type) + if err != nil { + return err + } + + created, err := store.UnitTypes.Create(&unit_type) + if err != nil { + return err + } + if created { + w.WriteHeader(http.StatusCreated) + } + + return writeJSON(w, unit_type) +} diff --git a/api/unit_types_test.go b/api/unit_types_test.go index c3b5738..a762b79 100644 --- a/api/unit_types_test.go +++ b/api/unit_types_test.go @@ -38,3 +38,30 @@ func TestUnitType_Get(t *testing.T) { t.Errorf("got %+v but wanted %+v", got, want) } } + +func TestUnitType_Create(t *testing.T) { + setup() + + want := newUnitType() + + calledPost := false + store.UnitTypes.(*models.MockUnitTypesService).Create_ = func(unit_type *models.UnitType) (bool, error) { + if !normalizeDeepEqual(want, unit_type) { + t.Errorf("wanted request for unit_type %d but got %d", want, unit_type) + } + calledPost = true + return true, nil + } + + success, err := apiClient.UnitTypes.Create(want) + if err != nil { + t.Fatal(err) + } + + if !calledPost { + t.Error("!calledPost") + } + if !success { + t.Error("!success") + } +} diff --git a/datastore/unit_types.go b/datastore/unit_types.go index 3c9faec..a6c1ada 100644 --- a/datastore/unit_types.go +++ b/datastore/unit_types.go @@ -1,6 +1,10 @@ package datastore -import "github.com/thermokarst/bactdb/models" +import ( + "time" + + "github.com/thermokarst/bactdb/models" +) func init() { DB.AddTableWithName(models.UnitType{}, "unit_types").SetKeys(true, "Id") @@ -20,3 +24,13 @@ func (s *unitTypesStore) Get(id int64) (*models.UnitType, error) { } return unit_type[0], nil } + +func (s *unitTypesStore) Create(unit_type *models.UnitType) (bool, error) { + currentTime := time.Now() + unit_type.CreatedAt = currentTime + unit_type.UpdatedAt = currentTime + if err := s.dbh.Insert(unit_type); err != nil { + return false, err + } + return true, nil +} diff --git a/datastore/unit_types_test.go b/datastore/unit_types_test.go index 178f12a..ea39d4e 100644 --- a/datastore/unit_types_test.go +++ b/datastore/unit_types_test.go @@ -42,3 +42,23 @@ func TestUnitTypesStore_Get_db(t *testing.T) { t.Errorf("got unit_type %+v, want %+v", unit_type, want) } } + +func TestUnitTypesStore_Create_db(t *testing.T) { + tx, _ := DB.Begin() + defer tx.Rollback() + + unit_type := newUnitType(t, tx) + + d := NewDatastore(tx) + + created, err := d.UnitTypes.Create(unit_type) + if err != nil { + t.Fatal(err) + } + if !created { + t.Error("!created") + } + if unit_type.Id == 0 { + t.Error("want nonzero unit_type.Id after submitting") + } +} diff --git a/models/unit_types.go b/models/unit_types.go index 6dc9597..b587f6e 100644 --- a/models/unit_types.go +++ b/models/unit_types.go @@ -2,6 +2,7 @@ package models import ( "errors" + "net/http" "strconv" "time" @@ -11,7 +12,7 @@ import ( // A UnitType is a lookup type type UnitType struct { - Id int64 `json:id,omitempty"` + Id int64 `json:"id,omitempty"` Name string `db:"name" json:"name"` Symbol string `db:"symbol" json:"symbol"` CreatedAt time.Time `db:"created_at" json:"createdAt"` @@ -29,6 +30,9 @@ func NewUnitType() *UnitType { type UnitTypesService interface { // Get a unit type Get(id int64) (*UnitType, error) + + // Create a unit type + Create(unit_type *UnitType) (bool, error) } var ( @@ -61,8 +65,28 @@ func (s *unitTypesService) Get(id int64) (*UnitType, error) { return unit_type, nil } +func (s *unitTypesService) Create(unit_type *UnitType) (bool, error) { + url, err := s.client.url(router.CreateUnitType, nil, nil) + if err != nil { + return false, err + } + + req, err := s.client.NewRequest("POST", url.String(), unit_type) + if err != nil { + return false, err + } + + resp, err := s.client.Do(req, &unit_type) + if err != nil { + return false, err + } + + return resp.StatusCode == http.StatusCreated, nil +} + type MockUnitTypesService struct { - Get_ func(id int64) (*UnitType, error) + Get_ func(id int64) (*UnitType, error) + Create_ func(unit_type *UnitType) (bool, error) } var _ UnitTypesService = &MockUnitTypesService{} @@ -73,3 +97,10 @@ func (s *MockUnitTypesService) Get(id int64) (*UnitType, error) { } return s.Get_(id) } + +func (s *MockUnitTypesService) Create(unit_type *UnitType) (bool, error) { + if s.Create_ == nil { + return false, nil + } + return s.Create_(unit_type) +} diff --git a/models/unit_types_test.go b/models/unit_types_test.go index b958f43..af674a7 100644 --- a/models/unit_types_test.go +++ b/models/unit_types_test.go @@ -43,3 +43,39 @@ func TestUnitTypeService_Get(t *testing.T) { t.Errorf("UnitTypes.Get return %+v, want %+v", unit_type, want) } } + +func TestUnitTypeService_Create(t *testing.T) { + setup() + defer teardown() + + want := newUnitType() + + var called bool + mux.HandleFunc(urlPath(t, router.CreateUnitType, nil), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "POST") + testBody(t, r, `{"id":1,"name":"Test Unit Type","symbol":"x","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") + + w.WriteHeader(http.StatusCreated) + writeJSON(w, want) + }) + + unit_type := newUnitType() + created, err := client.UnitTypes.Create(unit_type) + if err != nil { + t.Errorf("UnitTypes.Create returned error: %v", err) + } + + if !created { + t.Error("!created") + } + + if !called { + t.Fatal("!called") + } + + normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) + if !reflect.DeepEqual(unit_type, want) { + t.Errorf("UnitTypes.Create returned %+v, want %+v", unit_type, want) + } +} diff --git a/router/api.go b/router/api.go index e2b0eff..11b8bfd 100644 --- a/router/api.go +++ b/router/api.go @@ -53,6 +53,7 @@ func API() *mux.Router { m.Path("/text_measurement_types/{Id:.+}").Methods("DELETE").Name(DeleteTextMeasurementType) // UnitTypes + m.Path("/unit_types/").Methods("POST").Name(CreateUnitType) m.Path("/unit_types/{Id:.+}").Methods("GET").Name(UnitType) return m diff --git a/router/routes.go b/router/routes.go index dd80513..ffb436d 100644 --- a/router/routes.go +++ b/router/routes.go @@ -41,5 +41,6 @@ const ( UpdateTextMeasurementType = "text_measurement_type:update" DeleteTextMeasurementType = "text_measurement_type:delete" - UnitType = "unit_type:get" + UnitType = "unit_type:get" + CreateUnitType = "unit_type:create" )