From dac0721a4179b87d52c2809c7d4e0cc886289ccb Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 20 Nov 2014 15:48:59 -0900 Subject: [PATCH] List observations. --- api/handler.go | 1 + api/observations.go | 17 +++++++++++++++++ api/observations_test.go | 29 ++++++++++++++++++++++++++++ datastore/observations.go | 12 ++++++++++++ datastore/observations_test.go | 23 ++++++++++++++++++++++ models/observations.go | 35 ++++++++++++++++++++++++++++++++++ models/observations_test.go | 33 ++++++++++++++++++++++++++++++++ router/api.go | 1 + router/routes.go | 1 + 9 files changed, 152 insertions(+) diff --git a/api/handler.go b/api/handler.go index 9a061b7..d3748d8 100644 --- a/api/handler.go +++ b/api/handler.go @@ -49,6 +49,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)) return m } diff --git a/api/observations.go b/api/observations.go index 4a1827e..b1a8fc7 100644 --- a/api/observations.go +++ b/api/observations.go @@ -40,3 +40,20 @@ func serveCreateObservation(w http.ResponseWriter, r *http.Request) error { return writeJSON(w, observation) } + +func serveObservationList(w http.ResponseWriter, r *http.Request) error { + var opt models.ObservationListOptions + if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil { + return err + } + + observations, err := store.Observations.List(&opt) + if err != nil { + return err + } + if observations == nil { + observations = []*models.Observation{} + } + + return writeJSON(w, observations) +} diff --git a/api/observations_test.go b/api/observations_test.go index e39b24b..bdbf03b 100644 --- a/api/observations_test.go +++ b/api/observations_test.go @@ -65,3 +65,32 @@ func TestObservation_Create(t *testing.T) { t.Error("!success") } } + +func TestObservation_List(t *testing.T) { + setup() + + want := []*models.Observation{newObservation()} + wantOpt := &models.ObservationListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}} + + calledList := false + store.Observations.(*models.MockObservationsService).List_ = func(opt *models.ObservationListOptions) ([]*models.Observation, error) { + if !normalizeDeepEqual(wantOpt, opt) { + t.Errorf("wanted options %d but got %d", wantOpt, opt) + } + calledList = true + return want, nil + } + + observations, err := apiClient.Observations.List(wantOpt) + if err != nil { + t.Fatal(err) + } + + if !calledList { + t.Error("!calledList") + } + + if !normalizeDeepEqual(&want, &observations) { + t.Errorf("got observations %+v but wanted observations %+v", observations, want) + } +} diff --git a/datastore/observations.go b/datastore/observations.go index c6fe565..7e9e6c9 100644 --- a/datastore/observations.go +++ b/datastore/observations.go @@ -34,3 +34,15 @@ func (s *observationsStore) Create(observation *models.Observation) (bool, error } return true, nil } + +func (s *observationsStore) List(opt *models.ObservationListOptions) ([]*models.Observation, error) { + if opt == nil { + opt = &models.ObservationListOptions{} + } + var observations []*models.Observation + err := s.dbh.Select(&observations, `SELECT * FROM observations LIMIT $1 OFFSET $2;`, opt.PerPageOrDefault(), opt.Offset()) + if err != nil { + return nil, err + } + return observations, nil +} diff --git a/datastore/observations_test.go b/datastore/observations_test.go index 113f709..88174c0 100644 --- a/datastore/observations_test.go +++ b/datastore/observations_test.go @@ -65,3 +65,26 @@ func TestObservationsStore_Create_db(t *testing.T) { t.Error("want nonzero observation.Id after submitting") } } + +func TestObservationsStore_List_db(t *testing.T) { + tx, _ := DB.Begin() + defer tx.Rollback() + + want_observation := insertObservation(t, tx) + want := []*models.Observation{want_observation} + + d := NewDatastore(tx) + + observations, err := d.Observations.List(&models.ObservationListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}) + if err != nil { + t.Fatal(err) + } + + for i := range want { + normalizeTime(&want[i].CreatedAt, &want[i].UpdatedAt, &want[i].DeletedAt) + normalizeTime(&observations[i].CreatedAt, &observations[i].UpdatedAt, &observations[i].DeletedAt) + } + if !reflect.DeepEqual(observations, want) { + t.Errorf("got observations %+v, want %+v", observations, want) + } +} diff --git a/models/observations.go b/models/observations.go index 824a4c1..130208a 100644 --- a/models/observations.go +++ b/models/observations.go @@ -30,6 +30,9 @@ type ObservationsService interface { // Get an observation Get(id int64) (*Observation, error) + // List all observations + List(opt *ObservationListOptions) ([]*Observation, error) + // Create an observation Create(observation *Observation) (bool, error) } @@ -83,8 +86,33 @@ func (s *observationsService) Create(observation *Observation) (bool, error) { return resp.StatusCode == http.StatusCreated, nil } +type ObservationListOptions struct { + ListOptions +} + +func (s *observationsService) List(opt *ObservationListOptions) ([]*Observation, error) { + url, err := s.client.url(router.Observations, nil, opt) + if err != nil { + return nil, err + } + + req, err := s.client.NewRequest("GET", url.String(), nil) + if err != nil { + return nil, err + } + + var observations []*Observation + _, err = s.client.Do(req, &observations) + if err != nil { + return nil, err + } + + return observations, nil +} + type MockObservationsService struct { Get_ func(id int64) (*Observation, error) + List_ func(opt *ObservationListOptions) ([]*Observation, error) Create_ func(observation *Observation) (bool, error) } @@ -103,3 +131,10 @@ func (s *MockObservationsService) Create(observation *Observation) (bool, error) } return s.Create_(observation) } + +func (s *MockObservationsService) List(opt *ObservationListOptions) ([]*Observation, error) { + if s.List_ == nil { + return nil, nil + } + return s.List_(opt) +} diff --git a/models/observations_test.go b/models/observations_test.go index 2b3d595..2c57dbc 100644 --- a/models/observations_test.go +++ b/models/observations_test.go @@ -79,3 +79,36 @@ func TestObservationService_Create(t *testing.T) { t.Errorf("Observations.Create returned %+v, want %+v", observation, want) } } + +func TestObservationService_List(t *testing.T) { + setup() + defer teardown() + + want := []*Observation{newObservation()} + + var called bool + mux.HandleFunc(urlPath(t, router.Observations, nil), func(w http.ResponseWriter, r *http.Request) { + called = true + testMethod(t, r, "GET") + testFormValues(t, r, values{}) + + writeJSON(w, want) + }) + + observations, err := client.Observations.List(nil) + if err != nil { + t.Errorf("Observations.List returned error: %v", err) + } + + if !called { + t.Fatal("!called") + } + + for _, u := range want { + normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt) + } + + if !reflect.DeepEqual(observations, want) { + t.Errorf("Observations.List return %+v, want %+v", observations, want) + } +} diff --git a/router/api.go b/router/api.go index 046c8be..7b3a5a7 100644 --- a/router/api.go +++ b/router/api.go @@ -39,6 +39,7 @@ func API() *mux.Router { m.Path("/observation_types/{Id:.+}").Methods("DELETE").Name(DeleteObservationType) // Observations + m.Path("/observations").Methods("GET").Name(Observations) m.Path("/observations").Methods("POST").Name(CreateObservation) m.Path("/observations/{Id:.+}").Methods("GET").Name(Observation) diff --git a/router/routes.go b/router/routes.go index 0b57436..664a9f1 100644 --- a/router/routes.go +++ b/router/routes.go @@ -31,4 +31,5 @@ const ( Observation = "observation:get" CreateObservation = "observation:create" + Observations = "observation:list" )