github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/cmd/internal/ddl/table/ddl_test.go (about)

     1  package table
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	_ "github.com/go-sql-driver/mysql"
     8  	"github.com/jmoiron/sqlx"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/unionj-cloud/go-doudou/cmd/internal/ddl/columnenum"
    11  	"github.com/unionj-cloud/go-doudou/cmd/internal/ddl/sortenum"
    12  	"github.com/unionj-cloud/go-doudou/toolkit/sqlext/wrapper"
    13  	"reflect"
    14  	"testing"
    15  )
    16  
    17  func ExampleCreateTable() {
    18  	terminator, db, err := Setup()
    19  	if err != nil {
    20  		panic(err)
    21  	}
    22  	defer terminator()
    23  	defer db.Close()
    24  
    25  	expectjson := `{"Name":"user_createtable","Columns":[{"Table":"user","Name":"id","Type":"INT","Default":null,"Pk":true,"Nullable":false,"Unsigned":false,"Autoincrement":true,"Extra":"","Meta":{"Name":"ID","Type":"int","Tag":"dd:\"pk;auto\"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"name","Type":"VARCHAR(255)","Default":"'jack'","Pk":false,"Nullable":false,"Unsigned":false,"Autoincrement":false,"Extra":"","Meta":{"Name":"Name","Type":"string","Tag":"dd:\"index:name_phone_idx,2;default:'jack'\"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"phone","Type":"VARCHAR(255)","Default":"'13552053960'","Pk":false,"Nullable":false,"Unsigned":false,"Autoincrement":false,"Extra":"comment '手机号'","Meta":{"Name":"Phone","Type":"string","Tag":"dd:\"index:name_phone_idx,1;default:'13552053960';extra:comment '手机号'\"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"age","Type":"INT","Default":null,"Pk":false,"Nullable":false,"Unsigned":false,"Autoincrement":false,"Extra":"","Meta":{"Name":"Age","Type":"int","Tag":"dd:\"index\"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"no","Type":"INT","Default":null,"Pk":false,"Nullable":false,"Unsigned":false,"Autoincrement":false,"Extra":"","Meta":{"Name":"No","Type":"int","Tag":"dd:\"unique\"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"school","Type":"VARCHAR(255)","Default":"'harvard'","Pk":false,"Nullable":true,"Unsigned":false,"Autoincrement":false,"Extra":"comment '学校'","Meta":{"Name":"School","Type":"string","Tag":"dd:\"null;default:'harvard';extra:comment '学校'\"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"is_student","Type":"TINYINT","Default":null,"Pk":false,"Nullable":false,"Unsigned":false,"Autoincrement":false,"Extra":"","Meta":{"Name":"IsStudent","Type":"bool","Tag":"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"delete_at","Type":"DATETIME","Default":null,"Pk":false,"Nullable":true,"Unsigned":false,"Autoincrement":false,"Extra":"","Meta":{"Name":"DeleteAt","Type":"*time.Time","Tag":"","Comments":null},"AutoSet":false,"Indexes":null},{"Table":"user","Name":"create_at","Type":"DATETIME","Default":"CURRENT_TIMESTAMP","Pk":false,"Nullable":true,"Unsigned":false,"Autoincrement":false,"Extra":"","Meta":{"Name":"CreateAt","Type":"*time.Time","Tag":"dd:\"default:CURRENT_TIMESTAMP\"","Comments":null},"AutoSet":true,"Indexes":null},{"Table":"user","Name":"update_at","Type":"DATETIME","Default":"CURRENT_TIMESTAMP","Pk":false,"Nullable":true,"Unsigned":false,"Autoincrement":false,"Extra":"ON UPDATE CURRENT_TIMESTAMP","Meta":{"Name":"UpdateAt","Type":"*time.Time","Tag":"dd:\"default:CURRENT_TIMESTAMP;extra:ON UPDATE CURRENT_TIMESTAMP\"","Comments":null},"AutoSet":true,"Indexes":null}],"Pk":"id","Indexes":[{"Unique":false,"Name":"name_phone_idx","Items":[{"Unique":false,"Name":"","Column":"phone","Order":1,"Sort":"asc"},{"Unique":false,"Name":"","Column":"name","Order":2,"Sort":"asc"}]},{"Unique":false,"Name":"age_idx","Items":[{"Unique":false,"Name":"","Column":"age","Order":1,"Sort":"asc"}]},{"Unique":true,"Name":"no_idx","Items":[{"Unique":false,"Name":"","Column":"no","Order":1,"Sort":"asc"}]}],"Meta":{"Name":"User","Fields":[{"Name":"ID","Type":"int","Tag":"dd:\"pk;auto\"","Comments":null},{"Name":"Name","Type":"string","Tag":"dd:\"index:name_phone_idx,2;default:'jack'\"","Comments":null},{"Name":"Phone","Type":"string","Tag":"dd:\"index:name_phone_idx,1;default:'13552053960';extra:comment '手机号'\"","Comments":null},{"Name":"Age","Type":"int","Tag":"dd:\"index\"","Comments":null},{"Name":"No","Type":"int","Tag":"dd:\"unique\"","Comments":null},{"Name":"School","Type":"string","Tag":"dd:\"null;default:'harvard';extra:comment '学校'\"","Comments":null},{"Name":"IsStudent","Type":"bool","Tag":"","Comments":null},{"Name":"DeleteAt","Type":"*time.Time","Tag":"","Comments":null},{"Name":"CreateAt","Type":"*time.Time","Tag":"dd:\"default:CURRENT_TIMESTAMP\"","Comments":null},{"Name":"UpdateAt","Type":"*time.Time","Tag":"dd:\"default:CURRENT_TIMESTAMP;extra:ON UPDATE CURRENT_TIMESTAMP\"","Comments":null}],"Comments":["dd:table"],"Methods":null}}`
    26  	var table Table
    27  	if err = json.Unmarshal([]byte(expectjson), &table); err != nil {
    28  		panic(err)
    29  	}
    30  	if err := CreateTable(context.Background(), db, table); (err != nil) != false {
    31  		panic(fmt.Sprintf("CreateTable() error = %v, wantErr %v", err, false))
    32  	}
    33  
    34  	// Output:
    35  	//CREATE TABLE `user_createtable` (
    36  	//`id` INT NOT NULL AUTO_INCREMENT,
    37  	//`name` VARCHAR(255) NOT NULL DEFAULT 'jack',
    38  	//`phone` VARCHAR(255) NOT NULL DEFAULT '13552053960' comment '手机号',
    39  	//`age` INT NOT NULL,
    40  	//`no` INT NOT NULL,
    41  	//`school` VARCHAR(255) NULL DEFAULT 'harvard' comment '学校',
    42  	//`is_student` TINYINT NOT NULL,
    43  	//`delete_at` DATETIME NULL,
    44  	//`create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    45  	//`update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    46  	//PRIMARY KEY (`id`),
    47  	//INDEX `name_phone_idx` (`phone` asc,`name` asc),
    48  	//INDEX `age_idx` (`age` asc),
    49  	//UNIQUE INDEX `no_idx` (`no` asc))
    50  }
    51  
    52  func TestChangeColumn(t *testing.T) {
    53  	terminator, db, err := Setup()
    54  	if err != nil {
    55  		panic(err)
    56  	}
    57  	defer terminator()
    58  	defer db.Close()
    59  
    60  	type args struct {
    61  		db  *sqlx.DB
    62  		col Column
    63  	}
    64  	tests := []struct {
    65  		name    string
    66  		args    args
    67  		wantErr bool
    68  		errmsg  string
    69  	}{
    70  		{
    71  			name: "1",
    72  			args: args{
    73  				db: db,
    74  				col: Column{
    75  					Table:   "ddl_user",
    76  					Name:    "school",
    77  					Type:    "varchar(45)",
    78  					Default: "'Beijing Univ.'",
    79  				},
    80  			},
    81  			wantErr: false,
    82  		},
    83  		{
    84  			name: "2",
    85  			args: args{
    86  				db: db,
    87  				col: Column{
    88  					Table:   "ddl_user",
    89  					Name:    "school",
    90  					Type:    columnenum.TextType,
    91  					Default: "'Beijing Univ.'",
    92  				},
    93  			},
    94  			wantErr: true,
    95  			errmsg:  `Error 1101: BLOB, TEXT, GEOMETRY or JSON column 'school' can't have a default value`,
    96  		},
    97  		{
    98  			name: "3",
    99  			args: args{
   100  				db: db,
   101  				col: Column{
   102  					Table:   "ddl_user",
   103  					Name:    "school",
   104  					Type:    "varchar(45)",
   105  					Default: "Beijing Univ.",
   106  				},
   107  			},
   108  			wantErr: true,
   109  			errmsg:  `Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Beijing Univ.' at line 2`,
   110  		},
   111  	}
   112  	for _, tt := range tests {
   113  		t.Run(tt.name, func(t *testing.T) {
   114  			var err error
   115  			if err = ChangeColumn(context.Background(), tt.args.db, tt.args.col); (err != nil) != tt.wantErr {
   116  				t.Errorf("ChangeColumn() error = %v, wantErr %v", err, tt.wantErr)
   117  			}
   118  			if err != nil {
   119  				if err.Error() != tt.errmsg {
   120  					t.Errorf("want %s, got %s", tt.errmsg, err.Error())
   121  				}
   122  			}
   123  		})
   124  	}
   125  }
   126  
   127  func TestAddColumn(t *testing.T) {
   128  	terminator, db, err := Setup()
   129  	if err != nil {
   130  		panic(err)
   131  	}
   132  	defer terminator()
   133  	defer db.Close()
   134  
   135  	type args struct {
   136  		db  *sqlx.DB
   137  		col Column
   138  	}
   139  	tests := []struct {
   140  		name    string
   141  		args    args
   142  		wantErr bool
   143  		errmsg  string
   144  	}{
   145  		{
   146  			name: "1",
   147  			args: args{
   148  				db: db,
   149  				col: Column{
   150  					Table:   "ddl_user",
   151  					Name:    "favourite",
   152  					Type:    "varchar(45)",
   153  					Default: "'football'",
   154  				},
   155  			},
   156  			wantErr: false,
   157  		},
   158  	}
   159  	for _, tt := range tests {
   160  		t.Run(tt.name, func(t *testing.T) {
   161  			var err error
   162  			if err = AddColumn(context.Background(), tt.args.db, tt.args.col); (err != nil) != tt.wantErr {
   163  				t.Errorf("ChangeColumn() error = %v, wantErr %v", err, tt.wantErr)
   164  			}
   165  		})
   166  	}
   167  }
   168  
   169  func TestDropIndex(t *testing.T) {
   170  	terminator, db, err := Setup()
   171  	if err != nil {
   172  		panic(err)
   173  	}
   174  	defer terminator()
   175  	defer db.Close()
   176  
   177  	type args struct {
   178  		ctx context.Context
   179  		db  wrapper.Querier
   180  		idx Index
   181  	}
   182  	tests := []struct {
   183  		name    string
   184  		args    args
   185  		wantErr bool
   186  	}{
   187  		{
   188  			name: "",
   189  			args: args{
   190  				ctx: context.Background(),
   191  				db:  db,
   192  				idx: Index{
   193  					Table:  "ddl_user",
   194  					Unique: true,
   195  					Name:   "age_idx",
   196  					Items: []IndexItem{
   197  						{
   198  							Column: "age",
   199  							Order:  1,
   200  							Sort:   sortenum.Asc,
   201  						},
   202  					},
   203  				},
   204  			},
   205  			wantErr: false,
   206  		},
   207  	}
   208  	for _, tt := range tests {
   209  		t.Run(tt.name, func(t *testing.T) {
   210  			if err := dropIndex(tt.args.ctx, tt.args.db, tt.args.idx); (err != nil) != tt.wantErr {
   211  				t.Errorf("dropIndex() error = %v, wantErr %v", err, tt.wantErr)
   212  			}
   213  		})
   214  	}
   215  }
   216  
   217  func TestAddIndex(t *testing.T) {
   218  	terminator, db, err := Setup()
   219  	if err != nil {
   220  		panic(err)
   221  	}
   222  	defer terminator()
   223  	defer db.Close()
   224  
   225  	type args struct {
   226  		ctx context.Context
   227  		db  wrapper.Querier
   228  		idx Index
   229  	}
   230  	tests := []struct {
   231  		name    string
   232  		args    args
   233  		wantErr bool
   234  	}{
   235  		{
   236  			name: "",
   237  			args: args{
   238  				ctx: context.Background(),
   239  				db:  db,
   240  				idx: Index{
   241  					Table:  "ddl_user",
   242  					Unique: true,
   243  					Name:   "school_idx",
   244  					Items: []IndexItem{
   245  						{
   246  							Column: "school",
   247  							Order:  1,
   248  							Sort:   sortenum.Asc,
   249  						},
   250  					},
   251  				},
   252  			},
   253  			wantErr: false,
   254  		},
   255  	}
   256  	for _, tt := range tests {
   257  		t.Run(tt.name, func(t *testing.T) {
   258  			if err := addIndex(tt.args.ctx, tt.args.db, tt.args.idx); (err != nil) != tt.wantErr {
   259  				t.Errorf("addIndex() error = %v, wantErr %v", err, tt.wantErr)
   260  			}
   261  		})
   262  	}
   263  }
   264  
   265  func TestDropAddIndex(t *testing.T) {
   266  	terminator, db, err := Setup()
   267  	if err != nil {
   268  		panic(err)
   269  	}
   270  	defer terminator()
   271  	defer db.Close()
   272  
   273  	type args struct {
   274  		ctx context.Context
   275  		db  wrapper.Querier
   276  		idx Index
   277  	}
   278  	tests := []struct {
   279  		name    string
   280  		args    args
   281  		wantErr bool
   282  	}{
   283  		{
   284  			name: "",
   285  			args: args{
   286  				ctx: context.Background(),
   287  				db:  db,
   288  				idx: Index{
   289  					Table:  "ddl_user",
   290  					Unique: true,
   291  					Name:   "age_idx",
   292  					Items: []IndexItem{
   293  						{
   294  							Column: "age",
   295  							Order:  1,
   296  							Sort:   sortenum.Asc,
   297  						},
   298  						{
   299  							Column: "school",
   300  							Order:  2,
   301  							Sort:   sortenum.Asc,
   302  						},
   303  					},
   304  				},
   305  			},
   306  			wantErr: false,
   307  		},
   308  	}
   309  	for _, tt := range tests {
   310  		t.Run(tt.name, func(t *testing.T) {
   311  			if err := dropAddIndex(tt.args.ctx, tt.args.db, tt.args.idx); (err != nil) != tt.wantErr {
   312  				t.Errorf("dropAddIndex() error = %v, wantErr %v", err, tt.wantErr)
   313  			}
   314  		})
   315  	}
   316  }
   317  
   318  func Test_foreignKeys(t *testing.T) {
   319  	terminator, db, err := Setup()
   320  	if err != nil {
   321  		panic(err)
   322  	}
   323  	defer terminator()
   324  	defer db.Close()
   325  
   326  	type args struct {
   327  		ctx    context.Context
   328  		db     *sqlx.DB
   329  		schema string
   330  		t      string
   331  	}
   332  	tests := []struct {
   333  		name    string
   334  		args    args
   335  		wantFks []ForeignKey
   336  	}{
   337  		{
   338  			name: "",
   339  			args: args{
   340  				ctx:    context.Background(),
   341  				db:     db,
   342  				schema: "test",
   343  				t:      "ddl_book",
   344  			},
   345  			wantFks: []ForeignKey{
   346  				{
   347  					Table:           "ddl_book",
   348  					Constraint:      "fk_user",
   349  					Fk:              "user_id",
   350  					ReferencedTable: "ddl_user",
   351  					ReferencedCol:   "id",
   352  					UpdateRule:      "NO ACTION",
   353  					DeleteRule:      "CASCADE",
   354  					FullRule:        "ON DELETE CASCADE ON UPDATE NO ACTION",
   355  				},
   356  			},
   357  		},
   358  	}
   359  	for _, tt := range tests {
   360  		t.Run(tt.name, func(t *testing.T) {
   361  			if gotFks := foreignKeys(tt.args.ctx, tt.args.db, tt.args.schema, tt.args.t); !reflect.DeepEqual(gotFks, tt.wantFks) {
   362  				t.Errorf("foreignKeys() = %v, want %v", gotFks, tt.wantFks)
   363  			}
   364  		})
   365  	}
   366  }
   367  
   368  func TestTable2struct(t *testing.T) {
   369  	terminator, db, err := Setup()
   370  	if err != nil {
   371  		panic(err)
   372  	}
   373  	defer terminator()
   374  	defer db.Close()
   375  
   376  	type args struct {
   377  		ctx         context.Context
   378  		dir         string
   379  		pre         string
   380  		schema      string
   381  		existTables []string
   382  		db          *sqlx.DB
   383  	}
   384  	tests := []struct {
   385  		name       string
   386  		args       args
   387  		wantTables []Table
   388  	}{
   389  		{
   390  			name: "",
   391  			args: args{
   392  				ctx:         context.Background(),
   393  				pre:         "ddl_",
   394  				schema:      "test",
   395  				existTables: []string{"ddl_book", "ddl_user"},
   396  				db:          db,
   397  			},
   398  		},
   399  	}
   400  	for _, tt := range tests {
   401  		assert.NotPanics(t, func() {
   402  			Table2struct(tt.args.ctx, tt.args.pre, tt.args.schema, tt.args.existTables, tt.args.db)
   403  		})
   404  	}
   405  }
   406  
   407  func ExampleStruct2Table() {
   408  	terminator, db, err := Setup()
   409  	if err != nil {
   410  		panic(err)
   411  	}
   412  	defer terminator()
   413  	defer db.Close()
   414  
   415  	_ = Struct2Table(context.Background(), "../testdata/domain", "ddl_", []string{"ddl_user", "ddl_book"}, db, "test")
   416  	// Output:
   417  	//CREATE TABLE `ddl_order` (
   418  	//`id` INT NOT NULL AUTO_INCREMENT,
   419  	//`amount` BIGINT NOT NULL,
   420  	//`user_id` int NOT NULL,
   421  	//`create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
   422  	//`delete_at` DATETIME NULL,
   423  	//`update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
   424  	//PRIMARY KEY (`id`),
   425  	//CONSTRAINT `fk_ddl_user` FOREIGN KEY (`user_id`)
   426  	//REFERENCES `ddl_user`(`id`)
   427  	//ON DELETE CASCADE ON UPDATE NO ACTION)
   428  	//ALTER TABLE `ddl_user`
   429  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   430  	//ALTER TABLE `ddl_user`
   431  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL DEFAULT 'jack';
   432  	//ALTER TABLE `ddl_user`
   433  	//CHANGE COLUMN `phone` `phone` VARCHAR(255) NOT NULL DEFAULT '13552053960' comment '手机号';
   434  	//ALTER TABLE `ddl_user`
   435  	//CHANGE COLUMN `age` `age` INT NOT NULL;
   436  	//ALTER TABLE `ddl_user`
   437  	//CHANGE COLUMN `no` `no` int NOT NULL;
   438  	//ALTER TABLE `ddl_user`
   439  	//ADD COLUMN `unique_col` int NOT NULL;
   440  	//ALTER TABLE `ddl_user`
   441  	//ADD COLUMN `unique_col_2` int NOT NULL;
   442  	//ALTER TABLE `ddl_user`
   443  	//CHANGE COLUMN `school` `school` VARCHAR(255) NULL DEFAULT 'harvard' comment '学校';
   444  	//ALTER TABLE `ddl_user`
   445  	//CHANGE COLUMN `is_student` `is_student` TINYINT NOT NULL;
   446  	//ALTER TABLE `ddl_user`
   447  	//ADD COLUMN `rule` varchar(255) NOT NULL comment '链接匹配规则,匹配的链接采用该css规则来爬';
   448  	//ALTER TABLE `ddl_user`
   449  	//ADD COLUMN `rule_type` varchar(45) NOT NULL comment '链接匹配规则类型,支持prefix前缀匹配和regex正则匹配';
   450  	//ALTER TABLE `ddl_user`
   451  	//ADD COLUMN `arrive_at` datetime NULL comment '到货时间';
   452  	//ALTER TABLE `ddl_user`
   453  	//ADD COLUMN `status` tinyint(4) NOT NULL comment '0进行中
   454  	//1完结
   455  	//2取消';
   456  	//ALTER TABLE `ddl_user`
   457  	//CHANGE COLUMN `create_at` `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   458  	//ALTER TABLE `ddl_user`
   459  	//CHANGE COLUMN `delete_at` `delete_at` DATETIME NULL;
   460  	//ALTER TABLE `ddl_user`
   461  	//CHANGE COLUMN `update_at` `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   462  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `rule_idx` (`rule` asc);
   463  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `unique_col_idx` (`unique_col` asc,`unique_col_2` asc);
   464  }
   465  
   466  func ExampleStruct2TableDrapAddFk() {
   467  	terminator, db, err := Setup()
   468  	if err != nil {
   469  		panic(err)
   470  	}
   471  	defer terminator()
   472  	defer db.Close()
   473  
   474  	_ = Struct2Table(context.Background(), "../testdata/domain2", "ddl_", []string{"ddl_user", "ddl_book", "ddl_publisher"}, db, "test")
   475  	// Output:
   476  	//ALTER TABLE `ddl_book`
   477  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   478  	//ALTER TABLE `ddl_book`
   479  	//CHANGE COLUMN `user_id` `user_id` int NOT NULL;
   480  	//ALTER TABLE `ddl_book`
   481  	//CHANGE COLUMN `publisher_id` `publisher_id` INT NOT NULL;
   482  	//ALTER TABLE `ddl_book`
   483  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   484  	//ALTER TABLE `ddl_book`
   485  	//ADD COLUMN `delete_at` DATETIME NULL;
   486  	//ALTER TABLE `ddl_book`
   487  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   488  	//ALTER TABLE `ddl_book` DROP FOREIGN KEY fk_user;
   489  	//ALTER TABLE `ddl_book` ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES ddl_publisher(id) ON DELETE CASCADE ON UPDATE NO ACTION;
   490  	//ALTER TABLE `ddl_publisher`
   491  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   492  	//ALTER TABLE `ddl_publisher`
   493  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL;
   494  	//ALTER TABLE `ddl_publisher`
   495  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   496  	//ALTER TABLE `ddl_publisher`
   497  	//ADD COLUMN `delete_at` DATETIME NULL;
   498  	//ALTER TABLE `ddl_publisher`
   499  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   500  	//ALTER TABLE `ddl_user`
   501  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   502  	//ALTER TABLE `ddl_user`
   503  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL DEFAULT 'jack';
   504  	//ALTER TABLE `ddl_user`
   505  	//CHANGE COLUMN `phone` `phone` VARCHAR(255) NOT NULL DEFAULT '13552053960' comment '手机号';
   506  	//ALTER TABLE `ddl_user`
   507  	//CHANGE COLUMN `age` `age` INT NOT NULL;
   508  	//ALTER TABLE `ddl_user`
   509  	//CHANGE COLUMN `no` `no` int NOT NULL;
   510  	//ALTER TABLE `ddl_user`
   511  	//ADD COLUMN `unique_col` int NOT NULL;
   512  	//ALTER TABLE `ddl_user`
   513  	//ADD COLUMN `unique_col_2` int NOT NULL;
   514  	//ALTER TABLE `ddl_user`
   515  	//CHANGE COLUMN `school` `school` VARCHAR(255) NULL DEFAULT 'harvard' comment '学校';
   516  	//ALTER TABLE `ddl_user`
   517  	//CHANGE COLUMN `is_student` `is_student` TINYINT NOT NULL;
   518  	//ALTER TABLE `ddl_user`
   519  	//ADD COLUMN `rule` varchar(255) NOT NULL comment '链接匹配规则,匹配的链接采用该css规则来爬';
   520  	//ALTER TABLE `ddl_user`
   521  	//ADD COLUMN `rule_type` varchar(45) NOT NULL comment '链接匹配规则类型,支持prefix前缀匹配和regex正则匹配';
   522  	//ALTER TABLE `ddl_user`
   523  	//ADD COLUMN `arrive_at` datetime NULL comment '到货时间';
   524  	//ALTER TABLE `ddl_user`
   525  	//ADD COLUMN `status` tinyint(4) NOT NULL comment '0进行中
   526  	//1完结
   527  	//2取消';
   528  	//ALTER TABLE `ddl_user`
   529  	//CHANGE COLUMN `create_at` `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   530  	//ALTER TABLE `ddl_user`
   531  	//CHANGE COLUMN `delete_at` `delete_at` DATETIME NULL;
   532  	//ALTER TABLE `ddl_user`
   533  	//CHANGE COLUMN `update_at` `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   534  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `rule_idx` (`rule` asc);
   535  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `unique_col_idx` (`unique_col` asc,`unique_col_2` asc);
   536  }
   537  
   538  func ExampleStruct2TableShouldDropDropFkAddFk() {
   539  	terminator, db, err := Setup()
   540  	if err != nil {
   541  		panic(err)
   542  	}
   543  	defer terminator()
   544  	defer db.Close()
   545  
   546  	_ = Struct2Table(context.Background(), "../testdata/domain3", "ddl_", []string{"ddl_user", "ddl_book", "ddl_publisher"}, db, "test")
   547  	// Output:
   548  	//ALTER TABLE `ddl_book`
   549  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   550  	//ALTER TABLE `ddl_book`
   551  	//CHANGE COLUMN `user_id` `user_id` int NOT NULL;
   552  	//ALTER TABLE `ddl_book`
   553  	//CHANGE COLUMN `publisher_id` `publisher_id` INT NOT NULL;
   554  	//ALTER TABLE `ddl_book`
   555  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   556  	//ALTER TABLE `ddl_book`
   557  	//ADD COLUMN `delete_at` DATETIME NULL;
   558  	//ALTER TABLE `ddl_book`
   559  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   560  	//ALTER TABLE `ddl_book` ADD CONSTRAINT fk_publisher FOREIGN KEY (publisher_id) REFERENCES ddl_publisher(id) ON DELETE CASCADE ON UPDATE NO ACTION;
   561  	//ALTER TABLE `ddl_book` DROP FOREIGN KEY fk_user;
   562  	//ALTER TABLE `ddl_publisher`
   563  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   564  	//ALTER TABLE `ddl_publisher`
   565  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL;
   566  	//ALTER TABLE `ddl_publisher`
   567  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   568  	//ALTER TABLE `ddl_publisher`
   569  	//ADD COLUMN `delete_at` DATETIME NULL;
   570  	//ALTER TABLE `ddl_publisher`
   571  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   572  	//ALTER TABLE `ddl_user`
   573  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   574  	//ALTER TABLE `ddl_user`
   575  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL DEFAULT 'jack';
   576  	//ALTER TABLE `ddl_user`
   577  	//CHANGE COLUMN `phone` `phone` VARCHAR(255) NOT NULL DEFAULT '13552053960' comment '手机号';
   578  	//ALTER TABLE `ddl_user`
   579  	//CHANGE COLUMN `age` `age` INT NOT NULL;
   580  	//ALTER TABLE `ddl_user`
   581  	//CHANGE COLUMN `no` `no` int NOT NULL;
   582  	//ALTER TABLE `ddl_user`
   583  	//ADD COLUMN `unique_col` int NOT NULL;
   584  	//ALTER TABLE `ddl_user`
   585  	//ADD COLUMN `unique_col_2` int NOT NULL;
   586  	//ALTER TABLE `ddl_user`
   587  	//CHANGE COLUMN `school` `school` VARCHAR(255) NULL DEFAULT 'harvard' comment '学校';
   588  	//ALTER TABLE `ddl_user`
   589  	//CHANGE COLUMN `is_student` `is_student` TINYINT NOT NULL;
   590  	//ALTER TABLE `ddl_user`
   591  	//ADD COLUMN `rule` varchar(255) NOT NULL comment '链接匹配规则,匹配的链接采用该css规则来爬';
   592  	//ALTER TABLE `ddl_user`
   593  	//ADD COLUMN `rule_type` varchar(45) NOT NULL comment '链接匹配规则类型,支持prefix前缀匹配和regex正则匹配';
   594  	//ALTER TABLE `ddl_user`
   595  	//ADD COLUMN `arrive_at` datetime NULL comment '到货时间';
   596  	//ALTER TABLE `ddl_user`
   597  	//ADD COLUMN `status` tinyint(4) NOT NULL comment '0进行中
   598  	//1完结
   599  	//2取消';
   600  	//ALTER TABLE `ddl_user`
   601  	//CHANGE COLUMN `create_at` `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   602  	//ALTER TABLE `ddl_user`
   603  	//CHANGE COLUMN `delete_at` `delete_at` DATETIME NULL;
   604  	//ALTER TABLE `ddl_user`
   605  	//CHANGE COLUMN `update_at` `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   606  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `rule_idx` (`rule` asc);
   607  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `unique_col_idx` (`unique_col` asc,`unique_col_2` asc);
   608  	//ALTER TABLE `ddl_user` DROP INDEX `age_idx`;
   609  }
   610  
   611  func ExampleStruct2TableFkContinue() {
   612  	terminator, db, err := Setup()
   613  	if err != nil {
   614  		panic(err)
   615  	}
   616  	defer terminator()
   617  	defer db.Close()
   618  
   619  	_ = Struct2Table(context.Background(), "../testdata/domain4", "ddl_", []string{"ddl_user", "ddl_book", "ddl_publisher"}, db, "test")
   620  	// Output:
   621  	//ALTER TABLE `ddl_book`
   622  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   623  	//ALTER TABLE `ddl_book`
   624  	//CHANGE COLUMN `user_id` `user_id` int NOT NULL;
   625  	//ALTER TABLE `ddl_book`
   626  	//CHANGE COLUMN `publisher_id` `publisher_id` INT NOT NULL;
   627  	//ALTER TABLE `ddl_book`
   628  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   629  	//ALTER TABLE `ddl_book`
   630  	//ADD COLUMN `delete_at` DATETIME NULL;
   631  	//ALTER TABLE `ddl_book`
   632  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   633  	//ALTER TABLE `ddl_publisher`
   634  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   635  	//ALTER TABLE `ddl_publisher`
   636  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL;
   637  	//ALTER TABLE `ddl_publisher`
   638  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   639  	//ALTER TABLE `ddl_publisher`
   640  	//ADD COLUMN `delete_at` DATETIME NULL;
   641  	//ALTER TABLE `ddl_publisher`
   642  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   643  	//ALTER TABLE `ddl_user`
   644  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   645  	//ALTER TABLE `ddl_user`
   646  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL DEFAULT 'jack';
   647  	//ALTER TABLE `ddl_user`
   648  	//CHANGE COLUMN `phone` `phone` VARCHAR(255) NOT NULL DEFAULT '13552053960' comment '手机号';
   649  	//ALTER TABLE `ddl_user`
   650  	//CHANGE COLUMN `age` `age` INT NOT NULL;
   651  	//ALTER TABLE `ddl_user`
   652  	//CHANGE COLUMN `no` `no` int NOT NULL;
   653  	//ALTER TABLE `ddl_user`
   654  	//ADD COLUMN `unique_col` int NOT NULL;
   655  	//ALTER TABLE `ddl_user`
   656  	//ADD COLUMN `unique_col_2` int NOT NULL;
   657  	//ALTER TABLE `ddl_user`
   658  	//CHANGE COLUMN `school` `school` VARCHAR(255) NULL DEFAULT 'harvard' comment '学校';
   659  	//ALTER TABLE `ddl_user`
   660  	//CHANGE COLUMN `is_student` `is_student` TINYINT NOT NULL;
   661  	//ALTER TABLE `ddl_user`
   662  	//ADD COLUMN `rule` varchar(255) NOT NULL comment '链接匹配规则,匹配的链接采用该css规则来爬';
   663  	//ALTER TABLE `ddl_user`
   664  	//ADD COLUMN `rule_type` varchar(45) NOT NULL comment '链接匹配规则类型,支持prefix前缀匹配和regex正则匹配';
   665  	//ALTER TABLE `ddl_user`
   666  	//ADD COLUMN `arrive_at` datetime NULL comment '到货时间';
   667  	//ALTER TABLE `ddl_user`
   668  	//ADD COLUMN `status` tinyint(4) NOT NULL comment '0进行中
   669  	//1完结
   670  	//2取消';
   671  	//ALTER TABLE `ddl_user`
   672  	//CHANGE COLUMN `create_at` `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   673  	//ALTER TABLE `ddl_user`
   674  	//CHANGE COLUMN `delete_at` `delete_at` DATETIME NULL;
   675  	//ALTER TABLE `ddl_user`
   676  	//CHANGE COLUMN `update_at` `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   677  	//ALTER TABLE `ddl_user` DROP INDEX `name_phone_idx`;
   678  	//ALTER TABLE `ddl_user` ADD  INDEX `name_phone_idx` (`school` asc,`name` asc);
   679  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `rule_idx` (`rule` asc);
   680  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `unique_col_idx` (`unique_col` asc,`unique_col_2` asc);
   681  	//ALTER TABLE `ddl_user` DROP INDEX `age_idx`;
   682  }
   683  
   684  func ExampleStruct2TableDropAddIndex_name_phone_idx() {
   685  	terminator, db, err := Setup()
   686  	if err != nil {
   687  		panic(err)
   688  	}
   689  	defer terminator()
   690  	defer db.Close()
   691  
   692  	_ = Struct2Table(context.Background(), "../testdata/domain4", "ddl_", []string{"ddl_user", "ddl_book", "ddl_publisher"}, db, "test")
   693  	// Output:
   694  	//ALTER TABLE `ddl_book`
   695  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   696  	//ALTER TABLE `ddl_book`
   697  	//CHANGE COLUMN `user_id` `user_id` int NOT NULL;
   698  	//ALTER TABLE `ddl_book`
   699  	//CHANGE COLUMN `publisher_id` `publisher_id` INT NOT NULL;
   700  	//ALTER TABLE `ddl_book`
   701  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   702  	//ALTER TABLE `ddl_book`
   703  	//ADD COLUMN `delete_at` DATETIME NULL;
   704  	//ALTER TABLE `ddl_book`
   705  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   706  	//ALTER TABLE `ddl_publisher`
   707  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   708  	//ALTER TABLE `ddl_publisher`
   709  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL;
   710  	//ALTER TABLE `ddl_publisher`
   711  	//ADD COLUMN `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   712  	//ALTER TABLE `ddl_publisher`
   713  	//ADD COLUMN `delete_at` DATETIME NULL;
   714  	//ALTER TABLE `ddl_publisher`
   715  	//ADD COLUMN `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   716  	//ALTER TABLE `ddl_user`
   717  	//CHANGE COLUMN `id` `id` INT NOT NULL AUTO_INCREMENT;
   718  	//ALTER TABLE `ddl_user`
   719  	//CHANGE COLUMN `name` `name` VARCHAR(255) NOT NULL DEFAULT 'jack';
   720  	//ALTER TABLE `ddl_user`
   721  	//CHANGE COLUMN `phone` `phone` VARCHAR(255) NOT NULL DEFAULT '13552053960' comment '手机号';
   722  	//ALTER TABLE `ddl_user`
   723  	//CHANGE COLUMN `age` `age` INT NOT NULL;
   724  	//ALTER TABLE `ddl_user`
   725  	//CHANGE COLUMN `no` `no` int NOT NULL;
   726  	//ALTER TABLE `ddl_user`
   727  	//ADD COLUMN `unique_col` int NOT NULL;
   728  	//ALTER TABLE `ddl_user`
   729  	//ADD COLUMN `unique_col_2` int NOT NULL;
   730  	//ALTER TABLE `ddl_user`
   731  	//CHANGE COLUMN `school` `school` VARCHAR(255) NULL DEFAULT 'harvard' comment '学校';
   732  	//ALTER TABLE `ddl_user`
   733  	//CHANGE COLUMN `is_student` `is_student` TINYINT NOT NULL;
   734  	//ALTER TABLE `ddl_user`
   735  	//ADD COLUMN `rule` varchar(255) NOT NULL comment '链接匹配规则,匹配的链接采用该css规则来爬';
   736  	//ALTER TABLE `ddl_user`
   737  	//ADD COLUMN `rule_type` varchar(45) NOT NULL comment '链接匹配规则类型,支持prefix前缀匹配和regex正则匹配';
   738  	//ALTER TABLE `ddl_user`
   739  	//ADD COLUMN `arrive_at` datetime NULL comment '到货时间';
   740  	//ALTER TABLE `ddl_user`
   741  	//ADD COLUMN `status` tinyint(4) NOT NULL comment '0进行中
   742  	//1完结
   743  	//2取消';
   744  	//ALTER TABLE `ddl_user`
   745  	//CHANGE COLUMN `create_at` `create_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
   746  	//ALTER TABLE `ddl_user`
   747  	//CHANGE COLUMN `delete_at` `delete_at` DATETIME NULL;
   748  	//ALTER TABLE `ddl_user`
   749  	//CHANGE COLUMN `update_at` `update_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
   750  	//ALTER TABLE `ddl_user` DROP INDEX `name_phone_idx`;
   751  	//ALTER TABLE `ddl_user` ADD  INDEX `name_phone_idx` (`school` asc,`name` asc);
   752  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `rule_idx` (`rule` asc);
   753  	//ALTER TABLE `ddl_user` ADD UNIQUE INDEX `unique_col_idx` (`unique_col` asc,`unique_col_2` asc);
   754  	//ALTER TABLE `ddl_user` DROP INDEX `age_idx`;
   755  }
   756  
   757  func Test_addFk(t *testing.T) {
   758  	terminator, db, err := Setup()
   759  	if err != nil {
   760  		panic(err)
   761  	}
   762  	defer terminator()
   763  	defer db.Close()
   764  
   765  	type args struct {
   766  		ctx context.Context
   767  		db  wrapper.Querier
   768  		fk  ForeignKey
   769  	}
   770  	tests := []struct {
   771  		name    string
   772  		args    args
   773  		wantErr bool
   774  	}{
   775  		{
   776  			name: "",
   777  			args: args{
   778  				ctx: context.Background(),
   779  				db:  db,
   780  				fk: ForeignKey{
   781  					Table:           "ddl_book",
   782  					Constraint:      "fk_addFk",
   783  					Fk:              "publisher_id",
   784  					ReferencedTable: "ddl_publisher",
   785  					ReferencedCol:   "id",
   786  					UpdateRule:      "NO ACTION",
   787  					DeleteRule:      "NO ACTION",
   788  					FullRule:        "ON DELETE NO ACTION ON UPDATE NO ACTION",
   789  				},
   790  			},
   791  			wantErr: false,
   792  		},
   793  	}
   794  	for _, tt := range tests {
   795  		t.Run(tt.name, func(t *testing.T) {
   796  			if err := addFk(tt.args.ctx, tt.args.db, tt.args.fk); (err != nil) != tt.wantErr {
   797  				t.Errorf("addFk() error = %v, wantErr %v", err, tt.wantErr)
   798  			}
   799  		})
   800  	}
   801  }
   802  
   803  func Test_dropFk(t *testing.T) {
   804  	terminator, db, err := Setup()
   805  	if err != nil {
   806  		panic(err)
   807  	}
   808  	defer terminator()
   809  	defer db.Close()
   810  
   811  	type args struct {
   812  		ctx context.Context
   813  		db  wrapper.Querier
   814  		fk  ForeignKey
   815  	}
   816  	tests := []struct {
   817  		name    string
   818  		args    args
   819  		wantErr bool
   820  	}{
   821  		{
   822  			name: "",
   823  			args: args{
   824  				ctx: context.Background(),
   825  				db:  db,
   826  				fk: ForeignKey{
   827  					Table:           "ddl_book",
   828  					Constraint:      "fk_user",
   829  					Fk:              "user_id",
   830  					ReferencedTable: "ddl_user",
   831  					ReferencedCol:   "id",
   832  					UpdateRule:      "NO ACTION",
   833  					DeleteRule:      "NO ACTION",
   834  					FullRule:        "ON DELETE NO ACTION ON UPDATE NO ACTION",
   835  				},
   836  			},
   837  			wantErr: false,
   838  		},
   839  	}
   840  	for _, tt := range tests {
   841  		t.Run(tt.name, func(t *testing.T) {
   842  			if err := dropFk(tt.args.ctx, tt.args.db, tt.args.fk); (err != nil) != tt.wantErr {
   843  				t.Errorf("addFk() error = %v, wantErr %v", err, tt.wantErr)
   844  			}
   845  		})
   846  	}
   847  }
   848  
   849  func Test_dropAddFk(t *testing.T) {
   850  	terminator, db, err := Setup()
   851  	if err != nil {
   852  		panic(err)
   853  	}
   854  	defer terminator()
   855  	defer db.Close()
   856  
   857  	type args struct {
   858  		ctx context.Context
   859  		db  wrapper.Querier
   860  		fk  ForeignKey
   861  	}
   862  	tests := []struct {
   863  		name    string
   864  		args    args
   865  		wantErr bool
   866  	}{
   867  		{
   868  			name: "",
   869  			args: args{
   870  				ctx: context.Background(),
   871  				db:  db,
   872  				fk: ForeignKey{
   873  					Table:           "ddl_book",
   874  					Constraint:      "fk_user",
   875  					Fk:              "user_id",
   876  					ReferencedTable: "ddl_publisher",
   877  					ReferencedCol:   "id",
   878  					UpdateRule:      "NO ACTION",
   879  					DeleteRule:      "NO ACTION",
   880  					FullRule:        "ON DELETE NO ACTION ON UPDATE NO ACTION",
   881  				},
   882  			},
   883  			wantErr: false,
   884  		},
   885  	}
   886  	for _, tt := range tests {
   887  		t.Run(tt.name, func(t *testing.T) {
   888  			if err := dropAddFk(tt.args.ctx, tt.args.db, tt.args.fk); (err != nil) != tt.wantErr {
   889  				t.Errorf("addFk() error = %v, wantErr %v", err, tt.wantErr)
   890  			}
   891  		})
   892  	}
   893  }