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"`   // 字段类型
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user