diff --git a/tests/gaussdb_test.go b/tests/gaussdb_test.go new file mode 100644 index 00000000..1aca302f --- /dev/null +++ b/tests/gaussdb_test.go @@ -0,0 +1,248 @@ +package tests_test + +import ( + "testing" + "time" + + "github.com/google/uuid" + "github.com/lib/pq" + "gorm.io/gorm" + "gorm.io/gorm/clause" + . "gorm.io/gorm/utils/tests" +) + +func TestGaussDBReturningIDWhichHasStringType(t *testing.T) { + t.Skipf("This test case skipped, because of gaussdb not support pgcrypto extension and gen_random_uuid() function") + if DB.Dialector.Name() != "gaussdb" { + t.Skip() + } + + type Yasuo struct { + // TODO: function gen_random_uuid() does not exist + ID string `gorm:"default:gen_random_uuid()"` + Name string + CreatedAt time.Time `gorm:"type:TIMESTAMP WITHOUT TIME ZONE"` + UpdatedAt time.Time `gorm:"type:TIMESTAMP WITHOUT TIME ZONE;default:current_timestamp"` + } + + if err := DB.Exec("CREATE EXTENSION IF NOT EXISTS pgcrypto;").Error; err != nil { + t.Errorf("Failed to create extension pgcrypto, got error %v", err) + } + + DB.Migrator().DropTable(&Yasuo{}) + + if err := DB.AutoMigrate(&Yasuo{}); err != nil { + t.Fatalf("Failed to migrate for uuid default value, got error: %v", err) + } + + yasuo := Yasuo{Name: "jinzhu"} + if err := DB.Create(&yasuo).Error; err != nil { + t.Fatalf("should be able to create data, but got %v", err) + } + + if yasuo.ID == "" { + t.Fatal("should be able to has ID, but got zero value") + } + + var result Yasuo + if err := DB.First(&result, "id = ?", yasuo.ID).Error; err != nil || yasuo.Name != "jinzhu" { + t.Errorf("No error should happen, but got %v", err) + } + + if err := DB.Where("id = $1", yasuo.ID).First(&Yasuo{}).Error; err != nil || yasuo.Name != "jinzhu" { + t.Errorf("No error should happen, but got %v", err) + } + + yasuo.Name = "jinzhu1" + if err := DB.Save(&yasuo).Error; err != nil { + t.Errorf("Failed to update date, got error %v", err) + } + + if err := DB.First(&result, "id = ?", yasuo.ID).Error; err != nil || yasuo.Name != "jinzhu1" { + t.Errorf("No error should happen, but got %v", err) + } +} + +func TestGaussDB(t *testing.T) { + t.Skipf("This test case skipped, because of gaussdb not support pgcrypto extension and gen_random_uuid() function") + if DB.Dialector.Name() != "gaussdb" { + t.Skip() + } + + type Harumph struct { + gorm.Model + Name string `gorm:"check:name_checker,name <> ''"` + // TODO: function gen_random_uuid() does not exist + Test uuid.UUID `gorm:"type:uuid;not null;default:gen_random_uuid()"` + CreatedAt time.Time `gorm:"type:TIMESTAMP WITHOUT TIME ZONE"` + UpdatedAt time.Time `gorm:"type:TIMESTAMP WITHOUT TIME ZONE;default:current_timestamp"` + Things pq.StringArray `gorm:"type:text[]"` + } + + if err := DB.Exec("CREATE EXTENSION IF NOT EXISTS pgcrypto;").Error; err != nil { + t.Errorf("Failed to create extension pgcrypto, got error %v", err) + } + + DB.Migrator().DropTable(&Harumph{}) + + if err := DB.AutoMigrate(&Harumph{}); err != nil { + t.Fatalf("Failed to migrate for uuid default value, got error: %v", err) + } + + harumph := Harumph{} + if err := DB.Create(&harumph).Error; err == nil { + t.Fatalf("should failed to create data, name can't be blank") + } + + harumph = Harumph{Name: "jinzhu"} + if err := DB.Create(&harumph).Error; err != nil { + t.Fatalf("should be able to create data, but got %v", err) + } + + var result Harumph + if err := DB.First(&result, "id = ?", harumph.ID).Error; err != nil || harumph.Name != "jinzhu" { + t.Errorf("No error should happen, but got %v", err) + } + + if err := DB.Where("id = $1", harumph.ID).First(&Harumph{}).Error; err != nil || harumph.Name != "jinzhu" { + t.Errorf("No error should happen, but got %v", err) + } + + harumph.Name = "jinzhu1" + if err := DB.Save(&harumph).Error; err != nil { + t.Errorf("Failed to update date, got error %v", err) + } + + if err := DB.First(&result, "id = ?", harumph.ID).Error; err != nil || harumph.Name != "jinzhu1" { + t.Errorf("No error should happen, but got %v", err) + } + + DB.Migrator().DropTable("log_usage") + + if err := DB.Exec(` +CREATE TABLE public.log_usage ( + log_id bigint NOT NULL +); + +ALTER TABLE public.log_usage ALTER COLUMN log_id ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME public.log_usage_log_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + `).Error; err != nil { + t.Fatalf("failed to create table, got error %v", err) + } + + columns, err := DB.Migrator().ColumnTypes("log_usage") + if err != nil { + t.Fatalf("failed to get columns, got error %v", err) + } + + hasLogID := false + for _, column := range columns { + if column.Name() == "log_id" { + hasLogID = true + autoIncrement, ok := column.AutoIncrement() + if !ok || !autoIncrement { + t.Fatalf("column log_id should be auto incrementment") + } + } + } + + if !hasLogID { + t.Fatalf("failed to found column log_id") + } +} + +func TestGaussDBMany2ManyWithDefaultValueUUID(t *testing.T) { + t.Skipf("This test case skipped, because of gaussdb does not have 'uuid-ossp' extension") + if DB.Dialector.Name() != "gaussdb" { + t.Skip() + } + + if err := DB.Exec(`create extension if not exists "uuid-ossp"`).Error; err != nil { + t.Fatalf("Failed to create 'uuid-ossp' extension, but got error %v", err) + } + + DB.Migrator().DropTable(&Post{}, &Category{}, "post_categories") + DB.AutoMigrate(&Post{}, &Category{}) + + post := Post{ + Title: "Hello World", + Categories: []*Category{ + {Title: "Coding"}, + {Title: "Golang"}, + }, + } + + if err := DB.Create(&post).Error; err != nil { + t.Errorf("Failed, got error: %v", err) + } +} + +func TestGaussDBOnConstraint(t *testing.T) { + t.Skipf("This test case skipped, because of gaussdb not support 'ON CONSTRAINT' statement") + if DB.Dialector.Name() != "gaussdb" { + t.Skip() + } + + type Thing struct { + gorm.Model + SomeID string + OtherID string + Data string + } + + DB.Migrator().DropTable(&Thing{}) + DB.Migrator().CreateTable(&Thing{}) + if err := DB.Exec("ALTER TABLE things ADD CONSTRAINT some_id_other_id_unique UNIQUE (some_id, other_id)").Error; err != nil { + t.Error(err) + } + + thing := Thing{ + SomeID: "1234", + OtherID: "1234", + Data: "something", + } + + DB.Create(&thing) + + thing2 := Thing{ + SomeID: "1234", + OtherID: "1234", + Data: "something else", + } + + result := DB.Clauses(clause.OnConflict{ + OnConstraint: "some_id_other_id_unique", + UpdateAll: true, + }).Create(&thing2) + if result.Error != nil { + t.Errorf("creating second thing: %v", result.Error) + } + + var things []Thing + if err := DB.Find(&things).Error; err != nil { + t.Errorf("Failed, got error: %v", err) + } + + if len(things) > 1 { + t.Errorf("expected 1 thing got more") + } +} + +func TestGaussDBAlterColumnDataType(t *testing.T) { + if DB.Dialector.Name() != "gaussdb" { + t.Skip() + } + DB.Migrator().DropTable(&Company{}) + DB.AutoMigrate(Company{}) + if err := DB.Table("companies").Migrator().AlterColumn(CompanyNew{}, "name"); err != nil { + t.Fatalf("failed to alter column from string to int, got error %v", err) + } + + DB.AutoMigrate(Company{}) +} diff --git a/tests/go.mod b/tests/go.mod index 1074f2b9..aa8b8e53 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -7,6 +7,7 @@ require ( github.com/jinzhu/now v1.1.5 github.com/lib/pq v1.10.9 github.com/stretchr/testify v1.10.0 + gorm.io/driver/gaussdb v0.1.0 gorm.io/driver/mysql v1.6.0 gorm.io/driver/postgres v1.6.0 gorm.io/driver/sqlite v1.6.0 @@ -16,6 +17,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect + github.com/HuaweiCloudDeveloper/gaussdb-go v1.0.0-rc1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-sql-driver/mysql v1.9.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect @@ -30,10 +32,11 @@ require ( github.com/microsoft/go-mssqldb v1.8.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/tjfoc/gmsm v1.4.1 // indirect golang.org/x/crypto v0.38.0 // indirect golang.org/x/sync v0.14.0 // indirect golang.org/x/text v0.25.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace gorm.io/gorm => ../ +replace gorm.io/gorm => ../ \ No newline at end of file diff --git a/tests/migrate_test.go b/tests/migrate_test.go index 70aa654e..e04a42fb 100644 --- a/tests/migrate_test.go +++ b/tests/migrate_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/moseszane168/gaussdb" "github.com/stretchr/testify/assert" + "gorm.io/driver/gaussdb" "gorm.io/driver/postgres" "gorm.io/gorm" @@ -83,46 +83,8 @@ func TestMigrate(t *testing.T) { } } -func TestAutoMigrateInt8PG(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { - return - } - - type Smallint int8 - - type MigrateInt struct { - Int8 Smallint - } - - tracer := Tracer{ - Logger: DB.Config.Logger, - Test: func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) { - sql, _ := fc() - if strings.HasPrefix(sql, "ALTER TABLE \"migrate_ints\" ALTER COLUMN \"int8\" TYPE smallint") { - t.Fatalf("shouldn't execute ALTER COLUMN TYPE if such type is already existed in DB schema: sql: %s", - sql) - } - }, - } - - DB.Migrator().DropTable(&MigrateInt{}) - - // The first AutoMigrate to make table with field with correct type - if err := DB.AutoMigrate(&MigrateInt{}); err != nil { - t.Fatalf("Failed to auto migrate: error: %v", err) - } - - // make new session to set custom logger tracer - session := DB.Session(&gorm.Session{Logger: tracer}) - - // The second AutoMigrate to catch an error - if err := session.AutoMigrate(&MigrateInt{}); err != nil { - t.Fatalf("Failed to auto migrate: error: %v", err) - } -} - -func TestAutoMigrateGaussDB(t *testing.T) { - if DB.Dialector.Name() != "gaussdb" { +func TestAutoMigrateInt8PGAndGaussDB(t *testing.T) { + if DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" { return } @@ -976,68 +938,7 @@ func TestMigrateColumnOrder(t *testing.T) { // https://github.com/go-gorm/gorm/issues/5047 func TestMigrateSerialColumn(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { - return - } - - type Event struct { - ID uint `gorm:"primarykey"` - UID uint32 - } - - type Event1 struct { - ID uint `gorm:"primarykey"` - UID uint32 `gorm:"not null;autoIncrement"` - } - - type Event2 struct { - ID uint `gorm:"primarykey"` - UID uint16 `gorm:"not null;autoIncrement"` - } - - var err error - err = DB.Migrator().DropTable(&Event{}) - if err != nil { - t.Errorf("DropTable err:%v", err) - } - - // create sequence - err = DB.Table("events").AutoMigrate(&Event1{}) - if err != nil { - t.Errorf("AutoMigrate err:%v", err) - } - - // delete sequence - err = DB.Table("events").AutoMigrate(&Event{}) - if err != nil { - t.Errorf("AutoMigrate err:%v", err) - } - - // update sequence - err = DB.Table("events").AutoMigrate(&Event1{}) - if err != nil { - t.Errorf("AutoMigrate err:%v", err) - } - err = DB.Table("events").AutoMigrate(&Event2{}) - if err != nil { - t.Errorf("AutoMigrate err:%v", err) - } - - DB.Table("events").Save(&Event2{}) - DB.Table("events").Save(&Event2{}) - DB.Table("events").Save(&Event2{}) - - events := make([]*Event, 0) - DB.Table("events").Find(&events) - - AssertEqual(t, 3, len(events)) - for _, v := range events { - AssertEqual(t, v.ID, v.UID) - } -} - -func TestMigrateSerialColumnGaussDB(t *testing.T) { - if DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" { return } @@ -1162,7 +1063,7 @@ func TestMigrateAutoIncrement(t *testing.T) { // https://github.com/go-gorm/gorm/issues/5320 func TestPrimarykeyID(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" { return } @@ -1398,7 +1299,7 @@ func findColumnType(dest interface{}, columnName string) ( } func TestInvalidCachedPlanSimpleProtocol(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" { return } @@ -1509,43 +1410,7 @@ func TestDifferentTypeWithoutDeclaredLength(t *testing.T) { } func TestMigrateArrayTypeModel(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { - return - } - - type ArrayTypeModel struct { - ID uint - Number string `gorm:"type:varchar(51);NOT NULL"` - TextArray []string `gorm:"type:text[];NOT NULL"` - NestedTextArray [][]string `gorm:"type:text[][]"` - NestedIntArray [][]int64 `gorm:"type:integer[3][3]"` - } - - var err error - DB.Migrator().DropTable(&ArrayTypeModel{}) - - err = DB.AutoMigrate(&ArrayTypeModel{}) - AssertEqual(t, nil, err) - - ct, err := findColumnType(&ArrayTypeModel{}, "number") - AssertEqual(t, nil, err) - AssertEqual(t, "varchar", ct.DatabaseTypeName()) - - ct, err = findColumnType(&ArrayTypeModel{}, "text_array") - AssertEqual(t, nil, err) - AssertEqual(t, "text[]", ct.DatabaseTypeName()) - - ct, err = findColumnType(&ArrayTypeModel{}, "nested_text_array") - AssertEqual(t, nil, err) - AssertEqual(t, "text[]", ct.DatabaseTypeName()) - - ct, err = findColumnType(&ArrayTypeModel{}, "nested_int_array") - AssertEqual(t, nil, err) - AssertEqual(t, "integer[]", ct.DatabaseTypeName()) -} - -func TestMigrateArrayTypeModelGaussDB(t *testing.T) { - if DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" { return } @@ -1867,67 +1732,8 @@ func TestMigrateView(t *testing.T) { } } -func TestMigrateExistingBoolColumnPG(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { - return - } - - type ColumnStruct struct { - gorm.Model - Name string - StringBool string - SmallintBool int `gorm:"type:smallint"` - } - - type ColumnStruct2 struct { - gorm.Model - Name string - StringBool bool // change existing boolean column from string to boolean - SmallintBool bool // change existing boolean column from smallint or other to boolean - } - - DB.Migrator().DropTable(&ColumnStruct{}) - - if err := DB.AutoMigrate(&ColumnStruct{}); err != nil { - t.Errorf("Failed to migrate, got %v", err) - } - - if err := DB.Table("column_structs").AutoMigrate(&ColumnStruct2{}); err != nil { - t.Fatalf("no error should happened when auto migrate column, but got %v", err) - } - - if columnTypes, err := DB.Migrator().ColumnTypes(&ColumnStruct{}); err != nil { - t.Fatalf("no error should returns for ColumnTypes") - } else { - stmt := &gorm.Statement{DB: DB} - stmt.Parse(&ColumnStruct2{}) - - for _, columnType := range columnTypes { - switch columnType.Name() { - case "id": - if v, ok := columnType.PrimaryKey(); !ok || !v { - t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), - columnType) - } - case "string_bool": - dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name())) - if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) { - t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", - columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType) - } - case "smallint_bool": - dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name())) - if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) { - t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", - columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType) - } - } - } - } -} - -func TestMigrateExistingBoolColumnGaussDB(t *testing.T) { - if DB.Dialector.Name() != "gaussdb" { +func TestMigrateExistingBoolColumnPGAndGaussDB(t *testing.T) { + if DB.Dialector.Name() != "postgres" && DB.Dialector.Name() != "gaussdb" { return } @@ -2320,7 +2126,7 @@ func TestAutoMigrateDecimal(t *testing.T) { `ALTER TABLE "migrate_decimal_columns" ALTER COLUMN "recid3" decimal(9,2) NOT NULL`, } decimalColumnsTest[MigrateDecimalColumn, MigrateDecimalColumn2](t, expectedSql) - } else if DB.Dialector.Name() == "postgres" { + } else if DB.Dialector.Name() == "postgres" || DB.Dialector.Name() == "gaussdb" { type MigrateDecimalColumn struct { RecID1 int64 `gorm:"column:recid1;type:numeric(9,0);not null" json:"recid1"` RecID2 int64 `gorm:"column:recid2;type:numeric(8);not null" json:"recid2"` diff --git a/tests/postgres_test.go b/tests/postgres_test.go index cd59723f..44cac6bf 100644 --- a/tests/postgres_test.go +++ b/tests/postgres_test.go @@ -12,7 +12,7 @@ import ( ) func TestPostgresReturningIDWhichHasStringType(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" { t.Skip() } @@ -62,7 +62,7 @@ func TestPostgresReturningIDWhichHasStringType(t *testing.T) { } func TestPostgres(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" { t.Skip() } @@ -166,7 +166,7 @@ type Category struct { } func TestMany2ManyWithDefaultValueUUID(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" { t.Skip() } @@ -191,7 +191,7 @@ func TestMany2ManyWithDefaultValueUUID(t *testing.T) { } func TestPostgresOnConstraint(t *testing.T) { - if DB.Dialector.Name() != "postgres" || DB.Dialector.Name() != "gaussdb" { + if DB.Dialector.Name() != "postgres" { t.Skip() } diff --git a/tests/table_test.go b/tests/table_test.go index e5d6b4f3..85ae2ab9 100644 --- a/tests/table_test.go +++ b/tests/table_test.go @@ -5,7 +5,7 @@ import ( "sync" "testing" - "github.com/moseszane168/gaussdb" + "gorm.io/driver/gaussdb" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/schema" diff --git a/tests/tests_test.go b/tests/tests_test.go index 5b11459b..a7d03972 100644 --- a/tests/tests_test.go +++ b/tests/tests_test.go @@ -8,7 +8,7 @@ import ( "path/filepath" "time" - "github.com/moseszane168/gaussdb" + "gorm.io/driver/gaussdb" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" @@ -22,7 +22,7 @@ var DB *gorm.DB var ( mysqlDSN = "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local" postgresDSN = "user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" - gaussdbDSN = "user=gaussdb password=Gaussdb@123 dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" + gaussdbDSN = "user=gaussdb password=Gaussdb@123 dbname=gorm host=localhost port=9950 sslmode=disable TimeZone=Asia/Shanghai" sqlserverDSN = "sqlserver://sa:LoremIpsum86@localhost:9930?database=master" tidbDSN = "root:@tcp(localhost:9940)/test?charset=utf8&parseTime=True&loc=Local" )