2019-02-02 16:18:25 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-04-20 23:23:42 +08:00
|
|
|
|
//
|
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-04-20 23:23:42 +08:00
|
|
|
|
|
|
|
|
|
|
package gdb
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2019-06-19 09:06:52 +08:00
|
|
|
|
"database/sql"
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"reflect"
|
2019-09-03 17:18:16 +08:00
|
|
|
|
"strings"
|
2019-10-15 17:44:47 +08:00
|
|
|
|
"time"
|
2019-07-02 23:14:40 +08:00
|
|
|
|
|
2019-09-29 14:27:09 +08:00
|
|
|
|
"github.com/gogf/gf/container/gset"
|
|
|
|
|
|
"github.com/gogf/gf/text/gstr"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gogf/gf/container/gmap"
|
|
|
|
|
|
|
2019-07-29 21:01:19 +08:00
|
|
|
|
"github.com/gogf/gf/util/gconv"
|
2018-04-20 23:23:42 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 数据库链式操作模型对象
|
|
|
|
|
|
type Model struct {
|
2019-10-21 19:13:25 +08:00
|
|
|
|
db DB // 数据库操作对象
|
|
|
|
|
|
tx *TX // 数据库事务对象
|
|
|
|
|
|
linkType int // 连接对象类型(用于主从集群时开发者自定义操作对象)
|
|
|
|
|
|
tablesInit string // 初始化Model时的表名称(可以是多个)
|
|
|
|
|
|
tables string // 数据库操作表
|
|
|
|
|
|
fields string // 操作字段
|
|
|
|
|
|
where string // 操作条件
|
|
|
|
|
|
whereArgs []interface{} // 操作条件参数
|
|
|
|
|
|
whereHolder []*whereHolder // 操作条件预处理
|
|
|
|
|
|
groupBy string // 分组语句
|
|
|
|
|
|
orderBy string // 排序语句
|
|
|
|
|
|
start int // 分页开始
|
|
|
|
|
|
limit int // 分页条数
|
|
|
|
|
|
option int // 操作选项
|
|
|
|
|
|
offset int // 查询偏移量(OFFSET语法)
|
|
|
|
|
|
data interface{} // 操作数据(注意仅支持Map/List/string类型)
|
|
|
|
|
|
batch int // 批量操作条数
|
|
|
|
|
|
filter bool // 是否按照表字段过滤data参数
|
|
|
|
|
|
cacheEnabled bool // 当前SQL操作是否开启查询缓存功能
|
|
|
|
|
|
cacheExpire time.Duration // 查询缓存时间
|
|
|
|
|
|
cacheName string // 查询缓存名称
|
|
|
|
|
|
safe bool // 当前模型是否安全模式(默认非安全表示链式操作直接修改当前模型属性;否则每一次链式操作都是返回新的模型对象)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// whereHolder is the holder for where condition preparing.
|
|
|
|
|
|
type whereHolder struct {
|
|
|
|
|
|
operator int // Operator for this holder.
|
|
|
|
|
|
where interface{} // Where parameter.
|
|
|
|
|
|
args []interface{} // Arguments for where parameter.
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-08-08 17:43:21 +08:00
|
|
|
|
const (
|
2019-10-21 19:13:25 +08:00
|
|
|
|
gLINK_TYPE_MASTER = 1
|
|
|
|
|
|
gLINK_TYPE_SLAVE = 2
|
|
|
|
|
|
gWHERE_HOLDER_WHERE = 1
|
|
|
|
|
|
gWHERE_HOLDER_AND = 2
|
|
|
|
|
|
gWHERE_HOLDER_OR = 3
|
|
|
|
|
|
OPTION_OMITEMPTY = 1 << iota
|
2019-09-26 20:01:48 +08:00
|
|
|
|
OPTION_ALLOWEMPTY
|
2019-08-08 17:43:21 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2018-04-20 23:23:42 +08:00
|
|
|
|
// 链式操作,数据表字段,可支持多个表,以半角逗号连接
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (bs *dbBase) Table(tables string) *Model {
|
|
|
|
|
|
return &Model{
|
|
|
|
|
|
db: bs.db,
|
|
|
|
|
|
tablesInit: tables,
|
2019-07-22 23:48:39 +08:00
|
|
|
|
tables: bs.db.quoteWord(tables),
|
2019-06-19 09:06:52 +08:00
|
|
|
|
fields: "*",
|
2019-07-02 23:14:40 +08:00
|
|
|
|
start: -1,
|
2019-07-09 12:50:38 +08:00
|
|
|
|
offset: -1,
|
2019-06-19 09:06:52 +08:00
|
|
|
|
safe: false,
|
2019-09-29 14:27:09 +08:00
|
|
|
|
option: OPTION_ALLOWEMPTY,
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,数据表字段,可支持多个表,以半角逗号连接
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (bs *dbBase) From(tables string) *Model {
|
2018-12-15 15:50:39 +08:00
|
|
|
|
return bs.db.Table(tables)
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (tx *TX) Table(tables string) *Model {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
return &Model{
|
2019-06-19 09:06:52 +08:00
|
|
|
|
db: tx.db,
|
|
|
|
|
|
tx: tx,
|
|
|
|
|
|
tablesInit: tables,
|
2019-07-22 23:48:39 +08:00
|
|
|
|
tables: tx.db.quoteWord(tables),
|
2019-07-15 19:54:13 +08:00
|
|
|
|
fields: "*",
|
|
|
|
|
|
start: -1,
|
|
|
|
|
|
offset: -1,
|
2019-06-19 09:06:52 +08:00
|
|
|
|
safe: false,
|
2019-09-29 14:27:09 +08:00
|
|
|
|
option: OPTION_ALLOWEMPTY,
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (tx *TX) From(tables string) *Model {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
return tx.Table(tables)
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-12-18 10:10:14 +08:00
|
|
|
|
// 克隆一个当前对象
|
|
|
|
|
|
func (md *Model) Clone() *Model {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
newModel := (*Model)(nil)
|
2018-12-18 10:10:14 +08:00
|
|
|
|
if md.tx != nil {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
newModel = md.tx.Table(md.tablesInit)
|
2018-12-18 10:10:14 +08:00
|
|
|
|
} else {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
newModel = md.db.Table(md.tablesInit)
|
2018-12-18 10:10:14 +08:00
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
*newModel = *md
|
|
|
|
|
|
return newModel
|
2018-12-14 10:09:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-08-08 17:43:21 +08:00
|
|
|
|
// 设置本次链式操作在主节点上
|
|
|
|
|
|
func (md *Model) Master() *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.linkType = gLINK_TYPE_MASTER
|
|
|
|
|
|
return model
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置本次链式操作在从节点上
|
|
|
|
|
|
func (md *Model) Slave() *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.linkType = gLINK_TYPE_SLAVE
|
|
|
|
|
|
return model
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-03-11 16:14:55 +08:00
|
|
|
|
// 标识当前对象运行安全模式(可被修改)。
|
2019-03-07 23:53:56 +08:00
|
|
|
|
// 1. 默认情况下,模型对象的对象属性无法被修改,
|
|
|
|
|
|
// 每一次链式操作都是克隆一个新的模型对象,这样所有的操作都不会污染模型对象。
|
|
|
|
|
|
// 但是链式操作如果需要分开执行,那么需要将新的克隆对象赋值给旧的模型对象继续操作。
|
|
|
|
|
|
// 2. 当标识模型对象为可修改,那么在当前模型对象的所有链式操作均会影响下一次的链式操作,
|
|
|
|
|
|
// 即使是链式操作分开执行。
|
|
|
|
|
|
// 3. 大部分ORM框架默认模型对象是可修改的,但是GF框架的ORM提供给开发者更灵活,更安全的链式操作选项。
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) Safe(safe ...bool) *Model {
|
|
|
|
|
|
if len(safe) > 0 {
|
|
|
|
|
|
md.safe = safe[0]
|
|
|
|
|
|
} else {
|
|
|
|
|
|
md.safe = true
|
|
|
|
|
|
}
|
|
|
|
|
|
return md
|
2019-03-07 23:53:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 返回操作的模型对象,可能是当前对象,也可能是新的克隆对象,根据alterable决定。
|
|
|
|
|
|
func (md *Model) getModel() *Model {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if !md.safe {
|
|
|
|
|
|
return md
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return md.Clone()
|
|
|
|
|
|
}
|
2019-03-07 23:53:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-20 23:23:42 +08:00
|
|
|
|
// 链式操作,左联表
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) LeftJoin(joinTable string, on string) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", joinTable, on)
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,右联表
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) RightJoin(joinTable string, on string) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.tables += fmt.Sprintf(" RIGHT JOIN %s ON (%s)", joinTable, on)
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,内联表
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) InnerJoin(joinTable string, on string) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.tables += fmt.Sprintf(" INNER JOIN %s ON (%s)", joinTable, on)
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,查询字段
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) Fields(fields string) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.fields = fields
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-29 14:27:09 +08:00
|
|
|
|
// 链式操作,选项设置
|
|
|
|
|
|
func (md *Model) Option(option int) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.option = option
|
|
|
|
|
|
return model
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-21 19:13:25 +08:00
|
|
|
|
// 链式操作,设置 OPTION_OMITEMPTY 常用选项
|
|
|
|
|
|
func (md *Model) OptionOmitEmpty() *Model {
|
|
|
|
|
|
return md.Option(OPTION_OMITEMPTY)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-12-16 22:22:07 +08:00
|
|
|
|
// 链式操作,过滤字段
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) Filter() *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.filter = true
|
|
|
|
|
|
return model
|
2018-12-16 22:22:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-21 19:13:25 +08:00
|
|
|
|
// 链式操作,condition,支持string/map/gmap/struct/*struct.
|
2019-03-11 16:14:55 +08:00
|
|
|
|
// 注意,多个Where调用时,会自动转换为And条件调用。
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) Where(where interface{}, args ...interface{}) *Model {
|
|
|
|
|
|
model := md.getModel()
|
2019-10-21 19:13:25 +08:00
|
|
|
|
if model.whereHolder == nil {
|
|
|
|
|
|
model.whereHolder = make([]*whereHolder, 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
model.whereHolder = append(model.whereHolder, &whereHolder{
|
|
|
|
|
|
operator: gWHERE_HOLDER_WHERE,
|
|
|
|
|
|
where: where,
|
|
|
|
|
|
args: args,
|
|
|
|
|
|
})
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,添加AND条件到Where中
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) And(where interface{}, args ...interface{}) *Model {
|
|
|
|
|
|
model := md.getModel()
|
2019-10-21 19:13:25 +08:00
|
|
|
|
if model.whereHolder == nil {
|
|
|
|
|
|
model.whereHolder = make([]*whereHolder, 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
model.whereHolder = append(model.whereHolder, &whereHolder{
|
|
|
|
|
|
operator: gWHERE_HOLDER_AND,
|
|
|
|
|
|
where: where,
|
|
|
|
|
|
args: args,
|
|
|
|
|
|
})
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,添加OR条件到Where中
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) Or(where interface{}, args ...interface{}) *Model {
|
|
|
|
|
|
model := md.getModel()
|
2019-10-21 19:13:25 +08:00
|
|
|
|
if model.whereHolder == nil {
|
|
|
|
|
|
model.whereHolder = make([]*whereHolder, 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
model.whereHolder = append(model.whereHolder, &whereHolder{
|
|
|
|
|
|
operator: gWHERE_HOLDER_OR,
|
|
|
|
|
|
where: where,
|
|
|
|
|
|
args: args,
|
|
|
|
|
|
})
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,group by
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) GroupBy(groupBy string) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.groupBy = groupBy
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,order by
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) OrderBy(orderBy string) *Model {
|
|
|
|
|
|
model := md.getModel()
|
2019-09-03 17:18:16 +08:00
|
|
|
|
array := strings.Split(orderBy, " ")
|
|
|
|
|
|
array[0] = md.db.quoteWord(array[0])
|
|
|
|
|
|
model.orderBy = strings.Join(array, " ")
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-02 23:14:40 +08:00
|
|
|
|
// 链式操作,limit。
|
|
|
|
|
|
//
|
|
|
|
|
|
// 如果给定一个参数,那么生成的SQL为:LIMIT limit[0]
|
|
|
|
|
|
//
|
|
|
|
|
|
// 如果给定两个参数,那么生成的SQL为:LIMIT limit[0], limit[1]
|
|
|
|
|
|
func (md *Model) Limit(limit ...int) *Model {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
model := md.getModel()
|
2019-07-02 23:14:40 +08:00
|
|
|
|
switch len(limit) {
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
model.limit = limit[0]
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
model.start = limit[0]
|
|
|
|
|
|
model.limit = limit[1]
|
|
|
|
|
|
}
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-09 12:50:38 +08:00
|
|
|
|
// 链式操作,OFFSET语法(部分数据库支持)。
|
|
|
|
|
|
// 注意:可以使用Limit方法调用替换该方法特性,底层不同数据库将会自动替换LIMIT语法为OFFSET语法。
|
|
|
|
|
|
func (md *Model) Offset(offset int) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.offset = offset
|
|
|
|
|
|
return model
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-03-11 16:14:55 +08:00
|
|
|
|
// 链式操作,翻页,注意分页页码从1开始,而Limit方法从0开始。
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func (md *Model) ForPage(page, limit int) *Model {
|
|
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.start = (page - 1) * limit
|
|
|
|
|
|
model.limit = limit
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置批处理的大小
|
|
|
|
|
|
func (md *Model) Batch(batch int) *Model {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
model := md.getModel()
|
|
|
|
|
|
model.batch = batch
|
|
|
|
|
|
return model
|
2018-12-22 21:03:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询缓存/清除缓存操作,需要注意的是,事务查询不支持缓存。
|
2019-10-15 17:44:47 +08:00
|
|
|
|
// 1. 当 expire < 0时表示清除缓存,expire=0 时表示不过期, expire > 0时表示过期时间。
|
|
|
|
|
|
// 2. expire参数类型为interface{},这是一个兼容旧版本的方式,该参数支持 int/time.Duration 类型,当传递类型为int时,表示缓存多少秒。
|
|
|
|
|
|
// 3. name表示自定义的缓存名称(注意不要出现重复),便于业务层精准定位缓存项(如果业务层需要手动清理时,必须指定缓存名称),
|
|
|
|
|
|
// 例如:查询缓存时设置名称,在特定的业务逻辑中清理缓存时可以给定缓存名称进行精准清理。
|
|
|
|
|
|
func (md *Model) Cache(expire interface{}, name ...string) *Model {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
model := md.getModel()
|
2019-10-15 17:44:47 +08:00
|
|
|
|
if d, ok := expire.(time.Duration); ok {
|
|
|
|
|
|
model.cacheExpire = d
|
|
|
|
|
|
} else {
|
|
|
|
|
|
model.cacheExpire = gconv.Duration(expire) * time.Second
|
|
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if len(name) > 0 {
|
|
|
|
|
|
model.cacheName = name[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
// 查询缓存特性不支持事务操作
|
|
|
|
|
|
if model.tx == nil {
|
|
|
|
|
|
model.cacheEnabled = true
|
|
|
|
|
|
}
|
|
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-02-27 12:38:12 +08:00
|
|
|
|
// 链式操作,操作数据项,参数data类型支持 string/map/slice/struct/*struct ,
|
|
|
|
|
|
// 也可以是:key,value,key,value,...。
|
|
|
|
|
|
func (md *Model) Data(data ...interface{}) *Model {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
model := md.getModel()
|
2018-08-15 18:14:21 +08:00
|
|
|
|
if len(data) > 1 {
|
|
|
|
|
|
m := make(map[string]interface{})
|
|
|
|
|
|
for i := 0; i < len(data); i += 2 {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
m[gconv.String(data[i])] = data[i+1]
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
model.data = m
|
2018-08-15 18:14:21 +08:00
|
|
|
|
} else {
|
2019-03-17 22:26:41 +08:00
|
|
|
|
switch params := data[0].(type) {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case Result:
|
2019-10-01 16:03:18 +08:00
|
|
|
|
model.data = params.List()
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case Record:
|
2019-10-01 16:03:18 +08:00
|
|
|
|
model.data = params.Map()
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case List:
|
|
|
|
|
|
model.data = params
|
|
|
|
|
|
case Map:
|
|
|
|
|
|
model.data = params
|
|
|
|
|
|
default:
|
|
|
|
|
|
rv := reflect.ValueOf(params)
|
|
|
|
|
|
kind := rv.Kind()
|
|
|
|
|
|
if kind == reflect.Ptr {
|
|
|
|
|
|
rv = rv.Elem()
|
|
|
|
|
|
kind = rv.Kind()
|
|
|
|
|
|
}
|
|
|
|
|
|
switch kind {
|
2019-09-29 14:27:09 +08:00
|
|
|
|
case reflect.Slice, reflect.Array:
|
2019-06-19 09:06:52 +08:00
|
|
|
|
list := make(List, rv.Len())
|
|
|
|
|
|
for i := 0; i < rv.Len(); i++ {
|
2019-10-21 19:13:25 +08:00
|
|
|
|
list[i] = varToMapDeep(rv.Index(i).Interface())
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
model.data = list
|
2019-09-29 14:27:09 +08:00
|
|
|
|
case reflect.Map, reflect.Struct:
|
2019-10-21 19:13:25 +08:00
|
|
|
|
model.data = varToMapDeep(data[0])
|
2018-12-16 22:22:07 +08:00
|
|
|
|
default:
|
2019-06-19 09:06:52 +08:00
|
|
|
|
model.data = data[0]
|
|
|
|
|
|
}
|
2018-12-16 22:22:07 +08:00
|
|
|
|
}
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
2018-12-22 21:03:03 +08:00
|
|
|
|
return model
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-29 14:27:09 +08:00
|
|
|
|
// filterDataForInsertOrUpdate does filter feature with data for inserting/updating operations.
|
|
|
|
|
|
// Note that, it does not filter list item, which is also type of map, for "omit empty" feature.
|
|
|
|
|
|
func (md *Model) filterDataForInsertOrUpdate(data interface{}) interface{} {
|
|
|
|
|
|
if list, ok := md.data.(List); ok {
|
|
|
|
|
|
for k, m := range list {
|
|
|
|
|
|
list[k] = md.doFilterDataMapForInsertOrUpdate(m, false)
|
|
|
|
|
|
}
|
|
|
|
|
|
return list
|
|
|
|
|
|
} else if m, ok := md.data.(Map); ok {
|
|
|
|
|
|
return md.doFilterDataMapForInsertOrUpdate(m, true)
|
|
|
|
|
|
}
|
2019-10-15 17:44:47 +08:00
|
|
|
|
return data
|
2019-09-29 14:27:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// doFilterDataMapForInsertOrUpdate does the filter features for map.
|
|
|
|
|
|
// Note that, it does not filter list item, which is also type of map, for "omit empty" feature.
|
|
|
|
|
|
func (md *Model) doFilterDataMapForInsertOrUpdate(data Map, allowOmitEmpty bool) Map {
|
|
|
|
|
|
if md.filter {
|
|
|
|
|
|
data = md.db.filterFields(md.tables, data)
|
|
|
|
|
|
}
|
2019-10-21 19:13:25 +08:00
|
|
|
|
// Remove key-value pairs of which the value is empty.
|
2019-09-29 14:27:09 +08:00
|
|
|
|
if allowOmitEmpty && md.option&OPTION_OMITEMPTY > 0 {
|
|
|
|
|
|
m := gmap.NewStrAnyMapFrom(data)
|
|
|
|
|
|
m.FilterEmpty()
|
|
|
|
|
|
data = m.Map()
|
|
|
|
|
|
}
|
2019-10-21 19:13:25 +08:00
|
|
|
|
// Keep specified fields.
|
2019-09-29 14:27:09 +08:00
|
|
|
|
if len(md.fields) > 0 && md.fields != "*" {
|
|
|
|
|
|
set := gset.NewStrSet()
|
|
|
|
|
|
for _, v := range gstr.SplitAndTrimSpace(md.fields, ",") {
|
|
|
|
|
|
set.Add(v)
|
|
|
|
|
|
}
|
|
|
|
|
|
for k, _ := range data {
|
|
|
|
|
|
if !set.Contains(k) {
|
|
|
|
|
|
delete(data, k)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-02-27 12:38:12 +08:00
|
|
|
|
// 链式操作, CURD - Insert/BatchInsert。
|
|
|
|
|
|
// 根据Data方法传递的参数类型决定该操作是单条操作还是批量操作,
|
|
|
|
|
|
// 如果Data方法传递的是slice类型,那么为批量操作。
|
2018-07-19 22:11:05 +08:00
|
|
|
|
func (md *Model) Insert() (result sql.Result, err error) {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
md.checkAndRemoveCache()
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
if md.data == nil {
|
|
|
|
|
|
return nil, errors.New("inserting into table with empty data")
|
|
|
|
|
|
}
|
|
|
|
|
|
// 批量操作
|
|
|
|
|
|
if list, ok := md.data.(List); ok {
|
|
|
|
|
|
batch := 10
|
|
|
|
|
|
if md.batch > 0 {
|
|
|
|
|
|
batch = md.batch
|
|
|
|
|
|
}
|
2019-09-29 14:27:09 +08:00
|
|
|
|
return md.db.doBatchInsert(
|
|
|
|
|
|
md.getLink(),
|
|
|
|
|
|
md.tables,
|
|
|
|
|
|
md.filterDataForInsertOrUpdate(list),
|
|
|
|
|
|
gINSERT_OPTION_DEFAULT,
|
|
|
|
|
|
batch,
|
|
|
|
|
|
)
|
2018-12-16 22:22:07 +08:00
|
|
|
|
} else if data, ok := md.data.(Map); ok {
|
2019-09-29 14:27:09 +08:00
|
|
|
|
return md.db.doInsert(
|
|
|
|
|
|
md.getLink(),
|
|
|
|
|
|
md.tables,
|
|
|
|
|
|
md.filterDataForInsertOrUpdate(data),
|
|
|
|
|
|
gINSERT_OPTION_DEFAULT,
|
|
|
|
|
|
)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil, errors.New("inserting into table with invalid data type")
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-02-27 12:38:12 +08:00
|
|
|
|
// 链式操作, CURD - Replace/BatchReplace。
|
|
|
|
|
|
// 根据Data方法传递的参数类型决定该操作是单条操作还是批量操作,
|
|
|
|
|
|
// 如果Data方法传递的是slice类型,那么为批量操作。
|
2018-07-19 22:11:05 +08:00
|
|
|
|
func (md *Model) Replace() (result sql.Result, err error) {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
md.checkAndRemoveCache()
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
if md.data == nil {
|
|
|
|
|
|
return nil, errors.New("replacing into table with empty data")
|
|
|
|
|
|
}
|
|
|
|
|
|
// 批量操作
|
|
|
|
|
|
if list, ok := md.data.(List); ok {
|
|
|
|
|
|
batch := 10
|
|
|
|
|
|
if md.batch > 0 {
|
|
|
|
|
|
batch = md.batch
|
|
|
|
|
|
}
|
2019-09-29 14:27:09 +08:00
|
|
|
|
return md.db.doBatchInsert(
|
|
|
|
|
|
md.getLink(),
|
|
|
|
|
|
md.tables,
|
|
|
|
|
|
md.filterDataForInsertOrUpdate(list),
|
|
|
|
|
|
gINSERT_OPTION_REPLACE,
|
|
|
|
|
|
batch,
|
|
|
|
|
|
)
|
2018-12-16 22:22:07 +08:00
|
|
|
|
} else if data, ok := md.data.(Map); ok {
|
2019-09-29 14:27:09 +08:00
|
|
|
|
return md.db.doInsert(
|
|
|
|
|
|
md.getLink(),
|
|
|
|
|
|
md.tables,
|
|
|
|
|
|
md.filterDataForInsertOrUpdate(data),
|
|
|
|
|
|
gINSERT_OPTION_REPLACE,
|
|
|
|
|
|
)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil, errors.New("replacing into table with invalid data type")
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-02-27 12:38:12 +08:00
|
|
|
|
// 链式操作, CURD - Save/BatchSave。
|
|
|
|
|
|
// 根据Data方法传递的参数类型决定该操作是单条操作还是批量操作,
|
|
|
|
|
|
// 如果Data方法传递的是slice类型,那么为批量操作。
|
2018-07-19 22:11:05 +08:00
|
|
|
|
func (md *Model) Save() (result sql.Result, err error) {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
md.checkAndRemoveCache()
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
if md.data == nil {
|
|
|
|
|
|
return nil, errors.New("replacing into table with empty data")
|
|
|
|
|
|
}
|
|
|
|
|
|
// 批量操作
|
|
|
|
|
|
if list, ok := md.data.(List); ok {
|
2019-02-27 09:38:10 +08:00
|
|
|
|
batch := gDEFAULT_BATCH_NUM
|
2018-08-15 18:14:21 +08:00
|
|
|
|
if md.batch > 0 {
|
|
|
|
|
|
batch = md.batch
|
|
|
|
|
|
}
|
2019-09-29 14:27:09 +08:00
|
|
|
|
return md.db.doBatchInsert(
|
|
|
|
|
|
md.getLink(),
|
|
|
|
|
|
md.tables,
|
|
|
|
|
|
md.filterDataForInsertOrUpdate(list),
|
|
|
|
|
|
gINSERT_OPTION_SAVE,
|
|
|
|
|
|
batch,
|
|
|
|
|
|
)
|
2018-12-16 22:22:07 +08:00
|
|
|
|
} else if data, ok := md.data.(Map); ok {
|
2019-09-29 14:27:09 +08:00
|
|
|
|
return md.db.doInsert(
|
|
|
|
|
|
md.getLink(),
|
|
|
|
|
|
md.tables,
|
|
|
|
|
|
md.filterDataForInsertOrUpdate(data),
|
|
|
|
|
|
gINSERT_OPTION_SAVE,
|
|
|
|
|
|
)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil, errors.New("saving into table with invalid data type")
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作, CURD - Update
|
2018-07-19 22:11:05 +08:00
|
|
|
|
func (md *Model) Update() (result sql.Result, err error) {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
md.checkAndRemoveCache()
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
if md.data == nil {
|
|
|
|
|
|
return nil, errors.New("updating table with empty data")
|
|
|
|
|
|
}
|
2019-09-29 14:27:09 +08:00
|
|
|
|
return md.db.doUpdate(
|
|
|
|
|
|
md.getLink(),
|
|
|
|
|
|
md.tables,
|
|
|
|
|
|
md.filterDataForInsertOrUpdate(md.data),
|
|
|
|
|
|
md.getConditionSql(),
|
|
|
|
|
|
md.whereArgs...,
|
|
|
|
|
|
)
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作, CURD - Delete
|
2018-07-19 22:11:05 +08:00
|
|
|
|
func (md *Model) Delete() (result sql.Result, err error) {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
md.checkAndRemoveCache()
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
2019-08-08 17:43:21 +08:00
|
|
|
|
return md.db.doDelete(md.getLink(), md.tables, md.getConditionSql(), md.whereArgs...)
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,select
|
2018-05-01 10:09:57 +08:00
|
|
|
|
func (md *Model) Select() (Result, error) {
|
2018-12-15 15:50:39 +08:00
|
|
|
|
return md.All()
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,查询所有记录
|
2018-05-01 10:09:57 +08:00
|
|
|
|
func (md *Model) All() (Result, error) {
|
2019-07-22 23:48:39 +08:00
|
|
|
|
return md.getAll(fmt.Sprintf("SELECT %s FROM %s%s", md.fields, md.tables, md.getConditionSql()), md.whereArgs...)
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,查询单条记录
|
2018-05-01 10:09:57 +08:00
|
|
|
|
func (md *Model) One() (Record, error) {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
list, err := md.All()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(list) > 0 {
|
|
|
|
|
|
return list[0], nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil, nil
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,查询字段值
|
2018-05-01 13:02:20 +08:00
|
|
|
|
func (md *Model) Value() (Value, error) {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
one, err := md.One()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
for _, v := range one {
|
|
|
|
|
|
return v, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil, nil
|
2018-04-20 23:23:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-03-07 23:36:45 +08:00
|
|
|
|
// 链式操作,查询单条记录,并自动转换为struct对象, 参数必须为对象的指针,不能为空指针。
|
2019-08-30 20:29:12 +08:00
|
|
|
|
func (md *Model) Struct(pointer interface{}) error {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
one, err := md.One()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2019-10-01 11:29:02 +08:00
|
|
|
|
return one.Struct(pointer)
|
2019-03-07 23:36:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,查询多条记录,并自动转换为指定的slice对象, 如: []struct/[]*struct。
|
2019-08-30 20:29:12 +08:00
|
|
|
|
func (md *Model) Structs(pointer interface{}) error {
|
2019-03-07 23:36:45 +08:00
|
|
|
|
r, err := md.All()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
2019-10-01 11:29:02 +08:00
|
|
|
|
return r.Structs(pointer)
|
2019-03-07 23:36:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 链式操作,将结果转换为指定的struct/*struct/[]struct/[]*struct,
|
|
|
|
|
|
// 参数应该为指针类型,否则返回失败。
|
|
|
|
|
|
// 该方法自动识别参数类型,调用Struct/Structs方法。
|
2019-07-06 15:51:32 +08:00
|
|
|
|
func (md *Model) Scan(pointer interface{}) error {
|
|
|
|
|
|
t := reflect.TypeOf(pointer)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
k := t.Kind()
|
|
|
|
|
|
if k != reflect.Ptr {
|
|
|
|
|
|
return fmt.Errorf("params should be type of pointer, but got: %v", k)
|
|
|
|
|
|
}
|
2019-07-06 15:51:32 +08:00
|
|
|
|
switch t.Elem().Kind() {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
case reflect.Array:
|
|
|
|
|
|
case reflect.Slice:
|
2019-07-06 15:51:32 +08:00
|
|
|
|
return md.Structs(pointer)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
default:
|
2019-07-06 15:51:32 +08:00
|
|
|
|
return md.Struct(pointer)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
return nil
|
2018-07-19 15:33:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-24 10:38:08 +08:00
|
|
|
|
// 链式操作,查询数量,fields可以为空,也可以自定义查询字段,
|
2018-07-19 15:33:17 +08:00
|
|
|
|
// 当给定自定义查询字段时,该字段必须为数量结果,否则会引起歧义,使用如:md.Fields("COUNT(id)")
|
2018-04-24 10:38:08 +08:00
|
|
|
|
func (md *Model) Count() (int, error) {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
defer func(fields string) {
|
|
|
|
|
|
md.fields = fields
|
|
|
|
|
|
}(md.fields)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
if md.fields == "" || md.fields == "*" {
|
|
|
|
|
|
md.fields = "COUNT(1)"
|
2018-12-05 13:52:34 +08:00
|
|
|
|
} else {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
md.fields = fmt.Sprintf(`COUNT(%s)`, md.fields)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
2019-07-02 23:14:40 +08:00
|
|
|
|
s := fmt.Sprintf("SELECT %s FROM %s %s", md.fields, md.tables, md.getConditionSql())
|
2018-08-15 18:14:21 +08:00
|
|
|
|
if len(md.groupBy) > 0 {
|
|
|
|
|
|
s = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", s)
|
|
|
|
|
|
}
|
|
|
|
|
|
list, err := md.getAll(s, md.whereArgs...)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(list) > 0 {
|
|
|
|
|
|
for _, v := range list[0] {
|
|
|
|
|
|
return v.Int(), nil
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0, nil
|
2018-07-19 15:33:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-08-08 17:43:21 +08:00
|
|
|
|
// 获得操作的连接对象
|
|
|
|
|
|
func (md *Model) getLink() dbLink {
|
|
|
|
|
|
if md.tx != nil {
|
|
|
|
|
|
return md.tx.tx
|
|
|
|
|
|
}
|
|
|
|
|
|
switch md.linkType {
|
|
|
|
|
|
case gLINK_TYPE_MASTER:
|
|
|
|
|
|
link, _ := md.db.Master()
|
|
|
|
|
|
return link
|
|
|
|
|
|
case gLINK_TYPE_SLAVE:
|
|
|
|
|
|
link, _ := md.db.Slave()
|
|
|
|
|
|
return link
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-19 15:33:17 +08:00
|
|
|
|
// 查询操作,对底层SQL操作的封装
|
2018-12-17 19:26:59 +08:00
|
|
|
|
func (md *Model) getAll(query string, args ...interface{}) (result Result, err error) {
|
|
|
|
|
|
cacheKey := ""
|
2018-08-15 18:14:21 +08:00
|
|
|
|
// 查询缓存查询处理
|
|
|
|
|
|
if md.cacheEnabled {
|
|
|
|
|
|
cacheKey = md.cacheName
|
|
|
|
|
|
if len(cacheKey) == 0 {
|
2018-12-17 19:26:59 +08:00
|
|
|
|
cacheKey = query + "/" + gconv.String(args)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
2018-12-14 18:35:51 +08:00
|
|
|
|
if v := md.db.getCache().Get(cacheKey); v != nil {
|
2018-08-15 18:14:21 +08:00
|
|
|
|
return v.(Result), nil
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-08-08 17:43:21 +08:00
|
|
|
|
result, err = md.db.doGetAll(md.getLink(), query, args...)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
// 查询缓存保存处理
|
|
|
|
|
|
if len(cacheKey) > 0 && err == nil {
|
2019-10-15 17:44:47 +08:00
|
|
|
|
if md.cacheExpire < 0 {
|
2018-12-14 18:35:51 +08:00
|
|
|
|
md.db.getCache().Remove(cacheKey)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
} else {
|
2019-10-15 17:44:47 +08:00
|
|
|
|
md.db.getCache().Set(cacheKey, result, md.cacheExpire)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result, err
|
2018-04-24 10:38:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-19 22:11:05 +08:00
|
|
|
|
// 检查是否需要查询查询缓存
|
|
|
|
|
|
func (md *Model) checkAndRemoveCache() {
|
2019-10-15 17:44:47 +08:00
|
|
|
|
if md.cacheEnabled && md.cacheExpire < 0 && len(md.cacheName) > 0 {
|
2018-12-14 18:35:51 +08:00
|
|
|
|
md.db.getCache().Remove(md.cacheName)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
2018-07-19 22:11:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-07-02 23:14:40 +08:00
|
|
|
|
// 格式化当前输入参数,返回SQL条件语句(不带参数)
|
|
|
|
|
|
func (md *Model) getConditionSql() string {
|
2019-10-21 19:13:25 +08:00
|
|
|
|
if len(md.whereHolder) > 0 {
|
|
|
|
|
|
for _, v := range md.whereHolder {
|
|
|
|
|
|
switch v.operator {
|
|
|
|
|
|
case gWHERE_HOLDER_WHERE:
|
|
|
|
|
|
if md.where == "" {
|
|
|
|
|
|
newWhere, newArgs := formatWhere(md.db, v.where, v.args, md.option&OPTION_OMITEMPTY > 0)
|
|
|
|
|
|
if len(newWhere) > 0 {
|
|
|
|
|
|
md.where = newWhere
|
|
|
|
|
|
md.whereArgs = newArgs
|
|
|
|
|
|
}
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
|
|
|
|
case gWHERE_HOLDER_AND:
|
|
|
|
|
|
newWhere, newArgs := formatWhere(md.db, v.where, v.args, md.option&OPTION_OMITEMPTY > 0)
|
|
|
|
|
|
if len(newWhere) > 0 {
|
|
|
|
|
|
if md.where[0] == '(' {
|
|
|
|
|
|
md.where = fmt.Sprintf(`%s AND (%s)`, md.where, newWhere)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
md.where = fmt.Sprintf(`(%s) AND (%s)`, md.where, newWhere)
|
|
|
|
|
|
}
|
|
|
|
|
|
md.whereArgs = append(md.whereArgs, newArgs...)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case gWHERE_HOLDER_OR:
|
|
|
|
|
|
newWhere, newArgs := formatWhere(md.db, v.where, v.args, md.option&OPTION_OMITEMPTY > 0)
|
|
|
|
|
|
if len(newWhere) > 0 {
|
|
|
|
|
|
if md.where[0] == '(' {
|
|
|
|
|
|
md.where = fmt.Sprintf(`%s OR (%s)`, md.where, newWhere)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
md.where = fmt.Sprintf(`(%s) OR (%s)`, md.where, newWhere)
|
|
|
|
|
|
}
|
|
|
|
|
|
md.whereArgs = append(md.whereArgs, newArgs...)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-07-02 23:14:40 +08:00
|
|
|
|
s := ""
|
2018-08-15 18:14:21 +08:00
|
|
|
|
if md.where != "" {
|
|
|
|
|
|
s += " WHERE " + md.where
|
|
|
|
|
|
}
|
|
|
|
|
|
if md.groupBy != "" {
|
|
|
|
|
|
s += " GROUP BY " + md.groupBy
|
|
|
|
|
|
}
|
|
|
|
|
|
if md.orderBy != "" {
|
|
|
|
|
|
s += " ORDER BY " + md.orderBy
|
|
|
|
|
|
}
|
|
|
|
|
|
if md.limit != 0 {
|
2019-07-02 23:14:40 +08:00
|
|
|
|
if md.start >= 0 {
|
2019-07-09 12:50:38 +08:00
|
|
|
|
s += fmt.Sprintf(" LIMIT %d,%d", md.start, md.limit)
|
2019-07-02 23:14:40 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
s += fmt.Sprintf(" LIMIT %d", md.limit)
|
|
|
|
|
|
}
|
2019-07-09 12:50:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
if md.offset >= 0 {
|
|
|
|
|
|
s += fmt.Sprintf(" OFFSET %d", md.offset)
|
2018-08-15 18:14:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
return s
|
2018-07-19 15:33:17 +08:00
|
|
|
|
}
|
2018-08-13 10:29:01 +08:00
|
|
|
|
|
2019-03-11 16:14:55 +08:00
|
|
|
|
// 组块结果集。
|
2018-08-15 18:16:36 +08:00
|
|
|
|
func (md *Model) Chunk(limit int, callback func(result Result, err error) bool) {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
page := 1
|
2019-03-11 16:14:55 +08:00
|
|
|
|
model := md
|
2018-08-13 10:29:01 +08:00
|
|
|
|
for {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
model = model.ForPage(page, limit)
|
2019-03-11 16:14:55 +08:00
|
|
|
|
data, err := model.All()
|
2018-08-13 10:29:01 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
callback(nil, err)
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(data) == 0 {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
2018-08-14 10:28:52 +08:00
|
|
|
|
if callback(data, err) == false {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
2018-08-13 10:29:01 +08:00
|
|
|
|
if len(data) < limit {
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
2018-08-15 18:14:21 +08:00
|
|
|
|
page++
|
2018-08-13 10:29:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|