Renaming observations to characteristics
This commit is contained in:
		
							parent
							
								
									c1323f9c1f
								
							
						
					
					
						commit
						950b15a117
					
				
					 27 changed files with 889 additions and 889 deletions
				
			
		
							
								
								
									
										92
									
								
								api/characteristics.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								api/characteristics.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/gorilla/mux"
 | 
				
			||||||
 | 
						"github.com/thermokarst/bactdb/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func serveCharacteristic(w http.ResponseWriter, r *http.Request) error {
 | 
				
			||||||
 | 
						id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic, err := store.Characteristics.Get(id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return writeJSON(w, characteristic)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func serveCreateCharacteristic(w http.ResponseWriter, r *http.Request) error {
 | 
				
			||||||
 | 
						var characteristic models.Characteristic
 | 
				
			||||||
 | 
						err := json.NewDecoder(r.Body).Decode(&characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						created, err := store.Characteristics.Create(&characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if created {
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusCreated)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return writeJSON(w, characteristic)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func serveCharacteristicList(w http.ResponseWriter, r *http.Request) error {
 | 
				
			||||||
 | 
						var opt models.CharacteristicListOptions
 | 
				
			||||||
 | 
						if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristics, err := store.Characteristics.List(&opt)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if characteristics == nil {
 | 
				
			||||||
 | 
							characteristics = []*models.Characteristic{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return writeJSON(w, characteristics)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func serveUpdateCharacteristic(w http.ResponseWriter, r *http.Request) error {
 | 
				
			||||||
 | 
						id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
 | 
				
			||||||
 | 
						var characteristic models.Characteristic
 | 
				
			||||||
 | 
						err := json.NewDecoder(r.Body).Decode(&characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						updated, err := store.Characteristics.Update(id, &characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if updated {
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return writeJSON(w, characteristic)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func serveDeleteCharacteristic(w http.ResponseWriter, r *http.Request) error {
 | 
				
			||||||
 | 
						id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						deleted, err := store.Characteristics.Delete(id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if deleted {
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return writeJSON(w, &models.Characteristic{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										153
									
								
								api/characteristics_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								api/characteristics_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,153 @@
 | 
				
			||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/thermokarst/bactdb/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newCharacteristic() *models.Characteristic {
 | 
				
			||||||
 | 
						characteristic := models.NewCharacteristic()
 | 
				
			||||||
 | 
						return characteristic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristic_Get(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						calledGet := false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						store.Characteristics.(*models.MockCharacteristicsService).Get_ = func(id int64) (*models.Characteristic, error) {
 | 
				
			||||||
 | 
							if id != want.Id {
 | 
				
			||||||
 | 
								t.Errorf("wanted request for characteristic %d but got %d", want.Id, id)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							calledGet = true
 | 
				
			||||||
 | 
							return want, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						got, err := apiClient.Characteristics.Get(want.Id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !calledGet {
 | 
				
			||||||
 | 
							t.Error("!calledGet")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !normalizeDeepEqual(want, got) {
 | 
				
			||||||
 | 
							t.Errorf("got %+v but wanted %+v", got, want)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristic_Create(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						calledPost := false
 | 
				
			||||||
 | 
						store.Characteristics.(*models.MockCharacteristicsService).Create_ = func(characteristic *models.Characteristic) (bool, error) {
 | 
				
			||||||
 | 
							if !normalizeDeepEqual(want, characteristic) {
 | 
				
			||||||
 | 
								t.Errorf("wanted request for characteristic %d but got %d", want, characteristic)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							calledPost = true
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						success, err := apiClient.Characteristics.Create(want)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !calledPost {
 | 
				
			||||||
 | 
							t.Error("!calledPost")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !success {
 | 
				
			||||||
 | 
							t.Error("!success")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristic_List(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := []*models.Characteristic{newCharacteristic()}
 | 
				
			||||||
 | 
						wantOpt := &models.CharacteristicListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						calledList := false
 | 
				
			||||||
 | 
						store.Characteristics.(*models.MockCharacteristicsService).List_ = func(opt *models.CharacteristicListOptions) ([]*models.Characteristic, error) {
 | 
				
			||||||
 | 
							if !normalizeDeepEqual(wantOpt, opt) {
 | 
				
			||||||
 | 
								t.Errorf("wanted options %d but got %d", wantOpt, opt)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							calledList = true
 | 
				
			||||||
 | 
							return want, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristics, err := apiClient.Characteristics.List(wantOpt)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !calledList {
 | 
				
			||||||
 | 
							t.Error("!calledList")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !normalizeDeepEqual(&want, &characteristics) {
 | 
				
			||||||
 | 
							t.Errorf("got characteristics %+v but wanted characteristics %+v", characteristics, want)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristic_Update(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						calledPut := false
 | 
				
			||||||
 | 
						store.Characteristics.(*models.MockCharacteristicsService).Update_ = func(id int64, characteristic *models.Characteristic) (bool, error) {
 | 
				
			||||||
 | 
							if id != want.Id {
 | 
				
			||||||
 | 
								t.Errorf("wanted request for characteristic %d but got %d", want.Id, id)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !normalizeDeepEqual(want, characteristic) {
 | 
				
			||||||
 | 
								t.Errorf("wanted request for characteristic %d but got %d", want, characteristic)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							calledPut = true
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						success, err := apiClient.Characteristics.Update(want.Id, want)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !calledPut {
 | 
				
			||||||
 | 
							t.Error("!calledPut")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !success {
 | 
				
			||||||
 | 
							t.Error("!success")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristic_Delete(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						calledDelete := false
 | 
				
			||||||
 | 
						store.Characteristics.(*models.MockCharacteristicsService).Delete_ = func(id int64) (bool, error) {
 | 
				
			||||||
 | 
							if id != want.Id {
 | 
				
			||||||
 | 
								t.Errorf("wanted request for characteristic %d but got %d", want.Id, id)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							calledDelete = true
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						success, err := apiClient.Characteristics.Delete(want.Id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !calledDelete {
 | 
				
			||||||
 | 
							t.Error("!calledDelete")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !success {
 | 
				
			||||||
 | 
							t.Error("!success")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -45,11 +45,11 @@ func Handler() *mux.Router {
 | 
				
			||||||
	m.Get(router.UpdateCharacteristicType).Handler(handler(serveUpdateCharacteristicType))
 | 
						m.Get(router.UpdateCharacteristicType).Handler(handler(serveUpdateCharacteristicType))
 | 
				
			||||||
	m.Get(router.DeleteCharacteristicType).Handler(handler(serveDeleteCharacteristicType))
 | 
						m.Get(router.DeleteCharacteristicType).Handler(handler(serveDeleteCharacteristicType))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m.Get(router.Observation).Handler(handler(serveObservation))
 | 
						m.Get(router.Characteristic).Handler(handler(serveCharacteristic))
 | 
				
			||||||
	m.Get(router.CreateObservation).Handler(handler(serveCreateObservation))
 | 
						m.Get(router.CreateCharacteristic).Handler(handler(serveCreateCharacteristic))
 | 
				
			||||||
	m.Get(router.Observations).Handler(handler(serveObservationList))
 | 
						m.Get(router.Characteristics).Handler(handler(serveCharacteristicList))
 | 
				
			||||||
	m.Get(router.UpdateObservation).Handler(handler(serveUpdateObservation))
 | 
						m.Get(router.UpdateCharacteristic).Handler(handler(serveUpdateCharacteristic))
 | 
				
			||||||
	m.Get(router.DeleteObservation).Handler(handler(serveDeleteObservation))
 | 
						m.Get(router.DeleteCharacteristic).Handler(handler(serveDeleteCharacteristic))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m.Get(router.TextMeasurementType).Handler(handler(serveTextMeasurementType))
 | 
						m.Get(router.TextMeasurementType).Handler(handler(serveTextMeasurementType))
 | 
				
			||||||
	m.Get(router.CreateTextMeasurementType).Handler(handler(serveCreateTextMeasurementType))
 | 
						m.Get(router.CreateTextMeasurementType).Handler(handler(serveCreateTextMeasurementType))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ func newMeasurement() *models.Measurement {
 | 
				
			||||||
	measurement := models.NewMeasurement()
 | 
						measurement := models.NewMeasurement()
 | 
				
			||||||
	measurement.Id = 1
 | 
						measurement.Id = 1
 | 
				
			||||||
	measurement.StrainId = 2
 | 
						measurement.StrainId = 2
 | 
				
			||||||
	measurement.ObservationId = 3
 | 
						measurement.CharacteristicId = 3
 | 
				
			||||||
	measurement.TextMeasurementTypeId = models.NullInt64{sql.NullInt64{Int64: 4, Valid: false}}
 | 
						measurement.TextMeasurementTypeId = models.NullInt64{sql.NullInt64{Int64: 4, Valid: false}}
 | 
				
			||||||
	measurement.UnitTypeId = models.NullInt64{sql.NullInt64{Int64: 5, Valid: true}}
 | 
						measurement.UnitTypeId = models.NullInt64{sql.NullInt64{Int64: 5, Valid: true}}
 | 
				
			||||||
	return measurement
 | 
						return measurement
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,92 +0,0 @@
 | 
				
			||||||
package api
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/gorilla/mux"
 | 
					 | 
				
			||||||
	"github.com/thermokarst/bactdb/models"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func serveObservation(w http.ResponseWriter, r *http.Request) error {
 | 
					 | 
				
			||||||
	id, err := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation, err := store.Observations.Get(id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return writeJSON(w, observation)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func serveCreateObservation(w http.ResponseWriter, r *http.Request) error {
 | 
					 | 
				
			||||||
	var observation models.Observation
 | 
					 | 
				
			||||||
	err := json.NewDecoder(r.Body).Decode(&observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	created, err := store.Observations.Create(&observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if created {
 | 
					 | 
				
			||||||
		w.WriteHeader(http.StatusCreated)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return writeJSON(w, observation)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func serveObservationList(w http.ResponseWriter, r *http.Request) error {
 | 
					 | 
				
			||||||
	var opt models.ObservationListOptions
 | 
					 | 
				
			||||||
	if err := schemaDecoder.Decode(&opt, r.URL.Query()); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observations, err := store.Observations.List(&opt)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if observations == nil {
 | 
					 | 
				
			||||||
		observations = []*models.Observation{}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return writeJSON(w, observations)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func serveUpdateObservation(w http.ResponseWriter, r *http.Request) error {
 | 
					 | 
				
			||||||
	id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
 | 
					 | 
				
			||||||
	var observation models.Observation
 | 
					 | 
				
			||||||
	err := json.NewDecoder(r.Body).Decode(&observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	updated, err := store.Observations.Update(id, &observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if updated {
 | 
					 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return writeJSON(w, observation)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func serveDeleteObservation(w http.ResponseWriter, r *http.Request) error {
 | 
					 | 
				
			||||||
	id, _ := strconv.ParseInt(mux.Vars(r)["Id"], 10, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	deleted, err := store.Observations.Delete(id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if deleted {
 | 
					 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return writeJSON(w, &models.Observation{})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,153 +0,0 @@
 | 
				
			||||||
package api
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/thermokarst/bactdb/models"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newObservation() *models.Observation {
 | 
					 | 
				
			||||||
	observation := models.NewObservation()
 | 
					 | 
				
			||||||
	return observation
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservation_Get(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	calledGet := false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	store.Observations.(*models.MockObservationsService).Get_ = func(id int64) (*models.Observation, error) {
 | 
					 | 
				
			||||||
		if id != want.Id {
 | 
					 | 
				
			||||||
			t.Errorf("wanted request for observation %d but got %d", want.Id, id)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		calledGet = true
 | 
					 | 
				
			||||||
		return want, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	got, err := apiClient.Observations.Get(want.Id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !calledGet {
 | 
					 | 
				
			||||||
		t.Error("!calledGet")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !normalizeDeepEqual(want, got) {
 | 
					 | 
				
			||||||
		t.Errorf("got %+v but wanted %+v", got, want)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservation_Create(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	calledPost := false
 | 
					 | 
				
			||||||
	store.Observations.(*models.MockObservationsService).Create_ = func(observation *models.Observation) (bool, error) {
 | 
					 | 
				
			||||||
		if !normalizeDeepEqual(want, observation) {
 | 
					 | 
				
			||||||
			t.Errorf("wanted request for observation %d but got %d", want, observation)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		calledPost = true
 | 
					 | 
				
			||||||
		return true, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	success, err := apiClient.Observations.Create(want)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !calledPost {
 | 
					 | 
				
			||||||
		t.Error("!calledPost")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !success {
 | 
					 | 
				
			||||||
		t.Error("!success")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservation_List(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := []*models.Observation{newObservation()}
 | 
					 | 
				
			||||||
	wantOpt := &models.ObservationListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	calledList := false
 | 
					 | 
				
			||||||
	store.Observations.(*models.MockObservationsService).List_ = func(opt *models.ObservationListOptions) ([]*models.Observation, error) {
 | 
					 | 
				
			||||||
		if !normalizeDeepEqual(wantOpt, opt) {
 | 
					 | 
				
			||||||
			t.Errorf("wanted options %d but got %d", wantOpt, opt)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		calledList = true
 | 
					 | 
				
			||||||
		return want, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observations, err := apiClient.Observations.List(wantOpt)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !calledList {
 | 
					 | 
				
			||||||
		t.Error("!calledList")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !normalizeDeepEqual(&want, &observations) {
 | 
					 | 
				
			||||||
		t.Errorf("got observations %+v but wanted observations %+v", observations, want)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservation_Update(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	calledPut := false
 | 
					 | 
				
			||||||
	store.Observations.(*models.MockObservationsService).Update_ = func(id int64, observation *models.Observation) (bool, error) {
 | 
					 | 
				
			||||||
		if id != want.Id {
 | 
					 | 
				
			||||||
			t.Errorf("wanted request for observation %d but got %d", want.Id, id)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if !normalizeDeepEqual(want, observation) {
 | 
					 | 
				
			||||||
			t.Errorf("wanted request for observation %d but got %d", want, observation)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		calledPut = true
 | 
					 | 
				
			||||||
		return true, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	success, err := apiClient.Observations.Update(want.Id, want)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !calledPut {
 | 
					 | 
				
			||||||
		t.Error("!calledPut")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !success {
 | 
					 | 
				
			||||||
		t.Error("!success")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservation_Delete(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	calledDelete := false
 | 
					 | 
				
			||||||
	store.Observations.(*models.MockObservationsService).Delete_ = func(id int64) (bool, error) {
 | 
					 | 
				
			||||||
		if id != want.Id {
 | 
					 | 
				
			||||||
			t.Errorf("wanted request for observation %d but got %d", want.Id, id)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		calledDelete = true
 | 
					 | 
				
			||||||
		return true, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	success, err := apiClient.Observations.Delete(want.Id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !calledDelete {
 | 
					 | 
				
			||||||
		t.Error("!calledDelete")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !success {
 | 
					 | 
				
			||||||
		t.Error("!success")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,7 @@ func insertCharacteristicType(t *testing.T, tx *modl.Transaction) *models.Charac
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newCharacteristicType(t *testing.T, tx *modl.Transaction) *models.CharacteristicType {
 | 
					func newCharacteristicType(t *testing.T, tx *modl.Transaction) *models.CharacteristicType {
 | 
				
			||||||
	return &models.CharacteristicType{CharacteristicTypeName: "Test Obs"}
 | 
						return &models.CharacteristicType{CharacteristicTypeName: "Test Char"}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCharacteristicTypesStore_Get_db(t *testing.T) {
 | 
					func TestCharacteristicTypesStore_Get_db(t *testing.T) {
 | 
				
			||||||
| 
						 | 
					@ -95,7 +95,7 @@ func TestCharacteristicTypesStore_Update_db(t *testing.T) {
 | 
				
			||||||
	d := NewDatastore(tx)
 | 
						d := NewDatastore(tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Tweak it
 | 
						// Tweak it
 | 
				
			||||||
	characteristic_type.CharacteristicTypeName = "Updated Obs Type"
 | 
						characteristic_type.CharacteristicTypeName = "Updated Char Type"
 | 
				
			||||||
	updated, err := d.CharacteristicTypes.Update(characteristic_type.Id, characteristic_type)
 | 
						updated, err := d.CharacteristicTypes.Update(characteristic_type.Id, characteristic_type)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										87
									
								
								datastore/characteristics.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								datastore/characteristics.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					package datastore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/thermokarst/bactdb/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						DB.AddTableWithName(models.Characteristic{}, "characteristics").SetKeys(true, "Id")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type characteristicsStore struct {
 | 
				
			||||||
 | 
						*Datastore
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsStore) Get(id int64) (*models.Characteristic, error) {
 | 
				
			||||||
 | 
						var characteristic []*models.Characteristic
 | 
				
			||||||
 | 
						if err := s.dbh.Select(&characteristic, `SELECT * FROM characteristics WHERE id=$1;`, id); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(characteristic) == 0 {
 | 
				
			||||||
 | 
							return nil, models.ErrCharacteristicNotFound
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return characteristic[0], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsStore) Create(characteristic *models.Characteristic) (bool, error) {
 | 
				
			||||||
 | 
						currentTime := time.Now()
 | 
				
			||||||
 | 
						characteristic.CreatedAt = currentTime
 | 
				
			||||||
 | 
						characteristic.UpdatedAt = currentTime
 | 
				
			||||||
 | 
						if err := s.dbh.Insert(characteristic); err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsStore) List(opt *models.CharacteristicListOptions) ([]*models.Characteristic, error) {
 | 
				
			||||||
 | 
						if opt == nil {
 | 
				
			||||||
 | 
							opt = &models.CharacteristicListOptions{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var characteristics []*models.Characteristic
 | 
				
			||||||
 | 
						err := s.dbh.Select(&characteristics, `SELECT * FROM characteristics LIMIT $1 OFFSET $2;`, opt.PerPageOrDefault(), opt.Offset())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return characteristics, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsStore) Update(id int64, characteristic *models.Characteristic) (bool, error) {
 | 
				
			||||||
 | 
						_, err := s.Get(id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if id != characteristic.Id {
 | 
				
			||||||
 | 
							return false, models.ErrCharacteristicNotFound
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic.UpdatedAt = time.Now()
 | 
				
			||||||
 | 
						changed, err := s.dbh.Update(characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if changed == 0 {
 | 
				
			||||||
 | 
							return false, ErrNoRowsUpdated
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsStore) Delete(id int64) (bool, error) {
 | 
				
			||||||
 | 
						characteristic, err := s.Get(id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						deleted, err := s.dbh.Delete(characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if deleted == 0 {
 | 
				
			||||||
 | 
							return false, ErrNoRowsDeleted
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										129
									
								
								datastore/characteristics_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								datastore/characteristics_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,129 @@
 | 
				
			||||||
 | 
					package datastore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/jmoiron/modl"
 | 
				
			||||||
 | 
						"github.com/thermokarst/bactdb/models"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func insertCharacteristic(t *testing.T, tx *modl.Transaction) *models.Characteristic {
 | 
				
			||||||
 | 
						// clean up our target table
 | 
				
			||||||
 | 
						tx.Exec(`DELETE FROM characteristics;`)
 | 
				
			||||||
 | 
						characteristic := newCharacteristic(t, tx)
 | 
				
			||||||
 | 
						if err := tx.Insert(characteristic); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return characteristic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newCharacteristic(t *testing.T, tx *modl.Transaction) *models.Characteristic {
 | 
				
			||||||
 | 
						// we want to create and insert an characteristic type record, too.
 | 
				
			||||||
 | 
						characteristic_type := insertCharacteristicType(t, tx)
 | 
				
			||||||
 | 
						return &models.Characteristic{CharacteristicName: "Test Characteristic",
 | 
				
			||||||
 | 
							CharacteristicTypeId: characteristic_type.Id}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicsStore_Get_db(t *testing.T) {
 | 
				
			||||||
 | 
						tx, _ := DB.Begin()
 | 
				
			||||||
 | 
						defer tx.Rollback()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := insertCharacteristic(t, tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d := NewDatastore(tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic, err := d.Characteristics.Get(want.Id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
 | 
				
			||||||
 | 
						normalizeTime(&characteristic.CreatedAt, &characteristic.UpdatedAt, &characteristic.DeletedAt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(characteristic, want) {
 | 
				
			||||||
 | 
							t.Errorf("got characteristic %+v, want %+v", characteristic, want)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicsStore_Create_db(t *testing.T) {
 | 
				
			||||||
 | 
						tx, _ := DB.Begin()
 | 
				
			||||||
 | 
						defer tx.Rollback()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic := newCharacteristic(t, tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d := NewDatastore(tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						created, err := d.Characteristics.Create(characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !created {
 | 
				
			||||||
 | 
							t.Error("!created")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if characteristic.Id == 0 {
 | 
				
			||||||
 | 
							t.Error("want nonzero characteristic.Id after submitting")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicsStore_List_db(t *testing.T) {
 | 
				
			||||||
 | 
						tx, _ := DB.Begin()
 | 
				
			||||||
 | 
						defer tx.Rollback()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want_characteristic := insertCharacteristic(t, tx)
 | 
				
			||||||
 | 
						want := []*models.Characteristic{want_characteristic}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d := NewDatastore(tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristics, err := d.Characteristics.List(&models.CharacteristicListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := range want {
 | 
				
			||||||
 | 
							normalizeTime(&want[i].CreatedAt, &want[i].UpdatedAt, &want[i].DeletedAt)
 | 
				
			||||||
 | 
							normalizeTime(&characteristics[i].CreatedAt, &characteristics[i].UpdatedAt, &characteristics[i].DeletedAt)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(characteristics, want) {
 | 
				
			||||||
 | 
							t.Errorf("got characteristics %+v, want %+v", characteristics, want)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicsStore_Update_db(t *testing.T) {
 | 
				
			||||||
 | 
						tx, _ := DB.Begin()
 | 
				
			||||||
 | 
						defer tx.Rollback()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic := insertCharacteristic(t, tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d := NewDatastore(tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Tweak it
 | 
				
			||||||
 | 
						characteristic.CharacteristicName = "Updated Char"
 | 
				
			||||||
 | 
						updated, err := d.Characteristics.Update(characteristic.Id, characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !updated {
 | 
				
			||||||
 | 
							t.Error("!updated")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicsStore_Delete_db(t *testing.T) {
 | 
				
			||||||
 | 
						tx, _ := DB.Begin()
 | 
				
			||||||
 | 
						defer tx.Rollback()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic := insertCharacteristic(t, tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d := NewDatastore(tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Delete it
 | 
				
			||||||
 | 
						deleted, err := d.Characteristics.Delete(characteristic.Id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !deleted {
 | 
				
			||||||
 | 
							t.Error("!delete")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ type Datastore struct {
 | 
				
			||||||
	Species              models.SpeciesService
 | 
						Species              models.SpeciesService
 | 
				
			||||||
	Strains              models.StrainsService
 | 
						Strains              models.StrainsService
 | 
				
			||||||
	CharacteristicTypes  models.CharacteristicTypesService
 | 
						CharacteristicTypes  models.CharacteristicTypesService
 | 
				
			||||||
	Observations         models.ObservationsService
 | 
						Characteristics      models.CharacteristicsService
 | 
				
			||||||
	TextMeasurementTypes models.TextMeasurementTypesService
 | 
						TextMeasurementTypes models.TextMeasurementTypesService
 | 
				
			||||||
	UnitTypes            models.UnitTypesService
 | 
						UnitTypes            models.UnitTypesService
 | 
				
			||||||
	Measurements         models.MeasurementsService
 | 
						Measurements         models.MeasurementsService
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ func NewDatastore(dbh modl.SqlExecutor) *Datastore {
 | 
				
			||||||
	d.Species = &speciesStore{d}
 | 
						d.Species = &speciesStore{d}
 | 
				
			||||||
	d.Strains = &strainsStore{d}
 | 
						d.Strains = &strainsStore{d}
 | 
				
			||||||
	d.CharacteristicTypes = &characteristicTypesStore{d}
 | 
						d.CharacteristicTypes = &characteristicTypesStore{d}
 | 
				
			||||||
	d.Observations = &observationsStore{d}
 | 
						d.Characteristics = &characteristicsStore{d}
 | 
				
			||||||
	d.TextMeasurementTypes = &textMeasurementTypesStore{d}
 | 
						d.TextMeasurementTypes = &textMeasurementTypesStore{d}
 | 
				
			||||||
	d.UnitTypes = &unitTypesStore{d}
 | 
						d.UnitTypes = &unitTypesStore{d}
 | 
				
			||||||
	d.Measurements = &measurementsStore{d}
 | 
						d.Measurements = &measurementsStore{d}
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@ func NewMockDatastore() *Datastore {
 | 
				
			||||||
		Species:              &models.MockSpeciesService{},
 | 
							Species:              &models.MockSpeciesService{},
 | 
				
			||||||
		Strains:              &models.MockStrainsService{},
 | 
							Strains:              &models.MockStrainsService{},
 | 
				
			||||||
		CharacteristicTypes:  &models.MockCharacteristicTypesService{},
 | 
							CharacteristicTypes:  &models.MockCharacteristicTypesService{},
 | 
				
			||||||
		Observations:         &models.MockObservationsService{},
 | 
							Characteristics:      &models.MockCharacteristicsService{},
 | 
				
			||||||
		TextMeasurementTypes: &models.MockTextMeasurementTypesService{},
 | 
							TextMeasurementTypes: &models.MockTextMeasurementTypesService{},
 | 
				
			||||||
		UnitTypes:            &models.MockUnitTypesService{},
 | 
							UnitTypes:            &models.MockUnitTypesService{},
 | 
				
			||||||
		Measurements:         &models.MockMeasurementsService{},
 | 
							Measurements:         &models.MockMeasurementsService{},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,14 +22,14 @@ func insertMeasurement(t *testing.T, tx *modl.Transaction) *models.Measurement {
 | 
				
			||||||
func newMeasurement(t *testing.T, tx *modl.Transaction) *models.Measurement {
 | 
					func newMeasurement(t *testing.T, tx *modl.Transaction) *models.Measurement {
 | 
				
			||||||
	// we have a few things to take care of first...
 | 
						// we have a few things to take care of first...
 | 
				
			||||||
	strain := insertStrain(t, tx)
 | 
						strain := insertStrain(t, tx)
 | 
				
			||||||
	observation := insertObservation(t, tx)
 | 
						characteristic := insertCharacteristic(t, tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// we want to create and insert a unit type record, too.
 | 
						// we want to create and insert a unit type record, too.
 | 
				
			||||||
	unit_type := insertUnitType(t, tx)
 | 
						unit_type := insertUnitType(t, tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &models.Measurement{
 | 
						return &models.Measurement{
 | 
				
			||||||
		StrainId:         strain.Id,
 | 
							StrainId:         strain.Id,
 | 
				
			||||||
		ObservationId: observation.Id,
 | 
							CharacteristicId: characteristic.Id,
 | 
				
			||||||
		NumValue:         models.NullFloat64{sql.NullFloat64{Float64: 1.23, Valid: true}},
 | 
							NumValue:         models.NullFloat64{sql.NullFloat64{Float64: 1.23, Valid: true}},
 | 
				
			||||||
		UnitTypeId:       models.NullInt64{sql.NullInt64{Int64: unit_type.Id, Valid: true}},
 | 
							UnitTypeId:       models.NullInt64{sql.NullInt64{Int64: unit_type.Id, Valid: true}},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
-- bactdb
 | 
					-- bactdb
 | 
				
			||||||
-- Matthew R Dillon
 | 
					-- Matthew R Dillon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DROP TABLE observations;
 | 
					DROP TABLE characteristics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,18 +1,18 @@
 | 
				
			||||||
-- bactdb
 | 
					-- bactdb
 | 
				
			||||||
-- Matthew R Dillon
 | 
					-- Matthew R Dillon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE TABLE observations (
 | 
					CREATE TABLE characteristics (
 | 
				
			||||||
    id BIGSERIAL NOT NULL,
 | 
					    id BIGSERIAL NOT NULL,
 | 
				
			||||||
    observation_name CHARACTER VARYING(100) NOT NULL,
 | 
					    characteristic_name CHARACTER VARYING(100) NOT NULL,
 | 
				
			||||||
    characteristic_type_id BIGINT NOT NULL,
 | 
					    characteristic_type_id BIGINT NOT NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    created_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
					    created_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
				
			||||||
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
					    updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
				
			||||||
    deleted_at TIMESTAMP WITH TIME ZONE NULL,
 | 
					    deleted_at TIMESTAMP WITH TIME ZONE NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CONSTRAINT observations_pkey PRIMARY KEY (id),
 | 
					    CONSTRAINT characteristics_pkey PRIMARY KEY (id),
 | 
				
			||||||
    FOREIGN KEY (characteristic_type_id) REFERENCES characteristic_types(id)
 | 
					    FOREIGN KEY (characteristic_type_id) REFERENCES characteristic_types(id)
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE INDEX characteristic_type_id_idx ON observations (characteristic_type_id);
 | 
					CREATE INDEX characteristic_type_id_idx ON characteristics (characteristic_type_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
CREATE TABLE measurements (
 | 
					CREATE TABLE measurements (
 | 
				
			||||||
    id BIGSERIAL NOT NULL,
 | 
					    id BIGSERIAL NOT NULL,
 | 
				
			||||||
    strain_id BIGINT NOT NULL,
 | 
					    strain_id BIGINT NOT NULL,
 | 
				
			||||||
    observation_id BIGINT NOT NULL,
 | 
					    characteristic_id BIGINT NOT NULL,
 | 
				
			||||||
    text_measurement_type_id BIGINT NULL,
 | 
					    text_measurement_type_id BIGINT NULL,
 | 
				
			||||||
    txt_value CHARACTER VARYING(255) NULL,
 | 
					    txt_value CHARACTER VARYING(255) NULL,
 | 
				
			||||||
    num_value NUMERIC(8, 3) NULL,
 | 
					    num_value NUMERIC(8, 3) NULL,
 | 
				
			||||||
| 
						 | 
					@ -16,9 +16,9 @@ CREATE TABLE measurements (
 | 
				
			||||||
    created_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
					    created_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
				
			||||||
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
					    updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CONSTRAINT strainsobsmeasurements_pkey PRIMARY KEY (id),
 | 
					    CONSTRAINT strainscharmeasurements_pkey PRIMARY KEY (id),
 | 
				
			||||||
    FOREIGN KEY (strain_id) REFERENCES strains(id),
 | 
					    FOREIGN KEY (strain_id) REFERENCES strains(id),
 | 
				
			||||||
    FOREIGN KEY (observation_id) REFERENCES observations(id),
 | 
					    FOREIGN KEY (characteristic_id) REFERENCES characteristics(id),
 | 
				
			||||||
    FOREIGN KEY (text_measurement_type_id) REFERENCES text_measurement_types(id),
 | 
					    FOREIGN KEY (text_measurement_type_id) REFERENCES text_measurement_types(id),
 | 
				
			||||||
    FOREIGN KEY (unit_type_id) REFERENCES unit_types(id),
 | 
					    FOREIGN KEY (unit_type_id) REFERENCES unit_types(id),
 | 
				
			||||||
    FOREIGN KEY (test_method_id) REFERENCES test_methods(id),
 | 
					    FOREIGN KEY (test_method_id) REFERENCES test_methods(id),
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ CREATE TABLE measurements (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE INDEX strain_id_idx ON measurements (strain_id);
 | 
					CREATE INDEX strain_id_idx ON measurements (strain_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE INDEX observation_id_idx ON measurements (observation_id);
 | 
					CREATE INDEX characteristic_id_idx ON measurements (characteristic_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE INDEX text_measurement_type_id_idx ON measurements (text_measurement_type_id);
 | 
					CREATE INDEX text_measurement_type_id_idx ON measurements (text_measurement_type_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,87 +0,0 @@
 | 
				
			||||||
package datastore
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/thermokarst/bactdb/models"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	DB.AddTableWithName(models.Observation{}, "observations").SetKeys(true, "Id")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type observationsStore struct {
 | 
					 | 
				
			||||||
	*Datastore
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsStore) Get(id int64) (*models.Observation, error) {
 | 
					 | 
				
			||||||
	var observation []*models.Observation
 | 
					 | 
				
			||||||
	if err := s.dbh.Select(&observation, `SELECT * FROM observations WHERE id=$1;`, id); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(observation) == 0 {
 | 
					 | 
				
			||||||
		return nil, models.ErrObservationNotFound
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return observation[0], nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsStore) Create(observation *models.Observation) (bool, error) {
 | 
					 | 
				
			||||||
	currentTime := time.Now()
 | 
					 | 
				
			||||||
	observation.CreatedAt = currentTime
 | 
					 | 
				
			||||||
	observation.UpdatedAt = currentTime
 | 
					 | 
				
			||||||
	if err := s.dbh.Insert(observation); err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsStore) List(opt *models.ObservationListOptions) ([]*models.Observation, error) {
 | 
					 | 
				
			||||||
	if opt == nil {
 | 
					 | 
				
			||||||
		opt = &models.ObservationListOptions{}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var observations []*models.Observation
 | 
					 | 
				
			||||||
	err := s.dbh.Select(&observations, `SELECT * FROM observations LIMIT $1 OFFSET $2;`, opt.PerPageOrDefault(), opt.Offset())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return observations, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsStore) Update(id int64, observation *models.Observation) (bool, error) {
 | 
					 | 
				
			||||||
	_, err := s.Get(id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if id != observation.Id {
 | 
					 | 
				
			||||||
		return false, models.ErrObservationNotFound
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation.UpdatedAt = time.Now()
 | 
					 | 
				
			||||||
	changed, err := s.dbh.Update(observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if changed == 0 {
 | 
					 | 
				
			||||||
		return false, ErrNoRowsUpdated
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsStore) Delete(id int64) (bool, error) {
 | 
					 | 
				
			||||||
	observation, err := s.Get(id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	deleted, err := s.dbh.Delete(observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if deleted == 0 {
 | 
					 | 
				
			||||||
		return false, ErrNoRowsDeleted
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,129 +0,0 @@
 | 
				
			||||||
package datastore
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"reflect"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/jmoiron/modl"
 | 
					 | 
				
			||||||
	"github.com/thermokarst/bactdb/models"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func insertObservation(t *testing.T, tx *modl.Transaction) *models.Observation {
 | 
					 | 
				
			||||||
	// clean up our target table
 | 
					 | 
				
			||||||
	tx.Exec(`DELETE FROM observations;`)
 | 
					 | 
				
			||||||
	observation := newObservation(t, tx)
 | 
					 | 
				
			||||||
	if err := tx.Insert(observation); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return observation
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newObservation(t *testing.T, tx *modl.Transaction) *models.Observation {
 | 
					 | 
				
			||||||
	// we want to create and insert an characteristic type record, too.
 | 
					 | 
				
			||||||
	characteristic_type := insertCharacteristicType(t, tx)
 | 
					 | 
				
			||||||
	return &models.Observation{ObservationName: "Test Observation",
 | 
					 | 
				
			||||||
		CharacteristicTypeId: characteristic_type.Id}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationsStore_Get_db(t *testing.T) {
 | 
					 | 
				
			||||||
	tx, _ := DB.Begin()
 | 
					 | 
				
			||||||
	defer tx.Rollback()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := insertObservation(t, tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d := NewDatastore(tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation, err := d.Observations.Get(want.Id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
 | 
					 | 
				
			||||||
	normalizeTime(&observation.CreatedAt, &observation.UpdatedAt, &observation.DeletedAt)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !reflect.DeepEqual(observation, want) {
 | 
					 | 
				
			||||||
		t.Errorf("got observation %+v, want %+v", observation, want)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationsStore_Create_db(t *testing.T) {
 | 
					 | 
				
			||||||
	tx, _ := DB.Begin()
 | 
					 | 
				
			||||||
	defer tx.Rollback()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation := newObservation(t, tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d := NewDatastore(tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	created, err := d.Observations.Create(observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !created {
 | 
					 | 
				
			||||||
		t.Error("!created")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if observation.Id == 0 {
 | 
					 | 
				
			||||||
		t.Error("want nonzero observation.Id after submitting")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationsStore_List_db(t *testing.T) {
 | 
					 | 
				
			||||||
	tx, _ := DB.Begin()
 | 
					 | 
				
			||||||
	defer tx.Rollback()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want_observation := insertObservation(t, tx)
 | 
					 | 
				
			||||||
	want := []*models.Observation{want_observation}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d := NewDatastore(tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observations, err := d.Observations.List(&models.ObservationListOptions{ListOptions: models.ListOptions{Page: 1, PerPage: 10}})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for i := range want {
 | 
					 | 
				
			||||||
		normalizeTime(&want[i].CreatedAt, &want[i].UpdatedAt, &want[i].DeletedAt)
 | 
					 | 
				
			||||||
		normalizeTime(&observations[i].CreatedAt, &observations[i].UpdatedAt, &observations[i].DeletedAt)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !reflect.DeepEqual(observations, want) {
 | 
					 | 
				
			||||||
		t.Errorf("got observations %+v, want %+v", observations, want)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationsStore_Update_db(t *testing.T) {
 | 
					 | 
				
			||||||
	tx, _ := DB.Begin()
 | 
					 | 
				
			||||||
	defer tx.Rollback()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation := insertObservation(t, tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d := NewDatastore(tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Tweak it
 | 
					 | 
				
			||||||
	observation.ObservationName = "Updated Obs"
 | 
					 | 
				
			||||||
	updated, err := d.Observations.Update(observation.Id, observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !updated {
 | 
					 | 
				
			||||||
		t.Error("!updated")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationsStore_Delete_db(t *testing.T) {
 | 
					 | 
				
			||||||
	tx, _ := DB.Begin()
 | 
					 | 
				
			||||||
	defer tx.Rollback()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation := insertObservation(t, tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d := NewDatastore(tx)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Delete it
 | 
					 | 
				
			||||||
	deleted, err := d.Observations.Delete(observation.Id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !deleted {
 | 
					 | 
				
			||||||
		t.Error("!delete")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ type CharacteristicType struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewCharacteristicType() *CharacteristicType {
 | 
					func NewCharacteristicType() *CharacteristicType {
 | 
				
			||||||
	return &CharacteristicType{
 | 
						return &CharacteristicType{
 | 
				
			||||||
		CharacteristicTypeName: "Test Obs Type",
 | 
							CharacteristicTypeName: "Test Char Type",
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,7 @@ func TestCharacteristicTypeService_Create(t *testing.T) {
 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.CreateCharacteristicType, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
						mux.HandleFunc(urlPath(t, router.CreateCharacteristicType, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		called = true
 | 
							called = true
 | 
				
			||||||
		testMethod(t, r, "POST")
 | 
							testMethod(t, r, "POST")
 | 
				
			||||||
		testBody(t, r, `{"id":1,"characteristicTypeName":"Test Obs Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
							testBody(t, r, `{"id":1,"characteristicTypeName":"Test Char Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		w.WriteHeader(http.StatusCreated)
 | 
							w.WriteHeader(http.StatusCreated)
 | 
				
			||||||
		writeJSON(w, want)
 | 
							writeJSON(w, want)
 | 
				
			||||||
| 
						 | 
					@ -123,13 +123,13 @@ func TestCharacteristicTypeService_Update(t *testing.T) {
 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.UpdateCharacteristicType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
						mux.HandleFunc(urlPath(t, router.UpdateCharacteristicType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		called = true
 | 
							called = true
 | 
				
			||||||
		testMethod(t, r, "PUT")
 | 
							testMethod(t, r, "PUT")
 | 
				
			||||||
		testBody(t, r, `{"id":1,"characteristicTypeName":"Test Obs Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
							testBody(t, r, `{"id":1,"characteristicTypeName":"Test Char Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
		writeJSON(w, want)
 | 
							writeJSON(w, want)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	characteristic_type := newCharacteristicType()
 | 
						characteristic_type := newCharacteristicType()
 | 
				
			||||||
	characteristic_type.CharacteristicTypeName = "Test Obs Type Updated"
 | 
						characteristic_type.CharacteristicTypeName = "Test Char Type Updated"
 | 
				
			||||||
	updated, err := client.CharacteristicTypes.Update(characteristic_type.Id, characteristic_type)
 | 
						updated, err := client.CharacteristicTypes.Update(characteristic_type.Id, characteristic_type)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Errorf("CharacteristicTypes.Update returned error: %v", err)
 | 
							t.Errorf("CharacteristicTypes.Update returned error: %v", err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										204
									
								
								models/characteristics.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								models/characteristics.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,204 @@
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/thermokarst/bactdb/router"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A Characteristic is a lookup type
 | 
				
			||||||
 | 
					type Characteristic struct {
 | 
				
			||||||
 | 
						Id                   int64     `json:"id,omitempty"`
 | 
				
			||||||
 | 
						CharacteristicName   string    `db:"characteristic_name" json:"characteristicName"`
 | 
				
			||||||
 | 
						CharacteristicTypeId int64     `db:"characteristic_type_id" json:"characteristicTypeId"`
 | 
				
			||||||
 | 
						CreatedAt            time.Time `db:"created_at" json:"createdAt"`
 | 
				
			||||||
 | 
						UpdatedAt            time.Time `db:"updated_at" json:"updatedAt"`
 | 
				
			||||||
 | 
						DeletedAt            NullTime  `db:"deleted_at" json:"deletedAt"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewCharacteristic() *Characteristic {
 | 
				
			||||||
 | 
						return &Characteristic{
 | 
				
			||||||
 | 
							CharacteristicName: "Test Characteristic",
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CharacteristicsService interface {
 | 
				
			||||||
 | 
						// Get an characteristic
 | 
				
			||||||
 | 
						Get(id int64) (*Characteristic, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// List all characteristics
 | 
				
			||||||
 | 
						List(opt *CharacteristicListOptions) ([]*Characteristic, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create an characteristic
 | 
				
			||||||
 | 
						Create(characteristic *Characteristic) (bool, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Update an characteristic
 | 
				
			||||||
 | 
						Update(id int64, Characteristic *Characteristic) (updated bool, err error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Delete an characteristic
 | 
				
			||||||
 | 
						Delete(id int64) (deleted bool, err error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						ErrCharacteristicNotFound = errors.New("characteristic not found")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type characteristicsService struct {
 | 
				
			||||||
 | 
						client *Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsService) Get(id int64) (*Characteristic, error) {
 | 
				
			||||||
 | 
						strId := strconv.FormatInt(id, 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						url, err := s.client.url(router.Characteristic, 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 characteristic *Characteristic
 | 
				
			||||||
 | 
						_, err = s.client.Do(req, &characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return characteristic, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsService) Create(characteristic *Characteristic) (bool, error) {
 | 
				
			||||||
 | 
						url, err := s.client.url(router.CreateCharacteristic, nil, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req, err := s.client.NewRequest("POST", url.String(), characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := s.client.Do(req, &characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp.StatusCode == http.StatusCreated, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CharacteristicListOptions struct {
 | 
				
			||||||
 | 
						ListOptions
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsService) List(opt *CharacteristicListOptions) ([]*Characteristic, error) {
 | 
				
			||||||
 | 
						url, err := s.client.url(router.Characteristics, nil, opt)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req, err := s.client.NewRequest("GET", url.String(), nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var characteristics []*Characteristic
 | 
				
			||||||
 | 
						_, err = s.client.Do(req, &characteristics)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return characteristics, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsService) Update(id int64, characteristic *Characteristic) (bool, error) {
 | 
				
			||||||
 | 
						strId := strconv.FormatInt(id, 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						url, err := s.client.url(router.UpdateCharacteristic, map[string]string{"Id": strId}, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req, err := s.client.NewRequest("PUT", url.String(), characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := s.client.Do(req, &characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp.StatusCode == http.StatusOK, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *characteristicsService) Delete(id int64) (bool, error) {
 | 
				
			||||||
 | 
						strId := strconv.FormatInt(id, 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						url, err := s.client.url(router.DeleteCharacteristic, map[string]string{"Id": strId}, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req, err := s.client.NewRequest("DELETE", url.String(), nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var characteristic *Characteristic
 | 
				
			||||||
 | 
						resp, err := s.client.Do(req, &characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp.StatusCode == http.StatusOK, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MockCharacteristicsService struct {
 | 
				
			||||||
 | 
						Get_    func(id int64) (*Characteristic, error)
 | 
				
			||||||
 | 
						List_   func(opt *CharacteristicListOptions) ([]*Characteristic, error)
 | 
				
			||||||
 | 
						Create_ func(characteristic *Characteristic) (bool, error)
 | 
				
			||||||
 | 
						Update_ func(id int64, characteristic *Characteristic) (bool, error)
 | 
				
			||||||
 | 
						Delete_ func(id int64) (bool, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ CharacteristicsService = &MockCharacteristicsService{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *MockCharacteristicsService) Get(id int64) (*Characteristic, error) {
 | 
				
			||||||
 | 
						if s.Get_ == nil {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s.Get_(id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *MockCharacteristicsService) Create(characteristic *Characteristic) (bool, error) {
 | 
				
			||||||
 | 
						if s.Create_ == nil {
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s.Create_(characteristic)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *MockCharacteristicsService) List(opt *CharacteristicListOptions) ([]*Characteristic, error) {
 | 
				
			||||||
 | 
						if s.List_ == nil {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s.List_(opt)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *MockCharacteristicsService) Update(id int64, characteristic *Characteristic) (bool, error) {
 | 
				
			||||||
 | 
						if s.Update_ == nil {
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s.Update_(id, characteristic)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *MockCharacteristicsService) Delete(id int64) (bool, error) {
 | 
				
			||||||
 | 
						if s.Delete_ == nil {
 | 
				
			||||||
 | 
							return false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s.Delete_(id)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										174
									
								
								models/characteristics_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								models/characteristics_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,174 @@
 | 
				
			||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/thermokarst/bactdb/router"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newCharacteristic() *Characteristic {
 | 
				
			||||||
 | 
						characteristic := NewCharacteristic()
 | 
				
			||||||
 | 
						characteristic.Id = 1
 | 
				
			||||||
 | 
						return characteristic
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicService_Get(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
						defer teardown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var called bool
 | 
				
			||||||
 | 
						mux.HandleFunc(urlPath(t, router.Characteristic, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							called = true
 | 
				
			||||||
 | 
							testMethod(t, r, "GET")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							writeJSON(w, want)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic, err := client.Characteristics.Get(want.Id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.Get returned error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !called {
 | 
				
			||||||
 | 
							t.Fatal("!called")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(characteristic, want) {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.Get return %+v, want %+v", characteristic, want)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicService_Create(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
						defer teardown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var called bool
 | 
				
			||||||
 | 
						mux.HandleFunc(urlPath(t, router.CreateCharacteristic, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							called = true
 | 
				
			||||||
 | 
							testMethod(t, r, "POST")
 | 
				
			||||||
 | 
							testBody(t, r, `{"id":1,"characteristicName":"Test Characteristic","characteristicTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusCreated)
 | 
				
			||||||
 | 
							writeJSON(w, want)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic := newCharacteristic()
 | 
				
			||||||
 | 
						created, err := client.Characteristics.Create(characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.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(characteristic, want) {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.Create returned %+v, want %+v", characteristic, want)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicService_List(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
						defer teardown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := []*Characteristic{newCharacteristic()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var called bool
 | 
				
			||||||
 | 
						mux.HandleFunc(urlPath(t, router.Characteristics, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							called = true
 | 
				
			||||||
 | 
							testMethod(t, r, "GET")
 | 
				
			||||||
 | 
							testFormValues(t, r, values{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							writeJSON(w, want)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristics, err := client.Characteristics.List(nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.List returned error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !called {
 | 
				
			||||||
 | 
							t.Fatal("!called")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, u := range want {
 | 
				
			||||||
 | 
							normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !reflect.DeepEqual(characteristics, want) {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.List return %+v, want %+v", characteristics, want)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicService_Update(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
						defer teardown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var called bool
 | 
				
			||||||
 | 
						mux.HandleFunc(urlPath(t, router.UpdateCharacteristic, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							called = true
 | 
				
			||||||
 | 
							testMethod(t, r, "PUT")
 | 
				
			||||||
 | 
							testBody(t, r, `{"id":1,"characteristicName":"Test Char Updated","characteristicTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
							writeJSON(w, want)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						characteristic := newCharacteristic()
 | 
				
			||||||
 | 
						characteristic.CharacteristicName = "Test Char Updated"
 | 
				
			||||||
 | 
						updated, err := client.Characteristics.Update(characteristic.Id, characteristic)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.Update returned error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !updated {
 | 
				
			||||||
 | 
							t.Error("!updated")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !called {
 | 
				
			||||||
 | 
							t.Fatal("!called")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCharacteristicService_Delete(t *testing.T) {
 | 
				
			||||||
 | 
						setup()
 | 
				
			||||||
 | 
						defer teardown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						want := newCharacteristic()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var called bool
 | 
				
			||||||
 | 
						mux.HandleFunc(urlPath(t, router.DeleteCharacteristic, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							called = true
 | 
				
			||||||
 | 
							testMethod(t, r, "DELETE")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
 | 
							writeJSON(w, want)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						deleted, err := client.Characteristics.Delete(want.Id)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("Characteristics.Delete returned error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !deleted {
 | 
				
			||||||
 | 
							t.Error("!deleted")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !called {
 | 
				
			||||||
 | 
							t.Fatal("!called")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ type Client struct {
 | 
				
			||||||
	Species              SpeciesService
 | 
						Species              SpeciesService
 | 
				
			||||||
	Strains              StrainsService
 | 
						Strains              StrainsService
 | 
				
			||||||
	CharacteristicTypes  CharacteristicTypesService
 | 
						CharacteristicTypes  CharacteristicTypesService
 | 
				
			||||||
	Observations         ObservationsService
 | 
						Characteristics      CharacteristicsService
 | 
				
			||||||
	TextMeasurementTypes TextMeasurementTypesService
 | 
						TextMeasurementTypes TextMeasurementTypesService
 | 
				
			||||||
	UnitTypes            UnitTypesService
 | 
						UnitTypes            UnitTypesService
 | 
				
			||||||
	Measurements         MeasurementsService
 | 
						Measurements         MeasurementsService
 | 
				
			||||||
| 
						 | 
					@ -57,7 +57,7 @@ func NewClient(httpClient *http.Client) *Client {
 | 
				
			||||||
	c.Species = &speciesService{c}
 | 
						c.Species = &speciesService{c}
 | 
				
			||||||
	c.Strains = &strainsService{c}
 | 
						c.Strains = &strainsService{c}
 | 
				
			||||||
	c.CharacteristicTypes = &characteristicTypesService{c}
 | 
						c.CharacteristicTypes = &characteristicTypesService{c}
 | 
				
			||||||
	c.Observations = &observationsService{c}
 | 
						c.Characteristics = &characteristicsService{c}
 | 
				
			||||||
	c.TextMeasurementTypes = &textMeasurementTypesService{c}
 | 
						c.TextMeasurementTypes = &textMeasurementTypesService{c}
 | 
				
			||||||
	c.UnitTypes = &unitTypesService{c}
 | 
						c.UnitTypes = &unitTypesService{c}
 | 
				
			||||||
	c.Measurements = &measurementsService{c}
 | 
						c.Measurements = &measurementsService{c}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,11 +13,11 @@ import (
 | 
				
			||||||
// A Measurement is the main data type for this application
 | 
					// A Measurement is the main data type for this application
 | 
				
			||||||
// There are two types of supported measurements: text & numerical. The table
 | 
					// There are two types of supported measurements: text & numerical. The table
 | 
				
			||||||
// has a constraint that will allow one or the other for a particular
 | 
					// has a constraint that will allow one or the other for a particular
 | 
				
			||||||
// combination of strain & observation, but not both.
 | 
					// combination of strain & characteristic, but not both.
 | 
				
			||||||
type Measurement struct {
 | 
					type Measurement struct {
 | 
				
			||||||
	Id                    int64       `json:"id,omitempty"`
 | 
						Id                    int64       `json:"id,omitempty"`
 | 
				
			||||||
	StrainId              int64       `db:"strain_id" json:"strainId"`
 | 
						StrainId              int64       `db:"strain_id" json:"strainId"`
 | 
				
			||||||
	ObservationId         int64       `db:"observation_id" json:"observationId"`
 | 
						CharacteristicId      int64       `db:"characteristic_id" json:"characteristicId"`
 | 
				
			||||||
	TextMeasurementTypeId NullInt64   `db:"text_measurement_type_id" json:"textMeasurementTypeId"`
 | 
						TextMeasurementTypeId NullInt64   `db:"text_measurement_type_id" json:"textMeasurementTypeId"`
 | 
				
			||||||
	TxtValue              NullString  `db:"txt_value" json:"txtValue"`
 | 
						TxtValue              NullString  `db:"txt_value" json:"txtValue"`
 | 
				
			||||||
	NumValue              NullFloat64 `db:"num_value" json:"numValue"`
 | 
						NumValue              NullFloat64 `db:"num_value" json:"numValue"`
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ func newMeasurement() *Measurement {
 | 
				
			||||||
	measurement := NewMeasurement()
 | 
						measurement := NewMeasurement()
 | 
				
			||||||
	measurement.Id = 1
 | 
						measurement.Id = 1
 | 
				
			||||||
	measurement.StrainId = 1
 | 
						measurement.StrainId = 1
 | 
				
			||||||
	measurement.ObservationId = 1
 | 
						measurement.CharacteristicId = 1
 | 
				
			||||||
	measurement.UnitTypeId = NullInt64{sql.NullInt64{Int64: 1, Valid: true}}
 | 
						measurement.UnitTypeId = NullInt64{sql.NullInt64{Int64: 1, Valid: true}}
 | 
				
			||||||
	return measurement
 | 
						return measurement
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,7 @@ func TestMeasurementService_Create(t *testing.T) {
 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.CreateMeasurement, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
						mux.HandleFunc(urlPath(t, router.CreateMeasurement, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		called = true
 | 
							called = true
 | 
				
			||||||
		testMethod(t, r, "POST")
 | 
							testMethod(t, r, "POST")
 | 
				
			||||||
		testBody(t, r, `{"id":1,"strainId":1,"observationId":1,"textMeasurementTypeId":null,"txtValue":null,"numValue":1.23,"confidenceInterval":null,"unitTypeId":1,"notes":null,"testMethodId":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`+"\n")
 | 
							testBody(t, r, `{"id":1,"strainId":1,"characteristicId":1,"textMeasurementTypeId":null,"txtValue":null,"numValue":1.23,"confidenceInterval":null,"unitTypeId":1,"notes":null,"testMethodId":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`+"\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		w.WriteHeader(http.StatusCreated)
 | 
							w.WriteHeader(http.StatusCreated)
 | 
				
			||||||
		writeJSON(w, want)
 | 
							writeJSON(w, want)
 | 
				
			||||||
| 
						 | 
					@ -127,7 +127,7 @@ func TestMeasurementService_Update(t *testing.T) {
 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.UpdateMeasurement, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
						mux.HandleFunc(urlPath(t, router.UpdateMeasurement, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		called = true
 | 
							called = true
 | 
				
			||||||
		testMethod(t, r, "PUT")
 | 
							testMethod(t, r, "PUT")
 | 
				
			||||||
		testBody(t, r, `{"id":1,"strainId":1,"observationId":1,"textMeasurementTypeId":null,"txtValue":null,"numValue":4.56,"confidenceInterval":null,"unitTypeId":1,"notes":null,"testMethodId":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`+"\n")
 | 
							testBody(t, r, `{"id":1,"strainId":1,"characteristicId":1,"textMeasurementTypeId":null,"txtValue":null,"numValue":4.56,"confidenceInterval":null,"unitTypeId":1,"notes":null,"testMethodId":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`+"\n")
 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
							w.WriteHeader(http.StatusOK)
 | 
				
			||||||
		writeJSON(w, want)
 | 
							writeJSON(w, want)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,204 +0,0 @@
 | 
				
			||||||
package models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/thermokarst/bactdb/router"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// An Observation is a lookup type
 | 
					 | 
				
			||||||
type Observation struct {
 | 
					 | 
				
			||||||
	Id                int64     `json:"id,omitempty"`
 | 
					 | 
				
			||||||
	ObservationName   string    `db:"observation_name" json:"observationName"`
 | 
					 | 
				
			||||||
	CharacteristicTypeId int64     `db:"characteristic_type_id" json:"characteristicTypeId"`
 | 
					 | 
				
			||||||
	CreatedAt         time.Time `db:"created_at" json:"createdAt"`
 | 
					 | 
				
			||||||
	UpdatedAt         time.Time `db:"updated_at" json:"updatedAt"`
 | 
					 | 
				
			||||||
	DeletedAt         NullTime  `db:"deleted_at" json:"deletedAt"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewObservation() *Observation {
 | 
					 | 
				
			||||||
	return &Observation{
 | 
					 | 
				
			||||||
		ObservationName: "Test Observation",
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ObservationsService interface {
 | 
					 | 
				
			||||||
	// Get an observation
 | 
					 | 
				
			||||||
	Get(id int64) (*Observation, error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// List all observations
 | 
					 | 
				
			||||||
	List(opt *ObservationListOptions) ([]*Observation, error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Create an observation
 | 
					 | 
				
			||||||
	Create(observation *Observation) (bool, error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Update an observation
 | 
					 | 
				
			||||||
	Update(id int64, Observation *Observation) (updated bool, err error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Delete an observation
 | 
					 | 
				
			||||||
	Delete(id int64) (deleted bool, err error)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	ErrObservationNotFound = errors.New("observation not found")
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type observationsService struct {
 | 
					 | 
				
			||||||
	client *Client
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsService) Get(id int64) (*Observation, error) {
 | 
					 | 
				
			||||||
	strId := strconv.FormatInt(id, 10)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	url, err := s.client.url(router.Observation, 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 observation *Observation
 | 
					 | 
				
			||||||
	_, err = s.client.Do(req, &observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return observation, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsService) Create(observation *Observation) (bool, error) {
 | 
					 | 
				
			||||||
	url, err := s.client.url(router.CreateObservation, nil, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req, err := s.client.NewRequest("POST", url.String(), observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	resp, err := s.client.Do(req, &observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return resp.StatusCode == http.StatusCreated, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ObservationListOptions struct {
 | 
					 | 
				
			||||||
	ListOptions
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsService) List(opt *ObservationListOptions) ([]*Observation, error) {
 | 
					 | 
				
			||||||
	url, err := s.client.url(router.Observations, nil, opt)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req, err := s.client.NewRequest("GET", url.String(), nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var observations []*Observation
 | 
					 | 
				
			||||||
	_, err = s.client.Do(req, &observations)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return observations, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsService) Update(id int64, observation *Observation) (bool, error) {
 | 
					 | 
				
			||||||
	strId := strconv.FormatInt(id, 10)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	url, err := s.client.url(router.UpdateObservation, map[string]string{"Id": strId}, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req, err := s.client.NewRequest("PUT", url.String(), observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	resp, err := s.client.Do(req, &observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return resp.StatusCode == http.StatusOK, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *observationsService) Delete(id int64) (bool, error) {
 | 
					 | 
				
			||||||
	strId := strconv.FormatInt(id, 10)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	url, err := s.client.url(router.DeleteObservation, map[string]string{"Id": strId}, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	req, err := s.client.NewRequest("DELETE", url.String(), nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var observation *Observation
 | 
					 | 
				
			||||||
	resp, err := s.client.Do(req, &observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return resp.StatusCode == http.StatusOK, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type MockObservationsService struct {
 | 
					 | 
				
			||||||
	Get_    func(id int64) (*Observation, error)
 | 
					 | 
				
			||||||
	List_   func(opt *ObservationListOptions) ([]*Observation, error)
 | 
					 | 
				
			||||||
	Create_ func(observation *Observation) (bool, error)
 | 
					 | 
				
			||||||
	Update_ func(id int64, observation *Observation) (bool, error)
 | 
					 | 
				
			||||||
	Delete_ func(id int64) (bool, error)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var _ ObservationsService = &MockObservationsService{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *MockObservationsService) Get(id int64) (*Observation, error) {
 | 
					 | 
				
			||||||
	if s.Get_ == nil {
 | 
					 | 
				
			||||||
		return nil, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s.Get_(id)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *MockObservationsService) Create(observation *Observation) (bool, error) {
 | 
					 | 
				
			||||||
	if s.Create_ == nil {
 | 
					 | 
				
			||||||
		return false, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s.Create_(observation)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *MockObservationsService) List(opt *ObservationListOptions) ([]*Observation, error) {
 | 
					 | 
				
			||||||
	if s.List_ == nil {
 | 
					 | 
				
			||||||
		return nil, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s.List_(opt)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *MockObservationsService) Update(id int64, observation *Observation) (bool, error) {
 | 
					 | 
				
			||||||
	if s.Update_ == nil {
 | 
					 | 
				
			||||||
		return false, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s.Update_(id, observation)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *MockObservationsService) Delete(id int64) (bool, error) {
 | 
					 | 
				
			||||||
	if s.Delete_ == nil {
 | 
					 | 
				
			||||||
		return false, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return s.Delete_(id)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,174 +0,0 @@
 | 
				
			||||||
package models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
	"reflect"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/thermokarst/bactdb/router"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newObservation() *Observation {
 | 
					 | 
				
			||||||
	observation := NewObservation()
 | 
					 | 
				
			||||||
	observation.Id = 1
 | 
					 | 
				
			||||||
	return observation
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationService_Get(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
	defer teardown()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var called bool
 | 
					 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.Observation, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
					 | 
				
			||||||
		called = true
 | 
					 | 
				
			||||||
		testMethod(t, r, "GET")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		writeJSON(w, want)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation, err := client.Observations.Get(want.Id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.Get returned error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !called {
 | 
					 | 
				
			||||||
		t.Fatal("!called")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	normalizeTime(&want.CreatedAt, &want.UpdatedAt, &want.DeletedAt)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !reflect.DeepEqual(observation, want) {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.Get return %+v, want %+v", observation, want)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationService_Create(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
	defer teardown()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var called bool
 | 
					 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.CreateObservation, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
					 | 
				
			||||||
		called = true
 | 
					 | 
				
			||||||
		testMethod(t, r, "POST")
 | 
					 | 
				
			||||||
		testBody(t, r, `{"id":1,"observationName":"Test Observation","characteristicTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		w.WriteHeader(http.StatusCreated)
 | 
					 | 
				
			||||||
		writeJSON(w, want)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation := newObservation()
 | 
					 | 
				
			||||||
	created, err := client.Observations.Create(observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.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(observation, want) {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.Create returned %+v, want %+v", observation, want)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationService_List(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
	defer teardown()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := []*Observation{newObservation()}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var called bool
 | 
					 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.Observations, nil), func(w http.ResponseWriter, r *http.Request) {
 | 
					 | 
				
			||||||
		called = true
 | 
					 | 
				
			||||||
		testMethod(t, r, "GET")
 | 
					 | 
				
			||||||
		testFormValues(t, r, values{})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		writeJSON(w, want)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observations, err := client.Observations.List(nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.List returned error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !called {
 | 
					 | 
				
			||||||
		t.Fatal("!called")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, u := range want {
 | 
					 | 
				
			||||||
		normalizeTime(&u.CreatedAt, &u.UpdatedAt, &u.DeletedAt)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !reflect.DeepEqual(observations, want) {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.List return %+v, want %+v", observations, want)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationService_Update(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
	defer teardown()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var called bool
 | 
					 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.UpdateObservation, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
					 | 
				
			||||||
		called = true
 | 
					 | 
				
			||||||
		testMethod(t, r, "PUT")
 | 
					 | 
				
			||||||
		testBody(t, r, `{"id":1,"observationName":"Test Obs Updated","characteristicTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n")
 | 
					 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
					 | 
				
			||||||
		writeJSON(w, want)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	observation := newObservation()
 | 
					 | 
				
			||||||
	observation.ObservationName = "Test Obs Updated"
 | 
					 | 
				
			||||||
	updated, err := client.Observations.Update(observation.Id, observation)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.Update returned error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !updated {
 | 
					 | 
				
			||||||
		t.Error("!updated")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !called {
 | 
					 | 
				
			||||||
		t.Fatal("!called")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestObservationService_Delete(t *testing.T) {
 | 
					 | 
				
			||||||
	setup()
 | 
					 | 
				
			||||||
	defer teardown()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	want := newObservation()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var called bool
 | 
					 | 
				
			||||||
	mux.HandleFunc(urlPath(t, router.DeleteObservation, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) {
 | 
					 | 
				
			||||||
		called = true
 | 
					 | 
				
			||||||
		testMethod(t, r, "DELETE")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		w.WriteHeader(http.StatusOK)
 | 
					 | 
				
			||||||
		writeJSON(w, want)
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	deleted, err := client.Observations.Delete(want.Id)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Observations.Delete returned error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !deleted {
 | 
					 | 
				
			||||||
		t.Error("!deleted")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !called {
 | 
					 | 
				
			||||||
		t.Fatal("!called")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -38,12 +38,12 @@ func API() *mux.Router {
 | 
				
			||||||
	m.Path("/characteristic_types/{Id:.+}").Methods("PUT").Name(UpdateCharacteristicType)
 | 
						m.Path("/characteristic_types/{Id:.+}").Methods("PUT").Name(UpdateCharacteristicType)
 | 
				
			||||||
	m.Path("/characteristic_types/{Id:.+}").Methods("DELETE").Name(DeleteCharacteristicType)
 | 
						m.Path("/characteristic_types/{Id:.+}").Methods("DELETE").Name(DeleteCharacteristicType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Observations
 | 
						// Characteristics
 | 
				
			||||||
	m.Path("/observations").Methods("GET").Name(Observations)
 | 
						m.Path("/characteristics").Methods("GET").Name(Characteristics)
 | 
				
			||||||
	m.Path("/observations").Methods("POST").Name(CreateObservation)
 | 
						m.Path("/characteristics").Methods("POST").Name(CreateCharacteristic)
 | 
				
			||||||
	m.Path("/observations/{Id:.+}").Methods("GET").Name(Observation)
 | 
						m.Path("/characteristics/{Id:.+}").Methods("GET").Name(Characteristic)
 | 
				
			||||||
	m.Path("/observations/{Id:.+}").Methods("PUT").Name(UpdateObservation)
 | 
						m.Path("/characteristics/{Id:.+}").Methods("PUT").Name(UpdateCharacteristic)
 | 
				
			||||||
	m.Path("/observations/{Id:.+}").Methods("DELETE").Name(DeleteObservation)
 | 
						m.Path("/characteristics/{Id:.+}").Methods("DELETE").Name(DeleteCharacteristic)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TextMeasurementTypes
 | 
						// TextMeasurementTypes
 | 
				
			||||||
	m.Path("/text_measurement_types/").Methods("GET").Name(TextMeasurementTypes)
 | 
						m.Path("/text_measurement_types/").Methods("GET").Name(TextMeasurementTypes)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,11 +29,11 @@ const (
 | 
				
			||||||
	UpdateCharacteristicType = "characteristic_type:update"
 | 
						UpdateCharacteristicType = "characteristic_type:update"
 | 
				
			||||||
	DeleteCharacteristicType = "characteristic_type:delete"
 | 
						DeleteCharacteristicType = "characteristic_type:delete"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Observation       = "observation:get"
 | 
						Characteristic       = "characteristic:get"
 | 
				
			||||||
	CreateObservation = "observation:create"
 | 
						CreateCharacteristic = "characteristic:create"
 | 
				
			||||||
	Observations      = "observation:list"
 | 
						Characteristics      = "characteristic:list"
 | 
				
			||||||
	UpdateObservation = "observation:update"
 | 
						UpdateCharacteristic = "characteristic:update"
 | 
				
			||||||
	DeleteObservation = "observation:delete"
 | 
						DeleteCharacteristic = "characteristic:delete"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TextMeasurementType       = "text_measurement_type:get"
 | 
						TextMeasurementType       = "text_measurement_type:get"
 | 
				
			||||||
	CreateTextMeasurementType = "text_measurement_type:create"
 | 
						CreateTextMeasurementType = "text_measurement_type:create"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in a new issue