diff --git a/README.md b/README.md index 2d1c1a21a3..df261a1ef4 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Powered by popular node packages : ([express](https://github.com/expressjs/expre * Group By, Having (as query params) :fire::fire: * Group By, Having (as a separate API) :fire::fire: * Multiple group by in one API :fire::fire: -* Chart API for numeric column :fire::fire: +* Chart API for numeric column :fire::fire::fire::fire::fire::fire: * Supports views * Prototyping (features available when using local MySql server only) * Run dynamic queries :fire::fire::fire: @@ -431,11 +431,11 @@ response body ## Chart [:arrow_heading_up:](#api-overview) -:fire::fire: **[ HOTNESS ALERT ]** +:fire::fire::fire::fire::fire::fire: **[ HOTNESS ALERT ]** Chart API returns distribution of a numeric column in a table -It comes in three flavours +It comes in **SIX** powerful flavours 1. Chart : With min, max, step in query params :fire::fire: [:arrow_heading_up:](#api-overview) @@ -550,6 +550,55 @@ Response ``` +4. Chart : With min, max, step in query params :fire::fire: + [:arrow_heading_up:](#api-overview) + + This API returns the number of rows where amount is between (0,25000), (0,50000) ... (0,maxValue) + + Number of records for amount is calculated everytime from min value to extended Range instead of incremental steps + + ``` + /api/payments/chart?_fields=amount&min=0&max=131000&step=25000&range=1 + + Response + +[ + { + "amount": "0 to 25000", + "_count": 107 + }, + { + "amount": "0 to 50000", + "_count": 231 + }, + { + "amount": "0 to 75000", + "_count": 261 + }, + { + "amount": "0 to 100000", + "_count": 268 + }, + { + "amount": "0 to 125000", + "_count": 273 + } +] + + ``` + +5. Range can be specified to other variations of chart operation #2 and #3 like below + + ``` +/api/payments/chart?_fields=amount&steparray=0,10000,20000,70000,140000 + ``` + +6. + +``` +/api/payments/chart?_fields=amount&range=1 +``` + Please Note: _fields in Chart API can only take numeric column as its argument. diff --git a/lib/util/cmd.helper.js b/lib/util/cmd.helper.js index 8b50e47dc2..349f328e59 100644 --- a/lib/util/cmd.helper.js +++ b/lib/util/cmd.helper.js @@ -11,7 +11,7 @@ program.on('--help', () => { }) program - .version('0.3.0') + .version('0.3.1') .option('-h, --host ', 'hostname / localhost by default') .option('-u, --user ', 'username of database / root by default') .option('-p, --password ', 'password of database / empty by default') diff --git a/lib/util/data.helper.js b/lib/util/data.helper.js index 2525bf2faa..75f3dcf490 100644 --- a/lib/util/data.helper.js +++ b/lib/util/data.helper.js @@ -66,7 +66,7 @@ exports.numberGetFixed = (number) => { return parseInt(number.toFixed()) } -exports.getRangeSimple = function (min, max, step) { +exports.getStepArraySimple = function (min, max, step) { var arr = [] for (var i = min; i <= max; i = i + step) { @@ -77,7 +77,7 @@ exports.getRangeSimple = function (min, max, step) { }; -exports.getRange = (min, max, stddev) => { +exports.getStepArray = (min, max, stddev) => { // console.log(' = = = = = = = '); //console.log('original numbers', min, max, stddev); diff --git a/lib/xapi.js b/lib/xapi.js index 8c36e00c04..74c4f40b40 100644 --- a/lib/xapi.js +++ b/lib/xapi.js @@ -772,7 +772,16 @@ class Xapi { let params = [] let obj = {} - if (req.query && req.query._fields) { + + if (req.query) { + + let isRange = false + + if (req.query.range) { + + isRange = true + } + if (req.query && req.query.min && req.query.max && req.query.step) { @@ -782,14 +791,16 @@ class Xapi { req.query._fields, parseInt(req.query.min), parseInt(req.query.max), - parseInt(req.query.step)) + parseInt(req.query.step), + isRange) } else if (req.query && req.query.steparray && req.query.steparray.length > 1) { obj = this.mysql.getChartQueryAndParamsFromStepArray(req.app.locals._tableName, req.query._fields, - (req.query.steparray.split(',')).map(Number)) + (req.query.steparray.split(',')).map(Number), + isRange) } else { @@ -814,7 +825,8 @@ class Xapi { req.query._fields, results[0]['min'], results[0]['max'], - results[0]['stddev'] + results[0]['stddev'], + isRange ) } diff --git a/lib/xsql.js b/lib/xsql.js index 2aff769ee4..02e4277d5b 100644 --- a/lib/xsql.js +++ b/lib/xsql.js @@ -592,16 +592,16 @@ class Xsql { } - getChartQueryAndParamsFromStepArray(tableName, columnName, stepArray) { + getChartQueryAndParamsFromStepArray(tableName, columnName, stepArray, isRange = false) { let obj = {} obj.query = '' obj.params = [] - if (stepArray.length && stepArray.length >= 2) { + //console.log('getChartQueryAndParamsFromStepArray',isRange); - let params = [tableName, columnName, stepArray[0], stepArray[1]] + if (stepArray.length && stepArray.length >= 2) { for (let i = 0; i < stepArray.length - 1; i = i + 1) { @@ -610,16 +610,27 @@ class Xsql { obj.query = obj.query + ' union ' } - if (i) { + if (i && isRange === false) { stepArray[i] = stepArray[i] + 1 } - obj.params.push((stepArray[i]) + ' to ' + stepArray[i + 1]) + if (isRange === false) { + obj.params.push((stepArray[i]) + ' to ' + stepArray[i + 1]) + } else { + obj.params.push((stepArray[0]) + ' to ' + stepArray[i + 1]) + } + obj.params.push(columnName) obj.params.push(tableName) obj.params.push(columnName) - obj.params.push(stepArray[i]) - obj.params.push(stepArray[i + 1]) + + if (isRange === false) { + obj.params.push(stepArray[i]) + obj.params.push(stepArray[i + 1]) + } else { + obj.params.push(stepArray[0]) + obj.params.push(stepArray[i + 1]) + } } @@ -632,13 +643,13 @@ class Xsql { } - getChartQueryAndParamsFromMinMaxStddev(tableName, columnName, min, max, stddev) { + getChartQueryAndParamsFromMinMaxStddev(tableName, columnName, min, max, stddev, isRange = false) { - let stepArray = dataHelp.getRange(min, max, stddev) + let stepArray = dataHelp.getStepArray(min, max, stddev) //console.log('steparray', stepArray); - let obj = this.getChartQueryAndParamsFromStepArray(tableName, columnName, stepArray) + let obj = this.getChartQueryAndParamsFromStepArray(tableName, columnName, stepArray, isRange) //console.log('steparray', obj); @@ -646,13 +657,13 @@ class Xsql { } - getChartQueryAndParamsFromMinMaxStep(tableName, columnName, min, max, step) { + getChartQueryAndParamsFromMinMaxStep(tableName, columnName, min, max, step, isRange = false) { - let stepArray = dataHelp.getRangeSimple(min, max, step) + let stepArray = dataHelp.getStepArraySimple(min, max, step) //console.log('steparray', stepArray); - let obj = this.getChartQueryAndParamsFromStepArray(tableName, columnName, stepArray) + let obj = this.getChartQueryAndParamsFromStepArray(tableName, columnName, stepArray, isRange) //console.log('steparray', obj); diff --git a/package.json b/package.json index b1ccabf657..302046ed94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "xmysql", - "version": "0.3.0", + "version": "0.3.1", "description": "One command to generate REST APIs for any MySql database", "main": "index.js", "scripts": { diff --git a/tests/tests.js b/tests/tests.js index 0ffc8d2a1b..a98d36e6f4 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -783,7 +783,8 @@ describe('xmysql : tests', function () { }); }); - // something weird going on + // SOMETHING WEIRD HERE + // test in travis show 7 but on local machine result has 6 elements // it('GET /api/productlines?_where=(htmlDescription,is,null) should PASS', function (done) { // // //post to an url with data @@ -1203,6 +1204,28 @@ describe('xmysql : tests', function () { }); }) + it('GET /api/payments/chart?_fields=amount&min=0&max=131000&step=25000&range=1 should PASS', function (done) { + + //post to an url with data + agent.get('/api/payments/chart?_fields=amount&min=0&max=131000&step=25000&range=1') //enter url + .expect(200)//200 for success 4xx for failure + .end(function (err, res) { + // Handle /api/v error + if (err) { + return done(err); + } + + res.body.length.should.be.equals(5) + res.body[4]['_count'].should.be.equals(273) + res.body[1]['_count'].should.be.equals(231) + res.body[0]['_count'].should.be.equals(107) + + + return done(); + + }); + }) + it('GET /api/payments/chart?_fields=amount&steparray=0,50000,100000,140000 should PASS', function (done) { //post to an url with data @@ -1224,6 +1247,47 @@ describe('xmysql : tests', function () { }); }) + it('GET /api/payments/chart?_fields=amount&steparray=0,50000,100000,140000&range=1 should PASS', function (done) { + + //post to an url with data + agent.get('/api/payments/chart?_fields=amount&steparray=0,50000,100000,140000&range=1') //enter url + .expect(200)//200 for success 4xx for failure + .end(function (err, res) { + // Handle /api/v error + if (err) { + return done(err); + } + + res.body.length.should.be.equals(3) + res.body[0]['_count'].should.be.equals(231) + res.body[1]['_count'].should.be.equals(268) + res.body[2]['_count'].should.be.equals(273) + + return done(); + + }); + }) + + it('GET /api/payments/chart?_fields=amount&range=1 should PASS', function (done) { + + //post to an url with data + agent.get('/api/payments/chart?_fields=amount&range=1') //enter url + .expect(200)//200 for success 4xx for failure + .end(function (err, res) { + // Handle /api/v error + if (err) { + return done(err); + } + + res.body.length.should.be.equals(7) + res.body[0]['_count'].should.be.equals(45) + res.body[6]['_count'].should.be.equals(273) + + return done(); + + }); + }) + it('GET /api/offices/1/employees?_groupby=jobTitle&_having=(_count,gt,1) should PASS', function (done) { //post to an url with data @@ -1823,8 +1887,6 @@ describe('xmysql : tests', function () { var err = whereClause.getConditionClause('(a,is,null)~and(b,is,true)~and(c,is,false)') - //console.log(err.params[1],err); - err.err.should.be.equal(0) err.query.should.be.equal('(?? is ?)and(?? is ?)and(?? is ?)') //err.params[1].should.be.equal(null)