mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-01 05:26:53 +00:00
Feature : xjoin API 🔥 🔥
npm v0.4.0
This commit is contained in:
233
lib/xapi.js
233
lib/xapi.js
@@ -1,10 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var Xsql = require('./xsql.js');
|
||||
var whrHelp = require('./util/whereClause.helper.js');
|
||||
var multer = require('multer');
|
||||
var path = require('path');
|
||||
const colors = require('colors');
|
||||
|
||||
|
||||
//define class
|
||||
class Xapi {
|
||||
|
||||
@@ -110,6 +112,11 @@ class Xapi {
|
||||
this.app.route('/api/tables')
|
||||
.get(this.asyncMiddleware(this.tables.bind(this)));
|
||||
|
||||
this.app.route('/api/xjoin')
|
||||
.get(this.asyncMiddleware(this.xjoin.bind(this)));
|
||||
|
||||
stat.api += 3;
|
||||
|
||||
|
||||
/**************** START : setup routes for each table ****************/
|
||||
let resources = [];
|
||||
@@ -276,12 +283,34 @@ class Xapi {
|
||||
}
|
||||
|
||||
|
||||
_getGrpByHavingOrderBy(req, tableName, queryParamsObj, listType) {
|
||||
|
||||
/**************** add group by ****************/
|
||||
this.mysql.getGroupByClause(req.query._groupby, req.app.locals._tableName, queryParamsObj);
|
||||
|
||||
/**************** add having ****************/
|
||||
this.mysql.getHavingClause(req.query._having, req.app.locals._tableName, queryParamsObj);
|
||||
|
||||
/**************** add order clause ****************/
|
||||
this.mysql.getOrderByClause(req.query, req.app.locals._tableName, queryParamsObj);
|
||||
|
||||
/**************** add limit clause ****************/
|
||||
if (listType === 2) { //nested
|
||||
queryParamsObj.query += ' limit 1 '
|
||||
} else {
|
||||
queryParamsObj.query += ' limit ?,? '
|
||||
queryParamsObj.params = queryParamsObj.params.concat(this.mysql.getLimitClause(req.query));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param req
|
||||
* @param res
|
||||
* @param queryParamsObj : {query, params}
|
||||
* @param listType : 0:list, 1:nested, 2:findOne, 3:bulkRead, 4:distinct
|
||||
* @param listType : 0:list, 1:nested, 2:findOne, 3:bulkRead, 4:distinct, 5:xjoin
|
||||
*
|
||||
* Updates query, params for query of type listType
|
||||
*/
|
||||
@@ -304,7 +333,7 @@ class Xapi {
|
||||
/**************** add tableName ****************/
|
||||
queryParamsObj.query += ' from ?? ';
|
||||
|
||||
if (listType === 1) {
|
||||
if (listType === 1) { //nested list
|
||||
|
||||
req.app.locals._tableName = req.app.locals._childTable;
|
||||
|
||||
@@ -357,27 +386,165 @@ class Xapi {
|
||||
|
||||
}
|
||||
|
||||
/**************** add group by ****************/
|
||||
this.mysql.getGroupByClause(req.query._groupby, req.app.locals._tableName, queryParamsObj);
|
||||
this._getGrpByHavingOrderBy(req, req.app.locals._tableName, queryParamsObj)
|
||||
|
||||
/**************** add having ****************/
|
||||
this.mysql.getHavingClause(req.query._having, req.app.locals._tableName, queryParamsObj);
|
||||
|
||||
/**************** add order clause ****************/
|
||||
this.mysql.getOrderByClause(req.query, req.app.locals._tableName, queryParamsObj);
|
||||
|
||||
/**************** add limit clause ****************/
|
||||
if (listType === 2) {
|
||||
queryParamsObj.query += ' limit 1 '
|
||||
} else {
|
||||
queryParamsObj.query += ' limit ?,? '
|
||||
queryParamsObj.params = queryParamsObj.params.concat(this.mysql.getLimitClause(req.query));
|
||||
}
|
||||
|
||||
//console.log(queryParamsObj.query, queryParamsObj.params);
|
||||
}
|
||||
|
||||
|
||||
_joinTableNames(isSecondJoin, joinTables, index, queryParamsObj) {
|
||||
|
||||
if (isSecondJoin) {
|
||||
|
||||
/**
|
||||
* in second join - there will be ONE table and an ON condition
|
||||
* this if clause deals with this
|
||||
*
|
||||
*/
|
||||
|
||||
// add : join / left join / right join / full join / inner join
|
||||
queryParamsObj.query += this.mysql.getJoinType(joinTables[index])
|
||||
queryParamsObj.query += ' ?? as ?? '
|
||||
|
||||
// eg: tbl.tableName
|
||||
let tableNameAndAs = joinTables[index + 1].split('.')
|
||||
|
||||
if (tableNameAndAs.length === 2) {
|
||||
queryParamsObj.params.push(tableNameAndAs[1])
|
||||
queryParamsObj.params.push(tableNameAndAs[0])
|
||||
} else {
|
||||
queryParamsObj.grammarErr = 1
|
||||
console.log('there was no dot for tableName ', joinTables[index + 1]);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* in first join - there will be TWO tables and an ON condition
|
||||
* this else clause deals with this
|
||||
*/
|
||||
|
||||
|
||||
// first table
|
||||
queryParamsObj.query += ' ?? as ?? '
|
||||
// add : join / left join / right join / full join / inner join
|
||||
queryParamsObj.query += this.mysql.getJoinType(joinTables[index + 1])
|
||||
// second table
|
||||
queryParamsObj.query += ' ?? as ?? '
|
||||
|
||||
let tableNameAndAs = joinTables[index].split('.')
|
||||
if (tableNameAndAs.length === 2) {
|
||||
queryParamsObj.params.push(tableNameAndAs[1])
|
||||
queryParamsObj.params.push(tableNameAndAs[0])
|
||||
} else {
|
||||
queryParamsObj.grammarErr = 1
|
||||
console.log('there was no dot for tableName ', joinTables[index]);
|
||||
}
|
||||
|
||||
tableNameAndAs = []
|
||||
tableNameAndAs = joinTables[index + 2].split('.')
|
||||
if (tableNameAndAs.length === 2) {
|
||||
queryParamsObj.params.push(tableNameAndAs[1])
|
||||
queryParamsObj.params.push(tableNameAndAs[0])
|
||||
} else {
|
||||
queryParamsObj.grammarErr = 1
|
||||
console.log('there was no dot for tableName ', joinTables[index]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
prepareJoinQuery(req, res, queryParamsObj) {
|
||||
|
||||
queryParamsObj.query = 'SELECT '
|
||||
queryParamsObj.grammarErr = 0;
|
||||
|
||||
/**************** START : get fields ****************/
|
||||
if (req.query._fields) {
|
||||
|
||||
let fields = req.query._fields.split(',')
|
||||
|
||||
// from _fields to - ??, ??, ?? [col1,col2,col3]
|
||||
for (var i = 0; i < fields.length; ++i) {
|
||||
if (i) {
|
||||
queryParamsObj.query += ','
|
||||
}
|
||||
queryParamsObj.query += ' ?? '
|
||||
queryParamsObj.params.push(fields[i])
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
queryParamsObj.query += ' * '
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//console.log('jointables.length', joinTables);
|
||||
|
||||
let onCondnCount = 0;
|
||||
|
||||
for (let i = 0; i < joinTables.length - 1 && queryParamsObj.grammarErr === 0; i = i + 2) {
|
||||
|
||||
onCondnCount++;
|
||||
|
||||
this._joinTableNames(i, joinTables, i, queryParamsObj)
|
||||
|
||||
if (queryParamsObj.grammarErr) {
|
||||
console.log('failed at _joinTableNames', queryParamsObj);
|
||||
break;
|
||||
}
|
||||
|
||||
//console.log('after join tables', queryParamsObj);
|
||||
|
||||
let onCondn = '_on' + (onCondnCount)
|
||||
let onCondnObj = {}
|
||||
if (onCondn in req.query) {
|
||||
//console.log(onCondn, req.query[onCondn]);
|
||||
onCondnObj = whrHelp.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;
|
||||
}
|
||||
|
||||
//console.log('- - - - - - -');
|
||||
if (i === 0) {
|
||||
i = i + 1
|
||||
}
|
||||
//console.log('index after loop', i);
|
||||
}
|
||||
/**************** END : get join + on ****************/
|
||||
|
||||
if (queryParamsObj.grammarErr) {
|
||||
queryParamsObj.query = ''
|
||||
queryParamsObj.params = []
|
||||
}
|
||||
|
||||
this.mysql.getWhereClause(req.query._where, ' ignore ', queryParamsObj, ' where ');
|
||||
|
||||
//console.log('after where',queryParamsObj);
|
||||
|
||||
this._getGrpByHavingOrderBy(req, 'ignore', queryParamsObj, 5)
|
||||
|
||||
return queryParamsObj;
|
||||
}
|
||||
|
||||
|
||||
async list(req, res) {
|
||||
|
||||
let queryParamsObj = {}
|
||||
@@ -391,6 +558,25 @@ class Xapi {
|
||||
|
||||
}
|
||||
|
||||
|
||||
async xjoin(req, res) {
|
||||
|
||||
let obj = {}
|
||||
|
||||
obj.query = '';
|
||||
obj.params = [];
|
||||
|
||||
this.prepareJoinQuery(req, res, obj)
|
||||
|
||||
//console.log(obj);
|
||||
|
||||
let results = await this.mysql.exec(obj.query, obj.params)
|
||||
res.status(200).json(results)
|
||||
|
||||
//http://localhost:3000/api/xjoin?_join=pl.productlines,j,pr.products,j,ord.orderdetails&on1=(pl.productline,eq,pr.products)&on2=(pr.productcode,eq,ord.productcode)
|
||||
|
||||
}
|
||||
|
||||
async distinct(req, res) {
|
||||
|
||||
let queryParamsObj = {}
|
||||
@@ -628,19 +814,24 @@ class Xapi {
|
||||
let results = await this.mysql.exec(query, params);
|
||||
res.status(200).json(results);
|
||||
|
||||
|
||||
}
|
||||
|
||||
async tables(req, res) {
|
||||
|
||||
let query = 'show tables';
|
||||
let params = [];
|
||||
let query = 'SELECT table_name AS resource FROM information_schema.tables WHERE table_schema = ? ';
|
||||
let params = [this.config.database];
|
||||
|
||||
if (Object.keys(this.config.ignoreTables).length > 0) {
|
||||
query += 'and table_name not in (?)'
|
||||
params.push(Object.keys(this.config.ignoreTables))
|
||||
}
|
||||
|
||||
let results = await this.mysql.exec(query, params)
|
||||
res.status(200).json(results)
|
||||
|
||||
res.status(200).json(results)
|
||||
}
|
||||
|
||||
|
||||
async runQuery(req, res) {
|
||||
|
||||
let query = req.body.query;
|
||||
|
||||
Reference in New Issue
Block a user