package migrator

import (
	
	
	
	
	
	
	
	

	
	
	
	
)

// This regular expression seeks to find a sequence of digits (\d+) among zero or more non-digit characters (\D*),
// with a possible trailing non-digit character (\D?).

// For example, values that can pass this regular expression are:
// - "123"
// - "abc456"
// -"%$#@789"
var regFullDataType = regexp.MustCompile(`\D*(\d+)\D?`)

// TODO:? Create const vars for raw sql queries ?

// Migrator m struct
type Migrator struct {
	Config
}

// Config schema config
type Config struct {
	CreateIndexAfterCreateTable bool
	DB                          *gorm.DB
	gorm.Dialector
}

type printSQLLogger struct {
	logger.Interface
}

func ( *printSQLLogger) ( context.Context,  time.Time,  func() ( string,  int64),  error) {
	,  := ()
	fmt.Println( + ";")
	.Interface.Trace(, , , )
}

// GormDataTypeInterface gorm data type interface
type GormDataTypeInterface interface {
	GormDBDataType(*gorm.DB, *schema.Field) string
}

// RunWithValue run migration with statement value
func ( Migrator) ( interface{},  func(*gorm.Statement) error) error {
	 := &gorm.Statement{DB: .DB}
	if .DB.Statement != nil {
		.Table = .DB.Statement.Table
		.TableExpr = .DB.Statement.TableExpr
	}

	if ,  := .(string);  {
		.Table = 
	} else if  := .ParseWithSpecialTableName(, .Table);  != nil {
		return 
	}

	return ()
}

// DataTypeOf return field's db data type
func ( Migrator) ( *schema.Field) string {
	 := reflect.New(.IndirectFieldType)
	if ,  := .Interface().(GormDataTypeInterface);  {
		if  := .GormDBDataType(.DB, );  != "" {
			return 
		}
	}

	return .Dialector.DataTypeOf()
}

// FullDataTypeOf returns field's db full data type
func ( Migrator) ( *schema.Field) ( clause.Expr) {
	.SQL = .DataTypeOf()

	if .NotNull {
		.SQL += " NOT NULL"
	}

	if .Unique {
		.SQL += " UNIQUE"
	}

	if .HasDefaultValue && (.DefaultValueInterface != nil || .DefaultValue != "") {
		if .DefaultValueInterface != nil {
			 := &gorm.Statement{Vars: []interface{}{.DefaultValueInterface}}
			.Dialector.BindVarTo(, , .DefaultValueInterface)
			.SQL += " DEFAULT " + .Dialector.Explain(.SQL.String(), .DefaultValueInterface)
		} else if .DefaultValue != "(-)" {
			.SQL += " DEFAULT " + .DefaultValue
		}
	}

	return
}

// AutoMigrate auto migrate values
func ( Migrator) ( ...interface{}) error {
	for ,  := range .ReorderModels(, true) {
		 := .DB.Session(&gorm.Session{})
		 := 
		if .DB.DryRun {
			.DryRun = false
			 = .DB.Session(&gorm.Session{Logger: &printSQLLogger{Interface: .DB.Logger}})
		}
		if !.Migrator().HasTable() {
			if  := .Migrator().CreateTable();  != nil {
				return 
			}
		} else {
			if  := .RunWithValue(, func( *gorm.Statement) error {
				,  := .Migrator().ColumnTypes()
				if  != nil {
					return 
				}
				var (
					          = .Schema.ParseIndexes()
					 = .Schema.ParseCheckConstraints()
				)
				for ,  := range .Schema.DBNames {
					var  gorm.ColumnType

					for ,  := range  {
						if .Name() ==  {
							 = 
							break
						}
					}

					if  == nil {
						// not found, add column
						if  = .Migrator().AddColumn(, );  != nil {
							return 
						}
					} else {
						// found, smartly migrate
						 := .Schema.FieldsByDBName[]
						if  = .Migrator().MigrateColumn(, , );  != nil {
							return 
						}
					}
				}

				if !.DB.DisableForeignKeyConstraintWhenMigrating && !.DB.IgnoreRelationshipsWhenMigrating {
					for ,  := range .Schema.Relationships.Relations {
						if .Field.IgnoreMigration {
							continue
						}
						if  := .ParseConstraint();  != nil &&
							.Schema == .Schema && !.Migrator().HasConstraint(, .Name) {
							if  := .Migrator().CreateConstraint(, .Name);  != nil {
								return 
							}
						}
					}
				}

				for ,  := range  {
					if !.Migrator().HasConstraint(, .Name) {
						if  := .Migrator().CreateConstraint(, .Name);  != nil {
							return 
						}
					}
				}

				for ,  := range  {
					if !.Migrator().HasIndex(, .Name) {
						if  := .Migrator().CreateIndex(, .Name);  != nil {
							return 
						}
					}
				}

				return nil
			});  != nil {
				return 
			}
		}
	}

	return nil
}

