优化结构

This commit is contained in:
Yvan
2026-08-27 22:33:43 +08:00
parent 5052835fcb
commit e407d3ac10
86 changed files with 3151 additions and 726 deletions
+90
View File
@@ -2,9 +2,21 @@ package system
import (
"context"
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"
"time"
)
var (
exportIdentifierPattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)?$`)
exportParameterPattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)
exportColumnPattern = regexp.MustCompile(`(?i)^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)?(\s+AS\s+[A-Za-z_][A-Za-z0-9_]*)?$`)
exportJoinOnPattern = regexp.MustCompile(`(?i)^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*\s*=\s*[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*(\s+AND\s+[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*\s*=\s*[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*)*$`)
)
type ExportCondition struct {
ID uint
CreatedAt, UpdatedAt time.Time
@@ -43,3 +55,81 @@ type ExportRepo interface {
type ExportUsecase struct{ ExportRepo }
func NewExportUsecase(repo ExportRepo) *ExportUsecase { return &ExportUsecase{ExportRepo: repo} }
func ValidateExportTemplate(value *ExportTemplate) error {
if value == nil {
return errors.New("导出模板为空")
}
if strings.TrimSpace(value.Name) == "" || strings.TrimSpace(value.TemplateID) == "" {
return errors.New("导出模板名称和模板 ID 不能为空")
}
if !exportIdentifierPattern.MatchString(strings.TrimSpace(value.TableName)) {
return errors.New("导出模板表名不合法")
}
if strings.TrimSpace(value.DBName) != "" && !exportIdentifierPattern.MatchString(strings.TrimSpace(value.DBName)) {
return errors.New("导出模板数据库别名不合法")
}
if strings.TrimSpace(value.SQL) != "" || strings.TrimSpace(value.ImportSQL) != "" {
return errors.New("导出模板不允许自定义 SQL")
}
var columns map[string]string
if err := json.Unmarshal([]byte(value.TemplateInfo), &columns); err != nil {
return fmt.Errorf("导出模板列定义无效: %w", err)
}
if len(columns) == 0 {
return errors.New("导出模板列为空")
}
for column := range columns {
if !exportColumnPattern.MatchString(strings.TrimSpace(column)) {
return fmt.Errorf("导出模板列不合法: %s", column)
}
}
for _, join := range value.Joins {
kind := strings.ToUpper(strings.Join(strings.Fields(join.Join), " "))
switch kind {
case "JOIN", "INNER JOIN", "LEFT JOIN", "RIGHT JOIN":
default:
return fmt.Errorf("导出模板 Join 类型不合法: %s", join.Join)
}
if !exportIdentifierPattern.MatchString(strings.TrimSpace(join.Table)) || !exportJoinOnPattern.MatchString(strings.TrimSpace(join.On)) {
return errors.New("导出模板 Join 表或条件不合法")
}
}
for _, condition := range value.Conditions {
if !exportParameterPattern.MatchString(strings.TrimSpace(condition.From)) || !exportIdentifierPattern.MatchString(strings.TrimSpace(condition.Column)) {
return errors.New("导出模板筛选字段不合法")
}
switch strings.ToUpper(strings.Join(strings.Fields(condition.Operator), " ")) {
case "=", "!=", "<>", ">", ">=", "<", "<=", "LIKE", "IN", "NOT IN", "BETWEEN":
default:
return fmt.Errorf("导出模板筛选运算符不合法: %s", condition.Operator)
}
}
if value.Limit != nil && (*value.Limit < 1 || *value.Limit > 100000) {
return errors.New("导出模板行数限制必须在 1 到 100000 之间")
}
if order := strings.TrimSpace(value.Order); order != "" {
parts := strings.Fields(order)
if len(parts) > 2 || !exportIdentifierPattern.MatchString(parts[0]) {
return errors.New("导出模板排序不合法")
}
if len(parts) == 2 && !strings.EqualFold(parts[1], "asc") && !strings.EqualFold(parts[1], "desc") {
return errors.New("导出模板排序方向不合法")
}
}
return nil
}
func (uc *ExportUsecase) CreateExportTemplate(ctx context.Context, value *ExportTemplate) error {
if err := ValidateExportTemplate(value); err != nil {
return err
}
return uc.ExportRepo.CreateExportTemplate(ctx, value)
}
func (uc *ExportUsecase) UpdateExportTemplate(ctx context.Context, value *ExportTemplate) error {
if err := ValidateExportTemplate(value); err != nil {
return err
}
return uc.ExportRepo.UpdateExportTemplate(ctx, value)
}