Repository: prometheus/prometheus
File: promql/functions.go (Go)

Code before:
		median := quantile(0.5, values)
		values = make(vectorByValueHeap, 0, len(s.Floats))
		for _, f := range s.Floats {
			values = append(values, Sample{F: math.Abs(f.F - median)})
		}
		return quantile(0.5, values)
	}), annos
}

// === ts_of_last_over_time(Matrix parser.ValueTypeMatrix) (Vector, Notes)  ===
func funcTsOfLastOverTime(vals []parser.Value, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
	el := vals[0].(Matrix)[0]

	var tf float64
	if len(el.Floats) > 0 {
		tf = float64(el.Floats[len(el.Floats)-1].T / 1000)
	}

	var th float64
	if len(el.Histograms) > 0 {
		th = float64(el.Floats[len(el.Floats)-1].T / 1000)
	}

	return append(enh.Out, Sample{
		Metric: el.Metric,
		F:      max(tf, th),
	}), nil
}

// === ts_of_max_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
func funcTsOfMaxOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
	return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
		return (cur >= maxVal) || math.IsNaN(maxVal)
	}, true)
}

// === ts_of_min_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
func funcTsOfMinOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
	return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
		return (cur <= maxVal) || math.IsNaN(maxVal)
	}, true)
}

// compareOverTime is a helper used by funcMaxOverTime and funcMinOverTime.
func compareOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper, compareFn func(float64, float64) bool, returnTimestamp bool) (Vector, annotations.Annotations) {
	samples := vals[0].(Matrix)[0]
	var annos annotations.Annotations
	if len(samples.Floats) == 0 {
		return enh.Out, nil
	}
	if len(samples.Histograms) > 0 {

Review comment (suggestion):
Maybe it's cleaner to make both `tf` and `th` int64, don't divide by 1000 above, and then do
```suggestion
		F:      float64(max(tf, th))/1000,
```
here.

Code after:
		median := quantile(0.5, values)
		values = make(vectorByValueHeap, 0, len(s.Floats))
		for _, f := range s.Floats {
			values = append(values, Sample{F: math.Abs(f.F - median)})
		}
		return quantile(0.5, values)
	}), annos
}

// === ts_of_last_over_time(Matrix parser.ValueTypeMatrix) (Vector, Notes)  ===
func funcTsOfLastOverTime(vals []parser.Value, _ parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
	el := vals[0].(Matrix)[0]

	var tf int64
	if len(el.Floats) > 0 {
		tf = el.Floats[len(el.Floats)-1].T
	}

	var th int64
	if len(el.Histograms) > 0 {
		th = el.Floats[len(el.Floats)-1].T
	}

	return append(enh.Out, Sample{
		Metric: el.Metric,
		F:      float64(max(tf, th)) / 1000,
	}), nil
}

// === ts_of_max_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
func funcTsOfMaxOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
	return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
		return (cur >= maxVal) || math.IsNaN(maxVal)
	}, true)
}

// === ts_of_min_over_time(Matrix parser.ValueTypeMatrix) (Vector, Annotations) ===
func funcTsOfMinOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
	return compareOverTime(vals, args, enh, func(cur, maxVal float64) bool {
		return (cur <= maxVal) || math.IsNaN(maxVal)
	}, true)
}

// compareOverTime is a helper used by funcMaxOverTime and funcMinOverTime.
func compareOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper, compareFn func(float64, float64) bool, returnTimestamp bool) (Vector, annotations.Annotations) {
	samples := vals[0].(Matrix)[0]
	var annos annotations.Annotations
	if len(samples.Floats) == 0 {
		return enh.Out, nil
	}
	if len(samples.Histograms) > 0 {