作者 yangfu

feat: v1.3.0 calc excel expr

@@ -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 +}