api2sql基础的能力 #8
@ -10,7 +10,9 @@ package api2sql
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"git.zhangdeman.cn/zhangdeman/consts"
|
"git.zhangdeman.cn/zhangdeman/consts"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/database"
|
||||||
"git.zhangdeman.cn/zhangdeman/database/abstract"
|
"git.zhangdeman.cn/zhangdeman/database/abstract"
|
||||||
"git.zhangdeman.cn/zhangdeman/database/define"
|
"git.zhangdeman.cn/zhangdeman/database/define"
|
||||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||||
@ -23,6 +25,7 @@ var (
|
|||||||
|
|
||||||
type execute struct {
|
type execute struct {
|
||||||
databaseClientManager abstract.IWrapperClient // 全部数据库管理的实例
|
databaseClientManager abstract.IWrapperClient // 全部数据库管理的实例
|
||||||
|
baseDao database.BaseDao // 基础dao
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDatabaseClientManager 设置数据库连接管理实例
|
// SetDatabaseClientManager 设置数据库连接管理实例
|
||||||
@ -72,8 +75,43 @@ func (e *execute) Run(ctx context.Context, inputParam *define.Api2SqlParam) (any
|
|||||||
//
|
//
|
||||||
// Date : 20:52 2024/8/21
|
// Date : 20:52 2024/8/21
|
||||||
func (e *execute) List(ctx context.Context, inputParam *define.Api2SqlParam) (any, error) {
|
func (e *execute) List(ctx context.Context, inputParam *define.Api2SqlParam) (any, error) {
|
||||||
|
var (
|
||||||
return nil, nil
|
err error
|
||||||
|
tx *gorm.DB
|
||||||
|
optionList []database.SetOption
|
||||||
|
)
|
||||||
|
if tx, err = e.getTx(ctx, inputParam); nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if optionList, err = e.getOptionList(ctx, inputParam); nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// 动态生成结果解析结构体
|
||||||
|
st := wrapper.NewDynamic()
|
||||||
|
for _, columnConfig := range inputParam.ColumnList {
|
||||||
|
tag := fmt.Sprintf(`gorm:%v json:%v`, columnConfig.Column, columnConfig.Alias)
|
||||||
|
switch columnConfig.Type {
|
||||||
|
case "int", "int8", "int16", "int32", "int64":
|
||||||
|
st.AddInt(columnConfig.Column, tag, "")
|
||||||
|
case "uint", "uint8", "uint16", "uint32", "uint64":
|
||||||
|
st.AddUint(columnConfig.Column, tag, "")
|
||||||
|
case "bool":
|
||||||
|
st.AddBool(columnConfig.Column, tag, "")
|
||||||
|
case "float":
|
||||||
|
st.AddBool(columnConfig.Column, tag, "")
|
||||||
|
case "string":
|
||||||
|
st.AddString(columnConfig.Column, tag, "")
|
||||||
|
case "map":
|
||||||
|
st.AddMap(columnConfig.Column, tag, "")
|
||||||
|
case "slice":
|
||||||
|
st.AddSlice(columnConfig.Column, tag, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val := st.ToStructDefaultSliceValue()
|
||||||
|
if err = e.baseDao.List(tx, &val, optionList...); nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 详情
|
// Detail 详情
|
||||||
@ -181,26 +219,22 @@ func (e *execute) formatAndValidateInputParam(inputParam *define.Api2SqlParam) e
|
|||||||
//
|
//
|
||||||
// Date : 11:48 2024/8/22
|
// Date : 11:48 2024/8/22
|
||||||
func (e *execute) validateColumn(inputParam *define.Api2SqlParam) error {
|
func (e *execute) validateColumn(inputParam *define.Api2SqlParam) error {
|
||||||
if len(inputParam.ColumnTable) == 0 && wrapper.ArrayType[string]([]string{
|
if len(inputParam.ColumnList) == 0 && wrapper.ArrayType[string]([]string{
|
||||||
consts.SqlTypeList, consts.SqlTypeDetail,
|
consts.SqlTypeList, consts.SqlTypeDetail,
|
||||||
}).Has(inputParam.SqlType) >= 0 {
|
}).Has(inputParam.SqlType) >= 0 {
|
||||||
for _, itemParam := range inputParam.TableColumnConfig {
|
return errors.New("column list is empty")
|
||||||
inputParam.ColumnTable[itemParam.ColumnName] = itemParam.ColumnName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 验证字段是否都正确
|
// 验证字段是否都正确
|
||||||
tableColumnTable := make(map[string]bool)
|
tableColumnTable := make(map[string]bool)
|
||||||
for _, itemColumn := range inputParam.TableColumnConfig {
|
for _, itemColumn := range inputParam.TableColumnConfig {
|
||||||
tableColumnTable[itemColumn.ColumnName] = true
|
tableColumnTable[itemColumn.ColumnName] = true
|
||||||
}
|
}
|
||||||
for columnName, _ := range inputParam.ColumnTable {
|
for _, columnConfig := range inputParam.ColumnList {
|
||||||
if !tableColumnTable[columnName] {
|
if !tableColumnTable[columnConfig.Column] {
|
||||||
return errors.New(columnName + " : input column not found in table column list")
|
return errors.New(columnConfig.Column + " : input column not found in table column list")
|
||||||
}
|
}
|
||||||
}
|
if len(columnConfig.Alias) == 0 {
|
||||||
for _, item := range inputParam.ValueList {
|
columnConfig.Alias = columnConfig.Column
|
||||||
if !tableColumnTable[item.Column] {
|
|
||||||
return errors.New(item.Column + " : input column in `ValueList` is not found in table column list")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -221,3 +255,26 @@ func (e *execute) getTx(ctx context.Context, inputParam *define.Api2SqlParam) (*
|
|||||||
}
|
}
|
||||||
return e.databaseClientManager.GetSlaveClient(ctx, inputParam.DatabaseFlag)
|
return e.databaseClientManager.GetSlaveClient(ctx, inputParam.DatabaseFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getOptionList 设置where条件
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 12:31 2024/8/23
|
||||||
|
func (e *execute) getOptionList(ctx context.Context, inputParam *define.Api2SqlParam) ([]database.SetOption, error) {
|
||||||
|
optionList := []database.SetOption{
|
||||||
|
database.WithTable(inputParam.Table),
|
||||||
|
}
|
||||||
|
// 设置 limit offset
|
||||||
|
if !inputParam.ForceNoLimit && inputParam.Limit > 0 {
|
||||||
|
optionList = append(optionList, database.WithLimit(inputParam.Limit, inputParam.Offset))
|
||||||
|
}
|
||||||
|
for _, item := range inputParam.ConditionList {
|
||||||
|
optionFunc, err := database.WithAnyCondition(item.Column, item.Operate, item.Value)
|
||||||
|
if nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
optionList = append(optionList, optionFunc)
|
||||||
|
}
|
||||||
|
return optionList, nil
|
||||||
|
}
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
// Date : 2024-08-21 16:05
|
// Date : 2024-08-21 16:05
|
||||||
package define
|
package define
|
||||||
|
|
||||||
import "gorm.io/gorm"
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
// Api2SqlParam 接口转sql的输入配置
|
// Api2SqlParam 接口转sql的输入配置
|
||||||
//
|
//
|
||||||
@ -31,44 +33,51 @@ type Api2SqlParam struct {
|
|||||||
Table string `json:"table"` // 操作的数据表
|
Table string `json:"table"` // 操作的数据表
|
||||||
ForceMaster bool `json:"force_master"` // 针对查询语句, 是否强制读主, 如果查询语句在事务中, 默认强制读主
|
ForceMaster bool `json:"force_master"` // 针对查询语句, 是否强制读主, 如果查询语句在事务中, 默认强制读主
|
||||||
InputSql string `json:"input_sql"` // 输入的sql模板, 仅依赖 ValueList 解析字段值, 依赖 split 相关解析分表配置
|
InputSql string `json:"input_sql"` // 输入的sql模板, 仅依赖 ValueList 解析字段值, 依赖 split 相关解析分表配置
|
||||||
TableSplit bool `json:"table_split"` // 是否分表
|
TableSplitConfig TableSplitConfig `json:"table_split_config"` // 分表配置
|
||||||
SplitField string `json:"split_field"` // 分表字段, 仅分表时有效, 分表字段要求在 ValueList 必须存在
|
|
||||||
SplitStrategy string `json:"split_strategy"` // 分表策略, 仅分表时有效, 支持注册自动以策略
|
|
||||||
SqlType string `json:"sql_type"` // sql语句类型 : detail - 查询详情 list - 查询列表 count - 查询数量 update - 更新 insert - 插入 delete - 删除
|
SqlType string `json:"sql_type"` // sql语句类型 : detail - 查询详情 list - 查询列表 count - 查询数量 update - 更新 insert - 插入 delete - 删除
|
||||||
ColumnTable map[string]string `json:"column_list"` // 仅针对 select / detail 有效, 查询的字段列表, 字段名 => 字段别名, 不设置, 则以字段名输出
|
ColumnList []*ColumnConfig `json:"column_list"` // 仅针对 select / detail 有效, 查询的字段列表, 字段名 => 字段别名, 不设置, 则以字段名输出
|
||||||
Limit int64 `json:"limit"` // 操作数据量
|
Limit int `json:"limit"` // 操作数量
|
||||||
Offset int64 `json:"offset"` // 操作偏移量
|
Offset int `json:"offset"` // 操作偏移量
|
||||||
ForceNoLimit bool `json:"force_no_limit"` // 强制允许不限制 : 正常操作 select / delete / update 均需要指定本次操作数据量, 如果确定不限制, 此参数设置为 `true` , sqlType = list , 且 ForceNoLimit = true 时, WithCount 参数无效
|
ForceNoLimit bool `json:"force_no_limit"` // 强制允许不限制 : 正常操作 select / delete / update 均需要指定本次操作数据量, 如果确定不限制, 此参数设置为 `true` , sqlType = list , 且 ForceNoLimit = true 时, WithCount 参数无效
|
||||||
OrderField string `json:"order_field"` // 排序字段, 仅 sqlType = list 生效
|
OrderField string `json:"order_field"` // 排序字段, 仅 sqlType = list 生效
|
||||||
OrderRule string `json:"order_rule"` // 排序规则, Asc / Desc
|
OrderRule string `json:"order_rule"` // 排序规则, Asc / Desc
|
||||||
WithCount bool `json:"with_count"` // 是否返回数据总量, 仅 sqlType = list 生效
|
WithCount bool `json:"with_count"` // 是否返回数据总量, 仅 sqlType = list 生效
|
||||||
ValueList []*Api2SqlParamValue `json:"value_list"` // 字段列表
|
ConditionList []SqlCondition `json:"value_list"` // 字段列表
|
||||||
TableColumnConfig []*ColumnInfo `json:"table_column_config"` // 表字段配置
|
TableColumnConfig []*ColumnInfo `json:"table_column_config"` // 表字段配置
|
||||||
Tx *gorm.DB `json:"-"` // 前后已有的数据库连接, 直接复用
|
Tx *gorm.DB `json:"-"` // 前后已有的数据库连接, 直接复用
|
||||||
}
|
}
|
||||||
|
|
||||||
// Api2SqlParamValue ...
|
// TableSplitConfig 分表配置
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:11 2024/8/21
|
// Date : 14:42 2024/8/23
|
||||||
type Api2SqlParamValue struct {
|
type TableSplitConfig struct {
|
||||||
Column string `json:"column"` // 表字段
|
IsSplit bool `json:"is_split"` // 是否分表
|
||||||
Value any `json:"value"` // 数据字段的值
|
SplitField string `json:"split_field"` // 分表字段, 仅分表时有效, 分表字段要求在 ValueList 必须存在
|
||||||
Operate string `json:"operate"` // 操作符 : Equal , NotEqual , In , NotIn , Like, NotLike
|
FieldValue any `json:"field_value"` // 分表字段值
|
||||||
Alias string `json:"alias"` // 字段对外输出的名字, 不配置, 默认 与 Field 一致, 仅查询语句生效
|
SplitStrategy string `json:"split_strategy"` // 分表策略, 仅分表时有效, 支持注册自动以策略
|
||||||
Default any `json:"-"` // 默认值 TODO : 配置默认值生成策略
|
TableCnt int64 `json:"table_cnt"` // 一共分表多少张
|
||||||
DataMask any `json:"-"` // 数据脱敏策略
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
// SqlCondition sql条件
|
||||||
SqlSelectBaseTpl = `SELECT {FIELD_LIST} FROM {TABLE}` // select 语句基础模板
|
//
|
||||||
SqlInsertBaseTpl = `INSERT INTO {TABLE} ({FIELD_LIST}) VALUES ({VALUE_LIST})` // Insert语句基础模板
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
SqlUpdateBaseTpl = `UPDATE {TABLE} SET {SET}` // Update语句基础模板
|
//
|
||||||
SqlDeleteBaseTpl = `DELETE FROM {TABLE}` // Delete语句基础模板
|
// Date : 14:46 2024/8/23
|
||||||
SqlCountBaseTpl = `SELECT COUNT(*) as count FROM {TABLE}` // Count语句基础模板
|
type SqlCondition struct {
|
||||||
SqlWhereTpl = "WHERE {WHERE}" // where 语句
|
Column string `json:"column"` // 表字段
|
||||||
SqlOrder = "ORDER BY {ORDER_FIELD} {ORDER_RULE}" // 排序语句
|
Operate string `json:"operate"` // 操作 : == / !== / in / not in / like / not like
|
||||||
SqlLimit = "LIMIT {LIMIT}" // limit 语句
|
Value any `json:"value"` // 数据值
|
||||||
SqlOffset = "OFFSET {OFFSET}" // offset 语句
|
}
|
||||||
)
|
|
||||||
|
// ColumnConfig ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 16:42 2024/8/23
|
||||||
|
type ColumnConfig struct {
|
||||||
|
Column string `json:"column"` // 字段名
|
||||||
|
Alias string `json:"alias"` // 字段别名
|
||||||
|
Type string `json:"type"` // 字段类型
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user