WIP move / change shape of body function
parent
292d04e5a8
commit
f3116aaab0
|
@ -1,5 +1,6 @@
|
|||
// Texas Ranger
|
||||
import _ from 'lodash'
|
||||
import {FlatBody, Func} from 'src/types/ifql'
|
||||
|
||||
interface Expression {
|
||||
argument: object
|
||||
|
@ -19,14 +20,9 @@ interface Body {
|
|||
}
|
||||
|
||||
interface FlatExpression {
|
||||
type: string
|
||||
source: string
|
||||
funcs: FuncNode[]
|
||||
}
|
||||
|
||||
interface FuncNode {
|
||||
name: string
|
||||
arguments: any[]
|
||||
source: string
|
||||
funcs: Func[]
|
||||
}
|
||||
|
||||
interface AST {
|
||||
|
@ -44,7 +40,7 @@ export default class Walker {
|
|||
return this.buildFuncNodes(this.walk(this.baseExpression))
|
||||
}
|
||||
|
||||
public get stuff() {
|
||||
public get body(): FlatBody[] {
|
||||
const body = _.get(this.ast, 'body', new Array<Body>())
|
||||
return body.map(b => {
|
||||
if (b.type.includes('Expression')) {
|
||||
|
@ -74,6 +70,7 @@ export default class Walker {
|
|||
const funcs = this.buildFuncNodes(this.walk(expression))
|
||||
|
||||
return {
|
||||
type: expression.type,
|
||||
source: location.source,
|
||||
funcs,
|
||||
}
|
||||
|
@ -86,6 +83,7 @@ export default class Walker {
|
|||
const funcs = this.buildFuncNodes(this.walk(expression))
|
||||
|
||||
return {
|
||||
type: expression.type,
|
||||
source: location.source,
|
||||
funcs,
|
||||
}
|
||||
|
@ -122,11 +120,11 @@ export default class Walker {
|
|||
return [{name, args, source}]
|
||||
}
|
||||
|
||||
private buildFuncNodes = (nodes): FuncNode[] => {
|
||||
private buildFuncNodes = (nodes): Func[] => {
|
||||
return nodes.map(({name, args, source}) => {
|
||||
return {
|
||||
name,
|
||||
arguments: this.reduceArgs(args),
|
||||
args: this.reduceArgs(args),
|
||||
source,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
import FuncSelector from 'src/ifql/components/FuncSelector'
|
||||
import FuncNode from 'src/ifql/components/FuncNode'
|
||||
import {
|
||||
FlatBody,
|
||||
OnAddNode,
|
||||
Suggestion,
|
||||
OnChangeArg,
|
||||
OnDeleteFuncNode,
|
||||
} from 'src/types/ifql'
|
||||
|
||||
interface Props {
|
||||
body: Body[]
|
||||
onAddNode: OnAddNode
|
||||
onChangeArg: OnChangeArg
|
||||
onDeleteFuncNode: OnDeleteFuncNode
|
||||
suggestions: Suggestion[]
|
||||
onGenerateScript: () => void
|
||||
}
|
||||
|
||||
interface Body extends FlatBody {
|
||||
id: string
|
||||
}
|
||||
|
||||
class BodyBuilder extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
body,
|
||||
onAddNode,
|
||||
onChangeArg,
|
||||
onDeleteFuncNode,
|
||||
onGenerateScript,
|
||||
} = this.props
|
||||
|
||||
const bodybuilder = body.map(b => {
|
||||
if (b.declarations.length) {
|
||||
return b.declarations.map(d => {
|
||||
if (d.funcs) {
|
||||
return (
|
||||
<div key={d.id} className="func-nodes-container">
|
||||
<h4>
|
||||
{d.name}
|
||||
<FuncSelector
|
||||
expressionID={d.id}
|
||||
funcs={this.funcNames}
|
||||
onAddNode={onAddNode}
|
||||
/>
|
||||
</h4>
|
||||
{d.funcs.map(func => (
|
||||
<FuncNode
|
||||
key={func.id}
|
||||
func={func}
|
||||
expressionID={func.id}
|
||||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <div key={b.id}>{b.source}</div>
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={b.id} className="func-nodes-container">
|
||||
<h4>
|
||||
Expression
|
||||
<FuncSelector
|
||||
expressionID={b.id}
|
||||
funcs={this.funcNames}
|
||||
onAddNode={onAddNode}
|
||||
/>
|
||||
</h4>
|
||||
{b.funcs.map(func => (
|
||||
<FuncNode
|
||||
key={func.id}
|
||||
func={func}
|
||||
expressionID={b.id}
|
||||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
return _.flatten(bodybuilder)
|
||||
}
|
||||
|
||||
private get funcNames() {
|
||||
return this.props.suggestions.map(f => f.name)
|
||||
}
|
||||
}
|
||||
|
||||
export default BodyBuilder
|
|
@ -2,21 +2,7 @@ import React, {PureComponent} from 'react'
|
|||
import FuncArg from 'src/ifql/components/FuncArg'
|
||||
import {OnChangeArg} from 'src/types/ifql'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
type Value = string | boolean
|
||||
|
||||
interface Arg {
|
||||
key: string
|
||||
value: Value
|
||||
type: string
|
||||
}
|
||||
|
||||
export interface Func {
|
||||
name: string
|
||||
args: Arg[]
|
||||
source: string
|
||||
id: string
|
||||
}
|
||||
import {Func} from 'src/types/ifql'
|
||||
|
||||
interface Props {
|
||||
func: Func
|
||||
|
@ -30,6 +16,10 @@ export default class FuncArgs extends PureComponent<Props> {
|
|||
public render() {
|
||||
const {expressionID, func, onChangeArg, onGenerateScript} = this.props
|
||||
|
||||
if (!func.args) {
|
||||
debugger
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="func-args">
|
||||
{func.args.map(({key, value, type}) => {
|
||||
|
|
|
@ -1,28 +1,20 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import FuncSelector from 'src/ifql/components/FuncSelector'
|
||||
import FuncNode from 'src/ifql/components/FuncNode'
|
||||
import BodyBuilder from 'src/ifql/components/BodyBuilder'
|
||||
import TimeMachineEditor from 'src/ifql/components/TimeMachineEditor'
|
||||
|
||||
import {Func} from 'src/ifql/components/FuncArgs'
|
||||
import {OnChangeArg, OnDeleteFuncNode, OnAddNode} from 'src/types/ifql'
|
||||
import {
|
||||
FlatBody,
|
||||
Suggestion,
|
||||
OnChangeArg,
|
||||
OnDeleteFuncNode,
|
||||
OnAddNode,
|
||||
} from 'src/types/ifql'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
export interface Suggestion {
|
||||
name: string
|
||||
params: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
|
||||
interface Expression {
|
||||
id: string
|
||||
funcs: Func[]
|
||||
}
|
||||
|
||||
interface Props {
|
||||
script: string
|
||||
suggestions: Suggestion[]
|
||||
expressions: Expression[]
|
||||
body: Body[]
|
||||
onSubmitScript: () => void
|
||||
onChangeScript: (script: string) => void
|
||||
onAddNode: OnAddNode
|
||||
|
@ -31,18 +23,23 @@ interface Props {
|
|||
onGenerateScript: () => void
|
||||
}
|
||||
|
||||
interface Body extends FlatBody {
|
||||
id: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class TimeMachine extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
body,
|
||||
script,
|
||||
onAddNode,
|
||||
expressions,
|
||||
onChangeArg,
|
||||
onChangeScript,
|
||||
onSubmitScript,
|
||||
onDeleteFuncNode,
|
||||
onGenerateScript,
|
||||
suggestions,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
|
@ -53,38 +50,18 @@ class TimeMachine extends PureComponent<Props> {
|
|||
onSubmitScript={onSubmitScript}
|
||||
/>
|
||||
<div className="expression-container">
|
||||
{expressions.map(({funcs, id}, i) => {
|
||||
return (
|
||||
<div key={id} className="func-nodes-container">
|
||||
<h4>
|
||||
Expression {i}
|
||||
<FuncSelector
|
||||
expressionID={id}
|
||||
funcs={this.funcNames}
|
||||
onAddNode={onAddNode}
|
||||
/>
|
||||
</h4>
|
||||
{funcs.map(func => (
|
||||
<FuncNode
|
||||
key={func.id}
|
||||
func={func}
|
||||
expressionID={id}
|
||||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
onGenerateScript={onGenerateScript}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<BodyBuilder
|
||||
body={body}
|
||||
onAddNode={onAddNode}
|
||||
onChangeArg={onChangeArg}
|
||||
onDeleteFuncNode={onDeleteFuncNode}
|
||||
onGenerateScript={onGenerateScript}
|
||||
suggestions={suggestions}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get funcNames() {
|
||||
return this.props.suggestions.map(f => f.name)
|
||||
}
|
||||
}
|
||||
|
||||
export default TimeMachine
|
||||
|
|
|
@ -4,12 +4,13 @@ import {connect} from 'react-redux'
|
|||
import uuid from 'uuid'
|
||||
import _ from 'lodash'
|
||||
|
||||
import TimeMachine, {Suggestion} from 'src/ifql/components/TimeMachine'
|
||||
import TimeMachine from 'src/ifql/components/TimeMachine'
|
||||
import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts'
|
||||
import Walker from 'src/ifql/ast/walker'
|
||||
import {Func} from 'src/ifql/components/FuncArgs'
|
||||
import {Func, Suggestion, FlatBody} from 'src/types/ifql'
|
||||
import {InputArg} from 'src/types/ifql'
|
||||
|
||||
import {bodyNodes} from 'src/ifql/helpers'
|
||||
import {getSuggestions, getAST} from 'src/ifql/apis'
|
||||
import * as argTypes from 'src/ifql/constants/argumentTypes'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -24,17 +25,15 @@ interface Props {
|
|||
links: Links
|
||||
}
|
||||
|
||||
interface State {
|
||||
suggestions: Suggestion[]
|
||||
expressions: Expression[]
|
||||
ast: object
|
||||
script: string
|
||||
interface Body extends FlatBody {
|
||||
id: string
|
||||
}
|
||||
|
||||
interface Expression {
|
||||
id: string
|
||||
funcs: Func[]
|
||||
source: string
|
||||
interface State {
|
||||
body: Body[]
|
||||
ast: object
|
||||
script: string
|
||||
suggestions: Suggestion[]
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -42,11 +41,11 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
suggestions: [],
|
||||
expressions: [],
|
||||
body: [],
|
||||
ast: null,
|
||||
suggestions: [],
|
||||
script:
|
||||
'from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n',
|
||||
'foo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n',
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +79,7 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
<div className="container-fluid">
|
||||
<TimeMachine
|
||||
script={script}
|
||||
expressions={this.state.expressions}
|
||||
body={this.state.body}
|
||||
suggestions={suggestions}
|
||||
onAddNode={this.handleAddNode}
|
||||
onChangeArg={this.handleChangeArg}
|
||||
|
@ -221,61 +220,13 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
this.getASTResponse(script)
|
||||
}
|
||||
|
||||
private expressions = (ast, suggestions): Expression[] => {
|
||||
if (!ast) {
|
||||
return []
|
||||
}
|
||||
|
||||
const walker = new Walker(ast)
|
||||
|
||||
const expressions = walker.expressions.map(({funcs, source}) => {
|
||||
const id = uuid.v4()
|
||||
return {
|
||||
id,
|
||||
funcs: this.functions(funcs, suggestions),
|
||||
source,
|
||||
}
|
||||
})
|
||||
|
||||
return expressions
|
||||
}
|
||||
|
||||
private functions = (funcs, suggestions): Func[] => {
|
||||
const functions = funcs.map(func => {
|
||||
const {params, name} = suggestions.find(f => f.name === func.name)
|
||||
|
||||
const args = Object.entries(params).map(([key, type]) => {
|
||||
const value = _.get(
|
||||
func.arguments.find(arg => arg.key === key),
|
||||
'value',
|
||||
''
|
||||
)
|
||||
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
type,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
id: uuid.v4(),
|
||||
source: func.source,
|
||||
name,
|
||||
args,
|
||||
}
|
||||
})
|
||||
|
||||
return functions
|
||||
}
|
||||
|
||||
private getASTResponse = async (script: string) => {
|
||||
const {links} = this.props
|
||||
|
||||
try {
|
||||
const ast = await getAST({url: links.ast, body: script})
|
||||
const expressions = this.expressions(ast, this.state.suggestions)
|
||||
this.setState({ast, script, expressions})
|
||||
const body = bodyNodes(ast, this.state.suggestions)
|
||||
this.setState({ast, script, body})
|
||||
} catch (error) {
|
||||
console.error('Could not parse AST', error)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import uuid from 'uuid'
|
||||
import _ from 'lodash'
|
||||
import Walker from 'src/ifql/ast/walker'
|
||||
import {FlatBody, Func} from 'src/types/ifql'
|
||||
|
||||
interface Body extends FlatBody {
|
||||
id: string
|
||||
}
|
||||
|
||||
export const bodyNodes = (ast, suggestions): Body[] => {
|
||||
if (!ast) {
|
||||
return []
|
||||
}
|
||||
|
||||
const walker = new Walker(ast)
|
||||
|
||||
const body = walker.body.map(b => {
|
||||
const {type} = b
|
||||
const id = uuid.v4()
|
||||
if (type.includes('Variable')) {
|
||||
const declarations = b.declarations.map(d => {
|
||||
if (!d.funcs) {
|
||||
return {...d, id: uuid.v4()}
|
||||
}
|
||||
|
||||
return {
|
||||
...d,
|
||||
id: uuid.v4(),
|
||||
funcs: functions(d.funcs, suggestions),
|
||||
}
|
||||
})
|
||||
|
||||
return {...b, type, id, declarations}
|
||||
}
|
||||
|
||||
const {funcs, source} = b
|
||||
|
||||
return {
|
||||
id,
|
||||
funcs: functions(funcs, suggestions),
|
||||
declarations: [],
|
||||
type,
|
||||
source,
|
||||
}
|
||||
})
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
const functions = (funcs, suggestions): Func[] => {
|
||||
const funcList = funcs.map(func => {
|
||||
const {params, name} = suggestions.find(f => f.name === func.name)
|
||||
const args = Object.entries(params).map(([key, type]) => {
|
||||
const value = _.get(func.args.find(arg => arg.key === key), 'value', '')
|
||||
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
type,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
id: uuid.v4(),
|
||||
source: func.source,
|
||||
name,
|
||||
args,
|
||||
}
|
||||
})
|
||||
|
||||
return funcList
|
||||
}
|
|
@ -9,3 +9,46 @@ export interface InputArg {
|
|||
value: string | boolean
|
||||
generate?: boolean
|
||||
}
|
||||
|
||||
// Flattened AST
|
||||
export interface FlatBody {
|
||||
type: string
|
||||
source: string
|
||||
funcs?: Func[]
|
||||
declarations?: FlatDeclaration[]
|
||||
}
|
||||
|
||||
export interface Func {
|
||||
type: string
|
||||
name: string
|
||||
args: Arg[]
|
||||
source: string
|
||||
id: string
|
||||
}
|
||||
|
||||
type Value = string | boolean
|
||||
|
||||
interface Arg {
|
||||
key: string
|
||||
value: Value
|
||||
type: string
|
||||
}
|
||||
|
||||
interface FlatExpression {
|
||||
id: string
|
||||
funcs?: Func[]
|
||||
}
|
||||
|
||||
interface FlatDeclaration extends FlatExpression {
|
||||
name: string
|
||||
value: string
|
||||
type: string
|
||||
}
|
||||
|
||||
// Semantic Graph list of available functions for ifql queries
|
||||
export interface Suggestion {
|
||||
name: string
|
||||
params: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
export default {
|
||||
type: 'Program',
|
||||
location: {
|
||||
start: {line: 1, column: 1},
|
||||
end: {line: 1, column: 129},
|
||||
source:
|
||||
'literal = "foo"\n\ntele = from(db: "telegraf")\n\t|\u003e range(start: -15m)\n\nfrom(db: "telegraf")\n\t|\u003e filter() \n\t|\u003e range(start: -15m)\n\n',
|
||||
},
|
||||
body: [
|
||||
{
|
||||
type: 'VariableDeclaration',
|
||||
location: {
|
||||
start: {line: 1, column: 1},
|
||||
end: {line: 1, column: 16},
|
||||
source: 'literal = "foo"',
|
||||
},
|
||||
declarations: [
|
||||
{
|
||||
type: 'VariableDeclarator',
|
||||
id: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 1, column: 1},
|
||||
end: {line: 1, column: 8},
|
||||
source: 'literal',
|
||||
},
|
||||
name: 'literal',
|
||||
},
|
||||
init: {
|
||||
type: 'StringLiteral',
|
||||
location: {
|
||||
start: {line: 1, column: 11},
|
||||
end: {line: 1, column: 16},
|
||||
source: '"foo"',
|
||||
},
|
||||
value: 'foo',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'VariableDeclaration',
|
||||
location: {
|
||||
start: {line: 3, column: 1},
|
||||
end: {line: 3, column: 53},
|
||||
source: 'tele = from(db: "telegraf")\n\t|\u003e range(start: -15m)\n\n',
|
||||
},
|
||||
declarations: [
|
||||
{
|
||||
type: 'VariableDeclarator',
|
||||
id: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 3, column: 1},
|
||||
end: {line: 3, column: 5},
|
||||
source: 'tele',
|
||||
},
|
||||
name: 'tele',
|
||||
},
|
||||
init: {
|
||||
type: 'PipeExpression',
|
||||
location: {
|
||||
start: {line: 4, column: 2},
|
||||
end: {line: 4, column: 23},
|
||||
source: '|\u003e range(start: -15m)',
|
||||
},
|
||||
argument: {
|
||||
type: 'CallExpression',
|
||||
location: {
|
||||
start: {line: 3, column: 8},
|
||||
end: {line: 3, column: 28},
|
||||
source: 'from(db: "telegraf")',
|
||||
},
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 3, column: 8},
|
||||
end: {line: 3, column: 12},
|
||||
source: 'from',
|
||||
},
|
||||
name: 'from',
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
type: 'ObjectExpression',
|
||||
location: {
|
||||
start: {line: 3, column: 13},
|
||||
end: {line: 3, column: 27},
|
||||
source: 'db: "telegraf"',
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
type: 'Property',
|
||||
location: {
|
||||
start: {line: 3, column: 13},
|
||||
end: {line: 3, column: 27},
|
||||
source: 'db: "telegraf"',
|
||||
},
|
||||
key: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 3, column: 13},
|
||||
end: {line: 3, column: 15},
|
||||
source: 'db',
|
||||
},
|
||||
name: 'db',
|
||||
},
|
||||
value: {
|
||||
type: 'StringLiteral',
|
||||
location: {
|
||||
start: {line: 3, column: 17},
|
||||
end: {line: 3, column: 27},
|
||||
source: '"telegraf"',
|
||||
},
|
||||
value: 'telegraf',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
call: {
|
||||
type: 'CallExpression',
|
||||
location: {
|
||||
start: {line: 4, column: 5},
|
||||
end: {line: 4, column: 23},
|
||||
source: 'range(start: -15m)',
|
||||
},
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 4, column: 5},
|
||||
end: {line: 4, column: 10},
|
||||
source: 'range',
|
||||
},
|
||||
name: 'range',
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
type: 'ObjectExpression',
|
||||
location: {
|
||||
start: {line: 4, column: 11},
|
||||
end: {line: 4, column: 22},
|
||||
source: 'start: -15m',
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
type: 'Property',
|
||||
location: {
|
||||
start: {line: 4, column: 11},
|
||||
end: {line: 4, column: 22},
|
||||
source: 'start: -15m',
|
||||
},
|
||||
key: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 4, column: 11},
|
||||
end: {line: 4, column: 16},
|
||||
source: 'start',
|
||||
},
|
||||
name: 'start',
|
||||
},
|
||||
value: {
|
||||
type: 'UnaryExpression',
|
||||
location: {
|
||||
start: {line: 4, column: 18},
|
||||
end: {line: 4, column: 22},
|
||||
source: '-15m',
|
||||
},
|
||||
operator: '-',
|
||||
argument: {
|
||||
type: 'DurationLiteral',
|
||||
location: {
|
||||
start: {line: 4, column: 19},
|
||||
end: {line: 4, column: 22},
|
||||
source: '15m',
|
||||
},
|
||||
value: '15m0s',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'ExpressionStatement',
|
||||
location: {
|
||||
start: {line: 6, column: 1},
|
||||
end: {line: 6, column: 60},
|
||||
source:
|
||||
'from(db: "telegraf")\n\t|\u003e filter() \n\t|\u003e range(start: -15m)\n\n',
|
||||
},
|
||||
expression: {
|
||||
type: 'PipeExpression',
|
||||
location: {
|
||||
start: {line: 8, column: 2},
|
||||
end: {line: 8, column: 23},
|
||||
source: '|\u003e range(start: -15m)',
|
||||
},
|
||||
argument: {
|
||||
type: 'PipeExpression',
|
||||
location: {
|
||||
start: {line: 7, column: 2},
|
||||
end: {line: 7, column: 13},
|
||||
source: '|\u003e filter()',
|
||||
},
|
||||
argument: {
|
||||
type: 'CallExpression',
|
||||
location: {
|
||||
start: {line: 6, column: 1},
|
||||
end: {line: 6, column: 21},
|
||||
source: 'from(db: "telegraf")',
|
||||
},
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 6, column: 1},
|
||||
end: {line: 6, column: 5},
|
||||
source: 'from',
|
||||
},
|
||||
name: 'from',
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
type: 'ObjectExpression',
|
||||
location: {
|
||||
start: {line: 6, column: 6},
|
||||
end: {line: 6, column: 20},
|
||||
source: 'db: "telegraf"',
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
type: 'Property',
|
||||
location: {
|
||||
start: {line: 6, column: 6},
|
||||
end: {line: 6, column: 20},
|
||||
source: 'db: "telegraf"',
|
||||
},
|
||||
key: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 6, column: 6},
|
||||
end: {line: 6, column: 8},
|
||||
source: 'db',
|
||||
},
|
||||
name: 'db',
|
||||
},
|
||||
value: {
|
||||
type: 'StringLiteral',
|
||||
location: {
|
||||
start: {line: 6, column: 10},
|
||||
end: {line: 6, column: 20},
|
||||
source: '"telegraf"',
|
||||
},
|
||||
value: 'telegraf',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
call: {
|
||||
type: 'CallExpression',
|
||||
location: {
|
||||
start: {line: 7, column: 5},
|
||||
end: {line: 7, column: 13},
|
||||
source: 'filter()',
|
||||
},
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 7, column: 5},
|
||||
end: {line: 7, column: 11},
|
||||
source: 'filter',
|
||||
},
|
||||
name: 'filter',
|
||||
},
|
||||
},
|
||||
},
|
||||
call: {
|
||||
type: 'CallExpression',
|
||||
location: {
|
||||
start: {line: 8, column: 5},
|
||||
end: {line: 8, column: 23},
|
||||
source: 'range(start: -15m)',
|
||||
},
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 8, column: 5},
|
||||
end: {line: 8, column: 10},
|
||||
source: 'range',
|
||||
},
|
||||
name: 'range',
|
||||
},
|
||||
arguments: [
|
||||
{
|
||||
type: 'ObjectExpression',
|
||||
location: {
|
||||
start: {line: 8, column: 11},
|
||||
end: {line: 8, column: 22},
|
||||
source: 'start: -15m',
|
||||
},
|
||||
properties: [
|
||||
{
|
||||
type: 'Property',
|
||||
location: {
|
||||
start: {line: 8, column: 11},
|
||||
end: {line: 8, column: 22},
|
||||
source: 'start: -15m',
|
||||
},
|
||||
key: {
|
||||
type: 'Identifier',
|
||||
location: {
|
||||
start: {line: 8, column: 11},
|
||||
end: {line: 8, column: 16},
|
||||
source: 'start',
|
||||
},
|
||||
name: 'start',
|
||||
},
|
||||
value: {
|
||||
type: 'UnaryExpression',
|
||||
location: {
|
||||
start: {line: 8, column: 18},
|
||||
end: {line: 8, column: 22},
|
||||
source: '-15m',
|
||||
},
|
||||
operator: '-',
|
||||
argument: {
|
||||
type: 'DurationLiteral',
|
||||
location: {
|
||||
start: {line: 8, column: 19},
|
||||
end: {line: 8, column: 22},
|
||||
source: '15m',
|
||||
},
|
||||
value: '15m0s',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
|
@ -7,16 +7,17 @@ describe('IFQL.AST.Walker', () => {
|
|||
describe('Walker#functions', () => {
|
||||
describe('simple example', () => {
|
||||
describe('a single expression', () => {
|
||||
it('returns a flattened ordered list of from and its arguments', () => {
|
||||
it('returns a flattened ordered list of from and its args', () => {
|
||||
const walker = new Walker(From)
|
||||
expect(walker.stuff).toEqual([
|
||||
expect(walker.body).toEqual([
|
||||
{
|
||||
type: 'CallExpression',
|
||||
source: 'from(db: "telegraf")',
|
||||
funcs: [
|
||||
{
|
||||
name: 'from',
|
||||
source: 'from(db: "telegraf")',
|
||||
arguments: [
|
||||
args: [
|
||||
{
|
||||
key: 'db',
|
||||
value: 'telegraf',
|
||||
|
@ -32,7 +33,7 @@ describe('IFQL.AST.Walker', () => {
|
|||
describe('a single string literal variable', () => {
|
||||
it('returns the expected list', () => {
|
||||
const walker = new Walker(StringLiteral)
|
||||
expect(walker.stuff).toEqual([
|
||||
expect(walker.body).toEqual([
|
||||
{
|
||||
type: 'VariableDeclaration',
|
||||
source: 'bux = "im a var"',
|
||||
|
@ -51,7 +52,7 @@ describe('IFQL.AST.Walker', () => {
|
|||
describe('a single expression variable', () => {
|
||||
it('returns the expected list', () => {
|
||||
const walker = new Walker(Expression)
|
||||
expect(walker.stuff).toEqual([
|
||||
expect(walker.body).toEqual([
|
||||
{
|
||||
type: 'VariableDeclaration',
|
||||
source: 'tele = from(db: "telegraf")',
|
||||
|
@ -64,7 +65,7 @@ describe('IFQL.AST.Walker', () => {
|
|||
{
|
||||
name: 'from',
|
||||
source: 'from(db: "telegraf")',
|
||||
arguments: [
|
||||
args: [
|
||||
{
|
||||
key: 'db',
|
||||
value: 'telegraf',
|
||||
|
@ -83,22 +84,23 @@ describe('IFQL.AST.Walker', () => {
|
|||
})
|
||||
|
||||
describe('complex example', () => {
|
||||
it('returns a flattened ordered list of all funcs and their arguments', () => {
|
||||
it('returns a flattened ordered list of all funcs and their args', () => {
|
||||
const walker = new Walker(Complex)
|
||||
expect(walker.stuff).toEqual([
|
||||
expect(walker.body).toEqual([
|
||||
{
|
||||
type: 'PipeExpression',
|
||||
source:
|
||||
'from(db: "telegraf") |> filter(fn: (r) => r["_measurement"] == "cpu") |> range(start: -1m)',
|
||||
funcs: [
|
||||
{
|
||||
name: 'from',
|
||||
source: 'from(db: "telegraf")',
|
||||
arguments: [{key: 'db', value: 'telegraf'}],
|
||||
args: [{key: 'db', value: 'telegraf'}],
|
||||
},
|
||||
{
|
||||
name: 'filter',
|
||||
source: '|> filter(fn: (r) => r["_measurement"] == "cpu")',
|
||||
arguments: [
|
||||
args: [
|
||||
{
|
||||
key: 'fn',
|
||||
value: '(r) => r["_measurement"] == "cpu"',
|
||||
|
@ -108,7 +110,7 @@ describe('IFQL.AST.Walker', () => {
|
|||
{
|
||||
name: 'range',
|
||||
source: '|> range(start: -1m)',
|
||||
arguments: [{key: 'start', value: '-1m'}],
|
||||
args: [{key: 'start', value: '-1m'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
import {bodyNodes} from 'src/ifql/helpers'
|
||||
import suggestions from 'test/ifql/semantic_graph/suggestions'
|
||||
import Variables from 'test/ifql/ast/variables'
|
||||
import {Expression, StringLiteral} from 'test/ifql/ast/variable'
|
||||
import From from 'test/ifql/ast/from'
|
||||
|
||||
const id = expect.any(String)
|
||||
|
||||
describe('IFQL.helpers', () => {
|
||||
describe('bodyNodes', () => {
|
||||
describe('bodyNodes for Expressions assigned to a variable', () => {
|
||||
it('can parse an Expression assigned to a Variable', () => {
|
||||
const actual = bodyNodes(Expression, suggestions)
|
||||
const expected = [
|
||||
{
|
||||
declarations: [
|
||||
{
|
||||
funcs: [
|
||||
{
|
||||
args: [{key: 'db', type: 'string', value: 'telegraf'}],
|
||||
id,
|
||||
name: 'from',
|
||||
source: 'from(db: "telegraf")',
|
||||
},
|
||||
],
|
||||
id,
|
||||
name: 'tele',
|
||||
source: 'tele = from(db: "telegraf")',
|
||||
type: 'CallExpression',
|
||||
},
|
||||
],
|
||||
id,
|
||||
source: 'tele = from(db: "telegraf")',
|
||||
type: 'VariableDeclaration',
|
||||
},
|
||||
]
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('bodyNodes for a Literal assigned to a Variable', () => {
|
||||
it('can parse an Expression assigned to a Variable', () => {
|
||||
const actual = bodyNodes(StringLiteral, suggestions)
|
||||
const expected = [
|
||||
{
|
||||
id,
|
||||
source: 'bux = "im a var"',
|
||||
type: 'VariableDeclaration',
|
||||
declarations: [
|
||||
{
|
||||
id,
|
||||
name: 'bux',
|
||||
type: 'StringLiteral',
|
||||
value: 'im a var',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('bodyNodes for an Expression', () => {
|
||||
it('can parse an Expression into bodyNodes', () => {
|
||||
const actual = bodyNodes(From, suggestions)
|
||||
|
||||
const expected = [
|
||||
{
|
||||
declarations: [],
|
||||
funcs: [
|
||||
{
|
||||
args: [{key: 'db', type: 'string', value: 'telegraf'}],
|
||||
id,
|
||||
name: 'from',
|
||||
source: 'from(db: "telegraf")',
|
||||
},
|
||||
],
|
||||
id,
|
||||
source: 'from(db: "telegraf")',
|
||||
type: 'CallExpression',
|
||||
},
|
||||
]
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('multiple bodyNodes', () => {
|
||||
it('can parse variables and expressions together', () => {
|
||||
const actual = bodyNodes(Variables, suggestions)
|
||||
const expected = [
|
||||
{
|
||||
declarations: [
|
||||
{
|
||||
id,
|
||||
name: 'bux',
|
||||
type: 'StringLiteral',
|
||||
value: 'ASDFASDFASDF',
|
||||
},
|
||||
],
|
||||
id,
|
||||
source: 'bux = "ASDFASDFASDF"',
|
||||
type: 'VariableDeclaration',
|
||||
},
|
||||
{
|
||||
declarations: [
|
||||
{
|
||||
funcs: [
|
||||
{
|
||||
args: [{key: 'db', type: 'string', value: 'foo'}],
|
||||
id,
|
||||
name: 'from',
|
||||
source: 'from(db: "foo")',
|
||||
},
|
||||
],
|
||||
id,
|
||||
name: 'foo',
|
||||
source: 'foo = from(db: "foo")',
|
||||
type: 'CallExpression',
|
||||
},
|
||||
],
|
||||
id,
|
||||
source: 'foo = from(db: "foo")',
|
||||
type: 'VariableDeclaration',
|
||||
},
|
||||
{
|
||||
declarations: [],
|
||||
funcs: [
|
||||
{
|
||||
args: [{key: 'db', type: 'string', value: 'bux'}],
|
||||
id,
|
||||
name: 'from',
|
||||
source: 'from(db: bux)',
|
||||
},
|
||||
],
|
||||
id,
|
||||
source: 'from(db: bux)',
|
||||
type: 'CallExpression',
|
||||
},
|
||||
]
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,93 @@
|
|||
export default [
|
||||
{
|
||||
name: '_highestOrLowest',
|
||||
params: {
|
||||
_sortLimit: 'invalid',
|
||||
by: 'invalid',
|
||||
cols: 'array',
|
||||
n: 'invalid',
|
||||
reducer: 'function',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '_sortLimit',
|
||||
params: {cols: 'array', desc: 'invalid', n: 'invalid'},
|
||||
},
|
||||
{name: 'bottom', params: {cols: 'array', n: 'invalid'}},
|
||||
{name: 'count', params: {}},
|
||||
{
|
||||
name: 'cov',
|
||||
params: {on: 'invalid', pearsonr: 'bool', x: 'invalid', y: 'invalid'},
|
||||
},
|
||||
{name: 'covariance', params: {pearsonr: 'bool'}},
|
||||
{name: 'derivative', params: {nonNegative: 'bool', unit: 'duration'}},
|
||||
{name: 'difference', params: {nonNegative: 'bool'}},
|
||||
{name: 'distinct', params: {column: 'string'}},
|
||||
{name: 'filter', params: {fn: 'function'}},
|
||||
{name: 'first', params: {column: 'string', useRowTime: 'bool'}},
|
||||
{name: 'from', params: {db: 'string'}},
|
||||
{name: 'group', params: {by: 'array', except: 'array', keep: 'array'}},
|
||||
{
|
||||
name: 'highestAverage',
|
||||
params: {by: 'invalid', cols: 'array', n: 'invalid'},
|
||||
},
|
||||
{
|
||||
name: 'highestCurrent',
|
||||
params: {by: 'invalid', cols: 'array', n: 'invalid'},
|
||||
},
|
||||
{name: 'highestMax', params: {by: 'invalid', cols: 'array', n: 'invalid'}},
|
||||
{name: 'integral', params: {unit: 'duration'}},
|
||||
{name: 'join', params: {}},
|
||||
{name: 'last', params: {column: 'string', useRowTime: 'bool'}},
|
||||
{name: 'limit', params: {}},
|
||||
{
|
||||
name: 'lowestAverage',
|
||||
params: {by: 'invalid', cols: 'array', n: 'invalid'},
|
||||
},
|
||||
{
|
||||
name: 'lowestCurrent',
|
||||
params: {by: 'invalid', cols: 'array', n: 'invalid'},
|
||||
},
|
||||
{name: 'lowestMin', params: {by: 'invalid', cols: 'array', n: 'invalid'}},
|
||||
{name: 'map', params: {fn: 'function'}},
|
||||
{name: 'max', params: {column: 'string', useRowTime: 'bool'}},
|
||||
{name: 'mean', params: {}},
|
||||
{name: 'median', params: {compression: 'float', exact: 'bool'}},
|
||||
{name: 'min', params: {column: 'string', useRowTime: 'bool'}},
|
||||
{name: 'pearsonr', params: {on: 'invalid', x: 'invalid', y: 'invalid'}},
|
||||
{name: 'percentile', params: {p: 'float'}},
|
||||
{name: 'range', params: {start: 'time', stop: 'time'}},
|
||||
{name: 'sample', params: {column: 'string', useRowTime: 'bool'}},
|
||||
{name: 'set', params: {key: 'string', value: 'string'}},
|
||||
{name: 'shift', params: {shift: 'duration'}},
|
||||
{name: 'skew', params: {}},
|
||||
{name: 'sort', params: {cols: 'array'}},
|
||||
{name: 'spread', params: {}},
|
||||
{name: 'stateCount', params: {fn: 'invalid', label: 'string'}},
|
||||
{
|
||||
name: 'stateDuration',
|
||||
params: {fn: 'invalid', label: 'string', unit: 'duration'},
|
||||
},
|
||||
{
|
||||
name: 'stateTracking',
|
||||
params: {
|
||||
countLabel: 'string',
|
||||
durationLabel: 'string',
|
||||
durationUnit: 'duration',
|
||||
fn: 'function',
|
||||
},
|
||||
},
|
||||
{name: 'stddev', params: {}},
|
||||
{name: 'sum', params: {}},
|
||||
{name: 'top', params: {cols: 'array', n: 'invalid'}},
|
||||
{
|
||||
name: 'window',
|
||||
params: {
|
||||
every: 'duration',
|
||||
period: 'duration',
|
||||
round: 'duration',
|
||||
start: 'time',
|
||||
},
|
||||
},
|
||||
{name: 'yield', params: {name: 'string'}},
|
||||
]
|
Loading…
Reference in New Issue