github.com/team-ide/go-dialect@v1.9.20/worker/task_export.go (about) 1 package worker 2 3 import ( 4 "database/sql" 5 "errors" 6 "fmt" 7 "github.com/team-ide/go-dialect/dialect" 8 "os" 9 "strings" 10 ) 11 12 func NewTaskExport(db *sql.DB, dia dialect.Dialect, targetDialect dialect.Dialect, taskExportParam *TaskExportParam) (res *taskExport) { 13 if targetDialect == nil { 14 targetDialect = dia 15 } 16 if taskExportParam.DataSourceType == nil { 17 taskExportParam.DataSourceType = DataSourceTypeSql 18 } 19 task := &Task{ 20 dia: dia, 21 db: db, 22 onProgress: taskExportParam.OnProgress, 23 } 24 res = &taskExport{ 25 Task: task, 26 TaskExportParam: taskExportParam, 27 targetDialect: targetDialect, 28 } 29 task.do = res.do 30 return 31 } 32 33 type TaskExportParam struct { 34 Owners []*TaskExportOwner `json:"owners"` 35 SkipOwnerNames []string `json:"skipOwnerNames"` 36 37 DataSourceType *DataSourceType `json:"dataSourceType"` 38 BatchNumber int `json:"batchNumber"` 39 ExportStruct bool `json:"exportStruct"` 40 ExportData bool `json:"exportData"` 41 ExportBatchSql bool `json:"exportBatchSql"` 42 ErrorContinue bool `json:"errorContinue"` 43 Dir string `json:"dir"` 44 AppendOwnerName bool `json:"appendOwnerName"` 45 46 IsDataListExport bool `json:"isDataListExport"` 47 DataList []map[string]interface{} `json:"dataList"` 48 49 MergeIntoOneFile bool `json:"mergeIntoOneFile"` 50 51 FormatIndexName func(ownerName string, tableName string, index *dialect.IndexModel) string `json:"-"` 52 OnProgress func(progress *TaskProgress) `json:"-"` 53 } 54 55 type TaskExportOwner struct { 56 SourceName string `json:"sourceName"` 57 TargetName string `json:"targetName"` 58 SkipTableNames []string `json:"skipTableNames"` 59 Tables []*TaskExportTable `json:"tables"` 60 } 61 62 type TaskExportTable struct { 63 SourceName string `json:"sourceName"` 64 TargetName string `json:"targetName"` 65 Columns []*TaskExportColumn `json:"columns"` 66 } 67 68 type TaskExportColumn struct { 69 SourceName string `json:"sourceName"` 70 TargetName string `json:"targetName"` 71 Value string `json:"value"` 72 } 73 74 type taskExport struct { 75 *Task 76 *TaskExportParam 77 targetDialect dialect.Dialect 78 mergeDataSource DataSource 79 } 80 81 func (this_ *taskExport) do() (err error) { 82 83 defer func() { 84 if e := recover(); e != nil { 85 err = errors.New(fmt.Sprint(e)) 86 } 87 }() 88 owners := this_.Owners 89 if len(owners) == 0 { 90 var list []*dialect.OwnerModel 91 list, err = OwnersSelect(this_.db, this_.dia, this_.Param) 92 if err != nil { 93 return 94 } 95 for _, one := range list { 96 owners = append(owners, &TaskExportOwner{ 97 SourceName: one.OwnerName, 98 }) 99 } 100 } 101 102 this_.countIncr(&this_.OwnerCount, len(owners)) 103 104 defer func() { 105 if this_.mergeDataSource != nil { 106 _ = this_.mergeDataSource.WriteEnd() 107 } 108 }() 109 for _, owner := range owners { 110 if len(this_.SkipOwnerNames) > 0 { 111 var skip bool 112 for _, skipTableName := range this_.SkipOwnerNames { 113 if strings.EqualFold(owner.SourceName, skipTableName) { 114 skip = true 115 } 116 } 117 if skip { 118 this_.countIncr(&this_.OwnerSuccessCount, 1) 119 continue 120 } 121 } 122 var success bool 123 success, err = this_.exportOwner(owner) 124 if success { 125 this_.countIncr(&this_.OwnerSuccessCount, 1) 126 } else { 127 this_.countIncr(&this_.OwnerErrorCount, 1) 128 } 129 if err != nil { 130 return 131 } 132 } 133 134 return 135 } 136 137 func (this_ *taskExport) getFileName(dir string, name string) (fileName string, err error) { 138 var exist bool 139 if this_.Dir != "" { 140 if dir != "" { 141 dir = this_.Dir + string(os.PathSeparator) + dir 142 } else { 143 dir = this_.Dir 144 } 145 } 146 if dir != "" { 147 exist, err = PathExists(dir) 148 if err != nil { 149 return 150 } 151 if !exist { 152 err = os.MkdirAll(dir, 0777) 153 if err != nil { 154 return 155 } 156 } 157 fileName = dir + string(os.PathSeparator) 158 } 159 fileName += name 160 return 161 } 162 163 func (this_ *taskExport) exportOwner(owner *TaskExportOwner) (success bool, err error) { 164 progress := &TaskProgress{ 165 Title: "导出[" + owner.SourceName + "]", 166 } 167 defer func() { 168 if e := recover(); e != nil { 169 err = errors.New(fmt.Sprint(e)) 170 } 171 if err != nil { 172 progress.Error = err.Error() 173 if progress.OnError != nil { 174 progress.OnError(err) 175 } 176 } 177 178 if this_.ErrorContinue { 179 err = nil 180 } 181 }() 182 183 this_.addProgress(progress) 184 185 if this_.IsStop { 186 return 187 } 188 189 if !this_.IsDataListExport { 190 var ownerOne *dialect.OwnerModel 191 192 ownerOne, err = OwnerSelect(this_.db, this_.dia, this_.Param, owner.SourceName) 193 if err != nil { 194 return 195 } 196 if ownerOne == nil { 197 err = errors.New("source db owner [" + owner.SourceName + "] is not exist") 198 return 199 } 200 } 201 tables := owner.Tables 202 203 if len(tables) == 0 { 204 var list []*dialect.TableModel 205 list, err = TablesSelect(this_.db, this_.dia, this_.Param, owner.SourceName) 206 if err != nil { 207 return 208 } 209 for _, one := range list { 210 tables = append(tables, &TaskExportTable{ 211 SourceName: one.TableName, 212 }) 213 } 214 } 215 this_.countIncr(&this_.TableCount, len(tables)) 216 217 ownerName := owner.TargetName 218 if ownerName == "" { 219 ownerName = owner.SourceName 220 } 221 222 var ownerDataSource DataSource 223 if this_.IsDataListExport { 224 fileName := "数据列表导出." + this_.DataSourceType.FileSuffix 225 fileName, err = this_.getFileName("", fileName) 226 if err != nil { 227 return 228 } 229 param := &DataSourceParam{ 230 Path: fileName, 231 SheetName: "数据列表导出", 232 Dia: this_.targetDialect, 233 } 234 ownerDataSource = this_.DataSourceType.New(param) 235 err = ownerDataSource.WriteStart() 236 if err != nil { 237 return 238 } 239 defer func() { 240 _ = ownerDataSource.WriteEnd() 241 }() 242 } else { 243 if this_.DataSourceType == DataSourceTypeSql { 244 if this_.MergeIntoOneFile { 245 if this_.mergeDataSource == nil { 246 fileName := "database." + this_.DataSourceType.FileSuffix 247 fileName, err = this_.getFileName("", fileName) 248 if err != nil { 249 return 250 } 251 param := &DataSourceParam{ 252 Path: fileName, 253 Dia: this_.targetDialect, 254 } 255 this_.mergeDataSource = this_.DataSourceType.New(param) 256 err = this_.mergeDataSource.WriteStart() 257 if err != nil { 258 return 259 } 260 } 261 ownerDataSource = this_.mergeDataSource 262 } else { 263 fileName := ownerName + "." + this_.DataSourceType.FileSuffix 264 fileName, err = this_.getFileName("", fileName) 265 if err != nil { 266 return 267 } 268 param := &DataSourceParam{ 269 Path: fileName, 270 SheetName: ownerName, 271 Dia: this_.targetDialect, 272 } 273 ownerDataSource = this_.DataSourceType.New(param) 274 err = ownerDataSource.WriteStart() 275 if err != nil { 276 return 277 } 278 defer func() { 279 _ = ownerDataSource.WriteEnd() 280 }() 281 } 282 } 283 } 284 for _, table := range tables { 285 286 if len(owner.SkipTableNames) > 0 { 287 var skip bool 288 for _, skipTableName := range owner.SkipTableNames { 289 if strings.EqualFold(table.SourceName, skipTableName) { 290 skip = true 291 } 292 } 293 if skip { 294 this_.countIncr(&this_.TableSuccessCount, 1) 295 continue 296 } 297 } 298 var success_ bool 299 success_, err = this_.exportTable(ownerDataSource, owner.SourceName, table.SourceName, owner.TargetName, table.TargetName, table.Columns) 300 if success_ { 301 this_.countIncr(&this_.TableSuccessCount, 1) 302 } else { 303 this_.countIncr(&this_.TableErrorCount, 1) 304 } 305 if err != nil { 306 return 307 } 308 } 309 success = true 310 return 311 } 312 313 func (this_ *taskExport) exportTable(ownerDataSource DataSource, sourceOwnerName string, sourceTableName string, targetOwnerName string, targetTableName string, columns []*TaskExportColumn) (success bool, err error) { 314 if targetOwnerName == "" { 315 targetOwnerName = sourceOwnerName 316 } 317 if targetTableName == "" { 318 targetTableName = sourceTableName 319 } 320 progress := &TaskProgress{ 321 Title: "导出[" + sourceOwnerName + "." + sourceTableName + "] 到 [" + targetOwnerName + "." + targetTableName + "]", 322 } 323 defer func() { 324 if e := recover(); e != nil { 325 err = errors.New(fmt.Sprint(e)) 326 } 327 if err != nil { 328 progress.Error = err.Error() 329 if progress.OnError != nil { 330 progress.OnError(err) 331 } 332 } 333 334 if this_.ErrorContinue { 335 err = nil 336 } 337 }() 338 339 this_.addProgress(progress) 340 341 if this_.IsStop { 342 return 343 } 344 345 var tableDetail *dialect.TableModel 346 if !this_.IsDataListExport { 347 tableDetail, err = TableDetail(this_.db, this_.dia, this_.Param, sourceOwnerName, sourceTableName, false) 348 if err != nil { 349 return 350 } 351 if tableDetail == nil { 352 err = errors.New("source db table [" + sourceOwnerName + "." + sourceTableName + "] is not exist") 353 return 354 } 355 } 356 357 var tableDataSource DataSource 358 if !this_.IsDataListExport { 359 if this_.DataSourceType != DataSourceTypeSql { 360 fileName := targetTableName + "." + this_.DataSourceType.FileSuffix 361 fileName, err = this_.getFileName(targetOwnerName, fileName) 362 if err != nil { 363 return 364 } 365 param := &DataSourceParam{ 366 Path: fileName, 367 SheetName: targetTableName, 368 Dia: this_.targetDialect, 369 } 370 tableDataSource = this_.DataSourceType.New(param) 371 err = tableDataSource.WriteStart() 372 if err != nil { 373 return 374 } 375 defer func() { 376 _ = tableDataSource.WriteEnd() 377 }() 378 } 379 } 380 381 if !this_.IsDataListExport { 382 if this_.ExportStruct { 383 err = this_.exportTableStruct(ownerDataSource, tableDataSource, tableDetail, targetOwnerName, targetTableName) 384 if err != nil { 385 return 386 } 387 } 388 } 389 if this_.ExportData { 390 err = this_.exportTableData(ownerDataSource, tableDataSource, tableDetail, targetOwnerName, targetTableName, columns) 391 if err != nil { 392 return 393 } 394 } 395 success = true 396 return 397 } 398 399 func (this_ *taskExport) exportTableStruct(ownerDataSource DataSource, tableDataSource DataSource, tableDetail *dialect.TableModel, targetOwnerName string, targetTableName string) (err error) { 400 401 progress := &TaskProgress{ 402 Title: "导出表结构[" + tableDetail.OwnerName + "." + tableDetail.TableName + "] 到 [" + targetOwnerName + "." + targetTableName + "]", 403 } 404 var oldOwnerName = tableDetail.OwnerName 405 var oldTableName = tableDetail.TableName 406 tableDetail.OwnerName = targetOwnerName 407 if this_.AppendOwnerName { 408 tableDetail.OwnerName = targetOwnerName 409 } else { 410 tableDetail.OwnerName = "" 411 } 412 tableDetail.TableName = targetTableName 413 defer func() { 414 tableDetail.OwnerName = oldOwnerName 415 tableDetail.TableName = oldTableName 416 417 if e := recover(); e != nil { 418 err = errors.New(fmt.Sprint(e)) 419 } 420 if err != nil { 421 progress.Error = err.Error() 422 if progress.OnError != nil { 423 progress.OnError(err) 424 } 425 } 426 427 if this_.ErrorContinue { 428 err = nil 429 } 430 }() 431 432 this_.addProgress(progress) 433 434 if this_.IsStop { 435 return 436 } 437 if this_.FormatIndexName != nil { 438 for _, index := range tableDetail.IndexList { 439 index.IndexName = this_.FormatIndexName(tableDetail.OwnerName, tableDetail.TableName, index) 440 } 441 } 442 443 // 导出结构体 444 445 lines, err := this_.targetDialect.TableCreateSql(this_.Param, tableDetail.OwnerName, tableDetail) 446 447 for _, line := range lines { 448 dataSourceData := &DataSourceData{ 449 HasSql: true, 450 Sql: line, 451 } 452 if ownerDataSource != nil { 453 err = ownerDataSource.Write(dataSourceData) 454 if err != nil { 455 return 456 } 457 } 458 if tableDataSource != nil { 459 err = tableDataSource.Write(dataSourceData) 460 if err != nil { 461 return 462 } 463 } 464 } 465 466 return 467 } 468 469 func (this_ *taskExport) exportTableData(ownerDataSource DataSource, tableDataSource DataSource, tableDetail *dialect.TableModel, targetOwnerName string, targetTableName string, columns []*TaskExportColumn) (err error) { 470 471 progress := &TaskProgress{} 472 if tableDetail != nil { 473 progress.Title = "导出表数据[" + tableDetail.OwnerName + "." + tableDetail.TableName + "] 到 [" + targetOwnerName + "." + targetTableName + "]" 474 } else { 475 progress.Title = "导出表数据[" + targetOwnerName + "." + targetTableName + "]" 476 } 477 478 defer func() { 479 if e := recover(); e != nil { 480 err = errors.New(fmt.Sprint(e)) 481 } 482 if err != nil { 483 progress.Error = err.Error() 484 if progress.OnError != nil { 485 progress.OnError(err) 486 } 487 } 488 489 if this_.ErrorContinue { 490 err = nil 491 } 492 }() 493 494 this_.addProgress(progress) 495 496 if this_.IsStop { 497 return 498 } 499 500 if this_.IsDataListExport { 501 dataListSize := len(this_.DataList) 502 this_.countIncr(&this_.DataCount, dataListSize) 503 this_.countIncr(&this_.DataReadyCount, dataListSize) 504 var success bool 505 success, err = this_.exportDataList(ownerDataSource, tableDataSource, this_.DataList, targetOwnerName, targetTableName, nil, columns) 506 if success { 507 this_.countIncr(&this_.DataSuccessCount, dataListSize) 508 } else { 509 this_.countIncr(&this_.DataErrorCount, dataListSize) 510 } 511 if err != nil { 512 return 513 } 514 return 515 } 516 517 selectSqlInfo := "SELECT " 518 var columnNames []string 519 for _, one := range tableDetail.ColumnList { 520 columnNames = append(columnNames, one.ColumnName) 521 } 522 selectSqlInfo += this_.dia.ColumnNamesPack(this_.Param, columnNames) 523 selectSqlInfo += " FROM " 524 525 selectSqlInfo += this_.dia.OwnerTablePack(this_.Param, tableDetail.OwnerName, tableDetail.TableName) 526 527 countSql, err := dialect.FormatCountSql(selectSqlInfo) 528 if err != nil { 529 return 530 } 531 totalCount, err := DoQueryCount(this_.db, countSql, nil) 532 if err != nil { 533 return 534 } 535 536 this_.countIncr(&this_.DataCount, totalCount) 537 batchNumber := this_.BatchNumber 538 if batchNumber <= 0 { 539 batchNumber = 100 540 } 541 var pageSize = batchNumber 542 var pageNo = 1 543 544 var dataList []map[string]interface{} 545 for { 546 547 if this_.IsStop { 548 return 549 } 550 pageSql := this_.dia.PackPageSql(selectSqlInfo, pageSize, pageNo) 551 dataList, err = DoQuery(this_.db, pageSql, nil) 552 if err != nil { 553 err = errors.New("query page query sql:" + pageSql + ",error:" + err.Error()) 554 return 555 } 556 pageNo += 1 557 dataListCount := len(dataList) 558 this_.countIncr(&this_.DataReadyCount, dataListCount) 559 if dataListCount == 0 { 560 break 561 } 562 var success bool 563 success, err = this_.exportDataList(ownerDataSource, tableDataSource, dataList, targetOwnerName, targetTableName, tableDetail.ColumnList, columns) 564 if success { 565 this_.countIncr(&this_.DataSuccessCount, dataListCount) 566 } else { 567 this_.countIncr(&this_.DataErrorCount, dataListCount) 568 } 569 if err != nil { 570 return 571 } 572 if dataListCount == 0 { 573 break 574 } 575 } 576 577 return 578 } 579 580 func (this_ *taskExport) exportDataList(ownerDataSource DataSource, tableDataSource DataSource, dataList []map[string]interface{}, targetOwnerName string, targetTableName string, columnList []*dialect.ColumnModel, columns []*TaskExportColumn) (success bool, err error) { 581 582 progress := &TaskProgress{ 583 Title: "导出数据[" + targetOwnerName + "." + targetTableName + "]", 584 } 585 defer func() { 586 if e := recover(); e != nil { 587 err = errors.New(fmt.Sprint(e)) 588 } 589 if err != nil { 590 progress.Error = err.Error() 591 if progress.OnError != nil { 592 progress.OnError(err) 593 } 594 } 595 596 if this_.ErrorContinue { 597 err = nil 598 } 599 }() 600 601 this_.addProgress(progress) 602 603 if this_.IsStop { 604 return 605 } 606 var columnCache = make(map[string]*dialect.ColumnModel) 607 for _, one := range columnList { 608 columnCache[one.ColumnName] = one 609 } 610 var newColumnList = columnList 611 if len(columns) > 0 { 612 newColumnList = []*dialect.ColumnModel{} 613 for _, one := range columns { 614 if one.SourceName == "" { 615 continue 616 } 617 column := columnCache[one.SourceName] 618 targetName := one.TargetName 619 if targetName == "" { 620 targetName = one.SourceName 621 } 622 newColumn := &dialect.ColumnModel{} 623 newColumn.ColumnName = targetName 624 if targetName != one.SourceName || one.Value != "" { 625 for _, data := range dataList { 626 if one.Value != "" { 627 data[targetName] = one.Value 628 } else { 629 data[targetName] = data[one.SourceName] 630 } 631 } 632 } 633 if column != nil { 634 newColumn.ColumnDataType = column.ColumnDataType 635 newColumn.ColumnDefault = column.ColumnDefault 636 newColumn.ColumnLength = column.ColumnLength 637 newColumn.ColumnPrecision = column.ColumnPrecision 638 newColumn.ColumnScale = column.ColumnScale 639 } 640 newColumnList = append(newColumnList, newColumn) 641 } 642 } 643 var sqlOwner = "" 644 if this_.AppendOwnerName { 645 sqlOwner = targetOwnerName 646 } 647 this_.Param.AppendSqlValue = new(bool) 648 *this_.Param.AppendSqlValue = true 649 sqlList, _, batchSqlList, _, err := this_.targetDialect.DataListInsertSql(this_.Param, sqlOwner, targetTableName, newColumnList, dataList) 650 if err != nil { 651 return 652 } 653 654 var lines []string 655 if this_.ExportBatchSql { 656 lines = batchSqlList 657 } else { 658 lines = sqlList 659 } 660 661 for _, line := range lines { 662 dataSourceData := &DataSourceData{ 663 HasSql: true, 664 Sql: line, 665 } 666 if ownerDataSource != nil { 667 err = ownerDataSource.Write(dataSourceData) 668 if err != nil { 669 return 670 } 671 } 672 if tableDataSource != nil { 673 err = tableDataSource.Write(dataSourceData) 674 if err != nil { 675 return 676 } 677 } 678 } 679 680 if ownerDataSource != nil { 681 err = ownerDataSource.WriteHeader(newColumnList) 682 if err != nil { 683 return 684 } 685 } 686 if tableDataSource != nil { 687 err = tableDataSource.WriteHeader(newColumnList) 688 if err != nil { 689 return 690 } 691 } 692 for _, data := range dataList { 693 dataSourceData := &DataSourceData{ 694 HasData: true, 695 Data: data, 696 ColumnList: newColumnList, 697 } 698 if ownerDataSource != nil { 699 err = ownerDataSource.Write(dataSourceData) 700 if err != nil { 701 return 702 } 703 } 704 if tableDataSource != nil { 705 err = tableDataSource.Write(dataSourceData) 706 if err != nil { 707 return 708 } 709 } 710 } 711 success = true 712 713 return 714 }