diff --git a/src/app/controllers/graphiteTarget.js b/src/app/controllers/graphiteTarget.js index 1de3e7c1c2c..43620c7bd87 100644 --- a/src/app/controllers/graphiteTarget.js +++ b/src/app/controllers/graphiteTarget.js @@ -17,6 +17,8 @@ function (angular, _, config, gfunc, Parser) { parseTarget(); }; + // The way parsing and the target editor works needs + // to be rewritten to handle functions that take multiple series function parseTarget() { $scope.functions = []; $scope.segments = []; @@ -72,7 +74,13 @@ function (angular, _, config, gfunc, Parser) { throw { message: 'invalid number of parameters to method ' + func.def.name }; } - func.params[index - 1] = astNode.value; + if (index === 0) { + func.params[index] = astNode.value; + } + else { + func.params[index - 1] = astNode.value; + } + break; case 'metric': @@ -141,16 +149,7 @@ function (angular, _, config, gfunc, Parser) { } function wrapFunction(target, func) { - var targetWrapped = func.def.name + '(' + target; - _.each(func.params, function(param) { - if (_.isString(param)) { - targetWrapped += ",'" + param + "'"; - } - else { - targetWrapped += "," + param; - } - }); - return targetWrapped + ')'; + return func.render(target); } $scope.getAltSegments = function (index) { diff --git a/src/app/services/graphite/gfunc.js b/src/app/services/graphite/gfunc.js index 92a802f63ec..4eb0016e6a0 100644 --- a/src/app/services/graphite/gfunc.js +++ b/src/app/services/graphite/gfunc.js @@ -31,13 +31,6 @@ function (_) { defaultParams: [1], }); - addFuncDef({ - name: "alias", - category: categories.Special, - params: [ { name: "alias", type: 'string' } ], - defaultParams: ['alias'] - }); - addFuncDef({ name: "holtWintersForecast", category: categories.Calculate, @@ -69,6 +62,20 @@ function (_) { category: categories.Combine, }); + addFuncDef({ + name: "alias", + category: categories.Special, + params: [ { name: "alias", type: 'string' } ], + defaultParams: ['alias'] + }); + + addFuncDef({ + name: "aliasSub", + category: categories.Special, + params: [ { name: "search", type: 'string' }, { name: "replace", type: 'string' } ], + defaultParams: ['', ''] + }); + addFuncDef({ name: "groupByNode", category: categories.Special, @@ -94,6 +101,30 @@ function (_) { defaultParams: [3] }); + addFuncDef({ + name: 'aliasByMetric', + category: categories.Special, + }); + + addFuncDef({ + name: 'randomWalk', + category: categories.Special, + params: [ { name: "name", type: "string", } ], + defaultParams: ['randomWalk'] + }); + + addFuncDef({ + name: 'countSeries', + category: categories.Special + }); + + addFuncDef({ + name: 'constantLine', + category: categories.Special, + params: [ { name: "value", type: "int", } ], + defaultParams: [10] + }); + addFuncDef({ name: 'scale', category: categories.Transform, @@ -125,6 +156,25 @@ function (_) { defaultParams: ['1h'] }); + addFuncDef({ + name: 'absolute', + category: categories.Transform, + }); + + addFuncDef({ + name: 'averageAbove', + category: categories.Filter, + params: [ { name: "n", type: "int", } ], + defaultParams: [25] + }); + + addFuncDef({ + name: 'averageBelow', + category: categories.Filter, + params: [ { name: "n", type: "int", } ], + defaultParams: [25] + }); + _.each(categories, function(funcList, catName) { categories[catName] = _.sortBy(funcList, 'name'); }); @@ -135,6 +185,19 @@ function (_) { this.updateText(); } + FuncInstance.prototype.render = function (metricExp) { + var str = this.def.name + '('; + var parameters = _.map(this.params, function(value) { + return _.isString(value) ? "'" + value + "'" : value; + }); + + if (metricExp !== undefined) { + parameters.unshift(metricExp); + } + + return str + parameters.join(',') + ')'; + }; + FuncInstance.prototype.updateText = function () { if (this.params.length === 0) { this.text = this.def.name + '()'; diff --git a/src/test/specs/gfunc-specs.js b/src/test/specs/gfunc-specs.js index 0a4e637f9c2..4ded6eb87ef 100644 --- a/src/test/specs/gfunc-specs.js +++ b/src/test/specs/gfunc-specs.js @@ -2,7 +2,7 @@ define([ 'app/services/graphite/gfunc' ], function(gfunc) { - describe('when creating func instance from func namae', function() { + describe('when creating func instance from func names', function() { it('should return func instance', function() { var func = gfunc.createFuncInstance('sumSeries'); @@ -34,11 +34,33 @@ define([ }); + describe('when rendering func instance', function() { + + it('should handle single metric param', function() { + var func = gfunc.createFuncInstance('sumSeries'); + expect(func.render('hello.metric')).to.equal("sumSeries(hello.metric)"); + }); + + it('should handle metric param and int param and string param', function() { + var func = gfunc.createFuncInstance('groupByNode'); + func.params[0] = 5; + func.params[1] = 'avg'; + expect(func.render('hello.metric')).to.equal("groupByNode(hello.metric,5,'avg')"); + }); + + it('should handle function with no metric param', function() { + var func = gfunc.createFuncInstance('randomWalk'); + func.params[0] = 'test'; + expect(func.render(undefined)).to.equal("randomWalk('test')"); + }); + + }); + describe('when requesting function categories', function() { it('should return function categories', function() { var catIndex = gfunc.getCategories(); - expect(catIndex.Special.length).to.equal(3); + expect(catIndex.Special.length).to.equal(7); }); }); diff --git a/src/test/specs/parser-specs.js b/src/test/specs/parser-specs.js index 00420c65c68..af3b5376130 100644 --- a/src/test/specs/parser-specs.js +++ b/src/test/specs/parser-specs.js @@ -20,6 +20,14 @@ define([ expect(rootNode.params.length).to.be(1); }); + it('simple function with string arg', function() { + var parser = new Parser("randomWalk('test')"); + var rootNode = parser.getAst(); + expect(rootNode.type).to.be('function'); + expect(rootNode.params.length).to.be(1); + expect(rootNode.params[0].type).to.be('string'); + }); + it('function with multiple args', function() { var parser = new Parser("sum(test, 1, 'test')"); var rootNode = parser.getAst();