fix(database/gdb): skip field filtering when table/alias is unknown in FieldsPrefix (#4602)

## Summary
- Fix FieldsPrefix silently dropping fields when called before LeftJoin
- When table/alias is unknown, skip filtering and return fields directly

## Test plan
- [x] Added unit test Test_Issue4595 in pgsql driver
- [x] Test covers: FieldsPrefix before LeftJoin, Fields with prefix,
FieldsPrefix after LeftJoin

Closes #4595
This commit is contained in:
Jack Ling
2026-01-15 10:25:40 +08:00
committed by GitHub
parent 1ed4e0267a
commit 3e73e2d2cc
2 changed files with 96 additions and 0 deletions

View File

@ -205,3 +205,94 @@ func Test_Issue4033(t *testing.T) {
t.AssertNil(err)
})
}
// https://github.com/gogf/gf/issues/4595
// FieldsPrefix silently drops fields when using table alias before LeftJoin.
func Test_Issue4595(t *testing.T) {
var (
tableUser = fmt.Sprintf(`%s_%d`, TablePrefix+"issue4595_user", gtime.TimestampNano())
tableUserDetail = fmt.Sprintf(`%s_%d`, TablePrefix+"issue4595_user_detail", gtime.TimestampNano())
)
// Create user table
if _, err := db.Exec(ctx, fmt.Sprintf(`
CREATE TABLE %s (
id bigserial PRIMARY KEY,
name varchar(100),
email varchar(100)
);`, tableUser,
)); err != nil {
gtest.Fatal(err)
}
defer dropTable(tableUser)
// Create user_detail table
if _, err := db.Exec(ctx, fmt.Sprintf(`
CREATE TABLE %s (
id bigserial PRIMARY KEY,
user_id bigint,
phone varchar(20),
address varchar(200)
);`, tableUserDetail,
)); err != nil {
gtest.Fatal(err)
}
defer dropTable(tableUserDetail)
// Insert test data
if _, err := db.Exec(ctx, fmt.Sprintf(`
INSERT INTO %s (id, name, email) VALUES (1, 'john', 'john@example.com');
INSERT INTO %s (id, user_id, phone, address) VALUES (1, 1, '1234567890', '123 Main St');
`, tableUser, tableUserDetail)); err != nil {
gtest.Fatal(err)
}
gtest.C(t, func(t *gtest.T) {
// Test case 1: FieldsPrefix called before LeftJoin
// Both t1 and t2 fields should be present
r, err := db.Model(tableUser).As("t1").
FieldsPrefix("t2", "phone", "address").
FieldsPrefix("t1", "id", "name", "email").
LeftJoin(tableUserDetail, "t2", "t1.id=t2.user_id").
All()
t.AssertNil(err)
t.Assert(len(r), 1)
t.Assert(r[0]["id"], 1)
t.Assert(r[0]["name"], "john")
t.Assert(r[0]["email"], "john@example.com")
t.Assert(r[0]["phone"], "1234567890")
t.Assert(r[0]["address"], "123 Main St")
})
gtest.C(t, func(t *gtest.T) {
// Test case 2: Using Fields() with prefix
r, err := db.Model(tableUser).As("t1").
Fields("t2.phone", "t2.address", "t1.id", "t1.name", "t1.email").
LeftJoin(tableUserDetail, "t2", "t1.id=t2.user_id").
All()
t.AssertNil(err)
t.Assert(len(r), 1)
t.Assert(r[0]["id"], 1)
t.Assert(r[0]["name"], "john")
t.Assert(r[0]["email"], "john@example.com")
t.Assert(r[0]["phone"], "1234567890")
t.Assert(r[0]["address"], "123 Main St")
})
gtest.C(t, func(t *gtest.T) {
// Test case 3: FieldsPrefix called after LeftJoin
r, err := db.Model(tableUser).As("t1").
LeftJoin(tableUserDetail, "t2", "t1.id=t2.user_id").
FieldsPrefix("t2", "phone", "address").
FieldsPrefix("t1", "id", "name", "email").
All()
t.AssertNil(err)
t.Assert(len(r), 1)
t.Assert(r[0]["id"], 1)
t.Assert(r[0]["name"], "john")
t.Assert(r[0]["email"], "john@example.com")
t.Assert(r[0]["phone"], "1234567890")
t.Assert(r[0]["address"], "123 Main St")
})
}

View File

@ -68,6 +68,11 @@ func (m *Model) mappingAndFilterToTableFields(table string, fields []any, filter
if fieldsTable != "" {
hasTable, _ := m.db.GetCore().HasTable(fieldsTable)
if !hasTable {
if fieldsTable != m.tablesInit {
// Table/alias unknown (e.g., FieldsPrefix called before LeftJoin), skip filtering.
return fields
}
// HasTable cache miss for main table, fallback to use main table for field mapping.
fieldsTable = m.tablesInit
}
}