query_set_components.go 6.9 KB
package domain

import (
	"fmt"
	"github.com/zeromicro/go-zero/core/collection"
	"strings"
)

var (
	SchemaTable     TableType = "Schema"         // 方案
	SubProcessTable TableType = "SubProcess"     // 子过程
	CalculateItem   TableType = "CalculateItem"  // 计算项
	CalculateTable  TableType = "CalculateTable" // 计算表
	CalculateSet    TableType = "CalculateSet"   // 计算集
)

var (
	FlagGroup = "Group"
	FlagSet   = "Set"
)

var (
	TableSplit   SelectExprType = "TableSplit"   //拆分
	SplitAssign  SelectExprType = "SplitAssign"  //拆分赋值
	NormalAssign SelectExprType = "NormalAssign" //正常赋值
)

type SelectExprType string

type QueryComponent struct {
	Id          string               `json:"id"`
	MasterTable *QueryComponentTable `json:"masterTable"`
	Conditions  []ConditionExpr      `json:"conditions"`
	Selects     []SelectExprGroup    `json:"selects"`
	Description string               `json:"description"`
	Formula     *FieldFormulaExpr    `json:"formula"`
	Aggregation *AggregationRule     `json:"aggregation"`
	Layout      *LayoutRule          `json:"layout"`
}

func (qc *QueryComponent) AllSelectExpr() []SelectExpr {
	var res = make([]SelectExpr, 0)
	for _, s := range qc.Selects {
		res = append(res, s.SelectExpr)
		if len(s.SubSelects) > 0 {
			res = append(res, s.SubSelects...)
		}
	}
	return res
}

type ConditionExpr struct { // 条件表达式
	Id             string    `json:"id"`
	FieldLeft      FieldExpr `json:"fieldLeft"`
	FieldRight     FieldExpr `json:"fieldRight"`
	OperatorSymbol string    `json:"operatorSymbol"`
	AndOr          string    `json:"andOr"` // and or
}

func (c ConditionExpr) Equal(compare ConditionExpr) bool {
	return c.OperatorSymbol == compare.OperatorSymbol &&
		c.FieldLeft.ExprSql == compare.FieldLeft.ExprSql &&
		c.FieldRight.ExprSql == compare.FieldRight.ExprSql
}

func (c ConditionExpr) ExprHuman() string {
	return c.FieldLeft.ExprHuman + c.OperatorSymbol + c.FieldRight.ExprHuman
}

type FieldFormulaExpr struct {
	ExprMode int `json:"exprMode"` // 表达式模式 0:sql 1:excel function
	FieldExpr
}

type SelectExpr struct { // 查询表达式
	Id         string    `json:"id"`
	FieldLeft  FieldExpr `json:"fieldLeft"`
	FieldRight FieldExpr `json:"fieldRight"` // has value when type is equal to 1
	Type       string    `json:"type"`       // 1.拆分 2.拆方赋值 3.正常赋值
}

func (s SelectExpr) Equal(compare SelectExpr) bool {
	return s.FieldLeft.ExprSql == compare.FieldLeft.ExprSql &&
		s.FieldRight.ExprSql == compare.FieldRight.ExprSql
}

func (c SelectExpr) ExprHuman() string {
	return c.FieldLeft.ExprHuman + "=" + c.FieldRight.ExprHuman
}

type SelectExprGroup struct { // 查询表达式
	SelectExpr
	SubSelects []SelectExpr `json:"subSelects,omitempty"`
}

type FieldExpr struct {
	ExprMode    int          `json:"exprMode,omitempty"`
	TableFields []TableField `json:"tableFields"`
	ExprHuman   string       `json:"exprHuman"`
	ExprSql     string       `json:"exprSql"`
}

func (expr *FieldExpr) Complete() string {
	exprSql := expr.ExprSql
	for _, f := range expr.TableFields {
		sql := fmt.Sprintf("%s.%s", f.TableSqlName, f.FieldSqlName)
		sub := fmt.Sprintf("max(%s.%s)", f.TableSqlName, f.FieldSqlName)
		if strings.Contains(expr.ExprSql, fmt.Sprintf("(%s)", sql)) {
			continue
		}
		exprSql = strings.ReplaceAll(exprSql, sql, sub)
	}
	exprSql = RemoveInvalidChar(exprSql)
	return exprSql
}

