正在显示
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 | +} |
-
请 注册 或 登录 后发表评论