febs db库用于连接数据库

`febs-db是在citong-db@1.5.3基础上进行开发, citong-db库已停止更新`

(v0.0.3及之前版本接口已经不适用, 请查看使用说明[README-v0.0.3](./README-v0.0.3.md))

目前支持 `mysql`, `mssql`; 其中 mysql请使用`InnoDB`引擎.

- [Install](#install)
- [Exception](#exception)
- [Define-table](#define-table)
  - [register table](#register-table)
  - [combined primary key](#combined-primary-key)
  - [column data type](#column-data-type)
  - [name map](#name-map)
  - [custom auto increase primary key](#custom-auto-increase-primary-key)
- [Connect db](#connect-db)
- [Query db](#query-db)
  - [add](#add)
  - [remove](#remove)
  - [update](#update)
  - [count](#count)
  - [exist](#exist)
  - [select](#select)
  - [selectLockRow](#selectlockrow)
  - [store procedure](#store-procedure)
  - [condition](#condition)
- [transaction](#transaction)
  - [isolation level](#isolation-level)
  - [transaction hook](#transaction-hook)
- [Join](#join)
- [Class database API](#class-database-api)
  - [transactionCustomData](#transactioncustomdata)
  - [constructor](#constructor)
  - [registerTable](#registertable)
  - [exec](#exec)
  - [execProcedure](#execprocedure)
  - [transaction](#transaction-1)
  - [dbType](#dbtype)
  - [sqlLogCallback](#sqllogcallback)
  - [escapeLike](#escapelike)
  - [type\_cast](#type_cast)
  - [ret\_data\_cvt](#ret_data_cvt)
- [Class tablebase API](#class-tablebase-api)
    - [constructor](#constructor-1)
    - [add](#add-1)
    - [remove](#remove-1)
    - [update](#update-1)
    - [selectLockRow](#selectlockrow-1)
    - [select](#select-1)
    - [count](#count-1)
    - [exist](#exist-1)
    - [sql\_add](#sql_add)
    - [sql\_remove](#sql_remove)
    - [sql\_update](#sql_update)
    - [sql\_selectLockRow](#sql_selectlockrow)
    - [sql\_select](#sql_select)
    - [sql\_count](#sql_count)
    - [tablename](#tablename)
    - [condition](#condition-1)
    - [db](#db)
    - [join\_inner](#join_inner)
    - [join\_cross](#join_cross)
    - [join\_left](#join_left)
    - [join\_right](#join_right)
    - [join\_full](#join_full)
- [Class condition API](#class-condition-api)
    - [equal](#equal)
    - [more\_than](#more_than)
    - [more\_equal](#more_equal)
    - [less\_equal](#less_equal)
    - [less\_than](#less_than)
    - [not\_equal](#not_equal)
    - [like](#like)
    - [between](#between)
    - [in](#in)
    - [not\_in](#not_in)
    - [col\_inc](#col_inc)
    - [col\_origin\_sql](#col_origin_sql)
- [Class dataType API](#class-datatype-api)
    - [NULL](#null)
    - [getType](#gettype)
    - [isIntegerType](#isintegertype)
    - [isStringType](#isstringtype)
  - [getValueBigInt](#getvaluebigint)
  - [getValueBit](#getvaluebit)
- [Class join](#class-join)
    - [sql\_select](#sql_select-1)
    - [set\_alias1](#set_alias1)
    - [set\_alias2](#set_alias2)
    - [set\_on](#set_on)
    - [table1](#table1)
    - [alias1](#alias1)
    - [join\_inner](#join_inner-1)
    - [join\_cross](#join_cross-1)
    - [join\_left](#join_left-1)
    - [join\_right](#join_right-1)
    - [join\_full](#join_full-1)
    - [select](#select-2)
    - [count](#count-2)

# Install

Use npm to install:

```js
npm install febs-db --save
```

 febs-db是一个orm库, 主要的类为:

> `database`: 代表一个数据库; 可以用于执行sql语句, 进行事务等操作.

> `tablebase`: 代表一个数据库表; 针对表的基本操作在这个对象中完成;

> `dataType`: 数据表的字段类型定义

> `condition`: 进行查询条件构造,会对类型与值进行类型检查. 每个表对象都有一个此对象, 使用 tablebase.condition 获取对象.

> `procedureParams`: 调用存储过程时, 用于构建参数.

# Exception

系统在错误发生时会抛出`exception`类型的异常

事务处理中发生异常将自动rollback.

异常类如下
```js
/**
* @desc: 构造异常对象.
* @param msg: 异常消息
* @param errcode: 异常代码
* @param filename: 异常文件名
* @param line: 异常文件所在行
*/
exception(msg, errcode, filename, line)
```
例子:
```js
var exception = require('febs-db').exception;
try {
  ...
} catch (e) {
  if (e instanceof exception) {
    if (e.code == exception.DB_SqlException) {
      // 查询语句错误.
    }
  } else {
    throw e;
  }
}
```

定义了常用的错误code.

```js
// @desc: 通用错误.
exception.DB_CommonException
// @desc: 数据查询条件错误。sql语句问题.
exception.DB_SqlException
// @desc: 数据库连接问题.
exception.DB_ConnectException
// @desc: 数据库查询时产生的问题, 可能是数据库服务器问题, 或是并发产生的事务锁问题等.
exception.DB_QueryException
```

# Define-table

操作一个数据表之前, 需要先对表结构进行定义, 与数据不匹配的定义在执行数据操作时会报错. 数据列可以仅列出需要操作的列.

```js
var tablebase = require('febs-db').tablebase;
var dataType  = require('febs-db').dataType;

class TableDemo extends tablebase {
  constructor() {
    super(
      'User',   // table name.
      'ID',     // primary key.
      {         // cols.
        ID:       {type: dataType.BigInt(true), key: true}, // key means auto-incrementing
        Name:     {type: dataType.Varchar(10)},
        NumberCol:{type: dataType.Float()},
        IntCol:   {type: dataType.Int(false)},
        BoolCol:  {type: dataType.Bit()}
      }
    );
  }
}
```
## register table
```js
var database  = require('febs-db').database;

class dbAgent extends database {
  constructor() {
    // 数据库对象.
    super('mysql', {});

    // 注册数据表.
    this.TableDemo = this.registerTable(new TableDemo(), 'mapName');
  }
}

// 使用此对象进行数据库操作, 存储至全局对象中, 所有的用户连接可以使用同一个对象. 内部使用连接池重复利用数据库连接.
global.dbagent = new dbAgent();
```

## combined primary key

```js
var tablebase     = require('febs-db').tablebase;
var dataType      = require('febs-db').dataType;

class TableDemo extends tablebase {
  constructor() {
    super(
      'Admin',  // table name.
      ['ID', 'IntCol'],     // primary keys.
      {         // cols.
        ID:       {type: dataType.BigInt(true), key: true}, // the auto-incrementing
        Name:     {type: dataType.Varchar(10), map:'Name1'},
        NumberCol:{type: dataType.Float()},
        IntCol:   {type: dataType.Int(false)},
        BoolCol:  {type: dataType.Bit()}
      }
    );
  }
}
```

## column data type

目前支持如下的数据类型. 数据类型定义在`dataType`类型中

|  类型  | 对应创建方法 | 说明 |
|-------|----|---|
| `VarChar` | dataType.VarChar(length)   | |
| `NVarChar` | dataType.NVarChar(length)   | |
| `Text` | dataType.Text()   | |
| `NText` | dataType.NText()   | |
| `Char` | dataType.Char(length)   | |
| `NChar` | dataType.NChar(length)   | |
| `Bit` | dataType.Bit()   | 对应`boolean`类型 |
| `BigInt` | dataType.BigInt(unsigned)   | 当数值在Number.MAX_SAFE_INTEGER之内时为`number`, 当数值超过时, 为`bignumber` (查看bignumber.js库 ( https://www.npmjs.com/package/bignumber.js ) |
| `TinyInt` | dataType.TinyInt(unsigned)   | |
| `SmallInt` | dataType.SmallInt(unsigned)   | |
| `Int` | dataType.Int(unsigned)   | |
| `Float` | dataType.Float(unsigned)   | |
| `Numeric` | dataType.Numeric(unsigned, precision, scale)   | |
| `Decimal` | dataType.Decimal(unsigned, precision, scale)   | |
| `Real` | dataType.Real(unsigned)   | |
| `DateTime` | dataType.DateTime()   | 对应js的`Date`类型; 数据库中使用utc时间存储. 本地设置时使用本地时间, 系统会自动转换.<br> 在数据库中, <br>  mssql: 存储的格式为 (YYYY-MM-DD hh:mm:ss.SSS)<br>sqlserver中可使用`smalldatetime`,`datetime`,`datetime2`类型.<br>  mysql:   datetime   (YYYY-MM-DD hh:mm:ss.SSS)<br> 使用length来指明ms数据存储. |
| `Binary` | dataType.Binary(length)   | 对应js的`Buffer`类型 |
| `VarBinary` | dataType.VarBinary(length)   | 对应js的`Buffer`类型 |

## name map

在定义数据表时, 可以对数据表名和字段名称进行映射, 隐藏真正的字段名称以便保证安全性.

在逻辑编写中使用有意义的名称, 而在数据库定义中使用无意义的名称来保证安全性.

```js
var tablebase     = require('febs-db').tablebase;
var dataType      = require('febs-db').dataType;

class TableDemo extends tablebase {
  constructor() {
    super(
      'Admin',  // table name.
      ['ID', 'IntCol'],     // primary keys.
      {         // cols.
        ID:       {type: dataType.BigInt(true), map:'col1', key: true}, // the auto-incrementing
        Name:     {type: dataType.Varchar(10),  map:'col2'},
        NumberCol:{type: dataType.Float(),      map:'col3'},
        IntCol:   {type: dataType.Int(false),   map:'col4'},
        BoolCol:  {type: dataType.Bit(),        map:'col5'}
      }
    );
  }
}

database.registerTable(new TableDemo(), 'realName');

```

## custom auto increase primary key

默认情况下, 指定了主键 `key=true`, 则会使用数据库默认的自增主键的方式设置主键, 并在成功 `add` 之后返回插入的键.

在分步式情况下, 可以使用自定义主键的生成行为:



```js
// custom generate key.
function customGenerateKeyCB() {
  // e.g. use objectId.
  return objectid().toHexString();
}


// create db.
var db = new database(
               'mysql', // 数据库类型, 目前支持 'mysql', 'mssql'
                opt,
                customGenerateKeyCB,  // 指定自定义主键生成方法.
              );
```

# Connect db

```js
var database = require('febs-db').database;


// 使用如下的结构来构建数据库, 数据库将使用此信息进行连接.
var opt = {

  /**
   * timeout of connect to database.
   */
  connectTimeout    : 5000,
  /**
   * timeout of query.
   */
  queryTimeout      : 5000,
  /**
   * timeout of acquire connection from pool.
   */
  acquireTimeout    : 5000,
  /**
   * max queue length of wait for acquire connection.
   */
  queueLimit        : 200,
  /**
   * max count of connection in pool.
   */
  connectionLimit   : 10,
  /**
   * idle timeout to recreate connect.
   */
  idleTimeoutMillis : 600000,
  /**
   * database host.
   */
  host              : '',
  /**
   * databse port.
   */
  port              : 3306,
  /**
   * database name.
   */
  database          : '',
  /**
   * user name of databse.
   */
  user              : '',
  /**
   * the password of user.
   */
  password          : '',

  /**
   * [for mssql] encrypt the connect scheme. (Windows Azure)
   */
  encrypt           : true,

  /**
   * the prefix of table.
   */
  table_prefix      : '',
};

var db = new database(
               'mysql', // 数据库类型, 目前支持 'mysql', 'mssql'
                opt
              );
```

# Query db

- [add](#add)
- [remove](#remove)
- [update](#update)
- [count](#count)
- [exist](#exist)
- [select](#select)
- [selectLockRow](#selectlockrow)
- [store procedure](#store-procedure)
- [condition](#condition)

## add

直接使用数据对象添加
```js
let mod = {Name:'demo', IntCol:10};

table.add(mod)
.then((ret)=>{
  console.log(`Result of exec is: ${ret}`);
  // 如果存在自增键.将自动写入存储在mod中.
})
.catch(e=>{});
```

## remove

使用查询条件进行删除.

!! 查询条件可以使用 [condition](#condition) 进行构造, condition会对数据类型进行验证.
```js
// 构造sql.
var where = table.condition.equal('id', 1);
table.remove(where); // 删除id=1的数据.
.then((ret)=>{
  console.log(`Result of exec is: ${ret}`);
})
.catch(e=>{});
```

## update

- 更新方法需传入一个对象, 更新其中的非主键对应的值; 

- 如果参数中附带主键, 则主键将作为更新的查询条件之一;

- 如果不附带主键, 则执行条件where必须存在, 否则抛出异常.

```js
// 构造sql.
let mod = {
  ID:     1,      // primary key.
  name:   "name",
  intCol: table.condition.col_inc(1),   // 此字段自增1.
  intCol2:table.condition.col_origin_sql('`intCol2`+1')   // 执行原始sql, 不进行类型验证.
};

table.update(mod);  // ID=1,name="name",intCol=intCol+1,intCol2=intCol2+1
.then((ret)=>{
  console.log(`Result of exec is: ${ret}`);
})
.catch(e=>{});
```

## count

```js
let where = '';
where += table.condition.equal('id', 43); // `id`=43.
where += 'AND';
where += table.condition.like('name', '%123'); // `name` like '%123'.

table.count(where)
.then(count=>{
  console.log(`Result is ${count}`);
})
.catch(err=>{})
```

## exist

```js
table.exist(1)  // 判断id=1的数据是否存在.
.then(ret=>{
  console.log(`Result is ${ret}`);
})
.catch(err=>{})
```

## select

查询时如果不指定分页信息, 则默认查询10000条.
```js

// make query conditon.
var where = '';
where += table.condition.equal('ID', 1);
where += 'AND';
where += table.condition.more_than('ID', 1);

// select.
// SELECT ID,Name FROM TableName WHERE [where]; and offset, limit.
table.select(where, {
  cols: ['ID','Name'],
  offset: 0,
  limit: 100
})
.then(ret=>{})
.catch(e=>{});

// query.
// SELECT COUNT(ID) as x,Name FROM TableName WHERE [where]; with <pagerInfo>.
table.select(where, {
  cols: ['COUNT(ID) as x','Name'],
  offset: 0,
  limit: 100
})
.then(ret=>{})
.catch(e=>{});
```

## selectLockRow

锁行方式查询, 只能在事务中使用此方式. 在事务结束或update之后自动解锁.

```js
table.selectLockRow(id, ['ID','Name'])
.then(ret=>{})
.catch(e=>{});
```

## store procedure

调用如下的存储过程.
```sql
# mysql procedure
CREATE PROCEDURE procedureName(out out1 int, out out2 int, in userid int)
BEGIN
  select count(id) INTO out1 from table1;
  select count(id) INTO out2 from table1 where id=userid;
  select out1, out2;
END
```
调用过程如下:
```js
var procedureParams = require('febs-db').procedureParams;
var dataType        = require('febs-db').dataType;

// make param.
var params = new procedureParams();
params.addOut('out1', dataType.Int());
params.addOut('out2', dataType.Int());
params.addIn('userid', dataType.Int(), 2);

// exec.
db.execProcedure('procedureName', params)
.then(ret=>{
  console.log('');
  console.log('[promise procedure]');
  console.log(ret.out.out1);
  console.log(ret.out.out2);
})
.catch(e=>{
  console.log(e);
})
```

## condition

构造`key=value`条件语句
```js
table.condition.equal('colName', value) // return sql string.
```

构造`key>value`条件语句
```js
table.condition.more_than('colName', value) // return sql string.
```

构造`key>=value`条件语句
```js
table.condition.more_equal('colName', value) // return sql string.
```

构造`key<=value`条件语句
```js
table.condition.less_equal('colName', value) // return sql string.
```

构造`key<value`条件语句
```js
table.condition.less_than('colName', value) // return sql string.
```

构造`key<>value`条件语句
```js
table.condition.not_equal('colName', value) // return sql string.
```

构造`key LIKE value`条件语句
```js
// 可对value添加%_通配符前,进行db.escapeLike(value),进行安全转义.
table.condition.like('colName', value) // return sql string.
```

构造`key BETWEEN value1 AND value2`条件语句
```js
table.condition.between('colName', value1, value2) // return sql string.
```

构造`key IN (value1,value2...)`条件语句
```js
table.condition.in('colName', valueArray) // return sql string.
```

构造`key NOT IN (value1,value2...)`条件语句
```js
table.condition.not_in('colName', valueArray) // return sql string.
```

复杂逻辑条件.
```js
let where = '';
where += table.condition.equal('colName', value);
where += 'AND';
where += table.condition.equal('colName2', value2);
```

在update中使用, 构造自增字段.
```js
let mod = {
  id:   1,
  col1: table.condition.col_inc(2)  // 相当于 col1 = col1+2
}
await table.update(mod);
```

在update中使用, 调用原始sql语句.
```js
let mod = {
  id:   1,
  col1: table.condition.col_origin_sql('table2.col2+col1')  // 相当于 col1 = table2.col2+col1
}
await table.update(mod);
```


# transaction

* 执行事务系统将创建一个独立的连接, 事务完成后连接对象将重新被插入到连接池中. 在嵌套的事务中, 不会重新创建连接.
* 事务处理函数中, 返回`false`或发生`异常` 将`rollback`, 返回`true`将`commit`
* 允许事务嵌套调用.
* 仅支持行级锁, 不支持表级锁.

## isolation level

事务隔离级别在 `isolationLevel` 类中定义; 

事务默认提供`共享锁`, 需要获得`排他锁`使用 `selectLockRow`

```js
var isolationLevel = require('febs-db').isolationLevel;

/**
* @desc: 允许事务读取另外一个事务中未commit的数据. (脏读)
*/
isolationLevel.Read_uncommitted;
/**
* @desc: 一个事务读取数据,另外一个事务也可以读取数据并且进行更新提交. (不可重复读)
*/
isolationLevel.Read_committed;
/**
* @desc: 不同事务互相不影响, 即使其中一个事务修改了数据并提交, 另一个事务还是查询到原来的数据. (幻读)
*/
isolationLevel.Repeatable_read;
/**
* @desc: 一个事务进行数据查询后, 并且在事务提交之前, 其他事务不允许修改此数据.
*        查询操作就将锁住数据, 避免其他事务修改. 但读共享.
*/
isolationLevel.Serializable;
```

|   |  脏读 |  不可重复读  |  幻读  |
|---|------|-------------|--------|
| Read_uncommitted | √ | √ | √ |
| Read_committed | ×  | √ | √ |
| Repeatable_read | × | × | √ |
| Serializable | × | × | × |


```js
//
// 开启sql日志. global.dbagent 是预先存储的全局数据库对象
global.dbagent.sqlLogCallback = function(err, sql, isTransactionBeginOrEnd) {
  console.log(
`
${febs.utils.getTimeString(Date.now(), 'yyyy-MM-dd hh:mm:ss')}
SQL: ${sql}
ERR: ${err}
`);
}

//
// 开启一个事务.
global.dbagent.transaction(
  isolationLevel.Repeatable_read, // 使用可重读隔离级别.
  async function(db){
    // !!![在此事务中sql相关方法只能使用db, 使用其他数据库对象将引起错误.]

    db.transactionCustomData = 'custom data'; // 存储此对象, 在后续的嵌套事务中都可以使用.


    // db是一个global.dbagent的副本. 克隆了全部的global.dbagent方法, 可以直接调用.

    // 执行sql方法 or 嵌套执行其他事务.

    /**
    * 返回true则事务自动提交, 返回false或者异常则rollback.
    */
    return true; 
  })
  .then(res=>{
    // res表明事务是否成功提交.
    if (res)
      console.log(`the transaction is committed`);
    else
      console.log(`the transaction is rollback`);
  })
  .catch(err=>{  });
```

## transaction hook

事务的commit与rollback都会进行回调, 开发者可以在此处添加如redis事务等特殊的处理方法

```js
//
// 开启一个事务.
dbagent.transaction(
  isolationLevel.Repeatable_read, // 使用可重读隔离级别.
  async function(db){
  },
  // 事务commit前的回调.
  async function(db){
  },
  // 事务rollback前的回调.
  async function(db){
  }
);
```

# Join

```js

  let table1 = new Table1(...);
  let table2 = new Table2(...); 
  let table3 = new Table3(...); 

  let join = table1.join_inner(table2)
                   .set_alias1('A')
                   .set_alias2('B')
                   .on('A.id = B.id')
                   .join_inner(table3);

  /*
  * version 1.7.0 之前.
  */

  // select ... from (table1 as A inner join table2 as B on A.id = B.id) inner join table3.
  let joinSql = join.sql_select(...);

  // query.
  let r = await db.exec(joinSql);

  // convert data to fix time or other data.
  db.ret_data_cvt(r.rows, table1, table2, table3);

  /*
  * version 1.7.0 及之后
  */ 
  let r = await join.select(...);

```

# Class database API

- [transactionCustomData](#transactionCustomData)
- [constructor](#constructor)
- [registerTable](#registertable)
- [exec](#exec)
- [execProcedure](#execProcedure)
- [transaction](#transaction)
- [dbType](#dbtype)
- [sqlLogCallback](#sqllogcallback)
- [escapeLike](#escapeLike)
- [type_cast](#typecast)
- [ret_data_cvt](#ret_data_cvt)

## transactionCustomData

```js
  /**
  * @desc: 可在事务处理中使用的自定义变量, 同一个事务, 此变量一致.
  */
  transactionCustomData:any;
```

## constructor

```js
/*
* 构造
*/
constructor(dbtype, opt, customGenerateKeyCB = null)
```
* dbtype: 数据库类型, 目前仅支持 `'mysql'`, `'mssql'`
* customGenerateKeyCB: 自定义的主键生成方法; function():any;
* opt: 连接参数
```js
// 使用如下的结构来构建数据库, 数据库将使用此信息进行连接.
var opt = {

  /**
   * timeout of connect to database.
   */
  connectTimeout    : 5000,
  /**
   * timeout of query.
   */
  queryTimeout      : 5000,
  /**
   * timeout of acquire connection from pool.
   */
  acquireTimeout    : 5000,
  /**
   * max queue length of wait for acquire connection.
   */
  queueLimit        : 200,
  /**
   * max count of connection in pool.
   */
  connectionLimit   : 10,
  /**
   * database host.
   */
  host              : '',
  /**
   * databse port.
   */
  port              : 3306,
  /**
   * database name.
   */
  database          : '',
  /**
   * user name of databse.
   */
  user              : '',
  /**
   * the password of user.
   */
  password          : '',
  /**
   * the prefix of all tables.
   */
  table_prefix      : '',
};
```

## registerTable
```js
/**
* @desc: 注册表格到此数据库.
* @param mapName: 映射数据中真实的表名.
* @return 将db内部注册的tablebase对象返回.
*/
registerTable(table, mapName=null) : tablebase
```

## exec
```js
/**
* @desc: 执行sql语句.
* @return: Promise.
* @resolve:
*     ret - 查询结果.
*       {
          rowsAffected,  // 受影响的行数.
          rows,          // 返回的数据数组.
          insertId,      // 自增键的值.
        }
*/
exec(sql)
```

## execProcedure
```js
/**
* @desc: 执行存储过程.
* @param name: procedure name.
* @param procedureParams: in,out参数; 使用 procedureParams对象.
* @return: Promise.
* @resolve:
*     ret - 查询结果,out参数存储至其中.
*       {
          rowsAffected,  // 受影响的行数.
          rows,          // 返回的数据数组.
          insertId,      // 自增键的值.
          out,           // 输出结果的参数集合.
        }
*/
execProcedure(name, procedureParams)
```

## transaction
```js
/**
* @desc: 创建一个事务.
* @param isolationLevel: 事务级别. 使用了数据库不支持的隔离级别将reject (例如oracle中不支持READ UNCOMMITTED)
* @param taskCB: async function(db):boolean {}; 返回false则rollback, 返回true则commit.
* @param preCB: task执行前的第一个的回调.
* @param commitCB: 提交前的回调. 返回false则rollback, 返回true则commit.
* @param rollbackCB: rollback前的回调.
* @return: Promise.
* @resolve:
*     ret - 是否成功提交.
*/
transaction(isolationLevel, taskCB, commitCB, rollbackCB)
```

## dbType
```js
/**
* @desc: 数据库类型.
* @return: 'mysql' / 'mssql'.
*/
get dbtype()
```

## sqlLogCallback
```js
/**
* @desc: 设置执行sql的log回调. 每次执行数据库查询都将调用此方法.
* @param cb: function(err, sql, isTransactionBeginOrEnd) {}
*             - isTransactionBeginOrEnd: 是否是 事务 begin/commit/rollback.
*/
set sqlLogCallback(cb)
get sqlLogCallback()
```

## escapeLike
```js
  /**
  * @desc: 对likeSql进行转义操作.
  *         如mssql中, like字符为 'abc%a', 其中%需转义为 [%]
  * @return: string.
  */
  escapeLike(likeSql)
```

## type_cast
```js
/**
  * @desc: type cast, 为指定类型和值返回正确的sql值.
  * @return: 传入不配对的value与type,可引发异常. 返回sql.
  */
  type_cast(type, value)
```

## ret_data_cvt
```js
/**
* @desc: 转换查询结果中的数据,按类型转换.
* @return: 
*/
  ret_data_cvt(rows, ...table)
```


# Class tablebase API

- [constructor](#constructor-1)
- [add](#add-1)
- [remove](#remove-1)
- [update](#update-1)
- [selectLockRow](#selectlockrow-1)
- [select](#select-1)
- [count](#count-1)
- [exist](#exist-1)
- [sql_add](#sql_add)
- [sql_remove](#sql_remove)
- [sql_update](#sql_update)
- [sql_selectLockRow](#sql_selectlockrow)
- [sql_select](#sql_select)
- [sql_count](#sql_count)
- [tablename](#tablename)
- [db](#db)
- [condition](#condition-1)
- [getLogicColName](#getLogicColName)
- [join_inner](#join_inner)
- [join_cross](#join_cross)
- [join_left](#join_left)
- [join_right](#join_right)
- [join_full](#join_full)

### constructor
```js
/**
* @desc 构造数据表.
* @param idKeyName: 主键. 单主键时为主键名, 多主键时为主键名数组.
* @param tablename: 本表名.
* @param model: 本表模型.
*/
constructor(tablename, idKeyName, model)
```

`model`的定义格式如下:

> {<br>
    colName: {`type`: dataType.BigInt(10), `map`: '', `key`: true}, // the auto-incrementing<br>
    ...<br>
  }

- `colName`: 表示列名称
- `type`: 表示列类型, 查看 [column data type](#column-data-type)
- `map`:  映射数据库中真实的字段名称. 如果不指定则使用`colName`
- `key`:  是否是自增键; (同一个表只能有一个自增键, 当指定多个自增键时, 只认为最后一个为自增)


### add

```js
  /**
  * @desc: add
  *         (insertId will set to item.id)
  * @param item: 要添加的数据对象.
  * @return: Promise.
  * @resolve:
  *   ret - boolean. 表明是否有满足条件的插入更新成功.
  */
  add( item )
```

### remove

```js
  /**
  * @desc: remove; 删除条件必须存在.
  * @return: Promise.
  * @resolve:
  *   ret - boolean. 表明是否有满足条件的数据删除成功..
  */
  remove( where )
```

### update

```js
  /**
  * @desc: update data.
  *         if item.id is existed, sql condition is: 'id=value' AND (where)
  *         otherwise sql condition is: where 
  * @param item: 要更新的数据. 使用其中的主键值做为查询条件之一
  * @param where: 查询条件, 如果item中不存在主键, 则查询条件必须存在.
  * @return: Promise.
  * @resolve:
  *   ret - boolean. 表明是否有满足条件的数据更新成功.
  */
  update( item, where = null )
```

### selectLockRow

```js
  /**
  * @desc: select by id and lock row for update (use in transaction).
  *        
  * @param id: 主鍵值. 如果表定义为复合主键, 则id为object, 例如: {ID1:1, ID2:2}. 单住进直接为主键值.
  * @param cols:
  *           需要查询出的字段名称数组, 例如:['col1', 'col2', ...].
  * @return: Promise.
  * @resolve:
  *   ret - mod.
  */
  selectLockRow( id, cols = null )
```

### select

```js
  /**
  * @desc: select.
  *         sql的连接顺序为: SELECT cols FROM table where groupSql orderby pageInfo.
  *
  * @param where:
  *           查询条件,不会对此字符串验证. 使用 condition 对象进行构建.
  * @param opt: 查询选项. 可以包含以下键值.
  *         - cols:  需要查询出的字段名称数组; 例如: [col1, col2, ...]; 不指定则为查询全部.
  *         - groupSql:   group by子句, 不会对内容进行验证; 应包含group by关键字.
  *         - orderby:    orderby by子句, 例如: {key:true/false} true-means asc, false-means desc..
  *         - offset:     分页查询起始位置.
  *         - limit:      分页查询查询行数.
  * @return: Promise.
  * @resolve:
  *   ret - mod array.
  */
  select( where, opt = null )
```

### count

```js
  /**
  * @desc: count
  * @param: where
  * @return: Promise.
  * @resolve:
  *   ret - number.
  */
  count(where = null)
```

### exist

```js
  /**
  * @desc: exist
  *         id is Object if table is combined primary. 
  * @return: Promise.
  * @resolve:
  *   ret - boolean.
  */
  exist(id)
```

### sql_add

```js
/**
* @desc: 返回sql add.
* @return: string
*/
sql_add(item)
```

### sql_remove


```js
/**
* @desc: 返回sql remove.
* @return: string
*/
sql_remove(where)
```

### sql_update


```js
/**
* @desc: 返回sql remove.
* @return: string
*/
sql_update(item, where = null)
```

### sql_selectLockRow


```js
/**
* @desc: 返回sql selectLockRow.
* @return: string
*/
sql_selectLockRow(id, cols = null, alias=null)
```

### sql_select


```js
/**
* @desc: 返回sql select.
* @return: string
*/
sql_select(where, opt = null, alias=null)
```

### sql_count


```js
/**
* @desc: 返回sql count.
* @return: string
*/
sql_count(where, alias=null)
```


### tablename

```js
/**
  * @desc: 表名称.
  * @return: string.
  */
  get tablename()
```

### condition

```js
  /**
  * @desc: 条件构造对象，使用此对象可以在类型安全的情况下构造查询条件.
  * @return: 
  */
  get condition()
```

```js
/**
  * @desc: 使用字段的映射名称获得字段的逻辑名称.
  * @return: string; 找不到返回undefined.
  */
  getLogicColName(mapName)
```

### db

```js
  /**
  * @desc: 所属数据库.
  * @return: 
  */
  get db()
```

### join_inner

```js
  /**
  * @desc: join tableB后, 返回join对象.
  */
  join_inner(tableB)
```

### join_cross

```js
  /**
  * @desc: join tableB后, 返回join对象.
  */
  join_cross(tableB)
```

### join_left

```js
  /**
  * @desc: join tableB后, 返回join对象.
  */
  join_left(tableB)
```

### join_right

```js
  /**
  * @desc: join tableB后, 返回join对象.
  */
  join_right(tableB)
```

### join_full

```js
  /**
  * @desc: join tableB后, 返回join对象.
  */
  join_full(tableB)
```


# Class condition API

- [equal](#equal)
- [more_than](#more_than)
- [more_equal](#more_equal)
- [less_equal](#less_equal)
- [less_than](#less_than)
- [not_equal](#not_equal)
- [like](#like)
- [between](#between)
- [in](#in)
- [not_in](#not_in)
- [col_inc](#col_inc)
- [col_origin_sql](#col_origin_sql)

### equal

```js
  /**
  * @desc: 构造一个 key=value的sql条件语句.
  * @return: sql;
  */
  equal( key, value ) 
```

### more_than

```js
  /**
  * @desc: 构造一个 key>value的sql条件语句.
  * @return: sql;
  */
  more_than( key, value )
```

### more_equal

```js
  /**
  * @desc: 构造一个 key>=value的sql条件语句.
  * @return: sql;
  */
  more_equal( key, value )
```

### less_equal

```js
  /**
  * @desc: 构造一个 key<=value的sql条件语句.
  * @return: sql;
  */
  less_equal( key, value )
```

### less_than

```js
  /**
  * @desc: 构造一个 key<value的sql条件语句.
  * @return: sql;
  */
  less_than( key, value )
```

### not_equal

```js
  /**
  * @desc: 构造一个 key<>value的sql条件语句.
  * @return: sql;
  */
  not_equal( key, value ) 
```

### like

```js
  /**
  * @desc: 构造一个 key LIKE value的sql条件语句.
  *     不对value值进行反义操作.
  * @return: sql;
  */
  like( key, value )
```

### between

```js
  /**
  * @desc: 构造一个 key BETWEEN value1 AND value2的sql条件语句
  * @return: sql;
  */
  between( key, value1, value2 )
```

### in

```js
  /**
  * @desc: 构造一个 key IN (value1, value2, ...) 的sql条件语句
  * @return: sql;
  */
  in( key, valueArray )
```

### not_in

```js
  /**
  * @desc: 构造一个 key NOT IN (value1, value2, ...) 的sql条件语句
  * @return: sql;
  */
  not_in( key, valueArray )
```

### col_inc

```js
  /**
  * @desc: 在update中使用, 用于表明sql中字段自增n.
  * @example: col=col+n
  */
  col_inc(n)
```

### col_origin_sql

```js
  /**
  * @desc: 在update中使用, 用于表明 col=v, 将不对v进行任何检验.(也不在v字符串两边加'符号)
  */
  col_origin_sql(v)
```


# Class dataType API

- [NULL](#NULL)
- [getType](#gettype)
- [isIntegerType](#isintegertype)
- [isStringType](#isstringtype)
- [getValueBigInt](#getValueBigInt)
- [getValueBit](#getValueBit)

### NULL

```js
  /**
  * @desc: 代表NULL.
  */
  NULL   ()
```


### getType

```js
  /**
  * @desc: 获得参数的类型.(不考虑长度等其他选项)
  */
  getType   (value)
```

### isIntegerType

```js
  /**
  * @desc: 判断类型是否为整型. 
  */
  isIntegerType (value) 
```

### isStringType

```js
  /**
  * @desc: 判断类型是否为字符串. 
  */
  isStringType (value)
```

## getValueBigInt

```js
  /**
   * 将sql类型的bigint值转换成nodejs值, 大于13位的数值将使用bignumber, 否者使用number.
   * @param {*} sqlValue 数据库bigint值.
   */
  getValueBigInt(sqlValue)
```

## getValueBit

```js
  /**
   * 将sql类型的bit值转换成nodejs值
   * @param {*} sqlValue 数据库bit值.
   */
  getValueBit(sqlValue)
```


# Class join

- [sql_select](#sql_select-1)
- [set_alias1](#set_alias1)
- [set_alias2](#set_alias2)
- [set_on](#set_on)
- [table1](#table1)
- [table2](#table1)
- [alias1](#alias1)
- [alias2](#alias1)
- [join_inner](#join_inner-1)
- [join_cross](#join_cross-1)
- [join_left](#join_left-1)
- [join_right](#join_right-1)
- [join_full](#join_full-1)
- [select](#select-2)
- [count](#count-2)

### sql_select

```js
  /**
  * @desc: 返回sql select.
  *         查询的字段必须明确指明.
  * @return: string
  */
  sql_select(where, opt = null)
```

### set_alias1

```js
  /**
  * @desc: 设置别名1. (仅第一次join时可以设置.)
  * @return: 支持语法糖
  */
  set_alias1(aliasName)
```

### set_alias2

```js
  /**
  * @desc: 设置别名2.
  * @return: 支持语法糖
  */
  set_alias2(aliasName)
```

### set_on

```js
  /**
  * @desc: 设置join条件.
  * @return: 支持语法糖
  */
  set_on(onSql)
```

### table1

```js
  /**
  * @desc: 当前操作的 table1对象. table2对象.
  */
  get table1;
  get table2;
```

### alias1

```js
  /**
  * @desc: 当前操作的 table1对象别名. table2对象别名.
  * @return: 返回的alias为: 'aliasName.'; 如果alias为空, 则返回 '';
  */
  get alias1;
  get alias2;
```


### join_inner

```js
  /**
  * @desc: join tableB后, 返回join对象. 后续在新的join上操作
  */
  join_inner(tableB)
```

### join_cross

```js
  /**
  * @desc: join tableB后, 返回join对象. 后续在新的join上操作
  */
  join_cross(tableB)
```

### join_left

```js
  /**
  * @desc: join tableB后, 返回join对象. 后续在新的join上操作
  */
  join_left(tableB)
```

### join_right

```js
  /**
  * @desc: join tableB后, 返回join对象. 后续在新的join上操作
  */
  join_right(tableB)
```

### join_full

```js
  /**
  * @desc: join tableB后, 返回join对象. 后续在新的join上操作
  */
  join_full(tableB)
```

### select

```js
  /**
  * @desc: select.
  *         sql的连接顺序为: SELECT cols FROM table where groupSql orderby pageInfo.
  *
  * @param where:
  *           查询条件,不会对此字符串验证. 使用 condition 对象进行构建.
  * @param opt: 查询选项. 可以包含以下键值.
  *         - cols:  需要查询出的字段名称数组; 例如: [col1, col2, ...]; 不指定则为查询全部.
  *         - groupSql:   group by子句, 不会对内容进行验证; 应包含group by关键字.
  *         - orderby:    orderby by子句, 例如: {key:true/false} true-means asc, false-means desc..
  *         - offset:     分页查询起始位置.
  *         - limit:      分页查询查询行数.
  * @return: Promise.
  * @resolve:
  *   ret - mod array.
  */
  select( where, opt = null )
```

### count

```js
  /**
  * @desc: count
  * @param: where
  * @return: Promise.
  * @resolve:
  *   ret - number.
  */
  count(where = null)
```
