Cleaning up null values in json
This commit is contained in:
		
							parent
							
								
									bc6e585b8d
								
							
						
					
					
						commit
						8dc07e3cc8
					
				
					 21 changed files with 222 additions and 92 deletions
				
			
		|  | @ -1,6 +1,7 @@ | |||
| package api | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/thermokarst/bactdb/models" | ||||
|  | @ -8,6 +9,11 @@ import ( | |||
| 
 | ||||
| func newMeasurement() *models.Measurement { | ||||
| 	measurement := models.NewMeasurement() | ||||
| 	measurement.Id = 1 | ||||
| 	measurement.StrainId = 2 | ||||
| 	measurement.ObservationId = 3 | ||||
| 	measurement.TextMeasurementTypeId = models.NullInt64{sql.NullInt64{Int64: 4, Valid: false}} | ||||
| 	measurement.UnitTypeId = models.NullInt64{sql.NullInt64{Int64: 5, Valid: true}} | ||||
| 	return measurement | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import ( | |||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/models" | ||||
| ) | ||||
| 
 | ||||
| func normalizeTime(t ...interface{}) { | ||||
|  | @ -15,9 +16,9 @@ func normalizeTime(t ...interface{}) { | |||
| 		case *time.Time: | ||||
| 			x, _ := v.(*time.Time) | ||||
| 			*x = x.In(time.UTC) | ||||
| 		case *pq.NullTime: | ||||
| 			x, _ := v.(*pq.NullTime) | ||||
| 			*x = pq.NullTime{Time: x.Time.In(time.UTC), Valid: x.Valid} | ||||
| 		case *models.NullTime: | ||||
| 			x, _ := v.(*models.NullTime) | ||||
| 			*x = models.NullTime{pq.NullTime{Time: x.Time.In(time.UTC), Valid: x.Valid}} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -30,8 +30,8 @@ func newMeasurement(t *testing.T, tx *modl.Transaction) *models.Measurement { | |||
| 	return &models.Measurement{ | ||||
| 		StrainId:      strain.Id, | ||||
| 		ObservationId: observation.Id, | ||||
| 		NumValue:      sql.NullFloat64{Float64: 1.23, Valid: true}, | ||||
| 		UnitTypeId:    sql.NullInt64{Int64: unit_type.Id, Valid: true}, | ||||
| 		NumValue:      models.NullFloat64{sql.NullFloat64{Float64: 1.23, Valid: true}}, | ||||
| 		UnitTypeId:    models.NullInt64{sql.NullInt64{Int64: unit_type.Id, Valid: true}}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -108,7 +108,7 @@ func TestMeasurementsStore_Update_db(t *testing.T) { | |||
| 	d := NewDatastore(tx) | ||||
| 
 | ||||
| 	// Tweak it | ||||
| 	measurement.NumValue = sql.NullFloat64{Float64: 4.56, Valid: true} | ||||
| 	measurement.NumValue = models.NullFloat64{sql.NullFloat64{Float64: 4.56, Valid: true}} | ||||
| 	updated, err := d.Measurements.Update(measurement.Id, measurement) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
|  |  | |||
|  | @ -99,9 +99,9 @@ func normalizeTime(t ...interface{}) { | |||
| 		case *time.Time: | ||||
| 			x, _ := v.(*time.Time) | ||||
| 			*x = x.In(time.UTC) | ||||
| 		case *pq.NullTime: | ||||
| 			x, _ := v.(*pq.NullTime) | ||||
| 			*x = pq.NullTime{Time: x.Time.In(time.UTC), Valid: x.Valid} | ||||
| 		case *NullTime: | ||||
| 			x, _ := v.(*NullTime) | ||||
| 			*x = NullTime{pq.NullTime{Time: x.Time.In(time.UTC), Valid: x.Valid}} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/router" | ||||
| ) | ||||
| 
 | ||||
|  | @ -16,7 +15,7 @@ type Genus struct { | |||
| 	GenusName string    `db:"genus_name" json:"genusName"` | ||||
| 	CreatedAt time.Time `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt time.Time `db:"updated_at" json:"updatedAt"` | ||||
| 	DeletedAt pq.NullTime `db:"deleted_at" json:"deletedAt"` | ||||
| 	DeletedAt NullTime  `db:"deleted_at" json:"deletedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewGenus() *Genus { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ func TestGeneraService_Create(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.CreateGenus, nil), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testBody(t, r, `{"id":1,"genusName":"Test Genus","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"genusName":"Test Genus","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -124,7 +124,7 @@ func TestGeneraService_Update(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.UpdateGenus, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "PUT") | ||||
| 		testBody(t, r, `{"id":1,"genusName":"Test Genus Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"genusName":"Test Genus Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
|  |  | |||
|  | @ -18,20 +18,20 @@ type Measurement struct { | |||
| 	Id                    int64       `json:"id,omitempty"` | ||||
| 	StrainId              int64       `db:"strain_id" json:"strainId"` | ||||
| 	ObservationId         int64       `db:"observation_id" json:"observationId"` | ||||
| 	TextMeasurementTypeId sql.NullInt64   `db:"text_measurement_type_id" json:"textMeasurementTypeId"` | ||||
| 	TxtValue              sql.NullString  `db:"txt_value" json:"txtValue"` | ||||
| 	NumValue              sql.NullFloat64 `db:"num_value" json:"numValue"` | ||||
| 	ConfidenceInterval    sql.NullFloat64 `db:"confidence_interval" json:"confidenceInterval"` | ||||
| 	UnitTypeId            sql.NullInt64   `db:"unit_type_id" json:"unitTypeId"` | ||||
| 	Notes                 sql.NullString  `db:"notes" json:"notes"` | ||||
| 	TestMethodId          sql.NullInt64   `db:"test_method_id" json:"testMethodId"` | ||||
| 	TextMeasurementTypeId NullInt64   `db:"text_measurement_type_id" json:"textMeasurementTypeId"` | ||||
| 	TxtValue              NullString  `db:"txt_value" json:"txtValue"` | ||||
| 	NumValue              NullFloat64 `db:"num_value" json:"numValue"` | ||||
| 	ConfidenceInterval    NullFloat64 `db:"confidence_interval" json:"confidenceInterval"` | ||||
| 	UnitTypeId            NullInt64   `db:"unit_type_id" json:"unitTypeId"` | ||||
| 	Notes                 NullString  `db:"notes" json:"notes"` | ||||
| 	TestMethodId          NullInt64   `db:"test_method_id" json:"testMethodId"` | ||||
| 	CreatedAt             time.Time   `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt             time.Time   `db:"updated_at" json:"updatedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewMeasurement() *Measurement { | ||||
| 	return &Measurement{ | ||||
| 		NumValue: sql.NullFloat64{Float64: 1.23, Valid: true}, | ||||
| 		NumValue: NullFloat64{sql.NullFloat64{Float64: 1.23, Valid: true}}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ func newMeasurement() *Measurement { | |||
| 	measurement.Id = 1 | ||||
| 	measurement.StrainId = 1 | ||||
| 	measurement.ObservationId = 1 | ||||
| 	measurement.UnitTypeId = sql.NullInt64{Int64: 1, Valid: true} | ||||
| 	measurement.UnitTypeId = NullInt64{sql.NullInt64{Int64: 1, Valid: true}} | ||||
| 	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) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testBody(t, r, `{"id":1,"strainId":1,"observationId":1,"textMeasurementTypeId":{"Int64":0,"Valid":false},"txtValue":{"String":"","Valid":false},"numValue":{"Float64":1.23,"Valid":true},"confidenceInterval":{"Float64":0,"Valid":false},"unitTypeId":{"Int64":1,"Valid":true},"notes":{"String":"","Valid":false},"testMethodId":{"Int64":0,"Valid":false},"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`+"\n") | ||||
| 		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") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -127,13 +127,13 @@ func TestMeasurementService_Update(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.UpdateMeasurement, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "PUT") | ||||
| 		testBody(t, r, `{"id":1,"strainId":1,"observationId":1,"textMeasurementTypeId":{"Int64":0,"Valid":false},"txtValue":{"String":"","Valid":false},"numValue":{"Float64":4.56,"Valid":true},"confidenceInterval":{"Float64":0,"Valid":false},"unitTypeId":{"Int64":1,"Valid":true},"notes":{"String":"","Valid":false},"testMethodId":{"Int64":0,"Valid":false},"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z"}`+"\n") | ||||
| 		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") | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
| 	}) | ||||
| 
 | ||||
| 	measurement := newMeasurement() | ||||
| 	measurement.NumValue = sql.NullFloat64{Float64: 4.56, Valid: true} | ||||
| 	measurement.NumValue = NullFloat64{sql.NullFloat64{Float64: 4.56, Valid: true}} | ||||
| 	updated, err := client.Measurements.Update(measurement.Id, measurement) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Measurements.Update returned error: %v", err) | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/router" | ||||
| ) | ||||
| 
 | ||||
|  | @ -16,7 +15,7 @@ type ObservationType struct { | |||
| 	ObservationTypeName string    `db:"observation_type_name" json:"observationTypeName"` | ||||
| 	CreatedAt           time.Time `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt           time.Time `db:"updated_at" json:"updatedAt"` | ||||
| 	DeletedAt           pq.NullTime `db:"deleted_at" json:"deletedAt"` | ||||
| 	DeletedAt           NullTime  `db:"deleted_at" json:"deletedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewObservationType() *ObservationType { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ func TestObservationTypeService_Create(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.CreateObservationType, nil), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testBody(t, r, `{"id":1,"observationTypeName":"Test Obs Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"observationTypeName":"Test Obs Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -123,7 +123,7 @@ func TestObservationTypeService_Update(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.UpdateObservationType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "PUT") | ||||
| 		testBody(t, r, `{"id":1,"observationTypeName":"Test Obs Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"observationTypeName":"Test Obs Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
| 	}) | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/router" | ||||
| ) | ||||
| 
 | ||||
|  | @ -17,7 +16,7 @@ type Observation struct { | |||
| 	ObservationTypeId int64     `db:"observation_type_id" json:"observationTypeId"` | ||||
| 	CreatedAt         time.Time `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt         time.Time `db:"updated_at" json:"updatedAt"` | ||||
| 	DeletedAt         pq.NullTime `db:"deleted_at" json:"deletedAt"` | ||||
| 	DeletedAt         NullTime  `db:"deleted_at" json:"deletedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewObservation() *Observation { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ func TestObservationService_Create(t *testing.T) { | |||
| 	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","observationTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"observationName":"Test Observation","observationTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -123,7 +123,7 @@ func TestObservationService_Update(t *testing.T) { | |||
| 	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","observationTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"observationName":"Test Obs Updated","observationTypeId":0,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
| 	}) | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/router" | ||||
| ) | ||||
| 
 | ||||
|  | @ -17,7 +16,7 @@ type Species struct { | |||
| 	SpeciesName string    `db:"species_name" json:"speciesName"` | ||||
| 	CreatedAt   time.Time `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt   time.Time `db:"updated_at" json:"updatedAt"` | ||||
| 	DeletedAt   pq.NullTime `db:"deleted_at" json:"deletedAt"` | ||||
| 	DeletedAt   NullTime  `db:"deleted_at" json:"deletedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewSpecies() *Species { | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ func TestSpeciesService_Create(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.CreateSpecies, nil), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testBody(t, r, `{"id":1,"genusId":1,"speciesName":"Test Species","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"genusId":1,"speciesName":"Test Species","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -124,7 +124,7 @@ func TestSpeciesService_Update(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.UpdateSpecies, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "PUT") | ||||
| 		testBody(t, r, `{"id":1,"genusId":1,"speciesName":"Test Species Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"genusId":1,"speciesName":"Test Species Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
|  |  | |||
|  | @ -1,13 +1,11 @@ | |||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"errors" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/router" | ||||
| ) | ||||
| 
 | ||||
|  | @ -20,10 +18,10 @@ type Strain struct { | |||
| 	Etymology      string     `db:"etymology" json:"etymology"` | ||||
| 	AccessionBanks string     `db:"accession_banks" json:"accessionBanks"` | ||||
| 	GenbankEmblDdb string     `db:"genbank_embl_ddb" json:"genbankEmblDdb"` | ||||
| 	IsolatedFrom   sql.NullString `db:"isolated_from" json:"isolatedFrom"` | ||||
| 	IsolatedFrom   NullString `db:"isolated_from" json:"isolatedFrom"` | ||||
| 	CreatedAt      time.Time  `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt      time.Time  `db:"updated_at" json:"updatedAt"` | ||||
| 	DeletedAt      pq.NullTime    `db:"deleted_at" json:"deletedAt"` | ||||
| 	DeletedAt      NullTime   `db:"deleted_at" json:"deletedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewStrain() *Strain { | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ func TestStrainService_Create(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.CreateStrain, nil), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testBody(t, r, `{"id":1,"speciesId":1,"strainName":"Test Strain","strainType":"Test Type","etymology":"Test Etymology","accessionBanks":"Test Accession","genbankEmblDdb":"Test Genbank","isolatedFrom":{"String":"","Valid":false},"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"speciesId":1,"strainName":"Test Strain","strainType":"Test Type","etymology":"Test Etymology","accessionBanks":"Test Accession","genbankEmblDdb":"Test Genbank","isolatedFrom":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -124,7 +124,7 @@ func TestStrainService_Update(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.UpdateStrain, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "PUT") | ||||
| 		testBody(t, r, `{"id":1,"speciesId":1,"strainName":"Test Strain Updated","strainType":"Test Type Updated","etymology":"Test Etymology Updated","accessionBanks":"Test Accession Updated","genbankEmblDdb":"Test Genbank Updated","isolatedFrom":{"String":"","Valid":false},"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"speciesId":1,"strainName":"Test Strain Updated","strainType":"Test Type Updated","etymology":"Test Etymology Updated","accessionBanks":"Test Accession Updated","genbankEmblDdb":"Test Genbank Updated","isolatedFrom":null,"createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
| 	}) | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/router" | ||||
| ) | ||||
| 
 | ||||
|  | @ -16,7 +15,7 @@ type TextMeasurementType struct { | |||
| 	TextMeasurementName string    `db:"text_measurement_name" json:"textMeasurementName"` | ||||
| 	CreatedAt           time.Time `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt           time.Time `db:"updated_at" json:"updatedAt"` | ||||
| 	DeletedAt           pq.NullTime `db:"deleted_at" json:"deletedAt"` | ||||
| 	DeletedAt           NullTime  `db:"deleted_at" json:"deletedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewTextMeasurementType() *TextMeasurementType { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ func TestTextMeasurementTypeService_Create(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.CreateTextMeasurementType, nil), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testBody(t, r, `{"id":1,"textMeasurementName":"Test Text Measurement Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"textMeasurementName":"Test Text Measurement Type","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -123,7 +123,7 @@ func TestTextMeasurementTypeService_Update(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.UpdateTextMeasurementType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "PUT") | ||||
| 		testBody(t, r, `{"id":1,"textMeasurementName":"Test Text Measurement Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"textMeasurementName":"Test Text Measurement Type Updated","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
| 	}) | ||||
|  |  | |||
							
								
								
									
										131
									
								
								models/types.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								models/types.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,131 @@ | |||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"database/sql" | ||||
| 	"encoding/json" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| ) | ||||
| 
 | ||||
| type NullString struct { | ||||
| 	sql.NullString | ||||
| } | ||||
| 
 | ||||
| func (s *NullString) MarshalJSON() ([]byte, error) { | ||||
| 	if !s.Valid { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
| 	return json.Marshal(s.String) | ||||
| } | ||||
| 
 | ||||
| func (s *NullString) UnmarshalJSON(b []byte) error { | ||||
| 	if bytes.Equal(b, []byte("null")) { | ||||
| 		s.String = "" | ||||
| 		s.Valid = false | ||||
| 		return nil | ||||
| 	} | ||||
| 	var x interface{} | ||||
| 	var err error | ||||
| 	json.Unmarshal(b, &x) | ||||
| 	switch x.(type) { | ||||
| 	case float64: | ||||
| 		err = json.Unmarshal(b, &s.String) | ||||
| 	case map[string]interface{}: | ||||
| 		err = json.Unmarshal(b, &s.NullString) | ||||
| 	} | ||||
| 	s.Valid = true | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| type NullInt64 struct { | ||||
| 	sql.NullInt64 | ||||
| } | ||||
| 
 | ||||
| func (i *NullInt64) MarshalJSON() ([]byte, error) { | ||||
| 	if !i.Valid { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
| 	return json.Marshal(i.Int64) | ||||
| } | ||||
| 
 | ||||
| func (i *NullInt64) UnmarshalJSON(b []byte) error { | ||||
| 	if bytes.Equal(b, []byte("null")) { | ||||
| 		i.Int64 = 0 | ||||
| 		i.Valid = false | ||||
| 		return nil | ||||
| 	} | ||||
| 	var x interface{} | ||||
| 	var err error | ||||
| 	json.Unmarshal(b, &x) | ||||
| 	switch x.(type) { | ||||
| 	case float64: | ||||
| 		err = json.Unmarshal(b, &i.Int64) | ||||
| 	case map[string]interface{}: | ||||
| 		err = json.Unmarshal(b, &i.NullInt64) | ||||
| 	} | ||||
| 	i.Valid = true | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| type NullFloat64 struct { | ||||
| 	sql.NullFloat64 | ||||
| } | ||||
| 
 | ||||
| func (f *NullFloat64) MarshalJSON() ([]byte, error) { | ||||
| 	if !f.Valid { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
| 	return json.Marshal(f.Float64) | ||||
| } | ||||
| 
 | ||||
| func (f *NullFloat64) UnmarshalJSON(b []byte) error { | ||||
| 	if bytes.Equal(b, []byte("null")) { | ||||
| 		f.Float64 = 0 | ||||
| 		f.Valid = false | ||||
| 		return nil | ||||
| 	} | ||||
| 	var x interface{} | ||||
| 	var err error | ||||
| 	json.Unmarshal(b, &x) | ||||
| 	switch x.(type) { | ||||
| 	case float64: | ||||
| 		err = json.Unmarshal(b, &f.Float64) | ||||
| 	case map[string]interface{}: | ||||
| 		err = json.Unmarshal(b, &f.NullFloat64) | ||||
| 	} | ||||
| 	f.Valid = true | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| type NullTime struct { | ||||
| 	pq.NullTime | ||||
| } | ||||
| 
 | ||||
| func (t *NullTime) MarshalJSON() ([]byte, error) { | ||||
| 	if !t.Valid { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
| 	return json.Marshal(t.Time) | ||||
| } | ||||
| 
 | ||||
| func (t *NullTime) UnmarshalJSON(b []byte) error { | ||||
| 	if bytes.Equal(b, []byte("null")) { | ||||
| 		var nt time.Time | ||||
| 		t.Time = nt.In(time.UTC) | ||||
| 		t.Valid = false | ||||
| 		return nil | ||||
| 	} | ||||
| 	var x interface{} | ||||
| 	var err error | ||||
| 	json.Unmarshal(b, &x) | ||||
| 	switch x.(type) { | ||||
| 	case time.Time: | ||||
| 		err = json.Unmarshal(b, &t.Time) | ||||
| 	case map[string]interface{}: | ||||
| 		err = json.Unmarshal(b, &t.NullTime) | ||||
| 	} | ||||
| 	t.Valid = true | ||||
| 	return err | ||||
| } | ||||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/lib/pq" | ||||
| 	"github.com/thermokarst/bactdb/router" | ||||
| ) | ||||
| 
 | ||||
|  | @ -17,7 +16,7 @@ type UnitType struct { | |||
| 	Symbol    string    `db:"symbol" json:"symbol"` | ||||
| 	CreatedAt time.Time `db:"created_at" json:"createdAt"` | ||||
| 	UpdatedAt time.Time `db:"updated_at" json:"updatedAt"` | ||||
| 	DeletedAt pq.NullTime `db:"deleted_at" json:"deletedAt"` | ||||
| 	DeletedAt NullTime  `db:"deleted_at" json:"deletedAt"` | ||||
| } | ||||
| 
 | ||||
| func NewUnitType() *UnitType { | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ func TestUnitTypeService_Create(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.CreateUnitType, nil), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "POST") | ||||
| 		testBody(t, r, `{"id":1,"name":"Test Unit Type","symbol":"x","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"name":"Test Unit Type","symbol":"x","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 
 | ||||
| 		w.WriteHeader(http.StatusCreated) | ||||
| 		writeJSON(w, want) | ||||
|  | @ -123,7 +123,7 @@ func TestUnitTypeService_Update(t *testing.T) { | |||
| 	mux.HandleFunc(urlPath(t, router.UpdateUnitType, map[string]string{"Id": "1"}), func(w http.ResponseWriter, r *http.Request) { | ||||
| 		called = true | ||||
| 		testMethod(t, r, "PUT") | ||||
| 		testBody(t, r, `{"id":1,"name":"Test Unit Type Updated","symbol":"x","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":{"Time":"0001-01-01T00:00:00Z","Valid":false}}`+"\n") | ||||
| 		testBody(t, r, `{"id":1,"name":"Test Unit Type Updated","symbol":"x","createdAt":"0001-01-01T00:00:00Z","updatedAt":"0001-01-01T00:00:00Z","deletedAt":null}`+"\n") | ||||
| 		w.WriteHeader(http.StatusOK) | ||||
| 		writeJSON(w, want) | ||||
| 	}) | ||||
|  |  | |||
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon