Beef up strains payload
This commit is contained in:
		
							parent
							
								
									86e6c45a2f
								
							
						
					
					
						commit
						12b460db9a
					
				
					 2 changed files with 115 additions and 16 deletions
				
			
		|  | @ -277,9 +277,10 @@ func listCharacteristics(opt ListOptions, claims *Claims) (*Characteristics, err | ||||||
| 		q += fmt.Sprintf(" WHERE %s", w) | 		q += fmt.Sprintf(" WHERE %s", w) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	q += " GROUP BY c.id, ct.characteristic_type_name;" | 	q += ` GROUP BY c.id, ct.characteristic_type_name | ||||||
|  | 			ORDER BY ct.characteristic_type_name, c.sort_order ASC;` | ||||||
| 
 | 
 | ||||||
| 	characteristics := make(Characteristics, 0) | 	var characteristics Characteristics | ||||||
| 	err := DBH.Select(&characteristics, q, vals...) | 	err := DBH.Select(&characteristics, q, vals...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
|  |  | ||||||
							
								
								
									
										106
									
								
								strains.go
									
										
									
									
									
								
							
							
						
						
									
										106
									
								
								strains.go
									
										
									
									
									
								
							|  | @ -56,6 +56,7 @@ type StrainBase struct { | ||||||
| type Strain struct { | type Strain struct { | ||||||
| 	*StrainBase | 	*StrainBase | ||||||
| 	Measurements      NullSliceInt64 `db:"measurements" json:"measurements"` | 	Measurements      NullSliceInt64 `db:"measurements" json:"measurements"` | ||||||
|  | 	Characteristics   NullSliceInt64 `db:"characteristics" json:"characteristics"` | ||||||
| 	TotalMeasurements int64          `db:"total_measurements" json:"totalMeasurements"` | 	TotalMeasurements int64          `db:"total_measurements" json:"totalMeasurements"` | ||||||
| 	SortOrder         int64          `db:"sort_order" json:"sortOrder"` | 	SortOrder         int64          `db:"sort_order" json:"sortOrder"` | ||||||
| 	CanEdit           bool           `db:"-" json:"canEdit"` | 	CanEdit           bool           `db:"-" json:"canEdit"` | ||||||
|  | @ -70,12 +71,16 @@ type StrainMeta struct { | ||||||
| type StrainPayload struct { | type StrainPayload struct { | ||||||
| 	Strain          *Strain          `json:"strain"` | 	Strain          *Strain          `json:"strain"` | ||||||
| 	Species         *ManySpecies     `json:"species"` | 	Species         *ManySpecies     `json:"species"` | ||||||
|  | 	Characteristics *Characteristics `json:"characteristics"` | ||||||
|  | 	Measurements    *Measurements    `json:"measurements"` | ||||||
| 	Meta            *StrainMeta      `json:"meta"` | 	Meta            *StrainMeta      `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type StrainsPayload struct { | type StrainsPayload struct { | ||||||
| 	Strains         *Strains         `json:"strains"` | 	Strains         *Strains         `json:"strains"` | ||||||
| 	Species         *ManySpecies     `json:"species"` | 	Species         *ManySpecies     `json:"species"` | ||||||
|  | 	Characteristics *Characteristics `json:"characteristics"` | ||||||
|  | 	Measurements    *Measurements    `json:"measurements"` | ||||||
| 	Meta            *StrainMeta      `json:"meta"` | 	Meta            *StrainMeta      `json:"meta"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -125,9 +130,44 @@ func (s StrainService) list(val *url.Values, claims *Claims) (entity, *appError) | ||||||
| 		return nil, newJSONError(err, http.StatusInternalServerError) | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	characteristics_opt, err := characteristicsOptsFromStrains(opt) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	characteristics, err := listCharacteristics(*characteristics_opt, claims) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	characteristic_ids := []int64{} | ||||||
|  | 	for _, c := range *characteristics { | ||||||
|  | 		characteristic_ids = append(characteristic_ids, c.Id) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	strain_ids := []int64{} | ||||||
|  | 	for _, s := range *strains { | ||||||
|  | 		strain_ids = append(strain_ids, s.Id) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	measurement_opt := MeasurementListOptions{ | ||||||
|  | 		ListOptions: ListOptions{ | ||||||
|  | 			Genus: opt.Genus, | ||||||
|  | 		}, | ||||||
|  | 		Strains:         strain_ids, | ||||||
|  | 		Characteristics: characteristic_ids, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	measurements, err := listMeasurements(measurement_opt, claims) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	payload := StrainsPayload{ | 	payload := StrainsPayload{ | ||||||
| 		Strains:         strains, | 		Strains:         strains, | ||||||
| 		Species:         species, | 		Species:         species, | ||||||
|  | 		Measurements:    measurements, | ||||||
|  | 		Characteristics: characteristics, | ||||||
| 		Meta: &StrainMeta{ | 		Meta: &StrainMeta{ | ||||||
| 			CanAdd: canAdd(claims), | 			CanAdd: canAdd(claims), | ||||||
| 		}, | 		}, | ||||||
|  | @ -147,11 +187,42 @@ func (s StrainService) get(id int64, genus string, claims *Claims) (entity, *app | ||||||
| 		return nil, newJSONError(err, http.StatusInternalServerError) | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	opt := ListOptions{Genus: genus, Ids: []int64{id}} | ||||||
|  | 	characteristics_opt, err := characteristicsOptsFromStrains(opt) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	characteristics, err := listCharacteristics(*characteristics_opt, claims) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	characteristic_ids := []int64{} | ||||||
|  | 	for _, c := range *characteristics { | ||||||
|  | 		characteristic_ids = append(characteristic_ids, c.Id) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	measurement_opt := MeasurementListOptions{ | ||||||
|  | 		ListOptions: ListOptions{ | ||||||
|  | 			Genus: genus, | ||||||
|  | 		}, | ||||||
|  | 		Strains:         []int64{id}, | ||||||
|  | 		Characteristics: characteristic_ids, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	measurements, err := listMeasurements(measurement_opt, claims) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, newJSONError(err, http.StatusInternalServerError) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	var many_species ManySpecies = []*Species{species} | 	var many_species ManySpecies = []*Species{species} | ||||||
| 
 | 
 | ||||||
| 	payload := StrainPayload{ | 	payload := StrainPayload{ | ||||||
| 		Strain:          strain, | 		Strain:          strain, | ||||||
| 		Species:         &many_species, | 		Species:         &many_species, | ||||||
|  | 		Characteristics: characteristics, | ||||||
|  | 		Measurements:    measurements, | ||||||
| 		Meta: &StrainMeta{ | 		Meta: &StrainMeta{ | ||||||
| 			CanAdd: canAdd(claims), | 			CanAdd: canAdd(claims), | ||||||
| 		}, | 		}, | ||||||
|  | @ -227,7 +298,9 @@ func (s StrainService) create(e *entity, genus string, claims *Claims) *appError | ||||||
| func listStrains(opt ListOptions, claims *Claims) (*Strains, error) { | func listStrains(opt ListOptions, claims *Claims) (*Strains, error) { | ||||||
| 	var vals []interface{} | 	var vals []interface{} | ||||||
| 
 | 
 | ||||||
| 	q := `SELECT st.*, array_agg(m.id) AS measurements, COUNT(m) AS total_measurements, | 	q := `SELECT st.*, array_agg(m.id) AS measurements, | ||||||
|  | 		array_agg(DISTINCT m.characteristic_id) AS characteristics, | ||||||
|  | 		COUNT(m) AS total_measurements, | ||||||
| 		rank() OVER (ORDER BY sp.species_name ASC, st.type_strain ASC, st.strain_name ASC) AS sort_order | 		rank() OVER (ORDER BY sp.species_name ASC, st.type_strain ASC, st.strain_name ASC) AS sort_order | ||||||
| 		FROM strains st | 		FROM strains st | ||||||
| 		INNER JOIN species sp ON sp.id=st.species_id | 		INNER JOIN species sp ON sp.id=st.species_id | ||||||
|  | @ -264,14 +337,15 @@ func listStrains(opt ListOptions, claims *Claims) (*Strains, error) { | ||||||
| 
 | 
 | ||||||
| func getStrain(id int64, genus string, claims *Claims) (*Strain, error) { | func getStrain(id int64, genus string, claims *Claims) (*Strain, error) { | ||||||
| 	var strain Strain | 	var strain Strain | ||||||
| 	q := `SELECT st.*, array_agg(m.id) AS measurements, | 	q := `SELECT st.*, array_agg(DISTINCT m.id) AS measurements, | ||||||
|  | 		array_agg(DISTINCT m.characteristic_id) AS characteristics, | ||||||
| 		COUNT(m) AS total_measurements, 0 AS sort_order | 		COUNT(m) AS total_measurements, 0 AS sort_order | ||||||
| 		FROM strains st | 		FROM strains st | ||||||
| 		INNER JOIN species sp ON sp.id=st.species_id | 		INNER JOIN species sp ON sp.id=st.species_id | ||||||
| 		INNER JOIN genera g ON g.id=sp.genus_id AND LOWER(g.genus_name)=LOWER($1) | 		INNER JOIN genera g ON g.id=sp.genus_id AND LOWER(g.genus_name)=LOWER($1) | ||||||
| 		LEFT OUTER JOIN measurements m ON m.strain_id=st.id | 		INNER JOIN measurements m ON m.strain_id=st.id | ||||||
| 		WHERE st.id=$2 | 		WHERE st.id=$2 | ||||||
| 		GROUP BY st.id, st.species_id;` | 		GROUP BY st.id;` | ||||||
| 	if err := DBH.SelectOne(&strain, q, genus, id); err != nil { | 	if err := DBH.SelectOne(&strain, q, genus, id); err != nil { | ||||||
| 		if err == sql.ErrNoRows { | 		if err == sql.ErrNoRows { | ||||||
| 			return nil, ErrStrainNotFound | 			return nil, ErrStrainNotFound | ||||||
|  | @ -306,3 +380,27 @@ func speciesOptsFromStrains(opt ListOptions) (*ListOptions, error) { | ||||||
| 
 | 
 | ||||||
| 	return &ListOptions{Genus: opt.Genus, Ids: relatedSpeciesIds}, nil | 	return &ListOptions{Genus: opt.Genus, Ids: relatedSpeciesIds}, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func characteristicsOptsFromStrains(opt ListOptions) (*ListOptions, error) { | ||||||
|  | 	relatedCharacteristicsIds := make([]int64, 0) | ||||||
|  | 
 | ||||||
|  | 	if opt.Ids == nil || len(opt.Ids) == 0 { | ||||||
|  | 		q := `SELECT DISTINCT m.characteristic_id | ||||||
|  | 				FROM measurements m | ||||||
|  | 				INNER JOIN strains st ON st.id=m.strain_id | ||||||
|  | 				INNER JOIN species sp ON sp.id=st.species_id | ||||||
|  | 				INNER JOIN genera g ON g.id=sp.genus_id AND LOWER(g.genus_name)=LOWER($1);` | ||||||
|  | 		if err := DBH.Select(&relatedCharacteristicsIds, q, opt.Genus); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		var vals []interface{} | ||||||
|  | 		var count int64 = 1 | ||||||
|  | 		q := fmt.Sprintf("SELECT DISTINCT characteristic_id FROM measurements WHERE %s;", valsIn("strain_id", opt.Ids, &vals, &count)) | ||||||
|  | 		if err := DBH.Select(&relatedCharacteristicsIds, q, vals...); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &ListOptions{Genus: opt.Genus, Ids: relatedCharacteristicsIds}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon