package gormlite

import (
	
	
	

	
	
	
	
)

type _Migrator struct {
	migrator.Migrator
}

func ( *_Migrator) ( func() error) error {
	var  int
	.DB.Raw("PRAGMA foreign_keys").Scan(&)
	if  == 1 {
		.DB.Exec("PRAGMA foreign_keys = OFF")
		defer .DB.Exec("PRAGMA foreign_keys = ON")
	}

	return ()
}

func ( _Migrator) ( interface{}) bool {
	var  int
	.Migrator.RunWithValue(, func( *gorm.Statement) error {
		return .DB.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", .Table).Row().Scan(&)
	})
	return  > 0
}

func ( _Migrator) ( ...interface{}) error {
	return .RunWithoutForeignKey(func() error {
		 = .ReorderModels(, false)
		 := .DB.Session(&gorm.Session{})

		for  := len() - 1;  >= 0; -- {
			if  := .RunWithValue([], func( *gorm.Statement) error {
				return .Exec("DROP TABLE IF EXISTS ?", clause.Table{Name: .Table}).Error
			});  != nil {
				return 
			}
		}

		return nil
	})
}

func ( _Migrator) () ( []string,  error) {
	return , .DB.Raw("SELECT name FROM sqlite_master where type=?", "table").Scan(&).Error
}

func ( _Migrator) ( interface{},  string) bool {
	var  int
	.Migrator.RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookUpField();  != nil {
				 = .DBName
			}
		}

		if  != "" {
			.DB.Raw(
				"SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)",
				"table", .Table, `%"`++`" %`, `%`++` %`, "%`"++"`%", "%["++"]%", "%\t"++"\t%",
			).Row().Scan(&)
		}
		return nil
	})
	return  > 0
}

func ( _Migrator) ( interface{},  string) error {
	return .RunWithoutForeignKey(func() error {
		return .recreateTable(, nil, func( *ddl,  *gorm.Statement) (*ddl, []interface{}, error) {
			if  := .Schema.LookUpField();  != nil {
				var  []interface{}
				for ,  := range .fields {
					if  := columnRegexp.FindStringSubmatch(); len() > 1 && [1] == .DBName {
						.fields[] = fmt.Sprintf("`%v` ?", .DBName)
						 = []interface{}{.FullDataTypeOf()}
						// table created by old version might look like `CREATE TABLE ? (? varchar(10) UNIQUE)`.
						// FullDataTypeOf doesn't contain UNIQUE, so we need to add unique constraint.
						if strings.Contains(strings.ToUpper([3]), " UNIQUE") {
							 := .DB.NamingStrategy.UniqueName(.Table, .DBName)
							,  := .GuessConstraintInterfaceAndTable(, )
							if  != nil {
								,  := .Build()
								.addConstraint(, )
								 = append(, ...)
							}
						}
						break
					}
				}
				return , , nil
			}
			return nil, nil, fmt.Errorf("failed to alter field with name %v", )
		})
	})
}

// ColumnTypes return columnTypes []gorm.ColumnType and execErr error
func ( _Migrator) ( interface{}) ([]gorm.ColumnType, error) {
	 := make([]gorm.ColumnType, 0)
	 := .RunWithValue(, func( *gorm.Statement) ( error) {
		var (
			   []string
			 *ddl
		)

		if  := .DB.Raw("SELECT sql FROM sqlite_master WHERE type IN ? AND tbl_name = ? AND sql IS NOT NULL order by type = ? desc", []string{"table", "index"}, .Table, "table").Scan(&).Error;  != nil {
			return 
		}

		if ,  = parseDDL(...);  != nil {
			return 
		}

		,  := .DB.Session(&gorm.Session{}).Table(.Table).Limit(1).Rows()
		if  != nil {
			return 
		}
		defer func() {
			 = .Close()
		}()

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

		for ,  := range  {
			 := migrator.ColumnType{SQLColumnType: }
			for ,  := range .columns {
				if .NameValue.String == .Name() {
					.SQLColumnType = 
					 = 
					break
				}
			}
			 = append(, )
		}

		return 
	})

	return , 
}

func ( _Migrator) ( interface{},  string) error {
	return .recreateTable(, nil, func( *ddl,  *gorm.Statement) (*ddl, []interface{}, error) {
		if  := .Schema.LookUpField();  != nil {
			 = .DBName
		}

		.removeColumn()
		return , nil, nil
	})
}

func ( _Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		,  := .GuessConstraintInterfaceAndTable(, )

		return .recreateTable(, &,
			func( *ddl,  *gorm.Statement) (*ddl, []interface{}, error) {
				var (
					   string
					    string
					 []interface{}
				)

				if  != nil {
					 = .GetName()
					,  = .Build()
				} else {
					return nil, nil, nil
				}

				.addConstraint(, )
				return , , nil
			})
	})
}

func ( _Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		,  := .GuessConstraintInterfaceAndTable(, )
		if  != nil {
			 = .GetName()
		}

		return .recreateTable(, &,
			func( *ddl,  *gorm.Statement) (*ddl, []interface{}, error) {
				.removeConstraint()
				return , nil, nil
			})
	})
}

