合并分支 'test' 到 'master'
Test 查看合并请求 !4
正在显示
19 个修改的文件
包含
555 行增加
和
18 行删除
@@ -162,6 +162,97 @@ | @@ -162,6 +162,97 @@ | ||
162 | - [ ] 10W .. | 162 | - [ ] 10W .. |
163 | - [ ] 保存单个文件、压缩 | 保存多个文件、压缩 | 163 | - [ ] 保存单个文件、压缩 | 保存多个文件、压缩 |
164 | 164 | ||
165 | +## 表达式解析 | ||
166 | + | ||
167 | +### 表达式类型说明 | ||
168 | +- ValueExprAST: 值表达式(数值,字符串) e.g. 1 、 2011-1-1 、字符串 | ||
169 | +```json | ||
170 | +{ | ||
171 | + "exprType":"ValueExprAST", | ||
172 | + "val":"", | ||
173 | + "str":"业绩2" | ||
174 | +} | ||
175 | +``` | ||
176 | +- FieldExprAST: 字段表达式(处理的字段) e.g. 生产明细.业绩 | ||
177 | +```json | ||
178 | +{ | ||
179 | + "exprType":"FieldExprAST", | ||
180 | + "str":"业绩1", | ||
181 | + "field":{ | ||
182 | + "tableId":1, | ||
183 | + "tableName":"测试ABC", | ||
184 | + "tableSqlName":"table_abc_test", | ||
185 | + "fieldName":"业绩", | ||
186 | + "fieldSqlName":"ye_ji_1", | ||
187 | + "fieldSqlType":"Float" | ||
188 | + } | ||
189 | +} | ||
190 | +``` | ||
191 | +- BinaryExprAST: 二元表达式 e.g. 1 + 2 、 100 * 生产明细.业绩 | ||
192 | +```json | ||
193 | +{ | ||
194 | + "exprType":"BinaryExprAST", | ||
195 | + "op":"/", | ||
196 | + "lhs":{}, | ||
197 | + "rhs":{} | ||
198 | +} | ||
199 | +``` | ||
200 | + | ||
201 | +- FunCallerExprAST:函数表达式 e.g. sum(arg1,arg2,arg3) | ||
202 | +```json | ||
203 | +{ | ||
204 | + "arrayFlag": false, | ||
205 | + "exprType": "FunCallerExprAST", | ||
206 | + "name": "sum", | ||
207 | + "args": [] | ||
208 | +} | ||
209 | +``` | ||
210 | + | ||
211 | +### 用例 | ||
212 | +- 输入表达式 `SUM(1/COUNTIFS(【业绩】,【业绩】))` | ||
213 | +```json | ||
214 | +{ | ||
215 | + "arrayFlag":false, | ||
216 | + "exprType":"FunCallerExprAST", | ||
217 | + "name":"sum", | ||
218 | + "args":[ | ||
219 | + { | ||
220 | + "exprType":"BinaryExprAST", | ||
221 | + "op":"/", | ||
222 | + "lhs":{ | ||
223 | + "exprType":"ValueExprAST", | ||
224 | + "val":"", | ||
225 | + "str":"1" | ||
226 | + }, | ||
227 | + "rhs":{ | ||
228 | + "arrayFlag":false, | ||
229 | + "exprType":"FunCallerExprAST", | ||
230 | + "name":"countifs", | ||
231 | + "args":[ | ||
232 | + { | ||
233 | + "exprType":"FieldExprAST", | ||
234 | + "str":"业绩1", | ||
235 | + "field":{ | ||
236 | + "tableId":1, | ||
237 | + "tableName":"测试ABC", | ||
238 | + "tableSqlName":"table_abc_test", | ||
239 | + "fieldName":"业绩", | ||
240 | + "fieldSqlName":"ye_ji_1", | ||
241 | + "fieldSqlType":"Float" | ||
242 | + } | ||
243 | + }, | ||
244 | + { | ||
245 | + "exprType":"ValueExprAST", | ||
246 | + "val":"", | ||
247 | + "str":"业绩2" | ||
248 | + } | ||
249 | + ] | ||
250 | + } | ||
251 | + } | ||
252 | + ] | ||
253 | +} | ||
254 | +``` | ||
255 | + | ||
165 | ## 讨论事项 | 256 | ## 讨论事项 |
166 | 257 | ||
167 | - [ ] 校验动作,参数模型讨论 | 258 | - [ ] 校验动作,参数模型讨论 |
@@ -19,7 +19,14 @@ type AppendDataToTableCommand struct { | @@ -19,7 +19,14 @@ type AppendDataToTableCommand struct { | ||
19 | } | 19 | } |
20 | 20 | ||
21 | func (cmd *AppendDataToTableCommand) Valid(validation *validation.Validation) { | 21 | func (cmd *AppendDataToTableCommand) Valid(validation *validation.Validation) { |
22 | - | 22 | + newMappingFields := make([]*domain.MappingField, 0) |
23 | + for i := range cmd.MappingFields { | ||
24 | + if len(cmd.MappingFields[i].VerifiedFileFieldName) == 0 { | ||
25 | + continue | ||
26 | + } | ||
27 | + newMappingFields = append(newMappingFields, cmd.MappingFields[i]) | ||
28 | + } | ||
29 | + cmd.MappingFields = newMappingFields | ||
23 | } | 30 | } |
24 | 31 | ||
25 | func (cmd *AppendDataToTableCommand) ValidateCommand() error { | 32 | func (cmd *AppendDataToTableCommand) ValidateCommand() error { |
@@ -190,6 +190,9 @@ func (fileService *FileService) AppendDataToTable(ctx *domain.Context, cmd *comm | @@ -190,6 +190,9 @@ func (fileService *FileService) AppendDataToTable(ctx *domain.Context, cmd *comm | ||
190 | if err := cmd.ValidateCommand(); err != nil { | 190 | if err := cmd.ValidateCommand(); err != nil { |
191 | return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | 191 | return nil, application.ThrowError(application.ARG_ERROR, err.Error()) |
192 | } | 192 | } |
193 | + if len(cmd.MappingFields) == 0 { | ||
194 | + return nil, factory.FastError(fmt.Errorf("请选择对应字段")) | ||
195 | + } | ||
193 | transactionContext, err := factory.CreateTransactionContext(nil) | 196 | transactionContext, err := factory.CreateTransactionContext(nil) |
194 | if err != nil { | 197 | if err != nil { |
195 | return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | 198 | return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) |
@@ -212,6 +215,33 @@ func (fileService *FileService) AppendDataToTable(ctx *domain.Context, cmd *comm | @@ -212,6 +215,33 @@ func (fileService *FileService) AppendDataToTable(ctx *domain.Context, cmd *comm | ||
212 | return result, nil | 215 | return result, nil |
213 | } | 216 | } |
214 | 217 | ||
218 | +// AppendDataToTable 追加数据 | ||
219 | +func (fileService *FileService) AppendDataToTablePreflightCheck(ctx *domain.Context, cmd *command.AppendDataToTableCommand) (interface{}, error) { | ||
220 | + if err := cmd.ValidateCommand(); err != nil { | ||
221 | + return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | ||
222 | + } | ||
223 | + transactionContext, err := factory.CreateTransactionContext(nil) | ||
224 | + if err != nil { | ||
225 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
226 | + } | ||
227 | + if err := transactionContext.StartTransaction(); err != nil { | ||
228 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
229 | + } | ||
230 | + defer func() { | ||
231 | + transactionContext.RollbackTransaction() | ||
232 | + }() | ||
233 | + | ||
234 | + generateMainTableService, _ := factory.CreateAppendDataToTableService(transactionContext) | ||
235 | + result, err := generateMainTableService.PreflightCheck(ctx, cmd.FileId, cmd.TableId, cmd.MappingFields) | ||
236 | + if err != nil { | ||
237 | + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error()) | ||
238 | + } | ||
239 | + if err := transactionContext.CommitTransaction(); err != nil { | ||
240 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
241 | + } | ||
242 | + return result, nil | ||
243 | +} | ||
244 | + | ||
215 | // ExportFile 文件下载 | 245 | // ExportFile 文件下载 |
216 | func (fileService *FileService) ExportFile(ctx *domain.Context, cmd *command.ExportFileCommand) (interface{}, error) { | 246 | func (fileService *FileService) ExportFile(ctx *domain.Context, cmd *command.ExportFileCommand) (interface{}, error) { |
217 | if err := cmd.ValidateCommand(); err != nil { | 247 | if err := cmd.ValidateCommand(); err != nil { |
@@ -17,7 +17,7 @@ type QuerySetDetailDto struct { | @@ -17,7 +17,7 @@ type QuerySetDetailDto struct { | ||
17 | TableId int `json:"tableId"` | 17 | TableId int `json:"tableId"` |
18 | } | 18 | } |
19 | 19 | ||
20 | -func (d *QuerySetDetailDto) Load(m *domain.QuerySet) *QuerySetDetailDto { | 20 | +func (d *QuerySetDetailDto) Load(m *domain.QuerySet, mapTables map[int]*domain.Table) *QuerySetDetailDto { |
21 | d.QuerySetId = m.QuerySetId | 21 | d.QuerySetId = m.QuerySetId |
22 | d.Type = m.Type | 22 | d.Type = m.Type |
23 | d.Flag = m.Flag | 23 | d.Flag = m.Flag |
@@ -26,7 +26,12 @@ func (d *QuerySetDetailDto) Load(m *domain.QuerySet) *QuerySetDetailDto { | @@ -26,7 +26,12 @@ func (d *QuerySetDetailDto) Load(m *domain.QuerySet) *QuerySetDetailDto { | ||
26 | if m.QuerySetInfo != nil { | 26 | if m.QuerySetInfo != nil { |
27 | d.TableId = m.QuerySetInfo.BindTableId | 27 | d.TableId = m.QuerySetInfo.BindTableId |
28 | } | 28 | } |
29 | - for i := range d.QueryComponents { | 29 | + for i, q := range d.QueryComponents { |
30 | + if q.MasterTable != nil && q.MasterTable.TableId != 0 { | ||
31 | + if t, ok := mapTables[q.MasterTable.TableId]; ok { | ||
32 | + d.QueryComponents[i].MasterTable = domain.NewQueryComponentTable(t) | ||
33 | + } | ||
34 | + } | ||
30 | if d.QueryComponents[i].Aggregation != nil { | 35 | if d.QueryComponents[i].Aggregation != nil { |
31 | d.QueryComponents[i].Aggregation.Aggregation.AllFields = d.QueryComponents[i].Aggregation.AggregationFields() | 36 | d.QueryComponents[i].Aggregation.Aggregation.AllFields = d.QueryComponents[i].Aggregation.AggregationFields() |
32 | } | 37 | } |
@@ -159,7 +159,17 @@ func (querySetService *QuerySetService) GetQuerySet(ctx *domain.Context, getQuer | @@ -159,7 +159,17 @@ func (querySetService *QuerySetService) GetQuerySet(ctx *domain.Context, getQuer | ||
159 | if err != nil { | 159 | if err != nil { |
160 | return nil, factory.FastError(err) | 160 | return nil, factory.FastError(err) |
161 | } | 161 | } |
162 | - return (&dto.QuerySetDetailDto{}).Load(querySet), nil | 162 | + |
163 | + tableRepository, _, _ := factory.FastPgTable(transactionContext, 0) | ||
164 | + dependencyTables := querySet.GetDependencyTables(querySet.QueryComponents) | ||
165 | + var tables domain.Tables | ||
166 | + if len(dependencyTables) > 0 { | ||
167 | + _, tables, err = tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": dependencyTables}) | ||
168 | + if err != nil { | ||
169 | + return nil, factory.FastError(err) | ||
170 | + } | ||
171 | + } | ||
172 | + return (&dto.QuerySetDetailDto{}).Load(querySet, tables.ToMap()), nil | ||
163 | } | 173 | } |
164 | 174 | ||
165 | // 返回查询集合服务列表 | 175 | // 返回查询集合服务列表 |
pkg/domain/ast_expr.go
0 → 100644
1 | +package domain | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "fmt" | ||
6 | +) | ||
7 | + | ||
8 | +const ( | ||
9 | + TypeFunCallerExprAST = "FunCallerExprAST" | ||
10 | + TypeBinaryExprAST = "BinaryExprAST" | ||
11 | + TypeFieldExprAST = "FieldExprAST" | ||
12 | + TypeValueExprAST = "ValueExprAST" | ||
13 | +) | ||
14 | + | ||
15 | +type ExprAST interface { | ||
16 | + toStr() string | ||
17 | +} | ||
18 | + | ||
19 | +type ValueExprAST struct { | ||
20 | + ExprType string `json:"exprType"` | ||
21 | + Val string `json:"val"` | ||
22 | + Str string `json:"str"` | ||
23 | +} | ||
24 | + | ||
25 | +type FieldExprAST struct { | ||
26 | + ExprType string `json:"exprType"` | ||
27 | + Str string `json:"str"` | ||
28 | + Field *TableField `json:"field"` | ||
29 | +} | ||
30 | + | ||
31 | +type BinaryExprAST struct { | ||
32 | + ExprType string `json:"exprType"` | ||
33 | + Op string `json:"op"` | ||
34 | + Lhs ExprAST `json:"lhs"` | ||
35 | + Rhs ExprAST `json:"rhs"` | ||
36 | +} | ||
37 | + | ||
38 | +type FunCallerExprAST struct { | ||
39 | + ArrayFlag bool `json:"arrayFlag"` | ||
40 | + ExprType string `json:"exprType"` | ||
41 | + Name string `json:"name"` | ||
42 | + Args []ExprAST `json:"args"` | ||
43 | +} | ||
44 | + | ||
45 | +func (n ValueExprAST) toStr() string { | ||
46 | + return fmt.Sprintf( | ||
47 | + "ValueExprAST:%s", | ||
48 | + n.Str, | ||
49 | + ) | ||
50 | +} | ||
51 | + | ||
52 | +func (n FieldExprAST) toStr() string { | ||
53 | + return fmt.Sprintf( | ||
54 | + "FieldExprAST:%s", | ||
55 | + n.Str, | ||
56 | + ) | ||
57 | +} | ||
58 | + | ||
59 | +func (b BinaryExprAST) toStr() string { | ||
60 | + return fmt.Sprintf( | ||
61 | + "BinaryExprAST: (%s %s %s)", | ||
62 | + b.Op, | ||
63 | + b.Lhs.toStr(), | ||
64 | + b.Rhs.toStr(), | ||
65 | + ) | ||
66 | +} | ||
67 | + | ||
68 | +func (n FunCallerExprAST) toStr() string { | ||
69 | + return fmt.Sprintf( | ||
70 | + "FunCallerExprAST:%s", | ||
71 | + n.Name, | ||
72 | + ) | ||
73 | +} | ||
74 | + | ||
75 | +type CloneFunCallerExprAST struct { | ||
76 | + ArrayFlag bool `json:"arrayFlag"` | ||
77 | + Name string `json:"name"` | ||
78 | + Arg []json.RawMessage `json:"args"` | ||
79 | +} | ||
80 | + | ||
81 | +type CloneBinaryExprAST struct { | ||
82 | + Op string `json:"op"` | ||
83 | + Lhs json.RawMessage `json:"lhs"` | ||
84 | + Rhs json.RawMessage `json:"rhs"` | ||
85 | +} | ||
86 | + | ||
87 | +func AstExprUnmarshalJSON(data []byte) (interface{}, error) { | ||
88 | + var m = make(map[string]interface{}) | ||
89 | + if err := json.Unmarshal(data, &m); err != nil { | ||
90 | + return nil, err | ||
91 | + } | ||
92 | + value, err := unmarshalMapInterface(m, data) | ||
93 | + if err != nil { | ||
94 | + return data, err | ||
95 | + } | ||
96 | + return value, nil | ||
97 | +} | ||
98 | + | ||
99 | +func unmarshalMapInterface(m map[string]interface{}, rawData []byte) (interface{}, error) { | ||
100 | + t, ok := m["exprType"] | ||
101 | + if !ok { | ||
102 | + return nil, nil | ||
103 | + } | ||
104 | + if t == TypeFunCallerExprAST { | ||
105 | + expr := &CloneFunCallerExprAST{} | ||
106 | + if err := json.Unmarshal(rawData, expr); err != nil { | ||
107 | + return nil, err | ||
108 | + } | ||
109 | + exprReturn := &FunCallerExprAST{Name: expr.Name, ExprType: TypeFunCallerExprAST} | ||
110 | + for i := range expr.Arg { | ||
111 | + subExpr, err := AstExprUnmarshalJSON(expr.Arg[i]) | ||
112 | + if err != nil { | ||
113 | + return nil, err | ||
114 | + } | ||
115 | + if subExpr == nil { | ||
116 | + continue | ||
117 | + } | ||
118 | + exprReturn.Args = append(exprReturn.Args, subExpr.(ExprAST)) | ||
119 | + } | ||
120 | + return exprReturn, nil | ||
121 | + } | ||
122 | + if t == TypeBinaryExprAST { | ||
123 | + expr := &CloneBinaryExprAST{} | ||
124 | + if err := json.Unmarshal(rawData, expr); err != nil { | ||
125 | + return nil, err | ||
126 | + } | ||
127 | + exprReturn := &BinaryExprAST{Op: expr.Op, ExprType: TypeBinaryExprAST} | ||
128 | + if len(expr.Lhs) > 0 { | ||
129 | + subExpr, err := AstExprUnmarshalJSON(expr.Lhs) | ||
130 | + if err != nil { | ||
131 | + return nil, err | ||
132 | + } | ||
133 | + if subExpr != nil { | ||
134 | + exprReturn.Lhs = subExpr.(ExprAST) | ||
135 | + } | ||
136 | + } | ||
137 | + if len(expr.Rhs) > 0 { | ||
138 | + subExpr, err := AstExprUnmarshalJSON(expr.Rhs) | ||
139 | + if err != nil { | ||
140 | + return nil, err | ||
141 | + } | ||
142 | + if subExpr != nil { | ||
143 | + exprReturn.Rhs = subExpr.(ExprAST) | ||
144 | + } | ||
145 | + } | ||
146 | + return exprReturn, nil | ||
147 | + } | ||
148 | + if t == TypeFieldExprAST { | ||
149 | + expr := &FieldExprAST{ExprType: TypeFieldExprAST} | ||
150 | + if err := json.Unmarshal(rawData, expr); err != nil { | ||
151 | + return nil, err | ||
152 | + } | ||
153 | + return expr, nil | ||
154 | + } | ||
155 | + if t == TypeValueExprAST { | ||
156 | + expr := &ValueExprAST{ExprType: TypeValueExprAST} | ||
157 | + if err := json.Unmarshal(rawData, expr); err != nil { | ||
158 | + return nil, err | ||
159 | + } | ||
160 | + return expr, nil | ||
161 | + } | ||
162 | + return nil, fmt.Errorf("unkonw expr type '%v'", t) | ||
163 | +} |
pkg/domain/ast_expr_test.go
0 → 100644
1 | +package domain | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/linmadan/egglib-go/utils/json" | ||
5 | + "github.com/stretchr/testify/assert" | ||
6 | + "testing" | ||
7 | +) | ||
8 | + | ||
9 | +func TestAstExprUnmarshalJSON(t *testing.T) { | ||
10 | + inputs := []struct { | ||
11 | + data ExprAST | ||
12 | + }{ | ||
13 | + { | ||
14 | + data: &FunCallerExprAST{ | ||
15 | + Name: "if", | ||
16 | + ExprType: TypeFunCallerExprAST, | ||
17 | + Args: []ExprAST{ | ||
18 | + &BinaryExprAST{ | ||
19 | + ExprType: TypeBinaryExprAST, | ||
20 | + Op: "<", | ||
21 | + Lhs: &FieldExprAST{ | ||
22 | + ExprType: TypeFieldExprAST, | ||
23 | + Str: "table.count", | ||
24 | + }, | ||
25 | + Rhs: &FieldExprAST{ | ||
26 | + ExprType: TypeFieldExprAST, | ||
27 | + Str: "100", | ||
28 | + }, | ||
29 | + }, | ||
30 | + &FieldExprAST{ | ||
31 | + ExprType: TypeFieldExprAST, | ||
32 | + Str: "200", | ||
33 | + }, | ||
34 | + &FieldExprAST{ | ||
35 | + ExprType: TypeFieldExprAST, | ||
36 | + Str: "300", | ||
37 | + }, | ||
38 | + }, | ||
39 | + }, | ||
40 | + }, | ||
41 | + { | ||
42 | + data: &FunCallerExprAST{ | ||
43 | + Name: "sum", | ||
44 | + ExprType: TypeFunCallerExprAST, | ||
45 | + Args: []ExprAST{ | ||
46 | + &BinaryExprAST{ | ||
47 | + ExprType: TypeBinaryExprAST, | ||
48 | + Op: "/", | ||
49 | + Lhs: &ValueExprAST{ | ||
50 | + ExprType: TypeValueExprAST, | ||
51 | + Str: "1", | ||
52 | + }, | ||
53 | + Rhs: &FunCallerExprAST{ | ||
54 | + ExprType: TypeFunCallerExprAST, | ||
55 | + Name: "countifs", | ||
56 | + Args: []ExprAST{ | ||
57 | + &FieldExprAST{ | ||
58 | + ExprType: TypeFieldExprAST, | ||
59 | + Str: "业绩1", | ||
60 | + Field: &TableField{ | ||
61 | + TableId: 1, | ||
62 | + TableName: "测试ABC", | ||
63 | + TableSqlName: "table_abc_test", | ||
64 | + FieldName: "业绩", | ||
65 | + FieldSqlName: "ye_ji_1", | ||
66 | + FieldSQLType: "Float", | ||
67 | + }, | ||
68 | + }, | ||
69 | + &ValueExprAST{ | ||
70 | + ExprType: TypeValueExprAST, | ||
71 | + Str: "业绩2", | ||
72 | + }, | ||
73 | + }, | ||
74 | + }, | ||
75 | + }, | ||
76 | + }, | ||
77 | + }, | ||
78 | + }, | ||
79 | + } | ||
80 | + | ||
81 | + for _, input := range inputs { | ||
82 | + data, err := json.Marshal(input.data) | ||
83 | + if err != nil { | ||
84 | + t.Fatal(err) | ||
85 | + } | ||
86 | + v, err := AstExprUnmarshalJSON(data) | ||
87 | + if err != nil { | ||
88 | + t.Fatal(err) | ||
89 | + } | ||
90 | + if v != nil { | ||
91 | + | ||
92 | + } | ||
93 | + assert.Equal(t, input.data, v) | ||
94 | + } | ||
95 | +} |
@@ -50,6 +50,7 @@ type DeleteDataTableService interface { | @@ -50,6 +50,7 @@ type DeleteDataTableService interface { | ||
50 | 50 | ||
51 | type AppendDataToTableService interface { | 51 | type AppendDataToTableService interface { |
52 | AppendData(ctx *Context, fileId int, tableId int, mappingFields []*MappingField) (interface{}, error) | 52 | AppendData(ctx *Context, fileId int, tableId int, mappingFields []*MappingField) (interface{}, error) |
53 | + PreflightCheck(ctx *Context, fileId int, tableId int, mappingFields []*MappingField) (interface{}, error) | ||
53 | } | 54 | } |
54 | 55 | ||
55 | /************************************/ | 56 | /************************************/ |
@@ -18,6 +18,8 @@ type LogEntry struct { | @@ -18,6 +18,8 @@ type LogEntry struct { | ||
18 | Level string `json:"level"` | 18 | Level string `json:"level"` |
19 | // 日志时间 | 19 | // 日志时间 |
20 | LogTime string `json:"logTime"` | 20 | LogTime string `json:"logTime"` |
21 | + // 追加文件ID (操作类型 主表生成、数据导入时有效) | ||
22 | + AppendFileId int `json:"appendFileId,omitempty"` | ||
21 | // 错误信息 | 23 | // 错误信息 |
22 | Error string `json:"error"` | 24 | Error string `json:"error"` |
23 | ctx *Context `json:"-"` | 25 | ctx *Context `json:"-"` |
@@ -40,6 +42,11 @@ func (l LogEntry) OperateType() string { | @@ -40,6 +42,11 @@ func (l LogEntry) OperateType() string { | ||
40 | return l.OperationType | 42 | return l.OperationType |
41 | } | 43 | } |
42 | 44 | ||
45 | +func (l *LogEntry) WithAppendFileId(fileId int) LogEntry { | ||
46 | + l.AppendFileId = fileId | ||
47 | + return *l | ||
48 | +} | ||
49 | + | ||
43 | func NewLogEntry(fileOrTableName string, objectType string, operationType OperationType, ctx *Context) LogEntry { | 50 | func NewLogEntry(fileOrTableName string, objectType string, operationType OperationType, ctx *Context) LogEntry { |
44 | return LogEntry{ | 51 | return LogEntry{ |
45 | ObjectName: fileOrTableName, | 52 | ObjectName: fileOrTableName, |
@@ -163,3 +163,13 @@ func TableTypesToStringList(list ...TableType) []string { | @@ -163,3 +163,13 @@ func TableTypesToStringList(list ...TableType) []string { | ||
163 | } | 163 | } |
164 | return result | 164 | return result |
165 | } | 165 | } |
166 | + | ||
167 | +type Tables []*Table | ||
168 | + | ||
169 | +func (tables Tables) ToMap() map[int]*Table { | ||
170 | + var result = make(map[int]*Table) | ||
171 | + for i := range tables { | ||
172 | + result[tables[i].TableId] = tables[i] | ||
173 | + } | ||
174 | + return result | ||
175 | +} |
@@ -139,9 +139,11 @@ func NewTable(tableType domain.TableType, fileName string, dataFields []*domain. | @@ -139,9 +139,11 @@ func NewTable(tableType domain.TableType, fileName string, dataFields []*domain. | ||
139 | if table.TableType == domain.CalculateTable.ToString() || table.TableType == domain.CalculateItem.ToString() { | 139 | if table.TableType == domain.CalculateTable.ToString() || table.TableType == domain.CalculateItem.ToString() { |
140 | table.PK = nil | 140 | table.PK = nil |
141 | } | 141 | } |
142 | + builder := NewDataFieldsBuilder() | ||
142 | table.DataFieldIndex = len(dataFields) | 143 | table.DataFieldIndex = len(dataFields) |
143 | - for i, field := range dataFields { | ||
144 | - table.DataFields = append(table.DataFields, DataField(field.Name, field.SQLType, domain.MainTableField, i+1)) | 144 | + for _, field := range dataFields { |
145 | + //table.DataFields = append(table.DataFields, DataField(field.Name, field.SQLType, domain.MainTableField, i+1)) | ||
146 | + table.DataFields = append(table.DataFields, builder.NewDataField(field.Name, field.SQLType, domain.MainTableField)) | ||
145 | } | 147 | } |
146 | table.ManualFields = make([]*domain.Field, 0) | 148 | table.ManualFields = make([]*domain.Field, 0) |
147 | table.CreatedAt = time.Now() | 149 | table.CreatedAt = time.Now() |
@@ -197,6 +199,44 @@ func DataField(name string, sqlType string, flag int, index int) *domain.Field { | @@ -197,6 +199,44 @@ func DataField(name string, sqlType string, flag int, index int) *domain.Field { | ||
197 | } | 199 | } |
198 | } | 200 | } |
199 | 201 | ||
202 | +type DataFieldsBuilder struct { | ||
203 | + mapPinFields map[string]int | ||
204 | +} | ||
205 | + | ||
206 | +func NewDataFieldsBuilder() *DataFieldsBuilder { | ||
207 | + builder := &DataFieldsBuilder{ | ||
208 | + mapPinFields: make(map[string]int), | ||
209 | + } | ||
210 | + return builder | ||
211 | +} | ||
212 | + | ||
213 | +func (builder *DataFieldsBuilder) NewDataField(name string, sqlType string, flag int) *domain.Field { | ||
214 | + var index = 0 | ||
215 | + pinName := pin(name) | ||
216 | + index = builder.AddPinItem(pinName) | ||
217 | + return &domain.Field{ | ||
218 | + Index: index, | ||
219 | + Name: name, | ||
220 | + SQLName: fmt.Sprintf("%v_%d", pinName, index), | ||
221 | + SQLType: sqlType, | ||
222 | + Description: "", | ||
223 | + Flag: flag, | ||
224 | + } | ||
225 | +} | ||
226 | + | ||
227 | +func (builder *DataFieldsBuilder) AddPinItem(pin string) int { | ||
228 | + var index = 1 | ||
229 | + for { | ||
230 | + key := fmt.Sprintf("%v_%d", pin, index) | ||
231 | + if _, ok := builder.mapPinFields[key]; !ok { | ||
232 | + builder.mapPinFields[key] = index | ||
233 | + break | ||
234 | + } | ||
235 | + index++ | ||
236 | + } | ||
237 | + return index | ||
238 | +} | ||
239 | + | ||
200 | func pin(name string) string { | 240 | func pin(name string) string { |
201 | pinyin := tool_funs.ToPinYin(name, "_") | 241 | pinyin := tool_funs.ToPinYin(name, "_") |
202 | newPinyin := bytes.NewBuffer(nil) | 242 | newPinyin := bytes.NewBuffer(nil) |
@@ -37,8 +37,9 @@ func (ptr *GenerateMainTableService) GenerateTable(ctx *domain.Context, fileId i | @@ -37,8 +37,9 @@ func (ptr *GenerateMainTableService) GenerateTable(ctx *domain.Context, fileId i | ||
37 | return nil, err | 37 | return nil, err |
38 | } | 38 | } |
39 | // 日志 | 39 | // 日志 |
40 | + entry := domain.NewLogEntry(tableName, domain.MainTable.ToString(), domain.GenerateMainTable, ctx) | ||
40 | if err = FastLog(ptr.transactionContext, domain.CommonLog, mainTable.TableId, &GenerateMainTableLog{ | 41 | if err = FastLog(ptr.transactionContext, domain.CommonLog, mainTable.TableId, &GenerateMainTableLog{ |
41 | - LogEntry: domain.NewLogEntry(tableName, domain.MainTable.ToString(), domain.GenerateMainTable, ctx), | 42 | + LogEntry: (&entry).WithAppendFileId(file.FileId), |
42 | FileName: file.FileInfo.Name, | 43 | FileName: file.FileInfo.Name, |
43 | }); err != nil { | 44 | }); err != nil { |
44 | return nil, err | 45 | return nil, err |
@@ -295,8 +295,10 @@ func (ptr *QuerySetService) PreviewPrepare(ctx *domain.Context, querySetId int, | @@ -295,8 +295,10 @@ func (ptr *QuerySetService) PreviewPrepare(ctx *domain.Context, querySetId int, | ||
295 | dependencyTables := querySet.GetDependencyTables(queryComponents) | 295 | dependencyTables := querySet.GetDependencyTables(queryComponents) |
296 | if querySet.Type == domain.CalculateTable.ToString() { | 296 | if querySet.Type == domain.CalculateTable.ToString() { |
297 | aggregationFields := append(queryComponents[0].Aggregation.RowFields, queryComponents[0].Aggregation.ValueFields...) | 297 | aggregationFields := append(queryComponents[0].Aggregation.RowFields, queryComponents[0].Aggregation.ValueFields...) |
298 | - for index, f := range aggregationFields { | ||
299 | - fields = append(fields, DataField(f.DisplayName, f.Field.SQLType, domain.MainTableField, index)) | 298 | + builder := NewDataFieldsBuilder() |
299 | + for _, f := range aggregationFields { | ||
300 | + //fields = append(fields, DataField(f.DisplayName, f.Field.SQLType, domain.MainTableField, index)) | ||
301 | + fields = append(fields, builder.NewDataField(f.DisplayName, f.Field.SQLType, domain.MainTableField)) | ||
300 | } | 302 | } |
301 | } else { | 303 | } else { |
302 | masterTable := queryComponents[0].MasterTable | 304 | masterTable := queryComponents[0].MasterTable |
@@ -723,7 +725,9 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateItemTable(ctx *domain.Context | @@ -723,7 +725,9 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateItemTable(ctx *domain.Context | ||
723 | //if queryComponent.Formula.MixTableModel() { | 725 | //if queryComponent.Formula.MixTableModel() { |
724 | // queryComponent.Formula.Complete() | 726 | // queryComponent.Formula.Complete() |
725 | //} | 727 | //} |
726 | - field := DataField(querySet.Name, domain.String.ToString(), domain.MainTableField, 1) | 728 | + builder := NewDataFieldsBuilder() |
729 | + //field := DataField(querySet.Name, domain.String.ToString(), domain.MainTableField, 1) | ||
730 | + field := builder.NewDataField(querySet.Name, domain.String.ToString(), domain.MainTableField) | ||
727 | if len(queryComponent.Formula.TableFields) > 0 { | 731 | if len(queryComponent.Formula.TableFields) > 0 { |
728 | field.SQLType = queryComponent.Formula.TableFields[0].FieldSQLType | 732 | field.SQLType = queryComponent.Formula.TableFields[0].FieldSQLType |
729 | } | 733 | } |
@@ -768,13 +772,15 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateTable(ctx *domain.Context, qu | @@ -768,13 +772,15 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateTable(ctx *domain.Context, qu | ||
768 | return nil, fmt.Errorf("行、值不能同时为空") | 772 | return nil, fmt.Errorf("行、值不能同时为空") |
769 | } | 773 | } |
770 | selectedFields := make([]string, 0) | 774 | selectedFields := make([]string, 0) |
771 | - for index, f := range aggregationFields { | 775 | + builder := NewDataFieldsBuilder() |
776 | + for _, f := range aggregationFields { | ||
772 | // 数值类型转浮点类型, 兼容类似表达式 1 * 1.1 | 777 | // 数值类型转浮点类型, 兼容类似表达式 1 * 1.1 |
773 | sqlType := f.Field.SQLType | 778 | sqlType := f.Field.SQLType |
774 | if f.Field.SQLType == domain.Int.ToString() || f.Field.SQLType == domain.BigInt.ToString() { | 779 | if f.Field.SQLType == domain.Int.ToString() || f.Field.SQLType == domain.BigInt.ToString() { |
775 | sqlType = domain.Float.ToString() | 780 | sqlType = domain.Float.ToString() |
776 | } | 781 | } |
777 | - fields = append(fields, DataField(f.DisplayName, sqlType, domain.MainTableField, index)) | 782 | + //fields = append(fields, DataField(f.DisplayName, sqlType, domain.MainTableField, index)) |
783 | + fields = append(fields, builder.NewDataField(f.DisplayName, sqlType, domain.MainTableField)) | ||
778 | selectedFields = append(selectedFields, f.Field.Name) | 784 | selectedFields = append(selectedFields, f.Field.Name) |
779 | } | 785 | } |
780 | queryComponent.Aggregation.SelectFields = selectedFields | 786 | queryComponent.Aggregation.SelectFields = selectedFields |
@@ -37,7 +37,7 @@ func (ptr *AddTableStructService) AddTableStruct(ctx *domain.Context, parentTabl | @@ -37,7 +37,7 @@ func (ptr *AddTableStructService) AddTableStruct(ctx *domain.Context, parentTabl | ||
37 | return nil, fmt.Errorf("表名称重复") | 37 | return nil, fmt.Errorf("表名称重复") |
38 | } | 38 | } |
39 | 39 | ||
40 | - fields = MappingFields(mainTable, fields) | 40 | + fields = MappingFieldsV2(mainTable, fields) |
41 | dataFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.MainTableField}) | 41 | dataFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.MainTableField}) |
42 | manualFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.ManualField}) | 42 | manualFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.ManualField}) |
43 | table := NewTable(domain.SubTable, name, fields, mainTable.RowCount).WithContext(ctx).WithPrefix(string(domain.SubTable)) | 43 | table := NewTable(domain.SubTable, name, fields, mainTable.RowCount).WithContext(ctx).WithPrefix(string(domain.SubTable)) |
@@ -49,8 +49,9 @@ func (ptr *AppendDataToTableService) AppendData(ctx *domain.Context, fileId int, | @@ -49,8 +49,9 @@ func (ptr *AppendDataToTableService) AppendData(ctx *domain.Context, fileId int, | ||
49 | } | 49 | } |
50 | 50 | ||
51 | // 日志 | 51 | // 日志 |
52 | + entry := domain.NewLogEntry(table.Name, domain.MainTable.ToString(), domain.AppendData, ctx) | ||
52 | if err = FastLog(ptr.transactionContext, domain.CommonLog, table.TableId, &AppendDataToTableLog{ | 53 | if err = FastLog(ptr.transactionContext, domain.CommonLog, table.TableId, &AppendDataToTableLog{ |
53 | - LogEntry: domain.NewLogEntry(table.Name, domain.MainTable.ToString(), domain.AppendData, ctx), | 54 | + LogEntry: (&entry).WithAppendFileId(fileId), |
54 | File: file, | 55 | File: file, |
55 | Table: table, | 56 | Table: table, |
56 | SubTables: subTables, | 57 | SubTables: subTables, |
@@ -90,6 +91,39 @@ func (ptr *AppendDataToTableService) AppendData(ctx *domain.Context, fileId int, | @@ -90,6 +91,39 @@ func (ptr *AppendDataToTableService) AppendData(ctx *domain.Context, fileId int, | ||
90 | }, nil | 91 | }, nil |
91 | } | 92 | } |
92 | 93 | ||
94 | +// PreflightCheck 预检 | ||
95 | +func (ptr *AppendDataToTableService) PreflightCheck(ctx *domain.Context, fileId int, tableId int, mappingFields []*domain.MappingField) (interface{}, error) { | ||
96 | + tableRepository, _ := repository.NewTableRepository(ptr.transactionContext) | ||
97 | + table, err := tableRepository.FindOne(map[string]interface{}{"tableId": tableId}) | ||
98 | + if err != nil { | ||
99 | + return nil, fmt.Errorf("表不存在") | ||
100 | + } | ||
101 | + inSourceId := []int{table.TableId} | ||
102 | + if table.ParentId != 0 { | ||
103 | + inSourceId = append(inSourceId, table.ParentId) | ||
104 | + } | ||
105 | + logRepository, _ := repository.NewLogRepository(ptr.transactionContext) | ||
106 | + _, logs, err := logRepository.Find(map[string]interface{}{ | ||
107 | + "inSourceId": inSourceId, | ||
108 | + "inOperationType": []string{domain.GenerateMainTable.ToString(), domain.AppendData.ToString()}, | ||
109 | + "limit": 500, | ||
110 | + }) | ||
111 | + if err != nil { | ||
112 | + return nil, err | ||
113 | + } | ||
114 | + | ||
115 | + for _, log := range logs { | ||
116 | + if log.Entry.AppendFileId == fileId { | ||
117 | + return map[string]interface{}{ | ||
118 | + "fileAppended": true, | ||
119 | + }, nil | ||
120 | + } | ||
121 | + } | ||
122 | + return map[string]interface{}{ | ||
123 | + "fileAppended": false, | ||
124 | + }, nil | ||
125 | +} | ||
126 | + | ||
93 | func NewAppendDataToTableService(transactionContext *pgTransaction.TransactionContext) (*AppendDataToTableService, error) { | 127 | func NewAppendDataToTableService(transactionContext *pgTransaction.TransactionContext) (*AppendDataToTableService, error) { |
94 | if transactionContext == nil { | 128 | if transactionContext == nil { |
95 | return nil, fmt.Errorf("transactionContext参数不能为nil") | 129 | return nil, fmt.Errorf("transactionContext参数不能为nil") |
@@ -36,7 +36,7 @@ func (ptr *UpdateTableStructService) UpdateTableStruct(ctx *domain.Context, tabl | @@ -36,7 +36,7 @@ func (ptr *UpdateTableStructService) UpdateTableStruct(ctx *domain.Context, tabl | ||
36 | return nil, fmt.Errorf("主表不存在") | 36 | return nil, fmt.Errorf("主表不存在") |
37 | } | 37 | } |
38 | 38 | ||
39 | - fields = MappingFields(mainTable, fields) | 39 | + fields = MappingFieldsV2(mainTable, fields) |
40 | reserves, deletes, adds := domain.FieldsChange(table.Fields(false), fields) | 40 | reserves, deletes, adds := domain.FieldsChange(table.Fields(false), fields) |
41 | dataFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.MainTableField}) | 41 | dataFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.MainTableField}) |
42 | manualFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.ManualField}) | 42 | manualFields := (domain.Fields)(fields).Select(map[string]interface{}{"flag": domain.ManualField}) |
@@ -81,9 +81,33 @@ func (ptr *UpdateTableStructService) UpdateTableStruct(ctx *domain.Context, tabl | @@ -81,9 +81,33 @@ func (ptr *UpdateTableStructService) UpdateTableStruct(ctx *domain.Context, tabl | ||
81 | return struct{}{}, nil | 81 | return struct{}{}, nil |
82 | } | 82 | } |
83 | 83 | ||
84 | -func MappingFields(mainTable *domain.Table, fields []*domain.Field) []*domain.Field { | 84 | +//func MappingFields(mainTable *domain.Table, fields []*domain.Field) []*domain.Field { |
85 | +// tableFields := mainTable.Fields(false) | ||
86 | +// tableFieldsMap := (domain.Fields)(tableFields).ToMap() | ||
87 | +// for i := range fields { | ||
88 | +// f := fields[i] | ||
89 | +// if v, ok := tableFieldsMap[f.Name]; ok { | ||
90 | +// fields[i].Name = v.Name | ||
91 | +// fields[i].SQLName = v.SQLName | ||
92 | +// fields[i].Index = v.Index | ||
93 | +// fields[i].SQLType = v.SQLType | ||
94 | +// fields[i].Description = f.Description | ||
95 | +// fields[i].Flag = v.Flag | ||
96 | +// } else { | ||
97 | +// if f.Flag == domain.ManualField && f.Index == 0 { | ||
98 | +// mainTable.DataFieldIndex += 1 | ||
99 | +// fields[i] = DataField(f.Name, f.SQLType, domain.ManualField, mainTable.DataFieldIndex) | ||
100 | +// fields[i].Description = f.Description | ||
101 | +// } | ||
102 | +// } | ||
103 | +// } | ||
104 | +// return fields | ||
105 | +//} | ||
106 | + | ||
107 | +func MappingFieldsV2(mainTable *domain.Table, fields []*domain.Field) []*domain.Field { | ||
85 | tableFields := mainTable.Fields(false) | 108 | tableFields := mainTable.Fields(false) |
86 | tableFieldsMap := (domain.Fields)(tableFields).ToMap() | 109 | tableFieldsMap := (domain.Fields)(tableFields).ToMap() |
110 | + builder := NewDataFieldsBuilder() | ||
87 | for i := range fields { | 111 | for i := range fields { |
88 | f := fields[i] | 112 | f := fields[i] |
89 | if v, ok := tableFieldsMap[f.Name]; ok { | 113 | if v, ok := tableFieldsMap[f.Name]; ok { |
@@ -93,10 +117,11 @@ func MappingFields(mainTable *domain.Table, fields []*domain.Field) []*domain.Fi | @@ -93,10 +117,11 @@ func MappingFields(mainTable *domain.Table, fields []*domain.Field) []*domain.Fi | ||
93 | fields[i].SQLType = v.SQLType | 117 | fields[i].SQLType = v.SQLType |
94 | fields[i].Description = f.Description | 118 | fields[i].Description = f.Description |
95 | fields[i].Flag = v.Flag | 119 | fields[i].Flag = v.Flag |
120 | + builder.NewDataField(v.Name, v.SQLType, v.Flag) | ||
96 | } else { | 121 | } else { |
97 | if f.Flag == domain.ManualField && f.Index == 0 { | 122 | if f.Flag == domain.ManualField && f.Index == 0 { |
98 | - mainTable.DataFieldIndex += 1 | ||
99 | - fields[i] = DataField(f.Name, f.SQLType, domain.ManualField, mainTable.DataFieldIndex) | 123 | + //mainTable.DataFieldIndex += 1 |
124 | + fields[i] = builder.NewDataField(f.Name, f.SQLType, domain.ManualField) | ||
100 | fields[i].Description = f.Description | 125 | fields[i].Description = f.Description |
101 | } | 126 | } |
102 | } | 127 | } |
@@ -144,6 +144,9 @@ func (repository *LogRepository) Find(queryOptions map[string]interface{}) (int6 | @@ -144,6 +144,9 @@ func (repository *LogRepository) Find(queryOptions map[string]interface{}) (int6 | ||
144 | if v, ok := queryOptions["inSourceId"]; ok && len(v.([]int)) > 0 { | 144 | if v, ok := queryOptions["inSourceId"]; ok && len(v.([]int)) > 0 { |
145 | query.Where("source_id in (?)", pg.In(v.([]int))) | 145 | query.Where("source_id in (?)", pg.In(v.([]int))) |
146 | } | 146 | } |
147 | + if v, ok := queryOptions["inOperationType"]; ok && len(v.([]string)) > 0 { | ||
148 | + query.Where("entry->>'operationType' in (?)", pg.In(v.([]string))) | ||
149 | + } | ||
147 | if v, ok := queryOptions["matchContent"]; ok && len(v.(string)) > 0 { | 150 | if v, ok := queryOptions["matchContent"]; ok && len(v.(string)) > 0 { |
148 | query.WhereGroup(func(query *orm.Query) (*orm.Query, error) { | 151 | query.WhereGroup(func(query *orm.Query) (*orm.Query, error) { |
149 | matchContent := v.(string) | 152 | matchContent := v.(string) |
@@ -138,6 +138,14 @@ func (controller *FileController) AppendDataToTable() { | @@ -138,6 +138,14 @@ func (controller *FileController) AppendDataToTable() { | ||
138 | controller.Response(data, err) | 138 | controller.Response(data, err) |
139 | } | 139 | } |
140 | 140 | ||
141 | +func (controller *FileController) AppendDataToTablePreflightCheck() { | ||
142 | + fileService := service.NewFileService(nil) | ||
143 | + cmd := &command.AppendDataToTableCommand{} | ||
144 | + controller.Unmarshal(cmd) | ||
145 | + data, err := fileService.AppendDataToTablePreflightCheck(ParseContext(controller.BaseController), cmd) | ||
146 | + controller.Response(data, err) | ||
147 | +} | ||
148 | + | ||
141 | func (controller *FileController) CancelVerifyingFile() { | 149 | func (controller *FileController) CancelVerifyingFile() { |
142 | fileService := service.NewFileService(nil) | 150 | fileService := service.NewFileService(nil) |
143 | cmd := &command.CancelVerifyingFileCommand{} | 151 | cmd := &command.CancelVerifyingFileCommand{} |
@@ -24,4 +24,5 @@ func init() { | @@ -24,4 +24,5 @@ func init() { | ||
24 | web.Router("/data/flush-data-table", &controllers.FileController{}, "Post:FlushDataTable") | 24 | web.Router("/data/flush-data-table", &controllers.FileController{}, "Post:FlushDataTable") |
25 | web.Router("/data/generate-main-table", &controllers.FileController{}, "Post:GenerateMainTable") | 25 | web.Router("/data/generate-main-table", &controllers.FileController{}, "Post:GenerateMainTable") |
26 | web.Router("/data/append-data-to-table", &controllers.FileController{}, "Post:AppendDataToTable") | 26 | web.Router("/data/append-data-to-table", &controllers.FileController{}, "Post:AppendDataToTable") |
27 | + web.Router("/data/append-data-preflight-check", &controllers.FileController{}, "Post:AppendDataToTablePreflightCheck") | ||
27 | } | 28 | } |
-
请 注册 或 登录 后发表评论