github.com/wfusion/gofusion@v1.1.14/test/db/cases/table_sharding_test.go (about)

     1  package cases
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/suite"
     9  
    10  	"github.com/wfusion/gofusion/common/utils"
    11  	"github.com/wfusion/gofusion/db"
    12  	"github.com/wfusion/gofusion/log"
    13  
    14  	testDB "github.com/wfusion/gofusion/test/db"
    15  )
    16  
    17  func TestTableSharding(t *testing.T) {
    18  	testingSuite := &TableSharding{Test: new(testDB.Test)}
    19  	testingSuite.Init(testingSuite)
    20  	suite.Run(t, testingSuite)
    21  }
    22  
    23  type TableSharding struct {
    24  	*testDB.Test
    25  }
    26  
    27  func (t *TableSharding) BeforeTest(suiteName, testName string) {
    28  	t.Catch(func() {
    29  		log.Info(context.Background(), "right before %s %s", suiteName, testName)
    30  	})
    31  }
    32  
    33  func (t *TableSharding) AfterTest(suiteName, testName string) {
    34  	t.Catch(func() {
    35  		log.Info(context.Background(), "right after %s %s", suiteName, testName)
    36  	})
    37  }
    38  
    39  func (t *TableSharding) TestMysql() {
    40  	t.testDefault(nameMysqlRead, nameMysqlWrite)
    41  }
    42  
    43  func (t *TableSharding) TestPostgres() {
    44  	t.testDefault(namePostgres, namePostgres)
    45  }
    46  
    47  func (t *TableSharding) TestOpengauss() {
    48  	t.testDefault(nameOpenGauss, nameOpenGauss)
    49  }
    50  
    51  func (t *TableSharding) TestSqlserver() {
    52  	t.testDefault(nameSqlserver, nameSqlserver)
    53  }
    54  
    55  func (t *TableSharding) testDefault(read, write string) {
    56  	t.Run("Migrate", func() { t.testMigrate(read, write) })
    57  	t.Run("Insert", func() { t.testInsert(read, write) })
    58  	t.Run("InsertNested", func() { t.testInsertNested(read, write) })
    59  	t.Run("BatchInsert", func() { t.testBatchInsert(read, write) })
    60  	t.Run("BatchInInsert", func() { t.testBatchInInsert(read, write) })
    61  	t.Run("Query", func() { t.testQuery(read, write) })
    62  	t.Run("QueryNested", func() { t.testQueryNested(read, write) })
    63  	t.Run("Delete", func() { t.testDelete(read, write) })
    64  	t.Run("DAL", func() { t.testDAL(read, write) })
    65  	t.Run("DALQueryWithDeletedAt", func() { t.testDALQueryWithDeletedAt(read, write) })
    66  	t.Run("Joins", func() { t.testJoins(read, write) })
    67  	t.Run("DALFindAndCount", func() { t.testDALFindAndCount(read, write) })
    68  	t.Run("ShardingKeyByRawValue", func() { t.testShardingKeyByRawValue(read, write) })
    69  }
    70  
    71  func (t *TableSharding) testMigrate(read, write string) {
    72  	t.Catch(func() {
    73  		ctx := context.Background()
    74  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
    75  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
    76  		t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
    77  
    78  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingPtr)))
    79  		t.NoError(orm.Migrator().DropTable(new(modelWithShardingPtr)))
    80  
    81  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingByRawValue)))
    82  		t.NoError(orm.Migrator().DropTable(new(modelWithShardingByRawValue)))
    83  	})
    84  }
    85  
    86  func (t *TableSharding) testInsert(read, write string) {
    87  	t.Catch(func() {
    88  		ctx := context.Background()
    89  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
    90  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
    91  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingEmbed)))
    92  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingPtr)))
    93  		defer func() {
    94  			t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
    95  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingEmbed)))
    96  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingPtr)))
    97  		}()
    98  
    99  		m1 := &modelWithSharding{
   100  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   101  			Name:   "sharding1",
   102  		}
   103  		t.NoError(orm.Create(m1).Error)
   104  		t.NoError(orm.Delete(m1).Error)
   105  
   106  		m2 := &modelWithShardingPtr{
   107  			Name: "sharding_ptr1",
   108  			Age:  18,
   109  		}
   110  		t.NoError(orm.Create(m2).Error)
   111  		t.NoError(orm.Delete(m2).Error)
   112  	})
   113  }
   114  
   115  func (t *TableSharding) testInsertNested(read, write string) {
   116  	t.Catch(func() {
   117  		ctx := context.Background()
   118  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
   119  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
   120  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   121  		defer func() {
   122  			t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
   123  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingEmbed)))
   124  		}()
   125  
   126  		mws := &modelWithSharding{
   127  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   128  			Name:   "sharding1",
   129  			EmbedList: []*modelWithShardingEmbed{
   130  				{
   131  					AZBase:    AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   132  					OtherName: "other1",
   133  				},
   134  				{
   135  					AZBase:    AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   136  					OtherName: "other2",
   137  				},
   138  				{
   139  					AZBase:    AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   140  					OtherName: "other3",
   141  				},
   142  			},
   143  		}
   144  
   145  		t.NoError(orm.Create(mws).Error)
   146  		t.NoError(orm.Delete(mws).Error)
   147  		if read == nameOpenGauss {
   148  			t.NoError(orm.Where("az_name = ? AND model_id = ?", mws.AZName, mws.ID).Find(&mws.EmbedList).Error)
   149  		}
   150  
   151  		t.NoError(orm.Delete(mws.EmbedList).Error)
   152  	})
   153  }
   154  
   155  func (t *TableSharding) testBatchInsert(read, write string) {
   156  	t.Catch(func() {
   157  		ctx := context.Background()
   158  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
   159  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
   160  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   161  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingPtr)))
   162  		defer func() {
   163  			t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
   164  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingEmbed)))
   165  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingPtr)))
   166  		}()
   167  		mList1 := []*modelWithSharding{
   168  			{
   169  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   170  				Name:   "sharding1",
   171  			},
   172  			{
   173  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   174  				Name:   "sharding2",
   175  			},
   176  			{
   177  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   178  				Name:   "sharding3",
   179  			},
   180  		}
   181  		t.NoError(orm.Create(mList1).Error)
   182  		t.NoError(orm.Unscoped().Delete(mList1).Error)
   183  
   184  		mList2 := []*modelWithShardingPtr{
   185  			{
   186  				Business: db.Business{Data: db.Data{ID: 0x110}},
   187  				Name:     "sharding_ptr2",
   188  				Age:      18,
   189  			},
   190  			{
   191  				Business: db.Business{Data: db.Data{ID: 0x210}},
   192  				Name:     "sharding_ptr3",
   193  				Age:      18,
   194  			},
   195  			{
   196  				Business: db.Business{Data: db.Data{ID: 0x310}},
   197  				Name:     "sharding_ptr4",
   198  				Age:      18,
   199  			},
   200  		}
   201  		t.NoError(orm.Create(mList2).Error)
   202  		t.NoError(orm.Unscoped().Delete(mList2).Error)
   203  	})
   204  }
   205  
   206  func (t *TableSharding) testBatchInInsert(read, write string) {
   207  	t.Catch(func() {
   208  		ctx := context.Background()
   209  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
   210  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
   211  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   212  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingPtr)))
   213  		defer func() {
   214  			t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
   215  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingEmbed)))
   216  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingPtr)))
   217  		}()
   218  		mList1 := []*modelWithSharding{
   219  			{
   220  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   221  				Name:   "sharding1",
   222  			},
   223  			{
   224  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   225  				Name:   "sharding2",
   226  			},
   227  			{
   228  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   229  				Name:   "sharding3",
   230  			},
   231  		}
   232  		t.NoError(orm.CreateInBatches(mList1, 2).Error)
   233  		t.NoError(orm.Unscoped().Delete(mList1).Error)
   234  
   235  		mList2 := []*modelWithShardingPtr{
   236  			{
   237  				Business: db.Business{Data: db.Data{ID: 0x110}},
   238  				Name:     "sharding_ptr2",
   239  				Age:      18,
   240  			},
   241  			{
   242  				Business: db.Business{Data: db.Data{ID: 0x210}},
   243  				Name:     "sharding_ptr3",
   244  				Age:      18,
   245  			},
   246  			{
   247  				Business: db.Business{Data: db.Data{ID: 0x310}},
   248  				Name:     "sharding_ptr4",
   249  				Age:      18,
   250  			},
   251  		}
   252  		t.NoError(orm.CreateInBatches(mList2, 2).Error)
   253  		t.NoError(orm.Unscoped().Delete(mList2).Error)
   254  	})
   255  }
   256  
   257  // TestQuery may not pass if run all test cases cause table plugin only create table once while inserting
   258  func (t *TableSharding) testQuery(read, write string) {
   259  	t.Catch(func() {
   260  		ctx := context.Background()
   261  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
   262  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
   263  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   264  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingPtr)))
   265  		defer func() {
   266  			t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
   267  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingEmbed)))
   268  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingPtr)))
   269  		}()
   270  		mList1 := []*modelWithSharding{
   271  			{
   272  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   273  				Name:   "sharding1",
   274  			},
   275  			{
   276  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   277  				Name:   "sharding2",
   278  			},
   279  			{
   280  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   281  				Name:   "sharding3",
   282  			},
   283  		}
   284  		t.NoError(orm.Create(mList1).Error)
   285  		var mList1Dup []*modelWithSharding
   286  		t.NoError(orm.Where("az_name = 'az1'").Find(&mList1Dup).Error)
   287  		t.EqualValues(mList1, mList1Dup)
   288  		t.NoError(orm.Unscoped().Delete(mList1).Error)
   289  
   290  		mList2 := []*modelWithShardingPtr{
   291  			{
   292  				Business: db.Business{Data: db.Data{ID: 0x110}},
   293  				Name:     "sharding_ptr2",
   294  				Age:      18,
   295  			},
   296  			{
   297  				Business: db.Business{Data: db.Data{ID: 0x210}},
   298  				Name:     "sharding_ptr3",
   299  				Age:      18,
   300  			},
   301  			{
   302  				Business: db.Business{Data: db.Data{ID: 0x310}},
   303  				Name:     "sharding_ptr4",
   304  				Age:      18,
   305  			},
   306  		}
   307  		t.NoError(orm.Create(mList2).Error)
   308  		var m2Dup *modelWithShardingPtr
   309  		m2 := mList2[0]
   310  		t.NoError(orm.Where("name = ? AND id = ? AND age = ?", m2.Name, m2.ID, m2.Age).First(&m2Dup).Error)
   311  		t.EqualValues(m2, m2Dup)
   312  		t.NoError(orm.Unscoped().Delete(mList2).Error)
   313  	})
   314  }
   315  
   316  // TestQueryNested may not pass if run all test cases cause plugin only create table once while inserting
   317  func (t *TableSharding) testQueryNested(read, write string) {
   318  	t.Catch(func() {
   319  		ctx := context.Background()
   320  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
   321  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
   322  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   323  		defer func() {
   324  			t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
   325  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingEmbed)))
   326  		}()
   327  		mws := &modelWithSharding{
   328  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   329  			Name:   "sharding1",
   330  			EmbedList: []*modelWithShardingEmbed{
   331  				{
   332  					AZBase:    AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   333  					OtherName: "other1",
   334  				},
   335  				{
   336  					AZBase:    AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   337  					OtherName: "other2",
   338  				},
   339  				{
   340  					AZBase:    AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   341  					OtherName: "other3",
   342  				},
   343  			},
   344  		}
   345  
   346  		t.NoError(orm.Create(mws).Error)
   347  
   348  		var mwsList []*modelWithSharding
   349  		t.NoError(orm.
   350  			Preload("EmbedList", "az_name = ?", "az1").
   351  			Where("az_name = ?", "az1").
   352  			Find(&mwsList).Error,
   353  		)
   354  		t.NotEmpty(mwsList)
   355  
   356  		t.NoError(orm.Unscoped().Delete(mws).Error)
   357  		if read == nameOpenGauss {
   358  			t.NoError(orm.Where("az_name = ? AND model_id = ?", mws.AZName, mws.ID).Find(&mws.EmbedList).Error)
   359  		}
   360  
   361  		t.NoError(orm.Unscoped().Delete(mws.EmbedList).Error)
   362  	})
   363  }
   364  
   365  func (t *TableSharding) testDelete(read, write string) {
   366  	t.Catch(func() {
   367  		ctx := context.Background()
   368  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
   369  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithSharding)))
   370  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   371  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingPtr)))
   372  		defer func() {
   373  			t.NoError(orm.Migrator().DropTable(new(modelWithSharding)))
   374  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingEmbed)))
   375  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingPtr)))
   376  		}()
   377  		m1 := &modelWithSharding{
   378  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   379  			Name:   "sharding1",
   380  		}
   381  		t.NoError(orm.Create(m1).Error)
   382  		t.NoError(orm.Unscoped().
   383  			Where("az_name = ? AND name = ?", m1.AZName, m1.Name).
   384  			Delete(new(modelWithSharding)).Error)
   385  
   386  		m2 := &modelWithShardingPtr{
   387  			Name: "sharding_ptr1",
   388  			Age:  18,
   389  		}
   390  		t.NoError(orm.Create(m2).Error)
   391  		t.NoError(orm.Unscoped().
   392  			Where("name = ? AND id = ? AND age = ?", m2.Name, m2.ID, m2.Age).
   393  			Delete(new(modelWithShardingPtr)).Error)
   394  	})
   395  }
   396  
   397  func (t *TableSharding) testDAL(read, write string) {
   398  	t.Catch(func() {
   399  		ctx := context.Background()
   400  		dal1 := db.NewDAL[modelWithSharding, []*modelWithSharding](read, write, db.AppName(t.AppName()))
   401  		t.NoError(dal1.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithSharding)))
   402  		t.NoError(dal1.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   403  		defer func() {
   404  			t.NoError(dal1.WriteDB(ctx).Migrator().DropTable(new(modelWithSharding)))
   405  			t.NoError(dal1.WriteDB(ctx).Migrator().DropTable(new(modelWithShardingEmbed)))
   406  		}()
   407  
   408  		mList1 := []*modelWithSharding{
   409  			{
   410  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   411  				Name:   "sharding1",
   412  			},
   413  			{
   414  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   415  				Name:   "sharding2",
   416  			},
   417  			{
   418  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az2"},
   419  				Name:   "sharding3",
   420  			},
   421  		}
   422  		t.NoError(dal1.InsertInBatches(ctx, mList1, 1))
   423  		if read != nameOpenGauss {
   424  			t.NoError(dal1.Save(ctx, mList1))
   425  		}
   426  		_, err := dal1.Delete(ctx, mList1, db.Unscoped())
   427  		t.NoError(err)
   428  
   429  		dal2 := db.NewDAL[modelWithShardingPtr, []*modelWithShardingPtr](read, write, db.AppName(t.AppName()))
   430  		t.NoError(dal2.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithShardingPtr)))
   431  		defer func() {
   432  			t.NoError(dal2.WriteDB(ctx).Migrator().DropTable(new(modelWithShardingPtr)))
   433  		}()
   434  
   435  		mList2 := []*modelWithShardingPtr{
   436  			{
   437  				Business: db.Business{Data: db.Data{ID: utils.Must(dal2.ShardingIDGen(ctx))}},
   438  				Name:     "sharding_ptr2",
   439  				Age:      18,
   440  			},
   441  			{
   442  				Business: db.Business{Data: db.Data{ID: 299}},
   443  				Name:     "sharding_ptr3",
   444  				Age:      19,
   445  			},
   446  			{
   447  				Business: db.Business{Data: db.Data{ID: 399}},
   448  				Name:     "sharding_ptr4",
   449  				Age:      20,
   450  			},
   451  		}
   452  		t.NoError(dal2.InsertInBatches(ctx, mList2, 1))
   453  		if read != nameOpenGauss {
   454  			t.NoError(dal2.Save(ctx, mList2))
   455  		}
   456  		_, err = dal2.Delete(ctx, mList2, db.Unscoped())
   457  		t.NoError(err)
   458  	})
   459  }
   460  
   461  func (t *TableSharding) testDALQueryWithDeletedAt(read, write string) {
   462  	t.Catch(func() {
   463  		ctx := context.Background()
   464  
   465  		dal := db.NewDAL[modelWithSharding, []*modelWithSharding](read, write, db.AppName(t.AppName()))
   466  		t.NoError(dal.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithSharding)))
   467  		t.NoError(dal.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   468  		defer func() {
   469  			t.NoError(dal.WriteDB(ctx).Migrator().DropTable(new(modelWithSharding)))
   470  			t.NoError(dal.WriteDB(ctx).Migrator().DropTable(new(modelWithShardingEmbed)))
   471  		}()
   472  
   473  		expected := []*modelWithSharding{
   474  			{
   475  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   476  				Name:   "sharding1",
   477  			},
   478  			{
   479  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   480  				Name:   "sharding2",
   481  			},
   482  			{
   483  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az2"},
   484  				Name:   "sharding3",
   485  			},
   486  		}
   487  		t.NoError(dal.InsertInBatches(ctx, expected, 1))
   488  
   489  		tx := dal.ReadDB(ctx)
   490  		tx = tx.Where("az_name = ?", "az1")
   491  		tx = tx.Where("name like ?", "%sharding%")
   492  
   493  		var actual []*modelWithSharding
   494  		t.NoError(tx.Find(&actual).Error)
   495  		t.NotEmpty(actual)
   496  
   497  		_, err := dal.Delete(ctx, expected)
   498  		t.NoError(err)
   499  	})
   500  }
   501  
   502  func (t *TableSharding) testJoins(read, write string) {
   503  	t.Catch(func() {
   504  		ctx := context.Background()
   505  		mwsDAL := db.NewDAL[modelWithSharding, []*modelWithSharding](read, write, db.AppName(t.AppName()))
   506  		mwseDAL := db.NewDAL[modelWithShardingExtend, []*modelWithShardingExtend](
   507  			read, write, db.AppName(t.AppName()))
   508  		t.NoError(mwsDAL.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithSharding)))
   509  		t.NoError(mwsDAL.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithShardingEmbed)))
   510  		t.NoError(mwseDAL.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithShardingExtend)))
   511  		defer func() {
   512  			t.NoError(mwsDAL.WriteDB(ctx).Migrator().DropTable(new(modelWithSharding)))
   513  			t.NoError(mwsDAL.WriteDB(ctx).Migrator().DropTable(new(modelWithShardingEmbed)))
   514  			t.NoError(mwseDAL.WriteDB(ctx).Migrator().DropTable(new(modelWithShardingExtend)))
   515  		}()
   516  
   517  		mws := &modelWithSharding{
   518  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   519  			Name:   "sharding1",
   520  		}
   521  		t.NoError(mwsDAL.InsertOne(ctx, mws))
   522  		defer func() { _, _ = mwsDAL.Delete(ctx, mws) }()
   523  		mwsTblName := mws.TableName()
   524  
   525  		mwse := &modelWithShardingExtend{
   526  			AZBase:    AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   527  			OtherName: "sharding1",
   528  			ModelID:   mws.ID,
   529  		}
   530  		t.NoError(mwseDAL.InsertOne(ctx, mwse))
   531  		defer func() { _, _ = mwseDAL.Delete(ctx, mwse) }()
   532  		mwseTblName := mwse.TableName()
   533  
   534  		var mwsList []*modelWithSharding
   535  		joins := mwsDAL.ReadDB(ctx).
   536  			Joins(fmt.Sprintf("left join %s on %s.model_id = %s.id", mwseTblName, mwseTblName, mwsTblName)).
   537  			Where(fmt.Sprintf("%s.id = ?", mwsTblName), mws.ID).
   538  			Where(fmt.Sprintf("%s.az_name = ?", mwsTblName), "az1").
   539  			Where(fmt.Sprintf("%s.az_name = ?", mwseTblName), "az1")
   540  		t.NoError(joins.Find(&mwsList).Error)
   541  		t.NotEmpty(mwsList)
   542  	})
   543  }
   544  
   545  func (t *TableSharding) testDALFindAndCount(read, write string) {
   546  	t.Catch(func() {
   547  		ctx := context.Background()
   548  
   549  		dal := db.NewDAL[modelWithSharding, []*modelWithSharding](read, write, db.AppName(t.AppName()))
   550  		t.NoError(dal.WriteDB(ctx).Migrator().AutoMigrate(new(modelWithSharding)))
   551  		defer func() {
   552  			t.NoError(dal.WriteDB(ctx).Migrator().DropTable(new(modelWithSharding)))
   553  		}()
   554  		mList := []*modelWithSharding{
   555  			{
   556  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   557  				Name:   "sharding1",
   558  			},
   559  			{
   560  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az2"},
   561  				Name:   "sharding2",
   562  			},
   563  			{
   564  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az3"},
   565  				Name:   "sharding3",
   566  			},
   567  			{
   568  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   569  				Name:   "sharding4",
   570  			},
   571  			{
   572  				AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az2"},
   573  				Name:   "sharding5",
   574  			},
   575  		}
   576  		t.NoError(dal.InsertInBatches(ctx, mList, 100))
   577  		defer dal.WriteDB(ctx).Unscoped().Delete(mList)
   578  
   579  		var (
   580  			count  int64
   581  			result []*modelWithSharding
   582  		)
   583  		for _, azName := range []string{"az1", "az2", "az3"} {
   584  			count = 0
   585  			result = nil
   586  
   587  			t.NoError(dal.ReadDB(ctx).Where("az_name = ?", azName).Find(&result).Error)
   588  			t.NoError(dal.ReadDB(ctx).Where("az_name = ?", azName).Count(&count).Error)
   589  			t.EqualValues(count, len(result))
   590  		}
   591  	})
   592  }
   593  
   594  func (t *TableSharding) testShardingKeyByRawValue(read, write string) {
   595  	t.Catch(func() {
   596  		ctx := context.Background()
   597  		orm := db.Use(ctx, write, db.AppName(t.AppName()))
   598  		t.NoError(orm.Migrator().AutoMigrate(new(modelWithShardingByRawValue)))
   599  		defer func() {
   600  			t.NoError(orm.Migrator().DropTable(new(modelWithShardingByRawValue)))
   601  		}()
   602  
   603  		m1 := &modelWithShardingByRawValue{
   604  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az1"},
   605  			Name:   "sharding_ptr1",
   606  			Age:    18,
   607  		}
   608  		t.NoError(orm.Create(m1).Error)
   609  		defer func() {
   610  			t.NoError(orm.Unscoped().Delete(m1).Error)
   611  		}()
   612  
   613  		m2 := &modelWithShardingByRawValue{
   614  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az2"},
   615  			Name:   "sharding_ptr1",
   616  			Age:    18,
   617  		}
   618  		t.NoError(orm.Create(m2).Error)
   619  		defer func() {
   620  			t.NoError(orm.Unscoped().Delete(m2).Error)
   621  		}()
   622  
   623  		m3 := &modelWithShardingByRawValue{
   624  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az3"},
   625  			Name:   "sharding_ptr1",
   626  			Age:    18,
   627  		}
   628  		t.NoError(orm.Create(m3).Error)
   629  		defer func() {
   630  			t.NoError(orm.Unscoped().Delete(m3).Error)
   631  		}()
   632  
   633  		m4 := &modelWithShardingByRawValue{
   634  			AZBase: AZBase{RegionBase: RegionBase{RegionID: "12345"}, AZName: "az4"},
   635  			Name:   "sharding_ptr1",
   636  			Age:    18,
   637  		}
   638  		t.NoError(orm.Create(m4).Error)
   639  		defer func() {
   640  			t.NoError(orm.Unscoped().Delete(m4).Error)
   641  		}()
   642  	})
   643  }