Browse Source

first commit

pull/1/head
oof1lab 7 years ago
commit
67515e05df
  1. 11
      .eslintrc
  2. 77
      .gitignore
  3. 146
      README.md
  4. 39
      bin/index.js
  5. 39
      index.js
  6. 70
      lib/util/cmd.helper.js
  7. 63
      lib/util/data.helper.js
  8. 324
      lib/xapi.js
  9. 463
      lib/xsql.js
  10. 918
      package-lock.json
  11. 41
      package.json
  12. 4065
      tests/sample.sql
  13. 643
      tests/tests.js

11
.eslintrc

@ -0,0 +1,11 @@
{
"parserOptions": {
"ecmaVersion": 6
},
"rules": {
"eol-last": "error",
"indent": ["error", 2, { "SwitchCase": 1 }],
"no-trailing-spaces": "error",
"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }]
}
}

77
.gitignore vendored

@ -0,0 +1,77 @@
# OS
# ===========
.DS_Store
ehthumbs.db
Icon?
Thumbs.db
# Node and related ecosystem
# ==========================
.nodemonignore
.sass-cache/
node_modules/
help/
a
public/lib/
app/tests/coverage/
.bower-*/
.idea/
coverage/
# MEAN.js app and assets
# ======================
public/dist/
uploads
modules/users/client/img/profile/uploads
config/env/local.js
*.pem
# Ignoring MEAN.JS's gh-pages branch for documenation
_site/
# General
# =======
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.tmp
*.bak
*.swp
logs/
build/
uploads/
# Sublime editor
# ==============
.sublime-project
*.sublime-project
*.sublime-workspace
# Eclipse project files
# =====================
.project
.settings/
.*.md.html
.metadata
*~.nib
local.properties
# IntelliJ
# ========
*.iml
# Cloud9 IDE
# =========
.c9/
data/
mongod
# Visual Studio
# =========
*.suo
*.ntvs*
*.njsproj
*.sln

146
README.md

