Get a text measurement type
This commit is contained in:
		
							parent
							
								
									72078cf6e4
								
							
						
					
					
						commit
						3e0ca9df8c
					
				
					 11 changed files with 277 additions and 19 deletions
				
			
		|  | @ -53,6 +53,8 @@ func Handler() *mux.Router { | ||||||
| 	m.Get(router.UpdateObservation).Handler(handler(serveUpdateObservation)) | 	m.Get(router.UpdateObservation).Handler(handler(serveUpdateObservation)) | ||||||
| 	m.Get(router.DeleteObservation).Handler(handler(serveDeleteObservation)) | 	m.Get(router.DeleteObservation).Handler(handler(serveDeleteObservation)) | ||||||
| 
 | 
 | ||||||
|  | 	m.Get(router.TextMeasurementType).Handler(handler(serveTextMeasurementType)) | ||||||
|  | 
 | ||||||
| 	return m | 	return m | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								api/text_measurement_types.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								api/text_measurement_types.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | package api | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 	"strconv" | ||||||
|  | 
 | ||||||
|  | 	"github.com/gorilla/mux" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func serveTextMeasurementType(w http.ResponseWriter, r *http.Request) error { | ||||||
|  | 	id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	text_measurement_type, err := store.TextMeasurementTypes.Get(id) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return writeJSON(w, text_measurement_type) | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								api/text_measurement_types_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								api/text_measurement_types_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | package api | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/thermokarst/bactdb/models" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func newTextMeasurementType() *models.TextMeasurementType { | ||||||
|  | 	text_measurement_type := models.NewTextMeasurementType() | ||||||
|  | 	return text_measurement_type | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestTextMeasurementType_Get(t *testing.T) { | ||||||
|  | 	setup() | ||||||
|  | 
 | ||||||
|  | 	want := newTextMeasurementType() | ||||||
|  | 
 | ||||||
|  | 	calledGet := false | ||||||
|  | 
 | ||||||
|  | 	store.TextMeasurementTypes.(*models.MockTextMeasurementTypesService).Get_ = func(id int64) (*models.TextMeasurementType, error) { | ||||||
|  | 		if id != want.Id { | ||||||
|  | 			t.Errorf("wanted request for text_measurement_type %d but got %d", want.Id, id) | ||||||
|  | 		} | ||||||
|  | 		calledGet = true | ||||||
|  | 		return want, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	got, err := apiClient.TextMeasurementTypes.Get(want.Id) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !calledGet { | ||||||
|  | 		t.Error("!calledGet") | ||||||
|  | 	} | ||||||
|  | 	if !normalizeDeepEqual(want, got) { | ||||||
|  | 		t.Errorf("got %+v but wanted %+v", got, want) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -9,13 +9,14 @@ import ( | ||||||
| 
 | 
 | ||||||
| // A datastore access point (in PostgreSQL) | // A datastore access point (in PostgreSQL) | ||||||
| type Datastore struct { | type Datastore struct { | ||||||
| 	Users            models.UsersService | 	Users                models.UsersService | ||||||
| 	Genera           models.GeneraService | 	Genera               models.GeneraService | ||||||
| 	Species          models.SpeciesService | 	Species              models.SpeciesService | ||||||
| 	Strains          models.StrainsService | 	Strains              models.StrainsService | ||||||
| 	ObservationTypes models.ObservationTypesService | 	ObservationTypes     models.ObservationTypesService | ||||||
| 	Observations     models.ObservationsService | 	Observations         models.ObservationsService | ||||||
| 	dbh              modl.SqlExecutor | 	TextMeasurementTypes models.TextMeasurementTypesService | ||||||
|  | 	dbh                  modl.SqlExecutor | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
|  | @ -37,16 +38,18 @@ func NewDatastore(dbh modl.SqlExecutor) *Datastore { | ||||||
| 	d.Strains = &strainsStore{d} | 	d.Strains = &strainsStore{d} | ||||||
| 	d.ObservationTypes = &observationTypesStore{d} | 	d.ObservationTypes = &observationTypesStore{d} | ||||||
| 	d.Observations = &observationsStore{d} | 	d.Observations = &observationsStore{d} | ||||||
|  | 	d.TextMeasurementTypes = &textMeasurementTypesStore{d} | ||||||
| 	return d | 	return d | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewMockDatastore() *Datastore { | func NewMockDatastore() *Datastore { | ||||||
| 	return &Datastore{ | 	return &Datastore{ | ||||||
| 		Users:            &models.MockUsersService{}, | 		Users:                &models.MockUsersService{}, | ||||||
| 		Genera:           &models.MockGeneraService{}, | 		Genera:               &models.MockGeneraService{}, | ||||||
| 		Species:          &models.MockSpeciesService{}, | 		Species:              &models.MockSpeciesService{}, | ||||||
| 		Strains:          &models.MockStrainsService{}, | 		Strains:              &models.MockStrainsService{}, | ||||||
| 		ObservationTypes: &models.MockObservationTypesService{}, | 		ObservationTypes:     &models.MockObservationTypesService{}, | ||||||
| 		Observations:     &models.MockObservationsService{}, | 		Observations:         &models.MockObservationsService{}, | ||||||
|  | 		TextMeasurementTypes: &models.MockTextMeasurementTypesService{}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								datastore/text_measurement_types.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								datastore/text_measurement_types.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | package datastore | ||||||
|  | 
 | ||||||
|  | import "github.com/thermokarst/bactdb/models" | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	DB.AddTableWithName(models.TextMeasurementType{}, "text_measurement_types").SetKeys(true, "Id") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type textMeasurementTypesStore struct { | ||||||
|  | 	*Datastore | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *textMeasurementTypesStore) Get(id int64) (*models.TextMeasurementType, error) { | ||||||
|  | 	var text_measurement_type []*models.TextMeasurementType | ||||||
|  | 	if err := s.dbh.Select(&text_measurement_type, `SELECT * FROM text_measurement_types WHERE id=$1;`, id); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if len(text_measurement_type) == 0 { | ||||||
|  | 		return nil, models.ErrTextMeasurementTypeNotFound | ||||||
|  | 	} | ||||||
|  | 	return text_measurement_type[0], nil | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								datastore/text_measurement_types_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								datastore/text_measurement_types_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | ||||||
|  | package datastore | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/jmoiron/modl" | ||||||
|  | 	"github.com/thermokarst/bactdb/models" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func insertTextMeasurementType(t *testing.T, tx *modl.Transaction) *models.TextMeasurementType { | ||||||
|  | 	// clean up our target table | ||||||
|  | 	tx.Exec(`DELETE FROM text_measurement_types;`) | ||||||
|  | 	text_measurement_type := newTextMeasurementType(t, tx) | ||||||
|  | 	if err := tx.Insert(text_measurement_type); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	return text_measurement_type | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newTextMeasurementType(t *testing.T, tx *modl.Transaction) *models.TextMeasurementType { | ||||||
|  | 	return &models.TextMeasurementType{TextMeasurementName: "Test Text Measurement Type"} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestTextMeasurementTypesStore_Get_db(t *testing.T) { | ||||||
|  | 	tx, _ := DB.Begin() | ||||||
|  | 	defer tx.Rollback() | ||||||
|  | 
 | ||||||
|  | 	want := insertTextMeasurementType(t, tx) | ||||||
|  | 
 | ||||||
|  | 	d := NewDatastore(tx) | ||||||
|  | 
 | ||||||
|  | 	text_measurement_type, err := d.TextMeasurementTypes.Get(want.Id) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) | ||||||
|  | 	normalizeTime(&text_measurement_type.CreatedAt, &text_measurement_type.UpdatedAt, &text_measurement_type.DeletedAt) | ||||||
|  | 
 | ||||||
|  | 	if !reflect.DeepEqual(text_measurement_type, want) { | ||||||
|  | 		t.Errorf("got text_measurement_type %+v, want %+v", text_measurement_type, want) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -16,12 +16,13 @@ import ( | ||||||
| 
 | 
 | ||||||
| // A Client communicates with bactdb's HTTP API. | // A Client communicates with bactdb's HTTP API. | ||||||
| type Client struct { | type Client struct { | ||||||
| 	Users            UsersService | 	Users                UsersService | ||||||
| 	Genera           GeneraService | 	Genera               GeneraService | ||||||
| 	Species          SpeciesService | 	Species              SpeciesService | ||||||
| 	Strains          StrainsService | 	Strains              StrainsService | ||||||
| 	ObservationTypes ObservationTypesService | 	ObservationTypes     ObservationTypesService | ||||||
| 	Observations     ObservationsService | 	Observations         ObservationsService | ||||||
|  | 	TextMeasurementTypes TextMeasurementTypesService | ||||||
| 
 | 
 | ||||||
| 	// BaseURL for HTTP requests to bactdb's API. | 	// BaseURL for HTTP requests to bactdb's API. | ||||||
| 	BaseURL *url.URL | 	BaseURL *url.URL | ||||||
|  | @ -55,6 +56,7 @@ func NewClient(httpClient *http.Client) *Client { | ||||||
| 	c.Strains = &strainsService{c} | 	c.Strains = &strainsService{c} | ||||||
| 	c.ObservationTypes = &observationTypesService{c} | 	c.ObservationTypes = &observationTypesService{c} | ||||||
| 	c.Observations = &observationsService{c} | 	c.Observations = &observationsService{c} | ||||||
|  | 	c.TextMeasurementTypes = &textMeasurementTypesService{c} | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										73
									
								
								models/text_measurement_types.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								models/text_measurement_types.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | ||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"strconv" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/lib/pq" | ||||||
|  | 	"github.com/thermokarst/bactdb/router" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // A TextMeasurementType is a lookup type | ||||||
|  | type TextMeasurementType struct { | ||||||
|  | 	Id                  int64       `json:"id,omitempty"` | ||||||
|  | 	TextMeasurementName string      `db:"text_measurement_name" json:"textMeasurementName"` | ||||||
|  | 	CreatedAt           time.Time   `db:"created_at" json:"createdAt"` | ||||||
|  | 	UpdatedAt           time.Time   `db:"updated_at" json:"updatedAt"` | ||||||
|  | 	DeletedAt           pq.NullTime `db:"deleted_at" json:"deletedAt"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewTextMeasurementType() *TextMeasurementType { | ||||||
|  | 	return &TextMeasurementType{ | ||||||
|  | 		TextMeasurementName: "Test Text Measurement Type", | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type TextMeasurementTypesService interface { | ||||||
|  | 	// Get a text measurement type | ||||||
|  | 	Get(id int64) (*TextMeasurementType, error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	ErrTextMeasurementTypeNotFound = errors.New("text measurement type not found") | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type textMeasurementTypesService struct { | ||||||
|  | 	client *Client | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *textMeasurementTypesService) Get(id int64) (*TextMeasurementType, error) { | ||||||
|  | 	strId := strconv.FormatInt(id, 10) | ||||||
|  | 
 | ||||||
|  | 	url, err := s.client.url(router.TextMeasurementType, map[string]string{"Id": strId}, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	req, err := s.client.NewRequest("GET", url.String(), nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var text_measurement_type *TextMeasurementType | ||||||
|  | 	_, err = s.client.Do(req, &text_measurement_type) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return text_measurement_type, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type MockTextMeasurementTypesService struct { | ||||||
|  | 	Get_ func(id int64) (*TextMeasurementType, error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var _ TextMeasurementTypesService = &MockTextMeasurementTypesService{} | ||||||
|  | 
 | ||||||
|  | func (s *MockTextMeasurementTypesService) Get(id int64) (*TextMeasurementType, error) { | ||||||
|  | 	if s.Get_ == nil { | ||||||
|  | 		return nil, nil | ||||||
|  | 	} | ||||||
|  | 	return s.Get_(id) | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								models/text_measurement_types_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								models/text_measurement_types_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 	"reflect" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/thermokarst/bactdb/router" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func newTextMeasurementType() *TextMeasurementType { | ||||||
|  | 	text_measurement_type := NewTextMeasurementType() | ||||||
|  | 	text_measurement_type.Id = 1 | ||||||
|  | 	return text_measurement_type | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestTextMeasurementTypeService_Get(t *testing.T) { | ||||||
|  | 	setup() | ||||||
|  | 	defer teardown() | ||||||
|  | 
 | ||||||
|  | 	want := newTextMeasurementType() | ||||||
|  | 
 | ||||||
|  | 	var called bool | ||||||
|  | 	mux.HandleFunc(urlPath(t, router.TextMeasurementType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		called = true | ||||||
|  | 		testMethod(t, r, "GET") | ||||||
|  | 
 | ||||||
|  | 		writeJSON(w, want) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	text_measurement_type, err := client.TextMeasurementTypes.Get(want.Id) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("TextMeasurementTypes.Get returned error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !called { | ||||||
|  | 		t.Fatal("!called") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) | ||||||
|  | 
 | ||||||
|  | 	if !reflect.DeepEqual(text_measurement_type, want) { | ||||||
|  | 		t.Errorf("TextMeasurementTypes.Get return %+v, want %+v", text_measurement_type, want) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -45,5 +45,8 @@ func API() *mux.Router { | ||||||
| 	m.Path("/observations/{Id:.+}").Methods("PUT").Name(UpdateObservation) | 	m.Path("/observations/{Id:.+}").Methods("PUT").Name(UpdateObservation) | ||||||
| 	m.Path("/observations/{Id:.+}").Methods("DELETE").Name(DeleteObservation) | 	m.Path("/observations/{Id:.+}").Methods("DELETE").Name(DeleteObservation) | ||||||
| 
 | 
 | ||||||
|  | 	// TextMeasurementTypes | ||||||
|  | 	m.Path("/text_measurement_types/{Id:.+}").Methods("GET").Name(TextMeasurementType) | ||||||
|  | 
 | ||||||
| 	return m | 	return m | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -34,4 +34,6 @@ const ( | ||||||
| 	Observations      = "observation:list" | 	Observations      = "observation:list" | ||||||
| 	UpdateObservation = "observation:update" | 	UpdateObservation = "observation:update" | ||||||
| 	DeleteObservation = "observation:delete" | 	DeleteObservation = "observation:delete" | ||||||
|  | 
 | ||||||
|  | 	TextMeasurementType = "text_measurement_type:get" | ||||||
| ) | ) | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon