Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 132 additions & 24 deletions contrib/drivers/mysql/mysql_z_unit_feature_hook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package mysql_test

import (
"context"
"database/sql"
"fmt"
"testing"

Expand All @@ -23,19 +22,18 @@ func Test_Model_Hook_Select(t *testing.T) {
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
m := db.Model(table).Hook(gdb.HookHandler{
Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {
result, err = in.Next(ctx)
m := db.Model(table).Hook(
gdb.AfterSelect(func(ctx context.Context, in *gdb.HookSelectInput, result gdb.Result, err error) (gdb.Result, error) {
if err != nil {
return
return result, err
}
for i, record := range result {
record["test"] = gvar.New(100 + record["id"].Int())
result[i] = record
}
return
},
})
return result, nil
}),
)
all, err := m.Where(`id > 6`).OrderAsc(`id`).All(ctx)
t.AssertNil(err)
t.Assert(len(all), 4)
Expand All @@ -52,16 +50,16 @@ func Test_Model_Hook_Insert(t *testing.T) {
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
m := db.Model(table).Hook(gdb.HookHandler{
Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {
m := db.Model(table).Hook(
gdb.BeforeInsert(func(ctx context.Context, in *gdb.HookInsertInput) error {
for i, item := range in.Data {
item["passport"] = fmt.Sprintf(`test_port_%d`, item["id"])
item["nickname"] = fmt.Sprintf(`test_name_%d`, item["id"])
in.Data[i] = item
}
return in.Next(ctx)
},
})
return nil
}),
)
_, err := m.Data(g.Map{
"id": 1,
"nickname": "name_1",
Expand All @@ -80,8 +78,8 @@ func Test_Model_Hook_Update(t *testing.T) {
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
m := db.Model(table).Hook(gdb.HookHandler{
Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {
m := db.Model(table).Hook(
gdb.BeforeUpdate(func(ctx context.Context, in *gdb.HookUpdateInput) error {
switch value := in.Data.(type) {
case gdb.List:
for i, data := range value {
Expand All @@ -96,9 +94,9 @@ func Test_Model_Hook_Update(t *testing.T) {
value["nickname"] = `name`
in.Data = value
}
return in.Next(ctx)
},
})
return nil
}),
)
_, err := m.Data(g.Map{
"nickname": "name_1",
}).WherePri(1).Update(ctx)
Expand All @@ -117,13 +115,17 @@ func Test_Model_Hook_Delete(t *testing.T) {
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
m := db.Model(table).Hook(gdb.HookHandler{
Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {
return db.Model(table).Data(g.Map{
m := db.Model(table).Hook(
gdb.BeforeDelete(func(ctx context.Context, in *gdb.HookDeleteInput) error {
origCondition := in.Condition
// Make delete a no-op, then execute the intended update.
in.Condition = "1=0"
_, err := in.Model.Data(g.Map{
"nickname": `deleted`,
}).Where(in.Condition).Update(ctx)
},
})
}).Where(origCondition).Update(ctx)
return err
}),
)
_, err := m.Where(1).Delete(ctx)
t.AssertNil(err)

Expand All @@ -134,3 +136,109 @@ func Test_Model_Hook_Delete(t *testing.T) {
}
})
}

// Test_Model_Hook_Multiple tests multiple hooks execution order
func Test_Model_Hook_Multiple(t *testing.T) {
table := createInitTable()
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
var afterCalls []string
m := db.Model(table).
Hook(
gdb.AfterSelect(func(ctx context.Context, in *gdb.HookSelectInput, result gdb.Result, err error) (gdb.Result, error) {
afterCalls = append(afterCalls, "hook1")
if err != nil {
return result, err
}
for i, record := range result {
record["hook1"] = gvar.New("value1")
result[i] = record
}
return result, nil
}),
).
Hook(
gdb.AfterSelect(func(ctx context.Context, in *gdb.HookSelectInput, result gdb.Result, err error) (gdb.Result, error) {
afterCalls = append(afterCalls, "hook2")
if err != nil {
return result, err
}
for i, record := range result {
record["hook2"] = gvar.New("value2")
result[i] = record
}
return result, nil
}),
)

_, err := m.Where("id", 1).One(ctx)
t.AssertNil(err)

one, err := m.One(ctx)
t.AssertNil(err)
t.Assert(one["hook1"].String(), "value1")
t.Assert(one["hook2"].String(), "value2")
t.Assert(afterCalls, g.Slice{"hook1", "hook2"})
})
}

// Test_Model_Hook_Error_Abort tests hook returning error aborts operation
func Test_Model_Hook_Error_Abort(t *testing.T) {
table := createInitTable()
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
m := db.Model(table).Hook(
gdb.BeforeInsert(func(ctx context.Context, in *gdb.HookInsertInput) error {
// Return error to abort insert.
return fmt.Errorf("hook aborted insert")
}),
)

_, err := m.Data(g.Map{
"passport": "test_abort",
"password": "pass",
"nickname": "name",
}).Insert(ctx)
t.AssertNE(err, nil)
t.Assert(err.Error(), "hook aborted insert")

// Verify record was not inserted
count, err := db.Model(table).Where("passport", "test_abort").Count(ctx)
t.AssertNil(err)
t.Assert(count, 0)
})
}

// Test_Model_Hook_Modify_Data tests hook modifying data before insert
func Test_Model_Hook_Modify_Data(t *testing.T) {
table := createTable()
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
m := db.Model(table).Hook(
gdb.BeforeInsert(func(ctx context.Context, in *gdb.HookInsertInput) error {
// Modify all data items
for i := range in.Data {
in.Data[i]["password"] = "encrypted_" + fmt.Sprint(in.Data[i]["password"])
in.Data[i]["nickname"] = "verified_" + fmt.Sprint(in.Data[i]["nickname"])
}
return nil
}),
)

_, err := m.Data(g.Map{
"passport": "test_user",
"password": "plain123",
"nickname": "john",
}).Insert(ctx)
t.AssertNil(err)

// Verify data was modified by hook
one, err := db.Model(table).Where("passport", "test_user").One(ctx)
t.AssertNil(err)
t.Assert(one["password"].String(), "encrypted_plain123")
t.Assert(one["nickname"].String(), "verified_john")
})
}
63 changes: 31 additions & 32 deletions contrib/drivers/mysql/mysql_z_unit_feature_model_sharding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package mysql_test