@ -0,0 +1,146 @@
# xmysql: one command to generate REST APIs for **any** MySql database
> Requires node >= 7.6.0
## Why this ?
Deriving REST APIs for a database which do not follow conventions of frameworks such as rails, django etc
is like a small adventure ..
<p align="center">
<img src="https://media.giphy.com/media/8gWrk3QZrjF1C/giphy.gif" alt="Rick & Morty"/>
</p>
Hence this.
Powered by node packages : (express, mysql) => { xmysql }
## FEATURES
* Generates API for **ANY** MySql database
* Serves APIs irrespective of naming conventions of primary keys, foreign keys, tables etc
* CRUD : Usual suspects
* Support for composite primary keys
* Pagination
* Sorting
* Fields
* Relations
* Run dynamic queries
## Sample usage
* npm install -g xmysql
* xmysql -h localhost -u mysqlUsername -p mysqlPassword -d databaseName
* [http://localhost:3000](#http://localhost:3000)
Run HTTP client [Postman](https://www.getpostman.com/) or [similar tools](https://chrome.google.com/webstore/search/http%20client?_category=apps) to invoke REST API calls
## CRUD APIs Usual Suspects
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName
* POST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/:id
* PUT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/:id
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/count
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/exists
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:parentTable/:id/:childTable
* DELETE&nbsp; /api/:tableName/:id
* POST&nbsp;&nbsp;&nbsp;&nbsp; /dynamic
## Other APIS
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/:tableName/describe
* GET&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /api/tables
## Support for composite primary keys
#### ___ (three underscores)
```
/api/payments/103___JM555205
```
*___* : If there are multiple primary keys - seperate them by three underscores as shown
## Pagination
#### _p & _size
_p indicates page and _size indicates size of response rows
By default 20 records and max of 100 are returned per GET request on a table.
```
/api/payments?_size=50
```
```
/api/payments?_p=2
```
```
/api/payments?_p=2&_size=50
```
## Sorting
#### _sort
```
/api/payments?_sort=column1
```
eg: sorts ascending by column1
```
/api/payments?_sort=-column1
```
eg: sorts descending by column1
```
/api/payments?_sort=column1,-column2
```
eg: sorts ascending by column1 and descending by column2
## Fields
```
/api/payments?_fields=customerNumber,checkNumber
```
eg: gets only customerNumber and checkNumber in response of each record
```
/api/payments?_fields=-checkNumber
```
eg: gets all fields in table row but not checkNumber
## Run dynamic queries
Dynamic queries on a database can be run by POST method to URL localhost:3000/dynamic
This is enabled only in local i.e -h localhost or -h 127.0.0.1 option.
Post body takes two fields : query and params.
>query: SQL query or SQL prepared query (ones with ?? and ?)
>params : parameters for SQL prepared query
```
POST /dynamic
{
"query": "select * from ?? limit 1,20",
"params": ["customers"]
}
```
## Relational Tables
xmysql identifies foreign key relations automatically and provides GET api.
```
/api/customers/103/payments
```
eg: Customers is parent table and payments is child table. API invocation will result in all payments with customer 103.
## When to use ?
* You need REST APIs without much hassle for (ANY) MySql database
* You are learning new frontend frameworks and need REST APIs for your MySql database.
* You are working on a demo, hacks etc
## When NOT to use ?
* Other times not mentioned in when to use section

39
bin/index.js

@ -0,0 +1,39 @@
#! /usr/bin/env node
const morgan = require('morgan');
const bodyParser = require('body-parser');
const express = require('express');
const sqlConfig = require('commander');
const mysql = require('mysql');
const Xapi = require('../lib/xapi.js');
const cmdargs = require('../lib/util/cmd.helper.js');
cmdargs.handle(sqlConfig)
/**************** START : setup express ****************/
let app = express();
app.use(morgan('tiny'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
/**************** END : setup express ****************/
/**************** START : setup mysql ****************/
let mysqlPool = mysql.createPool(sqlConfig);
/**************** END : setup mysql ****************/
/**************** START : setup Xapi ****************/
let moreApis = new Xapi(sqlConfig,mysqlPool,app);
moreApis.init((err, results) => {
app.listen(sqlConfig.portNumber)
})
/**************** END : setup Xapi ****************/

39
index.js

@ -0,0 +1,39 @@
#! /usr/bin/env node
const morgan = require('morgan');
const bodyParser = require('body-parser');
const express = require('express');
const sqlConfig = require('commander');
const mysql = require('mysql');
const Xapi = require('./lib/xapi.js');
const cmdargs = require('./lib/util/cmd.helper.js');
cmdargs.handle(sqlConfig)
/**************** START : setup express ****************/
let app = express();
app.use(morgan('tiny'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
/**************** END : setup express ****************/
/**************** START : setup mysql ****************/
let mysqlPool = mysql.createPool(sqlConfig);
/**************** END : setup mysql ****************/
/**************** START : setup Xapi ****************/
let moreApis = new Xapi(sqlConfig,mysqlPool,app);
moreApis.init((err, results) => {
app.listen(sqlConfig.portNumber)
})
/**************** END : setup Xapi ****************/

70
lib/util/cmd.helper.js

@ -0,0 +1,70 @@
'use strict';
const program = require('commander');
const colors = require('colors');
program.on('--help', () => {
console.log('')
console.log(' Examples:'.blue)
console.log('')
console.log(' $ xmysql -u username -p password -d databaseSchema'.blue)
console.log('')
})
program
.version('0.0.2')
.option('-h, --host <n>', 'hostname')
.option('-d, --database <n>', 'database schema name')
.option('-u, --user <n>', 'username of database / root by default')
.option('-p, --password <n>', 'password of database / empty by default')
.option('-n, --portNumber <n>', 'port number : 3000 by default')
.parse(process.argv)
function paintHelp(txt) {
return colors.magenta(txt) //display the help text in a color
}
function processInvalidArguments(program) {
let err = '';
if (!program.password) {
err += 'Error: password for database is missing\n';
}
if (!program.database) {
err += 'Error: database name is missing\n';
}
if (err !== '') {
program.outputHelp(paintHelp)
console.log(err.red)
}
}
exports.handle = program => {
/**************** START : default values ****************/
program.portNumber = program.portNumber || 3000;
program.user = program.user || 'root';
program.password = program.password || '';
program.host = program.host || 'localhost';
program.connectionLimit = 10;
if (program.host === 'localhost' || program.host === '127.0.0.1') {
program.dynamic = 1
}
//console.log(program.rawArgs);
/**************** END : default values ****************/
if (program.database && program.host && program.user) {
console.log('Starting server at:', 'http://'+program.host + ':' + program.portNumber)
} else {
processInvalidArguments(program)
process.exit(1)
}
};

63
lib/util/data.helper.js

@ -0,0 +1,63 @@
'use strict';
exports.findOrInsertObjectArrayByKey = (obj, key, array) => {
let found = 0;
let i = 0;
for (i = 0; i < array.length; ++i) {
if (key in array[i]) {
if (obj[key] === array[i][key]) {
found = 1;
break;
}
}
}
if (!found) {
array.push(obj)
}
return array[i];
};
exports.findObjectInArrayByKey = (key, value, objArray) => {
for (let i = 0; i < objArray.length; ++i) {
if (objArray[i][key] === value) {
return objArray[i];
}
}
return null;
};
exports.getSchemaQuery = function () {
return 'select c.table_name, c.column_name, c.ordinal_position,c.column_key,c.is_nullable, c.data_type, c.column_type,c.extra,c.privileges, ' +
'c.column_comment,c.column_default,c.data_type,c.character_maximum_length, ' +
'c.character_octet_length,c.numeric_precision,c.numeric_scale,c.datetime_precision,c.character_set_name, ' +
'c.collation_name, ' +
'k.constraint_name, k.referenced_table_name, k.referenced_column_name, ' +
's.index_name,s.seq_in_index ' +
'from ' +
'information_schema.columns as c ' +
'left join ' +
'information_schema.key_column_usage as k ' +
'on ' +
'c.column_name=k.column_name and ' +
'c.table_schema = k.referenced_table_schema and ' +
'c.table_name = k.table_name ' +
'left join ' +
'information_schema.statistics as s ' +
'on ' +
'c.column_name = s.column_name and ' +
'c.table_schema = s.index_schema and ' +
'c.table_name = s.table_name ' +
'where ' +
'c.table_schema=? ' +
'order by ' +
'c.table_name, c.ordinal_position';
};

324
lib/xapi.js

@ -0,0 +1,324 @@
'use strict';
var Xsql = require('./xsql.js');
//define class
class Xapi {
constructor(args, mysqlPool, app) {
this.sqlConfig = args;
this.mysql = new Xsql(args, mysqlPool)
this.app = app;
}
init(cbk) {
this.mysql.init((err, results) => {
this.setupRoutes()
this.app.use(this.errorMiddleware)
cbk(err, results)
})
}
errorMiddleware(err, req, res, next) {
if(err && err.code)
res.status(400).json({error: err});
else
res.status(500).json({error: 'Internal server error : ' + err.message});
next(err);
}
asyncMiddleware(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next))
.catch((err) => {
next(err);
});
}
}
root(req, res) {
//res.sendFile(path + "index.html")
let v = [];
v = this.mysql.getSchemaRoutes(req.protocol + '://' + req.get('host') + '/api/');
v = v.concat(this.mysql.globalRoutesPrint(req.protocol + '://' + req.get('host') + '/api/'))
res.json(v)
}
setupRoutes() {
this.app.get('/', this.asyncMiddleware(this.root.bind(this)))
/**************** START : tables apis ****************/
this.app.route('/api/tables')
.get(this.asyncMiddleware(this.tables.bind(this)));
this.app.route('/api/:tableName/describe')
.get(this.asyncMiddleware(this.tableDescribe.bind(this)));
/**************** END : tables apis ****************/
/**************** START : basic apis ****************/
this.app.route('/api/:tableName/count')
.get(this.asyncMiddleware(this.count.bind(this)));
this.app.route('/api/:tableName')
.get(this.asyncMiddleware(this.list.bind(this)))
.post(this.asyncMiddleware(this.create.bind(this)));
this.app.route('/api/:tableName/:id')
.get(this.asyncMiddleware(this.read.bind(this)))
.put(this.asyncMiddleware(this.update.bind(this)))
.delete(this.asyncMiddleware(this.delete.bind(this)));
this.app.route('/api/:tableName/:id/exists')
.get(this.asyncMiddleware(this.exists.bind(this)));
this.app.route('/api/:parentTable/:id/:childTable')
.get(this.asyncMiddleware(this.nestedList.bind(this)));
/**************** END : basic apis ****************/
if (this.sqlConfig.dynamic === 1) {
this.app.route('/dynamic*')
.post(this.asyncMiddleware(this.runQuery.bind(this)));
}
}
async create(req, res) {
let query = 'INSERT INTO ?? SET ?';
let params = [];
params.push(req.params.tableName);
params.push(req.body);
var results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async list(req, res) {
let cols = this.mysql.getColumnsForSelectStmt(req.params.tableName, req.query);
let query = 'select ' + cols + ' from ?? ';
let params = [];
params.push(req.params.tableName);
query = query + this.mysql.getOrderByClause(req.query, req.params.tableName);
query = query + ' limit ?,? '
params = params.concat(this.mysql.getLimitClause(req.query));
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async nestedList(req, res) {
let cols = this.mysql.getColumnsForSelectStmt(req.params.childTable, req.query);
let query = 'select ' + cols + ' from ?? where ';
let params = [];
params.push(req.params.childTable);
let whereClause = this.mysql.getForeignKeyWhereClause(req.params.parentTable,
req.params.id,
req.params.childTable);
if (!whereClause) {
return res.status(400).send({
error: "Table is made of composite primary keys - all keys were not in input"
})
}
query += whereClause;
query = query + this.mysql.getOrderByClause(req.query, req.params.parentTable);
query = query + ' limit ?,? '
params = params.concat(this.mysql.getLimitClause(req.query));
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async read(req, res) {
let query = 'select * from ?? where ';
let params = [];
params.push(req.params.tableName);
let clause = this.mysql.getPrimaryKeyWhereClause(req.params.tableName,
req.params.id.split('___'));
if (!clause) {
return res.status(400).send({
error: "Table is made of composite primary keys - all keys were not in input"
});
}
query += clause;
query += ' LIMIT 1'
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async exists(req, res) {
let query = 'select * from ?? where ';
let params = [];
params.push(req.params.tableName);
let clause = this.mysql.getPrimaryKeyWhereClause(req.params.tableName,
req.params.id.split('___'));
if (!clause) {
return res.status(400).send({
error: "Table is made of composite primary keys - all keys were not in input"
})
}
query += clause;
query += ' LIMIT 1'
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async update(req, res) {
let query = 'UPDATE ?? SET ';
let keys = Object.keys(req.body);
// SET clause
let updateKeys = '';
for (let i = 0; i < keys.length; ++i) {
updateKeys += keys[i] + ' = ? '
if (i !== keys.length - 1)
updateKeys += ', '
}
// where clause
query += updateKeys + ' where '
let clause = this.mysql.getPrimaryKeyWhereClause(req.params.tableName,
req.params.id.split('___'));
if (!clause) {
return res.status(400).send({
error: "Table is made of composite primary keys - all keys were not in input"
})
}
query += clause;
// params
let params = [];
params.push(req.params.tableName);
params = params.concat(Object.values(req.body));
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async delete(req, res) {
let query = 'DELETE FROM ?? WHERE ';
let params = [];
params.push(req.params.tableName);
let clause = this.mysql.getPrimaryKeyWhereClause(req.params.tableName,
req.params.id.split('___'));
if (!clause) {
return res.status(400).send({
error: "Table is made of composite primary keys - all keys were not in input"
});
}
query += clause;
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async count(req, res) {
let query = 'select count(1) as no_of_rows from ??';
let params = [];
params.push(req.params.tableName);
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async tables(req, res) {
let query = 'show tables';
let params = [];
let results = await this.mysql.exec(query, params)
res.status(200).json(results)
}
async runQuery(req, res) {
let query = req.body.query;
let params = req.body.params;
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
async tableDescribe(req, res) {
let query = 'describe ??';
let params = [req.params.tableName];
let results = await this.mysql.exec(query, params);
res.status(200).json(results);
}
}
//expose class
module.exports = Xapi;

463
lib/xsql.js

@ -0,0 +1,463 @@
'use strict';
const mysql = require('mysql');
const dataHelp = require('./util/data.helper.js');
const assert = require('assert')
//define class
class Xsql {
constructor(sqlConfig, pool) {
//define this variables
this.sqlConfig = {}
this.pool = {}
this.metaDb = {};
this.metaDb.tables = {};
this.sqlConfig = sqlConfig;
this.pool = pool;
}
init(cbk) {
this.dbCacheInitAsync((err, results) => {
cbk(err, results)
})
}
dbCacheInitAsync(cbk) {
let self = this;
self.pool.query(dataHelp.getSchemaQuery(), [this.sqlConfig.database], (err, results) => {
if (err) {
console.log('Cache init failed during database reading')
console.log(err, results)
cbk(err, results)
} else {
self.iterateToCacheTables(results)
self.iterateToCacheTablePks(results)
self.iterateToCacheTableColumns(results)
self.iterateToCacheTableFks(results)
// osx mysql server has limitations related to open_tables
self.pool.query('FLUSH TABLES', [], (err, results) => {
cbk(null, null)
})
}
})
}
iterateToCacheTables(schemaResults) {
for (let i = 0; i < schemaResults.length; ++i) {
let schemaRow = schemaResults[i];
let tableName = schemaRow['table_name'];
if (!(tableName in this.metaDb.tables)) {
this.metaDb.tables[tableName] = {}
this.metaDb.tables[tableName]['primaryKeys'] = []
this.metaDb.tables[tableName]['foreignKeys'] = []
this.metaDb.tables[tableName]['columns'] = []
this.metaDb.tables[tableName]['indicies'] = []
}
}
}
iterateToCacheTableColumns(schemaResults) {
for (let i = 0; i < schemaResults.length; ++i) {
let schemaRow = schemaResults[i];
let tableName = schemaRow['table_name'];
let col = {};
col['column_name'] = schemaRow['column_name']
col['ordinal_position'] = schemaRow['ordinal_position']
col['column_key'] = schemaRow['column_key']
col['data_type'] = schemaRow['data_type']
col['column_type'] = schemaRow['column_type']
dataHelp.findOrInsertObjectArrayByKey(col, 'column_name', this.metaDb.tables[tableName]['columns'])
}
}
iterateToCacheTablePks(schemaResults) {
for (let i = 0; i < schemaResults.length; ++i) {
let schemaRow = schemaResults[i];
let tableName = schemaRow['table_name'];
if (schemaRow['column_key'] === 'PRI') {
let pk = {};
pk['column_name'] = schemaRow['column_name']
pk['ordinal_position'] = schemaRow['ordinal_position']
pk['column_key'] = schemaRow['column_key']
pk['data_type'] = schemaRow['data_type']
pk['column_type'] = schemaRow['column_type']
dataHelp.findOrInsertObjectArrayByKey(pk, 'column_name', this.metaDb.tables[tableName]['primaryKeys'])
}
}
}
iterateToCacheTableFks(schemaResults) {
for (let i = 0; i < schemaResults.length; ++i) {
let schemaRow = schemaResults[i];
let tableName = schemaRow['table_name'];
if (schemaRow['referenced_table_name']) {
let fk = {};
fk['column_name'] = schemaRow['column_name']
fk['table_name'] = schemaRow['table_name']
fk['referenced_table_name'] = schemaRow['referenced_table_name']
fk['referenced_column_name'] = schemaRow['referenced_column_name']
fk['data_type'] = schemaRow['data_type']
fk['column_type'] = schemaRow['column_type']
dataHelp.findOrInsertObjectArrayByKey(fk, 'column_name', this.metaDb.tables[tableName]['foreignKeys'])
//console.log(fk['referenced_table_name'],fk['referenced_column_name'],tableName, schemaRow['column_name'], this.metaDb.tables[tableName]['foreignKeys'].length)
}
}
}
exec(query, params) {
let _this = this;
return new Promise(function (resolve, reject) {
//console.log('mysql>', query, params);
_this.pool.query(query, params, function (error, rows, _fields) {
if (error) {
console.log('mysql> ', error);
return reject(error);
}
return resolve(rows);
});
});
}
getLimitClause(reqParams) {
//defaults
reqParams._index = 0;
reqParams._len = 20;
if ('_size' in reqParams && parseInt(reqParams._size) < 100) {
reqParams._len = parseInt(reqParams._size)
}
if ('_p' in reqParams && parseInt(reqParams._p) > 0) {
reqParams._index = (parseInt(reqParams._p)-1) * reqParams._len + 1;
}
//console.log(reqParams._index, reqParams._len);
return [reqParams._index, reqParams._len]
}
getOrderByClause(queryparams, tableName) {
//defaults
let orderBy = '';
if (queryparams._sort) {
orderBy += ' ORDER BY '
let orderByCols = queryparams._sort.split(',')
for (let i = 0; i < orderByCols.length; ++i) {
if (i) {
orderBy = orderBy + ', '
}
if (orderByCols[i][0] === '-') {
let len = orderByCols[i].length;
orderBy = orderBy + orderByCols[i].substring(1, len) + ' DESC'
} else {
orderBy = orderBy + orderByCols[i] + ' ASC'
}
}
}
return orderBy
}
getColumnsForSelectStmt(tableName, reqQueryParams) {
let table = this.metaDb.tables[tableName];
let cols = [];
let _fieldsInQuery = [];
let removeFieldsObj = {};
// populate _fields array from query params
if ('_fields' in reqQueryParams) {
_fieldsInQuery = reqQueryParams['_fields'].split(',')
} else {
return " * ";
}
// get column name in _fields and mark column name which start with '-'
for (let i = 0; i < _fieldsInQuery.length; ++i) {
if (_fieldsInQuery[i][0] == '-') {
removeFieldsObj[_fieldsInQuery[i].substring(1, _fieldsInQuery[i].length)] = 1;
} else {
cols.push(_fieldsInQuery[i])
}
}
if (!cols.length) {
// for each column in table - add only which are not in removeFieldsObj
for (let i = 0; i < table['columns'].length; ++i) {
if (!(table['columns'][i]['column_name'] in removeFieldsObj)) {
cols.push(table['columns'][i]['column_name'])
}
}
} else {
cols = this.removeUnknownColumns(cols, tableName)
}
return cols.join(',')
}
removeUnknownColumns(inputColumns, tableName) {
let cols = inputColumns;
let unknown_cols_in_input = []
let shadowCols = [];
let tableColumns = this.metaDb.tables[tableName]['columns']
// find unknown fields if any
for (var j = 0; j < cols.length; ++j) {
let found = 0;
for (var i = 0; i < tableColumns.length; ++i) {
if (tableColumns[i]['column_name'] === cols[j]) {
found = 1;
break;
}
}
if (!found) {
unknown_cols_in_input.push(j)
}
}
// if there are unknown fields - remove and ignore 'em
if (unknown_cols_in_input.length) {
for (var i = 0; i < cols.length; ++i) {
if (unknown_cols_in_input.indexOf(i) === -1) {
shadowCols.push(cols[i])
}
}
cols = [];
cols = shadowCols;
}
return cols;
}
getPrimaryKeyWhereClause(tableName, pksValues) {
let whereClause = '';
let whereCol = '';
let whereValue = '';
let pks = []
if (tableName in this.metaDb.tables) {
pks = this.metaDb.tables[tableName].primaryKeys;
} else {
return null
}
// number of primary keys in table and one sent should be same
if (pksValues.length !== pks.length) {
return null
}
// get a where clause out of the above columnNames and their values
for (let i = 0; i < pks.length; ++i) {
let type = getColumnType(pks[i]);
whereCol = pks[i]['column_name']
if (type === 'string') {
whereValue = mysql.escape(pksValues[i])
} else if (type === 'int') {
whereValue = parseInt(pksValues[i])
} else if (type === 'float') {
whereValue = parseFloat(pksValues[i])
} else if (type === 'date') {
whereValue = Date(pksValues[i])
} else {
console.error(pks[i])
assert(false, 'Unhandled type of primary key')
}
if (i) {
whereClause += ' and '
}
whereClause += whereCol + ' = ' + whereValue;
}
return whereClause;
}
getForeignKeyWhereClause(parentTable, parentId, childTable) {
let whereValue = '';
//get all foreign keys of child table
let fks = this.metaDb.tables[childTable].foreignKeys;
let fk = dataHelp.findObjectInArrayByKey('referenced_table_name', parentTable, fks);
let whereCol = fk['column_name']
let colType = getColumnType(fk);
if (colType === 'string') {
whereValue = mysql.escape(parentId)
} else if (colType === 'int') {
whereValue = mysql.escape(parseInt(parentId))
} else if (colType === 'float') {
whereValue = mysql.escape(parseFloat(parentId))
} else if (colType === 'date') {
whereValue = mysql.escape(Date(parentId))
} else {
console.error(pks[i])
assert(false, 'Unhandled column type in foreign key handling')
}
return whereCol + ' = ' + whereValue;
}
prepareRoute(httpType, apiPrefix, urlRoute) {
let route = {};
route['httpType'] = httpType;
route['routeUrl'] = apiPrefix + urlRoute;
return route;
}
getSchemaRoutes(apiPrefix) {
let schemaRoutes = [];
for (var tableName in this.metaDb.tables) {
let routes = []
let tableObj = {}
let table = this.metaDb.tables[tableName];
tableObj['resource'] = tableName;
routes.push(this.prepareRoute('get', apiPrefix, tableName))
routes.push(this.prepareRoute('post', apiPrefix, tableName))
routes.push(this.prepareRoute('get', apiPrefix, tableName + '/:id'))
routes.push(this.prepareRoute('put', apiPrefix, tableName + '/:id'))
routes.push(this.prepareRoute('delete', apiPrefix, tableName + '/:id'))
routes.push(this.prepareRoute('get', apiPrefix, tableName + '/:id/count'))
routes.push(this.prepareRoute('get', apiPrefix, tableName + '/:id/exists'))
for (var j = 0; j < table['foreignKeys'].length; ++j) {
let fk = table['foreignKeys'][j]
routes.push(this.prepareRoute('get', apiPrefix, fk['referenced_table_name'] + '/:id/' + fk['table_name']))
}
tableObj['routes'] = routes;
schemaRoutes.push(tableObj);
}
return schemaRoutes;
}
globalRoutesPrint(apiPrefix) {
let r = []
r.push(apiPrefix + "tables")
r.push(apiPrefix + ":tableName/describe")
if (this.sqlConfig.dynamic)
r.push(apiPrefix + "dynamic")
return r;
}
}
//expose class
module.exports = Xsql;
function getDataType(colType, typesArr) {
// console.log(colType,typesArr);
for (let i = 0; i < typesArr.length; ++i) {
if (colType.indexOf(typesArr[i]) !== -1) {
return 1;
}
}
return 0;
}
function getColumnType(column) {
let strTypes = ['varchar', 'text', 'char', 'tinytext', 'mediumtext', 'longtext', 'blob', 'mediumblob', 'longblob', 'tinyblob', 'binary', 'varbinary'];
let intTypes = ['int', 'long', 'smallint', 'mediumint', 'bigint', 'tinyint'];
let flatTypes = ['float', 'double', 'decimal'];
let dateTypes = ['date', 'datetime', 'timestamp', 'time', 'year'];
//console.log(column);
if (getDataType(column['data_type'], strTypes)) {
return "string"
} else if (getDataType(column['data_type'], intTypes)) {
return "int"
} else if (getDataType(column['data_type'], flatTypes)) {
return "float"
} else if (getDataType(column['data_type'], dateTypes)) {
return "date"
} else {
return "string"
}
}

918
package-lock.json generated

@ -0,0 +1,918 @@
{
"name": "More-Apis",
"version": "0.0.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"accepts": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
"integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
"requires": {
"mime-types": "2.1.17",
"negotiator": "0.6.1"
}
},
"append-field": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz",
"integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo="
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"assert": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
"integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
"requires": {
"util": "0.10.3"
}
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"basic-auth": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz",
"integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=",
"requires": {
"safe-buffer": "5.1.1"
}
},
"bignumber.js": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz",
"integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg=="
},
"body-parser": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
"requires": {
"bytes": "3.0.0",
"content-type": "1.0.4",
"debug": "2.6.9",
"depd": "1.1.1",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"on-finished": "2.3.0",
"qs": "6.5.1",
"raw-body": "2.3.2",
"type-is": "1.6.15"
}
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"browser-stdout": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
"integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8="
},
"busboy": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
"integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
"requires": {
"dicer": "0.2.5",
"readable-stream": "1.1.14"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "0.0.1",
"string_decoder": "0.10.31"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
}
}
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"colors": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
"integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM="
},
"combined-stream": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
"dev": true,
"requires": {
"delayed-stream": "1.0.0"
}
},
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
},
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
"requires": {
"inherits": "2.0.3",
"readable-stream": "2.3.3",
"typedarray": "0.0.6"
}
},
"content-disposition": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"cookiejar": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz",
"integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=",
"dev": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"depd": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"dicer": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
"integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
"requires": {
"readable-stream": "1.1.14",
"streamsearch": "0.1.2"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "0.0.1",
"string_decoder": "0.10.31"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
}
}
},
"diff": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
"integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww=="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.1.tgz",
"integrity": "sha512-STB7LZ4N0L+81FJHGla2oboUHTk4PaN1RsOkoRh9OSeEKylvF5hwKYVX1xCLFaCT7MD0BNG/gX2WFMLqY6EMBw==",
"requires": {
"accepts": "1.3.4",
"array-flatten": "1.1.1",
"body-parser": "1.18.2",
"content-disposition": "0.5.2",
"content-type": "1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "1.1.1",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"finalhandler": "1.1.0",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "1.1.2",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"path-to-regexp": "0.1.7",
"proxy-addr": "2.0.2",
"qs": "6.5.1",
"range-parser": "1.2.0",
"safe-buffer": "5.1.1",
"send": "0.16.1",
"serve-static": "1.13.1",
"setprototypeof": "1.1.0",
"statuses": "1.3.1",
"type-is": "1.6.15",
"utils-merge": "1.0.1",
"vary": "1.1.2"
}
},
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
"dev": true
},
"finalhandler": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
"integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
"requires": {
"debug": "2.6.9",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"statuses": "1.3.1",
"unpipe": "1.0.0"
}
},
"form-data": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
"integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
"dev": true,
"requires": {
"asynckit": "0.4.0",
"combined-stream": "1.0.5",
"mime-types": "2.1.17"
}
},
"formidable": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz",
"integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=",
"dev": true
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"growl": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
"integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q=="
},
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
},
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
},
"http-errors": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
"integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
"requires": {
"depd": "1.1.1",
"inherits": "2.0.3",
"setprototypeof": "1.0.3",
"statuses": "1.3.1"
},
"dependencies": {
"setprototypeof": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
"integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
}
}
},
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz",
"integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
},
"mime-db": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
},
"mime-types": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
"requires": {
"mime-db": "1.30.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.8"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"mocha": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.1.tgz",
"integrity": "sha512-evDmhkoA+cBNiQQQdSKZa2b9+W2mpLoj50367lhy+Klnx9OV8XlCIhigUnn1gaTFLQCa0kdNhEGDr0hCXOQFDw==",
"requires": {
"browser-stdout": "1.3.0",
"commander": "2.11.0",
"debug": "3.1.0",
"diff": "3.3.1",
"escape-string-regexp": "1.0.5",
"glob": "7.1.2",
"growl": "1.10.3",
"he": "1.1.1",
"mkdirp": "0.5.1",
"supports-color": "4.4.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"morgan": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
"integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=",
"requires": {
"basic-auth": "2.0.0",
"debug": "2.6.9",
"depd": "1.1.1",
"on-finished": "2.3.0",
"on-headers": "1.0.1"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"multer": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.3.0.tgz",
"integrity": "sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI=",
"requires": {
"append-field": "0.1.0",
"busboy": "0.2.14",
"concat-stream": "1.6.0",
"mkdirp": "0.5.1",
"object-assign": "3.0.0",
"on-finished": "2.3.0",
"type-is": "1.6.15",
"xtend": "4.0.1"
}
},
"mysql": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.15.0.tgz",
"integrity": "sha512-C7tjzWtbN5nzkLIV+E8Crnl9bFyc7d3XJcBAvHKEVkjrYjogz3llo22q6s/hw+UcsE4/844pDob9ac+3dVjQSA==",
"requires": {
"bignumber.js": "4.0.4",
"readable-stream": "2.3.3",
"safe-buffer": "5.1.1",
"sqlstring": "2.3.0"
}
},
"nan": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
"integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=",
"dev": true
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"object-assign": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
"integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"on-headers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
"integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1.0.2"
}
},
"parseurl": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"proxy-addr": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz",
"integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=",
"requires": {
"forwarded": "0.1.2",
"ipaddr.js": "1.5.2"
}
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
"raw-body": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
"integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
"requires": {
"bytes": "3.0.0",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"unpipe": "1.0.0"
}
},
"readable-stream": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "1.0.7",
"safe-buffer": "5.1.1",
"string_decoder": "1.0.3",
"util-deprecate": "1.0.2"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"send": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz",
"integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==",
"requires": {
"debug": "2.6.9",
"depd": "1.1.1",
"destroy": "1.0.4",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"fresh": "0.5.2",
"http-errors": "1.6.2",
"mime": "1.4.1",
"ms": "2.0.0",
"on-finished": "2.3.0",
"range-parser": "1.2.0",
"statuses": "1.3.1"
}
},
"serve-favicon": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.4.5.tgz",
"integrity": "sha512-s7F8h2NrslMkG50KxvlGdj+ApSwaLex0vexuJ9iFf3GLTIp1ph/l1qZvRe9T9TJEYZgmq72ZwJ2VYiAEtChknw==",
"requires": {
"etag": "1.8.1",
"fresh": "0.5.2",
"ms": "2.0.0",
"parseurl": "1.3.2",
"safe-buffer": "5.1.1"
}
},
"serve-static": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
"integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==",
"requires": {
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"parseurl": "1.3.2",
"send": "0.16.1"
}
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
},
"should": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/should/-/should-13.1.2.tgz",
"integrity": "sha512-oiGqKOuE4t98vdCs4ICifvzL2u9nWMaziSXVwHOYPyqqY1gBzGZS6LvzIc5uEFN0PiS69Sbvcqyw9hbYXkF4og==",
"dev": true,
"requires": {
"should-equal": "2.0.0",
"should-format": "3.0.3",
"should-type": "1.4.0",
"should-type-adaptors": "1.0.1",
"should-util": "1.0.0"
}
},
"should-equal": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz",
"integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==",
"dev": true,
"requires": {
"should-type": "1.4.0"
}
},
"should-format": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz",
"integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=",
"dev": true,
"requires": {
"should-type": "1.4.0",
"should-type-adaptors": "1.0.1"
}
},
"should-type": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz",
"integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=",
"dev": true
},
"should-type-adaptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz",
"integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=",
"dev": true,
"requires": {
"should-type": "1.4.0",
"should-util": "1.0.0"
}
},
"should-util": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz",
"integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=",
"dev": true
},
"sleep": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/sleep/-/sleep-5.1.1.tgz",
"integrity": "sha1-h4+h1E0I7rDyb7IBjvhinrGjq5Q=",
"dev": true,
"requires": {
"nan": "2.7.0"
}
},
"sqlstring": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz",
"integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg="
},
"statuses": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
"integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
},
"streamsearch": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "5.1.1"
}
},
"superagent": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-3.6.3.tgz",
"integrity": "sha512-GjsfCFijfjqoz2tRiStSOoTdy7gNZOcK3ar4zONP9D8dXQWE+Qg7cbePHimRpapo06WUvoU3dmgi2e4q+sab5A==",
"dev": true,
"requires": {
"component-emitter": "1.2.1",
"cookiejar": "2.1.1",
"debug": "3.1.0",
"extend": "3.0.1",
"form-data": "2.3.1",
"formidable": "1.1.1",
"methods": "1.1.2",
"mime": "1.4.1",
"qs": "6.5.1",
"readable-stream": "2.3.3"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
}
}
},
"supertest": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/supertest/-/supertest-3.0.0.tgz",
"integrity": "sha1-jUu2j9GDDuBwM7HFpamkAhyWUpY=",
"dev": true,
"requires": {
"methods": "1.1.2",
"superagent": "3.6.3"
}
},
"supports-color": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
"requires": {
"has-flag": "2.0.0"
}
},
"type-is": {
"version": "1.6.15",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
"integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
"requires": {
"media-typer": "0.3.0",
"mime-types": "2.1.17"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"util": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"requires": {
"inherits": "2.0.1"
},
"dependencies": {
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
}
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
}
}
}

