Browse Source

Feature addition : WHERE clause

version 0.0.8
pull/8/head
oof1lab 7 years ago
parent
commit
7df4c93a30
  1. 58
      README.md
  2. 2
      lib/util/cmd.helper.js
  3. 56
      lib/util/whereClause.helper.js
  4. 52
      lib/xapi.js
  5. 22
      lib/xsql.js
  6. 2
      package.json
  7. 196
      tests/tests.js

58
README.md

@ -36,18 +36,19 @@ That's it!
* Serves APIs irrespective of naming conventions of primary keys, foreign keys, tables etc
* CRUD : Usual suspects
* Support for composite primary keys
* Pagination
* Sorting
* Column filtering - Fields
* Group By
* Group By, Order By
* Pagination :tada:
* Sorting :tada:
* Column filtering - Fields :tada:
* Row filtering - Where :tada:
* Group By :tada:
* Group By, Order By :tada:
* Aggregate functions :tada:
* Relations
* Relations :tada: :tada:
* Run dynamic queries
* Upload single file
* Upload multiple files
* Download file
* Row filtering - Where - Work in progress :racehorse:
* Group By, Having - Work in Progress - :racehorse::racehorse:
Use HTTP clients like [Postman](https://www.getpostman.com/) or [similar tools](https://chrome.google.com/webstore/search/http%20client?_category=apps) to invoke REST API calls
@ -144,7 +145,48 @@ eg: gets only customerNumber and checkNumber in response of each record
eg: gets all fields in table row but not checkNumber
## Row filtering / Where
> Work in progress
#### Comparison operators
```
eq - '='
ne - '!='
gt - '>'
gte - '>='
lt - '<'
lte - '<='
```
#### Use of comparison operators
```
/api/payments?_where=(checkNumber,eq,JM555205)
```
#### Logical operators
```
~or - 'or'
~and - 'and'
~xor - 'xor'
```
#### Use of logical operators
```
/api/payments?_where=(checkNumber,eq,JM555205)~or(checkNumber,eq,OM314933)
```
eg: complex parentheses
```
/api/payments?_where=((checkNumber,eq,JM555205)~or(checkNumber,eq,OM314933))~and(amount,gt,100)
```
eg: where with sorting(_sort), pagination(_p), column filtering (_fields)
```
/api/payments?_where=(amount,gte,1000)&_sort=-amount&p=2&&_fields=customerNumber
```
eg: filter of rows using _where is available for relational route URLs too.
```
/api/offices/1/employees?_where=(jobTitle,eq,Sales%20Rep)
```
## Group By

2
lib/util/cmd.helper.js

@ -11,7 +11,7 @@ program.on('--help', () => {
})
program
.version('0.0.6')
.version('0.0.8')
.option('-h, --host <n>', 'hostname')
.option('-d, --database <n>', 'database schema name')
.option('-u, --user <n>', 'username of database / root by default')

56
lib/util/whereClause.helper.js

@ -54,13 +54,29 @@ function getComparisonOperator(operator) {
return '>='
break;
case 'like':
return ' like '
break;
// case 'is':
// return ' is '
// break;
case 'nlike':
return ' not like '
break;
// case 'isnot':
// return ' is not '
// break;
// case 'isnull':
// return ' is NULL '
// break;
// case 'isnnull':
// return ' is not NULL '
// break;
// case 'like':
// return ' like '
// break;
// case 'nlike':
// return ' not like '
// break;
// case 'in':
// return ' in '
@ -79,19 +95,19 @@ function getLogicalOperator(operator) {
switch (operator) {
case '+or':
case '~or':
return 'or'
break;
case '+and':
case '~and':
return 'and'
break;
case '+not':
return 'not'
break;
// case '~not':
// return 'not'
// break;
case '+xor':
case '~xor':
return 'xor'
break;
@ -103,17 +119,22 @@ function getLogicalOperator(operator) {
}
exports.getWhereClause = function (whereInQueryParams, whereQuery, whereParams) {
exports.getWhereClause = function (whereInQueryParams) {
let whereQuery = '';
let whereParams = [];
let grammarErr = 0;
let numOfConditions = whereInQueryParams.split(/\+or|\+and|\+not|\+xor/);
let logicalOperatorsInClause = whereInQueryParams.match(/(\+or|\+and|\+not|\+xor)/g)
let numOfConditions = whereInQueryParams.split(/~or|~and|~not|~xor/);
let logicalOperatorsInClause = whereInQueryParams.match(/(~or|~and|~not|~xor)/g)
if (numOfConditions && logicalOperatorsInClause && numOfConditions.length !== logicalOperatorsInClause.length + 1) {
console.log('conditions and logical operators mismatch', numOfConditions.length, logicalOperatorsInClause.length);
return
}
// console.log('numOfConditions',numOfConditions,whereInQueryParams);
// console.log('logicalOperatorsInClause',logicalOperatorsInClause);
for (var i = 0; i < numOfConditions.length; ++i) {
let variable = ''
@ -178,7 +199,7 @@ exports.getWhereClause = function (whereInQueryParams, whereQuery, whereParams)
}
whereParams.push(variableValue[1])
// then replace the variableName with ?
// then replace the variableValue with ?
temp = replaceWhereParamsToQMarks(false, result[2])
if (!temp) {
grammarErr = 1;
@ -220,9 +241,6 @@ exports.getWhereClause = function (whereInQueryParams, whereQuery, whereParams)
obj['params'] = whereParams
}
return obj
}

52
lib/xapi.js

@ -212,29 +212,45 @@ class Xapi {
async list(req, res) {
let queryParamsObj = {}
queryParamsObj.query = '';
queryParamsObj.params = [];
let cols = this.mysql.getColumnsForSelectStmt(req.app.locals._tableName, req.query);
let query = 'select ' + cols + ' from ?? ';
let params = [];
params.push(req.app.locals._tableName);
query = query + this.mysql.getOrderByClause(req.query, req.app.locals._tableName);
/**************** tableName ****************/
queryParamsObj.query = 'select ' + cols + ' from ?? ';
queryParamsObj.params.push(req.app.locals._tableName);
query = query + ' limit ?,? '
params = params.concat(this.mysql.getLimitClause(req.query));
/**************** where clause ****************/
this.mysql.getWhereClause(req.query, req.app.locals._tableName, queryParamsObj,' where ');
let results = await this.mysql.exec(query, params);
/**************** order clause ****************/
queryParamsObj.query += this.mysql.getOrderByClause(req.query, req.app.locals._tableName);
/**************** limit clause ****************/
queryParamsObj.query += ' limit ?,? '
queryParamsObj.params = queryParamsObj.params.concat(this.mysql.getLimitClause(req.query));
//console.log(queryParamsObj.query, queryParamsObj.params);
let results = await this.mysql.exec(queryParamsObj.query, queryParamsObj.params);
res.status(200).json(results);
}
async nestedList(req, res) {
let cols = this.mysql.getColumnsForSelectStmt(req.app.locals._childTable, req.query);
let query = 'select ' + cols + ' from ?? where ';
let params = [];
let queryParamsObj = {}
queryParamsObj.query = '';
queryParamsObj.params = [];
params.push(req.app.locals._childTable);
/**************** tableName ****************/
let cols = this.mysql.getColumnsForSelectStmt(req.app.locals._childTable, req.query);
queryParamsObj.query = 'select ' + cols + ' from ?? where ';
queryParamsObj.params.push(req.app.locals._childTable);
/**************** where foreign key ****************/
let whereClause = this.mysql.getForeignKeyWhereClause(req.app.locals._parentTable,
req.params.id,
req.app.locals._childTable);
@ -244,15 +260,19 @@ class Xapi {
error: "Table is made of composite primary keys - all keys were not in input"
})
}
queryParamsObj.query += whereClause;
query += whereClause;
/**************** where conditions in query ****************/
this.mysql.getWhereClause(req.query, req.app.locals._tableName, queryParamsObj, ' and ');
query = query + this.mysql.getOrderByClause(req.query, req.app.locals._parentTable);
/**************** order clause ****************/
queryParamsObj.query = queryParamsObj.query + this.mysql.getOrderByClause(req.query, req.app.locals._parentTable);
query = query + ' limit ?,? '
params = params.concat(this.mysql.getLimitClause(req.query));
/**************** limit clause ****************/
queryParamsObj.query = queryParamsObj.query + ' limit ?,? '
queryParamsObj.params = queryParamsObj.params.concat(this.mysql.getLimitClause(req.query));
let results = await this.mysql.exec(query, params);
let results = await this.mysql.exec(queryParamsObj.query, queryParamsObj.params);
res.status(200).json(results);
}

22
lib/xsql.js

@ -2,8 +2,10 @@
const mysql = require('mysql');
const dataHelp = require('./util/data.helper.js');
const whereHelp = require('./util/whereClause.helper.js');
const assert = require('assert')
//define class
class Xsql {
@ -171,6 +173,24 @@ class Xsql {
}
getWhereClause(queryparams, tableName, queryParamsObj, appendToWhere) {
let addWhereStr = ''
if (queryparams && queryparams._where) {
let whereClauseObj = whereHelp.getWhereClause(queryparams._where)
if (whereClauseObj.err === 0) {
queryParamsObj.query = queryParamsObj.query + appendToWhere + whereClauseObj.query;
queryParamsObj.params = queryParamsObj.params.concat(whereClauseObj.params)
}
//console.log('> > > after where clause filling up:', queryParamsObj.query, queryParamsObj.params);
}
}
getOrderByClause(queryparams, tableName) {
//defaults
@ -217,7 +237,7 @@ class Xsql {
// get column name in _fields and mark column name which start with '-'
for (let i = 0; i < _fieldsInQuery.length; ++i) {
if (_fieldsInQuery[i][0] == '-') {
if (_fieldsInQuery[i][0] === '-') {
removeFieldsObj[_fieldsInQuery[i].substring(1, _fieldsInQuery[i].length)] = 1;
} else {
cols.push(_fieldsInQuery[i])

2
package.json

@ -1,6 +1,6 @@
{
"name": "xmysql",
"version": "0.0.6",
"version": "0.0.8",
"description": "One command to generate REST APIs for any MySql database",
"main": "index.js",
"scripts": {

196
tests/tests.js

@ -504,6 +504,88 @@ describe('xmysql : tests', function () {
});
});
it('GET /api/offices/1/employees?_where=(jobTitle,eq,Sales%20Rep) should PASS', function (done) {
//post to an url with data
agent.get('/api/offices/1/employees?_where=(jobTitle,eq,Sales%20Rep)') //enter url
.expect(200)//200 for success 4xx for failure
.end(function (err, res) {
// Handle /api/v error
if (err) {
return done(err);
}
//validate response
res.body.length.should.be.equals(2)
return done();
});
});
it('GET /api/payments?_where=(amount,gte,1000)~and(customerNumber,lte,120) should PASS', function (done) {
//post to an url with data
agent.get('/api/payments?_where=(amount,gte,1000)~and(customerNumber,lte,120)') //enter url
.expect(200)//200 for success 4xx for failure
.end(function (err, res) {
// Handle /api/v error
if (err) {
return done(err);
}
//validate response
res.body.length.should.be.equals(13)
return done();
});
});
it('GET /api/payments?_where=(amount,gte,1000)&_sort=-amount should PASS', function (done) {
//post to an url with data
agent.get('/api/payments?_where=(amount,gte,1000)&_sort=-amount') //enter url
.expect(200)//200 for success 4xx for failure
.end(function (err, res) {
// Handle /api/v error
if (err) {
return done(err);
}
//validate response
res.body[0].amount.should.be.equals(120166.58)
return done();
});
});
http://localhost:3000/api/payments?_where=(checkNumber,eq,JM555205)~or(checkNumber,eq,OM314933)
it('GET /api/payments?_where=(checkNumber,eq,JM555205)~or(checkNumber,eq,OM314933) should PASS', function (done) {
//post to an url with data
agent.get('/api/payments?_where=(checkNumber,eq,JM555205)~or(checkNumber,eq,OM314933)') //enter url
.expect(200)//200 for success 4xx for failure
.end(function (err, res) {
// Handle /api/v error
if (err) {
return done(err);
}
//validate response
res.body.length.should.be.equals(2)
return done();
});
});
it('GET /api/employees/1002/employees should PASS', function (done) {
//post to an url with data
@ -753,7 +835,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,eq,1234)',query,params)
var err = whereClause.getWhereClause('(abc,eq,1234)')
err.err.should.be.equal(0)
err.query.should.be.equal('(??=?)')
@ -771,7 +853,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,ne,1234)',query,params)
var err = whereClause.getWhereClause('(abc,ne,1234)')
err.err.should.be.equal(0)
err.query.should.be.equal('(??!=?)')
@ -789,7 +871,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,lt,1234)',query,params)
var err = whereClause.getWhereClause('(abc,lt,1234)')
err.err.should.be.equal(0)
err.query.should.be.equal('(??<?)')
@ -806,7 +888,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,lte,1234)',query,params)
var err = whereClause.getWhereClause('(abc,lte,1234)')
err.err.should.be.equal(0)
err.query.should.be.equal('(??<=?)')
@ -823,7 +905,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,gt,1234)',query,params)
var err = whereClause.getWhereClause('(abc,gt,1234)')
err.err.should.be.equal(0)
err.query.should.be.equal('(??>?)')
@ -840,7 +922,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,gte,1234)',query,params)
var err = whereClause.getWhereClause('(abc,gte,1234)')
err.err.should.be.equal(0)
err.query.should.be.equal('(??>=?)')
@ -854,46 +936,46 @@ describe('xmysql : tests', function () {
});
it('where clause unit ?_where=(abc,like,1234) should PASS', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,like,1234)',query,params)
err.err.should.be.equal(0)
err.query.should.be.equal('(?? like ?)')
err.params[0].should.be.equal('abc')
err.params[1].should.be.equal('1234')
done()
//console.log(query,params,err);
});
it('where clause unit ?_where=(abc,nlike,1234) should PASS', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,nlike,1234)',query,params)
err.err.should.be.equal(0)
err.query.should.be.equal('(?? not like ?)')
err.params[0].should.be.equal('abc')
err.params[1].should.be.equal('1234')
done()
//console.log(query,params,err);
});
// it('where clause unit ?_where=(abc,like,1234) should PASS', function (done) {
//
// var query = ''
// var params = []
// var err = whereClause.getWhereClause('(abc,like,1234)')
//
// err.err.should.be.equal(0)
// err.query.should.be.equal('(?? like ?)')
// err.params[0].should.be.equal('abc')
// err.params[1].should.be.equal('1234')
//
// done()
//
// //console.log(query,params,err);
//
// });
//
//
// it('where clause unit ?_where=(abc,nlike,1234) should PASS', function (done) {
//
// var query = ''
// var params = []
// var err = whereClause.getWhereClause('(abc,nlike,1234)')
//
// err.err.should.be.equal(0)
// err.query.should.be.equal('(?? not like ?)')
// err.params[0].should.be.equal('abc')
// err.params[1].should.be.equal('1234')
//
// done()
//
// //console.log(query,params,err);
//
// });
it('where clause unit ?_where=abc,eq,1234) should FAIL', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('abc,eq,1234)',query,params)
var err = whereClause.getWhereClause('abc,eq,1234)')
err.err.should.be.equal(1)
err.query.should.be.equal('')
@ -909,7 +991,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,eq,1234',query,params)
var err = whereClause.getWhereClause('(abc,eq,1234')
err.err.should.be.equal(1)
err.query.should.be.equal('')
@ -925,7 +1007,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,eq1234)',query,params)
var err = whereClause.getWhereClause('(abc,eq1234)')
err.err.should.be.equal(1)
err.query.should.be.equal('')
@ -941,7 +1023,7 @@ describe('xmysql : tests', function () {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abceq,1234)',query,params)
var err = whereClause.getWhereClause('(abceq,1234)')
err.err.should.be.equal(1)
err.query.should.be.equal('')
@ -954,11 +1036,11 @@ describe('xmysql : tests', function () {
});
it('where clause unit ?_where=(1,eq,1)(1,eq,2)+or should FAIL', function (done) {
it('where clause unit ?_where=(1,eq,1)(1,eq,2)~or should FAIL', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('(1,eq,1)(1,eq,2)+or',query,params)
var err = whereClause.getWhereClause('(1,eq,1)(1,eq,2)~or')
err.err.should.be.equal(1)
err.query.should.be.equal('')
@ -970,11 +1052,11 @@ describe('xmysql : tests', function () {
});
it('where clause unit ?_where=(1,eq,1)+or+or(1,eq,2)(1,eq,2) should FAIL', function (done) {
it('where clause unit ?_where=(1,eq,1)~or~or(1,eq,2)(1,eq,2) should FAIL', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('(1,eq,1)+or+or(1,eq,2)(1,eq,2)',query,params)
var err = whereClause.getWhereClause('(1,eq,1)~or~or(1,eq,2)(1,eq,2)')
err.err.should.be.equal(1)
err.query.should.be.equal('')
@ -986,11 +1068,11 @@ describe('xmysql : tests', function () {
});
it('where clause unit ?_where=(abc,eq,1)+or(b,eq,2) should PASS', function (done) {
it('where clause unit ?_where=(abc,eq,1)~or(b,eq,2) should PASS', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('(abc,eq,1)+or(b,eq,2)',query,params)
var err = whereClause.getWhereClause('(abc,eq,1)~or(b,eq,2)')
err.err.should.be.equal(0)
err.query.should.be.equal('(??=?)or(??=?)')
@ -1009,11 +1091,11 @@ describe('xmysql : tests', function () {
});
it('where clause unit ?_where=((a,eq,1)+and(b,eq,2))+or(c,eq,3) should PASS', function (done) {
it('where clause unit ?_where=((a,eq,1)~and(b,eq,2))~or(c,eq,3) should PASS', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('((abc,eq,1234)+and(b,eq,2))+or(cde,eq,3)',query,params)
var err = whereClause.getWhereClause('((abc,eq,1234)~and(b,eq,2))~or(cde,eq,3)')
err.err.should.be.equal(0)
err.query.should.be.equal('((??=?)and(??=?))or(??=?)')
@ -1032,11 +1114,11 @@ describe('xmysql : tests', function () {
});
it('where clause unit ?_where=((a,eq,1)+and(b,eq,2))+xor(c,eq,3) should PASS', function (done) {
it('where clause unit ?_where=((a,eq,1)~and(b,eq,2))~xor(c,eq,3) should PASS', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('((abc,eq,1234)+and(b,eq,2))+xor(cde,eq,3)',query,params)
var err = whereClause.getWhereClause('((abc,eq,1234)~and(b,eq,2))~xor(cde,eq,3)')
err.err.should.be.equal(0)
err.query.should.be.equal('((??=?)and(??=?))xor(??=?)')
@ -1055,11 +1137,13 @@ describe('xmysql : tests', function () {
});
it('where clause unit ?_where=(a,eq,1)+and((b,eq,2)+or(c,eq,3)) should PASS', function (done) {
it('where clause unit ?_where=(a,eq,1)~and((b,eq,2)~or(c,eq,3)) should PASS', function (done) {
var query = ''
var params = []
var err = whereClause.getWhereClause('(a,eq,1)+and((b,eq,2)+or(c,eq,3))',query,params)
var err = whereClause.getWhereClause('(a,eq,1)~and((b,eq,2)~or(c,eq,3))')
//console.log(query,params);
err.err.should.be.equal(0)
err.query.should.be.equal('(??=?)and((??=?)or(??=?))')

Loading…
Cancel
Save