func ( _Migrator) ( interface{},  string) bool {
	var  int64
	.RunWithValue(, func( *gorm.Statement) error {
		,  := .GuessConstraintInterfaceAndTable(, )
		if  != nil {
			 = .GetName()
		}

		.DB.Raw(
			"SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)",
			"table", , `%CONSTRAINT "`++`" %`, `%CONSTRAINT `++` %`, "%CONSTRAINT `"++"`%", "%CONSTRAINT ["++"]%", "%CONSTRAINT \t"++"\t%",
		).Row().Scan(&)

		return nil
	})

	return  > 0
}

func ( _Migrator) () ( string) {
	var  interface{}
	.DB.Raw("PRAGMA database_list").Row().Scan(&, &, &)
	return
}

func ( _Migrator) ( []schema.IndexOption,  *gorm.Statement) ( []interface{}) {
	for ,  := range  {
		 := .Quote(.DBName)
		if .Expression != "" {
			 = .Expression
		}

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

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

func ( _Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookIndex();  != nil {
				 := .BuildIndexOptions(.Fields, )
				 := []interface{}{clause.Column{Name: .Name}, clause.Table{Name: .Table}, }

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

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

				if .Where != "" {
					 += " WHERE " + .Where
				}

				return .DB.Exec(, ...).Error
			}
		}
		return fmt.Errorf("failed to create index with name %v", )
	})
}

func ( _Migrator) ( interface{},  string) bool {
	var  int
	.RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookIndex();  != nil {
				 = .Name
			}
		}

		if  != "" {
			.DB.Raw(
				"SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", .Table, ,
			).Row().Scan(&)
		}
		return nil
	})
	return  > 0
}

func ( _Migrator) ( interface{}, ,  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		var  string
		.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", .Table, ).Row().Scan(&)
		if  != "" {
			if  := .DropIndex(, );  != nil {
				return 
			}
			return .DB.Exec(strings.Replace(, , , 1)).Error
		}
		return fmt.Errorf("failed to find index with name %v", )
	})
}

func ( _Migrator) ( interface{},  string) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		if .Schema != nil {
			if  := .Schema.LookIndex();  != nil {
				 = .Name
			}
		}

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

type _Index struct {
	Seq     int
	Name    string
	Unique  bool
	Origin  string
	Partial bool
}

// GetIndexes return Indexes []gorm.Index and execErr error,
// See the [doc]
//
// [doc]: https://sqlite.org/pragma.html#pragma_index_list
func ( _Migrator) ( interface{}) ([]gorm.Index, error) {
	 := make([]gorm.Index, 0)
	 := .RunWithValue(, func( *gorm.Statement) error {
		 := make([]*_Index, 0)
		if  := .DB.Debug().Raw("SELECT * FROM PRAGMA_index_list(?)", .Table).Scan(&).Error;  != nil { // alias `PRAGMA index_list(?)`
			return 
		}
		for ,  := range  {
			if .Origin == "u" { // skip the index was created by a UNIQUE constraint
				continue
			}
			var  []string
			if  := .DB.Raw("SELECT name FROM PRAGMA_index_info(?)", .Name).Scan(&).Error;  != nil { // alias `PRAGMA index_info(?)`
				return 
			}
			 = append(, &migrator.Index{
				TableName:       .Table,
				NameValue:       .Name,
				ColumnList:      ,
				PrimaryKeyValue: sql.NullBool{Bool: .Origin == "pk", Valid: true}, // The exceptions are INTEGER PRIMARY KEY
				UniqueValue:     sql.NullBool{Bool: .Unique, Valid: true},
			})
		}
		return nil
	})
	return , 
}

func ( _Migrator) ( string) (string, error) {
	var  string
	.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "table", , ).Row().Scan(&)

	if .DB.Error != nil {
		return "", .DB.Error
	}
	return , nil
}

func ( _Migrator) (
	 interface{},  *string,
	 func( *ddl,  *gorm.Statement) ( *ddl,  []interface{},  error),
) error {
	return .RunWithValue(, func( *gorm.Statement) error {
		 := .Table
		if  != nil {
			 = *
		}

		,  := .getRawDDL()
		if  != nil {
			return 
		}

		,  := parseDDL()
		if  != nil {
			return 
		}

		, ,  := (.clone(), )
		if  != nil {
			return 
		}
		if  == nil {
			return nil
		}

		 :=  + "__temp"
		if  := .renameTable(, );  != nil {
			return 
		}

		 := .getColumns()
		 := .compile()

		return .DB.Transaction(func( *gorm.DB) error {
			if  := .Exec(, ...).Error;  != nil {
				return 
			}

			 := []string{
				fmt.Sprintf("INSERT INTO `%v`(%v) SELECT %v FROM `%v`", , strings.Join(, ","), strings.Join(, ","), ),
				fmt.Sprintf("DROP TABLE `%v`", ),
				fmt.Sprintf("ALTER TABLE `%v` RENAME TO `%v`", , ),
			}
			for ,  := range  {
				if  := .Exec().Error;  != nil {
					return 
				}
			}
			return nil
		})
	})
}