// GetTables returns tables
func ( Migrator) () ( []string,  error) {
	 = .DB.Raw("SELECT TABLE_NAME FROM information_schema.tables where TABLE_SCHEMA=?", .CurrentDatabase()).
		Scan(&).Error
	return
}

// CreateTable create table in database for values
func ( Migrator) ( ...interface{}) error {
	for ,  := range .ReorderModels(, false) {
		 := .DB.Session(&gorm.Session{})
		if  := .RunWithValue(, func( *gorm.Statement) ( error) {
			var (
				          = "CREATE TABLE ? ("
				                  = []interface{}{.CurrentTable()}
				 bool
			)

			for ,  := range .Schema.DBNames {
				 := .Schema.FieldsByDBName[]
				if !.IgnoreMigration {
					 += "? ?"
					 =  || strings.Contains(strings.ToUpper(.DataTypeOf()), "PRIMARY KEY")
					 = append(, clause.Column{Name: }, .DB.Migrator().FullDataTypeOf())
					 += ","
				}
			}

			if ! && len(.Schema.PrimaryFields) > 0 {
				 += "PRIMARY KEY ?,"
				 := make([]interface{}, 0, len(.Schema.PrimaryFields))
				for ,  := range .Schema.PrimaryFields {
					 = append(, clause.Column{Name: .DBName})
				}

				 = append(, )
			}

			for ,  := range .Schema.ParseIndexes() {
				if .CreateIndexAfterCreateTable {
					defer func( interface{},  string) {
						if  == nil {
							 = .Migrator().CreateIndex(, )
						}
					}(, .Name)
				} else {
					if .Class != "" {
						 += .Class + " "
					}
					 += "INDEX ? ?"

					if .Comment != "" {
						 += fmt.Sprintf(" COMMENT '%s'", .Comment)
					}

					if .Option != "" {
						 += " " + .Option
					}

					 += ","
					 = append(, clause.Column{Name: .Name}, .Migrator().(BuildIndexOptionsInterface).BuildIndexOptions(.Fields, ))
				}
			}

			if !.DB.DisableForeignKeyConstraintWhenMigrating && !.DB.IgnoreRelationshipsWhenMigrating {
				for ,  := range .Schema.Relationships.Relations {
					if .Field.IgnoreMigration {
						continue
					}
					if  := .ParseConstraint();  != nil {
						if .Schema == .Schema {
							,  := buildConstraint()
							 +=  + ","
							 = append(, ...)
						}
					}
				}
			}

			for ,  := range .Schema.ParseCheckConstraints() {
				 += "CONSTRAINT ? CHECK (?),"
				 = append(, clause.Column{Name: .Name}, clause.Expr{SQL: .Constraint})
			}

			 = strings.TrimSuffix(, ",")

			 += ")"

			if ,  := .DB.Get("gorm:table_options");  {
				 += fmt.Sprint()
			}

			 = .Exec(, ...).Error
			return 
		});  != nil {
			return 
		}
	}
	return nil
}

// DropTable drop table for values
func ( Migrator) ( ...interface{}) error {
	 = .ReorderModels(, false)
	for  := len() - 1;  >= 0; -- {
		 := .DB.Session(&gorm.Session{})
		if  := .RunWithValue([], func( *gorm.Statement) error {
			return .Exec("DROP TABLE IF EXISTS ?", .CurrentTable()).Error
		});  != nil {
			return 
		}
	}
	return nil
}

// HasTable returns table exists or not for value, value could be a struct or string
func ( Migrator) ( interface{}) bool {
	var  int64

	.RunWithValue(, func( *gorm.Statement) error {
		 := .DB.Migrator().CurrentDatabase()
		return .DB.Raw("SELECT count(*) FROM information_schema.tables WHERE table_schema = ? AND table_name = ? AND table_type = ?", , .Table, "BASE TABLE").Row().Scan(&)
	})

	return  > 0
}

// RenameTable rename table from oldName to newName
func ( Migrator) (,  interface{}) error {
	var ,  interface{}
	if ,  := .(string);  {
		 = clause.Table{Name: }
	} else {
		 := &gorm.Statement{DB: .DB}
		if  := .Parse();  == nil {
			 = .CurrentTable()
		} else {
			return 
		}
	}

	if ,  := .(string);  {
		 = clause.Table{Name: }
	} else {
		 := &gorm.Statement{DB: .DB}
		if  := .Parse();  == nil {
			 = .CurrentTable()
		} else {
			return 
		}
	}

	return .DB.Exec("ALTER TABLE ? RENAME TO ?", , ).Error
}

// AddColumn create `name` column for value
func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		// avoid using the same name field
		 := .Schema.LookUpField()
		if  == nil {
			return fmt.Errorf("failed to look up field with name: %s", )
		}

		if !.IgnoreMigration {
			return .DB.Exec(
				"ALTER TABLE ? ADD ? ?",
				.CurrentTable(), clause.Column{Name: .DBName}, .DB.Migrator().FullDataTypeOf(),
			).Error
		}

		return nil
	})
}

// DropColumn drop value's `name` column
func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if  := .Schema.LookUpField();  != nil {
			 = .DBName
		}

		return .DB.Exec(
			"ALTER TABLE ? DROP COLUMN ?", .CurrentTable(), clause.Column{Name: },
		).Error
	})
}

// AlterColumn alter value's `field` column' type based on schema definition
func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if  := .Schema.LookUpField();  != nil {
			 := .FullDataTypeOf()
			return .DB.Exec(
				"ALTER TABLE ? ALTER COLUMN ? TYPE ?",
				.CurrentTable(), clause.Column{Name: .DBName}, ,
			).Error

		}
		return fmt.Errorf("failed to look up field with name: %s", )
	})
}

// HasColumn check has column `field` for value or not
func ( Migrator) ( interface{},  string) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		 := .DB.Migrator().CurrentDatabase()
		 := 
		if  := .Schema.LookUpField();  != nil {
			 = .DBName
		}

		return .DB.Raw(
			"SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_schema = ? AND table_name = ? AND column_name = ?",
			, .Table, ,
		).Row().Scan(&)
	})

	return  > 0
}

// RenameColumn rename value's field name from oldName to newName
func ( Migrator) ( interface{}, ,  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if  := .Schema.LookUpField();  != nil {
			 = .DBName
		}

		if  := .Schema.LookUpField();  != nil {
			 = .DBName
		}

		return .DB.Exec(
			"ALTER TABLE ? RENAME COLUMN ? TO ?",
			.CurrentTable(), clause.Column{Name: }, clause.Column{Name: },
		).Error
	})
}

// MigrateColumn migrate column
func ( Migrator) ( interface{},  *schema.Field,  gorm.ColumnType) error {
	// found, smart migrate
	 := strings.TrimSpace(strings.ToLower(.DB.Migrator().FullDataTypeOf().SQL))
	 := strings.ToLower(.DatabaseTypeName())

	var (
		 bool
		  =  == 
	)

	if !.PrimaryKey {
		// check type
		if !strings.HasPrefix(, ) {
			// check type aliases
			 := .DB.Migrator().GetTypeAliases()
			for ,  := range  {
				if strings.HasPrefix(, ) {
					 = true
					break
				}
			}

			if ! {
				 = true
			}
		}
	}

	if ! {
		// check size
		if ,  := .Length();  != int64(.Size) {
			if  > 0 && .Size > 0 {
				 = true
			} else {
				// has size in data type and not equal
				// Since the following code is frequently called in the for loop, reg optimization is needed here
				 := regFullDataType.FindAllStringSubmatch(, -1)
				if !.PrimaryKey &&
					(len() == 1 && [0][1] != fmt.Sprint() && ) {
					 = true
				}
			}
		}

		// check precision
		if , ,  := .DecimalSize();  && int64(.Precision) !=  {
			if regexp.MustCompile(fmt.Sprintf("[^0-9]%d[^0-9]", .Precision)).MatchString(.DataTypeOf()) {
				 = true
			}
		}
	}

	// check nullable
	if ,  := .Nullable();  &&  == .NotNull {
		// not primary key & database is nullable
		if !.PrimaryKey &&  {
			 = true
		}
	}

	// check unique
	if ,  := .Unique();  &&  != .Unique {
		// not primary key
		if !.PrimaryKey {
			 = true
		}
	}

	// check default value
	if !.PrimaryKey {
		 := .HasDefaultValue && (.DefaultValueInterface != nil || !strings.EqualFold(.DefaultValue, "NULL"))
		,  := .DefaultValue()
		if  && ! {
			// default value -> null
			 = true
		} else if ! &&  {
			// null -> default value
			 = true
		} else if (.GORMDataType != schema.Time &&  != .DefaultValue) ||
			(.GORMDataType == schema.Time && !strings.EqualFold(strings.TrimSuffix(, "()"), strings.TrimSuffix(.DefaultValue, "()"))) {
			// default value not equal
			// not both null
			if  ||  {
				 = true
			}
		}
	}

	// check comment
	if ,  := .Comment();  &&  != .Comment {
		// not primary key
		if !.PrimaryKey {
			 = true
		}
	}

	if  && !.IgnoreMigration {
		return .DB.Migrator().AlterColumn(, .DBName)
	}

	return nil
}

// ColumnTypes return columnTypes []gorm.ColumnType and execErr error
func ( Migrator) ( interface{}) ([]gorm.ColumnType, error) {
	 := make([]gorm.ColumnType, 0)
	 := .RunWithValue(, func( *gorm.Statement) ( error) {
		,  := .DB.Session(&gorm.Session{}).Table(.Table).Limit(1).Rows()
		if  != nil {
			return 
		}

		defer func() {
			 = .Close()
		}()

		var  []*sql.ColumnType
		,  = .ColumnTypes()
		if  != nil {
			return 
		}

		for ,  := range  {
			 = append(, ColumnType{SQLColumnType: })
		}

		return
	})

	return , 
}

// CreateView create view from Query in gorm.ViewOption.
// Query in gorm.ViewOption is a [subquery]
//
//	// CREATE VIEW `user_view` AS SELECT * FROM `users` WHERE age > 20
//	q := DB.Model(&User{}).Where("age > ?", 20)
//	DB.Debug().Migrator().CreateView("user_view", gorm.ViewOption{Query: q})
//
//	// CREATE OR REPLACE VIEW `users_view` AS SELECT * FROM `users` WITH CHECK OPTION
//	q := DB.Model(&User{})
//	DB.Debug().Migrator().CreateView("user_view", gorm.ViewOption{Query: q, Replace: true, CheckOption: "WITH CHECK OPTION"})
//
// [subquery]: https://gorm.io/docs/advanced_query.html#SubQuery
func ( Migrator) ( string,  gorm.ViewOption) error {
	if .Query == nil {
		return gorm.ErrSubQueryRequired
	}

	 := new(strings.Builder)
	.WriteString("CREATE ")
	if .Replace {
		.WriteString("OR REPLACE ")
	}
	.WriteString("VIEW ")
	.QuoteTo(, )
	.WriteString(" AS ")

	.DB.Statement.AddVar(, .Query)

	if .CheckOption != "" {
		.WriteString(" ")
		.WriteString(.CheckOption)
	}
	return .DB.Exec(.Explain(.String(), .DB.Statement.Vars...)).Error
}

// DropView drop view
func ( Migrator) ( string) error {
	return .DB.Exec("DROP VIEW IF EXISTS ?", clause.Table{Name: }).Error
}

func buildConstraint( *schema.Constraint) ( string,  []interface{}) {
	 = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??"
	if .OnDelete != "" {
		 += " ON DELETE " + .OnDelete
	}

	if .OnUpdate != "" {
		 += " ON UPDATE " + .OnUpdate
	}

	var ,  []interface{}
	for ,  := range .ForeignKeys {
		 = append(, clause.Column{Name: .DBName})
	}

	for ,  := range .References {
		 = append(, clause.Column{Name: .DBName})
	}
	 = append(, clause.Table{Name: .Name}, , clause.Table{Name: .ReferenceSchema.Table}, )
	return
}

// GuessConstraintAndTable guess statement's constraint and it's table based on name
func ( Migrator) ( *gorm.Statement,  string) ( *schema.Constraint,  *schema.Check,  string) {
	if .Schema == nil {
		return nil, nil, .Table
	}

	 := .Schema.ParseCheckConstraints()
	if ,  := [];  {
		return nil, &, .Table
	}

	 := func( *schema.Relationship) string {
		switch .Type {
		case schema.HasOne, schema.HasMany:
			return .FieldSchema.Table
		case schema.Many2Many:
			return .JoinTable.Table
		}
		return .Table
	}

	for ,  := range .Schema.Relationships.Relations {
		if  := .ParseConstraint();  != nil && .Name ==  {
			return , nil, ()
		}
	}

	if  := .Schema.LookUpField();  != nil {
		for  := range  {
			if [].Field ==  {
				 := []
				return nil, &, .Table
			}
		}

		for ,  := range .Schema.Relationships.Relations {
			if  := .ParseConstraint();  != nil && .Field ==  {
				return , nil, ()
			}
		}
	}

	return nil, nil, .Schema.Table
}

// CreateConstraint create constraint
func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		, ,  := .GuessConstraintAndTable(, )
		if  != nil {
			return .DB.Exec(
				"ALTER TABLE ? ADD CONSTRAINT ? CHECK (?)",
				.CurrentTable(), clause.Column{Name: .Name}, clause.Expr{SQL: .Constraint},
			).Error
		}

		if  != nil {
			 := []interface{}{clause.Table{Name: }}
			if .TableExpr != nil {
				[0] = .TableExpr
			}
			,  := buildConstraint()
			return .DB.Exec("ALTER TABLE ? ADD "+, append(, ...)...).Error
		}

		return nil
	})
}

// DropConstraint drop constraint
func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		, ,  := .GuessConstraintAndTable(, )
		if  != nil {
			 = .Name
		} else if  != nil {
			 = .Name
		}
		return .DB.Exec("ALTER TABLE ? DROP CONSTRAINT ?", clause.Table{Name: }, clause.Column{Name: }).Error
	})
}

// HasConstraint check has constraint or not
func ( Migrator) ( interface{},  string) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		 := .DB.Migrator().CurrentDatabase()
		, ,  := .GuessConstraintAndTable(, )
		if  != nil {
			 = .Name
		} else if  != nil {
			 = .Name
		}

		return .DB.Raw(
			"SELECT count(*) FROM INFORMATION_SCHEMA.table_constraints WHERE constraint_schema = ? AND table_name = ? AND constraint_name = ?",
			, , ,
		).Row().Scan(&)
	})

	return  > 0
}

// BuildIndexOptions build index options
func ( Migrator) ( []schema.IndexOption,  *gorm.Statement) ( []interface{}) {
	for ,  := range  {
		 := .Quote(.DBName)
		if .Expression != "" {
			 = .Expression
		} else if .Length > 0 {
			 += fmt.Sprintf("(%d)", .Length)
		}

		if .Collate != "" {
			 += " COLLATE " + .Collate
		}

		if .Sort != "" {
			 += " " + .Sort
		}
		 = append(, clause.Expr{SQL: })
	}
	return
}

// BuildIndexOptionsInterface build index options interface
type BuildIndexOptionsInterface interface {
	BuildIndexOptions([]schema.IndexOption, *gorm.Statement) []interface{}
}

// CreateIndex create index `name`
func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if  := .Schema.LookIndex();  != nil {
			 := .DB.Migrator().(BuildIndexOptionsInterface).BuildIndexOptions(.Fields, )
			 := []interface{}{clause.Column{Name: .Name}, .CurrentTable(), }

			 := "CREATE "
			if .Class != "" {
				 += .Class + " "
			}
			 += "INDEX ? ON ??"

			if .Type != "" {
				 += " USING " + .Type
			}

			if .Comment != "" {
				 += fmt.Sprintf(" COMMENT '%s'", .Comment)
			}

			if .Option != "" {
				 += " " + .Option
			}

			return .DB.Exec(, ...).Error
		}

		return fmt.Errorf("failed to create index with name %s", )
	})
}

