完成3.0版的转变

master
宇天 2018-05-29 02:42:12 +08:00
parent f289d2f3c2
commit 3340e93509
8 changed files with 488 additions and 230 deletions

View File

@ -1,12 +1,12 @@
3.0.0 / 2018-04-16 3.0.0 / 2018-04-16
================== ==================
> 这是一个全新的大版本, 不向下兼容2.x, 使用typescript重构 > 这是一个全新的大版本, 不向下兼容2.x。
* 重构API, 使用链式操作, 逻辑更加清晰 * 重构API, 使用链式操作, 逻辑更加清晰
* 支持完整的pool option * 支持完整的pool option
* 新增drop方法,支持删除数据库/数据表 * 新增drop方法,支持删除数据库/数据表
* 新增tableCreate/dbCreate方法, 支持创建数据库/数据表 * 新增tableCreate/dbCreate方法, 支持创建数据库/数据表
* 新增indexCreate/indexRename/indexDrop/indexList, 支持对索引的增删改查 * 新增indexCreate/indexDrop/indexList, 支持对索引的增删改查
2.2.2 / 2018-03-22 2.2.2 / 2018-03-22

21
LICENSE Normal file
View File

@ -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.

View File

@ -5,17 +5,15 @@
* *
*/ */
'use strict' 'use strict'
import 'es.shim' require('es.shim')
const mysql = require('mysql') const mysql = require('mysql')
import Api from './lib/api' const Api = require('./lib/api')
class Mysqli { class Mysqli {
useSlaveDB: boolean
pool: any
/** /**
* [constructor 构造数据库连接池] * [constructor 构造数据库连接池]
*/ */
constructor(config: any) { constructor(config) {
if (!Array.isArray(config)) { if (!Array.isArray(config)) {
config = [config] config = [config]
} }
@ -27,7 +25,7 @@ class Mysqli {
restoreNodeTimeout: 10000 restoreNodeTimeout: 10000
}) })
config.forEach((item: { [prop: string]: any }, i: number) => { config.forEach((item, i) => {
let { let {
host, host,
port, port,
@ -66,11 +64,11 @@ class Mysqli {
} }
//对外的escape方法 //对外的escape方法
static escape(val: any) { static escape(val) {
return mysql.escape(val) return mysql.escape(val)
} }
emit(fromSlave = false, db: string = '') { emit(fromSlave = false, db = '') {
let slave = fromSlave && this.useSlaveDB ? 'SLAVE*' : 'MASTER' let slave = fromSlave && this.useSlaveDB ? 'SLAVE*' : 'MASTER'
return new Api(this.pool, slave, db) return new Api(this.pool, slave, db)
} }

180
lib/api.js Normal file
View File

@ -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

View File

@ -5,57 +5,47 @@
* @version $Id$ * @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 { class Method {
pool: any constructor(pool, slave, db, table) {
slave: string
db: string
cache: { [prop: string]: any } = {}
constructor(pool: object, slave: string, db: string, table: string) {
this.pool = pool this.pool = pool
this.slave = slave this.slave = slave
this.db = db this.db = db
this.cache = { table } this.cache = { table }
} }
private connect() { connect() {
let out = defer() let defer = Promise.defer()
this.pool.getConnection(this.slave, (err: Error, conn: Conn) => { this.pool.getConnection(this.slave, (err, conn) => {
if (err) { if (err) {
return out.reject(new SqlErr(`MySQL connect ${err}`)) return defer.reject(new SqlErr(`MySQL connect ${err}`))
} }
if (this.db) { if (this.db) {
conn.query('USE ' + this.db, (err: Error) => { conn.query('USE ' + this.db, err => {
if (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 { } else {
out.resolve(conn) defer.resolve(conn)
} }
}) })
return out.promise return defer.promise
} }
leftJoin(tables: any[]) { leftJoin(tables) {
this.cache.leftJoin = tables this.cache.leftJoin = tables
return this return this
} }
rightJoin(tables: any[]) { rightJoin(tables) {
this.cache.rightJoin = tables this.cache.rightJoin = tables
return this return this
} }
join(tables: any[]) { join(tables) {
this.cache.join = tables this.cache.join = tables
return this return this
} }
@ -71,7 +61,7 @@ class Method {
* }) * })
* obj形式的过滤, 支持多种多样, 详细请看Readme介绍 * obj形式的过滤, 支持多种多样, 详细请看Readme介绍
*/ */
filter(val: any) { filter(val) {
this.cache.filter = val this.cache.filter = val
return this return this
} }
@ -81,25 +71,25 @@ class Method {
* @param {number }} keys [以对象形式传入值] * @param {number }} keys [以对象形式传入值]
* : {name: 1, age: -1} 1代表顺序, -1代表逆序 * : {name: 1, age: -1} 1代表顺序, -1代表逆序
*/ */
sort(keys: { [prop: string]: number }) { sort(keys) {
this.cache.sort = keys this.cache.sort = keys
return this return this
} }
// 从第几条记录开始返回, 必须搭配limit使用,否则会被忽略 // 从第几条记录开始返回, 必须搭配limit使用,否则会被忽略
skip(skip: number) { skip(skip) {
this.cache.skip = skip this.cache.skip = skip
return this return this
} }
// 返回指定数量的记录 // 返回指定数量的记录
limit(size: number) { limit(size) {
this.cache.size = size this.cache.size = size
return this return this
} }
// 截取指定范围内的记录 // 截取指定范围内的记录
slice(start: number, end: number) { slice(start, end) {
this.cache.limit = [start, end - start] this.cache.limit = [start, end - start]
return this return this
} }
@ -108,7 +98,7 @@ class Method {
* [withFields 选取指定的字段] * [withFields 选取指定的字段]
* @param {string[]} fields [以数组形式传入] * @param {string[]} fields [以数组形式传入]
*/ */
withFields(fields: string[]) { withFields(fields) {
this.cache.fields = fields this.cache.fields = fields
return this return this
} }
@ -121,9 +111,13 @@ class Method {
* [getAll 获取所有记录] * [getAll 获取所有记录]
* @param {any[]} ids [description] * @param {any[]} ids [description]
*/ */
getAll(ids?: any[]) { getAll(ids) {
if (!this.cache.filter && 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 { let {
@ -149,8 +143,7 @@ class Method {
} }
} }
let sql: string let sql = parser.select(fields)
sql = parser.select(fields)
sql += `FROM ${table} ` sql += `FROM ${table} `
if (leftJoin) { if (leftJoin) {
sql += parser.leftJoin(leftJoin) sql += parser.leftJoin(leftJoin)
@ -174,17 +167,17 @@ class Method {
sql += parser.limit(limit) sql += parser.limit(limit)
} }
return this.connect().then((conn: Conn) => { return this.connect().then(conn => {
let out = defer() let defer = Promise.defer()
conn.query(sql, (err: Error, result: any[]) => { conn.query(sql, (err, result) => {
conn.release() conn.release()
if (err) { 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 获取单条记录详细] * [get 获取单条记录详细]
* @param {any} id [取主键值为id的记录, 当且仅当没设置过滤条件时有效] * @param {any} id [取主键值为id的记录, 当且仅当没设置过滤条件时有效]
*/ */
get(id?: any) { get(id) {
return this.getAll(id ? [id] : null).then((list: any[]) => { return this.getAll(id ? [id] : null).then(list => {
return list[0] return list[0]
}) })
} }
@ -202,8 +195,8 @@ class Method {
* [count 获取记录总数] * [count 获取记录总数]
* @return {number} [description] * @return {number} [description]
*/ */
count(): number { count() {
return this.getAll().then((list: any[]) => { return this.getAll().then(list => {
return list.length return list.length
}) })
} }
@ -212,7 +205,7 @@ class Method {
* [insert 插入单条文档, 返回当前插入的文档的ID(如果是自增)] * [insert 插入单条文档, 返回当前插入的文档的ID(如果是自增)]
* @param {any }} doc [文档object] * @param {any }} doc [文档object]
*/ */
insert(doc: { [prop: string]: any }) { insert(doc) {
if (!doc) { if (!doc) {
return Promise.reject(new SqlErr('Insert Error: empty document')) return Promise.reject(new SqlErr('Insert Error: empty document'))
} }
@ -227,19 +220,19 @@ class Method {
} }
sql += `(${keys.join(',')}) VALUES (${vals.join(',')})` sql += `(${keys.join(',')}) VALUES (${vals.join(',')})`
return this.connect().then((conn: Conn) => { return this.connect().then(conn => {
const out = defer() const defer = Promise.defer()
conn.query(sql, (err: Error, result: any) => { conn.query(sql, (err, result) => {
conn.release() conn.release()
if (err) { 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过滤条件 * 可以使用filter过滤条件
* @param {any }} doc [要更新的字段] * @param {any }} doc [要更新的字段]
*/ */
update(doc: { [prop: string]: any }) { update(doc) {
if (!doc) { if (!doc) {
return Promise.reject(new SqlErr('Update Error: empty document')) return Promise.reject(new SqlErr('Update Error: empty document'))
} }
@ -267,19 +260,19 @@ class Method {
sql += fields.join(',') sql += fields.join(',')
sql += parser.filter(filter) sql += parser.filter(filter)
return this.connect().then((conn: Conn) => { return this.connect().then(conn => {
const out = defer() const defer = Promise.defer()
conn.query(sql, (err: Error, result: any) => { conn.query(sql, (err, result) => {
conn.release() conn.release()
if (err) { 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} ` let sql = `DELETE FROM ${table} `
sql += parser.filter(filter) sql += parser.filter(filter)
return this.connect().then((conn: Conn) => { return this.connect().then(conn => {
const out = defer() const defer = Promise.defer()
conn.query(sql, (err: Error, result: any) => { conn.query(sql, (err, result) => {
conn.release() conn.release()
if (err) { 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

View File

@ -6,7 +6,16 @@
*/ */
const { escape } = require('mysql') 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) { if (val === null) {
return String(val) return String(val)
} }
@ -15,7 +24,7 @@ function getType(val: any): string {
.slice(8, -1) .slice(8, -1)
.toLowerCase() .toLowerCase()
} }
function parse$or(arr: any[]) { function parse$or(arr) {
let sql = '' let sql = ''
for (let it of arr) { for (let it of arr) {
sql += '(' sql += '('
@ -29,7 +38,7 @@ function parse$or(arr: any[]) {
sql = sql.slice(0, -3) sql = sql.slice(0, -3)
return sql return sql
} }
function parse$and(arr: any[]) { function parse$and(arr) {
let sql = '' let sql = ''
for (let it of arr) { for (let it of arr) {
sql += '(' sql += '('
@ -44,7 +53,7 @@ function parse$and(arr: any[]) {
return sql return sql
} }
function parse$opt(opt: { [prop: string]: any }) { function parse$opt(opt) {
let sql = '' let sql = ''
for (let k in opt) { for (let k in opt) {
let tmp = opt[k] let tmp = opt[k]
@ -60,7 +69,7 @@ function parse$opt(opt: { [prop: string]: any }) {
} }
if (tmp.$in) { if (tmp.$in) {
let list = tmp.$in.map((it: any) => { let list = tmp.$in.map(it => {
return escape(it) return escape(it)
}) })
sql += ` ${k} IN (${list.join(',')}) ` sql += ` ${k} IN (${list.join(',')}) `
@ -70,7 +79,7 @@ function parse$opt(opt: { [prop: string]: any }) {
if (tmp.$between.length < 2) { if (tmp.$between.length < 2) {
throw new Error(`Array $between's length must be 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) return escape(it)
}) })
sql += ` ${k} BETWEEN ${list[0]} AND ${list[1]} ` sql += ` ${k} BETWEEN ${list[0]} AND ${list[1]} `
@ -102,32 +111,45 @@ function parse$opt(opt: { [prop: string]: any }) {
return sql 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 = '' let sql = ''
for (let it of tables) { for (let it of tables) {
it.table = fixtable(it.table)
sql += ` LEFT JOIN ${it.table} ON ${it.on} ` sql += ` LEFT JOIN ${it.table} ON ${it.on} `
} }
return sql return sql
}, },
rightJoin(tables: any[]) { rightJoin(tables = []) {
let sql = '' let sql = ''
for (let it of tables) { for (let it of tables) {
it.table = fixtable(it.table)
sql += ` RIGHT JOIN ${it.table} ON ${it.on} ` sql += ` RIGHT JOIN ${it.table} ON ${it.on} `
} }
return sql return sql
}, },
join(tables: any[]) { join(tables = []) {
let sql = '' let sql = ''
for (let it of tables) { for (let it of tables) {
it.table = fixtable(it.table)
sql += ` JOIN ${it[0]} ON ${it.on} ` sql += ` JOIN ${it[0]} ON ${it.on} `
} }
return sql return sql
}, },
filter(opt: any) { filter(opt) {
if (typeof opt === 'string') { if (typeof opt === 'string') {
return ` WHERE ${opt} ` return ` WHERE ${opt} `
} }
@ -146,12 +168,12 @@ export const parser = {
return ' ' return ' '
}, },
select(arr: string[] = ['*']) { select(arr = ['*']) {
return `SELECT ${arr.join(',')} ` return `SELECT ${arr.join(',')} `
}, },
// 排序 ---------------------------------- // 排序 ----------------------------------
sort(obj: { [propName: string]: number } = {}) { sort(obj = {}) {
let sort = '' let sort = ''
for (let i in obj) { for (let i in obj) {
let c = '' let c = ''
@ -167,28 +189,91 @@ export const parser = {
} }
}, },
limit(...args: number[]) { limit(...args) {
return ` LIMIT ${args.join(',')} ` 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 { class SqlErr {
sql: string constructor(msg = '', sql = '') {
constructor(msg: string = '', sql: string = '') { this.message = msg
super(msg)
this.sql = sql this.sql = sql
hideProperty(this, 'stack', msg)
}
toString() {
return this.message
} }
} }
export const defer = () => { exports.SqlErr = SqlErr
let obj: { [prop: string]: any } = {} exports.parser = parser
obj.promise = new Promise((yes, no) => { exports.escape = escape
obj.resolve = yes exports.fixtable = fixtable
obj.reject = no
})
return obj
}
export { escape }
export default escape

View File

@ -2,9 +2,9 @@
"name": "mysqli", "name": "mysqli",
"version": "3.0.0", "version": "3.0.0",
"description": "MySQL tool", "description": "MySQL tool",
"main": "dist/index.js", "main": "index.js",
"dependencies": { "dependencies": {
"es.shim": "^0.0.3", "es.shim": "^1.0.1",
"mysql": "^2.13.0" "mysql": "^2.13.0"
}, },
"repository": "https://github.com/yutent/mysqli.git", "repository": "https://github.com/yutent/mysqli.git",

View File

@ -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