41
package.json

@ -0,0 +1,41 @@
{
"name": "xmysql",
"version": "0.0.2",
"description": "One command to generate REST APIs for any MySql database",
"main": "index.js",
"scripts": {
"test": "./node_modules/.bin/mocha tests/*.js --exit"
},
"keywords": [
"mysql rest api generator",
"mysql rest api json",
"create rest api for sql database",
"node mysql rest api"
],
"engines": {
"node": ">= 7.6.0"
},
"bin": {
"xmysql": "bin/index.js"
},
"homepage": "https://github.com/o1lab/xmysql",
"author": "o1lab",
"license": "MIT",
"dependencies": {
"assert": "^1.4.1",
"body-parser": "^1.18.2",
"colors": "^1.1.2",
"commander": "^2.11.0",
"express": "^4.16.1",
"mocha": "^4.0.1",
"morgan": "^1.9.0",
"multer": "^1.3.0",
"mysql": "^2.15.0",
"serve-favicon": "^2.4.5"
},
"devDependencies": {
"should": "^13.1.2",
"sleep": "^5.1.1",
"supertest": "^3.0.0"
}
}

4065
tests/sample.sql

File diff suppressed because it is too large Load Diff

643
tests/tests.js

@ -0,0 +1,643 @@
'use strict';
var bodyParser = require('body-parser')
var express = require('express')
var mysql = require('mysql')
var Xapi = require('../lib/xapi.js')
var should = require('should');
var request = require('supertest')
var args = {}
var app = {}
var agent = {}
var api = {}
var mysqlPool = {}
args['host'] = 'localhost'
args['user'] = 'root'
args['password'] = ''
args['database'] = 'classicmodels'
//desribe group of tests done
describe('xmysql : tests', function () {
before(function (done) {
mysqlPool = mysql.createPool(args)
app = express()
//app.use(morgan('tiny'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
agent = request.agent(app);
api = new Xapi(args, mysqlPool, app)
api.init(function (err, results) {
if (err) {
process.exit(1)
}
app.listen(3000)
done();
})
});
after(function (done) {
mysqlPool.end(function (err) {
done();
})
});
beforeEach(function (done) {
//init common variables for each test
done();
});
afterEach(function (done) {
//term common variables for each test
done();
});
it('GET /api/tables should PASS', function (done) {
//http get an url
agent.get('/api/tables') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/tables error
if (err) {
return done(err);
}
//validate response
res.body.length.should.be.equal(8);
return done();
});
});
it('GET /api/payments/count should PASS', function (done) {
//http get an url
agent.get('/api/payments/count') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/tables error
if (err) {
return done(err);
}
//validate response
res.body[0]['no_of_rows'].should.be.equal(273);
return done();
});
});
it('GET /api/customers/describe should PASS', function (done) {
//http get an url
agent.get('/api/customers/describe') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/tables error
if (err) {
return done(err);
}
//validate response
res.body.length.should.be.equal(13);
return done();
});
});
it('GET /api/payments/103___JM555205 should PASS', function (done) {
//http get an url
agent.get('/api/payments/103___JM555205')// api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/tables error
if (err) {
return done(err);
}
//validate response - max value here is 14571.44
res.body.length.should.be.equal(1);
res.body[0]['amount'].should.be.greaterThan(14570);
return done();
});
});
it('GET /api/customers should PASS', function (done) {
//testcase
//http get an url
agent.get('/api/customers') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/customers error
if (err) {
return done(err);
}
res.body.should.be.instanceOf(Array)
res.body.length.should.be.greaterThan(0);
//validate response
return done();
});
});
it('GET /api/customers/103 should PASS', function (done) {
//http get an url
agent.get('/api/customers/103') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/customers/103 error
if (err) {
return done(err);
}
//validate response
res.body.should.be.instanceOf(Object)
res.body[0]['customerNumber'].should.be.equal(103)
return done();
});
});
it('GET /api/payments?_p=2 should PASS', function (done) {
//http get an url
agent.get('/api/payments?_p=2') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
res.body.length.should.be.equal(20)
return done();
});
});
it('GET /api/payments?_p=2&_size=10 should PASS', function (done) {
//http get an url
agent.get('/api/payments?_p=2&_size=10') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
res.body.length.should.be.equal(10)
return done();
});
});
it('GET /api/offices?_sort=city should PASS', function (done) {
//http get an url
agent.get('/api/offices?_sort=city') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
res.body[0]['city'].should.be.equal('Boston')
return done();
});
});
it('GET /api/offices?_fields=officeCode,city should PASS', function (done) {
//http get an url
agent.get('/api/offices?_fields=officeCode,city') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
Object.keys(res.body[0]).length.should.be.equal(2)
return done();
});
});
it('GET /api/offices?_fields=officeCode,ity should PASS', function (done) {
//http get an url
agent.get('/api/offices?_fields=officeCode,ity') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
// ity in _fields is an in valid column and it should be ignored
Object.keys(res.body[0]).length.should.be.equal(1)
return done();
});
});
it('GET /api/offices?_fields=-territory,-addressLine2,-state should PASS', function (done) {
//http get an url
agent.get('/api/offices?_fields=-territory,-addressLine2,-state') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
Object.keys(res.body[0]).length.should.be.equal(6)
return done();
});
});
it('GET /api/offices?_fields=-territory,-addressLine2,-state,-tate should PASS', function (done) {
//http get an url
agent.get('/api/offices?_fields=-territory,-addressLine2,-state') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
// tate is an invalid column but still it should query right number of columns
Object.keys(res.body[0]).length.should.be.equal(6)
return done();
});
});
it('GET /api/offices?_sort=-city should PASS', function (done) {
//http get an url
agent.get('/api/offices?_sort=-city') // api url
.expect(200) // 2xx for success and 4xx for failure
.end(function (err, res) {
// Handle /api/offices/1/employees error
if (err) {
return done(err);
}
//validate resonse
res.body.should.be.instanceOf(Array)
res.body[0]['city'].should.be.equal('Tokyo')
return done();
});
});
// it('GET /api/offices?_sort=-city,ity,-ity should PASS', function (done) {
//
// //http get an url
// agent.get('/api/offices?_sort=-city,ity,-ity') // api url
// .expect(200) // 2xx for success and 4xx for failure
// .end(function (err, res) {
// // Handle /api/offices/1/employees error
// if (err) {
// return done(err);
// }
//
// //validate resonse
// res.body.should.be.instanceOf(Array)
//
// // ity is an invalid sort element and should be ignored
// res.body[0]['city'].should.be.equal('Tokyo')
//
// return done();
// });
//
// });
it('POST /api/productlines should PASS', function (done) {
var obj = {};
obj['productLine'] = 'Hyperloop'
obj['textDescription'] = 'Hyperloop is essentially a train system that Musk calls \"a cross between ' +
'a Concorde, a railgun, and an air hockey table\". ' +
'It\'s based on the very high-speed transit (VHST) system proposed in 1972,' +
'which combines a magnetic levitation train and a low pressure transit tube.' +
'It evolves some of the original ideas of VHST, but it still uses tunnels' +
'and pods or capsules to move from place to place.'
//post to an url with data
agent.post('/api/productlines') //enter url
.send(obj) //postdata
.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['affectedRows'].should.be.equals(1)
return done();
});
});
it('PUT /api/customers/:id should PASS', function (done) {
var obj = {};
obj['textDescription'] = 'Hyperloop is essentially a train system that Elon Musk (https://twitter.com/elonmusk) calls \"a cross between ' +
'a Concorde, a railgun, and an air hockey table\". ' +
'It\'s based on the very high-speed transit (VHST) system proposed in 1972,' +
'which combines a magnetic levitation train and a low pressure transit tube.' +
'It evolves some of the original ideas of VHST, but it still uses tunnels' +
'and pods or capsules to move from place to place.'
//post to an url with data
agent.put('/api/productlines/Hyperloop') //enter url
.send(obj) //postdata
.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['affectedRows'].should.be.equals(1)
return done();
});
});
it('DELETE /api/customers/:id should PASS', function (done) {
var obj = {};
//post to an url with data
agent.del('/api/productlines/Hyperloop') //enter url
.send(obj) //postdata
.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['affectedRows'].should.be.equals(1)
return done();
});
});
it('GET /api/offices/1/employees should PASS', function (done) {
//post to an url with data
agent.get('/api/offices/1/employees') //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.above(1)
return done();
});
});
it('GET /api/employees/1002/employees should PASS', function (done) {
//post to an url with data
agent.get('/api/employees/1002/employees') //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.above(1)
return done();
});
});
it('GET /api/productlines/trains/products should PASS', function (done) {
//post to an url with data
agent.get('/api/productlines/trains/products') //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.above(1)
return done();
});
});
it('GET /api/productlines/trains/products should PASS', function (done) {
//post to an url with data
agent.get('/api/productlines/trains/products') //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.above(1)
return done();
});
});
it('GET /api/employees/1165/customers should PASS', function (done) {
//post to an url with data
agent.get('/api/employees/1165/customers') //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.above(1)
return done();
});
});
it('GET /api/customers/103/orders should PASS', function (done) {
//post to an url with data
agent.get('/api/customers/103/orders') //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.above(1)
return done();
});
});
it('GET /api/products/S10_1678/orderdetails should PASS', function (done) {
//post to an url with data
agent.get('/api/products/S10_1678/orderdetails') //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.above(1)
return done();
});
});
it('GET /api/customers/103/payments should PASS', function (done) {
//post to an url with data
agent.get('/api/customers/103/payments') //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.above(1)
return done();
});
});
});
Loading…
Cancel
Save