mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* fix(alerting): fixed evaluation for no_value condition, fixes #7244 * feat(alerting): moving null library into grafana, fixing handling on no value / no series
This commit is contained in:
parent
bccdd7cad1
commit
d354f3a8af
@ -3,6 +3,7 @@ package dtos
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
@ -51,7 +52,7 @@ type AlertTestResultLog struct {
|
||||
type EvalMatch struct {
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
Metric string `json:"metric"`
|
||||
Value float64 `json:"value"`
|
||||
Value null.Float `json:"value"`
|
||||
}
|
||||
|
||||
type NotificationTestCommand struct {
|
||||
|
@ -96,6 +96,16 @@ func (f Float) MarshalText() ([]byte, error) {
|
||||
return []byte(strconv.FormatFloat(f.Float64, 'f', -1, 64)), nil
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
// It will encode a blank string if this Float is null.
|
||||
func (f Float) String() string {
|
||||
if !f.Valid {
|
||||
return "null"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%1.3f", f.Float64)
|
||||
}
|
||||
|
||||
// SetValid changes this Float's value and also sets it to be non-null.
|
||||
func (f *Float) SetValid(n float64) {
|
||||
f.Float64 = n
|
@ -3,9 +3,9 @@ package conditions
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"gopkg.in/guregu/null.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -3,10 +3,10 @@ package conditions
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopkg.in/guregu/null.v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
|
||||
func evalutorScenario(json string, reducedValue float64, datapoints ...float64) bool {
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
@ -45,18 +46,18 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio
|
||||
emptySerieCount := 0
|
||||
evalMatchCount := 0
|
||||
var matches []*alerting.EvalMatch
|
||||
|
||||
for _, series := range seriesList {
|
||||
reducedValue := c.Reducer.Reduce(series)
|
||||
evalMatch := c.Evaluator.Eval(reducedValue)
|
||||
|
||||
if reducedValue.Valid == false {
|
||||
emptySerieCount++
|
||||
continue
|
||||
}
|
||||
|
||||
if context.IsTestRun {
|
||||
context.Logs = append(context.Logs, &alerting.ResultLogEntry{
|
||||
Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %1.3f", c.Index, evalMatch, series.Name, reducedValue.Float64),
|
||||
Message: fmt.Sprintf("Condition[%d]: Eval: %v, Metric: %s, Value: %s", c.Index, evalMatch, series.Name, reducedValue),
|
||||
})
|
||||
}
|
||||
|
||||
@ -65,11 +66,28 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio
|
||||
|
||||
matches = append(matches, &alerting.EvalMatch{
|
||||
Metric: series.Name,
|
||||
Value: reducedValue.Float64,
|
||||
Value: reducedValue,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// handle no series special case
|
||||
if len(seriesList) == 0 {
|
||||
// eval condition for null value
|
||||
evalMatch := c.Evaluator.Eval(null.FloatFromPtr(nil))
|
||||
|
||||
if context.IsTestRun {
|
||||
context.Logs = append(context.Logs, &alerting.ResultLogEntry{
|
||||
Message: fmt.Sprintf("Condition[%d]: Eval: %v, Query Returned No Series (reduced to null/no value)", evalMatch),
|
||||
})
|
||||
}
|
||||
|
||||
if evalMatch {
|
||||
evalMatchCount++
|
||||
matches = append(matches, &alerting.EvalMatch{Metric: "NoData", Value: null.FloatFromPtr(nil)})
|
||||
}
|
||||
}
|
||||
|
||||
return &alerting.ConditionResult{
|
||||
Firing: evalMatchCount > 0,
|
||||
NoDataFound: emptySerieCount == len(seriesList),
|
||||
|
@ -4,9 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
null "gopkg.in/guregu/null.v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
@ -72,7 +71,38 @@ func TestQueryCondition(t *testing.T) {
|
||||
So(cr.Firing, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("No series", func() {
|
||||
Convey("Should set NoDataFound when condition is gt", func() {
|
||||
ctx.series = tsdb.TimeSeriesSlice{}
|
||||
cr, err := ctx.exec()
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(cr.Firing, ShouldBeFalse)
|
||||
So(cr.NoDataFound, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Should be firing when condition is no_value", func() {
|
||||
ctx.evaluator = `{"type": "no_value", "params": []}`
|
||||
ctx.series = tsdb.TimeSeriesSlice{}
|
||||
cr, err := ctx.exec()
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(cr.Firing, ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Empty series", func() {
|
||||
Convey("Should set Firing if eval match", func() {
|
||||
ctx.evaluator = `{"type": "no_value", "params": []}`
|
||||
ctx.series = tsdb.TimeSeriesSlice{
|
||||
tsdb.NewTimeSeries("test1", tsdb.NewTimeSeriesPointsFromArgs()),
|
||||
}
|
||||
cr, err := ctx.exec()
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(cr.Firing, ShouldBeTrue)
|
||||
})
|
||||
|
||||
Convey("Should set NoDataFound both series are empty", func() {
|
||||
ctx.series = tsdb.TimeSeriesSlice{
|
||||
tsdb.NewTimeSeries("test1", tsdb.NewTimeSeriesPointsFromArgs()),
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
"gopkg.in/guregu/null.v3"
|
||||
)
|
||||
|
||||
type QueryReducer interface {
|
||||
|
@ -3,10 +3,10 @@ package conditions
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopkg.in/guregu/null.v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
||||
func TestSimpleReducer(t *testing.T) {
|
||||
@ -57,6 +57,16 @@ func TestSimpleReducer(t *testing.T) {
|
||||
So(result, ShouldEqual, float64(2))
|
||||
})
|
||||
|
||||
Convey("avg with only nulls", func() {
|
||||
reducer := NewSimpleReducer("avg")
|
||||
series := &tsdb.TimeSeries{
|
||||
Name: "test time serie",
|
||||
}
|
||||
|
||||
series.Points = append(series.Points, tsdb.NewTimePoint(null.FloatFromPtr(nil), 1))
|
||||
So(reducer.Reduce(series).Valid, ShouldEqual, false)
|
||||
})
|
||||
|
||||
Convey("avg of number values and null values should ignore nulls", func() {
|
||||
reducer := NewSimpleReducer("avg")
|
||||
series := &tsdb.TimeSeries{
|
||||
|
@ -1,5 +1,7 @@
|
||||
package alerting
|
||||
|
||||
import "github.com/grafana/grafana/pkg/components/null"
|
||||
|
||||
type Job struct {
|
||||
Offset int64
|
||||
OffsetWait bool
|
||||
@ -14,7 +16,7 @@ type ResultLogEntry struct {
|
||||
}
|
||||
|
||||
type EvalMatch struct {
|
||||
Value float64 `json:"value"`
|
||||
Value null.Float `json:"value"`
|
||||
Metric string `json:"metric"`
|
||||
Tags map[string]string `json:"tags"`
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
@ -63,12 +64,12 @@ func evalMatchesBasedOnState() []*EvalMatch {
|
||||
matches := make([]*EvalMatch, 0)
|
||||
matches = append(matches, &EvalMatch{
|
||||
Metric: "High value",
|
||||
Value: 100,
|
||||
Value: null.FloatFrom(100),
|
||||
})
|
||||
|
||||
matches = append(matches, &EvalMatch{
|
||||
Metric: "Higher Value",
|
||||
Value: 200,
|
||||
Value: null.FloatFrom(200),
|
||||
})
|
||||
|
||||
return matches
|
||||
|
@ -7,8 +7,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
"gopkg.in/guregu/null.v3"
|
||||
)
|
||||
|
||||
type ResponseParser struct{}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package tsdb
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"gopkg.in/guregu/null.v3"
|
||||
)
|
||||
|
||||
type Query struct {
|
||||
|
@ -5,10 +5,9 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
null "gopkg.in/guregu/null.v3"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
@ -14,8 +14,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"gopkg.in/guregu/null.v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
@ -7,10 +7,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/guregu/null.v3"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
|
3
pkg/tsdb/testdata/scenarios.go
vendored
3
pkg/tsdb/testdata/scenarios.go
vendored
@ -6,8 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/guregu/null.v3"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
@ -117,6 +117,7 @@ coreModule.directive('jsonNode', ['ajsRecursiveDirectiveHelper', function jsonNo
|
||||
var isArray = utils.is(scope.value, 'Array');
|
||||
scope.preview = isArray ? '[ ' : '{ ';
|
||||
utils.forKeys(scope.value, function jsonNodeDirectiveLinkForKeys(key, value) {
|
||||
if (value === null) { scope.value[key] = 'null'; }
|
||||
if (isArray) {
|
||||
scope.preview += value + ', ';
|
||||
} else {
|
||||
|
10
vendor/gopkg.in/guregu/null.v3/LICENSE
generated
vendored
10
vendor/gopkg.in/guregu/null.v3/LICENSE
generated
vendored
@ -1,10 +0,0 @@
|
||||
Copyright (c) 2014, Greg Roseberry
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
75
vendor/gopkg.in/guregu/null.v3/README.md
generated
vendored
75
vendor/gopkg.in/guregu/null.v3/README.md
generated
vendored
@ -1,75 +0,0 @@
|
||||
## null [](https://godoc.org/github.com/guregu/null) [](http://gocover.io/github.com/guregu/null)
|
||||
`import "gopkg.in/guregu/null.v3"`
|
||||
|
||||
null is a library with reasonable options for dealing with nullable SQL and JSON values
|
||||
|
||||
There are two packages: `null` and its subpackage `zero`.
|
||||
|
||||
Types in `null` will only be considered null on null input, and will JSON encode to `null`. If you need zero and null be considered separate values, use these.
|
||||
|
||||
Types in `zero` are treated like zero values in Go: blank string input will produce a null `zero.String`, and null Strings will JSON encode to `""`. Zero values of these types will be considered null to SQL. If you need zero and null treated the same, use these.
|
||||
|
||||
All types implement `sql.Scanner` and `driver.Valuer`, so you can use this library in place of `sql.NullXXX`. All types also implement: `encoding.TextMarshaler`, `encoding.TextUnmarshaler`, `json.Marshaler`, and `json.Unmarshaler`.
|
||||
|
||||
### null package
|
||||
|
||||
`import "gopkg.in/guregu/null.v3"`
|
||||
|
||||
#### null.String
|
||||
Nullable string.
|
||||
|
||||
Marshals to JSON null if SQL source data is null. Zero (blank) input will not produce a null String. Can unmarshal from `sql.NullString` JSON input or string input.
|
||||
|
||||
#### null.Int
|
||||
Nullable int64.
|
||||
|
||||
Marshals to JSON null if SQL source data is null. Zero input will not produce a null Int. Can unmarshal from `sql.NullInt64` JSON input.
|
||||
|
||||
#### null.Float
|
||||
Nullable float64.
|
||||
|
||||
Marshals to JSON null if SQL source data is null. Zero input will not produce a null Float. Can unmarshal from `sql.NullFloat64` JSON input.
|
||||
|
||||
#### null.Bool
|
||||
Nullable bool.
|
||||
|
||||
Marshals to JSON null if SQL source data is null. False input will not produce a null Bool. Can unmarshal from `sql.NullBool` JSON input.
|
||||
|
||||
#### null.Time
|
||||
|
||||
Marshals to JSON null if SQL source data is null. Uses `time.Time`'s marshaler. Can unmarshal from `pq.NullTime` and similar JSON input.
|
||||
|
||||
### zero package
|
||||
|
||||
`import "gopkg.in/guregu/null.v3/zero"`
|
||||
|
||||
#### zero.String
|
||||
Nullable string.
|
||||
|
||||
Will marshal to a blank string if null. Blank string input produces a null String. Null values and zero values are considered equivalent. Can unmarshal from `sql.NullString` JSON input.
|
||||
|
||||
#### zero.Int
|
||||
Nullable int64.
|
||||
|
||||
Will marshal to 0 if null. 0 produces a null Int. Null values and zero values are considered equivalent. Can unmarshal from `sql.NullInt64` JSON input.
|
||||
|
||||
#### zero.Float
|
||||
Nullable float64.
|
||||
|
||||
Will marshal to 0 if null. 0.0 produces a null Float. Null values and zero values are considered equivalent. Can unmarshal from `sql.NullFloat64` JSON input.
|
||||
|
||||
#### zero.Bool
|
||||
Nullable bool.
|
||||
|
||||
Will marshal to false if null. `false` produces a null Float. Null values and zero values are considered equivalent. Can unmarshal from `sql.NullBool` JSON input.
|
||||
|
||||
#### zero.Time
|
||||
|
||||
Will marshal to the zero time if null. Uses `time.Time`'s marshaler. Can unmarshal from `pq.NullTime` and similar JSON input.
|
||||
|
||||
|
||||
### Bugs
|
||||
`json`'s `",omitempty"` struct tag does not work correctly right now. It will never omit a null or empty String. This might be [fixed eventually](https://github.com/golang/go/issues/4357).
|
||||
|
||||
### License
|
||||
BSD
|
129
vendor/gopkg.in/guregu/null.v3/bool.go
generated
vendored
129
vendor/gopkg.in/guregu/null.v3/bool.go
generated
vendored
@ -1,129 +0,0 @@
|
||||
package null
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Bool is a nullable bool.
|
||||
// It does not consider false values to be null.
|
||||
// It will decode to null, not false, if null.
|
||||
type Bool struct {
|
||||
sql.NullBool
|
||||
}
|
||||
|
||||
// NewBool creates a new Bool
|
||||
func NewBool(b bool, valid bool) Bool {
|
||||
return Bool{
|
||||
NullBool: sql.NullBool{
|
||||
Bool: b,
|
||||
Valid: valid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// BoolFrom creates a new Bool that will always be valid.
|
||||
func BoolFrom(b bool) Bool {
|
||||
return NewBool(b, true)
|
||||
}
|
||||
|
||||
// BoolFromPtr creates a new Bool that will be null if f is nil.
|
||||
func BoolFromPtr(b *bool) Bool {
|
||||
if b == nil {
|
||||
return NewBool(false, false)
|
||||
}
|
||||
return NewBool(*b, true)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
// It supports number and null input.
|
||||
// 0 will not be considered a null Bool.
|
||||
// It also supports unmarshalling a sql.NullBool.
|
||||
func (b *Bool) UnmarshalJSON(data []byte) error {
|
||||
var err error
|
||||
var v interface{}
|
||||
if err = json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
switch x := v.(type) {
|
||||
case bool:
|
||||
b.Bool = x
|
||||
case map[string]interface{}:
|
||||
err = json.Unmarshal(data, &b.NullBool)
|
||||
case nil:
|
||||
b.Valid = false
|
||||
return nil
|
||||
default:
|
||||
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Bool", reflect.TypeOf(v).Name())
|
||||
}
|
||||
b.Valid = err == nil
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
// It will unmarshal to a null Bool if the input is a blank or not an integer.
|
||||
// It will return an error if the input is not an integer, blank, or "null".
|
||||
func (b *Bool) UnmarshalText(text []byte) error {
|
||||
str := string(text)
|
||||
switch str {
|
||||
case "", "null":
|
||||
b.Valid = false
|
||||
return nil
|
||||
case "true":
|
||||
b.Bool = true
|
||||
case "false":
|
||||
b.Bool = false
|
||||
default:
|
||||
b.Valid = false
|
||||
return errors.New("invalid input:" + str)
|
||||
}
|
||||
b.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
// It will encode null if this Bool is null.
|
||||
func (b Bool) MarshalJSON() ([]byte, error) {
|
||||
if !b.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
if !b.Bool {
|
||||
return []byte("false"), nil
|
||||
}
|
||||
return []byte("true"), nil
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
// It will encode a blank string if this Bool is null.
|
||||
func (b Bool) MarshalText() ([]byte, error) {
|
||||
if !b.Valid {
|
||||
return []byte{}, nil
|
||||
}
|
||||
if !b.Bool {
|
||||
return []byte("false"), nil
|
||||
}
|
||||
return []byte("true"), nil
|
||||
}
|
||||
|
||||
// SetValid changes this Bool's value and also sets it to be non-null.
|
||||
func (b *Bool) SetValid(v bool) {
|
||||
b.Bool = v
|
||||
b.Valid = true
|
||||
}
|
||||
|
||||
// Ptr returns a pointer to this Bool's value, or a nil pointer if this Bool is null.
|
||||
func (b Bool) Ptr() *bool {
|
||||
if !b.Valid {
|
||||
return nil
|
||||
}
|
||||
return &b.Bool
|
||||
}
|
||||
|
||||
// IsZero returns true for invalid Bools, for future omitempty support (Go 1.4?)
|
||||
// A non-null Bool with a 0 value will not be considered zero.
|
||||
func (b Bool) IsZero() bool {
|
||||
return !b.Valid
|
||||
}
|
118
vendor/gopkg.in/guregu/null.v3/int.go
generated
vendored
118
vendor/gopkg.in/guregu/null.v3/int.go
generated
vendored
@ -1,118 +0,0 @@
|
||||
package null
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Int is an nullable int64.
|
||||
// It does not consider zero values to be null.
|
||||
// It will decode to null, not zero, if null.
|
||||
type Int struct {
|
||||
sql.NullInt64
|
||||
}
|
||||
|
||||
// NewInt creates a new Int
|
||||
func NewInt(i int64, valid bool) Int {
|
||||
return Int{
|
||||
NullInt64: sql.NullInt64{
|
||||
Int64: i,
|
||||
Valid: valid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// IntFrom creates a new Int that will always be valid.
|
||||
func IntFrom(i int64) Int {
|
||||
return NewInt(i, true)
|
||||
}
|
||||
|
||||
// IntFromPtr creates a new Int that be null if i is nil.
|
||||
func IntFromPtr(i *int64) Int {
|
||||
if i == nil {
|
||||
return NewInt(0, false)
|
||||
}
|
||||
return NewInt(*i, true)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
// It supports number and null input.
|
||||
// 0 will not be considered a null Int.
|
||||
// It also supports unmarshalling a sql.NullInt64.
|
||||
func (i *Int) UnmarshalJSON(data []byte) error {
|
||||
var err error
|
||||
var v interface{}
|
||||
if err = json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
switch v.(type) {
|
||||
case float64:
|
||||
// Unmarshal again, directly to int64, to avoid intermediate float64
|
||||
err = json.Unmarshal(data, &i.Int64)
|
||||
case map[string]interface{}:
|
||||
err = json.Unmarshal(data, &i.NullInt64)
|
||||
case nil:
|
||||
i.Valid = false
|
||||
return nil
|
||||
default:
|
||||
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Int", reflect.TypeOf(v).Name())
|
||||
}
|
||||
i.Valid = err == nil
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
// It will unmarshal to a null Int if the input is a blank or not an integer.
|
||||
// It will return an error if the input is not an integer, blank, or "null".
|
||||
func (i *Int) UnmarshalText(text []byte) error {
|
||||
str := string(text)
|
||||
if str == "" || str == "null" {
|
||||
i.Valid = false
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
i.Int64, err = strconv.ParseInt(string(text), 10, 64)
|
||||
i.Valid = err == nil
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
// It will encode null if this Int is null.
|
||||
func (i Int) MarshalJSON() ([]byte, error) {
|
||||
if !i.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte(strconv.FormatInt(i.Int64, 10)), nil
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
// It will encode a blank string if this Int is null.
|
||||
func (i Int) MarshalText() ([]byte, error) {
|
||||
if !i.Valid {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return []byte(strconv.FormatInt(i.Int64, 10)), nil
|
||||
}
|
||||
|
||||
// SetValid changes this Int's value and also sets it to be non-null.
|
||||
func (i *Int) SetValid(n int64) {
|
||||
i.Int64 = n
|
||||
i.Valid = true
|
||||
}
|
||||
|
||||
// Ptr returns a pointer to this Int's value, or a nil pointer if this Int is null.
|
||||
func (i Int) Ptr() *int64 {
|
||||
if !i.Valid {
|
||||
return nil
|
||||
}
|
||||
return &i.Int64
|
||||
}
|
||||
|
||||
// IsZero returns true for invalid Ints, for future omitempty support (Go 1.4?)
|
||||
// A non-null Int with a 0 value will not be considered zero.
|
||||
func (i Int) IsZero() bool {
|
||||
return !i.Valid
|
||||
}
|
110
vendor/gopkg.in/guregu/null.v3/string.go
generated
vendored
110
vendor/gopkg.in/guregu/null.v3/string.go
generated
vendored
@ -1,110 +0,0 @@
|
||||
// Package null contains SQL types that consider zero input and null input as separate values,
|
||||
// with convenient support for JSON and text marshaling.
|
||||
// Types in this package will always encode to their null value if null.
|
||||
// Use the zero subpackage if you want zero values and null to be treated the same.
|
||||
package null
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// String is a nullable string. It supports SQL and JSON serialization.
|
||||
// It will marshal to null if null. Blank string input will be considered null.
|
||||
type String struct {
|
||||
sql.NullString
|
||||
}
|
||||
|
||||
// StringFrom creates a new String that will never be blank.
|
||||
func StringFrom(s string) String {
|
||||
return NewString(s, true)
|
||||
}
|
||||
|
||||
// StringFromPtr creates a new String that be null if s is nil.
|
||||
func StringFromPtr(s *string) String {
|
||||
if s == nil {
|
||||
return NewString("", false)
|
||||
}
|
||||
return NewString(*s, true)
|
||||
}
|
||||
|
||||
// NewString creates a new String
|
||||
func NewString(s string, valid bool) String {
|
||||
return String{
|
||||
NullString: sql.NullString{
|
||||
String: s,
|
||||
Valid: valid,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
// It supports string and null input. Blank string input does not produce a null String.
|
||||
// It also supports unmarshalling a sql.NullString.
|
||||
func (s *String) UnmarshalJSON(data []byte) error {
|
||||
var err error
|
||||
var v interface{}
|
||||
if err = json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
switch x := v.(type) {
|
||||
case string:
|
||||
s.String = x
|
||||
case map[string]interface{}:
|
||||
err = json.Unmarshal(data, &s.NullString)
|
||||
case nil:
|
||||
s.Valid = false
|
||||
return nil
|
||||
default:
|
||||
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.String", reflect.TypeOf(v).Name())
|
||||
}
|
||||
s.Valid = err == nil
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
// It will encode null if this String is null.
|
||||
func (s String) MarshalJSON() ([]byte, error) {
|
||||
if !s.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(s.String)
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
// It will encode a blank string when this String is null.
|
||||
func (s String) MarshalText() ([]byte, error) {
|
||||
if !s.Valid {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return []byte(s.String), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
// It will unmarshal to a null String if the input is a blank string.
|
||||
func (s *String) UnmarshalText(text []byte) error {
|
||||
s.String = string(text)
|
||||
s.Valid = s.String != ""
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetValid changes this String's value and also sets it to be non-null.
|
||||
func (s *String) SetValid(v string) {
|
||||
s.String = v
|
||||
s.Valid = true
|
||||
}
|
||||
|
||||
// Ptr returns a pointer to this String's value, or a nil pointer if this String is null.
|
||||
func (s String) Ptr() *string {
|
||||
if !s.Valid {
|
||||
return nil
|
||||
}
|
||||
return &s.String
|
||||
}
|
||||
|
||||
// IsZero returns true for null strings, for potential future omitempty support.
|
||||
func (s String) IsZero() bool {
|
||||
return !s.Valid
|
||||
}
|
135
vendor/gopkg.in/guregu/null.v3/time.go
generated
vendored
135
vendor/gopkg.in/guregu/null.v3/time.go
generated
vendored
@ -1,135 +0,0 @@
|
||||
package null
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time is a nullable time.Time. It supports SQL and JSON serialization.
|
||||
// It will marshal to null if null.
|
||||
type Time struct {
|
||||
Time time.Time
|
||||
Valid bool
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (t *Time) Scan(value interface{}) error {
|
||||
var err error
|
||||
switch x := value.(type) {
|
||||
case time.Time:
|
||||
t.Time = x
|
||||
case nil:
|
||||
t.Valid = false
|
||||
return nil
|
||||
default:
|
||||
err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value)
|
||||
}
|
||||
t.Valid = err == nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (t Time) Value() (driver.Value, error) {
|
||||
if !t.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return t.Time, nil
|
||||
}
|
||||
|
||||
// NewTime creates a new Time.
|
||||
func NewTime(t time.Time, valid bool) Time {
|
||||
return Time{
|
||||
Time: t,
|
||||
Valid: valid,
|
||||
}
|
||||
}
|
||||
|
||||
// TimeFrom creates a new Time that will always be valid.
|
||||
func TimeFrom(t time.Time) Time {
|
||||
return NewTime(t, true)
|
||||
}
|
||||
|
||||
// TimeFromPtr creates a new Time that will be null if t is nil.
|
||||
func TimeFromPtr(t *time.Time) Time {
|
||||
if t == nil {
|
||||
return NewTime(time.Time{}, false)
|
||||
}
|
||||
return NewTime(*t, true)
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
// It will encode null if this time is null.
|
||||
func (t Time) MarshalJSON() ([]byte, error) {
|
||||
if !t.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return t.Time.MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
// It supports string, object (e.g. pq.NullTime and friends)
|
||||
// and null input.
|
||||
func (t *Time) UnmarshalJSON(data []byte) error {
|
||||
var err error
|
||||
var v interface{}
|
||||
if err = json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
switch x := v.(type) {
|
||||
case string:
|
||||
err = t.Time.UnmarshalJSON(data)
|
||||
case map[string]interface{}:
|
||||
ti, tiOK := x["Time"].(string)
|
||||
valid, validOK := x["Valid"].(bool)
|
||||
if !tiOK || !validOK {
|
||||
return fmt.Errorf(`json: unmarshalling object into Go value of type null.Time requires key "Time" to be of type string and key "Valid" to be of type bool; found %T and %T, respectively`, x["Time"], x["Valid"])
|
||||
}
|
||||
err = t.Time.UnmarshalText([]byte(ti))
|
||||
t.Valid = valid
|
||||
return err
|
||||
case nil:
|
||||
t.Valid = false
|
||||
return nil
|
||||
default:
|
||||
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Time", reflect.TypeOf(v).Name())
|
||||
}
|
||||
t.Valid = err == nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (t Time) MarshalText() ([]byte, error) {
|
||||
if !t.Valid {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return t.Time.MarshalText()
|
||||
}
|
||||
|
||||
func (t *Time) UnmarshalText(text []byte) error {
|
||||
str := string(text)
|
||||
if str == "" || str == "null" {
|
||||
t.Valid = false
|
||||
return nil
|
||||
}
|
||||
if err := t.Time.UnmarshalText(text); err != nil {
|
||||
return err
|
||||
}
|
||||
t.Valid = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetValid changes this Time's value and sets it to be non-null.
|
||||
func (t *Time) SetValid(v time.Time) {
|
||||
t.Time = v
|
||||
t.Valid = true
|
||||
}
|
||||
|
||||
// Ptr returns a pointer to this Time's value, or a nil pointer if this Time is null.
|
||||
func (t Time) Ptr() *time.Time {
|
||||
if !t.Valid {
|
||||
return nil
|
||||
}
|
||||
return &t.Time
|
||||
}
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -411,12 +411,6 @@
|
||||
"path": "gopkg.in/gomail.v2",
|
||||
"revision": "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1",
|
||||
"revisionTime": "2016-04-11T21:29:32Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "PoHLopxwkiXxa3uVhezeq/qJ/Vo=",
|
||||
"path": "gopkg.in/guregu/null.v3",
|
||||
"revision": "41961cea0328defc5f95c1c473f89ebf0d1813f6",
|
||||
"revisionTime": "2016-02-28T00:53:16Z"
|
||||
}
|
||||
],
|
||||
"rootPath": "github.com/grafana/grafana"
|
||||
|
Loading…
Reference in New Issue
Block a user