import (
"context"
"database/sql"
"fmt"
"testing"

Expand Down Expand Up @@ -70,7 +69,7 @@ func dropShardingDatabase(t *gtest.T) {
}

func Test_Sharding_Basic(t *testing.T) {
return
t.Skip("disabled by default: requires sharding test databases")
gtest.C(t, func(t *gtest.T) {
var (
tablePrefix = "user_"
Expand Down Expand Up @@ -144,7 +143,7 @@ func Test_Sharding_Basic(t *testing.T) {

// Test_Sharding_Error tests error cases
func Test_Sharding_Error(t *testing.T) {
return
t.Skip("disabled by default: requires sharding test databases")
gtest.C(t, func(t *gtest.T) {
// Create test databases and tables
createShardingDatabase(t)
Expand Down Expand Up @@ -182,7 +181,7 @@ func Test_Sharding_Error(t *testing.T) {

// Test_Sharding_Complex tests complex sharding scenarios
func Test_Sharding_Complex(t *testing.T) {
return
t.Skip("disabled by default: requires sharding test databases")
gtest.C(t, func(t *gtest.T) {
// Create test databases and tables
createShardingDatabase(t)
Expand Down Expand Up @@ -251,24 +250,24 @@ func Test_Model_Sharding_Table_Using_Hook(t *testing.T) {
createTable(table2)
defer dropTable(table2)

shardingModel := db.Model(table1).Hook(gdb.HookHandler{
Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {
shardingModel := db.Model(table1).Hook(
gdb.BeforeSelect(func(ctx context.Context, in *gdb.HookSelectInput) error {
in.Table = table2
return in.Next(ctx)
},
Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {
return nil
}),
gdb.BeforeInsert(func(ctx context.Context, in *gdb.HookInsertInput) error {
in.Table = table2
return in.Next(ctx)
},
Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {
return nil
}),
gdb.BeforeUpdate(func(ctx context.Context, in *gdb.HookUpdateInput) error {
in.Table = table2
return in.Next(ctx)
},
Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {
return nil
}),
gdb.BeforeDelete(func(ctx context.Context, in *gdb.HookDeleteInput) error {
in.Table = table2
return in.Next(ctx)
},
})
return nil
}),
)
gtest.C(t, func(t *gtest.T) {
r, err := shardingModel.Data(g.Map{
"id": 1,
Expand Down Expand Up @@ -359,28 +358,28 @@ func Test_Model_Sharding_Schema_Using_Hook(t *testing.T) {
createTableWithDb(db2, table)
defer dropTableWithDb(db2, table)

shardingModel := db.Model(table).Hook(gdb.HookHandler{
Select: func(ctx context.Context, in *gdb.HookSelectInput) (result gdb.Result, err error) {
shardingModel := db.Model(table).Hook(
gdb.BeforeSelect(func(ctx context.Context, in *gdb.HookSelectInput) error {
in.Table = table
in.Schema = db2.GetSchema()
return in.Next(ctx)
},
Insert: func(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result, err error) {
return nil
}),
gdb.BeforeInsert(func(ctx context.Context, in *gdb.HookInsertInput) error {
in.Table = table
in.Schema = db2.GetSchema()
return in.Next(ctx)
},
Update: func(ctx context.Context, in *gdb.HookUpdateInput) (result sql.Result, err error) {
return nil
}),
gdb.BeforeUpdate(func(ctx context.Context, in *gdb.HookUpdateInput) error {
in.Table = table
in.Schema = db2.GetSchema()
return in.Next(ctx)
},
Delete: func(ctx context.Context, in *gdb.HookDeleteInput) (result sql.Result, err error) {
return nil
}),
gdb.BeforeDelete(func(ctx context.Context, in *gdb.HookDeleteInput) error {
in.Table = table
in.Schema = db2.GetSchema()
return in.Next(ctx)
},
})
return nil
}),
)
gtest.C(t, func(t *gtest.T) {
r, err := shardingModel.Data(g.Map{
"id": 1,
Expand Down
Loading
Loading