github.com/team-ide/go-dialect@v1.9.20/worker/task_import.go (about)

     1  package worker
     2  
     3  import (
     4  	"database/sql"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/team-ide/go-dialect/dialect"
     8  	"path/filepath"
     9  	"strings"
    10  )
    11  
    12  func NewTaskImport(db *sql.DB, dia dialect.Dialect, newDb func(owner *TaskImportOwner) (db *sql.DB, err error), taskImportParam *TaskImportParam) (res *taskImport) {
    13  	if taskImportParam.DataSourceType == nil {
    14  		taskImportParam.DataSourceType = DataSourceTypeSql
    15  	}
    16  	task := &Task{
    17  		dia:        dia,
    18  		db:         db,
    19  		onProgress: taskImportParam.OnProgress,
    20  	}
    21  	res = &taskImport{
    22  		Task:            task,
    23  		TaskImportParam: taskImportParam,
    24  		newDb:           newDb,
    25  	}
    26  	task.do = res.do
    27  	return
    28  }
    29  
    30  type TaskImportParam struct {
    31  	Owners []*TaskImportOwner `json:"owners"`
    32  
    33  	DataSourceType        *DataSourceType `json:"dataSourceType"`
    34  	BatchNumber           int             `json:"batchNumber"`
    35  	OwnerCreateIfNotExist bool            `json:"ownerCreateIfNotExist"`
    36  	ErrorContinue         bool            `json:"errorContinue"`
    37  
    38  	FormatIndexName func(ownerName string, tableName string, index *dialect.IndexModel) string `json:"-"`
    39  	OnProgress      func(progress *TaskProgress)
    40  }
    41  
    42  type TaskImportOwner struct {
    43  	Name           string             `json:"name"`
    44  	Path           string             `json:"path"`
    45  	SkipTableNames []string           `json:"skipTableNames"`
    46  	Tables         []*TaskImportTable `json:"tables"`
    47  	Username       string             `json:"username"`
    48  	Password       string             `json:"password"`
    49  }
    50  
    51  type TaskImportTable struct {
    52  	Name    string              `json:"name"`
    53  	Path    string              `json:"path"`
    54  	Columns []*TaskImportColumn `json:"columns"`
    55  }
    56  
    57  type TaskImportColumn struct {
    58  	Name  string `json:"name"`
    59  	Value string `json:"value"`
    60  }
    61  
    62  type taskImport struct {
    63  	*Task
    64  	*TaskImportParam `json:"-"`
    65  	newDb            func(owner *TaskImportOwner) (db *sql.DB, err error)
    66  }
    67  
    68  func (this_ *taskImport) do() (err error) {
    69  
    70  	defer func() {
    71  		if e := recover(); e != nil {
    72  			err = errors.New(fmt.Sprint(e))
    73  		}
    74  	}()
    75  	owners := this_.Owners
    76  	if len(owners) == 0 {
    77  		return
    78  	}
    79  	this_.countIncr(&this_.OwnerCount, len(owners))
    80  	for _, owner := range owners {
    81  		var success bool
    82  		success, err = this_.importOwner(owner)
    83  		if success {
    84  			this_.countIncr(&this_.OwnerSuccessCount, 1)
    85  		} else {
    86  			this_.countIncr(&this_.OwnerErrorCount, 1)
    87  		}
    88  		if err != nil {
    89  			return
    90  		}
    91  	}
    92  
    93  	return
    94  }
    95  
    96  func (this_ *taskImport) importOwner(owner *TaskImportOwner) (success bool, err error) {
    97  	progress := &TaskProgress{
    98  		Title: "导入[" + owner.Name + "]",
    99  	}
   100  	defer func() {
   101  		if e := recover(); e != nil {
   102  			err = errors.New(fmt.Sprint(e))
   103  		}
   104  		if err != nil {
   105  			progress.Error = err.Error()
   106  			if progress.OnError != nil {
   107  				progress.OnError(err)
   108  			}
   109  		}
   110  
   111  		if this_.ErrorContinue {
   112  			err = nil
   113  		}
   114  	}()
   115  
   116  	this_.addProgress(progress)
   117  
   118  	if this_.IsStop {
   119  		return
   120  	}
   121  
   122  	ownerName := owner.Name
   123  
   124  	//
   125  	if this_.OwnerCreateIfNotExist {
   126  		var ownerOne *dialect.OwnerModel
   127  		ownerOne, err = OwnerSelect(this_.db, this_.dia, this_.Param, ownerName)
   128  		if err != nil {
   129  			return
   130  		}
   131  		if ownerOne == nil {
   132  			this_.addProgress(&TaskProgress{
   133  				Title: "导入[" + owner.Name + "] 不存在,创建",
   134  			})
   135  			_, err = OwnerCreate(this_.db, this_.dia, this_.Param, &dialect.OwnerModel{
   136  				OwnerName:             ownerName,
   137  				OwnerPassword:         owner.Password,
   138  				OwnerCharacterSetName: "utf8mb4",
   139  			})
   140  			if err != nil {
   141  				return
   142  			}
   143  		} else {
   144  			this_.addProgress(&TaskProgress{
   145  				Title: "导入[" + owner.Name + "] 存在",
   146  			})
   147  		}
   148  	}
   149  
   150  	workDb, err := this_.newDb(owner)
   151  	if err != nil {
   152  		return
   153  	}
   154  
   155  	if owner.Path != "" {
   156  		var exists bool
   157  		exists, err = PathExists(owner.Path)
   158  		if err != nil {
   159  			return
   160  		}
   161  		if !exists {
   162  			err = errors.New("import [" + ownerName + "] path [" + owner.Path + "] not exists.")
   163  			return
   164  		}
   165  	}
   166  
   167  	if this_.DataSourceType == DataSourceTypeSql {
   168  		if owner.Path != "" {
   169  			var isDir bool
   170  			isDir, err = PathIsDir(owner.Path)
   171  			if err != nil {
   172  				return
   173  			}
   174  			if !isDir {
   175  				_, err = this_.importSql(workDb, ownerName, owner.Path)
   176  				if err != nil {
   177  					return
   178  				}
   179  			}
   180  		}
   181  
   182  	}
   183  	tables := owner.Tables
   184  	this_.countIncr(&this_.TableCount, len(tables))
   185  
   186  	for _, table := range tables {
   187  		tableName := table.Name
   188  		if len(owner.SkipTableNames) > 0 {
   189  			var skip bool
   190  			for _, skipTableName := range owner.SkipTableNames {
   191  				if strings.EqualFold(tableName, skipTableName) {
   192  					skip = true
   193  				}
   194  			}
   195  			if skip {
   196  				this_.countIncr(&this_.TableSuccessCount, 1)
   197  				continue
   198  			}
   199  		}
   200  		var success_ bool
   201  		success_, err = this_.importTable(workDb, owner.Name, tableName, owner.Path, table.Path, table.Columns)
   202  		if success_ {
   203  			this_.countIncr(&this_.TableSuccessCount, 1)
   204  		} else {
   205  			this_.countIncr(&this_.TableErrorCount, 1)
   206  		}
   207  		if err != nil {
   208  			return
   209  		}
   210  	}
   211  
   212  	success = true
   213  	return
   214  }
   215  
   216  func (this_ *taskImport) importSql(workDb *sql.DB, ownerName string, path string) (success bool, err error) {
   217  	progress := &TaskProgress{
   218  		Title: "导入[" + ownerName + "]",
   219  	}
   220  	defer func() {
   221  		if e := recover(); e != nil {
   222  			err = errors.New(fmt.Sprint(e))
   223  		}
   224  		if err != nil {
   225  			progress.Error = err.Error()
   226  			if progress.OnError != nil {
   227  				progress.OnError(err)
   228  			}
   229  		}
   230  
   231  		if this_.ErrorContinue {
   232  			err = nil
   233  		}
   234  	}()
   235  
   236  	this_.addProgress(progress)
   237  
   238  	if this_.IsStop {
   239  		return
   240  	}
   241  
   242  	param := &DataSourceParam{
   243  		Path:      path,
   244  		SheetName: ownerName,
   245  		Dia:       this_.dia,
   246  	}
   247  	ownerDataSource := this_.DataSourceType.New(param)
   248  	err = ownerDataSource.ReadStart()
   249  	if err != nil {
   250  		return
   251  	}
   252  	defer func() {
   253  		_ = ownerDataSource.ReadEnd()
   254  	}()
   255  	err = ownerDataSource.Read(nil, func(data *DataSourceData) (err error) {
   256  
   257  		if this_.IsStop {
   258  			return
   259  		}
   260  
   261  		if data.HasSql {
   262  			this_.countIncr(&this_.DataCount, 1)
   263  
   264  			var result sql.Result
   265  			result, err = DoExec(workDb, data.Sql, nil)
   266  			if err != nil {
   267  				this_.countIncr(&this_.DataErrorCount, 1)
   268  				if !this_.ErrorContinue {
   269  					err = errors.New("sql:" + data.Sql + " exec error," + err.Error())
   270  					return
   271  				}
   272  				err = nil
   273  			}
   274  			rowsAffected, _ := result.RowsAffected()
   275  			this_.countIncr(&this_.DataSuccessCount, int(rowsAffected))
   276  		}
   277  		return
   278  	})
   279  	if err != nil {
   280  		return
   281  	}
   282  	success = true
   283  	return
   284  }
   285  
   286  func (this_ *taskImport) importTable(workDb *sql.DB, ownerName string, tableName string, ownerPath string, tablePath string, columns []*TaskImportColumn) (success bool, err error) {
   287  
   288  	progress := &TaskProgress{
   289  		Title: "导入[" + ownerName + "." + tableName + "]",
   290  	}
   291  	defer func() {
   292  		if e := recover(); e != nil {
   293  			err = errors.New(fmt.Sprint(e))
   294  		}
   295  		if err != nil {
   296  			progress.Error = err.Error()
   297  			if progress.OnError != nil {
   298  				progress.OnError(err)
   299  			}
   300  		}
   301  
   302  		if this_.ErrorContinue {
   303  			err = nil
   304  		}
   305  	}()
   306  
   307  	this_.addProgress(progress)
   308  
   309  	if this_.IsStop {
   310  		return
   311  	}
   312  
   313  	if tablePath == "" {
   314  		if ownerPath == "" {
   315  			err = errors.New("import [" + ownerName + "." + tableName + "] table path is empty.")
   316  			return
   317  		}
   318  		tablePath = ownerPath + string(filepath.Separator) + tableName + "." + this_.DataSourceType.FileSuffix
   319  
   320  		var exists bool
   321  		exists, err = PathExists(tablePath)
   322  		if err != nil {
   323  			return
   324  		}
   325  		if !exists {
   326  			err = errors.New("import [" + ownerName + "." + tableName + "] path [" + tablePath + "] not exists.")
   327  			return
   328  		}
   329  		var isDir bool
   330  		isDir, err = PathIsDir(tablePath)
   331  		if err != nil {
   332  			return
   333  		}
   334  		if isDir {
   335  			err = errors.New("import [" + ownerName + "." + tableName + "] path [" + tablePath + "] is dir.")
   336  			return
   337  		}
   338  	}
   339  
   340  	if this_.DataSourceType == DataSourceTypeSql {
   341  		_, err = this_.importSql(workDb, ownerName, tablePath)
   342  		if err != nil {
   343  			return
   344  		}
   345  	} else {
   346  		var tableDetail *dialect.TableModel
   347  		tableDetail, err = TableDetail(workDb, this_.dia, this_.Param, ownerName, tableName, false)
   348  		if err != nil {
   349  			return
   350  		}
   351  		if tableDetail == nil {
   352  			err = errors.New("source db table [" + ownerName + "." + tableName + "] is not exist")
   353  			return
   354  		}
   355  
   356  		var tableDataSource DataSource
   357  		param := &DataSourceParam{
   358  			Path:      tablePath,
   359  			SheetName: tableName,
   360  			Dia:       this_.dia,
   361  		}
   362  		tableDataSource = this_.DataSourceType.New(param)
   363  		err = tableDataSource.ReadStart()
   364  		if err != nil {
   365  			return
   366  		}
   367  		defer func() {
   368  			_ = tableDataSource.ReadEnd()
   369  		}()
   370  
   371  		//if this_.ImportStructure {
   372  		//	err = this_.exportTableStructure(ownerDataSource, tableDataSource, tableDetail, targetOwnerName, targetTableName)
   373  		//	if err != nil {
   374  		//		return
   375  		//	}
   376  		//}
   377  		err = this_.importTableData(workDb, tableDataSource, tableDetail, ownerName, tableName, columns)
   378  		if err != nil {
   379  			return
   380  		}
   381  	}
   382  
   383  	success = true
   384  	return
   385  }
   386  func (this_ *taskImport) importTableData(workDb *sql.DB, tableDataSource DataSource, tableDetail *dialect.TableModel, targetOwnerName string, targetTableName string, columns []*TaskImportColumn) (err error) {
   387  
   388  	progress := &TaskProgress{
   389  		Title: "导入表数据[" + tableDetail.OwnerName + "." + tableDetail.TableName + "] 到 [" + targetOwnerName + "." + targetTableName + "]",
   390  	}
   391  	defer func() {
   392  		if e := recover(); e != nil {
   393  			err = errors.New(fmt.Sprint(e))
   394  		}
   395  		if err != nil {
   396  			progress.Error = err.Error()
   397  			if progress.OnError != nil {
   398  				progress.OnError(err)
   399  			}
   400  		}
   401  
   402  		if this_.ErrorContinue {
   403  			err = nil
   404  		}
   405  	}()
   406  
   407  	this_.addProgress(progress)
   408  
   409  	if this_.IsStop {
   410  		return
   411  	}
   412  
   413  	batchNumber := this_.BatchNumber
   414  	if batchNumber <= 0 {
   415  		batchNumber = 100
   416  	}
   417  	var columnCache = make(map[string]*dialect.ColumnModel)
   418  	for _, one := range tableDetail.ColumnList {
   419  		columnCache[one.ColumnName] = one
   420  	}
   421  	var newColumnList = tableDetail.ColumnList
   422  	if len(columns) > 0 {
   423  		newColumnList = []*dialect.ColumnModel{}
   424  		for _, one := range columns {
   425  			column := columnCache[one.Name]
   426  			newColumn := &dialect.ColumnModel{}
   427  			newColumn.ColumnName = one.Name
   428  			if column != nil {
   429  				newColumn.ColumnDataType = column.ColumnDataType
   430  				newColumn.ColumnDefault = column.ColumnDefault
   431  				newColumn.ColumnLength = column.ColumnLength
   432  				newColumn.ColumnPrecision = column.ColumnPrecision
   433  				newColumn.ColumnScale = column.ColumnScale
   434  			}
   435  			newColumnList = append(newColumnList, newColumn)
   436  		}
   437  	}
   438  
   439  	var dataList []map[string]interface{}
   440  
   441  	err = tableDataSource.Read(newColumnList, func(data *DataSourceData) (err error) {
   442  
   443  		if this_.IsStop {
   444  			return
   445  		}
   446  		if data.HasData && data.Data != nil {
   447  			dataList = append(dataList, data.Data)
   448  			this_.countIncr(&this_.DataCount, 1)
   449  			if len(dataList) >= batchNumber {
   450  				err = this_.importDataList(workDb, dataList, targetOwnerName, targetTableName, newColumnList)
   451  				dataList = make([]map[string]interface{}, 0)
   452  				if err != nil {
   453  					return
   454  				}
   455  			}
   456  
   457  		}
   458  		return
   459  	})
   460  	if err != nil {
   461  		return
   462  	}
   463  	if len(dataList) >= 0 {
   464  
   465  		if this_.IsStop {
   466  			return
   467  		}
   468  
   469  		err = this_.importDataList(workDb, dataList, targetOwnerName, targetTableName, newColumnList)
   470  		dataList = make([]map[string]interface{}, 0)
   471  		if err != nil {
   472  			return
   473  		}
   474  	}
   475  	return
   476  }
   477  
   478  func (this_ *taskImport) importDataList(workDb *sql.DB, dataList []map[string]interface{}, ownerName string, tableName string, columnList []*dialect.ColumnModel) (err error) {
   479  
   480  	dataListCount := len(dataList)
   481  	progress := &TaskProgress{
   482  		Title: "插入数据[" + ownerName + "." + tableName + "]",
   483  	}
   484  	defer func() {
   485  		if e := recover(); e != nil {
   486  			err = errors.New(fmt.Sprint(e))
   487  		}
   488  		if err != nil {
   489  			progress.Error = err.Error()
   490  			if progress.OnError != nil {
   491  				progress.OnError(err)
   492  			}
   493  			this_.countIncr(&this_.DataErrorCount, dataListCount)
   494  		} else {
   495  			this_.countIncr(&this_.DataSuccessCount, dataListCount)
   496  		}
   497  
   498  		if this_.ErrorContinue {
   499  			err = nil
   500  		}
   501  	}()
   502  
   503  	this_.addProgress(progress)
   504  
   505  	if this_.IsStop {
   506  		return
   507  	}
   508  
   509  	this_.countIncr(&this_.DataReadyCount, dataListCount)
   510  
   511  	var newColumnList []*dialect.ColumnModel
   512  	for _, one := range columnList {
   513  		if one.ColumnName != "" {
   514  			newColumnList = append(newColumnList, one)
   515  		}
   516  	}
   517  
   518  	_, _, batchSqlList, batchValuesList, err := this_.dia.DataListInsertSql(this_.Param, ownerName, tableName, newColumnList, dataList)
   519  	if err != nil {
   520  		return
   521  	}
   522  	var errSql string
   523  	_, errSql, _, err = DoExecs(workDb, batchSqlList, batchValuesList)
   524  	if err != nil {
   525  		if errSql != "" {
   526  			err = errors.New("sql:" + errSql + " exec error," + err.Error())
   527  		}
   528  		return
   529  	}
   530  	return
   531  }