From 3340e93509cc233c57f03d0fb6b50830a7f10780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=87=E5=A4=A9?= Date: Tue, 29 May 2018 02:42:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=903.0=E7=89=88=E7=9A=84?= =?UTF-8?q?=E8=BD=AC=E5=8F=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- History.md | 4 +- LICENSE | 21 +++ src/index.ts => index.js | 14 +- lib/api.js | 180 +++++++++++++++++++++++ src/lib/method.ts => lib/method.js | 227 ++++++++++++++++++++--------- src/lib/utils.ts => lib/utils.js | 145 ++++++++++++++---- package.json | 4 +- src/lib/api.ts | 123 ---------------- 8 files changed, 488 insertions(+), 230 deletions(-) create mode 100644 LICENSE rename src/index.ts => index.js (85%) create mode 100644 lib/api.js rename src/lib/method.ts => lib/method.js (51%) rename src/lib/utils.ts => lib/utils.js (50%) delete mode 100644 src/lib/api.ts diff --git a/History.md b/History.md index 4cd74fc..8488fca 100644 --- a/History.md +++ b/History.md @@ -1,12 +1,12 @@ 3.0.0 / 2018-04-16 ================== -> 这是一个全新的大版本, 不向下兼容2.x, 使用typescript重构。 +> 这是一个全新的大版本, 不向下兼容2.x。 * 重构API, 使用链式操作, 逻辑更加清晰 * 支持完整的pool option * 新增drop方法,支持删除数据库/数据表 * 新增tableCreate/dbCreate方法, 支持创建数据库/数据表 - * 新增indexCreate/indexRename/indexDrop/indexList, 支持对索引的增删改查 + * 新增indexCreate/indexDrop/indexList, 支持对索引的增删改查 2.2.2 / 2018-03-22 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ab60297 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/index.ts b/index.js similarity index 85% rename from src/index.ts rename to index.js index 20abe14..a6c1fbb 100644 --- a/src/index.ts +++ b/index.js @@ -5,17 +5,15 @@ * */ 'use strict' -import 'es.shim' +require('es.shim') const mysql = require('mysql') -import Api from './lib/api' +const Api = require('./lib/api') class Mysqli { - useSlaveDB: boolean - pool: any /** * [constructor 构造数据库连接池] */ - constructor(config: any) { + constructor(config) { if (!Array.isArray(config)) { config = [config] } @@ -27,7 +25,7 @@ class Mysqli { restoreNodeTimeout: 10000 }) - config.forEach((item: { [prop: string]: any }, i: number) => { + config.forEach((item, i) => { let { host, port, @@ -66,11 +64,11 @@ class Mysqli { } //对外的escape方法 - static escape(val: any) { + static escape(val) { return mysql.escape(val) } - emit(fromSlave = false, db: string = '') { + emit(fromSlave = false, db = '') { let slave = fromSlave && this.useSlaveDB ? 'SLAVE*' : 'MASTER' return new Api(this.pool, slave, db) } diff --git a/lib/api.js b/lib/api.js new file mode 100644 index 0000000..753e728 --- /dev/null +++ b/lib/api.js @@ -0,0 +1,180 @@ +/** + * + * @authors yutent (yutent@doui.cc) + * @date 2018-04-13 14:30:49 + * @version $Id$ + */ + +const { SqlErr, parser, fixtable } = require('./utils') +const Method = require('./method') + +class Api { + constructor(pool, slave = 'MASTER', db = '') { + this.pool = pool + this.slave = slave + this.db = db ? '`' + db + '`' : null + } + + connect() { + let defer = Promise.defer() + this.pool.getConnection(this.slave, (err, conn) => { + if (err) { + return defer.reject(new SqlErr(`MySQL connect ${err}`)) + } + if (this.db) { + conn.query('USE ' + this.db, err => { + if (err) { + return defer.reject(new SqlErr('Use DB ' + err)) + } + defer.resolve(conn) + }) + } else { + defer.resolve(conn) + } + }) + return defer.promise + } + + table(name) { + if (!name) { + throw new SqlErr('Query Error: empty table') + } + name = fixtable(name) + return new Method(this.pool, this.slave, this.db, name) + } + + /** + * [query sql语句执行] + * @param {[type]} sql [sql语句] + */ + query(sql) { + if (typeof sql !== 'string') { + return Promise.reject( + new SqlErr( + `Query error, argument sql must be string. ${typeof sql} given`, + sql + ) + ) + } + + return this.connect().then(conn => { + let defer = Promise.defer() + + conn.query(sql, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr(`Query ${err}`, sql)) + } + defer.resolve(result) + }) + return defer.promise + }) + } + + drop(db) { + if (!this.db && db) { + return Promise.reject('No database selected.') + } + this.db = db || this.db + let defer = Promise.defer() + + this.connect().then(conn => { + conn.query(`DROP DATABASE ${db || this.db}`, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr(`Drop database ${err}`)) + } + defer.resolve(true) + }) + }) + return defer.promise + } + + dbList() { + return this.connect().then(conn => { + let defer = Promise.defer() + + conn.query('SHOW DATABASES', (err, row) => { + conn.release() + if (err) { + return defer.reject(new SqlErr('Show databases ' + err)) + } + defer.resolve(row.map(it => it.Database)) + }) + + return defer.promise + }) + } + + //返回数据表 + tableList() { + return this.connect().then(conn => { + let defer = Promise.defer() + + conn.query('SHOW TABLES', (err, row) => { + conn.release() + if (err) { + return defer.reject(new SqlErr('Show tables ' + err)) + } + defer.resolve(row.map(it => it[Object.keys(it)[0]])) + }) + + return defer.promise + }) + } + + // 创建新的数据库 + dbCreate(name, { charset = 'utf8' }) { + if (!name) { + return Promise.reject('Empty database name.') + } + + let sql = `CREATE DATABASE \`${name}\` DEFAULT CHARACTER SET = \`${charset}\`` + return this.connect().then(conn => { + let defer = Promise.defer() + + conn.query(sql, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr('Create database ' + err)) + } + defer.resolve(true) + }) + + return defer.promise + }) + } + + // 创建新的表, + tableCreate(name, fields, { charset = 'utf8', engine = 'InnoDB' }) { + if (!name) { + return Promise.reject('Empty database name.') + } + + let sql = `CREATE TABLE \`${name}\` ` + + try { + sql += parser.field(fields) + } catch (err) { + return Promise.reject(err + '') + } + + sql += ` ENGINE=${engine} DEFAULT CHARSET=${charset}` + + return this.connect().then(conn => { + let defer = Promise.defer() + + conn.query(sql, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr('Create table ' + err, sql)) + } + defer.resolve(true) + }) + + return defer.promise + }) + } +} + +module.exports = Api diff --git a/src/lib/method.ts b/lib/method.js similarity index 51% rename from src/lib/method.ts rename to lib/method.js index aec3675..95379e4 100644 --- a/src/lib/method.ts +++ b/lib/method.js @@ -5,57 +5,47 @@ * @version $Id$ */ -import { defer, SqlErr, parser, escape } from './utils' +const { SqlErr, parser, escape, fixtable } = require('./utils') -console.log(escape(new Date())) -interface Conn { - query(sql: string, cb?: any): void - release(): void -} class Method { - pool: any - slave: string - db: string - cache: { [prop: string]: any } = {} - - constructor(pool: object, slave: string, db: string, table: string) { + constructor(pool, slave, db, table) { this.pool = pool this.slave = slave this.db = db this.cache = { table } } - private connect() { - let out = defer() - this.pool.getConnection(this.slave, (err: Error, conn: Conn) => { + connect() { + let defer = Promise.defer() + this.pool.getConnection(this.slave, (err, conn) => { if (err) { - return out.reject(new SqlErr(`MySQL connect ${err}`)) + return defer.reject(new SqlErr(`MySQL connect ${err}`)) } if (this.db) { - conn.query('USE ' + this.db, (err: Error) => { + conn.query('USE ' + this.db, err => { if (err) { - return out.reject(new SqlErr('Select DB ' + err)) + return defer.reject(new SqlErr('Use DB ' + err)) } - out.resolve(conn) + defer.resolve(conn) }) } else { - out.resolve(conn) + defer.resolve(conn) } }) - return out.promise + return defer.promise } - leftJoin(tables: any[]) { + leftJoin(tables) { this.cache.leftJoin = tables return this } - rightJoin(tables: any[]) { + rightJoin(tables) { this.cache.rightJoin = tables return this } - join(tables: any[]) { + join(tables) { this.cache.join = tables return this } @@ -71,7 +61,7 @@ class Method { * }) * obj形式的过滤, 支持多种多样, 详细请看Readme介绍 */ - filter(val: any) { + filter(val) { this.cache.filter = val return this } @@ -81,25 +71,25 @@ class Method { * @param {number }} keys [以对象形式传入值] * 如: {name: 1, age: -1} 1代表顺序, -1代表逆序 */ - sort(keys: { [prop: string]: number }) { + sort(keys) { this.cache.sort = keys return this } // 从第几条记录开始返回, 必须搭配limit使用,否则会被忽略 - skip(skip: number) { + skip(skip) { this.cache.skip = skip return this } // 返回指定数量的记录 - limit(size: number) { + limit(size) { this.cache.size = size return this } // 截取指定范围内的记录 - slice(start: number, end: number) { + slice(start, end) { this.cache.limit = [start, end - start] return this } @@ -108,7 +98,7 @@ class Method { * [withFields 选取指定的字段] * @param {string[]} fields [以数组形式传入] */ - withFields(fields: string[]) { + withFields(fields) { this.cache.fields = fields return this } @@ -121,9 +111,13 @@ class Method { * [getAll 获取所有记录] * @param {any[]} ids [description] */ - getAll(ids?: any[]) { + getAll(ids) { if (!this.cache.filter && ids) { - this.cache.filter = { id: { $in: ids } } + if (ids.length === 1) { + this.cache.filter = { id: ids[0] } + } else { + this.cache.filter = { id: { $in: ids } } + } } let { @@ -149,8 +143,7 @@ class Method { } } - let sql: string - sql = parser.select(fields) + let sql = parser.select(fields) sql += `FROM ${table} ` if (leftJoin) { sql += parser.leftJoin(leftJoin) @@ -174,17 +167,17 @@ class Method { sql += parser.limit(limit) } - return this.connect().then((conn: Conn) => { - let out = defer() + return this.connect().then(conn => { + let defer = Promise.defer() - conn.query(sql, (err: Error, result: any[]) => { + conn.query(sql, (err, result) => { conn.release() if (err) { - return out.reject(new SqlErr(`Find ${err}`, sql)) + return defer.reject(new SqlErr(`Find ${err}`, sql)) } - out.resolve(result) + defer.resolve(result) }) - return out.promise + return defer.promise }) } @@ -192,8 +185,8 @@ class Method { * [get 获取单条记录详细] * @param {any} id [取主键值为id的记录, 当且仅当没设置过滤条件时有效] */ - get(id?: any) { - return this.getAll(id ? [id] : null).then((list: any[]) => { + get(id) { + return this.getAll(id ? [id] : null).then(list => { return list[0] }) } @@ -202,8 +195,8 @@ class Method { * [count 获取记录总数] * @return {number} [description] */ - count(): number { - return this.getAll().then((list: any[]) => { + count() { + return this.getAll().then(list => { return list.length }) } @@ -212,7 +205,7 @@ class Method { * [insert 插入单条文档, 返回当前插入的文档的ID(如果是自增)] * @param {any }} doc [文档object] */ - insert(doc: { [prop: string]: any }) { + insert(doc) { if (!doc) { return Promise.reject(new SqlErr('Insert Error: empty document')) } @@ -227,19 +220,19 @@ class Method { } sql += `(${keys.join(',')}) VALUES (${vals.join(',')})` - return this.connect().then((conn: Conn) => { - const out = defer() + return this.connect().then(conn => { + const defer = Promise.defer() - conn.query(sql, (err: Error, result: any) => { + conn.query(sql, (err, result) => { conn.release() if (err) { - return out.reject(new SqlErr(`Insert ${err}`, sql)) + return defer.reject(new SqlErr(`Insert ${err}`, sql)) } - out.resolve(result.insertId) + defer.resolve(result.insertId) }) - return out.promise + return defer.promise }) } @@ -248,7 +241,7 @@ class Method { * 可以使用filter过滤条件 * @param {any }} doc [要更新的字段] */ - update(doc: { [prop: string]: any }) { + update(doc) { if (!doc) { return Promise.reject(new SqlErr('Update Error: empty document')) } @@ -267,19 +260,19 @@ class Method { sql += fields.join(',') sql += parser.filter(filter) - return this.connect().then((conn: Conn) => { - const out = defer() + return this.connect().then(conn => { + const defer = Promise.defer() - conn.query(sql, (err: Error, result: any) => { + conn.query(sql, (err, result) => { conn.release() if (err) { - return out.reject(new SqlErr(`Update ${err}`, sql)) + return defer.reject(new SqlErr(`Update ${err}`, sql)) } - out.resolve(result.affectedRows) + defer.resolve(result.affectedRows) }) - return out.promise + return defer.promise }) } @@ -292,21 +285,125 @@ class Method { let sql = `DELETE FROM ${table} ` sql += parser.filter(filter) - return this.connect().then((conn: Conn) => { - const out = defer() + return this.connect().then(conn => { + const defer = Promise.defer() - conn.query(sql, (err: Error, result: any) => { + conn.query(sql, (err, result) => { conn.release() if (err) { - return out.reject(new SqlErr(`Remove ${err}`, sql)) + return defer.reject(new SqlErr(`Remove ${err}`, sql)) } - out.resolve(result.affectedRows) + defer.resolve(result.affectedRows) }) - return out.promise + return defer.promise + }) + } + + // 重命名表 + renameTo(name) { + return this.connect().then(conn => { + const defer = Promise.defer() + + let sql = `RENAME TABLE ${this.cache.table} TO ${fixtable(name)}` + conn.query(sql, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr(`List index ${err}`, sql)) + } + + defer.resolve(true) + }) + + return defer.promise + }) + } + + // 返回索引列表 + indexList() { + return this.connect().then(conn => { + const defer = Promise.defer() + + let sql = `SHOW INDEX FROM ${this.cache.table}` + conn.query(sql, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr(`List index ${err}`, sql)) + } + let list = result.map(it => { + return { + name: it.Key_name, + column: it.Column_name, + unique: !it.Non_unique, + cardinality: it.Cardinality, + collation: it.Collation, + index: it.Seq_in_index + } + }) + + defer.resolve(list) + }) + + return defer.promise + }) + } + + // 删除指定索引 + indexDrop(name) { + if (!name) { + return Promise.reject('Empty index name') + } + return this.connect().then(conn => { + const defer = Promise.defer() + + let sql = `ALTER TABLE ${this.cache.table} DROP INDEX \`${name}\`` + conn.query(sql, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr(`Drop index ${err}`, sql)) + } + + defer.resolve(true) + }) + + return defer.promise + }) + } + + // 删除指定索引 + indexCreate(name, opt = {}) { + if (!name) { + return Promise.reject('Empty index name') + } + if (!opt.field) { + return Promise.reject('Empty field name') + } + let unique = '' + opt.field = '`' + opt.field + '`' + if (opt.unique) { + unique = 'UNIQUE' + } + + return this.connect().then(conn => { + const defer = Promise.defer() + + let sql = `ALTER TABLE ${ + this.cache.table + } ADD ${unique} INDEX \`${name}\` (${opt.field})` + + conn.query(sql, (err, result) => { + conn.release() + if (err) { + return defer.reject(new SqlErr(`Drop index ${err}`, sql)) + } + + defer.resolve(true) + }) + + return defer.promise }) } } -export default Method +module.exports = Method diff --git a/src/lib/utils.ts b/lib/utils.js similarity index 50% rename from src/lib/utils.ts rename to lib/utils.js index d250ce8..46d7793 100644 --- a/src/lib/utils.ts +++ b/lib/utils.js @@ -6,7 +6,16 @@ */ const { escape } = require('mysql') -function getType(val: any): string { +function hideProperty(host, name, value) { + Object.defineProperty(host, name, { + value: value, + writable: true, + enumerable: false, + configurable: true + }) +} + +function getType(val) { if (val === null) { return String(val) } @@ -15,7 +24,7 @@ function getType(val: any): string { .slice(8, -1) .toLowerCase() } -function parse$or(arr: any[]) { +function parse$or(arr) { let sql = '' for (let it of arr) { sql += '(' @@ -29,7 +38,7 @@ function parse$or(arr: any[]) { sql = sql.slice(0, -3) return sql } -function parse$and(arr: any[]) { +function parse$and(arr) { let sql = '' for (let it of arr) { sql += '(' @@ -44,7 +53,7 @@ function parse$and(arr: any[]) { return sql } -function parse$opt(opt: { [prop: string]: any }) { +function parse$opt(opt) { let sql = '' for (let k in opt) { let tmp = opt[k] @@ -60,7 +69,7 @@ function parse$opt(opt: { [prop: string]: any }) { } if (tmp.$in) { - let list = tmp.$in.map((it: any) => { + let list = tmp.$in.map(it => { return escape(it) }) sql += ` ${k} IN (${list.join(',')}) ` @@ -70,7 +79,7 @@ function parse$opt(opt: { [prop: string]: any }) { if (tmp.$between.length < 2) { throw new Error(`Array $between's length must be 2.`) } - let list = tmp.$between.map((it: any) => { + let list = tmp.$between.map(it => { return escape(it) }) sql += ` ${k} BETWEEN ${list[0]} AND ${list[1]} ` @@ -102,32 +111,45 @@ function parse$opt(opt: { [prop: string]: any }) { return sql } -export const parser = { - leftJoin(tables: any[]) { +// 格式化表名 +function fixtable(name) { + return name + .split('.') + .map(it => { + return '`' + it + '`' + }) + .join('.') +} + +const parser = { + leftJoin(tables = []) { let sql = '' for (let it of tables) { + it.table = fixtable(it.table) sql += ` LEFT JOIN ${it.table} ON ${it.on} ` } return sql }, - rightJoin(tables: any[]) { + rightJoin(tables = []) { let sql = '' for (let it of tables) { + it.table = fixtable(it.table) sql += ` RIGHT JOIN ${it.table} ON ${it.on} ` } return sql }, - join(tables: any[]) { + join(tables = []) { let sql = '' for (let it of tables) { + it.table = fixtable(it.table) sql += ` JOIN ${it[0]} ON ${it.on} ` } return sql }, - filter(opt: any) { + filter(opt) { if (typeof opt === 'string') { return ` WHERE ${opt} ` } @@ -146,12 +168,12 @@ export const parser = { return ' ' }, - select(arr: string[] = ['*']) { + select(arr = ['*']) { return `SELECT ${arr.join(',')} ` }, // 排序 ---------------------------------- - sort(obj: { [propName: string]: number } = {}) { + sort(obj = {}) { let sort = '' for (let i in obj) { let c = '' @@ -167,28 +189,91 @@ export const parser = { } }, - limit(...args: number[]) { + limit(...args) { return ` LIMIT ${args.join(',')} ` + }, + + // 解析数据表的配置(新建表时) + field(fields = []) { + let primary = null + let indexes = [] + let sql = `(\n` + for (let it of fields) { + it.type = it.type.toUpperCase() + let inc = '' // 自增 + let autoUpdate = '' // 自动更新时间戳(仅 DATETIME & TIMESTAMP) + let defaultVal = '' + // 只处理1个主键, 其他的忽略, 且作为主键,必须 NOT NULL + if (!primary && it.primary) { + primary = `PRIMARY KEY (\`${it.name}\`),\n` + it.notnull = true + if (it.inc) { + inc = 'AUTO_INCREMENT' + } + } + let notnull = it.notnull ? 'NOT NULL' : 'NULL' + + if (/CHAR/.test(it.type)) { + it.default = it.default ? escape(it.default) : '' + } + + // 这几种类型,不允许设置默认值 + if (['TEXT', 'BLOB', 'JSON', 'GEOMETRY'].includes(it.type)) { + notnull = 'NULL' + } + + // 这2种类型,如果设置了自动更新时间戳, 则默认值自动改为当前时间戳 + if (['TIMESTAMP', 'DATETIME'].includes(it.type)) { + if (it.update) { + autoUpdate = 'ON UPDATE CURRENT_TIMESTAMP' + it.default = 'CURRENT_TIMESTAMP' + } + } + + // 这3种时间类型,不允许设置默认值为 当前时间戳 + if (['TIME', 'DATE', 'YEAR'].includes(it.type)) { + if (it.default.toUpperCase() === 'CURRENT_TIMESTAMP') { + it.default = '' + } + } + defaultVal = it.default ? `DEFAULT ${it.default}` : '' + + // 非主键下, 设置了unique & index时,都为索引 + if (!it.primary) { + if (it.index || it.unique) { + let idx = `INDEX \`${it.name}_idx\` (\`${it.name}\`)` + if (it.unique) { + idx = 'UNIQUE ' + idx + } + indexes.push(idx) + } + } + sql += `\`${it.name}\` ${ + it.type + } ${notnull} ${defaultVal} ${inc} ${autoUpdate},\n` + } + if (!primary) { + throw new Error('Can not create table without primary key.') + } + sql += primary + sql += indexes.join(', \n') + ')' + return sql } } -export class SqlErr extends Error { - sql: string - constructor(msg: string = '', sql: string = '') { - super(msg) +class SqlErr { + constructor(msg = '', sql = '') { + this.message = msg this.sql = sql + hideProperty(this, 'stack', msg) + } + + toString() { + return this.message } } -export const defer = () => { - let obj: { [prop: string]: any } = {} - obj.promise = new Promise((yes, no) => { - obj.resolve = yes - obj.reject = no - }) - return obj -} - -export { escape } - -export default escape +exports.SqlErr = SqlErr +exports.parser = parser +exports.escape = escape +exports.fixtable = fixtable diff --git a/package.json b/package.json index 0e28ccd..ab064a8 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "mysqli", "version": "3.0.0", "description": "MySQL tool", - "main": "dist/index.js", + "main": "index.js", "dependencies": { - "es.shim": "^0.0.3", + "es.shim": "^1.0.1", "mysql": "^2.13.0" }, "repository": "https://github.com/yutent/mysqli.git", diff --git a/src/lib/api.ts b/src/lib/api.ts deleted file mode 100644 index 1cb2d27..0000000 --- a/src/lib/api.ts +++ /dev/null @@ -1,123 +0,0 @@ -/** - * - * @authors yutent (yutent@doui.cc) - * @date 2018-04-13 14:30:49 - * @version $Id$ - */ - -import { defer, SqlErr } from './utils' -import Method from './method' -interface Conn { - query(sql: string, cb?: any): void - release(): void -} -class Api { - pool: any - slave: string - db: string - constructor(pool: object, slave: string = 'MASTER', db: string = '') { - this.pool = pool - this.slave = slave - this.db = db - } - - connect() { - let out = defer() - this.pool.getConnection(this.slave, (err: Error, conn: Conn) => { - if (err) { - return out.reject(new SqlErr(`MySQL connect ${err}`)) - } - if (this.db) { - conn.query('USE ' + this.db, (err: Error) => { - if (err) { - return out.reject(new SqlErr('Select DB ' + err)) - } - out.resolve(conn) - }) - } else { - out.resolve(conn) - } - }) - return out.promise - } - - table(name: string) { - if (!name) { - throw new SqlErr('Query Error: empty table') - } - return new Method(this.pool, this.slave, this.db, name) - } - - /** - * [query sql语句执行] - * @param {[type]} sql [sql语句] - */ - query(sql: string) { - if (typeof sql !== 'string') { - return Promise.reject( - new SqlErr( - `Query error, argument sql must be string. ${typeof sql} given`, - sql - ) - ) - } - - return this.connect().then((conn: Conn) => { - let out = defer() - - conn.query(sql, (err: Error, result: any) => { - conn.release() - if (err) { - return out.reject(new SqlErr(`Query ${err}`, sql)) - } - out.resolve(result) - }) - return out.promise - }) - } - - drop() { - if (!this.db) { - return Promise.reject('') - } - - this.connect().then((conn: Conn) => { - conn.query('') - }) - } - - dbList() { - return this.connect().then((conn: Conn) => { - let out = defer() - - conn.query('SHOW DATABASES', (err: Error, row: any) => { - conn.release() - if (err) { - return out.reject(new SqlErr('SHOW DATABASES ' + err)) - } - out.resolve(row.map((it: any) => it.Database)) - }) - - return out.promise - }) - } - - //返回数据表 - tableList() { - return this.connect().then((conn: Conn) => { - const out = defer() - - conn.query('SHOW TABLES', (err: Error, row: any) => { - conn.release() - if (err) { - return out.reject(new SqlErr('SHOW TABLES ' + err)) - } - out.resolve(row.map((it: any) => it[Object.keys(it)[0]])) - }) - - return out.promise - }) - } -} - -export default Api