Add compare handler

This commit is contained in:
Matthew Dillon 2015-07-17 16:35:09 -08:00
parent ec93617ca8
commit 763c1f77d1
3 changed files with 169 additions and 3 deletions

119
compare.go Normal file
View file

@ -0,0 +1,119 @@
package main
import (
"bytes"
"encoding/csv"
"encoding/json"
"fmt"
"net/http"
"strconv"
"strings"
"time"
"github.com/gorilla/mux"
)
func handleCompare(w http.ResponseWriter, r *http.Request) *appError {
// types
type Comparisions map[string]map[string]string
type ComparisionsJSON [][]string
// vars
mimeType := r.FormValue("mimeType")
if mimeType == "" {
mimeType = "json"
}
claims := getClaims(r)
var header string
var data []byte
// Get measurements for comparision
measService := MeasurementService{}
opt := r.URL.Query()
opt.Del("mimeType")
opt.Del("token")
opt.Add("Genus", mux.Vars(r)["genus"])
measurementsEntity, appErr := measService.list(&opt, &claims)
if appErr != nil {
return appErr
}
measurementsPayload := (measurementsEntity).(*MeasurementsPayload)
// Assemble matrix
characteristic_ids := strings.Split(opt.Get("characteristic_ids"), ",")
strain_ids := strings.Split(opt.Get("strain_ids"), ",")
comparisions := make(Comparisions)
for _, characteristic_id := range characteristic_ids {
characteristic_id_int, _ := strconv.ParseInt(characteristic_id, 10, 0)
values := make(map[string]string)
for _, strain_id := range strain_ids {
strain_id_int, _ := strconv.ParseInt(strain_id, 10, 0)
for _, m := range *measurementsPayload.Measurements {
if (m.CharacteristicId == characteristic_id_int) && (m.StrainId == strain_id_int) {
values[strain_id] = m.Value()
}
}
}
comparisions[characteristic_id] = values
}
// Return, based on mimetype
switch mimeType {
case "json":
header = "application/json"
comparisionsJSON := make(ComparisionsJSON, 0)
for _, characteristic_id := range characteristic_ids {
row := []string{characteristic_id}
for _, strain_id := range strain_ids {
row = append(row, comparisions[characteristic_id][strain_id])
}
comparisionsJSON = append(comparisionsJSON, row)
}
data, _ = json.Marshal(comparisionsJSON)
case "csv":
header = "text/csv"
// maps to translate ids
strains := make(map[string]string)
for _, strain := range *measurementsPayload.Strains {
strains[fmt.Sprintf("%d", strain.Id)] = strain.StrainName
}
characteristics := make(map[string]string)
for _, characteristic := range *measurementsPayload.Characteristics {
characteristics[fmt.Sprintf("%d", characteristic.Id)] = characteristic.CharacteristicName
}
b := &bytes.Buffer{}
wr := csv.NewWriter(b)
// Write header row
r := []string{""}
for _, strain_id := range strain_ids {
r = append(r, strains[strain_id])
}
wr.Write(r)
// Write data
for key, record := range comparisions {
r := []string{characteristics[key]}
for _, val := range record {
r = append(r, val)
}
wr.Write(r)
}
wr.Flush()
data = b.Bytes()
w.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="compare-%d.csv"`, int32(time.Now().Unix())))
}
// Wrap it up
w.Header().Set("Content-Type", header)
w.Write(data)
return nil
}

View file

@ -92,6 +92,8 @@ func Handler() http.Handler {
s.Handle("/users/verify/{Nonce}", errorHandler(handleUserVerify)).Methods("GET")
s.Handle("/users/lockout", errorHandler(handleUserLockout)).Methods("POST")
s.Handle("/compare", j.Secure(errorHandler(handleCompare), verifyClaims)).Methods("GET")
type r struct {
f errorHandler
m string

View file

@ -4,6 +4,7 @@ import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
@ -62,6 +63,19 @@ type Measurement struct {
CanEdit bool `db:"-" json:"canEdit"`
}
func (m *Measurement) Value() string {
if m.TextMeasurementType.Valid {
return m.TextMeasurementType.String
}
if m.TxtValue.Valid {
return m.TxtValue.String
}
if m.NumValue.Valid {
return fmt.Sprintf("%f", m.NumValue.Float64)
}
return ""
}
type Measurements []*Measurement
type MeasurementMeta struct {
@ -72,9 +86,10 @@ type MeasurementPayload struct {
Measurement *Measurement `json:"measurement"`
}
// TODO: Add related models
type MeasurementsPayload struct {
Measurements *Measurements `json:"measurements"`
Strains *Strains `json:"strains"`
Characteristics *Characteristics `json:"characteristics"`
Measurements *Measurements `json:"measurements"`
}
func (m *MeasurementPayload) marshal() ([]byte, error) {
@ -105,8 +120,30 @@ func (m MeasurementService) list(val *url.Values, claims *Claims) (entity, *appE
return nil, newJSONError(err, http.StatusInternalServerError)
}
char_opts, err := characteristicOptsFromMeasurements(opt)
if err != nil {
return nil, newJSONError(err, http.StatusInternalServerError)
}
characteristics, err := listCharacteristics(*char_opts, claims)
if err != nil {
return nil, newJSONError(err, http.StatusInternalServerError)
}
strain_opts, err := strainOptsFromMeasurements(opt)
if err != nil {
return nil, newJSONError(err, http.StatusInternalServerError)
}
strains, err := listStrains(*strain_opts, claims)
if err != nil {
return nil, newJSONError(err, http.StatusInternalServerError)
}
payload := MeasurementsPayload{
Measurements: measurements,
Characteristics: characteristics,
Strains: strains,
Measurements: measurements,
}
return &payload, nil
@ -212,3 +249,11 @@ func getMeasurement(id int64, genus string, claims *Claims) (*Measurement, error
return &measurement, nil
}
func characteristicOptsFromMeasurements(opt MeasurementListOptions) (*ListOptions, error) {
return &ListOptions{Genus: opt.Genus, Ids: opt.Characteristics}, nil
}
func strainOptsFromMeasurements(opt MeasurementListOptions) (*ListOptions, error) {
return &ListOptions{Genus: opt.Genus, Ids: opt.Strains}, nil
}