Merge branch 'feat_calc_excel_expr' into test
正在显示
15 个修改的文件
包含
285 行增加
和
66 行删除
| @@ -16,7 +16,7 @@ import ( | @@ -16,7 +16,7 @@ import ( | ||
| 16 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/event" | 16 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/port/event" |
| 17 | ) | 17 | ) |
| 18 | 18 | ||
| 19 | -const Version = "v1.2.0" | 19 | +const Version = "v1.3.0" |
| 20 | 20 | ||
| 21 | func main() { | 21 | func main() { |
| 22 | defer func() { | 22 | defer func() { |
| @@ -13,6 +13,7 @@ import ( | @@ -13,6 +13,7 @@ import ( | ||
| 13 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel" | 13 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel" |
| 14 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks" | 14 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks" |
| 15 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils" | 15 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils" |
| 16 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log" | ||
| 16 | "strings" | 17 | "strings" |
| 17 | "time" | 18 | "time" |
| 18 | ) | 19 | ) |
| @@ -441,7 +442,7 @@ func (querySetService *QuerySetService) CalculateItemPreview(ctx *domain.Context | @@ -441,7 +442,7 @@ func (querySetService *QuerySetService) CalculateItemPreview(ctx *domain.Context | ||
| 441 | if q.Formula.MixTableModel() { | 442 | if q.Formula.MixTableModel() { |
| 442 | q.Formula.ExprSql = q.Formula.Complete() | 443 | q.Formula.ExprSql = q.Formula.Complete() |
| 443 | } | 444 | } |
| 444 | - _, result := GetItemValues(transactionContext, q) | 445 | + _, result := GetItemValues(ctx, transactionContext, q) |
| 445 | if err := transactionContext.CommitTransaction(); err != nil { | 446 | if err := transactionContext.CommitTransaction(); err != nil { |
| 446 | return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | 447 | return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) |
| 447 | } | 448 | } |
| @@ -464,7 +465,7 @@ func (querySetService *QuerySetService) CalculateItemExport(ctx *domain.Context, | @@ -464,7 +465,7 @@ func (querySetService *QuerySetService) CalculateItemExport(ctx *domain.Context, | ||
| 464 | defer func() { | 465 | defer func() { |
| 465 | transactionContext.RollbackTransaction() | 466 | transactionContext.RollbackTransaction() |
| 466 | }() | 467 | }() |
| 467 | - querySet, result := GetItemValues(transactionContext, q) | 468 | + querySet, result := GetItemValues(ctx, transactionContext, q) |
| 468 | if querySet == nil { | 469 | if querySet == nil { |
| 469 | return nil, err | 470 | return nil, err |
| 470 | } | 471 | } |
| @@ -490,7 +491,7 @@ func (querySetService *QuerySetService) CalculateItemExport(ctx *domain.Context, | @@ -490,7 +491,7 @@ func (querySetService *QuerySetService) CalculateItemExport(ctx *domain.Context, | ||
| 490 | }, err | 491 | }, err |
| 491 | } | 492 | } |
| 492 | 493 | ||
| 493 | -func GetItemValues(transactionContext application.TransactionContext, q *query.CalculateItemPreviewQuery) (*domain.QuerySet, []itemValue) { | 494 | +func GetItemValues(ctx *domain.Context, transactionContext application.TransactionContext, q *query.CalculateItemPreviewQuery) (*domain.QuerySet, []itemValue) { |
| 494 | _, querySet, err := factory.FastPgQuerySet(transactionContext, q.QuerySetId) | 495 | _, querySet, err := factory.FastPgQuerySet(transactionContext, q.QuerySetId) |
| 495 | if err != nil { | 496 | if err != nil { |
| 496 | return nil, nil | 497 | return nil, nil |
| @@ -499,8 +500,24 @@ func GetItemValues(transactionContext application.TransactionContext, q *query.C | @@ -499,8 +500,24 @@ func GetItemValues(transactionContext application.TransactionContext, q *query.C | ||
| 499 | if q.Formula.MixTableModel() { | 500 | if q.Formula.MixTableModel() { |
| 500 | q.Formula.ExprSql = q.Formula.Complete() | 501 | q.Formula.ExprSql = q.Formula.Complete() |
| 501 | } | 502 | } |
| 502 | - value := starrocks.CalculateItemValue(starrocks.DB, q.Formula) | ||
| 503 | - | 503 | + var value string |
| 504 | + if q.Formula.ExprMode == domain.ExprModeExcelFunction { | ||
| 505 | + svr, _ := factory.FastQuerySetServices(transactionContext) | ||
| 506 | + dataTable, err := svr.LoadCalculateItemData(ctx, nil, &domain.FieldFormulaExpr{ | ||
| 507 | + FieldExpr: *q.Formula, | ||
| 508 | + ExprMode: q.Formula.ExprMode, | ||
| 509 | + }) | ||
| 510 | + if err != nil { | ||
| 511 | + log.Logger.Error(err.Error()) | ||
| 512 | + } | ||
| 513 | + if dataTable != nil && len(dataTable.Data) > 0 { | ||
| 514 | + if len(dataTable.Data[0]) > 0 { | ||
| 515 | + value = dataTable.Data[0][0] | ||
| 516 | + } | ||
| 517 | + } | ||
| 518 | + } else { | ||
| 519 | + value = starrocks.CalculateItemValue(starrocks.DB, q.Formula) | ||
| 520 | + } | ||
| 504 | var result = make([]itemValue, 0) | 521 | var result = make([]itemValue, 0) |
| 505 | result = append(result, itemValue{ | 522 | result = append(result, itemValue{ |
| 506 | Name: querySet.Name, | 523 | Name: querySet.Name, |
| @@ -10,6 +10,7 @@ import ( | @@ -10,6 +10,7 @@ import ( | ||
| 10 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/dto" | 10 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/dto" |
| 11 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/query" | 11 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/query" |
| 12 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" | 12 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" |
| 13 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain/astexpr" | ||
| 13 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/redis" | 14 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/redis" |
| 14 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks" | 15 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks" |
| 15 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils" | 16 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils" |
| @@ -427,32 +428,40 @@ func (tableService *TableService) ValidExprSql(ctx *domain.Context, cmd *command | @@ -427,32 +428,40 @@ func (tableService *TableService) ValidExprSql(ctx *domain.Context, cmd *command | ||
| 427 | if err := cmd.ValidateCommand(); err != nil { | 428 | if err := cmd.ValidateCommand(); err != nil { |
| 428 | return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | 429 | return nil, application.ThrowError(application.ARG_ERROR, err.Error()) |
| 429 | } | 430 | } |
| 430 | - | ||
| 431 | - set := collection.NewSet() | ||
| 432 | - for _, f := range cmd.TableFields { | ||
| 433 | - set.AddStr(f.TableSqlName) | ||
| 434 | - } | ||
| 435 | - if cmd.MixTableModel() { | ||
| 436 | - cmd.ExprSql = cmd.Complete() | ||
| 437 | - } | ||
| 438 | - selectValue := cmd.ExprSql | ||
| 439 | - //if _, parseErr := strconv.ParseFloat(cmd.ExprSql, 64); parseErr != nil { | ||
| 440 | - // selectValue = "'" + selectValue + "'" | ||
| 441 | - //} | ||
| 442 | - if len(cmd.ExprSql) == 0 { | ||
| 443 | - selectValue = "''" | ||
| 444 | - } | ||
| 445 | - sql := "select " + selectValue + " as expr" | ||
| 446 | - if len(set.KeysStr()) > 0 { | ||
| 447 | - sql += " from " + strings.Join(set.KeysStr(), ",") | ||
| 448 | - sql += " limit 1" | ||
| 449 | - } | ||
| 450 | - tx := starrocks.DB.Exec(sql) | ||
| 451 | - if tx.Error != nil { | ||
| 452 | - return map[string]string{ | ||
| 453 | - "result": tx.Error.Error(), | ||
| 454 | - }, nil | 431 | + switch cmd.FieldExpr.ExprMode { |
| 432 | + case domain.ExprModeSql: | ||
| 433 | + set := collection.NewSet() | ||
| 434 | + for _, f := range cmd.TableFields { | ||
| 435 | + set.AddStr(f.TableSqlName) | ||
| 436 | + } | ||
| 437 | + if cmd.MixTableModel() { | ||
| 438 | + cmd.ExprSql = cmd.Complete() | ||
| 439 | + } | ||
| 440 | + selectValue := cmd.ExprSql | ||
| 441 | + if len(cmd.ExprSql) == 0 { | ||
| 442 | + selectValue = "''" | ||
| 443 | + } | ||
| 444 | + sql := "select " + selectValue + " as expr" | ||
| 445 | + if len(set.KeysStr()) > 0 { | ||
| 446 | + sql += " from " + strings.Join(set.KeysStr(), ",") | ||
| 447 | + sql += " limit 1" | ||
| 448 | + } | ||
| 449 | + tx := starrocks.DB.Exec(sql) | ||
| 450 | + if tx.Error != nil { | ||
| 451 | + return map[string]string{ | ||
| 452 | + "result": tx.Error.Error(), | ||
| 453 | + }, nil | ||
| 454 | + } | ||
| 455 | + case domain.ExprModeExcelFunction: | ||
| 456 | + _, err := astexpr.NewExprAST(cmd.ExprSql) | ||
| 457 | + if err != nil { | ||
| 458 | + return map[string]string{ | ||
| 459 | + "result": err.Error(), | ||
| 460 | + }, nil | ||
| 461 | + } | ||
| 462 | + default: | ||
| 455 | } | 463 | } |
| 464 | + | ||
| 456 | return struct{}{}, nil | 465 | return struct{}{}, nil |
| 457 | } | 466 | } |
| 458 | 467 |
| @@ -4,6 +4,7 @@ import ( | @@ -4,6 +4,7 @@ import ( | ||
| 4 | "fmt" | 4 | "fmt" |
| 5 | "github.com/go-gota/gota/dataframe" | 5 | "github.com/go-gota/gota/dataframe" |
| 6 | "github.com/go-gota/gota/series" | 6 | "github.com/go-gota/gota/series" |
| 7 | + "github.com/shopspring/decimal" | ||
| 7 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" | 8 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" |
| 8 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils" | 9 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils" |
| 9 | "strings" | 10 | "strings" |
| @@ -16,6 +17,17 @@ type Calculator struct { | @@ -16,6 +17,17 @@ type Calculator struct { | ||
| 16 | } | 17 | } |
| 17 | 18 | ||
| 18 | func NewCalculator(expr string) (*Calculator, error) { | 19 | func NewCalculator(expr string) (*Calculator, error) { |
| 20 | + ar, err := NewExprAST(expr) | ||
| 21 | + if err != nil { | ||
| 22 | + return nil, err | ||
| 23 | + } | ||
| 24 | + cal := &Calculator{ | ||
| 25 | + ExprAST: ar, | ||
| 26 | + } | ||
| 27 | + return cal, nil | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +func NewExprAST(expr string) (ExprAST, error) { | ||
| 19 | toks, err := ParseToken(expr) | 31 | toks, err := ParseToken(expr) |
| 20 | if err != nil { | 32 | if err != nil { |
| 21 | return nil, err | 33 | return nil, err |
| @@ -28,11 +40,7 @@ func NewCalculator(expr string) (*Calculator, error) { | @@ -28,11 +40,7 @@ func NewCalculator(expr string) (*Calculator, error) { | ||
| 28 | if ast.Err != nil { | 40 | if ast.Err != nil { |
| 29 | return nil, ast.Err | 41 | return nil, ast.Err |
| 30 | } | 42 | } |
| 31 | - | ||
| 32 | - cal := &Calculator{ | ||
| 33 | - ExprAST: ar, | ||
| 34 | - } | ||
| 35 | - return cal, nil | 43 | + return ar, nil |
| 36 | } | 44 | } |
| 37 | 45 | ||
| 38 | func (cal *Calculator) SetDataTable(t *domain.DataTable) *Calculator { | 46 | func (cal *Calculator) SetDataTable(t *domain.DataTable) *Calculator { |
| @@ -106,19 +114,21 @@ func (cal *Calculator) callDef(name string, args []*param) *param { | @@ -106,19 +114,21 @@ func (cal *Calculator) callDef(name string, args []*param) *param { | ||
| 106 | 114 | ||
| 107 | func (cal *Calculator) sum(params ...*param) *param { | 115 | func (cal *Calculator) sum(params ...*param) *param { |
| 108 | var res = make([]string, 0) | 116 | var res = make([]string, 0) |
| 109 | - var total float64 | 117 | + var total = decimal.NewFromFloat(0) |
| 110 | for _, p := range params { | 118 | for _, p := range params { |
| 111 | for _, v := range p.data { | 119 | for _, v := range p.data { |
| 112 | - total += utils.NewNumberString(v).MustFloat64() | 120 | + dv, _ := decimal.NewFromString(v) |
| 121 | + total = total.Add(dv) | ||
| 113 | } | 122 | } |
| 114 | } | 123 | } |
| 115 | - res = append(res, utils.AssertString(total)) | 124 | + res = append(res, total.String()) |
| 116 | return NewResult(res) | 125 | return NewResult(res) |
| 117 | } | 126 | } |
| 118 | 127 | ||
| 119 | func (cal *Calculator) sumifs(params ...*param) *param { | 128 | func (cal *Calculator) sumifs(params ...*param) *param { |
| 120 | var list = make([]series.Series, 0) | 129 | var list = make([]series.Series, 0) |
| 121 | var filters = make([]dataframe.F, 0) | 130 | var filters = make([]dataframe.F, 0) |
| 131 | + var groupBy = make([]string, 0) | ||
| 122 | for i := 0; i < len(params)-1; i++ { | 132 | for i := 0; i < len(params)-1; i++ { |
| 123 | col := colName(i) | 133 | col := colName(i) |
| 124 | if i == 0 { | 134 | if i == 0 { |
| @@ -126,15 +136,27 @@ func (cal *Calculator) sumifs(params ...*param) *param { | @@ -126,15 +136,27 @@ func (cal *Calculator) sumifs(params ...*param) *param { | ||
| 126 | continue | 136 | continue |
| 127 | } | 137 | } |
| 128 | if i%2 == 1 { | 138 | if i%2 == 1 { |
| 129 | - list = append(list, series.New(params[i+1].Data(), series.String, col)) | ||
| 130 | - if f, ok := cal.resolverFilter(col, params[i]); ok { | ||
| 131 | - filters = append(filters, f) | 139 | + list = append(list, series.New(params[i].Data(), series.String, col)) |
| 140 | + // TODO 类型是行字段判断为按行分组 | ||
| 141 | + if params[i+1].Len() > 1 { | ||
| 142 | + groupBy = append(groupBy, col) | ||
| 143 | + } else { | ||
| 144 | + if f, ok := cal.resolverFilter(col, params[i+1]); ok { | ||
| 145 | + filters = append(filters, f) | ||
| 146 | + } | ||
| 132 | } | 147 | } |
| 133 | i++ | 148 | i++ |
| 134 | } | 149 | } |
| 135 | } | 150 | } |
| 136 | df := dataframe.New(list...) | 151 | df := dataframe.New(list...) |
| 137 | df = df.FilterAggregation(dataframe.And, filters...) | 152 | df = df.FilterAggregation(dataframe.And, filters...) |
| 153 | + if len(groupBy) > 0 { | ||
| 154 | + groups := df.GroupBy(groupBy...) | ||
| 155 | + df = groups.Aggregation([]dataframe.AggregationType{dataframe.Aggregation_SUM}, []string{"A0"}) | ||
| 156 | + s := df.Col("A0_SUM") | ||
| 157 | + return NewResult(toArrayFloat(s.Records())) //4000.00 需要格式化掉后缀 .00 | ||
| 158 | + } | ||
| 159 | + | ||
| 138 | s := df.Col("A0") | 160 | s := df.Col("A0") |
| 139 | return NewResult(s.Records()) | 161 | return NewResult(s.Records()) |
| 140 | } | 162 | } |
| @@ -220,17 +242,21 @@ func (cal *Calculator) OpCalc(op string, lp *param, rp *param) *param { | @@ -220,17 +242,21 @@ func (cal *Calculator) OpCalc(op string, lp *param, rp *param) *param { | ||
| 220 | } | 242 | } |
| 221 | 243 | ||
| 222 | func opCalc(op, v1, v2 string) string { | 244 | func opCalc(op, v1, v2 string) string { |
| 223 | - fv1 := utils.NumberString(v1).MustFloat64() | ||
| 224 | - fv2 := utils.NumberString(v2).MustFloat64() | 245 | + //fv1 := utils.NumberString(v1).MustFloat64() |
| 246 | + //fv2 := utils.NumberString(v2).MustFloat64() | ||
| 247 | + | ||
| 248 | + fv1, _ := decimal.NewFromString(v1) | ||
| 249 | + fv2, _ := decimal.NewFromString(v2) | ||
| 225 | switch op { | 250 | switch op { |
| 226 | case "+": | 251 | case "+": |
| 227 | - return utils.AssertString(fv1 + fv2) | 252 | + |
| 253 | + return utils.AssertString(fv1.Add(fv2).String()) | ||
| 228 | case "-": | 254 | case "-": |
| 229 | - return utils.AssertString(fv1 - fv2) | 255 | + return utils.AssertString(fv1.Sub(fv2).String()) // utils.Round(fv1-fv2, 15) |
| 230 | case "*": | 256 | case "*": |
| 231 | - return utils.AssertString(fv1 * fv2) | 257 | + return utils.AssertString(fv1.Mul(fv2).String()) |
| 232 | case "/": | 258 | case "/": |
| 233 | - return utils.AssertString(fv1 / fv2) | 259 | + return utils.AssertString(fv1.Div(fv2).String()) |
| 234 | } | 260 | } |
| 235 | return "" | 261 | return "" |
| 236 | } | 262 | } |
| @@ -252,3 +278,10 @@ func NewResult(data []string) *param { | @@ -252,3 +278,10 @@ func NewResult(data []string) *param { | ||
| 252 | data: data, | 278 | data: data, |
| 253 | } | 279 | } |
| 254 | } | 280 | } |
| 281 | + | ||
| 282 | +func toArrayFloat(list []string) []string { | ||
| 283 | + for i := range list { | ||
| 284 | + list[i] = utils.AssertString(utils.NewNumberString(list[i]).MustFloat64()) | ||
| 285 | + } | ||
| 286 | + return list | ||
| 287 | +} |
| @@ -125,19 +125,27 @@ func TestSumIfCalculator(t *testing.T) { | @@ -125,19 +125,27 @@ func TestSumIfCalculator(t *testing.T) { | ||
| 125 | want []string | 125 | want []string |
| 126 | }{ | 126 | }{ |
| 127 | { | 127 | { |
| 128 | - expr: `sum(sumifs(销售明细.业绩,"3月",销售明细.月份))`, | 128 | + expr: `sum(sumifs(销售明细.业绩,销售明细.月份,"3月"))`, |
| 129 | want: []string{"40000"}, | 129 | want: []string{"40000"}, |
| 130 | }, | 130 | }, |
| 131 | { | 131 | { |
| 132 | - expr: `sum(sumifs(销售明细.业绩,"3月",销售明细.月份,"<25000",销售明细.业绩))`, | 132 | + expr: `sum(sumifs(销售明细.业绩,销售明细.月份,"3月",销售明细.业绩,"<25000"))`, |
| 133 | want: []string{"40000"}, | 133 | want: []string{"40000"}, |
| 134 | }, | 134 | }, |
| 135 | { | 135 | { |
| 136 | - expr: `sum(sumifs(销售明细.业绩,"3*",销售明细.月份))`, | 136 | + expr: `sum(sumifs(销售明细.业绩,销售明细.月份,"3*"))`, |
| 137 | want: []string{"40000"}, | 137 | want: []string{"40000"}, |
| 138 | }, | 138 | }, |
| 139 | { | 139 | { |
| 140 | - expr: `sum(sumifs(销售明细.业绩,"*月",销售明细.月份))`, | 140 | + expr: `sum(sumifs(销售明细.业绩,销售明细.月份,"*月"))`, |
| 141 | + want: []string{"50000"}, | ||
| 142 | + }, | ||
| 143 | + { | ||
| 144 | + expr: `sumifs(销售明细.业绩,销售明细.月份,销售明细.月份)`, | ||
| 145 | + want: []string{"10000", "40000"}, | ||
| 146 | + }, | ||
| 147 | + { | ||
| 148 | + expr: `sum(sumifs(销售明细.业绩,销售明细.月份,销售明细.月份))`, | ||
| 141 | want: []string{"50000"}, | 149 | want: []string{"50000"}, |
| 142 | }, | 150 | }, |
| 143 | } | 151 | } |
| @@ -202,7 +202,7 @@ func (p *Parser) isDigitNum(c rune) bool { | @@ -202,7 +202,7 @@ func (p *Parser) isDigitNum(c rune) bool { | ||
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | func (p *Parser) isChar(c rune) bool { | 204 | func (p *Parser) isChar(c rune) bool { |
| 205 | - return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '.' || c == '"' || isChineseCharacter(c) | 205 | + return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '.' || c == '"' || isChineseCharacter(c) || c == '_' //|| p.isDigitNum(c) |
| 206 | //判断是汉字 | 206 | //判断是汉字 |
| 207 | } | 207 | } |
| 208 | 208 |
| @@ -89,6 +89,10 @@ func (t *DataTable) Values(f *Field) []string { | @@ -89,6 +89,10 @@ func (t *DataTable) Values(f *Field) []string { | ||
| 89 | index = i | 89 | index = i |
| 90 | break | 90 | break |
| 91 | } | 91 | } |
| 92 | + if t.Fields[i].Name == f.SQLName { | ||
| 93 | + index = i | ||
| 94 | + break | ||
| 95 | + } | ||
| 92 | } | 96 | } |
| 93 | if index < 0 { | 97 | if index < 0 { |
| 94 | return res | 98 | return res |
| @@ -5,6 +5,11 @@ import ( | @@ -5,6 +5,11 @@ import ( | ||
| 5 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant" | 5 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant" |
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | +const ( | ||
| 9 | + ExprModeSql = iota | ||
| 10 | + ExprModeExcelFunction | ||
| 11 | +) | ||
| 12 | + | ||
| 8 | var ( | 13 | var ( |
| 9 | ErrorNotFound = fmt.Errorf("没有此资源") | 14 | ErrorNotFound = fmt.Errorf("没有此资源") |
| 10 | ) | 15 | ) |
| @@ -38,6 +38,16 @@ func (f *Field) SqlTypeEqual(compare *Field) bool { | @@ -38,6 +38,16 @@ func (f *Field) SqlTypeEqual(compare *Field) bool { | ||
| 38 | return false | 38 | return false |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | +func (f *Field) SqlTypeToDB() string { | ||
| 42 | + if f.SQLType == Float.ToString() { | ||
| 43 | + return DECIMALV2.ToString() | ||
| 44 | + } | ||
| 45 | + if f.SQLType == Date.ToString() || f.SQLType == Datetime.ToString() { | ||
| 46 | + return "timestamp" | ||
| 47 | + } | ||
| 48 | + return f.SQLType | ||
| 49 | +} | ||
| 50 | + | ||
| 41 | func (f *Field) Valid() error { | 51 | func (f *Field) Valid() error { |
| 42 | if _, ok := SQLTypeMap[strings.ToUpper(f.SQLType)]; !ok { | 52 | if _, ok := SQLTypeMap[strings.ToUpper(f.SQLType)]; !ok { |
| 43 | return fmt.Errorf("unknown sql type:%v", f.SQLType) | 53 | return fmt.Errorf("unknown sql type:%v", f.SQLType) |
| @@ -68,6 +68,7 @@ func (c ConditionExpr) ExprHuman() string { | @@ -68,6 +68,7 @@ func (c ConditionExpr) ExprHuman() string { | ||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | type FieldFormulaExpr struct { | 70 | type FieldFormulaExpr struct { |
| 71 | + ExprMode int `json:"exprMode"` // 表达式模式 0:sql 1:excel function | ||
| 71 | FieldExpr | 72 | FieldExpr |
| 72 | } | 73 | } |
| 73 | 74 | ||
| @@ -93,6 +94,7 @@ type SelectExprGroup struct { // 查询表达式 | @@ -93,6 +94,7 @@ type SelectExprGroup struct { // 查询表达式 | ||
| 93 | } | 94 | } |
| 94 | 95 | ||
| 95 | type FieldExpr struct { | 96 | type FieldExpr struct { |
| 97 | + ExprMode int `json:"exprMode,omitempty"` | ||
| 96 | TableFields []TableField `json:"tableFields"` | 98 | TableFields []TableField `json:"tableFields"` |
| 97 | ExprHuman string `json:"exprHuman"` | 99 | ExprHuman string `json:"exprHuman"` |
| 98 | ExprSql string `json:"exprSql"` | 100 | ExprSql string `json:"exprSql"` |
| @@ -2,12 +2,12 @@ package domainService | @@ -2,12 +2,12 @@ package domainService | ||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "bytes" | 4 | "bytes" |
| 5 | - | ||
| 6 | "github.com/beego/beego/v2/client/httplib" | 5 | "github.com/beego/beego/v2/client/httplib" |
| 7 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant" | 6 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/constant" |
| 8 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" | 7 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" |
| 9 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/api/bytelib" | 8 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/api/bytelib" |
| 10 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel" | 9 | "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel" |
| 10 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks" | ||
| 11 | ) | 11 | ) |
| 12 | 12 | ||
| 13 | type ByteCoreService struct { | 13 | type ByteCoreService struct { |
| @@ -147,6 +147,12 @@ func (ptr *ByteCoreService) FormulasGenerate(param domain.ReqFormulasGenerate) ( | @@ -147,6 +147,12 @@ func (ptr *ByteCoreService) FormulasGenerate(param domain.ReqFormulasGenerate) ( | ||
| 147 | // } | 147 | // } |
| 148 | // return &domain.DataFormulasGenerate{}, nil | 148 | // return &domain.DataFormulasGenerate{}, nil |
| 149 | //} | 149 | //} |
| 150 | + if param.QuerySet.Type == domain.CalculateItem.ToString() { | ||
| 151 | + if param.QuerySet.QueryComponents[0].Formula.ExprMode != 0 { | ||
| 152 | + err := ptr.ExcelExprCalcPersistence(param.QuerySet.QueryComponents[0].Formula, param, true) | ||
| 153 | + return &domain.DataFormulasGenerate{}, err | ||
| 154 | + } | ||
| 155 | + } | ||
| 150 | if param.QuerySet.Type == domain.CalculateSet.ToString() { | 156 | if param.QuerySet.Type == domain.CalculateSet.ToString() { |
| 151 | _, err := param.QuerySetService.(*QuerySetService).LoadCalculateSetData(param.Context.(*domain.Context), param.QuerySet, param.QueryComponents) | 157 | _, err := param.QuerySetService.(*QuerySetService).LoadCalculateSetData(param.Context.(*domain.Context), param.QuerySet, param.QueryComponents) |
| 152 | if err != nil { | 158 | if err != nil { |
| @@ -162,6 +168,24 @@ func (ptr *ByteCoreService) FormulasClear(param domain.ReqFormulasClear) (*domai | @@ -162,6 +168,24 @@ func (ptr *ByteCoreService) FormulasClear(param domain.ReqFormulasClear) (*domai | ||
| 162 | return apiByteLib.FormulasClear(param) | 168 | return apiByteLib.FormulasClear(param) |
| 163 | } | 169 | } |
| 164 | 170 | ||
| 171 | +func (ptr *ByteCoreService) ExcelExprCalcPersistence(expr *domain.FieldFormulaExpr, param domain.ReqFormulasGenerate, persistence bool) error { | ||
| 172 | + if len(param.QueryComponents) == 0 { | ||
| 173 | + return nil | ||
| 174 | + } | ||
| 175 | + // 加载Tables数据 | ||
| 176 | + q := param.QueryComponents[0] | ||
| 177 | + result, err := param.QuerySetService.(*QuerySetService).LoadCalculateItemData(param.Context.(*domain.Context), param.Table, q.Formula) | ||
| 178 | + if err != nil { | ||
| 179 | + return err | ||
| 180 | + } | ||
| 181 | + if persistence { | ||
| 182 | + starrocks.DropView(starrocks.DB, param.Table.SQLName) | ||
| 183 | + starrocks.DropTable(starrocks.DB, param.Table.SQLName) | ||
| 184 | + return starrocks.Exec(starrocks.DB, starrocks.CreateTableSql(param.Table.SQLName, param.Table.Fields(false), result.Data[0])) | ||
| 185 | + } | ||
| 186 | + return nil | ||
| 187 | +} | ||
| 188 | + | ||
| 165 | ////////////// | 189 | ////////////// |
| 166 | // 字库核心 | 190 | // 字库核心 |
| 167 | ////////////// | 191 | ////////////// |
| @@ -176,6 +176,8 @@ func (ptr *QuerySetService) UpdateCalculateItem(ctx *domain.Context, qs *domain. | @@ -176,6 +176,8 @@ func (ptr *QuerySetService) UpdateCalculateItem(ctx *domain.Context, qs *domain. | ||
| 176 | QuerySet: qs, | 176 | QuerySet: qs, |
| 177 | Table: table, | 177 | Table: table, |
| 178 | QueryComponents: queryComponents, | 178 | QueryComponents: queryComponents, |
| 179 | + QuerySetService: ptr, | ||
| 180 | + Context: ctx, | ||
| 179 | }) | 181 | }) |
| 180 | if err != nil { | 182 | if err != nil { |
| 181 | return err | 183 | return err |
| @@ -751,18 +753,12 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateItemTable(ctx *domain.Context | @@ -751,18 +753,12 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateItemTable(ctx *domain.Context | ||
| 751 | dependencyTables := querySet.GetDependencyTables(queryComponents) | 753 | dependencyTables := querySet.GetDependencyTables(queryComponents) |
| 752 | tableRepository, _ := repository.NewTableRepository(ptr.transactionContext) | 754 | tableRepository, _ := repository.NewTableRepository(ptr.transactionContext) |
| 753 | queryComponent := queryComponents[0] | 755 | queryComponent := queryComponents[0] |
| 754 | - //!!!warning:每个字段默认需要带函数,没有就补全max() | ||
| 755 | - //if queryComponent.Formula.MixTableModel() { | ||
| 756 | - // queryComponent.Formula.Complete() | ||
| 757 | - //} | ||
| 758 | builder := NewDataFieldsBuilder() | 756 | builder := NewDataFieldsBuilder() |
| 759 | - //field := DataField(querySet.Name, domain.String.ToString(), domain.MainTableField, 1) | ||
| 760 | field := builder.NewDataField(querySet.Name, domain.String.ToString(), domain.MainTableField) | 757 | field := builder.NewDataField(querySet.Name, domain.String.ToString(), domain.MainTableField) |
| 761 | if len(queryComponent.Formula.TableFields) > 0 { | 758 | if len(queryComponent.Formula.TableFields) > 0 { |
| 762 | field.SQLType = queryComponent.Formula.TableFields[0].FieldSQLType | 759 | field.SQLType = queryComponent.Formula.TableFields[0].FieldSQLType |
| 763 | } | 760 | } |
| 764 | var table *domain.Table = NewCopyTable(domain.TableType(querySet.Type), querySet.Name, []*domain.Field{field}, 1).WithContext(ctx).WithPrefix(strings.ToLower(querySet.Type)) | 761 | var table *domain.Table = NewCopyTable(domain.TableType(querySet.Type), querySet.Name, []*domain.Field{field}, 1).WithContext(ctx).WithPrefix(strings.ToLower(querySet.Type)) |
| 765 | - //table.PK = nil | ||
| 766 | if querySet.QuerySetInfo.BindTableId > 0 { | 762 | if querySet.QuerySetInfo.BindTableId > 0 { |
| 767 | table, err = tableRepository.FindOne(map[string]interface{}{"context": ctx, "tableId": querySet.QuerySetInfo.BindTableId}) | 763 | table, err = tableRepository.FindOne(map[string]interface{}{"context": ctx, "tableId": querySet.QuerySetInfo.BindTableId}) |
| 768 | if err != nil { | 764 | if err != nil { |
| 1 | +package domainService | ||
| 2 | + | ||
| 3 | +import ( | ||
| 4 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" | ||
| 5 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain/astexpr" | ||
| 6 | +) | ||
| 7 | + | ||
| 8 | +func (ptr *QuerySetService) LoadCalculateItemData(ctx *domain.Context, t *domain.Table, formula *domain.FieldFormulaExpr) (*domain.DataTable, error) { | ||
| 9 | + var ( | ||
| 10 | + res = &domain.DataTable{} | ||
| 11 | + err error | ||
| 12 | + ) | ||
| 13 | + | ||
| 14 | + calc, err := astexpr.NewCalculator(formula.ExprSql) | ||
| 15 | + if err != nil { | ||
| 16 | + return nil, err | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + if len(formula.TableFields) > 0 { | ||
| 20 | + var tableId = formula.TableFields[0].TableId | ||
| 21 | + mapTable, _ := ptr.loadDataTables(ctx, []int{tableId}) | ||
| 22 | + calc.SetDataTable(mapTable[tableId]) | ||
| 23 | + } | ||
| 24 | + result, err := calc.ExprASTResult(calc.ExprAST) | ||
| 25 | + if err != nil { | ||
| 26 | + return nil, err | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + res.Data = [][]string{ | ||
| 30 | + result.Data(), | ||
| 31 | + } | ||
| 32 | + if t != nil { | ||
| 33 | + res.Fields = t.Fields(false) | ||
| 34 | + } | ||
| 35 | + res.Total = int64(len(res.Data)) | ||
| 36 | + // 数据持久化 | ||
| 37 | + return res, nil | ||
| 38 | +} |
| @@ -225,10 +225,10 @@ func FastDataTable(options starrocks.QueryOptions) (*domain.DataTable, error) { | @@ -225,10 +225,10 @@ func FastDataTable(options starrocks.QueryOptions) (*domain.DataTable, error) { | ||
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | func (ptr *QuerySetService) LoadDataTables(ctx *domain.Context, cells []*domain.LayoutCell) (map[int]*domain.DataTable, error) { | 227 | func (ptr *QuerySetService) LoadDataTables(ctx *domain.Context, cells []*domain.LayoutCell) (map[int]*domain.DataTable, error) { |
| 228 | - var ( | ||
| 229 | - dataTables = make(map[int]*domain.DataTable) | ||
| 230 | - tableRepository, _ = repository.NewTableRepository(ptr.transactionContext) | ||
| 231 | - ) | 228 | + //var ( |
| 229 | + // dataTables = make(map[int]*domain.DataTable) | ||
| 230 | + // tableRepository, _ = repository.NewTableRepository(ptr.transactionContext) | ||
| 231 | + //) | ||
| 232 | tableIds := collection.NewSet() | 232 | tableIds := collection.NewSet() |
| 233 | for _, cell := range cells { | 233 | for _, cell := range cells { |
| 234 | if cell.Data == nil || cell.Data.TableField == nil || cell.Data.TableField.TableId == 0 { | 234 | if cell.Data == nil || cell.Data.TableField == nil || cell.Data.TableField.TableId == 0 { |
| @@ -236,8 +236,34 @@ func (ptr *QuerySetService) LoadDataTables(ctx *domain.Context, cells []*domain. | @@ -236,8 +236,34 @@ func (ptr *QuerySetService) LoadDataTables(ctx *domain.Context, cells []*domain. | ||
| 236 | } | 236 | } |
| 237 | tableIds.AddInt(cell.Data.TableField.TableId) | 237 | tableIds.AddInt(cell.Data.TableField.TableId) |
| 238 | } | 238 | } |
| 239 | - if len(tableIds.KeysInt()) > 0 { | ||
| 240 | - _, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": tableIds.KeysInt()}) | 239 | + //if len(tableIds.KeysInt()) > 0 { |
| 240 | + // _, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": tableIds.KeysInt()}) | ||
| 241 | + // if err != nil { | ||
| 242 | + // return nil, err | ||
| 243 | + // } | ||
| 244 | + // for _, t := range tables { | ||
| 245 | + // if _, ok := dataTables[t.TableId]; ok { | ||
| 246 | + // continue | ||
| 247 | + // } | ||
| 248 | + // dataTable, err := FastTable(t) | ||
| 249 | + // if err != nil { | ||
| 250 | + // log.Logger.Error(err.Error()) | ||
| 251 | + // return nil, fmt.Errorf("获取【%s】出现异常:%s", t.Name, err.Error()) | ||
| 252 | + // } | ||
| 253 | + // dataTable.Fields = t.DataFields | ||
| 254 | + // dataTables[t.TableId] = dataTable | ||
| 255 | + // } | ||
| 256 | + //} | ||
| 257 | + return ptr.loadDataTables(ctx, tableIds.KeysInt()) | ||
| 258 | +} | ||
| 259 | + | ||
| 260 | +func (ptr *QuerySetService) loadDataTables(ctx *domain.Context, tableIds []int) (map[int]*domain.DataTable, error) { | ||
| 261 | + var ( | ||
| 262 | + dataTables = make(map[int]*domain.DataTable) | ||
| 263 | + tableRepository, _ = repository.NewTableRepository(ptr.transactionContext) | ||
| 264 | + ) | ||
| 265 | + if len(tableIds) > 0 { | ||
| 266 | + _, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": tableIds}) | ||
| 241 | if err != nil { | 267 | if err != nil { |
| 242 | return nil, err | 268 | return nil, err |
| 243 | } | 269 | } |
| @@ -112,3 +112,50 @@ create view {{.ViewName}}( | @@ -112,3 +112,50 @@ create view {{.ViewName}}( | ||
| 112 | }) | 112 | }) |
| 113 | return html.UnescapeString(buf.String()) | 113 | return html.UnescapeString(buf.String()) |
| 114 | } | 114 | } |
| 115 | + | ||
| 116 | +func DropTable(db *gorm.DB, tableName string) error { | ||
| 117 | + tx := db.Exec("DROP TABLE IF EXISTS " + tableName) | ||
| 118 | + return tx.Error | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +func CreateTableSql(viewName string, fields []*domain.Field, data []string) string { | ||
| 122 | + sql := ` | ||
| 123 | +## DROP VIEW IF EXISTS {{.ViewName}}; | ||
| 124 | +## DROP TABLE IF EXISTS {{.ViewName}}; | ||
| 125 | +Create TABLE {{.ViewName}} ( | ||
| 126 | +id BIGINT, | ||
| 127 | +{{.Field}} | ||
| 128 | +) | ||
| 129 | +UNIQUE KEY(id) | ||
| 130 | +DISTRIBUTED BY HASH(id) BUCKETS 3 | ||
| 131 | +PROPERTIES("replication_num"="1"); | ||
| 132 | + | ||
| 133 | +TRUNCATE TABLE {{.ViewName}}; | ||
| 134 | + | ||
| 135 | +insert into {{.ViewName}} Values {{.Values}} | ||
| 136 | +` | ||
| 137 | + tmp := template.New("ViewCreator") | ||
| 138 | + tmp.Parse(sql) | ||
| 139 | + | ||
| 140 | + buf := bytes.NewBuffer(nil) | ||
| 141 | + bufField := bytes.NewBuffer(nil) | ||
| 142 | + for i, f := range fields { | ||
| 143 | + bufField.WriteString(fmt.Sprintf(`%s VARCHAR(65533)`, f.SQLName)) //, f.SqlTypeToDB() | ||
| 144 | + if i != len(fields)-1 { | ||
| 145 | + bufField.WriteString(",\n") | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + bufInsert := bytes.NewBuffer(nil) | ||
| 150 | + for _, d := range data { | ||
| 151 | + id, _ := utils.NewSnowflakeId() | ||
| 152 | + bufInsert.WriteString(fmt.Sprintf("(%d,'%s')", id, d)) | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + tmp.Execute(buf, map[string]interface{}{ | ||
| 156 | + "ViewName": viewName, | ||
| 157 | + "Field": bufField.String(), | ||
| 158 | + "Values": bufInsert.String(), | ||
| 159 | + }) | ||
| 160 | + return html.UnescapeString(buf.String()) | ||
| 161 | +} |
-
请 注册 或 登录 后发表评论