From 00e83fed3f9dfa06953d25ae1f0766095242ecd1 Mon Sep 17 00:00:00 2001 From: aries Date: Sat, 7 Oct 2023 20:49:21 -0500 Subject: [PATCH] add function `Partition` for Model of package gdb (#2989) --- contrib/drivers/mysql/mysql__test.go | 75 ++++++++++++++++++++++++++-- database/gdb/gdb_model.go | 10 ++++ 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/contrib/drivers/mysql/mysql__test.go b/contrib/drivers/mysql/mysql__test.go index 97f428c4d..fabafd8d8 100644 --- a/contrib/drivers/mysql/mysql__test.go +++ b/contrib/drivers/mysql/mysql__test.go @@ -9,6 +9,7 @@ package mysql_test import ( "context" "fmt" + "testing" "github.com/gogf/gf/v2/container/garray" "github.com/gogf/gf/v2/database/gdb" @@ -22,6 +23,7 @@ const ( TableName = "user" TestSchema1 = "test1" TestSchema2 = "test2" + TestPartitionDB = "test3" TableNamePrefix1 = "gf_" TestDbUser = "root" TestDbPass = "12345678" @@ -31,6 +33,7 @@ const ( var ( db gdb.DB db2 gdb.DB + db3 gdb.DB dbPrefix gdb.DB dbInvalid gdb.DB ctx = context.TODO() @@ -38,21 +41,25 @@ var ( func init() { nodeDefault := gdb.ConfigNode{ - Link: "mysql:root:12345678@tcp(127.0.0.1:3306)/?loc=Local&parseTime=true", + Link: fmt.Sprintf("mysql:root:%s@tcp(127.0.0.1:3306)/?loc=Local&parseTime=true", TestDbPass), + } + partitionDefault := gdb.ConfigNode{ + Link: fmt.Sprintf("mysql:root:%s@tcp(127.0.0.1:3307)/?loc=Local&parseTime=true", TestDbPass), + Debug: true, } - nodePrefix := gdb.ConfigNode{ - Link: "mysql:root:12345678@tcp(127.0.0.1:3306)/?loc=Local&parseTime=true", + Link: fmt.Sprintf("mysql:root:%s@tcp(127.0.0.1:3306)/?loc=Local&parseTime=true", TestDbPass), } nodePrefix.Prefix = TableNamePrefix1 nodeInvalid := gdb.ConfigNode{ - Link: "mysql:root:12345678@tcp(127.0.0.1:3307)/?loc=Local&parseTime=true", + Link: fmt.Sprintf("mysql:root:%s@tcp(127.0.0.1:3307)/?loc=Local&parseTime=true", TestDbPass), } gdb.AddConfigNode("test", nodeDefault) gdb.AddConfigNode("prefix", nodePrefix) gdb.AddConfigNode("nodeinvalid", nodeInvalid) + gdb.AddConfigNode("partition", partitionDefault) gdb.AddConfigNode(gdb.DefaultGroupName, nodeDefault) // Default db. @@ -68,9 +75,12 @@ func init() { if _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, TestSchema2)); err != nil { gtest.Error(err) } + if _, err := db.Exec(ctx, fmt.Sprintf(schemaTemplate, TestPartitionDB)); err != nil { + gtest.Error(err) + } db = db.Schema(TestSchema1) db2 = db.Schema(TestSchema2) - + db3 = db.Schema(TestPartitionDB) // Prefix db. if r, err := gdb.NewByGroup("prefix"); err != nil { gtest.Error(err) @@ -156,3 +166,58 @@ func dropTableWithDb(db gdb.DB, table string) { gtest.Error(err) } } + +func Test_PartitionTable(t *testing.T) { + dropShopDBTable() + createShopDBTable() + insertShopDBData() + + //defer dropShopDBTable() + gtest.C(t, func(t *gtest.T) { + data, err := db3.Ctx(ctx).Model("dbx_order").Partition("p3", "p4").All() + t.AssertNil(err) + dataLen := len(data) + t.Assert(dataLen, 5) + data, err = db3.Ctx(ctx).Model("dbx_order").Partition("p3").All() + t.AssertNil(err) + dataLen = len(data) + t.Assert(dataLen, 5) + }) +} +func createShopDBTable() { + sql := `CREATE TABLE dbx_order ( + id int(11) NOT NULL, + sales_date date DEFAULT NULL, + amount decimal(10,2) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 +PARTITION BY RANGE (YEAR(sales_date)) +(PARTITION p1 VALUES LESS THAN (2020) ENGINE = InnoDB, + PARTITION p2 VALUES LESS THAN (2021) ENGINE = InnoDB, + PARTITION p3 VALUES LESS THAN (2022) ENGINE = InnoDB, + PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = InnoDB);` + _, err := db3.Exec(ctx, sql) + if err != nil { + gtest.Fatal(err.Error()) + } +} +func insertShopDBData() { + data := g.Slice{} + year := 2020 + for i := 1; i <= 5; i++ { + year++ + data = append(data, g.Map{ + "id": i, + "sales_date": fmt.Sprintf("%d-09-21", year), + "amount": fmt.Sprintf("1%d.21", i), + }) + } + _, err := db3.Model("dbx_order").Ctx(ctx).Data(data).Insert() + if err != nil { + gtest.Error(err) + } +} +func dropShopDBTable() { + if _, err := db3.Exec(ctx, "DROP TABLE IF EXISTS `dbx_order`"); err != nil { + gtest.Error(err) + } +} diff --git a/database/gdb/gdb_model.go b/database/gdb/gdb_model.go index a4a629049..5e70154b9 100644 --- a/database/gdb/gdb_model.go +++ b/database/gdb/gdb_model.go @@ -37,6 +37,7 @@ type Model struct { limit int // Used for "select ... start, limit ..." statement. option int // Option for extra operation features. offset int // Offset statement for some databases grammar. + partition string // Partition table partition name. data interface{} // Data for operation, which can be type of map/[]map/struct/*struct/string, etc. batch int // Batch number for batch Insert/Replace/Save operations. filter bool // Filter data and where key-value pairs according to the fields of the table. @@ -174,6 +175,15 @@ func (c *Core) With(objects ...interface{}) *Model { return c.db.Model().With(objects...) } +// Partition sets Partition name. +// Example: +// dao.User.Ctx(ctx).Partition("p1","p2","p3").All() +func (m *Model) Partition(partitions ...string) *Model { + model := m.getModel() + model.partition = gstr.Join(partitions, ",") + return model +} + // Model acts like Core.Model except it operates on transaction. // See Core.Model. func (tx *TXCore) Model(tableNameQueryOrStruct ...interface{}) *Model {