gf/g/database/gdb/gdb_model.go

559 lines
15 KiB
Go
Raw Normal View History

// 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,
// You can obtain one at https://github.com/gogf/gf.
2018-04-20 23:23:42 +08:00
package gdb
import (
"fmt"
"errors"
"database/sql"
"github.com/gogf/gf/g/util/gconv"
_ "github.com/gogf/gf/third/github.com/go-sql-driver/mysql"
2018-12-16 22:22:07 +08:00
"reflect"
2018-12-14 10:09:45 +08:00
"strings"
2018-04-20 23:23:42 +08:00
)
// 数据库链式操作模型对象
type Model struct {
2018-12-14 18:35:51 +08:00
db DB // 数据库操作对象
tx *TX // 数据库事务对象
2018-12-14 10:09:45 +08:00
tablesInit string // 初始化Model时的表名称(可以是多个)
tables string // 数据库操作表
fields string // 操作字段
where string // 操作条件
whereArgs []interface{} // 操作条件参数
groupBy string // 分组语句
orderBy string // 排序语句
start int // 分页开始
limit int // 分页条数
data interface{} // 操作记录(支持Map/List/string类型)
batch int // 批量操作条数
2018-12-16 22:22:07 +08:00
filter bool // 是否按照表字段过滤data参数
cacheEnabled bool // 当前SQL操作是否开启查询缓存功能
cacheTime int // 查询缓存时间
cacheName string // 查询缓存名称
2018-04-20 23:23:42 +08:00
}
// 链式操作,数据表字段,可支持多个表,以半角逗号连接
func (bs *dbBase) Table(tables string) (*Model) {
return &Model {
db : bs.db,
2018-12-14 10:09:45 +08:00
tablesInit : tables,
tables : tables,
fields : "*",
}
2018-04-20 23:23:42 +08:00
}
// 链式操作,数据表字段,可支持多个表,以半角逗号连接
func (bs *dbBase) From(tables string) (*Model) {
return bs.db.Table(tables)
2018-04-20 23:23:42 +08:00
}
// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接
func (tx *TX) Table(tables string) (*Model) {
return &Model{
2018-12-14 10:09:45 +08:00
db : tx.db,
tx : tx,
tablesInit : tables,
tables : tables,
}
2018-04-20 23:23:42 +08:00
}
// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接
func (tx *TX) From(tables string) (*Model) {
return tx.Table(tables)
2018-04-20 23:23:42 +08:00
}
// 克隆一个当前对象
func (md *Model) Clone() *Model {
newModel := (*Model)(nil)
if md.tx != nil {
newModel = md.tx.Table(md.tablesInit)
} else {
newModel = md.db.Table(md.tablesInit)
}
*newModel = *md
return newModel
2018-12-14 10:09:45 +08:00
}
2018-04-20 23:23:42 +08:00
// 链式操作,左联表
func (md *Model) LeftJoin(joinTable string, on string) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", joinTable, on)
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作,右联表
func (md *Model) RightJoin(joinTable string, on string) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.tables += fmt.Sprintf(" RIGHT JOIN %s ON (%s)", joinTable, on)
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作,内联表
func (md *Model) InnerJoin(joinTable string, on string) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.tables += fmt.Sprintf(" INNER JOIN %s ON (%s)", joinTable, on)
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作,查询字段
func (md *Model) Fields(fields string) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.fields = fields
return model
2018-04-20 23:23:42 +08:00
}
2018-12-16 22:22:07 +08:00
// 链式操作,过滤字段
func (md *Model) Filter() (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.filter = true
return model
2018-12-16 22:22:07 +08:00
}
2018-04-20 23:23:42 +08:00
// 链式操作condition支持string & gdb.Map
func (md *Model) Where(where interface{}, args ...interface{}) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
newWhere, newArgs := formatCondition(where, args)
2018-12-22 21:03:03 +08:00
model.where = newWhere
model.whereArgs = append(model.whereArgs, newArgs...)
2018-12-14 10:09:45 +08:00
// 支持 Where("uid", 1)这种格式
2018-12-22 21:03:03 +08:00
if len(args) == 1 && strings.Index(model.where , "?") < 0 {
model.where += "=?"
2018-12-14 10:09:45 +08:00
}
2018-12-22 21:03:03 +08:00
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作添加AND条件到Where中
func (md *Model) And(where interface{}, args ...interface{}) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
newWhere, newArgs := formatCondition(where, args)
2018-12-22 21:03:03 +08:00
model.where += " AND " + newWhere
model.whereArgs = append(model.whereArgs, newArgs...)
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作添加OR条件到Where中
func (md *Model) Or(where interface{}, args ...interface{}) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
newWhere, newArgs := formatCondition(where, args)
2018-12-22 21:03:03 +08:00
model.where += " OR " + newWhere
model.whereArgs = append(model.whereArgs, newArgs...)
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作group by
func (md *Model) GroupBy(groupBy string) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.groupBy = groupBy
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作order by
func (md *Model) OrderBy(orderBy string) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.orderBy = orderBy
return model
2018-04-20 23:23:42 +08:00
}
// 链式操作limit
func (md *Model) Limit(start int, limit int) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.start = start
model.limit = limit
return model
}
// 链式操作,翻页
// @author ymrjqyy
func (md *Model) ForPage(page, limit int) (*Model) {
2018-12-22 21:03:03 +08:00
model := md.Clone()
model.start = (page - 1) * limit
model.limit = limit
return model
}
// 设置批处理的大小
func (md *Model) Batch(batch int) *Model {
model := md.Clone()
model.batch = batch
return model
}
// 查询缓存/清除缓存操作,需要注意的是,事务查询不支持缓存。
// 当time < 0时表示清除缓存 time=0时表示不过期, time > 0时表示过期时间time过期时间单位
// name表示自定义的缓存名称便于业务层精准定位缓存项(如果业务层需要手动清理时,必须指定缓存名称)
// 例如:查询缓存时设置名称,清理缓存时可以给定清理的缓存名称进行精准清理。
func (md *Model) Cache(time int, name ... string) *Model {
model := md.Clone()
model.cacheTime = time
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 {
2018-12-22 21:03:03 +08:00
model := md.Clone()
if len(data) > 1 {
m := make(map[string]interface{})
for i := 0; i < len(data); i += 2 {
m[gconv.String(data[i])] = data[i + 1]
}
2018-12-22 21:03:03 +08:00
model.data = m
} else {
2018-12-16 22:22:07 +08:00
switch data[0].(type) {
case List:
2018-12-22 21:03:03 +08:00
model.data = data[0]
2018-12-16 22:22:07 +08:00
case Map:
2018-12-22 21:03:03 +08:00
model.data = data[0]
2018-12-16 22:22:07 +08:00
default:
rv := reflect.ValueOf(data[0])
kind := rv.Kind()
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
// 如果是slice那么转换为List类型
2018-12-16 22:22:07 +08:00
case reflect.Slice: fallthrough
case reflect.Array:
list := make(List, rv.Len())
for i := 0; i < rv.Len(); i++ {
list[i] = gconv.Map(rv.Index(i).Interface())
}
2018-12-22 21:03:03 +08:00
model.data = list
case reflect.Map: fallthrough
case reflect.Struct:
model.data = Map(gconv.Map(data[0]))
2018-12-16 22:22:07 +08:00
default:
2018-12-22 21:03:03 +08:00
model.data = data[0]
2018-12-16 22:22:07 +08:00
}
}
}
2018-12-22 21:03:03 +08:00
return model
2018-04-20 23:23:42 +08:00
}
2019-02-27 12:38:12 +08:00
// 链式操作, CURD - Insert/BatchInsert。
// 根据Data方法传递的参数类型决定该操作是单条操作还是批量操作
// 如果Data方法传递的是slice类型那么为批量操作。
func (md *Model) Insert() (result sql.Result, err error) {
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
}
2018-12-16 22:22:07 +08:00
if md.filter {
for k, m := range list {
list[k] = md.db.filterFields(md.tables, m)
}
}
if md.tx == nil {
return md.db.BatchInsert(md.tables, list, batch)
} else {
return md.tx.BatchInsert(md.tables, list, batch)
}
2018-12-16 22:22:07 +08:00
} else if data, ok := md.data.(Map); ok {
if md.filter {
data = md.db.filterFields(md.tables, data)
}
if md.tx == nil {
2018-12-16 22:22:07 +08:00
return md.db.Insert(md.tables, data)
} else {
2018-12-16 22:22:07 +08:00
return md.tx.Insert(md.tables, data)
}
}
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类型那么为批量操作。
func (md *Model) Replace() (result sql.Result, err error) {
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
}
2018-12-16 22:22:07 +08:00
if md.filter {
for k, m := range list {
list[k] = md.db.filterFields(md.tables, m)
}
}
if md.tx == nil {
return md.db.BatchReplace(md.tables, list, batch)
} else {
return md.tx.BatchReplace(md.tables, list, batch)
}
2018-12-16 22:22:07 +08:00
} else if data, ok := md.data.(Map); ok {
if md.filter {
data = md.db.filterFields(md.tables, data)
}
if md.tx == nil {
2018-12-16 22:22:07 +08:00
return md.db.Replace(md.tables, data)
} else {
2018-12-16 22:22:07 +08:00
return md.tx.Replace(md.tables, data)
}
}
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类型那么为批量操作。
func (md *Model) Save() (result sql.Result, err error) {
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 := gDEFAULT_BATCH_NUM
if md.batch > 0 {
batch = md.batch
}
2018-12-16 22:22:07 +08:00
if md.filter {
for k, m := range list {
list[k] = md.db.filterFields(md.tables, m)
}
}
if md.tx == nil {
return md.db.BatchSave(md.tables, list, batch)
} else {
return md.tx.BatchSave(md.tables, list, batch)
}
2018-12-16 22:22:07 +08:00
} else if data, ok := md.data.(Map); ok {
if md.filter {
data = md.db.filterFields(md.tables, data)
}
if md.tx == nil {
2018-12-16 22:22:07 +08:00
return md.db.Save(md.tables, data)
} else {
2018-12-16 22:22:07 +08:00
return md.tx.Save(md.tables, data)
}
}
return nil, errors.New("saving into table with invalid data type")
2018-04-20 23:23:42 +08:00
}
// 链式操作, CURD - Update
func (md *Model) Update() (result sql.Result, err error) {
defer func() {
if err == nil {
md.checkAndRemoveCache()
}
}()
if md.data == nil {
return nil, errors.New("updating table with empty data")
}
2018-12-16 22:22:07 +08:00
if md.filter {
if data, ok := md.data.(Map); ok {
if md.filter {
md.data = md.db.filterFields(md.tables, data)
}
}
}
if md.tx == nil {
return md.db.Update(md.tables, md.data, md.where, md.whereArgs ...)
} else {
return md.tx.Update(md.tables, md.data, md.where, md.whereArgs ...)
}
2018-04-20 23:23:42 +08:00
}
// 链式操作, CURD - Delete
func (md *Model) Delete() (result sql.Result, err error) {
defer func() {
if err == nil {
md.checkAndRemoveCache()
}
}()
if md.tx == nil {
return md.db.Delete(md.tables, md.where, md.whereArgs...)
} else {
return md.tx.Delete(md.tables, md.where, md.whereArgs...)
}
2018-04-20 23:23:42 +08:00
}
// 链式操作select
func (md *Model) Select() (Result, error) {
return md.All()
2018-04-20 23:23:42 +08:00
}
// 链式操作,查询所有记录
func (md *Model) All() (Result, error) {
return md.getAll(md.getFormattedSql(), md.whereArgs...)
2018-04-20 23:23:42 +08:00
}
// 链式操作,查询单条记录
func (md *Model) One() (Record, error) {
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
}
// 链式操作,查询字段值
func (md *Model) Value() (Value, error) {
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
}
2018-07-19 15:33:17 +08:00
// 链式操作查询单条记录并自动转换为struct对象
func (md *Model) Struct(obj interface{}) error {
one, err := md.One()
if err != nil {
return err
}
return one.ToStruct(obj)
2018-07-19 15:33:17 +08:00
}
// 链式操作查询数量fields可以为空也可以自定义查询字段
2018-07-19 15:33:17 +08:00
// 当给定自定义查询字段时该字段必须为数量结果否则会引起歧义使用如md.Fields("COUNT(id)")
func (md *Model) Count() (int, error) {
defer func(fields string) {
md.fields = fields
}(md.fields)
if md.fields == "" || md.fields == "*" {
md.fields = "COUNT(1)"
} else {
md.fields = fmt.Sprintf(`COUNT(%s)`, md.fields)
}
s := md.getFormattedSql()
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
}
// 查询操作对底层SQL操作的封装
2018-12-17 19:26:59 +08:00
func (md *Model) getAll(query string, args ...interface{}) (result Result, err error) {
cacheKey := ""
// 查询缓存查询处理
if md.cacheEnabled {
cacheKey = md.cacheName
if len(cacheKey) == 0 {
2018-12-17 19:26:59 +08:00
cacheKey = query + "/" + gconv.String(args)
}
2018-12-14 18:35:51 +08:00
if v := md.db.getCache().Get(cacheKey); v != nil {
return v.(Result), nil
}
}
2018-12-17 19:26:59 +08:00
if md.tx == nil {
2018-12-17 19:26:59 +08:00
result, err = md.db.GetAll(query, args...)
} else {
2018-12-17 19:26:59 +08:00
result, err = md.tx.GetAll(query, args...)
}
// 查询缓存保存处理
if len(cacheKey) > 0 && err == nil {
if md.cacheTime < 0 {
2018-12-14 18:35:51 +08:00
md.db.getCache().Remove(cacheKey)
} else {
2018-12-14 18:35:51 +08:00
md.db.getCache().Set(cacheKey, result, md.cacheTime*1000)
}
}
return result, err
}
// 检查是否需要查询查询缓存
func (md *Model) checkAndRemoveCache() {
if md.cacheEnabled && md.cacheTime < 0 && len(md.cacheName) > 0 {
2018-12-14 18:35:51 +08:00
md.db.getCache().Remove(md.cacheName)
}
}
// 格式化当前输入参数返回可执行的SQL语句不带参数
func (md *Model) getFormattedSql() string {
if md.fields == "" {
md.fields = "*"
}
s := fmt.Sprintf("SELECT %s FROM %s", md.fields, md.tables)
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 {
s += fmt.Sprintf(" LIMIT %d, %d", md.start, md.limit)
}
return s
2018-07-19 15:33:17 +08:00
}
2018-08-13 10:29:01 +08:00
// 组块结果集
// @author ymrjqyy
2018-08-15 18:17:29 +08:00
// @author 2018-08-15
2018-08-15 18:16:36 +08:00
func (md *Model) Chunk(limit int, callback func(result Result, err error) bool) {
2018-12-14 10:09:45 +08:00
page := 1
2018-08-13 10:29:01 +08:00
for {
md.ForPage(page, limit)
2018-12-14 10:09:45 +08:00
data, err := md.getAll(md.getFormattedSql(), md.whereArgs...)
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
}
page++
2018-08-13 10:29:01 +08:00
}
}