作者 yangfu

feat:formula create

... ... @@ -15,7 +15,7 @@ import (
_ "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/beego"
)
const Version = "v1.0.1"
const Version = "v1.2.0"
func main() {
defer func() {
... ...
... ... @@ -13,6 +13,8 @@ type QuerySetDetailDto struct {
Name string `json:"name"`
// 查询组件
QueryComponents []*domain.QueryComponent `json:"queryComponents"`
// 查询集绑定的表
TableId int `json:"tableId"`
}
func (d *QuerySetDetailDto) Load(m *domain.QuerySet) *QuerySetDetailDto {
... ... @@ -21,5 +23,8 @@ func (d *QuerySetDetailDto) Load(m *domain.QuerySet) *QuerySetDetailDto {
d.Flag = m.Flag
d.Name = m.Name
d.QueryComponents = m.QueryComponents
if m.QuerySetInfo != nil {
d.TableId = m.QuerySetInfo.BindTableId
}
return d
}
... ...
... ... @@ -426,7 +426,6 @@ func (tableService *TableService) ValidExprSql(ctx *domain.Context, cmd *command
if err := cmd.ValidateCommand(); err != nil {
return nil, application.ThrowError(application.ARG_ERROR, err.Error())
}
var result string = "成功"
set := collection.NewSet()
for _, f := range cmd.TableFields {
... ... @@ -439,11 +438,11 @@ func (tableService *TableService) ValidExprSql(ctx *domain.Context, cmd *command
sql += " limit 1"
tx := starrocks.DB.Exec(sql)
if tx.Error != nil {
result = tx.Error.Error()
return map[string]string{
"result": tx.Error.Error(),
}, nil
}
return map[string]string{
"result": result,
}, nil
return struct{}{}, nil
}
func NewTableService(options map[string]interface{}) *TableService {
... ...
... ... @@ -12,6 +12,8 @@ type ByteLibService interface {
CancelFile(param ReqCancelFile) (*DataCancelFile, error)
EditTableData(param ReqEditTableData) (*DataEditTableData, error)
FieldOptionalValues(param ReqFieldOptionalValues) (*DataFieldOptionalValues, error)
FormulasGenerate(param ReqFormulasGenerate) (*DataFormulasGenerate, error)
FormulasClear(param ReqFormulasClear) (*DataFormulasClear, error)
}
type (
... ... @@ -267,3 +269,24 @@ func ToFields(fields []*Field) []*Field {
// }
// return result
//}
type (
ReqFormulasGenerate struct {
QuerySet *QuerySet
Table *Table
QueryComponents []*QueryComponent
}
DataFormulasGenerate struct {
FormulaName string `json:"formulaName"`
}
)
type (
ReqFormulasClear struct {
QuerySetId int
}
DataFormulasClear struct {
}
)
... ...
... ... @@ -259,3 +259,16 @@ func MakeToInterfaces(fields []*Field) func([]string) []interface{} {
return output
}
}
func RangeFields(fields []*Field, set ...func(*Field)) []*Field {
for i := range fields {
for j := range set {
set[j](fields[i])
}
}
return fields
}
func ChangeFieldFlag(f *Field) {
f.Flag = MainTableField
}
... ...
... ... @@ -97,7 +97,9 @@ func ValidQuerySetFlag(t string) error {
func (querySet *QuerySet) GetDependencyTables(queryComponents []*QueryComponent) []int {
set := collection.NewSet()
for i := range queryComponents {
set.AddInt(queryComponents[i].MasterTable.TableId)
for _, c := range queryComponents[i].Conditions {
for _, f := range c.FieldLeft.TableFields {
set.AddInt(f.TableId)
... ...
package domain
import "fmt"
var (
SchemaTable TableType = "Schema"
SubProcessTable TableType = "SubProcess"
... ... @@ -97,6 +99,11 @@ type TableField struct {
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 {
... ...
... ... @@ -248,3 +248,33 @@ func (gateway ApiByteLib) FieldOptionalValues(param domain.ReqFieldOptionalValue
}
return &response, nil
}
func (gateway ApiByteLib) FormulasGenerate(param domain.ReqFormulasGenerate) (*domain.DataFormulasGenerate, error) {
url := gateway.Host() + "/formulas/generate"
method := "post"
var data FormulasGenerateResponse
request := NewFormulasGenerateRequest(param.Table, param.QueryComponents)
err := gateway.FastDoRequest(url, method, request, &data)
if err != nil {
return nil, err
}
var response = domain.DataFormulasGenerate{
FormulaName: data.FormulaName,
}
return &response, nil
}
func (gateway ApiByteLib) FormulasClear(param domain.ReqFormulasClear) (*domain.DataFormulasClear, error) {
url := gateway.Host() + "/formulas/generate"
method := "post"
var data FormulasGenerateResponse
request := FormulasClearRequest{
FormulaId: intToString(param.QuerySetId),
}
err := gateway.FastDoRequest(url, method, request, &data)
if err != nil {
return nil, err
}
var response = domain.DataFormulasClear{}
return &response, nil
}
... ...
... ... @@ -309,6 +309,7 @@ type (
SplitTableName string `json:"splitTableName"`
DatabaseTableFieldSchemas []FieldSchema `json:"databaseTableFieldSchemas"`
SplitTableFieldSchemas []FieldSchema `json:"splitTableFieldSchemas"`
ManuallyFieldSchemas []FieldSchema `json:"manuallyFieldSchemas"`
}
SplitTableResponse struct{}
... ... @@ -329,7 +330,8 @@ func NewSplitTableRequest(param domain.ReqSplitTable) SplitTableRequest {
DatabaseTableName: param.FromTable.SQLName,
SplitTableName: param.ToSubTable.SQLName,
DatabaseTableFieldSchemas: ToFieldSchemas(param.FromTable.DataFields),
SplitTableFieldSchemas: ToFieldSchemas(param.ToSubTable.DataFields),
SplitTableFieldSchemas: ToFieldSchemas(param.ToSubTable.Fields(false)),
ManuallyFieldSchemas: ToFieldSchemas(param.ToSubTable.ManualFields),
}
}
... ... @@ -359,3 +361,11 @@ func NewCheckoutTablesFilterColumnDataRequest(param domain.ReqFieldOptionalValue
FilterParameters: map[string]string{"keyWord": param.Match},
}
}
type (
FormulasClearRequest struct {
FormulaId string `json:"formulaId"`
}
FormulasClearResponse struct {
}
)
... ...
package bytelib
import (
"fmt"
"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
"strings"
)
type (
FormulasGenerateRequest struct {
FormulaId string `json:"formulaId"`
FormulaName string `json:"formulaName"`
FormulaType int `json:"formulaType"` //公式类型 1.方案2.子过程
FormulaConditions []FormulaCondition `json:"formulaConditions"`
}
FormulasGenerateResponse struct {
FormulaName string `json:"formulaName"`
}
FormulaCondition struct {
FormulaSelectFields FormulaSelectFields `json:"formulaSelectFields"`
FormulaSelectConditions []FormulaSelectCondition `json:"formulaSelectConditions"`
FormulaDataHandleRules []FormulaDataHandleRule `json:"formulaDataHandleRules"`
}
// FormulaSelectFields 公式select字段
FormulaSelectFields struct {
DatabaseTableName string `json:"databaseTableName"`
FieldSchemas []FieldSchema `json:"fieldSchemas"`
}
FormulaSelectCondition struct {
ConditionLeftField FormulaField `json:"conditionLeftField"`
ConditionOperator string `json:"conditionOperator"`
ConditionRightField FormulaField `json:"conditionRightField"`
AndOr string `json:"andOr"`
}
FormulaDataHandleRule struct {
RuleType int `json:"ruleType"` //Int, 规则类型 1.拆分赋值2.正常赋值
FormulaJoinCondition FormulaJoinCondition `json:"formulaJoinCondition"` // 拆分赋值
AssignValueCondition AssignValueCondition `json:"assignValueCondition"` // 正常赋值
}
// FormulaJoinCondition 拆分链接条件
FormulaJoinCondition struct {
ConditionLeftField FormulaField `json:"conditionLeftField"`
ConditionRightField FormulaField `json:"conditionRightField"`
JoinAssignValues []AssignValueCondition `json:"joinAssignValues"`
}
// AssignValueCondition 拆分规则
AssignValueCondition struct {
ConditionLeftField FormulaField `json:"conditionLeftField"`
ConditionRightField FormulaField `json:"conditionRightField"`
}
// FormulaField 公式字段
FormulaField struct {
DatabaseTableName string `json:"databaseTableName"`
FieldSchema FieldSchema `json:"fieldSchema"`
ConditionExpression string `json:"conditionExpression"`
}
)
func NewFormulasGenerateRequest(table *domain.Table, queryComponents []*domain.QueryComponent) FormulasGenerateRequest {
var formatFormulaName = func(input string) string {
sep := fmt.Sprintf("_c%d", table.Context.CompanyId)
before := strings.Split(input, sep)
if len(before) >= 2 {
return before[0] + sep
}
return input
}
var req = FormulasGenerateRequest{
FormulaId: intToString(table.TableId),
FormulaName: formatFormulaName(table.SQLName),
FormulaType: 0,
FormulaConditions: make([]FormulaCondition, 0),
}
if table.TableType == domain.SchemaTable.ToString() {
req.FormulaType = 1
} else {
req.FormulaType = 2
}
for i := range queryComponents {
req.FormulaConditions = append(req.FormulaConditions, NewFormulaCondition(queryComponents[i]))
}
return req
}
func NewFormulaCondition(queryComponent *domain.QueryComponent) FormulaCondition {
var res = FormulaCondition{
FormulaSelectFields: NewFormulaSelectFields(queryComponent.MasterTable),
FormulaSelectConditions: make([]FormulaSelectCondition, 0),
FormulaDataHandleRules: make([]FormulaDataHandleRule, 0),
}
for _, c := range queryComponent.Conditions {
res.FormulaSelectConditions = append(res.FormulaSelectConditions, NewFormulaSelectCondition(c))
}
for _, s := range queryComponent.Selects {
res.FormulaDataHandleRules = append(res.FormulaDataHandleRules, NewFormulaDataHandleRule(s))
}
return res
}
func NewFormulaSelectFields(t domain.QueryComponentTable) FormulaSelectFields {
var res = FormulaSelectFields{
DatabaseTableName: t.SQLName,
FieldSchemas: ToFieldSchemas(t.Fields),
}
return res
}
func NewFormulaSelectCondition(c domain.ConditionExpr) FormulaSelectCondition {
var res = FormulaSelectCondition{
ConditionOperator: c.OperatorSymbol,
AndOr: c.AndOr,
ConditionLeftField: NewFormulaField(c.FieldLeft, true),
ConditionRightField: NewFormulaField(c.FieldRight),
}
return res
}
func NewFormulaField(f domain.FieldExpr, args ...interface{}) FormulaField {
var res = FormulaField{
DatabaseTableName: "",
FieldSchema: FieldSchema{},
ConditionExpression: f.ExprSql,
}
// 字段包含多个列
if len(f.TableFields) > 0 {
res.DatabaseTableName = f.TableFields[0].TableSqlName
res.FieldSchema = NewFieldSchema(f.TableFields[0])
}
if len(args) >= 1 && len(f.TableFields) >= 1 {
// set ConditionExpression empty
if args[0].(bool) && f.ExprSql == f.TableFields[0].String() {
res.ConditionExpression = ""
}
}
return res
}
func NewFieldSchema(f domain.TableField) FieldSchema {
var res = FieldSchema{
FieldZhName: f.FieldName,
FieldEnName: f.FieldSqlName,
FieldType: f.FieldSQLType,
FieldDescription: "",
IsAllowNull: true,
}
return res
}
func NewFormulaDataHandleRule(s domain.SelectExprGroup) FormulaDataHandleRule {
var res = FormulaDataHandleRule{
RuleType: 1,
}
if s.Type == string(domain.TableSplit) {
res.RuleType = 1
res.FormulaJoinCondition = NewFormulaJoinCondition(s)
}
if s.Type == string(domain.NormalAssign) {
res.RuleType = 2
res.AssignValueCondition = NewAssignValueCondition(s.SelectExpr)
}
return res
}
func NewFormulaJoinCondition(s domain.SelectExprGroup) FormulaJoinCondition {
var res = FormulaJoinCondition{
ConditionLeftField: NewFormulaField(s.FieldLeft, true),
ConditionRightField: NewFormulaField(s.FieldRight),
}
for _, sub := range s.SubSelects {
res.JoinAssignValues = append(res.JoinAssignValues, NewAssignValueCondition(sub))
}
return res
}
func NewAssignValueCondition(selectExpr domain.SelectExpr) AssignValueCondition {
var res = AssignValueCondition{
ConditionLeftField: NewFormulaField(selectExpr.FieldLeft, true),
ConditionRightField: NewFormulaField(selectExpr.FieldRight),
}
return res
}
... ...
... ... @@ -126,6 +126,16 @@ func (ptr *ByteCoreService) FieldOptionalValues(param domain.ReqFieldOptionalVal
return apiByteLib.FieldOptionalValues(param)
}
func (ptr *ByteCoreService) FormulasGenerate(param domain.ReqFormulasGenerate) (*domain.DataFormulasGenerate, error) {
apiByteLib := bytelib.NewApiByteLib(constant.BYTE_CORE_HOST)
return apiByteLib.FormulasGenerate(param)
}
func (ptr *ByteCoreService) FormulasClear(param domain.ReqFormulasClear) (*domain.DataFormulasClear, error) {
apiByteLib := bytelib.NewApiByteLib(constant.BYTE_CORE_HOST)
return apiByteLib.FormulasClear(param)
}
//////////////
// 字库核心
//////////////
... ...
... ... @@ -100,6 +100,22 @@ func (ptr *QuerySetService) Update(ctx *domain.Context, querySetId int, queryCom
}
// 调用底层的组装sql
formulasGenerateResponse, err := ByteCore.FormulasGenerate(domain.ReqFormulasGenerate{
QuerySet: qs,
Table: table,
QueryComponents: queryComponents,
})
if err != nil {
return err
}
if len(formulasGenerateResponse.FormulaName) > 0 && formulasGenerateResponse.FormulaName != table.SQLName {
table.SQLName = formulasGenerateResponse.FormulaName
tableRepository, _ := repository.NewTableRepository(ptr.transactionContext)
table, err = tableRepository.Save(table)
if err != nil {
return err
}
}
// 生成日志
if err = ptr.UpdateQuerySetLog(ctx, qs, queryComponents); err != nil {
... ... @@ -311,7 +327,7 @@ func (ptr *QuerySetService) CreateOrUpdateQuerySetTable(ctx *domain.Context, que
return nil, err
}
masterTable = domain.NewQueryComponentTable(foundMasterTable)
var table *domain.Table = NewTable(domain.TableType(querySet.Type), querySet.Name, masterTable.Fields, 0).WithContext(ctx).WithPrefix(strings.ToLower(querySet.Type))
var table *domain.Table = NewTable(domain.TableType(querySet.Type), querySet.Name, domain.RangeFields(masterTable.Fields, domain.ChangeFieldFlag), 0).WithContext(ctx).WithPrefix(strings.ToLower(querySet.Type))
if querySet.QuerySetInfo.BindTableId > 0 {
table, err = tableRepository.FindOne(map[string]interface{}{"context": ctx, "tableId": querySet.QuerySetInfo.BindTableId})
if err != nil {
... ... @@ -320,22 +336,37 @@ func (ptr *QuerySetService) CreateOrUpdateQuerySetTable(ctx *domain.Context, que
table.DataFields = masterTable.Fields
table.UpdatedAt = time.Now()
}
// 循环依赖判断
tableDependencyService, _ := NewTableDependencyService(ptr.transactionContext)
var validTables = make([]*domain.Table, 0)
if len(dependencyTables) > 0 {
_, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": dependencyTables, "tableTypes": []string{domain.SchemaTable.ToString(), domain.SubProcessTable.ToString()}})
_, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": dependencyTables})
if err != nil {
return nil, err
}
if len(tables) > 0 {
tree := tableDependencyService.TableDependTree(tables, querySet.QuerySetInfo.BindTableId)
if tableDependencyService.Detect(ctx, tree.EdgesArray()) {
return nil, NewCircleDependError(tableDependencyService.CircleTable(), querySet)
tableMap := make(map[int]*domain.Table)
for i := range tables {
tableMap[tables[i].TableId] = tables[i]
}
for _, c := range queryComponents {
if t, ok := tableMap[c.MasterTable.TableId]; ok {
c.MasterTable = domain.NewQueryComponentTable(t)
}
}
for _, t := range validTables {
if t.TableType == domain.SchemaTable.ToString() || t.TableType == domain.SubProcessTable.ToString() {
validTables = append(validTables, t)
}
}
}
// 循环依赖判断
tableDependencyService, _ := NewTableDependencyService(ptr.transactionContext)
if len(validTables) > 0 {
tree := tableDependencyService.TableDependTree(validTables, querySet.QuerySetInfo.BindTableId)
if tableDependencyService.Detect(ctx, tree.EdgesArray()) {
return nil, NewCircleDependError(tableDependencyService.CircleTable(), querySet)
}
}
table.TableInfo.ApplyOnModule = domain.ModuleAll
table.TableInfo.DependencyTables = dependencyTables
table, err = tableRepository.Save(table)
... ... @@ -392,6 +423,22 @@ func (ptr *QuerySetService) ChangeStatus(ctx *domain.Context, querySetId int, st
if err != nil {
return err
}
if qs.QuerySetInfo.BindTableId != 0 {
tableRepository, _ := repository.NewTableRepository(ptr.transactionContext)
table, err := tableRepository.FindOne(map[string]interface{}{"tableId": qs.QuerySetInfo.BindTableId})
if err != nil {
return err
}
if status == domain.StatusOn {
table.TableInfo.SetApplyOn(domain.ModuleAll)
} else {
table.TableInfo.SetApplyOn(domain.ModuleQuerySetCenter | domain.ModuleCalculateCenter)
}
if _, err = tableRepository.Save(table); err != nil {
return err
}
}
return nil
}
... ... @@ -417,14 +464,37 @@ func (ptr *QuerySetService) Copy(ctx *domain.Context, querySetId int, t string,
if found, foundErr := querySetRepository.FindOne(options); foundErr == nil && found != nil && found.Name == name {
return ErrQuerySetNameExists
}
// TODO:create-table
if copy.QuerySetInfo.BindTableId != 0 {
tableRepository, _ := repository.NewTableRepository(ptr.transactionContext)
table, err := tableRepository.FindOne(map[string]interface{}{"tableId": copy.QuerySetInfo.BindTableId})
if err != nil {
return err
}
NewTable(domain.TableType(t), name, table.DataFields, 0).WithContext(ctx)
copyTable := NewTable(domain.TableType(t), name, table.Fields(false), 0).WithContext(ctx).WithPrefix(qs.Type)
copyTable, err = tableRepository.Save(copyTable)
if err != nil {
return err
}
// 调用底层的组装sql
formulasGenerateResponse, err := ByteCore.FormulasGenerate(domain.ReqFormulasGenerate{
QuerySet: qs,
Table: table,
QueryComponents: qs.QueryComponents,
})
if err != nil {
return err
}
if len(formulasGenerateResponse.FormulaName) > 0 && formulasGenerateResponse.FormulaName != table.SQLName {
copyTable.SQLName = formulasGenerateResponse.FormulaName
tableRepository, _ := repository.NewTableRepository(ptr.transactionContext)
copyTable, err = tableRepository.Save(copyTable)
if err != nil {
return err
}
}
copy.QuerySetInfo.BindTableId = copyTable.TableId
}
_, err = querySetRepository.Save(copy)
if err != nil {
... ... @@ -469,6 +539,9 @@ func (ptr *QuerySetService) Delete(ctx *domain.Context, querySetId int) error {
if err := dao.TableSoftDelete(ptr.transactionContext, querySets[i].QuerySetInfo.BindTableId, domain.TableType(querySets[i].Type)); err != nil {
return err
}
ByteCore.FormulasClear(domain.ReqFormulasClear{
QuerySetId: querySets[i].QuerySetId,
})
}
}
// 日志
... ... @@ -620,3 +693,21 @@ func (ptr *QuerySetService) GetAllChild(ctx *domain.Context, querySetId int, inc
}
return result, nil
}
/*
DROP VIEW IF EXISTS schema_xiao_shou_ming_xi_fen_biao_t456157_c1;
create view schema_xiao_shou_ming_xi_fen_biao_t456157_c1(
hui_zong_qu_yu_c5 COMMENT "汇总区域"
) as(
WITH xiao_shou_ming_xi_fen_biao_t456157_c1 AS (
SELECT
IF
( ke_hu_dui_zhao_biao_t969072_c1.hui_zong_qu_yu_c5 IS NULL, xiao_shou_ming_xi_fen_biao_t456157_c1.yuan_gong_bian_ma_c4, ke_hu_dui_zhao_biao_t969072_c1.hui_zong_qu_yu_c5 ) hui_zong_qu_yu_c5
FROM
xiao_shou_ming_xi_fen_biao_t456157_c1
LEFT JOIN ke_hu_dui_zhao_biao_t969072_c1 ON xiao_shou_ming_xi_fen_biao_t456157_c1.ke_hu_bian_ma_c14 = ke_hu_dui_zhao_biao_t969072_c1.jin_die_ke_hu_bian_ma_c3
)
SELECT *
FROM
xiao_shou_ming_xi_fen_biao_t456157_c1
*/
... ...