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.DeleteGenus).Handler(handler(serveDeleteGenus))
m.Get(router.Species).Handler(handler(serveSpecies)) m.Get(router.Species).Handler(handler(serveSpecies))
m.Get(router.CreateSpecies).Handler(handler(serveCreateSpecies))
return m return m
} }

View file

@ -1,10 +1,12 @@
package api package api
import ( import (
"encoding/json"
"net/http" "net/http"
"strconv" "strconv"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/thermokarst/bactdb/models"
) )
func serveSpecies(w http.ResponseWriter, r *http.Request) error { 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) 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) 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 ( CREATE TABLE species (
id BIGSERIAL NOT NULL, id BIGSERIAL NOT NULL,
genusid BIGINT, genusid BIGINT NOT NULL,
speciesname CHARACTER VARYING(100), speciesname CHARACTER VARYING(100),
createdat TIMESTAMP WITH TIME ZONE, createdat TIMESTAMP WITH TIME ZONE,

View file

@ -20,3 +20,10 @@ func (s *speciesStore) Get(id int64) (*models.Species, error) {
} }
return species[0], nil 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) 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 ( import (
"errors" "errors"
"net/http"
"strconv" "strconv"
"time" "time"
@ -22,6 +23,9 @@ type Species struct {
type SpeciesService interface { type SpeciesService interface {
// Get a species // Get a species
Get(id int64) (*Species, error) Get(id int64) (*Species, error)
// Create a species record
Create(species *Species) (bool, error)
} }
var ( var (
@ -55,8 +59,28 @@ func (s *speciesService) Get(id int64) (*Species, error) {
return species, nil 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 { type MockSpeciesService struct {
Get_ func(id int64) (*Species, error) Get_ func(id int64) (*Species, error)
Create_ func(species *Species) (bool, error)
} }
var _ SpeciesService = &MockSpeciesService{} var _ SpeciesService = &MockSpeciesService{}
@ -67,3 +91,10 @@ func (s *MockSpeciesService) Get(id int64) (*Species, error) {
} }
return s.Get_(id) 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) 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) m.Path("/genera/{Id:.+}").Methods("DELETE").Name(DeleteGenus)
// Species // Species
m.Path("/species").Methods("POST").Name(CreateSpecies)
m.Path("/species/{Id:.+}").Methods("GET").Name(Species) m.Path("/species/{Id:.+}").Methods("GET").Name(Species)
return m return m

View file

@ -12,4 +12,5 @@ const (
DeleteGenus = "genus:delete" DeleteGenus = "genus:delete"
Species = "species" Species = "species"
CreateSpecies = "species:create"
) )