Refactor: generic handlers
This commit is contained in:
parent
58843133f5
commit
d413226d4d
6 changed files with 166 additions and 214 deletions
|
@ -4,18 +4,16 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
DB.AddTableWithName(CharacteristicBase{}, "characteristics").SetKeys(true, "Id")
|
DB.AddTableWithName(CharacteristicBase{}, "characteristics").SetKeys(true, "Id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CharacteristicService struct{}
|
||||||
|
|
||||||
// A Characteristic is a lookup type
|
// A Characteristic is a lookup type
|
||||||
type CharacteristicBase struct {
|
type CharacteristicBase struct {
|
||||||
Id int64 `json:"id,omitempty"`
|
Id int64 `json:"id,omitempty"`
|
||||||
|
@ -36,67 +34,25 @@ type Characteristic struct {
|
||||||
CharacteristicTypeName string `db:"characteristic_type_name" json:"characteristicType"`
|
CharacteristicTypeName string `db:"characteristic_type_name" json:"characteristicType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Characteristics []*Characteristic
|
||||||
|
|
||||||
type CharacteristicJSON struct {
|
type CharacteristicJSON struct {
|
||||||
Characteristic *Characteristic `json:"characteristic"`
|
Characteristic *Characteristic `json:"characteristic"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CharacteristicsJSON struct {
|
type CharacteristicsJSON struct {
|
||||||
Characteristics []*Characteristic `json:"characteristics"`
|
Characteristics *Characteristics `json:"characteristics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CharacteristicListOptions struct {
|
func (c *Characteristic) marshal() ([]byte, error) {
|
||||||
ListOptions
|
return json.Marshal(&CharacteristicJSON{Characteristic: c})
|
||||||
Genus string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveCharacteristicsList(w http.ResponseWriter, r *http.Request) {
|
func (c *Characteristics) marshal() ([]byte, error) {
|
||||||
var opt CharacteristicListOptions
|
return json.Marshal(&CharacteristicsJSON{Characteristics: c})
|
||||||
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
opt.Genus = mux.Vars(r)["genus"]
|
|
||||||
|
|
||||||
characteristics, err := dbGetCharacteristics(&opt)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if characteristics == nil {
|
|
||||||
characteristics = []*Characteristic{}
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(CharacteristicsJSON{Characteristics: characteristics})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.Write(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveCharacteristic(w http.ResponseWriter, r *http.Request) {
|
func (c CharacteristicService) list(opt *ListOptions) (entity, error) {
|
||||||
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
characteristic, err := dbGetCharacteristic(id)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(CharacteristicJSON{Characteristic: characteristic})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dbGetCharacteristics(opt *CharacteristicListOptions) ([]*Characteristic, error) {
|
|
||||||
if opt == nil {
|
if opt == nil {
|
||||||
return nil, errors.New("must provide options")
|
return nil, errors.New("must provide options")
|
||||||
}
|
}
|
||||||
|
@ -123,15 +79,15 @@ func dbGetCharacteristics(opt *CharacteristicListOptions) ([]*Characteristic, er
|
||||||
|
|
||||||
sql += " GROUP BY c.id, ct.characteristic_type_name;"
|
sql += " GROUP BY c.id, ct.characteristic_type_name;"
|
||||||
|
|
||||||
var characteristics []*Characteristic
|
var characteristics Characteristics
|
||||||
err := DBH.Select(&characteristics, sql, vals...)
|
err := DBH.Select(&characteristics, sql, vals...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return characteristics, nil
|
return &characteristics, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dbGetCharacteristic(id int64) (*Characteristic, error) {
|
func (c CharacteristicService) get(id int64, dummy string) (entity, error) {
|
||||||
var characteristic Characteristic
|
var characteristic Characteristic
|
||||||
sql := `SELECT c.*, ct.characteristic_type_name,
|
sql := `SELECT c.*, ct.characteristic_type_name,
|
||||||
array_agg(m.id) AS measurements, array_agg(st.id) AS strains
|
array_agg(m.id) AS measurements, array_agg(st.id) AS strains
|
||||||
|
|
18
entities.go
Normal file
18
entities.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
type entity interface {
|
||||||
|
marshal() ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type getter interface {
|
||||||
|
get(int64, string) (entity, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type lister interface {
|
||||||
|
list(*ListOptions) (entity, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type updater interface {
|
||||||
|
update(int64, *entity, Claims) error
|
||||||
|
unmarshal([]byte) (entity, error)
|
||||||
|
}
|
103
handlers.go
103
handlers.go
|
@ -3,8 +3,10 @@ package main
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -83,13 +85,13 @@ func Handler() http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
routes := []r{
|
routes := []r{
|
||||||
r{serveStrainsList, "GET", "/strains"},
|
r{handleLister(StrainService{}), "GET", "/strains"},
|
||||||
r{serveStrain, "GET", "/strains/{Id:.+}"},
|
r{handleGetter(StrainService{}), "GET", "/strains/{Id:.+}"},
|
||||||
r{serveUpdateStrain, "PUT", "/strains/{Id:.+}"},
|
r{handleUpdater(StrainService{}), "PUT", "/strains/{Id:.+}"},
|
||||||
r{serveMeasurementsList, "GET", "/measurements"},
|
r{handleLister(MeasurementService{}), "GET", "/measurements"},
|
||||||
r{serveMeasurement, "GET", "/measurements/{Id:.+}"},
|
r{handleGetter(MeasurementService{}), "GET", "/measurements/{Id:.+}"},
|
||||||
r{serveCharacteristicsList, "GET", "/characteristics"},
|
r{handleLister(CharacteristicService{}), "GET", "/characteristics"},
|
||||||
r{serveCharacteristic, "GET", "/characteristics/{Id:.+}"},
|
r{handleGetter(CharacteristicService{}), "GET", "/characteristics/{Id:.+}"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
|
@ -99,6 +101,93 @@ func Handler() http.Handler {
|
||||||
return corsHandler(m)
|
return corsHandler(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleGetter(g getter) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e, err := g.get(id, mux.Vars(r)["genus"])
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := e.marshal()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleLister(l lister) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var opt ListOptions
|
||||||
|
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.Genus = mux.Vars(r)["genus"]
|
||||||
|
|
||||||
|
es, err := l.list(&opt)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := es.marshal()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleUpdater(u updater) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyBytes, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e, err := u.unmarshal(bodyBytes)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c := context.Get(r, "claims")
|
||||||
|
var claims Claims = c.(Claims)
|
||||||
|
|
||||||
|
err = u.update(id, &e, claims)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := e.marshal()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func tokenHandler(h http.Handler) http.Handler {
|
func tokenHandler(h http.Handler) http.Handler {
|
||||||
token := func(w http.ResponseWriter, r *http.Request) {
|
token := func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||||
|
|
|
@ -11,6 +11,7 @@ type ListOptions struct {
|
||||||
PerPage int `url:",omitempty" json:",omitempty"`
|
PerPage int `url:",omitempty" json:",omitempty"`
|
||||||
Page int `url:",omitempty" json:",omitempty"`
|
Page int `url:",omitempty" json:",omitempty"`
|
||||||
Ids []int `url:",omitempty" json:",omitempty" schema:"ids[]"`
|
Ids []int `url:",omitempty" json:",omitempty" schema:"ids[]"`
|
||||||
|
Genus string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o ListOptions) PageOrDefault() int {
|
func (o ListOptions) PageOrDefault() int {
|
||||||
|
|
|
@ -4,12 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrMeasurementNotFound = errors.New("measurement not found")
|
var ErrMeasurementNotFound = errors.New("measurement not found")
|
||||||
|
@ -18,6 +14,8 @@ func init() {
|
||||||
DB.AddTableWithName(MeasurementBase{}, "measurements").SetKeys(true, "Id")
|
DB.AddTableWithName(MeasurementBase{}, "measurements").SetKeys(true, "Id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MeasurementService struct{}
|
||||||
|
|
||||||
// There are three types of supported measurements: fixed-test, free-text,
|
// There are three types of supported measurements: fixed-test, free-text,
|
||||||
// & numerical. The table has a constraint that will allow one or the other
|
// & numerical. The table has a constraint that will allow one or the other
|
||||||
// for a particular combination of strain & characteristic, but not both.
|
// for a particular combination of strain & characteristic, but not both.
|
||||||
|
@ -48,67 +46,25 @@ type Measurement struct {
|
||||||
TestMethod NullString `db:"test_method_name" json:"testMethod"`
|
TestMethod NullString `db:"test_method_name" json:"testMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Measurements []*Measurement
|
||||||
|
|
||||||
type MeasurementJSON struct {
|
type MeasurementJSON struct {
|
||||||
Measurement *Measurement `json:"measurement"`
|
Measurement *Measurement `json:"measurement"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MeasurementsJSON struct {
|
type MeasurementsJSON struct {
|
||||||
Measurements []*Measurement `json:"measurements"`
|
Measurements *Measurements `json:"measurements"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MeasurementListOptions struct {
|
func (m *Measurement) marshal() ([]byte, error) {
|
||||||
ListOptions
|
return json.Marshal(&MeasurementJSON{Measurement: m})
|
||||||
Genus string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveMeasurementsList(w http.ResponseWriter, r *http.Request) {
|
func (m *Measurements) marshal() ([]byte, error) {
|
||||||
var opt MeasurementListOptions
|
return json.Marshal(&MeasurementsJSON{Measurements: m})
|
||||||
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
opt.Genus = mux.Vars(r)["genus"]
|
|
||||||
|
|
||||||
measurements, err := dbGetMeasurements(&opt)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if measurements == nil {
|
|
||||||
measurements = []*Measurement{}
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(MeasurementsJSON{Measurements: measurements})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.Write(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveMeasurement(w http.ResponseWriter, r *http.Request) {
|
func (m MeasurementService) list(opt *ListOptions) (entity, error) {
|
||||||
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
measurement, err := dbGetMeasurement(id, mux.Vars(r)["genus"])
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(MeasurementJSON{Measurement: measurement})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dbGetMeasurements(opt *MeasurementListOptions) ([]*Measurement, error) {
|
|
||||||
if opt == nil {
|
if opt == nil {
|
||||||
return nil, errors.New("must provide options")
|
return nil, errors.New("must provide options")
|
||||||
}
|
}
|
||||||
|
@ -142,15 +98,15 @@ func dbGetMeasurements(opt *MeasurementListOptions) ([]*Measurement, error) {
|
||||||
|
|
||||||
sql += ";"
|
sql += ";"
|
||||||
|
|
||||||
var measurements []*Measurement
|
var measurements Measurements
|
||||||
err := DBH.Select(&measurements, sql, vals...)
|
err := DBH.Select(&measurements, sql, vals...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return measurements, nil
|
return &measurements, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dbGetMeasurement(id int64, genus string) (*Measurement, error) {
|
func (m MeasurementService) get(id int64, genus string) (entity, error) {
|
||||||
var measurement Measurement
|
var measurement Measurement
|
||||||
sql := `SELECT m.*, c.characteristic_name,
|
sql := `SELECT m.*, c.characteristic_name,
|
||||||
t.text_measurement_name AS text_measurement_type_name,
|
t.text_measurement_name AS text_measurement_type_name,
|
||||||
|
|
118
strains.go
118
strains.go
|
@ -5,12 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/context"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -22,6 +17,8 @@ func init() {
|
||||||
DB.AddTableWithName(StrainBase{}, "strains").SetKeys(true, "Id")
|
DB.AddTableWithName(StrainBase{}, "strains").SetKeys(true, "Id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StrainService struct{}
|
||||||
|
|
||||||
// StrainBase is what the DB expects to see for inserts/updates
|
// StrainBase is what the DB expects to see for inserts/updates
|
||||||
type StrainBase struct {
|
type StrainBase struct {
|
||||||
Id int64 `db:"id" json:"id"`
|
Id int64 `db:"id" json:"id"`
|
||||||
|
@ -45,105 +42,34 @@ type Strain struct {
|
||||||
*StrainBase
|
*StrainBase
|
||||||
SpeciesName string `db:"species_name" json:"speciesName"`
|
SpeciesName string `db:"species_name" json:"speciesName"`
|
||||||
Measurements NullSliceInt64 `db:"measurements" json:"measurements"`
|
Measurements NullSliceInt64 `db:"measurements" json:"measurements"`
|
||||||
TotalMeasurements int `db:"total_measurements" json:"totalMeasurements"`
|
TotalMeasurements int64 `db:"total_measurements" json:"totalMeasurements"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Strains []*Strain
|
||||||
|
|
||||||
type StrainJSON struct {
|
type StrainJSON struct {
|
||||||
Strain *Strain `json:"strain"`
|
Strain *Strain `json:"strain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StrainsJSON struct {
|
type StrainsJSON struct {
|
||||||
Strains []*Strain `json:"strains"`
|
Strains *Strains `json:"strains"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StrainListOptions struct {
|
func (s *Strain) marshal() ([]byte, error) {
|
||||||
ListOptions
|
return json.Marshal(&StrainJSON{Strain: s})
|
||||||
Genus string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveStrainsList(w http.ResponseWriter, r *http.Request) {
|
func (s *Strains) marshal() ([]byte, error) {
|
||||||
var opt StrainListOptions
|
return json.Marshal(&StrainsJSON{Strains: s})
|
||||||
if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
opt.Genus = mux.Vars(r)["genus"]
|
|
||||||
|
|
||||||
strains, err := dbGetStrains(&opt)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strains == nil {
|
|
||||||
strains = []*Strain{}
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(StrainsJSON{Strains: strains})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.Write(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveStrain(w http.ResponseWriter, r *http.Request) {
|
func (s StrainService) unmarshal(b []byte) (entity, error) {
|
||||||
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
|
var sj StrainJSON
|
||||||
if err != nil {
|
err := json.Unmarshal(b, &sj)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return sj.Strain, err
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
strain, err := dbGetStrain(id, mux.Vars(r)["genus"])
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(StrainJSON{Strain: strain})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.Write(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveUpdateStrain(w http.ResponseWriter, r *http.Request) {
|
func (s StrainService) list(opt *ListOptions) (entity, error) {
|
||||||
id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var strainjson StrainJSON
|
|
||||||
err = json.NewDecoder(r.Body).Decode(&strainjson)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c := context.Get(r, "claims")
|
|
||||||
var claims Claims = c.(Claims)
|
|
||||||
strainjson.Strain.UpdatedBy = claims.Sub
|
|
||||||
strainjson.Strain.UpdatedAt = currentTime()
|
|
||||||
strainjson.Strain.Id = id
|
|
||||||
|
|
||||||
err = dbUpdateStrain(strainjson.Strain)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(StrainJSON{Strain: strainjson.Strain})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
|
||||||
w.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dbGetStrains(opt *StrainListOptions) ([]*Strain, error) {
|
|
||||||
if opt == nil {
|
if opt == nil {
|
||||||
return nil, errors.New("must provide options")
|
return nil, errors.New("must provide options")
|
||||||
}
|
}
|
||||||
|
@ -171,15 +97,15 @@ func dbGetStrains(opt *StrainListOptions) ([]*Strain, error) {
|
||||||
|
|
||||||
sql += " GROUP BY st.id, sp.species_name;"
|
sql += " GROUP BY st.id, sp.species_name;"
|
||||||
|
|
||||||
var strains []*Strain
|
var strains Strains
|
||||||
err := DBH.Select(&strains, sql, vals...)
|
err := DBH.Select(&strains, sql, vals...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return strains, nil
|
return &strains, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dbGetStrain(id int64, genus string) (*Strain, error) {
|
func (s StrainService) get(id int64, genus string) (entity, error) {
|
||||||
var strain Strain
|
var strain Strain
|
||||||
q := `SELECT st.*, sp.species_name, array_agg(m.id) AS measurements,
|
q := `SELECT st.*, sp.species_name, array_agg(m.id) AS measurements,
|
||||||
COUNT(m) AS total_measurements
|
COUNT(m) AS total_measurements
|
||||||
|
@ -198,13 +124,19 @@ func dbGetStrain(id int64, genus string) (*Strain, error) {
|
||||||
return &strain, nil
|
return &strain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dbUpdateStrain(strain *Strain) error {
|
func (s StrainService) update(id int64, e *entity, claims Claims) error {
|
||||||
|
strain := (*e).(*Strain)
|
||||||
|
strain.UpdatedBy = claims.Sub
|
||||||
|
strain.UpdatedAt = currentTime()
|
||||||
|
strain.Id = id
|
||||||
|
|
||||||
var species_id struct{ Id int64 }
|
var species_id struct{ Id int64 }
|
||||||
q := `SELECT id FROM species WHERE species_name = $1;`
|
q := `SELECT id FROM species WHERE species_name = $1;`
|
||||||
if err := DBH.SelectOne(&species_id, q, strain.SpeciesName); err != nil {
|
if err := DBH.SelectOne(&species_id, q, strain.SpeciesName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
strain.StrainBase.SpeciesId = species_id.Id
|
strain.StrainBase.SpeciesId = species_id.Id
|
||||||
|
|
||||||
count, err := DBH.Update(strain.StrainBase)
|
count, err := DBH.Update(strain.StrainBase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Reference in a new issue