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  }