mirror of https://github.com/nocodb/nocodb
oof1lab
7 years ago
commit
67515e05df
13 changed files with 6899 additions and 0 deletions
@ -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 }] |
||||
} |
||||
} |
@ -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 |
@ -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 /api/:tableName |
||||
* POST /api/:tableName |
||||
* GET /api/:tableName/:id |
||||
* PUT /api/:tableName/:id |
||||
* GET /api/:tableName/count |
||||
* GET /api/:tableName/exists |
||||
* GET /api/:parentTable/:id/:childTable |
||||
* DELETE /api/:tableName/:id |
||||
* POST /dynamic |
||||
|
||||
## Other APIS |
||||
* GET /api/:tableName/describe |
||||
* GET /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 |
||||
|
||||
|
||||
|
||||
|
@ -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 ****************/ |
@ -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 ****************/ |
@ -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) |
||||
} |
||||
|
||||
}; |
@ -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'; |
||||
}; |
@ -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; |
||||
|
@ -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" |
||||
} |
||||
|
||||
} |
||||
|
@ -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=" |
||||
} |
||||
} |
||||
} |
@ -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" |
||||
} |
||||
} |
@ -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…
Reference in new issue