// DropIndex drop index `name`
func ( Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if  := .Schema.LookIndex();  != nil {
			 = .Name
		}

		return .DB.Exec("DROP INDEX ? ON ?", clause.Column{Name: }, .CurrentTable()).Error
	})
}

// HasIndex check has index `name` or not
func ( Migrator) ( interface{},  string) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		 := .DB.Migrator().CurrentDatabase()
		if  := .Schema.LookIndex();  != nil {
			 = .Name
		}

		return .DB.Raw(
			"SELECT count(*) FROM information_schema.statistics WHERE table_schema = ? AND table_name = ? AND index_name = ?",
			, .Table, ,
		).Row().Scan(&)
	})

	return  > 0
}

// RenameIndex rename index from oldName to newName
func ( Migrator) ( interface{}, ,  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		return .DB.Exec(
			"ALTER TABLE ? RENAME INDEX ? TO ?",
			.CurrentTable(), clause.Column{Name: }, clause.Column{Name: },
		).Error
	})
}

// CurrentDatabase returns current database name
func ( Migrator) () ( string) {
	.DB.Raw("SELECT DATABASE()").Row().Scan(&)
	return
}

// ReorderModels reorder models according to constraint dependencies
func ( Migrator) ( []interface{},  bool) ( []interface{}) {
	type  struct {
		*gorm.Statement
		 []*schema.Schema
	}

	var (
		,  []string
		          = map[string]bool{}
		                 = map[*schema.Schema]bool{}
		                     = map[string]{}
		         func( string)
		               func( interface{},  bool)
	)

	 = func( interface{},  bool) {
		 := {
			: &gorm.Statement{DB: .DB, Dest: },
		}
		 := map[*schema.Schema]bool{}
		// support for special table name
		if  := .ParseWithSpecialTableName(, .DB.Statement.Table);  != nil {
			.DB.Logger.Error(context.Background(), "failed to parse value %#v, got error %v", , )
		}
		if ,  := [..Schema];  {
			return
		}
		[..Schema] = true

		if !.DB.IgnoreRelationshipsWhenMigrating {
			for ,  := range .Schema.Relationships.Relations {
				if .Field.IgnoreMigration {
					continue
				}
				if  := .ParseConstraint();  != nil && .Schema == ..Schema && .Schema != .ReferenceSchema {
					. = append(., .ReferenceSchema)
				}

				if .Type == schema.HasOne || .Type == schema.HasMany {
					[.FieldSchema] = true
				}

				if .JoinTable != nil {
					// append join value
					defer func( *schema.Relationship,  interface{}) {
						if ![.FieldSchema] {
							. = append(., .FieldSchema)
						} else {
							 := reflect.New(.FieldSchema.ModelType).Interface()
							(, )
						}
						(, )
					}(, reflect.New(.JoinTable.ModelType).Interface())
				}
			}
		}

		[.Schema.Table] = 

		if  {
			 = append(, .Schema.Table)
		}
	}

	 = func( string) {
		if ,  := [];  {
			return // avoid loop
		}
		[] = true

		if  {
			 := []
			for ,  := range . {
				if ,  := [.Table];  {
					(.Table)
				} else {
					(reflect.New(.ModelType).Interface(), )
					(.Table)
				}
			}
		}

		 = append(, )
	}

	for ,  := range  {
		if ,  := .(string);  {
			 = append(, )
		} else {
			(, true)
		}
	}

	for ,  := range  {
		()
	}

	for ,  := range  {
		 = append(, []..Dest)
	}
	return
}

// CurrentTable returns current statement's table expression
func ( Migrator) ( *gorm.Statement) interface{} {
	if .TableExpr != nil {
		return *.TableExpr
	}
	return clause.Table{Name: .Table}
}

// GetIndexes return Indexes []gorm.Index and execErr error
func ( Migrator) ( interface{}) ([]gorm.Index, error) {
	return nil, errors.New("not support")
}

// GetTypeAliases return database type aliases
func ( Migrator) ( string) []string {
	return nil
}

// TableType return tableType gorm.TableType and execErr error
func ( Migrator) ( interface{}) (gorm.TableType, error) {
	return nil, errors.New("not support")
}