feat(http): define external preprocessing options via http api (#11939)
Closes #11702.pull/11916/head
parent
817e45d60d
commit
af258e62e7
2
go.mod
2
go.mod
|
@ -62,7 +62,7 @@ require (
|
|||
github.com/hashicorp/vault v0.11.5
|
||||
github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20181106190520-2236f141171e // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
|
||||
github.com/influxdata/flux v0.20.0
|
||||
github.com/influxdata/flux v0.20.1-0.20190220204516-5138168746ee
|
||||
github.com/influxdata/influxql v0.0.0-20180925231337-1cbfca8e56b6
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368
|
||||
github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -224,8 +224,8 @@ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
|||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/flux v0.20.0 h1:v+R/pQGamzx5XVB03dCuVnHPnoreLTNLDrrNJkS5xEA=
|
||||
github.com/influxdata/flux v0.20.0/go.mod h1:0f5Yrm4VPSd/Ne6jIVOVtPo0MFe6jpLCr6vdaZYp7wY=
|
||||
github.com/influxdata/flux v0.20.1-0.20190220204516-5138168746ee h1:Mlg8OS1IHpAHOHlrsb0oi/Rn6yVkI68IrqCbkWbXWBQ=
|
||||
github.com/influxdata/flux v0.20.1-0.20190220204516-5138168746ee/go.mod h1:0f5Yrm4VPSd/Ne6jIVOVtPo0MFe6jpLCr6vdaZYp7wY=
|
||||
github.com/influxdata/goreleaser v0.97.0-influx/go.mod h1:MnjA0e0Uq6ISqjG1WxxMAl+3VS1QYjILSWVnMYDxasE=
|
||||
github.com/influxdata/influxql v0.0.0-20180925231337-1cbfca8e56b6 h1:CFx+pP90q/qg3spoiZjf8donE4WpAdjeJfPOcoNqkWo=
|
||||
github.com/influxdata/influxql v0.0.0-20180925231337-1cbfca8e56b6/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo=
|
||||
|
|
|
@ -16,25 +16,23 @@ import (
|
|||
"github.com/influxdata/flux"
|
||||
"github.com/influxdata/flux/ast"
|
||||
"github.com/influxdata/flux/csv"
|
||||
"github.com/influxdata/flux/interpreter"
|
||||
"github.com/influxdata/flux/lang"
|
||||
"github.com/influxdata/flux/parser"
|
||||
"github.com/influxdata/flux/semantic"
|
||||
"github.com/influxdata/flux/values"
|
||||
platform "github.com/influxdata/influxdb"
|
||||
"github.com/influxdata/influxdb"
|
||||
"github.com/influxdata/influxdb/query"
|
||||
"github.com/influxdata/influxql"
|
||||
)
|
||||
|
||||
// QueryRequest is a flux query request.
|
||||
type QueryRequest struct {
|
||||
Extern *ast.File `json:"extern,omitempty"`
|
||||
Spec *flux.Spec `json:"spec,omitempty"`
|
||||
AST *ast.Package `json:"ast,omitempty"`
|
||||
Query string `json:"query"`
|
||||
Type string `json:"type"`
|
||||
Dialect QueryDialect `json:"dialect"`
|
||||
|
||||
Org *platform.Organization `json:"-"`
|
||||
Org *influxdb.Organization `json:"-"`
|
||||
}
|
||||
|
||||
// QueryDialect is the formatting options for the query response.
|
||||
|
@ -70,6 +68,13 @@ func (r QueryRequest) Validate() error {
|
|||
return errors.New(`request body requires either query, spec, or AST`)
|
||||
}
|
||||
|
||||
if r.Spec != nil && r.Extern != nil {
|
||||
return &influxdb.Error{
|
||||
Code: influxdb.EInvalid,
|
||||
Msg: "request body cannot specify both a spec and external declarations",
|
||||
}
|
||||
}
|
||||
|
||||
if r.Type != "flux" {
|
||||
return fmt.Errorf(`unknown query type: %s`, r.Type)
|
||||
}
|
||||
|
@ -206,47 +211,6 @@ func columnFromCharacter(q string, char int) int {
|
|||
|
||||
var influxqlParseErrorRE = regexp.MustCompile(`^(.+) at line (\d+), char (\d+)$`)
|
||||
|
||||
func nowFunc(now time.Time) values.Function {
|
||||
timeVal := values.NewTime(values.ConvertTime(now))
|
||||
ftype := semantic.NewFunctionPolyType(semantic.FunctionPolySignature{
|
||||
Return: semantic.Time,
|
||||
})
|
||||
call := func(args values.Object) (values.Value, error) {
|
||||
return timeVal, nil
|
||||
}
|
||||
sideEffect := false
|
||||
return values.NewFunction("now", ftype, call, sideEffect)
|
||||
}
|
||||
|
||||
func toSpec(p *ast.Package, now func() time.Time) (*flux.Spec, error) {
|
||||
semProg, err := semantic.New(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scope := flux.Prelude()
|
||||
scope.Set("now", nowFunc(now()))
|
||||
|
||||
itrp := interpreter.NewInterpreter()
|
||||
|
||||
sideEffects, err := itrp.Eval(semProg, scope, flux.StdLib())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nowOpt, ok := scope.Lookup("now")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("now option not set")
|
||||
}
|
||||
|
||||
nowTime, err := nowOpt.Function().Call(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return flux.ToSpec(sideEffects, nowTime.Time().Time())
|
||||
}
|
||||
|
||||
// ProxyRequest returns a request to proxy from the flux.
|
||||
func (r QueryRequest) ProxyRequest() (*query.ProxyRequest, error) {
|
||||
return r.proxyRequest(time.Now)
|
||||
|
@ -259,18 +223,27 @@ func (r QueryRequest) proxyRequest(now func() time.Time) (*query.ProxyRequest, e
|
|||
// Query is preferred over spec
|
||||
var compiler flux.Compiler
|
||||
if r.Query != "" {
|
||||
compiler = lang.FluxCompiler{
|
||||
Query: r.Query,
|
||||
}
|
||||
} else if r.AST != nil {
|
||||
var err error
|
||||
r.Spec, err = toSpec(r.AST, now)
|
||||
pkg, err := flux.Parse(r.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
compiler = lang.SpecCompiler{
|
||||
Spec: r.Spec,
|
||||
c := lang.ASTCompiler{
|
||||
AST: pkg,
|
||||
Now: now,
|
||||
}
|
||||
if r.Extern != nil {
|
||||
c.PrependFile(r.Extern)
|
||||
}
|
||||
compiler = c
|
||||
} else if r.AST != nil {
|
||||
c := lang.ASTCompiler{
|
||||
AST: r.AST,
|
||||
Now: now,
|
||||
}
|
||||
if r.Extern != nil {
|
||||
c.PrependFile(r.Extern)
|
||||
}
|
||||
compiler = c
|
||||
} else if r.Spec != nil {
|
||||
compiler = lang.SpecCompiler{
|
||||
Spec: r.Spec,
|
||||
|
@ -312,6 +285,9 @@ func QueryRequestFromProxyRequest(req *query.ProxyRequest) (*QueryRequest, error
|
|||
case lang.SpecCompiler:
|
||||
qr.Type = "flux"
|
||||
qr.Spec = c.Spec
|
||||
case lang.ASTCompiler:
|
||||
qr.Type = "flux"
|
||||
qr.AST = c.AST
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported compiler %T", c)
|
||||
}
|
||||
|
@ -330,7 +306,7 @@ func QueryRequestFromProxyRequest(req *query.ProxyRequest) (*QueryRequest, error
|
|||
return qr, nil
|
||||
}
|
||||
|
||||
func decodeQueryRequest(ctx context.Context, r *http.Request, svc platform.OrganizationService) (*QueryRequest, error) {
|
||||
func decodeQueryRequest(ctx context.Context, r *http.Request, svc influxdb.OrganizationService) (*QueryRequest, error) {
|
||||
var req QueryRequest
|
||||
|
||||
var contentType = "application/json"
|
||||
|
@ -365,7 +341,7 @@ func decodeQueryRequest(ctx context.Context, r *http.Request, svc platform.Organ
|
|||
return &req, err
|
||||
}
|
||||
|
||||
func decodeProxyQueryRequest(ctx context.Context, r *http.Request, auth platform.Authorizer, svc platform.OrganizationService) (*query.ProxyRequest, error) {
|
||||
func decodeProxyQueryRequest(ctx context.Context, r *http.Request, auth influxdb.Authorizer, svc influxdb.OrganizationService) (*query.ProxyRequest, error) {
|
||||
req, err := decodeQueryRequest(ctx, r, svc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -376,10 +352,10 @@ func decodeProxyQueryRequest(ctx context.Context, r *http.Request, auth platform
|
|||
return nil, err
|
||||
}
|
||||
|
||||
a, ok := auth.(*platform.Authorization)
|
||||
a, ok := auth.(*influxdb.Authorization)
|
||||
if !ok {
|
||||
// TODO(desa): this should go away once we're using platform.Authorizers everywhere.
|
||||
return pr, platform.ErrAuthorizerNotSupported
|
||||
// TODO(desa): this should go away once we're using influxdb.Authorizers everywhere.
|
||||
return pr, influxdb.ErrAuthorizerNotSupported
|
||||
}
|
||||
|
||||
pr.Request.Authorization = a
|
||||
|
|
|
@ -22,6 +22,27 @@ import (
|
|||
_ "github.com/influxdata/influxdb/query/builtin"
|
||||
)
|
||||
|
||||
var compareASTCompiler = func(x, y lang.ASTCompiler) bool {
|
||||
if x.Now == nil && y.Now != nil {
|
||||
return false
|
||||
}
|
||||
if x.Now != nil && y.Now == nil {
|
||||
return false
|
||||
}
|
||||
if x.Now != nil && y.Now != nil && !x.Now().Equal(y.Now()) {
|
||||
return false
|
||||
}
|
||||
return cmp.Equal(x.AST, y.AST, cmpopts.IgnoreTypes(ast.BaseNode{}))
|
||||
}
|
||||
|
||||
var cmpOptions = cmp.Options{
|
||||
cmpopts.IgnoreTypes(ast.BaseNode{}),
|
||||
cmpopts.IgnoreUnexported(query.ProxyRequest{}),
|
||||
cmpopts.IgnoreUnexported(query.Request{}),
|
||||
cmpopts.IgnoreUnexported(flux.Spec{}),
|
||||
cmpopts.EquateEmpty(),
|
||||
}
|
||||
|
||||
func TestQueryRequest_WithDefaults(t *testing.T) {
|
||||
type fields struct {
|
||||
Spec *flux.Spec
|
||||
|
@ -67,6 +88,7 @@ func TestQueryRequest_WithDefaults(t *testing.T) {
|
|||
|
||||
func TestQueryRequest_Validate(t *testing.T) {
|
||||
type fields struct {
|
||||
Extern *ast.File
|
||||
Spec *flux.Spec
|
||||
AST *ast.Package
|
||||
Query string
|
||||
|
@ -86,6 +108,19 @@ func TestQueryRequest_Validate(t *testing.T) {
|
|||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "query cannot have both extern and spec",
|
||||
fields: fields{
|
||||
Extern: &ast.File{},
|
||||
Spec: &flux.Spec{},
|
||||
Type: "flux",
|
||||
Dialect: QueryDialect{
|
||||
Delimiter: ",",
|
||||
DateTimeFormat: "RFC3339",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "requires flux type",
|
||||
fields: fields{
|
||||
|
@ -166,6 +201,7 @@ func TestQueryRequest_Validate(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := QueryRequest{
|
||||
Extern: tt.fields.Extern,
|
||||
Spec: tt.fields.Spec,
|
||||
AST: tt.fields.AST,
|
||||
Query: tt.fields.Query,
|
||||
|
@ -180,59 +216,9 @@ func TestQueryRequest_Validate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_toSpec(t *testing.T) {
|
||||
type args struct {
|
||||
p *ast.Package
|
||||
now func() time.Time
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *flux.Spec
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "ast converts to spec",
|
||||
args: args{
|
||||
p: &ast.Package{},
|
||||
now: func() time.Time { return time.Unix(0, 0) },
|
||||
},
|
||||
want: &flux.Spec{
|
||||
Now: time.Unix(0, 0).UTC(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bad semantics error",
|
||||
args: args{
|
||||
p: &ast.Package{
|
||||
Files: []*ast.File{{
|
||||
Body: []ast.Statement{
|
||||
&ast.ReturnStatement{},
|
||||
},
|
||||
}},
|
||||
},
|
||||
now: func() time.Time { return time.Unix(0, 0) },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
got, err := toSpec(tt.args.p, tt.args.now)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("toSpec() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("toSpec() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryRequest_proxyRequest(t *testing.T) {
|
||||
type fields struct {
|
||||
Extern *ast.File
|
||||
Spec *flux.Spec
|
||||
AST *ast.Package
|
||||
Query string
|
||||
|
@ -265,10 +251,23 @@ func TestQueryRequest_proxyRequest(t *testing.T) {
|
|||
},
|
||||
org: &platform.Organization{},
|
||||
},
|
||||
now: func() time.Time { return time.Unix(1, 1) },
|
||||
want: &query.ProxyRequest{
|
||||
Request: query.Request{
|
||||
Compiler: lang.FluxCompiler{
|
||||
Query: "howdy",
|
||||
Compiler: lang.ASTCompiler{
|
||||
AST: &ast.Package{
|
||||
Package: "main",
|
||||
Files: []*ast.File{
|
||||
{
|
||||
Body: []ast.Statement{
|
||||
&ast.ExpressionStatement{
|
||||
Expression: &ast.Identifier{Name: "howdy"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Now: func() time.Time { return time.Unix(1, 1) },
|
||||
},
|
||||
},
|
||||
Dialect: &csv.Dialect{
|
||||
|
@ -290,15 +289,64 @@ func TestQueryRequest_proxyRequest(t *testing.T) {
|
|||
},
|
||||
org: &platform.Organization{},
|
||||
},
|
||||
now: func() time.Time { return time.Unix(0, 0).UTC() },
|
||||
now: func() time.Time { return time.Unix(1, 1) },
|
||||
want: &query.ProxyRequest{
|
||||
Request: query.Request{
|
||||
Compiler: lang.SpecCompiler{
|
||||
Spec: &flux.Spec{
|
||||
Now: time.Unix(0, 0).UTC(),
|
||||
Compiler: lang.ASTCompiler{
|
||||
AST: &ast.Package{},
|
||||
Now: func() time.Time { return time.Unix(1, 1) },
|
||||
},
|
||||
},
|
||||
Dialect: &csv.Dialect{
|
||||
ResultEncoderConfig: csv.ResultEncoderConfig{
|
||||
NoHeader: false,
|
||||
Delimiter: ',',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid AST with extern",
|
||||
fields: fields{
|
||||
Extern: &ast.File{
|
||||
Body: []ast.Statement{
|
||||
&ast.OptionStatement{
|
||||
Assignment: &ast.VariableAssignment{
|
||||
ID: &ast.Identifier{Name: "x"},
|
||||
Init: &ast.IntegerLiteral{Value: 0},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AST: &ast.Package{},
|
||||
Type: "flux",
|
||||
Dialect: QueryDialect{
|
||||
Delimiter: ",",
|
||||
DateTimeFormat: "RFC3339",
|
||||
},
|
||||
org: &platform.Organization{},
|
||||
},
|
||||
now: func() time.Time { return time.Unix(1, 1) },
|
||||
want: &query.ProxyRequest{
|
||||
Request: query.Request{
|
||||
Compiler: lang.ASTCompiler{
|
||||
AST: &ast.Package{
|
||||
Files: []*ast.File{
|
||||
{
|
||||
Body: []ast.Statement{
|
||||
&ast.OptionStatement{
|
||||
Assignment: &ast.VariableAssignment{
|
||||
ID: &ast.Identifier{Name: "x"},
|
||||
Init: &ast.IntegerLiteral{Value: 0},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Now: func() time.Time { return time.Unix(1, 1) },
|
||||
},
|
||||
},
|
||||
Dialect: &csv.Dialect{
|
||||
ResultEncoderConfig: csv.ResultEncoderConfig{
|
||||
NoHeader: false,
|
||||
|
@ -337,9 +385,11 @@ func TestQueryRequest_proxyRequest(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
cmpOptions := append(cmpOptions, cmp.Comparer(compareASTCompiler))
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := QueryRequest{
|
||||
Extern: tt.fields.Extern,
|
||||
Spec: tt.fields.Spec,
|
||||
AST: tt.fields.AST,
|
||||
Query: tt.fields.Query,
|
||||
|
@ -352,8 +402,8 @@ func TestQueryRequest_proxyRequest(t *testing.T) {
|
|||
t.Errorf("QueryRequest.ProxyRequest() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("QueryRequest.ProxyRequest() = %#v, want %#v", got, tt.want)
|
||||
if !cmp.Equal(got, tt.want, cmpOptions...) {
|
||||
t.Errorf("QueryRequest.ProxyRequest() -want/+got\n%s", cmp.Diff(tt.want, got, cmpOptions...))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -482,8 +532,104 @@ func Test_decodeProxyQueryRequest(t *testing.T) {
|
|||
want: &query.ProxyRequest{
|
||||
Request: query.Request{
|
||||
OrganizationID: func() platform.ID { s, _ := platform.IDFromString("deadbeefdeadbeef"); return *s }(),
|
||||
Compiler: lang.FluxCompiler{
|
||||
Query: "from()",
|
||||
Compiler: lang.ASTCompiler{
|
||||
AST: &ast.Package{
|
||||
Package: "main",
|
||||
Files: []*ast.File{
|
||||
{
|
||||
Body: []ast.Statement{
|
||||
&ast.ExpressionStatement{
|
||||
Expression: &ast.CallExpression{
|
||||
Callee: &ast.Identifier{Name: "from"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dialect: &csv.Dialect{
|
||||
ResultEncoderConfig: csv.ResultEncoderConfig{
|
||||
NoHeader: false,
|
||||
Delimiter: ',',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid query including extern definition",
|
||||
args: args{
|
||||
r: httptest.NewRequest("POST", "/", bytes.NewBufferString(`
|
||||
{
|
||||
"extern": {
|
||||
"type": "File",
|
||||
"body": [
|
||||
{
|
||||
"type": "OptionStatement",
|
||||
"assignment": {
|
||||
"type": "VariableAssignment",
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"name": "x"
|
||||
},
|
||||
"init": {
|
||||
"type": "IntegerLiteral",
|
||||
"value": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"query": "from(bucket: \"mybucket\")"
|
||||
}
|
||||
`)),
|
||||
svc: &mock.OrganizationService{
|
||||
FindOrganizationF: func(ctx context.Context, filter platform.OrganizationFilter) (*platform.Organization, error) {
|
||||
return &platform.Organization{
|
||||
ID: func() platform.ID { s, _ := platform.IDFromString("deadbeefdeadbeef"); return *s }(),
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &query.ProxyRequest{
|
||||
Request: query.Request{
|
||||
OrganizationID: func() platform.ID { s, _ := platform.IDFromString("deadbeefdeadbeef"); return *s }(),
|
||||
Compiler: lang.ASTCompiler{
|
||||
AST: &ast.Package{
|
||||
Package: "main",
|
||||
Files: []*ast.File{
|
||||
{
|
||||
Body: []ast.Statement{
|
||||
&ast.OptionStatement{
|
||||
Assignment: &ast.VariableAssignment{
|
||||
ID: &ast.Identifier{Name: "x"},
|
||||
Init: &ast.IntegerLiteral{Value: 0},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Body: []ast.Statement{
|
||||
&ast.ExpressionStatement{
|
||||
Expression: &ast.CallExpression{
|
||||
Callee: &ast.Identifier{Name: "from"},
|
||||
Arguments: []ast.Expression{
|
||||
&ast.ObjectExpression{
|
||||
Properties: []*ast.Property{
|
||||
{
|
||||
Key: &ast.Identifier{Name: "bucket"},
|
||||
Value: &ast.StringLiteral{Value: "mybucket"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dialect: &csv.Dialect{
|
||||
|
@ -513,8 +659,31 @@ func Test_decodeProxyQueryRequest(t *testing.T) {
|
|||
want: &query.ProxyRequest{
|
||||
Request: query.Request{
|
||||
OrganizationID: func() platform.ID { s, _ := platform.IDFromString("deadbeefdeadbeef"); return *s }(),
|
||||
Compiler: lang.FluxCompiler{
|
||||
Query: "from(bucket: \"mybucket\")",
|
||||
Compiler: lang.ASTCompiler{
|
||||
AST: &ast.Package{
|
||||
Package: "main",
|
||||
Files: []*ast.File{
|
||||
{
|
||||
Body: []ast.Statement{
|
||||
&ast.ExpressionStatement{
|
||||
Expression: &ast.CallExpression{
|
||||
Callee: &ast.Identifier{Name: "from"},
|
||||
Arguments: []ast.Expression{
|
||||
&ast.ObjectExpression{
|
||||
Properties: []*ast.Property{
|
||||
{
|
||||
Key: &ast.Identifier{Name: "bucket"},
|
||||
Value: &ast.StringLiteral{Value: "mybucket"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dialect: &csv.Dialect{
|
||||
|
@ -526,11 +695,7 @@ func Test_decodeProxyQueryRequest(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
var cmpOptions = cmp.Options{
|
||||
cmpopts.IgnoreUnexported(query.ProxyRequest{}),
|
||||
cmpopts.IgnoreUnexported(query.Request{}),
|
||||
cmpopts.EquateEmpty(),
|
||||
}
|
||||
cmpOptions := append(cmpOptions, cmpopts.IgnoreFields(lang.ASTCompiler{}, "Now"))
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := decodeProxyQueryRequest(tt.args.ctx, tt.args.r, tt.args.auth, tt.args.svc)
|
||||
|
@ -538,8 +703,8 @@ func Test_decodeProxyQueryRequest(t *testing.T) {
|
|||
t.Errorf("decodeProxyQueryRequest() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if diff := cmp.Diff(got, tt.want, cmpOptions...); diff != "" {
|
||||
t.Errorf("decodeProxyQueryRequest() = got/want %v", diff)
|
||||
if !cmp.Equal(tt.want, got, cmpOptions...) {
|
||||
t.Errorf("decodeProxyQueryRequest() -want/+got\n%s", cmp.Diff(tt.want, got, cmpOptions...))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
412
http/swagger.yml
412
http/swagger.yml
|
@ -4688,6 +4688,8 @@ components:
|
|||
required:
|
||||
- query
|
||||
properties:
|
||||
extern:
|
||||
$ref: "#/components/schemas/File"
|
||||
query:
|
||||
description: query script to execute.
|
||||
type: string
|
||||
|
@ -4711,6 +4713,413 @@ components:
|
|||
type: string
|
||||
dialect:
|
||||
$ref: "#/components/schemas/Dialect"
|
||||
Package:
|
||||
description: represents a complete package source tree
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
path:
|
||||
description: package import path
|
||||
type: string
|
||||
package:
|
||||
description: package name
|
||||
type: string
|
||||
files:
|
||||
description: package files
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/File"
|
||||
File:
|
||||
description: represents a source from a single file
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
name:
|
||||
description: name of the file
|
||||
type: string
|
||||
package:
|
||||
$ref: "#/components/schemas/PackageClause"
|
||||
imports:
|
||||
description: a list of package imports
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ImportDeclaration"
|
||||
body:
|
||||
description: list of Flux statements
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Statement"
|
||||
PackageClause:
|
||||
description: defines a package identifier
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
name:
|
||||
$ref: "#/components/schemas/Identifier"
|
||||
ImportDeclaration:
|
||||
description: declares a package import
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
as:
|
||||
$ref: "#/components/schemas/Identifier"
|
||||
path:
|
||||
$ref: "#/components/schemas/StringLiteral"
|
||||
Node:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/Expression"
|
||||
- $ref: "#/components/schemas/Block"
|
||||
Block:
|
||||
description: a set of statements
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
body:
|
||||
description: block body
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Statement"
|
||||
Statement:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/BadStatement"
|
||||
- $ref: "#/components/schemas/VariableAssignment"
|
||||
- $ref: "#/components/schemas/MemberAssignment"
|
||||
- $ref: "#/components/schemas/ExpressionStatement"
|
||||
- $ref: "#/components/schemas/ReturnStatement"
|
||||
- $ref: "#/components/schemas/OptionStatement"
|
||||
- $ref: "#/components/schemas/BuiltinStatement"
|
||||
- $ref: "#/components/schemas/TestStatement"
|
||||
BadStatement:
|
||||
description: a placeholder for statements for which no correct statement nodes can be created
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
text:
|
||||
description: raw source text
|
||||
type: string
|
||||
VariableAssignment:
|
||||
description: represents the declaration of a variable
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
id:
|
||||
$ref: "#/components/schemas/Identifier"
|
||||
init:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
MemberAssignment:
|
||||
description: object property assignment
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
member:
|
||||
$ref: "#/components/schemas/MemberExpression"
|
||||
init:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
ExpressionStatement:
|
||||
description: may consist of an expression that does not return a value and is executed solely for its side-effects
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
expression:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
ReturnStatement:
|
||||
description: defines an expression to return
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
argument:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
OptionStatement:
|
||||
description: a single variable declaration
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
assignment:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/VariableAssignment"
|
||||
- $ref: "#/components/schemas/MemberAssignment"
|
||||
BuiltinStatement:
|
||||
description: declares a builtin identifier and its type
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
id:
|
||||
$ref: "#/components/schemas/Identifier"
|
||||
TestStatement:
|
||||
description: declares a Flux test case
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
assignment:
|
||||
$ref: "#/components/schemas/VariableAssignment"
|
||||
Expression:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/ArrayExpression"
|
||||
- $ref: "#/components/schemas/FunctionExpression"
|
||||
- $ref: "#/components/schemas/BinaryExpression"
|
||||
- $ref: "#/components/schemas/CallExpression"
|
||||
- $ref: "#/components/schemas/ConditionalExpression"
|
||||
- $ref: "#/components/schemas/LogicalExpression"
|
||||
- $ref: "#/components/schemas/MemberExpression"
|
||||
- $ref: "#/components/schemas/IndexExpression"
|
||||
- $ref: "#/components/schemas/ObjectExpression"
|
||||
- $ref: "#/components/schemas/PipeExpression"
|
||||
- $ref: "#/components/schemas/UnaryExpression"
|
||||
- $ref: "#/components/schemas/BooleanLiteral"
|
||||
- $ref: "#/components/schemas/DateTimeLiteral"
|
||||
- $ref: "#/components/schemas/DurationLiteral"
|
||||
- $ref: "#/components/schemas/FloatLiteral"
|
||||
- $ref: "#/components/schemas/IntegerLiteral"
|
||||
- $ref: "#/components/schemas/PipeLiteral"
|
||||
- $ref: "#/components/schemas/RegexpLiteral"
|
||||
- $ref: "#/components/schemas/StringLiteral"
|
||||
- $ref: "#/components/schemas/UnsignedIntegerLiteral"
|
||||
- $ref: "#/components/schemas/Identifier"
|
||||
ArrayExpression:
|
||||
description: used to create and directly specify the elements of an array object
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
elements:
|
||||
description: elements of the array
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
FunctionExpression:
|
||||
description: function expression
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
params:
|
||||
description: function parameters
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Property"
|
||||
body:
|
||||
$ref: "#/components/schemas/Node"
|
||||
BinaryExpression:
|
||||
description: uses binary operators to act on two operands in an expression
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
operator:
|
||||
type: string
|
||||
left:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
right:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
CallExpression:
|
||||
description: represents a function call
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
callee:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
arguments:
|
||||
description: function arguments
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
ConditionalExpression:
|
||||
description: selects one of two expressions, `Alternate` or `Consequent`, depending on a third boolean expression, `Test`
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
test:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
alternate:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
consequent:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
LogicalExpression:
|
||||
description: represents the rule conditions that collectively evaluate to either true or false
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
operator:
|
||||
type: string
|
||||
left:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
right:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
MemberExpression:
|
||||
description: represents accessing a property of an object
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
object:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
property:
|
||||
$ref: "#/components/schemas/PropertyKey"
|
||||
IndexExpression:
|
||||
description: represents indexing into an array
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
array:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
index:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
ObjectExpression:
|
||||
description: allows the declaration of an anonymous object within a declaration
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
properties:
|
||||
description: object properties
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Property"
|
||||
PipeExpression:
|
||||
description: call expression with pipe argument
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
argument:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
call:
|
||||
$ref: "#/components/schemas/CallExpression"
|
||||
UnaryExpression:
|
||||
description: uses operators to act on a single operand in an expression
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
operator:
|
||||
type: string
|
||||
argument:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
BooleanLiteral:
|
||||
description: represents boolean values
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
value:
|
||||
type: boolean
|
||||
DateTimeLiteral:
|
||||
description: represents an instant in time with nanosecond precision using the syntax of golang's RFC3339 Nanosecond variant
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
value:
|
||||
type: string
|
||||
DurationLiteral:
|
||||
description: represents the elapsed time between two instants as an int64 nanosecond count with syntax of golang's time.Duration
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
values:
|
||||
description: duration values
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Duration"
|
||||
FloatLiteral:
|
||||
description: represents floating point numbers according to the double representations defined by the IEEE-754-1985
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
value:
|
||||
type: number
|
||||
IntegerLiteral:
|
||||
description: represents integer numbers
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
value:
|
||||
type: string
|
||||
PipeLiteral:
|
||||
description: represents a specialized literal value, indicating the left hand value of a pipe expression
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
RegexpLiteral:
|
||||
description: expressions begin and end with `/` and are regular expressions with syntax accepted by RE2
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
value:
|
||||
type: string
|
||||
StringLiteral:
|
||||
description: expressions begin and end with double quote marks
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
value:
|
||||
type: string
|
||||
UnsignedIntegerLiteral:
|
||||
description: represents integer numbers
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
value:
|
||||
type: string
|
||||
Duration:
|
||||
description: a pair consisting of length of time and the unit of time measured. It is the atomic unit from which all duration literals are composed.
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
magnitude:
|
||||
type: integer
|
||||
unit:
|
||||
type: string
|
||||
Property:
|
||||
description: the value associated with a key
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
key:
|
||||
$ref: "#/components/schemas/PropertyKey"
|
||||
value:
|
||||
$ref: "#/components/schemas/Expression"
|
||||
PropertyKey:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/Identifier"
|
||||
- $ref: "#/components/schemas/StringLiteral"
|
||||
Identifier:
|
||||
description: a valid Flux identifier
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
$ref: "#/components/schemas/NodeType"
|
||||
name:
|
||||
type: string
|
||||
NodeType:
|
||||
description: type of AST node
|
||||
type: string
|
||||
QuerySpecification:
|
||||
description: consists of a set of operations and a set of edges between those operations to instruct the query engine to operate.
|
||||
type: object
|
||||
|
@ -7087,8 +7496,7 @@ components:
|
|||
type: object
|
||||
properties:
|
||||
ast:
|
||||
description: the AST of the supplied Flux query
|
||||
type: object
|
||||
$ref: "#/components/schemas/Package"
|
||||
WritePrecision:
|
||||
type: string
|
||||
enum:
|
||||
|
|
Loading…
Reference in New Issue