Create species, cleanup schema.

- create species
- species genus_id not null
This commit is contained in:
Matthew Dillon 2014-10-15 16:43:09 -08:00
parent ed2ba26654
commit 7fe5566edf
10 changed files with 155 additions and 3 deletions

View file

@ -30,6 +30,7 @@ func Handler() *mux.Router {
m.Get(router.DeleteGenus).Handler(handler(serveDeleteGenus))
m.Get(router.Species).Handler(handler(serveSpecies))
m.Get(router.CreateSpecies).Handler(handler(serveCreateSpecies))
return m
}

View file

@ -1,10 +1,12 @@
package api
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
)
func serveSpecies(w http.ResponseWriter, r *http.Request) error {
@ -20,3 +22,21 @@ func serveSpecies(w http.ResponseWriter, r *http.Request) error {
return writeJSON(w, species)
}
func serveCreateSpecies(w http.ResponseWriter, r *http.Request) error {
var species models.Species
err := json.NewDecoder(r.Body).Decode(&species)
if err != nil {
return err
}
created, err := store.Species.Create(&species)
if err != nil {
return err
}
if created {
w.WriteHeader(http.StatusCreated)
}
return writeJSON(w, species)
}

View file

@ -32,3 +32,30 @@ func TestSpecies_Get(t *testing.T) {
t.Errorf("got species %+v but wanted species %+v", got, want)
}
}
func TestSpecies_Create(t *testing.T) {
setup()
want := &models.Species{Id: 1, GenusId: 1, SpeciesName: "Test Species"}
calledPost := false
store.Species.(*models.MockSpeciesService).Create_ = func(species *models.Species) (bool, error) {
if !normalizeDeepEqual(want, species) {
t.Errorf("wanted request for species %d but got %d", want, species)
}
calledPost = true
return true, nil
}
success, err := apiClient.Species.Create(want)
if err != nil {
t.Fatal(err)
}
if !calledPost {
t.Error("!calledPost")
}
if !success {
t.Error("!success")
}
}

View file

@ -3,7 +3,7 @@
CREATE TABLE species (
id BIGSERIAL NOT NULL,
genusid BIGINT,
genusid BIGINT NOT NULL,
speciesname CHARACTER VARYING(100),
createdat TIMESTAMP WITH TIME ZONE,

View file

@ -20,3 +20,10 @@ func (s *speciesStore) Get(id int64) (*models.Species, error) {
}
return species[0], nil
}
func (s *speciesStore) Create(species *models.Species) (bool, error) {
if err := s.dbh.Insert(species); err != nil {
return false, err
}
return true, nil
}

View file

@ -35,3 +35,31 @@ func TestSpeciesStore_Get_db(t *testing.T) {
t.Errorf("got species %+v, want %+v", species, want)
}
}
func TestSpeciesStore_Create_db(t *testing.T) {
tx, _ := DB.Begin()
defer tx.Rollback()
// Test on a clean database
tx.Exec(`DELETE FROM species;`)
genus := &models.Genus{}
if err := tx.Insert(genus); err != nil {
t.Fatal(err)
}
species := &models.Species{Id: 1, GenusId: genus.Id, SpeciesName: "Test Species"}
d := NewDatastore(tx)
created, err := d.Species.Create(species)
if err != nil {
t.Fatal(err)
}
if !created {
t.Error("!created")
}
if species.Id == 0 {
t.Error("want nonzero species.Id after submitting")
}
}

View file

@ -2,6 +2,7 @@ package models
import (
"errors"
"net/http"
"strconv"
"time"
@ -22,6 +23,9 @@ type Species struct {
type SpeciesService interface {
// Get a species
Get(id int64) (*Species, error)
// Create a species record
Create(species *Species) (bool, error)
}
var (
@ -55,8 +59,28 @@ func (s *speciesService) Get(id int64) (*Species, error) {
return species, nil
}
func (s *speciesService) Create(species *Species) (bool, error) {
url, err := s.client.url(router.CreateSpecies, nil, nil)
if err != nil {
return false, err
}
req, err := s.client.NewRequest("POST", url.String(), species)
if err != nil {
return false, err
}
resp, err := s.client.Do(req, &species)
if err != nil {
return false, err
}
return resp.StatusCode == http.StatusCreated, nil
}
type MockSpeciesService struct {
Get_ func(id int64) (*Species, error)
Get_ func(id int64) (*Species, error)
Create_ func(species *Species) (bool, error)
}
var _ SpeciesService = &MockSpeciesService{}
@ -67,3 +91,10 @@ func (s *MockSpeciesService) Get(id int64) (*Species, error) {
}
return s.Get_(id)
}
func (s *MockSpeciesService) Create(species *Species) (bool, error) {
if s.Create_ == nil {
return false, nil
}
return s.Create_(species)
}

View file

@ -37,3 +37,39 @@ func TestSpeciesService_Get(t *testing.T) {
t.Errorf("Species.Get returned %+v, want %+v", species, want)
}
}
func TestSpeciesService_Create(t *testing.T) {
setup()
defer teardown()
want := &Species{Id: 1, GenusId: 1, SpeciesName: "Test Species"}
var called bool
mux.HandleFunc(urlPath(t, router.CreateSpecies, nil), func(w http.ResponseWriter, r *http.Request) {
called = true
testMethod(t, r, "POST")
testBody(t, r, `{"id":1,"genus_id":1,"species_name":"Test Species","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)
})
species := &Species{Id: 1, GenusId: 1, SpeciesName: "Test Species"}
created, err := client.Species.Create(species)
if err != nil {
t.Errorf("Species.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(species, want) {
t.Errorf("Species.Create returned %+v, want %+v", species, want)
}
}

View file

@ -18,6 +18,7 @@ func API() *mux.Router {
m.Path("/genera/{Id:.+}").Methods("DELETE").Name(DeleteGenus)
// Species
m.Path("/species").Methods("POST").Name(CreateSpecies)
m.Path("/species/{Id:.+}").Methods("GET").Name(Species)
return m

View file

@ -11,5 +11,6 @@ const (
UpdateGenus = "genus:update"
DeleteGenus = "genus:delete"
Species = "species"
Species = "species"
CreateSpecies = "species:create"
)