// RemoveInvalidChar 移除非法字符
// 前台的字符串的一个空格(ASCII:32)被UTF-8编码之后变成了一个诡异的字符(ASCII:194 和 160的组合)
// https://www.cnblogs.com/mingmingruyuedlut/archive/2012/07/04/2575180.html
func RemoveInvalidChar(exprSql string) string {
	tmpValue := string([]byte{0xC2, 0xA0})
	exprSql = strings.ReplaceAll(exprSql, tmpValue, " ")
	return exprSql
}

func (expr *FieldExpr) UpdateTable(t *Table) {
	if t == nil || t.TableId == 0 {
		return
	}
	matchTableName := ""
	for i, f := range expr.TableFields {
		if f.TableId == t.TableId {
			matchTableName = f.TableName
			if f.TableId == t.TableId {
				expr.TableFields[i].TableName = t.Name
			}
		}
	}
	if len(matchTableName) > 0 {
		expr.ExprHuman = strings.ReplaceAll(expr.ExprHuman, matchTableName, t.Name)
	}
}

func (expr *FieldExpr) Tables() []int {
	set := collection.NewSet()
	for _, f := range expr.TableFields {
		if f.TableId == 0 {
			continue
		}
		set.Add(f.TableId)
	}
	return set.KeysInt()
}

func (expr *FieldExpr) MixTableModel() bool {
	var result = 0
	for _, f := range expr.TableFields {
		if strings.HasPrefix(f.TableSqlName, strings.ToLower(CalculateItem.ToString())) {
			if result&1 == 0 {
				result += 1
			}
		} else {
			if result&2 == 0 {
				result += 2
			}
		}
	}
	return result == 3
}

type LabelColumn struct {
	Column    TableField `json:"column,omitempty"`
	LabelExpr string     `json:"labelExpr"`
}

type TableField struct {
	TableId      int    `json:"tableId"`
	TableName    string `json:"tableName"`
	TableSqlName string `json:"tableSqlName"`
	FieldName    string `json:"fieldName"`
	FieldSqlName string `json:"fieldSqlName"`
	FieldSQLType string `json:"fieldSqlType"`
}

func (f TableField) String() string {
	return fmt.Sprintf("%s.%s", f.TableSqlName, f.FieldSqlName)
}

type QueryComponentTable struct {
	// 表Id
	TableId int `json:"tableId"`
	// 表类型 MainTable:主表 SideTable:副表 SubTable:分表  ExcelTable:Excel表
	TableType string `json:"tableType"`
	// 名称
	Name string `json:"name"`
	// 对应数据库名称
	SQLName string `json:"sqlName"`
	// 父级ID
	ParentId int `json:"parentId"`
	// 所有列
	Fields []*Field `json:"fields"`
}

type Join struct {
	TableId      int
	TableName    string
	TableSqlName string
	Conditions   []ConditionExpr
	On           SelectExpr
}

func NewQueryComponentTable(t *Table) *QueryComponentTable {
	return &QueryComponentTable{
		TableId:   t.TableId,
		TableType: t.TableType,
		Name:      t.Name,
		SQLName:   t.SQLName,
		ParentId:  t.ParentId,
		Fields:    t.Fields(false),
	}
}

func QueryComponentsToMapById(items []*QueryComponent) map[string]*QueryComponent {
	var res = make(map[string]*QueryComponent)
	for i := range items {
		res[items[i].Id] = items[i]
	}
	return res
}

func ConditionsToMapById(items []ConditionExpr) map[string]ConditionExpr {
	var res = make(map[string]ConditionExpr)
	for i := range items {
		res[items[i].Id] = items[i]
	}
	return res
}

func SelectsToMapById(items []SelectExprGroup) map[string]SelectExprGroup {
	var res = make(map[string]SelectExprGroup)
	for i := range items {
		res[items[i].Id] = items[i]
	}
	return res
}

func SelectsExprToMapById(items []SelectExpr) map[string]SelectExpr {
	var res = make(map[string]SelectExpr)
	for i := range items {
		res[items[i].Id] = items[i]
	}
	return res
}

type QueryComponents []*QueryComponent

func (list QueryComponents) IsEmpty(t TableType) bool {
	if len(list) == 0 {
		return true
	}
	for _, q := range list {
		switch t {
		case CalculateTable:
			if q.Aggregation != nil && len(q.Aggregation.RowFields) == 0 && len(q.Aggregation.ValueFields) == 0 {
				return true
			}
		}
	}
	return false
}