作者 Administrator

合并分支 'test' 到 'master'

Test



查看合并请求 !4
@@ -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 // 返回查询集合服务列表
  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 +}
  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 }