From b90da728feeebd348aefc8368d2b9bcb8603ac90 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 21 Nov 2014 16:48:55 -0900 Subject: [PATCH] Update an observation --- api/handler.go | 1 + api/observations.go | 19 +++++++++++++++++++ api/observations_test.go | 30 ++++++++++++++++++++++++++++++ datastore/observations.go | 23 +++++++++++++++++++++++ datastore/observations_test.go | 20 ++++++++++++++++++++ models/observations.go | 32 ++++++++++++++++++++++++++++++++ models/observations_test.go | 31 +++++++++++++++++++++++++++++++ router/api.go | 1 + router/routes.go | 1 + 9 files changed, 158 insertions(+) diff --git a/api/handler.go b/api/handler.go index d3748d8..0e67f60 100644 --- a/api/handler.go +++ b/api/handler.go @@ -50,6 +50,7 @@ func Handler() *mux.Router { m.Get(router.Observation).Handler(handler(serveObservation)) m.Get(router.CreateObservation).Handler(handler(serveCreateObservation)) m.Get(router.Observations).Handler(handler(serveObservationList)) + m.Get(router.UpdateObservation).Handler(handler(serveUpdateObservation)) return m } diff --git a/api/observations.go b/api/observations.go index b1a8fc7..181874e 100644 --- a/api/observations.go +++ b/api/observations.go @@ -57,3 +57,22 @@ func serveObservationList(w http.ResponseWriter, r *http.Request) error { return writeJSON(w, observations) } + +func serveUpdateObservation(w http.ResponseWriter, r *http.Request) error { + id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0) + var observation models.Observation + err := json.NewDecoder(r.Body).Decode(&observation) + if err != nil { + return err + } + + updated, err := store.Observations.Update(id, &observation) + if err != nil { + return err + } + if updated { + w.WriteHeader(http.StatusOK) + } + + return writeJSON(w, observation) +} diff --git a/api/observations_test.go b/api/observations_test.go index bdbf03b..38ce5bb 100644 --- a/api/observations_test.go +++ b/api/observations_test.go @@ -94,3 +94,33 @@ func TestObservation_List(t *testing.T) { t.Errorf("got observations %+v but wanted observations %+v", observations, want) } } + +func TestObservation_Update(t *testing.T) { + setup() + + want := newObservation() + + calledPut := false + store.Observations.(*models.MockObservationsService).Update_ = func(id int64, observation *models.Observation) (bool, error) { + if id != want.Id { + t.Errorf("wanted request for observation %d but got %d", want.Id, id) + } + if !normalizeDeepEqual(want, observation) { + t.Errorf("wanted request for observation %d but got %d", want, observation) + } + calledPut = true + return true, nil + } + + success, err := apiClient.Observations.Update(want.Id, want) + if err != nil { + t.Fatal(err) + } + + if !calledPut { + t.Error("!calledPut") + } + if !success { + t.Error("!success") + } +} diff --git a/datastore/observations.go b/datastore/observations.go index 7e9e6c9..806c834 100644 --- a/datastore/observations.go +++ b/datastore/observations.go @@ -46,3 +46,26 @@ func (s *observationsStore) List(opt *models.ObservationListOptions) ([]*models. } return observations, nil } + +func (s *observationsStore) Update(id int64, observation *models.Observation) (bool, error) { + _, err := s.Get(id) + if err != nil { + return false, err + } + + if id != observation.Id { + return false, models.ErrObservationNotFound + } + + observation.UpdatedAt = time.Now() + changed, err := s.dbh.Update(observation) + if err != nil { + return false, err + } + + if changed == 0 { + return false, ErrNoRowsUpdated + } + + return true, nil +} diff --git a/datastore/observations_test.go b/datastore/observations_test.go index 88174c0..3d4aa46 100644 --- a/datastore/observations_test.go +++ b/datastore/observations_test.go @@ -88,3 +88,23 @@ func TestObservationsStore_List_db(t *testing.T) { t.Errorf("got observations %+v, want %+v", observations, want) } } + +func TestObservationsStore_Update_db(t *testing.T) { + tx, _ := DB.Begin() + defer tx.Rollback() + + observation := insertObservation(t, tx) + + d := NewDatastore(tx) + + // Tweak it + observation.ObservationName = "Updated Obs" + updated, err := d.Observations.Update(observation.Id, observation) + if err != nil { + t.Fatal(err) + } + + if !updated { + t.Error("!updated") + } +} diff --git a/models/observations.go b/models/observations.go index 130208a..bd9b5ab 100644 --- a/models/observations.go +++ b/models/observations.go @@ -35,6 +35,9 @@ type ObservationsService interface { // Create an observation Create(observation *Observation) (bool, error) + + // Update an observation + Update(id int64, Observation *Observation) (updated bool, err error) } var ( @@ -110,10 +113,32 @@ func (s *observationsService) List(opt *ObservationListOptions) ([]*Observation, return observations, nil } +func (s *observationsService) Update(id int64, observation *Observation) (bool, error) { + strId := strconv.FormatInt(id, 10) + + url, err := s.client.url(router.UpdateObservation, map[string]string{"Id": strId}, nil) + if err != nil { + return false, err + } + + req, err := s.client.NewRequest("PUT", url.String(), observation) + if err != nil { + return false, err + } + + resp, err := s.client.Do(req, &observation) + if err != nil { + return false, err + } + + return resp.StatusCode == http.StatusOK, nil +} + type MockObservationsService struct { Get_ func(id int64) (*Observation, error) List_ func(opt *ObservationListOptions) ([]*Observation, error) Create_ func(observation *Observation) (bool, error) + Update_ func(id int64, observation *Observation) (bool, error) } var _ObservationsService = &MockObservationsService{} @@ -138,3 +163,10 @@ func (s *MockObservationsService) List(opt *ObservationListOptions) ([]*Observat } return s.List_(opt) } + +func (s *MockObservationsService) Update(id int64, observation *Observation) (bool, error) { + if s.Update_ == nil { + return false, nil + } + return s.Update_(id, observation) +} diff --git a/models/observations_test.go b/models/observations_test.go index 2c57dbc..c5a7fbc 100644 --- a/models/observations_test.go +++ b/models/observations_test.go @@ -112,3 +112,34 @@ func TestObservationService_List(t *testing.T) { t.Errorf("Observations.List return %+v, want %+v", observations, want) } } + +func TestObservationService_Update(t *testing.T) { + setup() + defer teardown() + + want := newObservation() + + var called bool + mux.HandleFunc(urlPath(t, router.UpdateObservation, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "PUT") + testBody(t, r, `{"id":1,"observation_name":"Test Obs Updated","observation_type_id":0,"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") + w.WriteHeader(http.StatusOK) + writeJSON(w, want) + }) + + observation := newObservation() + observation.ObservationName = "Test Obs Updated" + updated, err := client.Observations.Update(observation.Id, observation) + if err != nil { + t.Errorf("Observations.Update returned error: %v", err) + } + + if !updated { + t.Error("!updated") + } + + if !called { + t.Fatal("!called") + } +} diff --git a/router/api.go b/router/api.go index 7b3a5a7..0cfe8ad 100644 --- a/router/api.go +++ b/router/api.go @@ -42,6 +42,7 @@ func API() *mux.Router { m.Path("/observations").Methods("GET").Name(Observations) m.Path("/observations").Methods("POST").Name(CreateObservation) m.Path("/observations/{Id:.+}").Methods("GET").Name(Observation) + m.Path("/observations/{Id:.+}").Methods("PUT").Name(UpdateObservation) return m } diff --git a/router/routes.go b/router/routes.go index 664a9f1..93e8001 100644 --- a/router/routes.go +++ b/router/routes.go @@ -32,4 +32,5 @@ const ( Observation = "observation:get" CreateObservation = "observation:create" Observations = "observation:list" + UpdateObservation = "observation:update" )