1 Star 0 Fork 0

海风 / zorm-dm

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
sql.go 20.45 KB
一键复制 编辑 原始数据 按行查看 历史
海风 提交于 2024-03-27 17:13 . 修复: SeleceCount bug(Oracle)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
package zd
import (
"bytes"
"context"
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"gitee.com/chunanyong/zorm"
)
// PageInfo 分页数据
type PageInfo struct {
PageNo int `json:"pageNo,omitempty"`
PageSize int `json:"pageSize,omitempty"`
TotalCount int `json:"totalCount,omitempty"`
}
// TableExists 判断表是否存在
//
// @param tblName string 表名
// @return bool 是否存在
func TableExists(tblName string) bool {
// 表是否存在
// `select count(1) from dba_segments where segment_type='TABLE' AND OWNER='FEEMGR' and SEGMENT_NAME=''` 默认owner='sbsdba
finder := zorm.NewFinder()
finder.Append(fmt.Sprintf(`select count(1) from dba_segments where segment_type='TABLE' AND OWNER='%s' and SEGMENT_NAME='%s'`, strings.Split(tblName, ".")[0], strings.Split(tblName, ".")[1])) // getTableName中增加了 feemgr.
finder.InjectionCheck = false
finder.GetSQL()
var cnt int
ok, err := zorm.QueryRow(ctxDefault, finder, &cnt)
if err != nil {
fmt.Println(err.Error())
return false
}
if !ok || cnt == 0 { // 表不存在
return false
}
return true
}
// GetPrimaryKeyByName 获取主键
//
// @param tblName string 表名
// @return []string 主键名称
// @return error 错误
func GetPrimaryKeyByName(tblName string) ([]string, error) {
sqlStr := `Select col.column_name from all_constraints con, all_cons_columns col where con.constraint_name=col.constraint_name and con.constraint_type=? and col.owner=? and col.table_name=?`
finder := zorm.NewFinder()
if strings.Contains(tblName, ".") {
tblName = strings.Split(tblName, ".")[1]
}
finder.Append(sqlStr, "P", SchemaName, tblName)
finder.GetSQL()
var keys = make([]string, 0)
err := zorm.Query(ctxDefault, finder, &keys, nil)
if err != nil {
return nil, err
}
return keys, nil
}
var valToSql = func(v any) any {
switch v := v.(type) {
case string, int, float64:
return v
case bool:
if v {
return "1"
} else {
return "0"
}
}
// 处理类型别名
var val any
if newVal, _ := json.Marshal(v); bytes.Contains(newVal, []byte("\"")) { // 有 " 表示内容为 基于 string的自定义类型
val = fmt.Sprintf("%s", v)
} else if n, err := strconv.ParseInt(string(newVal), 0, 8); err == nil { // byte
val = fmt.Sprintf("%c", n) // fmt.Sprintf("%s", v):: TSNew->"New"
} else if n, err := strconv.Atoi(string(newVal)); err == nil { // int
val = fmt.Sprintf("%d", n)
} else if n, err := strconv.ParseFloat(string(newVal), 64); err == nil { // float64
val = fmt.Sprintf("%f", n)
} else if b, err := strconv.ParseBool(string(newVal)); err == nil { // bool 别名
if b {
val = "1"
} else {
val = "0"
}
} else {
val = v
}
return val
}
/*
mapToFinder
自定义类型转换 byte -> char
*/
var mapToFinder = func(params map[string]any, joinStr string) *zorm.Finder {
if len(params) == 0 {
return zorm.NewFinder().Append("1=1")
}
var vals = make([]any, 0)
var keys = make([]string, 0)
for k, v := range params {
if v == nil {
if joinStr == "AND" { // 处理 where 中的 NULL(nil)
keys = append(keys, fmt.Sprintf("ISNULL(%s) = ?", k))
vals = append(vals, true)
} else {
keys = append(keys, k+" = NULL")
}
continue
}
switch v := v.(type) {
case map[string]any: // 实现 between .. and .. 以及 >= < != 等操作
for kSub, vSub := range v {
if kSub == "between" { // between vSub 为数组
// and 会被 fnd 替换成 ,
keys = append(keys, k+" between ? and ?")
vals = append(vals, vSub.([]any)...)
} else {
keys = append(keys, fmt.Sprintf("%s %s ?", k, kSub))
vals = append(vals, valToSql(vSub))
}
}
case []any, []string, []int, []float64, []bool, []time.Time: // 数组
keys = append(keys, k+" in (?)")
vals = append(vals, v)
case bool:
keys = append(keys, k+" = ?")
if v {
vals = append(vals, "1")
} else {
vals = append(vals, "0")
}
case string, int, float64:
keys = append(keys, k+" = ?")
vals = append(vals, v)
default: // 自定义类型别名
kind := reflect.TypeOf(v).Kind()
switch kind {
case reflect.Slice: // 自定义类型的数组: []InstrumentIDType
keys = append(keys, k+" in (?)")
vals = append(vals, v)
case reflect.Int, reflect.Int32, reflect.Int64, reflect.Float64, reflect.Float32, reflect.String:
keys = append(keys, k+" = ?")
vals = append(vals, v)
case reflect.Bool:
keys = append(keys, k+" = ?")
if v.(bool) {
vals = append(vals, "1")
} else {
vals = append(vals, "0")
}
case reflect.Int8: // byte
keys = append(keys, k+" = ?")
vals = append(vals, fmt.Sprintf("%c", v.(byte)))
default:
keys = append(keys, k+" = ?")
vals = append(vals, valToSql(v))
}
}
}
key := strings.Join(keys, " "+joinStr+" ")
fnd := zorm.NewFinder()
fnd.InjectionCheck = false
return fnd.Append(key, vals...)
}
// mapToWhereFinder 用以 where update 操作
//
// @param params map[string]any 参数
// @return *zorm.Finder 查询
func mapToWhereFinder(params map[string]any) *zorm.Finder {
return mapToFinder(params, "AND")
}
// mapToSetFinder 用于 update
//
// @param params map[string]any 参数
// @return *zorm.Finder 查询
func mapToSetFinder(params map[string]any) *zorm.Finder {
return mapToFinder(params, ",")
}
// Transaction 使用事务
//
// @param fun func() error 使用了什么代码就抛出什么错误
// @return error 错误
func Transaction(fun func() error) error {
_, err := zorm.Transaction(ctxDefault, func(ctx context.Context) (interface{}, error) {
return nil, fun()
})
return err
}
// SelectCount 查询 count(1)
//
// @param where map[string]any 查询条件
// @return int count(1)
// @return error 错误
func SelectCount[T IEntity](where map[string]any) (int, error) {
return SelectCountByName(GetTableName[T](), where)
}
// SelectCountByName 根据表名查询 count(1)
//
// @param tblName string 表名
// @param where map[string]any 查询条件
// @return int count(1)
// @return error 错误
func SelectCountByName(tblName string, where map[string]any) (int, error) {
_, fnd := getFinderByName(tblName, nil, where, []string{"Count(1)"})
var cnt float64
_, err := zorm.QueryRow(ctxDefault, fnd, &cnt)
if err != nil {
return -1, err
}
return int(cnt), nil
}
// SelectRow 查询首行指定列的值
//
// @param columnName string 列名
// @param params map[string]any 查询条件
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return any 无效查询返回 nil
// @return error
func SelectRow[T IEntity](columnName string, params map[string]any, sqlStrAppend ...string) (any, error) {
return SelectRowByName(GetTableName[T](), columnName, params, sqlStrAppend...)
}
// SelectRowByName 查询首行指定列的值
//
// @param tblName string 表名
// @param columnName string 列名
// @param params map[string]any 查询条件
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return any 无效查询返回 nil
// @return error
func SelectRowByName(tblName string, columnName string, params map[string]any, sqlStrAppend ...string) (any, error) {
rows, err := SelectMapColumnsByName(tblName, nil, params, []string{columnName}, sqlStrAppend...)
if err != nil {
return nil, err
}
if len(rows) == 0 {
return nil, nil
}
for _, v := range rows[0] {
return v, nil
}
return nil, nil
}
// getFinderByName 生成 finder
//
// @param tblName string 表名
// @param p *PageInfo 分页
// @param params map[string]any 查询条件
// @param columns []string 查询列
// @param sqlStrAppend []string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return *zorm.Page 分页信息
// @return *zorm.Finder finder
func getFinderByName(tblName string, p *PageInfo, params map[string]any, columns []string, sqlStrAppend ...string) (*zorm.Page, *zorm.Finder) {
//构造查询用的fnd
if !strings.Contains(tblName, ".") { // 不带 schema 的用默认 schemaName
tblName = SchemaName + "." + tblName
}
var fnd = zorm.NewSelectFinder(tblName) // select * from t_demo
if len(columns) > 0 {
cols := make([]string, len(columns)) // 转为大写,以适应列名
for i, v := range columns {
cols[i] = strings.ToUpper(v)
}
fnd = zorm.NewSelectFinder(tblName, strings.Join(cols, ",")) // select * from t_demo
}
if len(params) > 0 { // 只处理 where xx=? 的情况
fnd.Append("WHERE").AppendFinder(mapToWhereFinder(params))
} else {
fnd.Append("WHERE 1=1")
}
if len(sqlStrAppend) > 0 {
fndAppend := zorm.NewFinder()
for _, v := range sqlStrAppend {
fndAppend = fndAppend.Append(v)
}
fndAppend.InjectionCheck = false
fndAppend.GetSQL() // 以 isActive='0' 附加查询条件时, 这样才能使 fndAppend 生效
fnd.AppendFinder(fndAppend)
}
fnd.InjectionCheck = false
fnd.GetSQL() // fnd 生效
//创建分页对象,查询完成后,page对象可以直接给前端分页组件使用
var page *zorm.Page
if p != nil && p.PageSize > 0 { // 避免出现 除数为0的情况
if p.PageNo == 0 { // 避免无返回的情况
p.PageNo = 1
}
page = &zorm.Page{
PageNo: p.PageNo, //查询第1页,默认是1
PageSize: p.PageSize, //每页20条,默认是20
}
}
return page, fnd
}
// SelectMap 查询返回 map(key 全大写)
//
// @param p *PageInfo 分页
// @param params map[string]any 查询条件
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return []map[string]any 返回结果集
// @return error 错误
func SelectMap[T IEntity](p *PageInfo, params map[string]any, sqlStrAppend ...string) ([]map[string]any, error) {
ts, err := Select[T](p, params, sqlStrAppend...)
if err != nil {
return nil, err
}
data := make([]map[string]any, len(ts))
for i, t := range ts {
data[i] = ToUpperMap(t)
}
return data, nil
}
// SelectMap 查询返回 map(key camel 小驼峰)
//
// @param p *PageInfo 分页
// @param params map[string]any 查询条件
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return []map[string]any 返回结果集
// @return error 错误
func SelectMapCamel[T IEntity](p *PageInfo, params map[string]any, sqlStrAppend ...string) ([]map[string]any, error) {
ts, err := Select[T](p, params, sqlStrAppend...)
if err != nil {
return nil, err
}
data := make([]map[string]any, len(ts))
for i, t := range ts {
data[i] = ToLittleCamelMap(t)
}
return data, nil
}
// SelectMapColumns 返回 map 指定列名
//
// @param p *PageInfo 分页
// @param params map[string]any 查询条件
// @param columns []string 查询列
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return []map[string]any 返回结果集
// @return error 错误
func SelectMapColumns[T IEntity](p *PageInfo, params map[string]any, columns []string, sqlStrAppend ...string) ([]map[string]any, error) {
return SelectMapColumnsByName(GetTableName[T](), p, params, columns, sqlStrAppend...)
}
// SelectMapByName 根据表名查询, 返回 map
//
// @param tblName string 表名
// @param p *PageInfo 分页
// @param params map[string]any 查询条件
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return []map[string]any 返回结果集
// @return error 错误
func SelectMapByName(tblName string, p *PageInfo, params map[string]any, sqlStrAppend ...string) ([]map[string]any, error) {
return SelectMapColumnsByName(tblName, p, params, nil, sqlStrAppend...)
}
// SelectMapColumnsByName 根据表名查询, 返回 map 指定列名
//
// **所有 SelectMap 基于此**
//
// @param tblName string 表名
// @param p *PageInfo 分页
// @param params map[string]any 查询条件
// @param columns []string 查询列
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return []map[string]any 返回结果集
// @return error 错误
func SelectMapColumnsByName(tblName string, p *PageInfo, params map[string]any, columns []string, sqlStrAppend ...string) ([]map[string]any, error) {
page, fnd := getFinderByName(tblName, p, params, columns, sqlStrAppend...)
rows, err := zorm.QueryMap(ctxDefault, fnd, page)
if p != nil {
p.TotalCount = page.TotalCount
}
return rows, err
}
// Select 查询, 返回 struct
//
// @param p *PageInfo 分页
// @param params map[string]any 查询条件
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return []T 返回结果集
// @return error 错误
func Select[T IEntity](p *PageInfo, params map[string]any, sqlStrAppend ...string) ([]T, error) {
var data []T
pg, fnd := getFinderByName(GetTableName[T](), p, params, nil, sqlStrAppend...)
err := zorm.Query(ctxDefault, fnd, &data, pg)
if err != nil {
return nil, err
}
// 返回总数
if p != nil {
p.TotalCount = pg.TotalCount
}
return data, nil
}
// SelectByStruct 查询,条件用 IEntity 实例, 返回 struct
//
// @param p *PageInfo 分页
// @param t T 只接受非0值, 若查查询 bool:false int:0 string:"" 的条件,可在 sqlStrAppend 拼接
// @param sqlStrAppend string sql拓展, 如 order by xxx, 不会被 fnd 替换
// @return []T 返回结果集
// @return error 错误
func SelectByStruct[T IEntity](p *PageInfo, t T, sqlStrAppend ...string) ([]T, error) {
params := StructToMap(t, true, false)
return Select[T](p, params, sqlStrAppend...)
}
// Insert 插入数据(不要用指针类型!!!不要用指针类型!!!不要用指针类型!!!)
//
// 不过滤空值: struct 初始化的字段也会入库, 如 string 字段会以*空白字串*入库
//
// @param entities ...T 插入数据
// @return error 错误
func Insert[T IEntity](entities ...T) error {
// 有自增字段时先执行 SET IDENTITY_INSERT %s ON
for _, col := range GetColumns[T]() {
if col.AutoIncrement {
zorm.UpdateFinder(ctxDefault, zorm.NewFinder().Append(fmt.Sprintf("SET IDENTITY_INSERT %s ON", GetTableName[T]())))
break
}
}
return Transaction(func() error {
entityMaps := make([]map[string]any, len(entities))
for i, entity := range entities {
// 不过滤空值: struct 初始化的字段也会入库, 如 string 字段会以*空白字串*入库
entityMaps[i] = StructToMap(entity, false, true)
}
return InsertMapByName(GetTableName[T](), entityMaps...)
})
}
// InsertNotZero 插入数据(不要用指针类型!!!不要用指针类型!!!不要用指针类型!!!)
//
// 过滤0值(bool:false, int:0, string:""), string字段入库后为 NULL
//
// @param entities ...T 插入数据
// @return error 错误
func InsertNotZero[T IEntity](entities ...T) error {
// 有自增字段时先执行 SET IDENTITY_INSERT %s ON
for _, col := range GetColumns[T]() {
if col.AutoIncrement {
zorm.UpdateFinder(ctxDefault, zorm.NewFinder().Append(fmt.Sprintf("SET IDENTITY_INSERT %s ON", GetTableName[T]())))
break
}
}
return Transaction(func() error {
entityMaps := make([]map[string]any, len(entities))
for i, entity := range entities {
entityMaps[i] = StructToMap(entity, true, true)
}
return InsertMapByName(GetTableName[T](), entityMaps...)
})
}
// InsertMap 插入数据
//
// @param entities ...map[string]any 插入数据
// @return error 错误
func InsertMap[T IEntity](entities ...map[string]any) error {
return InsertMapByName(GetTableName[T](), entities...)
}
// InsertMapByName 根据表名插入数据
//
// @param tblName string 表名
// @param entities ...map[string]any 插入数据
// @return error 错误
func InsertMapByName(tblName string, entities ...map[string]any) error {
return Transaction(func() error {
entitySlice := make([]zorm.IEntityMap, len(entities))
for i, entity := range entities {
entityMap := zorm.NewEntityMap(tblName)
entityMap.PkColumnName = "" //不写此行也可以 但是会打印log
entity = ToUpperMap(entity)
for k, v := range entity {
if v == nil { // 过滤 nil值, 入库数据会变为 NULL
continue
}
// byte 自定义数据类型
if reflect.TypeOf(v).Kind() == reflect.Uint8 && reflect.TypeOf(v).Name() != "uint8" {
entityMap.Set(k, fmt.Sprintf("%c", v))
continue
}
entityMap.Set(k, v)
}
entitySlice[i] = entityMap
}
_, err := zorm.InsertEntityMapSlice(ctxDefault, entitySlice)
return err
})
}
// Update 更新 Struct
//
// @param entities ...T 替换数据(**不能是指针! 不能是指针! 不能是指针!**)
// @return int 替换数量
// @return error 错误
func Update[T IEntity](entities ...T) (int, error) {
keys := GetPrimaryKey[T]()
err := Transaction(func() error {
for _, entity := range entities {
mp := StructToMap(entity, false, true)
mp = ToUpperMap(mp)
where := make(map[string]any)
for _, key := range keys {
var ok bool
if where[key], ok = mp[key]; !ok {
return fmt.Errorf("缺少主键 %s 的值", key)
}
// 过滤主键(一般自增字段或作为主键,在此一并过滤,否则报不能更新自增列的错误)
delete(mp, key)
}
if _, err := UpdateMapConditionsByName(GetTableName[T](), []map[string]any{where}, mp); err != nil {
return err
}
}
return nil
})
if err != nil {
return 0, err
}
return len(entities), nil
}
// UpdateMap UpdateOne 更新(单个条件)
//
// @param where map[string]any 查询条件
// @param set map[string]any 替换数据
// @return int 替换数量
// @return error 错误
func UpdateMap[T IEntity](where map[string]any, set map[string]any) (int, error) {
return UpdateMapConditionsByName(GetTableName[T](), []map[string]any{where}, set)
}
// UpdateMapByName 根据表名更新(单个条件)
//
// @param tblName string 表名
// @param where map[string]any 查询条件
// @param set map[string]any 替换数据
// @return int 替换数量
// @return error 错误
func UpdateMapByName(tblName string, where map[string]any, set map[string]any) (int, error) {
return UpdateMapConditionsByName(tblName, []map[string]any{where}, set)
}
// UpdateMapConditions 更新(多条件)
//
// @param wheres []map[string]any 查询条件
// @param set map[string]any 替换数据
// @return int 替换数量
// @return error 错误
func UpdateMapConditions[T IEntity](wheres []map[string]any, set map[string]any) (int, error) {
return UpdateMapConditionsByName(GetTableName[T](), wheres, set)
}
// UpdateMapConditionsByName 根据表名更新
//
// 所有 Update 基于此
//
// @param tblName string 表名
// @param wheres []map[string]any 查询条件
// @param set map[string]any 替换数据
// @return int 替换数量(更新数据量为 0 没有符合条件的数据)
// @return error 错误
func UpdateMapConditionsByName(tblName string, wheres []map[string]any, set map[string]any) (int, error) {
set = ToUpperMap(set)
cnt := 0
err := Transaction(func() error {
for _, where := range wheres {
finder := zorm.NewUpdateFinder(tblName) // UPDATE t_demo SET
finder.AppendFinder(mapToSetFinder(set))
finder.Append("WHERE").AppendFinder(mapToWhereFinder(where))
finder.GetSQL()
n, err := zorm.UpdateFinder(ctxDefault, finder)
if err != nil {
return err
}
// if n == 0 {
// return fmt.Errorf("没有符合条件的数据: %v", where)
// }
cnt += n
}
return nil
})
if err != nil {
return 0, err
}
return cnt, nil
}
// Delete 删除
//
// @param params map[string]any 删除条件
// @return int 删除数量
// @return error 错误
func Delete[T IEntity](params map[string]any) (int, error) {
return DeleteByName(GetTableName[T](), params)
}
// DeleteByName 根据表名删除
//
// @param tblName string 表名
// @param params map[string]any 删除条件
// @return int 删除数量
// @return error 错误
func DeleteByName(tblName string, params map[string]any) (int, error) {
cnt := 0
err := Transaction(func() (err error) {
finder := zorm.NewDeleteFinder(tblName) // DELETE FROM t_demo
finder.Append(`WHERE`).AppendFinder(mapToWhereFinder(params))
finder.GetSQL()
cnt, err = zorm.UpdateFinder(ctxDefault, finder)
return
})
return cnt, err
}
// QueryMap 执行sql指令进行查询
//
// 用于多表联查,或其他复杂的情况
//
// @param sqlStr string sql进行查询
// @param values ...any sql中?对应的值
// @return []map[string]any 结果集
// @return error 错误
func QueryMap(sqlStr string, values ...any) ([]map[string]any, error) {
fnd := zorm.NewFinder()
fnd.Append(sqlStr, values...)
fnd.InjectionCheck = false
fnd.GetSQL()
return zorm.QueryMap(ctxDefault, fnd, nil)
}
// ExecuteSql 执行 sql 语句
//
// @param sqlStr string sql进行查询
// @param values ...any sql中?对应的结果
// @return int 返回影响的行数
// @return error 错误
func ExecuteSql(sqlStr string, values ...any) (int, error) {
var cnt int
err := Transaction(func() (err error) {
fnd := zorm.NewFinder()
fnd.Append(sqlStr, values...)
fnd.InjectionCheck = false
fnd.GetSQL()
cnt, err = zorm.UpdateFinder(ctxDefault, fnd)
return err
})
return cnt, err
}
Go
1
https://gitee.com/haifengat/zorm-dm.git
git@gitee.com:haifengat/zorm-dm.git
haifengat
zorm-dm
zorm-dm
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891