diff --git a/cmd/gf/internal/cmd/cmd_z_init_test.go b/cmd/gf/internal/cmd/cmd_z_init_test.go index 1e71cbd8bb6..d066a259905 100644 --- a/cmd/gf/internal/cmd/cmd_z_init_test.go +++ b/cmd/gf/internal/cmd/cmd_z_init_test.go @@ -15,9 +15,11 @@ import ( ) var ( - ctx = context.Background() - testDB gdb.DB - link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true" + ctx = context.Background() + testDB gdb.DB + testPgDB gdb.DB + link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true" + linkPg = "pgsql:postgres:12345678@tcp(127.0.0.1:5432)/test" ) func init() { @@ -28,6 +30,10 @@ func init() { if err != nil { panic(err) } + // PostgreSQL connection (optional, may not be available in all environments) + testPgDB, _ = gdb.New(gdb.ConfigNode{ + Link: linkPg, + }) } func dropTableWithDb(db gdb.DB, table string) { @@ -36,3 +42,11 @@ func dropTableWithDb(db gdb.DB, table string) { gtest.Error(err) } } + +// dropTableStd uses standard SQL syntax compatible with MySQL and PostgreSQL. +func dropTableStd(db gdb.DB, table string) { + dropTableStmt := fmt.Sprintf("DROP TABLE IF EXISTS %s", table) + if _, err := db.Exec(ctx, dropTableStmt); err != nil { + gtest.Error(err) + } +} diff --git a/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_issue_test.go b/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_issue_test.go index 02d5f5936da..3a8421fda35 100644 --- a/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_issue_test.go +++ b/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_issue_test.go @@ -460,3 +460,398 @@ func Test_Gen_Dao_Issue3749(t *testing.T) { } }) } + +// https://github.com/gogf/gf/issues/4629 +// Test tables pattern matching with * wildcard. +func Test_Gen_Dao_Issue4629_TablesPattern_Star(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + err error + db = testDB + table1 = "trade_order" + table2 = "trade_item" + table3 = "user_info" + table4 = "user_log" + table5 = "config" + sqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`) + ) + dropTableStd(db, table1) + dropTableStd(db, table2) + dropTableStd(db, table3) + dropTableStd(db, table4) + dropTableStd(db, table5) + t.AssertNil(execSqlFile(db, sqlFilePath)) + defer dropTableStd(db, table1) + defer dropTableStd(db, table2) + defer dropTableStd(db, table3) + defer dropTableStd(db, table4) + defer dropTableStd(db, table5) + + var ( + path = gfile.Temp(guid.S()) + group = "test" + in = gendao.CGenDaoInput{ + Path: path, + Link: link, + Group: group, + Tables: "trade_*", // Should match trade_order, trade_item + } + ) + err = gutil.FillStructWithDefault(&in) + t.AssertNil(err) + + err = gfile.Mkdir(path) + t.AssertNil(err) + + pwd := gfile.Pwd() + err = gfile.Chdir(path) + t.AssertNil(err) + defer gfile.Chdir(pwd) + defer gfile.RemoveAll(path) + + _, err = gendao.CGenDao{}.Dao(ctx, in) + t.AssertNil(err) + + // Should generate 2 dao files: trade_order.go, trade_item.go + generatedFiles, err := gfile.ScanDir(gfile.Join(path, "dao"), "*.go", false) + t.AssertNil(err) + t.Assert(len(generatedFiles), 2) + + // Verify the correct files are generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_order.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_item.go")), true) + // user_* and config should NOT be generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_info.go")), false) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_log.go")), false) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "config.go")), false) + }) +} + +// https://github.com/gogf/gf/issues/4629 +// Test tables pattern matching with multiple patterns. +func Test_Gen_Dao_Issue4629_TablesPattern_Multiple(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + err error + db = testDB + table1 = "trade_order" + table2 = "trade_item" + table3 = "user_info" + table4 = "user_log" + table5 = "config" + sqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`) + ) + dropTableStd(db, table1) + dropTableStd(db, table2) + dropTableStd(db, table3) + dropTableStd(db, table4) + dropTableStd(db, table5) + t.AssertNil(execSqlFile(db, sqlFilePath)) + defer dropTableStd(db, table1) + defer dropTableStd(db, table2) + defer dropTableStd(db, table3) + defer dropTableStd(db, table4) + defer dropTableStd(db, table5) + + var ( + path = gfile.Temp(guid.S()) + group = "test" + in = gendao.CGenDaoInput{ + Path: path, + Link: link, + Group: group, + Tables: "trade_*,user_*", // Should match trade_order, trade_item, user_info, user_log + } + ) + err = gutil.FillStructWithDefault(&in) + t.AssertNil(err) + + err = gfile.Mkdir(path) + t.AssertNil(err) + + pwd := gfile.Pwd() + err = gfile.Chdir(path) + t.AssertNil(err) + defer gfile.Chdir(pwd) + defer gfile.RemoveAll(path) + + _, err = gendao.CGenDao{}.Dao(ctx, in) + t.AssertNil(err) + + // Should generate 4 dao files + generatedFiles, err := gfile.ScanDir(gfile.Join(path, "dao"), "*.go", false) + t.AssertNil(err) + t.Assert(len(generatedFiles), 4) + + // Verify the correct files are generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_order.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_item.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_info.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_log.go")), true) + // config should NOT be generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "config.go")), false) + }) +} + +// https://github.com/gogf/gf/issues/4629 +// Test tables pattern mixed with exact table name. +func Test_Gen_Dao_Issue4629_TablesPattern_Mixed(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + err error + db = testDB + table1 = "trade_order" + table2 = "trade_item" + table3 = "user_info" + table4 = "user_log" + table5 = "config" + sqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`) + ) + dropTableStd(db, table1) + dropTableStd(db, table2) + dropTableStd(db, table3) + dropTableStd(db, table4) + dropTableStd(db, table5) + t.AssertNil(execSqlFile(db, sqlFilePath)) + defer dropTableStd(db, table1) + defer dropTableStd(db, table2) + defer dropTableStd(db, table3) + defer dropTableStd(db, table4) + defer dropTableStd(db, table5) + + var ( + path = gfile.Temp(guid.S()) + group = "test" + in = gendao.CGenDaoInput{ + Path: path, + Link: link, + Group: group, + Tables: "trade_*,config", // Pattern + exact name + } + ) + err = gutil.FillStructWithDefault(&in) + t.AssertNil(err) + + err = gfile.Mkdir(path) + t.AssertNil(err) + + pwd := gfile.Pwd() + err = gfile.Chdir(path) + t.AssertNil(err) + defer gfile.Chdir(pwd) + defer gfile.RemoveAll(path) + + _, err = gendao.CGenDao{}.Dao(ctx, in) + t.AssertNil(err) + + // Should generate 3 dao files: trade_order.go, trade_item.go, config.go + generatedFiles, err := gfile.ScanDir(gfile.Join(path, "dao"), "*.go", false) + t.AssertNil(err) + t.Assert(len(generatedFiles), 3) + + // Verify the correct files are generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_order.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_item.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "config.go")), true) + // user_* should NOT be generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_info.go")), false) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_log.go")), false) + }) +} + +// https://github.com/gogf/gf/issues/4629 +// Test tables pattern with ? wildcard (single character match). +func Test_Gen_Dao_Issue4629_TablesPattern_Question(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + err error + db = testDB + table1 = "trade_order" + table2 = "trade_item" + table3 = "user_info" + table4 = "user_log" + table5 = "config" + sqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`) + ) + dropTableStd(db, table1) + dropTableStd(db, table2) + dropTableStd(db, table3) + dropTableStd(db, table4) + dropTableStd(db, table5) + t.AssertNil(execSqlFile(db, sqlFilePath)) + defer dropTableStd(db, table1) + defer dropTableStd(db, table2) + defer dropTableStd(db, table3) + defer dropTableStd(db, table4) + defer dropTableStd(db, table5) + + var ( + path = gfile.Temp(guid.S()) + group = "test" + in = gendao.CGenDaoInput{ + Path: path, + Link: link, + Group: group, + Tables: "user_???", // ? matches single char: user_log (3 chars) but not user_info (4 chars) + } + ) + err = gutil.FillStructWithDefault(&in) + t.AssertNil(err) + + err = gfile.Mkdir(path) + t.AssertNil(err) + + pwd := gfile.Pwd() + err = gfile.Chdir(path) + t.AssertNil(err) + defer gfile.Chdir(pwd) + defer gfile.RemoveAll(path) + + _, err = gendao.CGenDao{}.Dao(ctx, in) + t.AssertNil(err) + + // Should generate 1 dao file: user_log.go (3 chars after user_) + generatedFiles, err := gfile.ScanDir(gfile.Join(path, "dao"), "*.go", false) + t.AssertNil(err) + t.Assert(len(generatedFiles), 1) + + // Verify only user_log is generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_log.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_info.go")), false) // 4 chars, doesn't match + }) +} + +// https://github.com/gogf/gf/issues/4629 +// Test that exact table names still work (backward compatibility). +func Test_Gen_Dao_Issue4629_TablesPattern_ExactNames(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + err error + db = testDB + table1 = "trade_order" + table2 = "trade_item" + table3 = "user_info" + table4 = "user_log" + table5 = "config" + sqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`) + ) + dropTableStd(db, table1) + dropTableStd(db, table2) + dropTableStd(db, table3) + dropTableStd(db, table4) + dropTableStd(db, table5) + t.AssertNil(execSqlFile(db, sqlFilePath)) + defer dropTableStd(db, table1) + defer dropTableStd(db, table2) + defer dropTableStd(db, table3) + defer dropTableStd(db, table4) + defer dropTableStd(db, table5) + + var ( + path = gfile.Temp(guid.S()) + group = "test" + in = gendao.CGenDaoInput{ + Path: path, + Link: link, + Group: group, + Tables: "trade_order,config", // Exact names, no patterns + } + ) + err = gutil.FillStructWithDefault(&in) + t.AssertNil(err) + + err = gfile.Mkdir(path) + t.AssertNil(err) + + pwd := gfile.Pwd() + err = gfile.Chdir(path) + t.AssertNil(err) + defer gfile.Chdir(pwd) + defer gfile.RemoveAll(path) + + _, err = gendao.CGenDao{}.Dao(ctx, in) + t.AssertNil(err) + + // Should generate 2 dao files + generatedFiles, err := gfile.ScanDir(gfile.Join(path, "dao"), "*.go", false) + t.AssertNil(err) + t.Assert(len(generatedFiles), 2) + + // Verify exactly the specified tables are generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_order.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "config.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_item.go")), false) + }) +} + +// https://github.com/gogf/gf/issues/4629 +// Test tables pattern matching with PostgreSQL. +func Test_Gen_Dao_Issue4629_TablesPattern_PgSql(t *testing.T) { + if testPgDB == nil { + t.Skip("PostgreSQL database not available, skipping test") + return + } + gtest.C(t, func(t *gtest.T) { + var ( + err error + db = testPgDB + table1 = "trade_order" + table2 = "trade_item" + table3 = "user_info" + table4 = "user_log" + table5 = "config" + sqlFilePath = gtest.DataPath(`gendao`, `tables_pattern.sql`) + ) + dropTableStd(db, table1) + dropTableStd(db, table2) + dropTableStd(db, table3) + dropTableStd(db, table4) + dropTableStd(db, table5) + t.AssertNil(execSqlFile(db, sqlFilePath)) + defer dropTableStd(db, table1) + defer dropTableStd(db, table2) + defer dropTableStd(db, table3) + defer dropTableStd(db, table4) + defer dropTableStd(db, table5) + + // Test tables pattern with tablesEx pattern + var ( + path = gfile.Temp(guid.S()) + group = "test" + in = gendao.CGenDaoInput{ + Path: path, + Link: linkPg, + Group: group, + Tables: "trade_*,user_*,config", // Match only our test tables + TablesEx: "user_*", // Exclude user_* tables + } + ) + err = gutil.FillStructWithDefault(&in) + t.AssertNil(err) + + err = gfile.Mkdir(path) + t.AssertNil(err) + + pwd := gfile.Pwd() + err = gfile.Chdir(path) + t.AssertNil(err) + defer gfile.Chdir(pwd) + defer gfile.RemoveAll(path) + + _, err = gendao.CGenDao{}.Dao(ctx, in) + t.AssertNil(err) + + // Should generate 3 dao files: trade_order, trade_item, config (user_* excluded by tablesEx) + generatedFiles, err := gfile.ScanDir(gfile.Join(path, "dao"), "*.go", false) + t.AssertNil(err) + t.Assert(len(generatedFiles), 3) + + // Verify the correct files are generated + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_order.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "trade_item.go")), true) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "config.go")), true) + // user_* should NOT be generated (excluded by tablesEx) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_info.go")), false) + t.Assert(gfile.Exists(gfile.Join(path, "dao", "user_log.go")), false) + }) +} diff --git a/cmd/gf/internal/cmd/gendao/gendao.go b/cmd/gf/internal/cmd/gendao/gendao.go index bc6ad943ac5..47c0cef2a73 100644 --- a/cmd/gf/internal/cmd/gendao/gendao.go +++ b/cmd/gf/internal/cmd/gendao/gendao.go @@ -187,7 +187,27 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) { var tableNames []string if in.Tables != "" { - tableNames = gstr.SplitAndTrim(in.Tables, ",") + inputTables := gstr.SplitAndTrim(in.Tables, ",") + // Check if any table pattern contains wildcard characters. + // https://github.com/gogf/gf/issues/4629 + var hasPattern bool + for _, t := range inputTables { + if containsWildcard(t) { + hasPattern = true + break + } + } + if hasPattern { + // Fetch all tables first, then filter by patterns. + allTables, err := db.Tables(context.TODO()) + if err != nil { + mlog.Fatalf("fetching tables failed: %+v", err) + } + tableNames = filterTablesByPatterns(allTables, inputTables) + } else { + // Use exact table names as before. + tableNames = inputTables + } } else { tableNames, err = db.Tables(context.TODO()) if err != nil { @@ -198,22 +218,11 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) { if in.TablesEx != "" { array := garray.NewStrArrayFrom(tableNames) for _, p := range gstr.SplitAndTrim(in.TablesEx, ",") { - if gstr.Contains(p, "*") || gstr.Contains(p, "?") { - p = gstr.ReplaceByMap(p, map[string]string{ - "\r": "", - "\n": "", - }) - p = gstr.ReplaceByMap(p, map[string]string{ - "*": "\r", - "?": "\n", - }) - p = gregex.Quote(p) - p = gstr.ReplaceByMap(p, map[string]string{ - "\r": ".*", - "\n": ".", - }) + if containsWildcard(p) { + // Use exact match with ^ and $ anchors for consistency with tables pattern. + regPattern := "^" + patternToRegex(p) + "$" for _, v := range array.Clone().Slice() { - if gregex.IsMatchString(p, v) { + if gregex.IsMatchString(regPattern, v) { array.RemoveValue(v) } } @@ -411,3 +420,61 @@ func getTemplateFromPathOrDefault(filePath string, def string) string { } return def } + +// containsWildcard checks if the pattern contains wildcard characters (* or ?). +func containsWildcard(pattern string) bool { + return gstr.Contains(pattern, "*") || gstr.Contains(pattern, "?") +} + +// patternToRegex converts a wildcard pattern to a regex pattern. +// Wildcard characters: * matches any characters, ? matches single character. +func patternToRegex(pattern string) string { + pattern = gstr.ReplaceByMap(pattern, map[string]string{ + "\r": "", + "\n": "", + }) + pattern = gstr.ReplaceByMap(pattern, map[string]string{ + "*": "\r", + "?": "\n", + }) + pattern = gregex.Quote(pattern) + pattern = gstr.ReplaceByMap(pattern, map[string]string{ + "\r": ".*", + "\n": ".", + }) + return pattern +} + +// filterTablesByPatterns filters tables by given patterns. +// Patterns support wildcard characters: * matches any characters, ? matches single character. +// https://github.com/gogf/gf/issues/4629 +func filterTablesByPatterns(allTables []string, patterns []string) []string { + var result []string + matched := make(map[string]bool) + allTablesSet := make(map[string]bool) + for _, t := range allTables { + allTablesSet[t] = true + } + for _, p := range patterns { + if containsWildcard(p) { + regPattern := "^" + patternToRegex(p) + "$" + for _, table := range allTables { + if !matched[table] && gregex.IsMatchString(regPattern, table) { + result = append(result, table) + matched[table] = true + } + } + } else { + // Exact table name, use direct string comparison. + if !allTablesSet[p] { + mlog.Printf(`table "%s" does not exist, skipped`, p) + continue + } + if !matched[p] { + result = append(result, p) + matched[p] = true + } + } + } + return result +} diff --git a/cmd/gf/internal/cmd/gendao/gendao_test.go b/cmd/gf/internal/cmd/gendao/gendao_test.go new file mode 100644 index 00000000000..80b67d907e8 --- /dev/null +++ b/cmd/gf/internal/cmd/gendao/gendao_test.go @@ -0,0 +1,182 @@ +// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gendao + +import ( + "testing" + + "github.com/gogf/gf/v2/test/gtest" +) + +// Test containsWildcard function. +func Test_containsWildcard(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + t.Assert(containsWildcard("trade_*"), true) + t.Assert(containsWildcard("user_?"), true) + t.Assert(containsWildcard("*"), true) + t.Assert(containsWildcard("?"), true) + t.Assert(containsWildcard("trade_order"), false) + t.Assert(containsWildcard(""), false) + }) +} + +// Test patternToRegex function. +func Test_patternToRegex(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + // * should become .* + t.Assert(patternToRegex("trade_*"), "trade_.*") + // ? should become . + t.Assert(patternToRegex("user_???"), "user_...") + // Mixed + t.Assert(patternToRegex("*_order_?"), ".*_order_.") + // No wildcards - should escape special regex chars + t.Assert(patternToRegex("trade_order"), "trade_order") + // Just * + t.Assert(patternToRegex("*"), ".*") + }) +} + +// Test filterTablesByPatterns with * wildcard. +func Test_filterTablesByPatterns_Star(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info", "user_log", "config"} + + // Single pattern with * + result := filterTablesByPatterns(allTables, []string{"trade_*"}) + t.Assert(len(result), 2) + t.AssertIN("trade_order", result) + t.AssertIN("trade_item", result) + + // Multiple patterns with * + result = filterTablesByPatterns(allTables, []string{"trade_*", "user_*"}) + t.Assert(len(result), 4) + t.AssertIN("trade_order", result) + t.AssertIN("trade_item", result) + t.AssertIN("user_info", result) + t.AssertIN("user_log", result) + }) +} + +// Test filterTablesByPatterns with ? wildcard. +func Test_filterTablesByPatterns_Question(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info", "user_log", "config"} + + // ? matches single character: user_log (3 chars) but not user_info (4 chars) + result := filterTablesByPatterns(allTables, []string{"user_???"}) + t.Assert(len(result), 1) + t.AssertIN("user_log", result) + t.AssertNI("user_info", result) + + // user_???? should match user_info (4 chars) + result = filterTablesByPatterns(allTables, []string{"user_????"}) + t.Assert(len(result), 1) + t.AssertIN("user_info", result) + t.AssertNI("user_log", result) + }) +} + +// Test filterTablesByPatterns with mixed patterns and exact names. +func Test_filterTablesByPatterns_Mixed(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info", "user_log", "config"} + + // Pattern + exact name + result := filterTablesByPatterns(allTables, []string{"trade_*", "config"}) + t.Assert(len(result), 3) + t.AssertIN("trade_order", result) + t.AssertIN("trade_item", result) + t.AssertIN("config", result) + t.AssertNI("user_info", result) + t.AssertNI("user_log", result) + }) +} + +// Test filterTablesByPatterns with exact names only (backward compatibility). +func Test_filterTablesByPatterns_ExactNames(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info", "user_log", "config"} + + // Exact names only + result := filterTablesByPatterns(allTables, []string{"trade_order", "config"}) + t.Assert(len(result), 2) + t.AssertIN("trade_order", result) + t.AssertIN("config", result) + t.AssertNI("trade_item", result) + }) +} + +// Test filterTablesByPatterns - no duplicates when table matches multiple patterns. +func Test_filterTablesByPatterns_NoDuplicates(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info"} + + // trade_order matches both patterns, should only appear once + result := filterTablesByPatterns(allTables, []string{"trade_*", "trade_order"}) + t.Assert(len(result), 2) // trade_order, trade_item + + // Count occurrences of trade_order + count := 0 + for _, v := range result { + if v == "trade_order" { + count++ + } + } + t.Assert(count, 1) // No duplicates + }) +} + +// Test filterTablesByPatterns - pattern matches nothing. +func Test_filterTablesByPatterns_NoMatch(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info"} + + // Pattern that matches nothing + result := filterTablesByPatterns(allTables, []string{"nonexistent_*"}) + t.Assert(len(result), 0) + }) +} + +// Test filterTablesByPatterns - empty input. +func Test_filterTablesByPatterns_Empty(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item"} + + // Empty patterns + result := filterTablesByPatterns(allTables, []string{}) + t.Assert(len(result), 0) + + // Empty tables + result = filterTablesByPatterns([]string{}, []string{"trade_*"}) + t.Assert(len(result), 0) + }) +} + +// Test filterTablesByPatterns - "*" matches all tables. +func Test_filterTablesByPatterns_MatchAll(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info", "user_log", "config"} + + // "*" should match all tables + result := filterTablesByPatterns(allTables, []string{"*"}) + t.Assert(len(result), 5) + }) +} + +// Test filterTablesByPatterns - non-existent exact table name should be skipped. +func Test_filterTablesByPatterns_NonExistent(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + allTables := []string{"trade_order", "trade_item", "user_info"} + + // Mix of existing and non-existing tables + result := filterTablesByPatterns(allTables, []string{"trade_order", "nonexistent", "user_info"}) + t.Assert(len(result), 2) + t.AssertIN("trade_order", result) + t.AssertIN("user_info", result) + t.AssertNI("nonexistent", result) + }) +} diff --git a/cmd/gf/internal/cmd/testdata/gendao/tables_pattern.sql b/cmd/gf/internal/cmd/testdata/gendao/tables_pattern.sql new file mode 100644 index 00000000000..0d122de3ab4 --- /dev/null +++ b/cmd/gf/internal/cmd/testdata/gendao/tables_pattern.sql @@ -0,0 +1,30 @@ +-- Test case for issue #4629: tables pattern matching +-- https://github.com/gogf/gf/issues/4629 +-- Standard SQL syntax compatible with MySQL and PostgreSQL +-- +-- Tables: trade_order, trade_item, user_info, user_log, config + +CREATE TABLE trade_order ( + id INTEGER PRIMARY KEY, + name VARCHAR(45) NOT NULL +); + +CREATE TABLE trade_item ( + id INTEGER PRIMARY KEY, + name VARCHAR(45) NOT NULL +); + +CREATE TABLE user_info ( + id INTEGER PRIMARY KEY, + name VARCHAR(45) NOT NULL +); + +CREATE TABLE user_log ( + id INTEGER PRIMARY KEY, + name VARCHAR(45) NOT NULL +); + +CREATE TABLE config ( + id INTEGER PRIMARY KEY, + name VARCHAR(45) NOT NULL +);