Thinkjs ZH-CN 3.0
Thinkjs ZH-CN 3.0
0 Documentation
ThinkJS Node.js
3.0 ThinkJS koa 2.x koa middleware
async/await */yield
ThinkJS ES6
Node.js 6.x LTS
ThinkJS
thinkjs thinkjs -v
2.x
thinkjs new [project_name]
http://127.0.0.1:8360/ IP
2.x 3.x
http ctx
middleware
Master src/boostrap/master.js
Woker src/boostrap/worker.js
require
hook middleware
Controller
Model
think.model.base think.Model
ThinkJS
think.config think.logger
src/bootstrap/matser.js
src/
app/
workers fork Worker Worker appReady
think.app.on("appReady")
Worker fork
Worker
think.config think.logger
Extend src/config/extend.js
think.app.modules
src/config/crontab.js
src/bootstrap/worker.js
process onUncaughtException onUnhandledRejection
src/config.js
think.beforeStartServer
createServer
createServer(port, host, callback)
think.app.listen
appReady think.app.on("appReady")
think.app.server
meta ThinkJS
resource www/static/
middleware middleware
trace
payload
request.body
router Controller Action ctx.controller
ctx.action ctx.module
logic controller action logic
logic ctx
__before false
xxxAction false
xxxAction __call
__after false
false
controller controller action controller
logic
404
action this.body
Worker onUncaughtException onUnhandledRejection Worker
Master fork Worker
middleware
middleware
middleware middleware
next
function middlewareFunction(options){
return (ctx, next) => {
if(userLogin){ //这⾥里里判断如果⽤用户登录了了才执⾏行行后续的⾏行行为
return next();
}
}
}
false
__before(){
if(!userLogin) return false; //这⾥里里⽤用户未登录时返回了了 false,那么后⾯面的 xxxAction 不不再
执⾏行行
}
ThinkJS
src/config/
config.js
adapter.js adapter
router.js
middleware.js middlware
validator.js
extend.js
// src/config.js
module.exports = {
port: 1234,
redis: {
host: '192.168.1.2',
port: 2456,
password: ''
}
}
[name].[env].js config.development.js
config.production.js
config.js adapter.js
[ThinkJS]/lib/config.js
[ThinkJS]/lib/config.[env].js
[ThinkJS]/lib/adapter.js
[ThinkJS]/lib/adapter.[env].js
src/config/config.js
src/config/config.[env].js
src/config/adapter.js
src/config/adapter.[env].js
[env] key
think-loader https://github.com/thinkjs/think-loader/b
lob/master/loader/config.js
ctx ctx.config(key)
controller controller.config(key)
think.config(key)
think.config(key, value)
// src/bootstrap/worker.js
//HTTP 服务启动前执⾏行行
think.beforeStartServer(async () => {
const config = await think.model('config').select();
think.config('userConfig', config); //从数据库中将配置读取出来,然后设置
})
不不能
Context
ThinkJS Extend
https://github.com/thinkjs/thinkjs/blob/3.0/lib/extend/context.js
API
userAgent
ctx.userAgent userAgent
ctx.isGet GET
isPost
ctx.isPost POST
isCli
ctx.isCli CLI
referer(onlyHost)
referer
referer
isMethod(method)
method {String}
return {Boolean}
method
isAjax(method)
method {String}
return {Boolean}
isJsonp(callbackField)
jsonp
jsonp(data, callbackField)
data {Mixed}
callbackField {String} callback this.config('jsonpCallbackField')
return {Boolean} false
ctx.jsonp({name: 'test'});
//output
jsonp111({
name: 'test'
})
json(data)
data {Mixed}
return {Boolean} false
ctx.json({name: 'test'});
//output
{
name: 'test'
}
success(data, message)
data {Mixed}
message {String} errmsg
return {Boolean} false
{
errno: 0,
errmsg: '',
data: ...
}
errno errmsg errnoField errmsgField
errno {Number}
errmsg {String}
data {Mixed}
return {Boolean} false
{
errno: 1000,
errmsg: 'no permission',
data: ''
}
expires(time)
time {Number} 1s 1m
return {undefined}
Cache-Control Expires
ctx.expires('1h'); //缓存⼀一⼩小时
config(name, value, m)
name {Mixed}
value {Mixed}
m {String}
return {Mixed}
think.config
ctx.config('name'); //获取配置
ctx.config('name', value); //设置配置值
ctx.config('name', undefined, 'admin'); //获取 admin 模块下配置值,多模块项⽬目下⽣生效
param(name, value)
name {String}
value {Mixed}
return {Mixed}
post(name, value)
name {String}
value {Mixed}
return {Mixed}
POST
file(name, value)
name {String}
value {Mixed}
return {Mixed}
Cookie
controller(name, m)
Controller think.controller
service service
// 获取 src/service/github.js 模块
const github = ctx.service('github');
Middleware
Koa app.use
module.exports = [
{
handle: 'meta',
options: {
logRequest: isDev,
sendResponseTime: isDev,
},
},
{
handle: 'resource',
enable: isDev,
options: {
root: path.join(think.ROOT_PATH, 'www'),
publicPath: /^\/(static|favicon\.ico)/,
},
}
]
handle
middleware
middleware
middleware
}
}
enable
middleware middleware
{
handle: 'resouce',
enable: think.env === 'development' //这个 middleware 只在开发环境下⽣生效
}
options
middleware
module.exports = [
{
handle:
}
]
match
middleware
module.exports = [
{
handle: 'xxx-middleware',
match: '/resource' //请求的 URL 是 /resource 打头时才⽣生效这个 middleware
}
]
module.exports = [
{
handle: 'xxx-middleware',
match: ctx => { // match 为⼀一个函数,将 ctx 传递给这个函数,如果返回结果为 true,则启⽤用
该 middleware
return true;
}
}
]
middleware
middleware
module.exports = [
{
handle: 'meta',
options: {}
}
]
middleware
middleware src/middleware
src/middleware/csrf.js csrf
middleware
module.exports = [
{
handle: 'csrf',
options: {}
}
]
middleware
middleware
middleaware
middleware
DEBUG=koa:application node development.js
koa:application use ...
worker
Logic
Action
Action Action
Logic
Logic
Logic Controller
Action
module.exports = class extends think.Logic {
indexAction() {
this.allowMethods = 'post'; // 只允许 POST 请求类型
}
detailAction() {
this.allowMethods = 'get,post'; // 允许 GET、POST 请求类型
}
}
header
version
GET this.param('version') version
POST this.post('version') FILE
this.file('version') verison
POST URL
GET POST FILE
default:value
this.validate
}
}
false this.validateErrors
this.fail JSON
this.display Logic Controller Controller
JSON
this.validate this.rules
this.rules Action
JSON
children
children
array
split(',') [字段值]
// logic index.js
module.exports = class extends think.Logic {
indexAction() {
let rules = {
name1: {
eqValid: 'lucy',
method: 'GET'
}
}
let flag = this.validate(rules);
if(!flag) {
console.log(this.validateErrors); // name1 shoud eq lucy
}
}
}
}
// src/config/validator.js
module.exports = {
rules: {
/**
* @param {Mixed} value [相应字段的请求值]
* @param {Mixed} parsedValue [校验规则的参数值]
* @param {String} validName [校验规则的参数名称]
* @return {Boolean} [校验结果]
*/
eqValid(value, parsedValue, validName) {
console.log(value, parsedValue, validName); // 'jack', 'lucy', 'eqValid'
return value === parsedValue;
}
},
messages: {
eqValid: '{name} should eq {args}'
}
}
GET name1 name2
/index/?name1=tom&name2=lily
// logic index.js
module.exports = class extends think.Logic {
indexAction() {
let rules = {
name1: {
eqValid: 'name2',
method: 'GET'
}
}
let flag = this.validate(rules);
if(!flag) {
console.log(validateErrors); // name1 shoud eq name2
}
}
}
// src/config/validator.js
module.exports = {
rules: {
/**
* 需要下划线开头的同名⽅方法
* @param {Mixed} validValue [校验规则的参数值]
* @param {Mixed} query [校验规则method指定的参数来源下的参数]
* @param {String} validName [校验规则的参数名称]
* @return {Mixed} [解析之后的校验规则的参数值]
*/
_eqValid(validValue, query, validName){
console.log(validValue, query, validName); // 'name2', {name1: 'tom', name2:
'lily'}, 'eqValid'
let parsedValue = query[validValue];
return parsedValue;
},
/**
* @param {Mixed} value [相应字段的请求值]
* @param {Mixed} parsedValue [_eqValid⽅方法返回的解析之后的校验规则的参数值]
* @param {String} validName [校验规则的参数名称]
* @return {Boolean} [校验结果]
*/
eqValid(value, parsedValue, validName) {
console.log(value, parsedValue, validName); // 'tom', 'lily', 'eqValid'
return value === parsedValue;
}
},
messages: {
eqValid: '{name} should eq {args}'
}
}
{name} {args} {pargs} {name}
{args} {pargs}
{args} {pargs} JSON.stringify
Object: true 1
2 3 { }
3> 2> 1
required
name
requiredIf
requiredNotIf
requiredWith
requiredWithOut
requiredWithOutAll
contains
equals
different
before
alpha
alphaDash
alphaNumeric
alphaNumericDash
ascii
base64
byteLength
byteLength: options
creditCard: true
currency
date
date: true
decimal
divisibleBy
divisibleBy: number
fqdn
fqdn: true | options options
https://github.com/chriso/validator.js
float
fullWidth
fullWidth: true
halfWidth
halfWidth: true
hexColor
hexColor: true
hex
hex: true
ip
ip ip: true
ip4
ip6
isbn
isbn: true
isin
isin: true
iso8601
issn
issn: true
uuid
dataURI
md5
macAddress
variableWidth: true
in
in: [...]
notIn
notIn: [...]
int
length: options
lowercase
lowercase: true
uppercase
uppercase: true
mobile
multibyte
multibyte: true
url
order
field
image
image: true
startWith
startWith: string
endWith
, endWith: string
string
string: true
array
object
object: true
regexp
Controller
user.js Action
Controller
controller think.Controller
controller
base.js controller
//src/controller/user.js
http://127.0.0.1:8360/user/index
hello word!
__before
__before
__before Action
__after
}
__after(){
//indexAction 执⾏行行完成后执⾏行行,如果 indexAction 返回了了 false 则不不再执⾏行行
}
}
ctx
controller ctx controller this.ctx ctx
controller ctx
API
controller.ctx
ctx
controller.body
return {String}
controller.ip
return {String}
ip ctx.ip
controller.ips
return {Array}
ip ctx.ips
controller.method
return {String}
controller.isGet
return {Boolean}
GET
controller.isPost
return {Boolean}
POST
controller.isCli
return {Boolean}
controller.userAgent
userAgent
controller.isMethod(method)
method {String}
return {Boolean}
controller.isAjax(method)
method {String}
return {Boolean}
Ajax method
controller.isJsonp(callback)
jsonp
controller.get(name)
name {String}
GET
controller.post(name)
name {String}
POST
controller.param(name)
name {String}
POST GET
controller.file(name)
name {String}
{
fieldName: 'file', //表单字段名称
originalFilename: filename, //原始的⽂文件名
path: filepath, //⽂文件保存的临时路路径,使⽤用时需要将其移动到项⽬目⾥里里的⽬目录,否则请求结束时会被删
除
size: 1000 //⽂文件⼤大⼩小
}
{} ctx.file
controller.header(name, value)
header
time {Number}
Cache-Control Expires
ctx.expires
controller.referer(onlyHost)
referrer
controller.referrer(onlyHost)
controller.referer
cookie
controller.redirect(url)
controller.jsonp(data, callback)
data {Mixed}
callback {String} callback
jsonp callback
controller.json(data)
data {Mixed}
json
controller.status(status)
status {Number} 404
controller.success(data, message)
ctx.success
ctx.fail
View
Extend View
src/config/extend.js
view
View Adapter
src/config/adapter.js
exports.view = {
type: 'nunjucks',
common: {
viewPath: path.join(think.ROOT_PATH, 'view'), //模板⽂文件的根⽬目录
sep: '_', //Controller 与 Action 之间的连接符
extname: '.html' //⽂文件扩展名
},
nunjucks: {
handle: nunjucks
}
}
nunjucks
assign
render
Adapter
src/config/middleware.js
URL URL
http://www.thinkjs.org/zh-cn/doc/3.0/router.html pathname
/zh-cn/doc/3.0/router.html
URL
URL .html
ThinkJS pathname
{
prefix: [],
suffix: ['.html'],
// 其他配置...
}
prefix subffix
pathname pathname
/zh-cn/doc/3.0/router
src/config/router.js
module.exports = [
[/libs\/(.*)/i, '/libs/:1', 'get'],
[/fonts\/(.*)/i, '/fonts/:1', 'get,post'],
];
[
match, // url 匹配规则, 预先使⽤用 path-to-regexp 转换
path, // 对应的操作(action)的路路径
method, // 允许匹配的请求类型,多个请求类型之间逗号分隔,get|post|redirect|rest|cli
[options] // 额外参数,如 method=redirect时,指定跳转码 {statusCode: 301}
]
match path-to-regexp
module.exports = [
['/api_libs/(.*)/:id', '/libs/:1/', 'get'],
]
[模块]/控制器器/操作/... pathname
(action)
URL http:/www.thinkjs.org/api_libs/inbox/123
path /libs/inbox/ , {id: '123'} this.ctx pathname
libs controller inbox action inboxAction
this.ctx.param('id') id 123
ThinkJS
{
subdomainOffset: 2,
prefix: [],
suffix: ['.html'],
subdomain: {
'news,zm': 'news'
},
// 其他配置...
}
http://zm.news.so.com:8360/api_lib/inbox/123
pathname /news/api_lib/inbox/123
subdomain
subdomain: ['admin', 'user'] subdomain: {admin: 'admin', user: 'user'}
Adapter
Adapter
Adapter
Adapter src/config/adapter.js
exports.view = {
type: 'nunjucks', // 默认的模板引擎为 nunjucks
common: { //通⽤用配置
viewPath: path.join(think.ROOT_PATH, 'view'),
sep: '_',
extname: '.html'
},
nunjucks: { // nunjucks 的具体配置
handle: nunjucks
},
ejs: { // ejs 的具体配置
handle: ejs,
viewPath: path.join(think.ROOT_PATH, 'view/ejs/'),
}
}
exports.cache = {
...
}
type Adapter
common adapter
nunjucks,ejs Adapter common
handle
Adapter
Adapter Adapter
Adapter
exports.cache = {
type: 'file',
xcache: {
handle: 'xcache', //这⾥里里配置字符串串,项⽬目启动时会⾃自动查找 src/adapter/cache/xcache.js
⽂文件
...
}
}
Adapter
Adapter https://github.com/thinkjs/think-awesome#adapters
Extend
3.0
Extend think application context
request response controller logic
Extend
Extend src/config/extend.js
module.exports = [
view, //make application support view
fetch, // HTTP request client
model(think.app)
];
Extend
Extend
src/extend/
ctx isMobile
//src/extend/context.js
module.exports = {
isMobile: function(){
const userAgent = this.userAgent.toLowerCase();
const mList = ['iphone', 'android'];
return mList.some(item => userAgent.indexOf(item) > -1);
}
}
ctx.isMobile()
getter
//src/extend/context.js
module.exports = {
get isMobile: function(){
const userAgent = this.userAgent.toLowerCase();
const mList = ['iphone', 'android'];
return mList.some(item => userAgent.indexOf(item) > -1);
}
}
//src/extend/controller.js
module.exports = {
get isMobile: function(){
return this.ctx.isMobile;
}
}
npm
// 模块⼊入⼝口⽂文件
module.exports = {
controller: controllerExtend,
context: contextExtend
}
Extend app
// src/config/extend.js
const model = require('think-model');
module.exports = [
model(think.app) //将 think.app 传递给 model 扩展
];
app
Extend
Extend https://github.com/thinkjs/think-awesome#extends
Extend Pull Request
think
think
think.app
app
think.app.modules
think.app.controllers controller
think.app.logics logic
think.app.models
think.app.services service
think.app.routers
think.app.validators
appReady
think.app.on('appReady', () => {
console.log(think.app.controllers)
})
API
think.env
think.app.env development.js
think.isCli
think.version
ThinkJS
think.Controller
think.Logic
logic
think.controller(name, ctx, m)
name {String}
ctx {Object} Koa ctx
m {String}
think.beforeStartServer(fn)
fn {Function}
fn Promise
npm start node production.js
bootstrap
src/boostrap/
Master src/bootstrap/master.js
Worker src/bootstrap/worker.js
Master Worker
master.js worker.js required
// src/bootstrap/common.js
global.commonFn = function(){
// src/bootstrap/master.js
require('./common.js')
// src/boostrap/worker.js
require('./common.js')
node http
think.beforeStartServer
think.beforeStartServer(async () => {
const data = await getDataFromApi();
think.config(key, data);
})
think.beforeStartServer
Promise
startServerTimeout 3
//src/config/config.js
module.exports = {
startServerTimeout: 5000 // 将超时时间改为 5s
}
http
//src/config/config.js
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
module.exports = {
// app 为 Koa app 对象
createServer: function(app, ...args){
https.createServer(options, app.callback()).listen(...args);
}
}
think.app.server
appReady
Service
Cookie
src/config/config.js cookie
module.exports = {
cookie: {
domain: '',
path: '/',
httponly: false, // 是否 http only
secure: false,
timeout: 0 // 有效时间,0 表示载浏览器器进程内有效,单位为秒。
}
}
cookie
this.ctx.cookie('theme');
cookie
this.ctx.cookie('theme', 'default');
cookie
cookie
this.ctx.cookie('theme', null);
Session
Session
cookie Cookie
mysql Mysql
file
redis Redis
Mysql session
redis Session
Session
exports.session = {
type: 'cookie',
common: {
cookie: {
name: 'test',
keys: ['werwer', 'werwer'],
signed: true
}
},
cookie: {
handle: cookieSession,
cookie: {
maxAge: 1009990 * 1000,
keys: ['welefen', 'suredy'],
encrypt: true
}
},
file: {
handle: fileSession,
sessionPath: path.join(think.ROOT_PATH, 'runtime/session')
}
}
Cookie handle
* maxAge session cookie
* keys encrypt true keys
* encrypt true session
file
* sessionPath session session
'/path_of_your_project/runtime/session'
session
Session
this.session() session
this.session(name) name session
Session
Session
this.session(null) session
ctx session
Logger
ThinkJS think-logger3
log4js
think.logger.debug('debug message');
think.logger.info('info message');
think.logger.warn('warning');
think.logger.error(new Error('error'));
Console , File , DateFile Console
src/config/adapter/logger.js
```javascript
const path = require('path');
const {File} = require('think-logger3');
module.exports = {
type: 'file',
file: {
handle: File,
backups: 10,
absolute: true,
maxLogSize: 50 * 1024, //50M
filename: path.join(think.ROOT_PATH, 'logs/xx.log')
}
}
src/config/adater.js
exports.logger = require('./adapter/logger.js')
logs/xx.log maxLogSize
logs/xx.log.1 backups
filename
maxLogSize KB
backups 5
absolute filename filename absolute
true
layouts
src/config/adapter/logger.js
```javascript
const path = require('path');
const {DateFile} = require('think-logger3');
module.exports = {
type: 'dateFile',
dateFile: {
handle: DateFile,
level: 'ALL',
absolute: true,
pattern: '-yyyy-MM-dd',
alwaysIncludePattern: false,
filename: path.join(think.ROOT_PATH, 'logs/xx.log')
}
}
src/config/adater.js
exports.logger = require('./adapter/logger.js')
logs/xx.log xx.log-2017-07-01
logs/xx.log
level
filename
absolute filename filename absolute
true
pattern
yyyy - yy
MM -
dd - 2
hh - 24
mm -
ss -
SSS -
O -
alwaysIncludePattern alwaysIncludePattern true
xx.log-2017-07-01 xx.log-2017-07-02
layouts
Level
ALL
ERROR
WARN
INFO
DEBUG
Layout
module.exports = {
type: 'file',
file: {
handle: File,
backups: 10,
absolute: true,
maxLogSize: 50 * 1024, //50M
filename: path.join(think.ROOT_PATH, 'logs/xx.log'),
layouts: {
type: 'coloured',
pattern: '%[[%d] [%p]%] - %m',
}
}
}
layouts
type
basic
coloured
messagePassThrough
dummy
pattern
Adding your own layouts
pattern
%r - .toLocaleTimeString() 下午5:13:04
%p -
%h -
%m -
%d - ISO8601 ISO8601 , ISO8601_WITH_TZ_OFFSET ,
ABSOUTE , DATE %d{DATE}
%d{yyyy/MM/dd-hh.mm.ss}
%% - %
%n -
%z - process.pid ID
%[ -
%] -
handle
handle
handle
module.exports = class {
/**
* @param {Object} config {} 配置传⼊入的参数
* @param {Boolean} clusterMode true 是否是多进程模式
*/
constructor(config, clusterMode) {
debug() {
info() {
warn() {
error() {
}
}
node cluster
think-cluster
workers 0 cpu
//src/config/config.js
module.exports = {
workers: 0 // 可以根据实际情况修改,0 为 cpu 的个数
}
Worker Worker
Master
think.messenger
think.messenger.broadcast Worker
//监听事件
think.messenger.on('test', data => {
//所有进程都会捕获到该事件,包含当前的进程
});
if(xxx){
//发送⼴广播事件
think.messenger.broadcast('test', data)
}
Master
src/bootstrap/master.js Worker src/bootstrap/worker.js
// src/bootstrap/master.js
process.on('message', (worker, message) => {
// 接收到特定的消息进程处理理
if(message && message.act === 'xxx'){
}
})
// src/bootstrap/worker.js
process.send({act: 'xxxx', ...args}); //发送数据到 Master 进程
Babel
Babel
Babel
Babel development.js
instance.run();
Babel development.js
instance.run();
-w Babel development.js
RESTful API
REST Controller
-r REST Controller
thinkjs controller user -r
create : src/controller/rest.js
create : src/controller/user.js
create : src/logic/user.js
REST Controller
src/config/router.js
module.exports = [
[/\/user(?:\/(\d+))?/, 'user?id=:1', 'rest']
]
/\/user(?:\/(\d+))?/ URL
user?id=:1 :1 (\d+)
rest REST API
Controller Logic
src/logic/user.js Action Controller
Logic
REST API
REST API
module.exports = [
[/\/post\/(\d+)\/comments(?:\/(\d+))?/, 'comment?postId=:1&id=:2', 'rest']
]
Action this.get("postId") id
REST API
REST API
module.exports = [
[/\/v1\/user(?:\/(\d+))?/, 'v1/user?id=:1', 'rest'], //v1 版本
[/\/v2\/user(?:\/(\d+))?/, 'v2/user?id=:1', 'rest'] //v2 版本
]
module.exports = [
[/\/user(?:\/(\w+))?/, 'user?id=:1', 'rest']
]
MySQL
src/model/user.js
model.pk
key id
model.schema
{
id: {
name: 'id',
type: 'int', //类型
required: true, //是否必填
primary: true, //是否是主键
unique: true, //是否唯⼀一
auto_increment: true //是否⾃自增
}
}
default
update: true
readonly
注 readonly update
model
think.model
let getModelInstance = function(){
let model = think.model('user', think.config('model'));
}
think.model
jQuery
this
where ,
table ,
alias ,
data ,
field ,
order ,
limit ,
page , sql limit
group , group
having , having
join , join
union , union
distinct , distinct
cache
think_ user
think_user user_group think_user_group
tablePrefix
tableName
id Primary Key id
//src/config/adapter/model.js
module.exports = {
type: 'mysql',
mysql: {
host: '127.0.0.1',
port: '',
database: 'test1',
user: 'root1',
password: 'root1',
prefix: '',
encoding: 'utf8'
},
mysql2: {
type: 'mysql', //这⾥里里需要将 type 重新设置为 mysql
host: '127.0.0.1',
port: '',
database: 'test2',
user: 'root2',
password: 'root2',
prefix: '',
encoding: 'utf8'
}
}
ThinkJS
parser src/config/adapter/model.js
//读配置
const MYSQL_READ = {
host: '10.0.10.1',
}
//写配置
const MYSQL_WRITE = {
host: '10.0.10.2'
}
module.exports = {
host: '127.0.0.1',
adapter: {
mysql: {
parser(options) { //mysql 的配置解析⽅方法
let sql = options.sql; //接下来要执⾏行行的 SQL 语句句
if(sql.indexOf('SELECT') === 0){ //SELECT 查询
return MYSQL_READ;
}
return MYSQL_WRITE;
}
}
}
}
CRUD
add id
mysql CURRENT_TIMESTAMP
exp
export default class extends think.controller.base {
async addAction(){
let model = this.model('user');
let insertId = await model.add({
name: 'test',
time: ['exp', 'CURRENT_TIMESTAMP()']
});
}
}
addMany
thenAdd
thenAdd
update
where
1=1 where
exp
increment
increment
decrement
decrement
find
{} think.isEmpty
select
[] think.isEmpty
countSelect
{
numsPerPage: 10, //每⻚页显示的条数
currentPage: 1, //当前⻚页
count: 100, //总条数
totalPages: 10, //总⻚页数
data: [{ //当前⻚页下的数据列列表
name: 'thinkjs',
email: '[email protected]'
}, ...]
}
true
false countSelect(true) countSelect(false)
countSelect(1000)
1000
count
count
sum
sum
max
max
min
min
key get_list
cache src/common/config/db.js
module.exports = {
cache: {
on: true,
type: '',
timeout: 3600
}
}
on cache
type Adapter -> Cache
timeout
delete
SQLite
startTrans
commit
rollback
transaction
transaction
db
indexAction(){
let model = this.model('user');
await model.transaction(async () => {
//通过 db ⽅方法将 user 模型的数据库连接传递给 article 模型
let model2 = this.model('article').db(model.db());
// do something
})
}
ThinkJS
4
think.Model.Relation.HAS_ONE
think.Model.Relation.BELONG_TO
think.Model.Relation.HAS_MANY
think.Model.Relation.MANY_TO_MANY
src/model/post.js
relation
ES7 relation
//直接定义 relation 属性
relation = {
cate: {},
comment: {}
};
}
module.exports = class extends think.Model.Relation {
constructor(...args){
super(...args);
this.relation = {
cate: {
type: think.Model.Relation.MANY_TO_MANY, //relation type
model: '', //model name
name: 'profile', //data name
key: 'id',
fKey: 'user_id', //forign key
field: 'id,name',
where: 'name=xx',
order: '',
limit: '',
rModel: '',
rfKey: ''
},
};
}
}
type
model key cate
name key cate
key key
fKey key
field field fKey
where where
order order
limit limit
page page
rModel
rfKey key
HAS_ONE
[
{
id: 1,
name: '111',
info: { //关联表⾥里里的数据信息
user_id: 1,
desc: 'info'
}
}, ...]
BELONG_TO
HAS_ONE
[
{
id: 1,
user_id: 1,
desc: 'info',
user: {
name: 'thinkjs'
}
}, ...
]
HAS_MANY
this.relation = {
comment: {
type: think.Model.Relation.HAS_MANY
}
};
}
}
[{
id: 1,
title: 'first post',
content: 'content',
comment: [{
id: 1,
post_id: 1,
name: 'welefen',
content: 'first comment'
}, ...]
}, ...]
page
this.relation = {
comment: {
type: think.Model.Relation.HAS_MANY
}
};
}
getList(page){
return this.setRelation('comment', {page: page}).select();
}
}
setRelation
MANY_TO_MANY
post cate
rModel post_cate rfKey cate_id
this.relation = {
cate: {
type: think.Model.Relation.MANY_TO_MANY,
rModel: 'post_cate',
rfKey: 'cate_id'
}
};
}
}
[{
id: 1,
title: 'first post',
cate: [{
id: 1,
name: 'cate1',
post_id: 1
}, ...]
}, ...]
2 HAS_ONE BELONG_TO
relation
setRelation
setRelation(false)
setRelation('comment') comment
setRelation(true)
field
field
module.exports = class extends think.Model.Relation {
constructor(...args){
super(...args);
this.relation = {
user: {
type: think.Model.Relation.BELONG_TO,
field: 'id,name,email' //必须要包含关联字段 id
}
};
}
}
field
model
where
where
where
model
page
model
limit
limit
limit
model
order
order
order
model
id int user_id int
Mysql
Mysql
src/config/adapter/model.js
module.exports = {
common: {
connectionLimit: 10 //建⽴立 10 个连接
}
}
socketPath
module.exports = {
common: {
socketPath: '/tmp/mysql.socket'
}
}
SSL options
SSL
const fs = require('fs');
module.exports = {
common: {
ssl: {
ca: fs.readFileSync(__dirname + '/mysql-ca.crt')
}
}
}
emoji
module.exports = {
common: {
encoding: 'utf8mb4'
}
}
model
think.Model
}
}
model.pk
id
model.name
for/bar/app/home/model/user.js user
model.tablePrefix
think_
model.tableName
model.schema
model.indexes
model.config
model._db
model._data
model._options
model.model(name, options, module)
name {String}
options {Object}
module {String}
return {Object}
model.getTablePrefix()
return {string}
model.getConfigKey()
return {String}
key db
model.db()
return {Object}
db
model.getModelName()
return {String}
model.getTableName()
return {String}
model.cache(key, timeout)
key
key
offset {Number}
length {Number}
return {this}
model.page(page, listRows)
page {Number} 1
listRows {Number}
return {this}
limit
model.where(where)
注
1. mongo model mongo where model.mongo where
2. where Logic
null
EXP
ThinkJS
EXP
LIKE
IN
BETWEEN
model.field(field)
SQL
model.table(table, hasPrefix)
table {String}
hasPrefix {Boolean} table
return {this}
SQL
SQL
model.union(union, all)
SQL
module.exports = class extends think.Model {
getList(){
//SELECT * FROM `think_user` UNION (SELECT * FROM think_pic2)
return this.union('SELECT * FROM think_pic2').select();
}
}
model.join(join)
JOIN
ON
model.order(order)
model.alias(tableAlias)
tableAlias {String}
return {this}
model.having(having)
having
model.group(group)
group {String}
return {this}
model.distinct(distinct)
distinct {String}
return {this}
model.explain(explain)
model.optionsFilter(options)
model.dataFilter(data)
data {Object}
model.afterAdd(data)
data {Object}
model.afterDelete(data)
model.beforeUpdate(data)
data {Object}
model.afterUpdate(data)
data {Object}
model.afterFind(data)
data {Object}
return {Object | Promise}
find
model.afterSelect(data)
data [Array]
return {Array | Promise}
select
model.data(data)
data {Object}
model.options(options)
options {Object}
model.close()
model.getSchema(table)
table {String}
return {Promise}
model.getTableFields(table)
已废弃 model.getSchema
model.getLastSql()
return {String}
SQL
model.buildSql()
return {Promise}
SQL
model.parseOptions(oriOpts, extraOptions)
oriOpts {Object}
extraOptions {Object}
return {Promise}
model.getPk()
return {Promise}
pk Promise
model.parseType(field, value)
field {String}
value {Mixed}
return {Mixed}
value
model.parseData(data)
data {Object}
return {Object}
parseType
data {Object}
options {Object}
replace {Boolean}
return {Promise} ID
model.thenAdd(data, where)
data {Object}
where {Object} where
return {Promise}
where
dataList {Array}
options {Object}
replace {Boolean}
return {Promise} ID
model.delete(options)
options {Object}
return {Promise}
id 7
model.delete({
where: {id: 7}
});
model.update(data, options)
data {Object}
options {Object}
return {Promise}
model.thenUpdate(data, where)
data {Object}
where {Object} where
return {Promise}
where
updateMany(dataList, options)
dataList {Array}
options {Object}
return {Promise}
dataList
model.increment(field, step)
field {String}
step {Number} 1
return {Promise}
model.decrement(field, step)
field {String}
step {Number} 1
return {Promise}
model.find(options)
options {Object}
return {Promise}
{}
model.select(options)
options {Object}
return {Promise}
[]
model.countSelect(options, pageFlag)
options {Object}
pageFlag {Boolean} true false
return {Promise}
page
{
numsPerPage: 10, //每⻚页显示的条数
currentPage: 1, //当前⻚页
count: 100, //总条数
totalPages: 10, //总⻚页数
data: [{ //当前⻚页下的数据列列表
name: "thinkjs",
email: "[email protected]"
}, ...]
}
model.getField(field, one)
field {String}
one {Boolean | Number}
return {Promise}
model.count(field)
field {String}
return {Promise}
model.sum(field)
field {String}
return {Promise}
model.min(field)
field {String}
return {Promise}
model.max(field)
field {String}
return {Promise}
model.avg(field)
field {String}
return {Promise}
model.query(...args)
return {Promise}
SQL
model.execute(...args)
return {Promise}
SQL
model.parseSql(sql, ...args)
sql {String} SQL
return {String}
model.startTrans()
return {Promise}
model.commit()
return {Promise}
model.rollback()
return {Promise}
model.transaction(fn)
fn {Function}
return {Promise}
Promise
--mode=multi
src/common
src/home
src/xxx