diff --git a/README.md b/README.md index 2337a5a8fd..9072e0842a 100644 --- a/README.md +++ b/README.md @@ -726,7 +726,7 @@ Sql join query: ```sql -SELECT * +SELECT pl.field1, pr.field2 FROM productlines as pl JOIN products as pr ON pl.productline = pr.productline @@ -735,14 +735,14 @@ FROM productlines as pl Equivalent xjoin query API: ``` -/api/xjoin?_join=pl.productlines,_j,pr.products&_on1=(pl.productline,eq,pr.productline) +/api/xjoin?_join=pl.productlines,_j,pr.products&_on1=(pl.productline,eq,pr.productline)&_fields=pl.field1,pr.field2 ``` #### Multiple tables join Sql join query: ```sql -SELECT * +SELECT pl.field1, pr.field2, ord.field3 FROM productlines as pl JOIN products as pr ON pl.productline = pr.productline @@ -753,7 +753,7 @@ FROM productlines as pl Equivalent xjoin query API: ``` -/api/xjoin?_join=pl.productlines,_j,pr.products,_j,ord.orderDetails&_on1=(pl.productline,eq,pr.productline)&_on2=(pr.productcode,eq,ord.productcode) +/api/xjoin?_join=pl.productlines,_j,pr.products,_j,ord.orderDetails&_on1=(pl.productline,eq,pr.productline)&_on2=(pr.productcode,eq,ord.productcode)&_fields=&_fields=pl.field1,pr.field2,ord.field3 ``` @@ -774,6 +774,16 @@ Example to use : _fields, _where, _p, _size in query params /api/xjoin?_join=pl.productlines,_j,pr.products&_on1=(pl.productline,eq,pr.productline)&_fields=pl.productline,pr.productName&_size=2&_where=(productName,like,1972~) ``` +Response: + +``` +[{"pl_productline":"Classic Cars","pr_productName":"1972 Alfa Romeo GTA"}] +``` + +Please note : +Xjoin response has aliases for fields like below aliasTableName + '_' + columnName. +eg: pl.productline in _fields query params - returns as pl_productline in response. + ## Run dynamic queries [:arrow_heading_up:](#api-overview) diff --git a/lib/xapi.js b/lib/xapi.js index a3b449b486..032fde41b0 100644 --- a/lib/xapi.js +++ b/lib/xapi.js @@ -304,9 +304,12 @@ class Xapi { this.mysql.prepareJoinQuery(req, res, obj) //console.log(obj); - - let results = await this.mysql.exec(obj.query, obj.params) - res.status(200).json(results) + if(obj.query.length){ + let results = await this.mysql.exec(obj.query, obj.params) + res.status(200).json(results) + } else { + res.status(400).json({err: 'Invalid Xjoin request'}); + } } diff --git a/lib/xsql.js b/lib/xsql.js index 3cb18b1f28..e590380cb9 100644 --- a/lib/xsql.js +++ b/lib/xsql.js @@ -139,6 +139,7 @@ class Xsql { } } } + /**************** END : Cache functions ****************/ @@ -249,7 +250,7 @@ class Xsql { /**************** START : prepare value object in prepared statement ****************/ - // iterate over sent object array + // iterate over sent object array let arrOfArr = [] for (var i = 0; i < objectArray.length; ++i) { let arrValues = [] @@ -670,7 +671,7 @@ class Xsql { //select ? as ??, count(*) as _count from ?? where ?? between ? and ? - if (stepArray.length && stepArray.length >= 2 && stepArray.length%2 === 0) { + if (stepArray.length && stepArray.length >= 2 && stepArray.length % 2 === 0) { for (let i = 0; i < stepArray.length && stepArray.length >= 2; i = i + 2) { @@ -954,93 +955,109 @@ class Xsql { queryParamsObj.query = 'SELECT ' queryParamsObj.grammarErr = 0; - /**************** START : get fields ****************/ - if (req.query._fields) { + while (1) { - let fields = req.query._fields.split(',') + /**************** START : get fields ****************/ + if (req.query._fields) { - // from _fields to - ??, ??, ?? [col1,col2,col3] - for (var i = 0; i < fields.length; ++i) { - if (i) { - queryParamsObj.query += ',' + let fields = req.query._fields.split(',') + + // from _fields to - ??, ??, ?? [col1,col2,col3] + for (var i = 0; i < fields.length && (!queryParamsObj.grammarErr); ++i) { + if (i) { + queryParamsObj.query += ',' + } + queryParamsObj.query += ' ?? ' + queryParamsObj.params.push(fields[i]) + let aliases = fields[i].split('.'); + if (aliases.length === 2) { + queryParamsObj.query += 'as ' + aliases[0] + '_' + aliases[1]; + //console.log(queryParamsObj.query); + } else { + queryParamsObj.grammarErr = 1; + } } - queryParamsObj.query += ' ?? ' - queryParamsObj.params.push(fields[i]) + } else { + queryParamsObj.grammarErr = 1; } - } else { + queryParamsObj.query += ' from ' - queryParamsObj.query += ' * ' + if(queryParamsObj.grammarErr){ + break; + } - } + /**************** END : get fields ****************/ - queryParamsObj.query += ' from ' - /**************** END : get fields ****************/ + /**************** START : get join + on ****************/ + let joinTables = req.query._join.split(',') + if (joinTables.length < 3) { + //console.log('grammar error ', joinTables.length); + queryParamsObj.grammarErr = 1; + break; + } - /**************** START : get join + on ****************/ - let joinTables = req.query._join.split(',') - if (joinTables.length < 3) { - //console.log('grammar error ', joinTables.length); - queryParamsObj.grammarErr = 1; - } + //console.log('jointables.length', joinTables); - //console.log('jointables.length', joinTables); + let onCondnCount = 0; - let onCondnCount = 0; + for (let i = 0; i < joinTables.length - 1 && queryParamsObj.grammarErr === 0; i = i + 2) { - for (let i = 0; i < joinTables.length - 1 && queryParamsObj.grammarErr === 0; i = i + 2) { + onCondnCount++; - onCondnCount++; + this._joinTableNames(i, joinTables, i, queryParamsObj) - this._joinTableNames(i, joinTables, i, queryParamsObj) + if (queryParamsObj.grammarErr) { + console.log('failed at _joinTableNames', queryParamsObj); + break; + } - if (queryParamsObj.grammarErr) { - console.log('failed at _joinTableNames', queryParamsObj); - break; - } + //console.log('after join tables', queryParamsObj); - //console.log('after join tables', queryParamsObj); + let onCondn = '_on' + (onCondnCount) + let onCondnObj = {} + if (onCondn in req.query) { + //console.log(onCondn, req.query[onCondn]); + onCondnObj = whereHelp.getConditionClause(req.query[onCondn], ' on ') + //console.log('onCondnObj', onCondnObj); + queryParamsObj.query += ' on ' + onCondnObj.query + queryParamsObj.params = queryParamsObj.params.concat(onCondnObj.params) + } else { + queryParamsObj.grammarErr = 1; + //console.log('No on condition: ', onCondn); + break; + } - let onCondn = '_on' + (onCondnCount) - let onCondnObj = {} - if (onCondn in req.query) { - //console.log(onCondn, req.query[onCondn]); - onCondnObj = whereHelp.getConditionClause(req.query[onCondn], ' on ') - //console.log('onCondnObj', onCondnObj); - queryParamsObj.query += ' on ' + onCondnObj.query - queryParamsObj.params = queryParamsObj.params.concat(onCondnObj.params) - } else { - queryParamsObj.grammarErr = 1; - //console.log('No on condition: ', onCondn); - break; + if (i === 0) { + i = i + 1 + } } + /**************** END : get join + on ****************/ - //console.log('- - - - - - -'); - if (i === 0) { - i = i + 1 + if(queryParamsObj.grammarErr){ + break; + } else { + this.getWhereClause(req.query._where, ' ignore ', queryParamsObj, ' where '); + this._getGrpByHavingOrderBy(req, 'ignore', queryParamsObj, 5) + //console.log('after where',queryParamsObj); } - //console.log('index after loop', i); + + break; + } - /**************** END : get join + on ****************/ + if (queryParamsObj.grammarErr) { queryParamsObj.query = '' queryParamsObj.params = [] } - this.getWhereClause(req.query._where, ' ignore ', queryParamsObj, ' where '); - - //console.log('after where',queryParamsObj); - - this._getGrpByHavingOrderBy(req, 'ignore', queryParamsObj, 5) return queryParamsObj; } - - } diff --git a/tests/tests.js b/tests/tests.js index ad7c508659..a97259ac5c 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1599,7 +1599,7 @@ describe('xmysql : tests', function () { //post to an url with data agent.get(apiPrefix + 'xjoin?_join=pl.productlines,_j,pr.products&_on1=(pl.productline,eq,pr.productline)') //enter url - .expect(200)//200 for success 4xx for failure + .expect(400)//200 for success 4xx for failure .end(function (err, res) { // Handle /api/v error @@ -1607,8 +1607,6 @@ describe('xmysql : tests', function () { return done(err); } - //validate response - Object.keys(res.body[0]).length.should.be.equals(12) return done(); }); @@ -1636,6 +1634,24 @@ describe('xmysql : tests', function () { }); }); + it('GET ' + apiPrefix + 'xjoin?_join=pl.productlines,_j,pr.products&_on1=(pl.productline,eq,pr.productline)&_fields=pl_productline,pr.productName should PASS', function (done) { + + //post to an url with data + agent.get(apiPrefix + 'xjoin?_join=pl.productlines,_j,pr.products&_on1=(pl.productline,eq,pr.productline)&_fields=pl_productline,pr.productName') //enter url + .expect(400)//200 for success 4xx for failure + .end(function (err, res) { + + // Handle /api/v error + if (err) { + return done(err); + } + + return done(); + + }); + }); + + it('GET ' + apiPrefix + 'xjoin?_join=pl.productlines,_j,pr.products&_on1=(pl.productline,eq,pr.productline)&_fields=pl.productline,pr.productName&_size=2 should PASS', function (done) { //post to an url with data