Genera: router & models
This commit is contained in:
		
							parent
							
								
									08ae818d74
								
							
						
					
					
						commit
						9155ee88f1
					
				
					 5 changed files with 258 additions and 4 deletions
				
			
		|  | @ -17,6 +17,7 @@ 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 | ||||||
| 
 | 
 | ||||||
| 	// BaseURL for HTTP requests to bactdb's API. | 	// BaseURL for HTTP requests to bactdb's API. | ||||||
| 	BaseURL *url.URL | 	BaseURL *url.URL | ||||||
|  | @ -45,6 +46,7 @@ func NewClient(httpClient *http.Client) *Client { | ||||||
| 		httpClient: httpClient, | 		httpClient: httpClient, | ||||||
| 	} | 	} | ||||||
| 	c.Users = &usersService{c} | 	c.Users = &usersService{c} | ||||||
|  | 	c.Genera = &generaService{c} | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										135
									
								
								models/genera.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								models/genera.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | ||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"net/http" | ||||||
|  | 	"strconv" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/thermokarst/bactdb/router" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // A Genus is a high-level classifier in bactdb. | ||||||
|  | type Genus struct { | ||||||
|  | 	Id        int64     `json:"id,omitempty"` | ||||||
|  | 	GenusName string    `json:"genus_name"` | ||||||
|  | 	CreatedAt time.Time `json:"created_at"` | ||||||
|  | 	UpdatedAt time.Time `json:"updated_at"` | ||||||
|  | 	DeletedAt time.Time `json:"deleted_at"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GeneraService interacts with the genus-related endpoints in bactdb's API. | ||||||
|  | type GeneraService interface { | ||||||
|  | 	// Get a genus. | ||||||
|  | 	Get(id int64) (*Genus, error) | ||||||
|  | 
 | ||||||
|  | 	// List all genera. | ||||||
|  | 	List(opt *GenusListOptions) ([]*Genus, error) | ||||||
|  | 
 | ||||||
|  | 	// Create a new genus. The newly created genus's ID is written to genus.Id | ||||||
|  | 	Create(genus *Genus) (created bool, err error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	ErrGenusNotFound = errors.New("genus not found") | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type generaService struct { | ||||||
|  | 	client *Client | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *generaService) Get(id int64) (*Genus, error) { | ||||||
|  | 	// Pass in key value pairs as strings, so that the gorilla mux URL | ||||||
|  | 	// generation is happy. | ||||||
|  | 	strId := strconv.FormatInt(id, 10) | ||||||
|  | 
 | ||||||
|  | 	url, err := s.client.url(router.Genus, 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 genus *Genus | ||||||
|  | 	_, err = s.client.Do(req, &genus) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return genus, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *generaService) Create(genus *Genus) (bool, error) { | ||||||
|  | 	url, err := s.client.url(router.CreateGenus, nil, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	req, err := s.client.NewRequest("POST", url.String(), genus) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	resp, err := s.client.Do(req, &genus) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return resp.StatusCode == http.StatusCreated, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type GenusListOptions struct { | ||||||
|  | 	ListOptions | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *generaService) List(opt *GenusListOptions) ([]*Genus, error) { | ||||||
|  | 	url, err := s.client.url(router.Genera, nil, opt) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	req, err := s.client.NewRequest("GET", url.String(), nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var genera []*Genus | ||||||
|  | 	_, err = s.client.Do(req, &genera) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return genera, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type MockGeneraService struct { | ||||||
|  | 	Get_    func(id int64) (*Genus, error) | ||||||
|  | 	List_   func(opt *GenusListOptions) ([]*Genus, error) | ||||||
|  | 	Create_ func(post *Genus) (bool, error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var _ GeneraService = &MockGeneraService{} | ||||||
|  | 
 | ||||||
|  | func (s *MockGeneraService) Get(id int64) (*Genus, error) { | ||||||
|  | 	if s.Get_ == nil { | ||||||
|  | 		return nil, nil | ||||||
|  | 	} | ||||||
|  | 	return s.Get_(id) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *MockGeneraService) Create(genus *Genus) (bool, error) { | ||||||
|  | 	if s.Create_ == nil { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  | 	return s.Create_(genus) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *MockGeneraService) List(opt *GenusListOptions) ([]*Genus, error) { | ||||||
|  | 	if s.List_ == nil { | ||||||
|  | 		return nil, nil | ||||||
|  | 	} | ||||||
|  | 	return s.List_(opt) | ||||||
|  | } | ||||||
							
								
								
									
										107
									
								
								models/genera_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								models/genera_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | ||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  | 	"reflect" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/thermokarst/bactdb/router" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestGeneraService_Get(t *testing.T) { | ||||||
|  | 	setup() | ||||||
|  | 	defer teardown() | ||||||
|  | 
 | ||||||
|  | 	want := &Genus{Id: 1, GenusName: "Test Genus"} | ||||||
|  | 
 | ||||||
|  | 	var called bool | ||||||
|  | 	mux.HandleFunc(urlPath(t, router.Genus, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		called = true | ||||||
|  | 		testMethod(t, r, "GET") | ||||||
|  | 
 | ||||||
|  | 		writeJSON(w, want) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	genus, err := client.Genera.Get(1) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Genera.Get returned error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !called { | ||||||
|  | 		t.Fatal("!called") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt) | ||||||
|  | 
 | ||||||
|  | 	if !reflect.DeepEqual(genus, want) { | ||||||
|  | 		t.Errorf("Genera.Get returned %+v, want %+v", genus, want) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGeneraService_Create(t *testing.T) { | ||||||
|  | 	setup() | ||||||
|  | 	defer teardown() | ||||||
|  | 
 | ||||||
|  | 	want := &Genus{Id: 1, GenusName: "Test Genus"} | ||||||
|  | 
 | ||||||
|  | 	var called bool | ||||||
|  | 	mux.HandleFunc(urlPath(t, router.CreateGenus, nil), func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		called = true | ||||||
|  | 		testMethod(t, r, "POST") | ||||||
|  | 		testBody(t, r, `{"id":1,"genus_name":"Test Genus","created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","deleted_at":"0001-01-01T00:00:00Z"}`+"\n") | ||||||
|  | 
 | ||||||
|  | 		w.WriteHeader(http.StatusCreated) | ||||||
|  | 		writeJSON(w, want) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	genus := &Genus{Id: 1, GenusName: "Test Genus"} | ||||||
|  | 	created, err := client.Genera.Create(genus) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Genera.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(genus, want) { | ||||||
|  | 		t.Errorf("Genera.Create returned %+v, want %+v", genus, want) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGeneraService_List(t *testing.T) { | ||||||
|  | 	setup() | ||||||
|  | 	defer teardown() | ||||||
|  | 
 | ||||||
|  | 	want := []*Genus{{Id: 1, GenusName: "Test Genus"}} | ||||||
|  | 
 | ||||||
|  | 	var called bool | ||||||
|  | 	mux.HandleFunc(urlPath(t, router.Genera, nil), func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		called = true | ||||||
|  | 		testMethod(t, r, "GET") | ||||||
|  | 		testFormValues(t, r, values{}) | ||||||
|  | 
 | ||||||
|  | 		writeJSON(w, want) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	genera, err := client.Genera.List(nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Genera.List returned error: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !called { | ||||||
|  | 		t.Fatal("!called") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, u := range want { | ||||||
|  | 		normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt) | ||||||
|  | 	} | ||||||
|  | 	if !reflect.DeepEqual(genera, want) { | ||||||
|  | 		t.Errorf("Genera.List return %+v, want %+v", genera, want) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -4,8 +4,15 @@ import "github.com/gorilla/mux" | ||||||
| 
 | 
 | ||||||
| func API() *mux.Router { | func API() *mux.Router { | ||||||
| 	m := mux.NewRouter() | 	m := mux.NewRouter() | ||||||
|  | 
 | ||||||
|  | 	// Users | ||||||
| 	m.Path("/users").Methods("GET").Name(Users) | 	m.Path("/users").Methods("GET").Name(Users) | ||||||
| 	m.Path("/users").Methods("POST").Name(CreateUser) | 	m.Path("/users").Methods("POST").Name(CreateUser) | ||||||
| 	m.Path("/users/{Id:.+}").Methods("GET").Name(User) | 	m.Path("/users/{Id:.+}").Methods("GET").Name(User) | ||||||
|  | 
 | ||||||
|  | 	// Genera | ||||||
|  | 	m.Path("/genera").Methods("GET").Name(Genera) | ||||||
|  | 	m.Path("/genera").Methods("POST").Name(CreateGenus) | ||||||
|  | 	m.Path("/genera/{Id:.+}").Methods("GET").Name(Genus) | ||||||
| 	return m | 	return m | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,4 +4,7 @@ const ( | ||||||
| 	User        = "user" | 	User        = "user" | ||||||
| 	CreateUser  = "user:create" | 	CreateUser  = "user:create" | ||||||
| 	Users       = "users" | 	Users       = "users" | ||||||
|  | 	Genus       = "genus" | ||||||
|  | 	CreateGenus = "genus:create" | ||||||
|  | 	Genera      = "genera" | ||||||
| ) | ) | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon