mirror of https://github.com/grafana/grafana.git
				
				
				
			SSE: Change math expression to accept any value convertible to float (#34996)
* SSE: Change math expression to accept any scalar value * Apply suggestions from code review * Update test * Remove TODO
This commit is contained in:
		
							parent
							
								
									b558d32502
								
							
						
					
					
						commit
						eeb84d09c2
					
				
							
								
								
									
										2
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										2
									
								
								go.mod
								
								
								
								
							|  | @ -52,7 +52,7 @@ require ( | ||||||
| 	github.com/gosimple/slug v1.9.0 | 	github.com/gosimple/slug v1.9.0 | ||||||
| 	github.com/grafana/grafana-aws-sdk v0.4.0 | 	github.com/grafana/grafana-aws-sdk v0.4.0 | ||||||
| 	github.com/grafana/grafana-live-sdk v0.0.6 | 	github.com/grafana/grafana-live-sdk v0.0.6 | ||||||
| 	github.com/grafana/grafana-plugin-sdk-go v0.102.0 | 	github.com/grafana/grafana-plugin-sdk-go v0.104.0 | ||||||
| 	github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103 | 	github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103 | ||||||
| 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 | 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 | ||||||
| 	github.com/hashicorp/go-hclog v0.16.0 | 	github.com/hashicorp/go-hclog v0.16.0 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										2
									
								
								go.sum
								
								
								
								
							|  | @ -922,6 +922,8 @@ github.com/grafana/grafana-plugin-sdk-go v0.79.0/go.mod h1:NvxLzGkVhnoBKwzkst6CF | ||||||
| github.com/grafana/grafana-plugin-sdk-go v0.91.0/go.mod h1:Ot3k7nY7P6DXmUsDgKvNB7oG1v7PRyTdmnYVoS554bU= | github.com/grafana/grafana-plugin-sdk-go v0.91.0/go.mod h1:Ot3k7nY7P6DXmUsDgKvNB7oG1v7PRyTdmnYVoS554bU= | ||||||
| github.com/grafana/grafana-plugin-sdk-go v0.102.0 h1:Pknh7mlOaJvdhPgKHxcimDOSd9h29eSpA34W0/sOF6c= | github.com/grafana/grafana-plugin-sdk-go v0.102.0 h1:Pknh7mlOaJvdhPgKHxcimDOSd9h29eSpA34W0/sOF6c= | ||||||
| github.com/grafana/grafana-plugin-sdk-go v0.102.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= | github.com/grafana/grafana-plugin-sdk-go v0.102.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= | ||||||
|  | github.com/grafana/grafana-plugin-sdk-go v0.104.0 h1:Ij2tPdEasSjCb2MxHaaiylyW4RLVZYyWpApzN/mlTxo= | ||||||
|  | github.com/grafana/grafana-plugin-sdk-go v0.104.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= | ||||||
| github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103 h1:qCmofFVwQR9QnsinstVqI1NPLMVl33jNCnOCXEAVn6E= | github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103 h1:qCmofFVwQR9QnsinstVqI1NPLMVl33jNCnOCXEAVn6E= | ||||||
| github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103/go.mod h1:GHIsn+EohCChsdu5YouNZewqLeV9L2FNw4DEJU3P9qE= | github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103/go.mod h1:GHIsn+EohCChsdu5YouNZewqLeV9L2FNw4DEJU3P9qE= | ||||||
| github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= | ||||||
|  |  | ||||||
|  | @ -30,10 +30,27 @@ func makeNumber(name string, labels data.Labels, f *float64) Number { | ||||||
| 	return newNumber | 	return newNumber | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func unixTimePointer(sec, nsec int64) *time.Time { | ||||||
|  | 	t := time.Unix(sec, nsec) | ||||||
|  | 	return &t | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func float64Pointer(f float64) *float64 { | func float64Pointer(f float64) *float64 { | ||||||
| 	return &f | 	return &f | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func strPointer(s string) *string { | ||||||
|  | 	return &s | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func int64Pointer(i int64) *int64 { | ||||||
|  | 	return &i | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func boolPointer(b bool) *bool { | ||||||
|  | 	return &b | ||||||
|  | } | ||||||
|  | 
 | ||||||
| var aSeries = Vars{ | var aSeries = Vars{ | ||||||
| 	"A": Results{ | 	"A": Results{ | ||||||
| 		[]Value{ | 		[]Value{ | ||||||
|  |  | ||||||
|  | @ -18,8 +18,6 @@ const seriesTypeValIdx = 1 | ||||||
| // Series has a time.Time and a *float64 fields.
 | // Series has a time.Time and a *float64 fields.
 | ||||||
| type Series struct { | type Series struct { | ||||||
| 	Frame *data.Frame | 	Frame *data.Frame | ||||||
| 	// TODO:
 |  | ||||||
| 	// - Value can be different number types
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SeriesFromFrame validates that the dataframe can be considered a Series type
 | // SeriesFromFrame validates that the dataframe can be considered a Series type
 | ||||||
|  | @ -49,6 +47,26 @@ FIELDS: | ||||||
| 			valueNullable = true | 			valueNullable = true | ||||||
| 			valueIdx = i | 			valueIdx = i | ||||||
| 		default: | 		default: | ||||||
|  | 			// Handle default case
 | ||||||
|  | 			// try to convert to *float64
 | ||||||
|  | 			var convertedField *data.Field | ||||||
|  | 			for j := 0; j < field.Len(); j++ { | ||||||
|  | 				ff, err := field.NullableFloatAt(j) | ||||||
|  | 				if err != nil { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				if convertedField == nil { // initialise field
 | ||||||
|  | 					convertedField = data.NewFieldFromFieldType(data.FieldTypeNullableFloat64, field.Len()) | ||||||
|  | 					convertedField.Name = field.Name | ||||||
|  | 					convertedField.Labels = field.Labels | ||||||
|  | 				} | ||||||
|  | 				convertedField.Set(j, ff) | ||||||
|  | 			} | ||||||
|  | 			if convertedField != nil { | ||||||
|  | 				frame.Fields[i] = convertedField | ||||||
|  | 				valueNullable = true | ||||||
|  | 				valueIdx = i | ||||||
|  | 			} | ||||||
| 			if valueIdx != -1 && timeIdx != -1 { | 			if valueIdx != -1 && timeIdx != -1 { | ||||||
| 				break FIELDS | 				break FIELDS | ||||||
| 			} | 			} | ||||||
|  | @ -65,7 +83,7 @@ FIELDS: | ||||||
| 	if timeNullable { // make time not nullable if it is in the input
 | 	if timeNullable { // make time not nullable if it is in the input
 | ||||||
| 		timeSlice := make([]time.Time, 0, frame.Fields[timeIdx].Len()) | 		timeSlice := make([]time.Time, 0, frame.Fields[timeIdx].Len()) | ||||||
| 		for rowIdx := 0; rowIdx < frame.Fields[timeIdx].Len(); rowIdx++ { | 		for rowIdx := 0; rowIdx < frame.Fields[timeIdx].Len(); rowIdx++ { | ||||||
| 			val, ok := frame.At(0, rowIdx).(*time.Time) | 			val, ok := frame.At(timeIdx, rowIdx).(*time.Time) | ||||||
| 			if !ok { | 			if !ok { | ||||||
| 				return s, fmt.Errorf("unexpected time type, expected *time.Time but got %T", val) | 				return s, fmt.Errorf("unexpected time type, expected *time.Time but got %T", val) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -136,6 +136,132 @@ func TestSeriesFromFrame(t *testing.T) { | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "[]*int, []*time frame should convert", | ||||||
|  | 			frame: &data.Frame{ | ||||||
|  | 				Name: "test", | ||||||
|  | 				Fields: []*data.Field{ | ||||||
|  | 					data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), | ||||||
|  | 					data.NewField("value", nil, []*int64{int64Pointer(5)}), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			errIs: assert.NoError, | ||||||
|  | 			Is:    assert.Equal, | ||||||
|  | 			Series: Series{ | ||||||
|  | 				Frame: &data.Frame{ | ||||||
|  | 					Name: "test", | ||||||
|  | 					Fields: []*data.Field{ | ||||||
|  | 						data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), | ||||||
|  | 						data.NewField("value", nil, []*float64{float64Pointer(5)}), | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "[]int, []*time frame should convert", | ||||||
|  | 			frame: &data.Frame{ | ||||||
|  | 				Name: "test", | ||||||
|  | 				Fields: []*data.Field{ | ||||||
|  | 					data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), | ||||||
|  | 					data.NewField("value", nil, []int64{5}), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			errIs: assert.NoError, | ||||||
|  | 			Is:    assert.Equal, | ||||||
|  | 			Series: Series{ | ||||||
|  | 				Frame: &data.Frame{ | ||||||
|  | 					Name: "test", | ||||||
|  | 					Fields: []*data.Field{ | ||||||
|  | 						data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), | ||||||
|  | 						data.NewField("value", nil, []*float64{float64Pointer(5)}), | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "[]string, []*time frame should convert", | ||||||
|  | 			frame: &data.Frame{ | ||||||
|  | 				Name: "test", | ||||||
|  | 				Fields: []*data.Field{ | ||||||
|  | 					data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), | ||||||
|  | 					data.NewField("value", nil, []string{"5"}), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			errIs: assert.NoError, | ||||||
|  | 			Is:    assert.Equal, | ||||||
|  | 			Series: Series{ | ||||||
|  | 				Frame: &data.Frame{ | ||||||
|  | 					Name: "test", | ||||||
|  | 					Fields: []*data.Field{ | ||||||
|  | 						data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), | ||||||
|  | 						data.NewField("value", nil, []*float64{float64Pointer(5)}), | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "[]*string, []*time frame should convert", | ||||||
|  | 			frame: &data.Frame{ | ||||||
|  | 				Name: "test", | ||||||
|  | 				Fields: []*data.Field{ | ||||||
|  | 					data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), | ||||||
|  | 					data.NewField("value", nil, []*string{strPointer("5")}), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			errIs: assert.NoError, | ||||||
|  | 			Is:    assert.Equal, | ||||||
|  | 			Series: Series{ | ||||||
|  | 				Frame: &data.Frame{ | ||||||
|  | 					Name: "test", | ||||||
|  | 					Fields: []*data.Field{ | ||||||
|  | 						data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), | ||||||
|  | 						data.NewField("value", nil, []*float64{float64Pointer(5)}), | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "[]bool, []*time frame should convert", | ||||||
|  | 			frame: &data.Frame{ | ||||||
|  | 				Name: "test", | ||||||
|  | 				Fields: []*data.Field{ | ||||||
|  | 					data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), | ||||||
|  | 					data.NewField("value", nil, []bool{true}), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			errIs: assert.NoError, | ||||||
|  | 			Is:    assert.Equal, | ||||||
|  | 			Series: Series{ | ||||||
|  | 				Frame: &data.Frame{ | ||||||
|  | 					Name: "test", | ||||||
|  | 					Fields: []*data.Field{ | ||||||
|  | 						data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), | ||||||
|  | 						data.NewField("value", nil, []*float64{float64Pointer(1)}), | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "[]*bool, []*time frame should convert", | ||||||
|  | 			frame: &data.Frame{ | ||||||
|  | 				Name: "test", | ||||||
|  | 				Fields: []*data.Field{ | ||||||
|  | 					data.NewField("time", nil, []*time.Time{unixTimePointer(5, 0)}), | ||||||
|  | 					data.NewField("value", nil, []*bool{boolPointer(true)}), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			errIs: assert.NoError, | ||||||
|  | 			Is:    assert.Equal, | ||||||
|  | 			Series: Series{ | ||||||
|  | 				Frame: &data.Frame{ | ||||||
|  | 					Name: "test", | ||||||
|  | 					Fields: []*data.Field{ | ||||||
|  | 						data.NewField("time", nil, []time.Time{time.Unix(5, 0)}), | ||||||
|  | 						data.NewField("value", nil, []*float64{float64Pointer(1)}), | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "[]*time, []*time frame should error", | 			name: "[]*time, []*time frame should error", | ||||||
| 			frame: &data.Frame{ | 			frame: &data.Frame{ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue