Golang go-jet 查询结果映射仅适用于匿名结构

问题描述 投票:0回答:1

我在使用 go-jet 时遇到一个非常奇怪的问题,它似乎只能填充匿名结构而不是命名结构?

这是我的代码

package api

import (
    "fmt"
    "reflect"

    "github.com/Napam/apato/internal/api/database"
    // gen "github.com/Napam/apato/internal/generated"
    . "github.com/Napam/apato/internal/generated/apato/app/table"
    "github.com/Napam/apato/internal/utils/auth"
    "github.com/Napam/apato/internal/utils/logging"
    . "github.com/go-jet/jet/v2/postgres"
    "github.com/labstack/echo/v4"
    "github.com/rs/zerolog"
)

func (h *Handlers) GetAuthUser(c echo.Context) error {
    logger := logging.GetRequestLogger(c)
    logger.Info().Msg("Start get auth user")

    userId, err := auth.GetRequestUserId(c)
    if err != nil {
        return &echo.HTTPError{
            Code:    401,
            Message: "Unauthorized",
        }
    }
    logger.Info().Str("userId", userId).Msg("Retrieved user id from request context")

    selectStatment := Users.SELECT(
        Users.FirstName.AS("firstName"),
        Users.LastName.AS("lastName"),
        Users.Email.AS("email"),
        Users.ID.AS("id"),
        Users.ProviderName.AS("providerName"),
    ).WHERE(
        Users.ID.EQ(String(userId)),
    )

    logger.Debug().Func(func(e *zerolog.Event) {
        e.Str("SQL", selectStatment.DebugSql())
    }).Msg("SQL to get user")

    type TEST struct {
        Email        string  `json:"email"`
        FirstName    *string `json:"firstName,omitempty"`
        Id           string  `json:"id"`
        LastName     *string `json:"lastName,omitempty"`
        ProviderName *string `json:"providerName,omitempty"`
    }

    var DBUser = TEST{
        Email:        "",
        FirstName:    nil,
        Id:           "",
        LastName:     nil,
        ProviderName: nil,
    }

    var DBUser2 struct {
        Email        string  `json:"email"`
        FirstName    *string `json:"firstName,omitempty"`
        Id           string  `json:"id"`
        LastName     *string `json:"lastName,omitempty"`
        ProviderName *string `json:"providerName,omitempty"`
    }

    // Use reflection to inspect the fields of DBUser
    val := reflect.ValueOf(DBUser)
    for i := 0; i < val.NumField(); i++ {
        field := val.Type().Field(i)
        value := val.Field(i).Interface()
        logger.Debug().Str("Field", field.Name).Interface("Value", value).Interface("Tag", field.Tag).Msg("DBUser field value")
    }

    // Use reflection to inspect the fields of DBUser2
    val = reflect.ValueOf(DBUser2)
    for i := 0; i < val.NumField(); i++ {
        field := val.Type().Field(i)
        value := val.Field(i).Interface()
        logger.Debug().Str("Field", field.Name).Interface("Value", value).Interface("Tag", field.Tag).Msg("DBUser2 field value")
    }

    err = selectStatment.Query(database.DB, &DBUser)
    if err != nil {
        return fmt.Errorf("Error querying database: %w", err)
    }

    err = selectStatment.Query(database.DB, &DBUser2)
    if err != nil {
        return fmt.Errorf("Error querying database: %w", err)
    }

    logger.Debug().Interface("DBUser", DBUser).Msg("Retrieved user from database")
    logger.Debug().Interface("DBUser2", DBUser2).Msg("Retrieved user from database")

    return c.JSON(200, map[string]any{
        "DBUser":  DBUser,
        "DBUser2": DBUser2,
    })
}

有人会认为这里的输出是两个相同的对象,但实际上输出是:

{
  DBUser: { email: '', id: '' },
  DBUser2: {
    email: '[email protected]',
    firstName: 'Naphat',
    id: '123123123',
    lastName: 'Amundsen',
    providerName: 'google'
  }
}

go-jet 的文档指出:“查询使用反射来内省目标类型结构和结果集列名称(别名),为结果集列找到适当的目标字段”

所以我使用反射仔细检查了结构,它们看起来相同:

2024-09-14T17:43:25+02:00 [DEBUG] DBUser field value Field=Email Tag="json:\"email\"" Value= requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser field value Field=FirstName Tag="json:\"firstName,omitempty\"" Value=null requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser field value Field=Id Tag="json:\"id\"" Value= requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser field value Field=LastName Tag="json:\"lastName,omitempty\"" Value=null requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser field value Field=ProviderName Tag="json:\"providerName,omitempty\"" Value=null requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser2 field value Field=Email Tag="json:\"email\"" Value= requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser2 field value Field=FirstName Tag="json:\"firstName,omitempty\"" Value=null requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser2 field value Field=Id Tag="json:\"id\"" Value= requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser2 field value Field=LastName Tag="json:\"lastName,omitempty\"" Value=null requestId=1726328605558-tVF-
2024-09-14T17:43:25+02:00 [DEBUG] DBUser2 field value Field=ProviderName Tag="json:\"providerName,omitempty\"" Value=null requestId=1726328605558-tVF-

如果我将 DBUser 设置为匿名结构,则一切正常

这可能是什么原因造成的? go-jets 文档中有具体的例子,作者使用命名结构就很好。

环境信息:

  • Golang:Go版本go1.23.1 darwin/arm64
  • 操作系统:MacOS 索诺玛 14.6.1
  • 数据库:Postgres 16 16.4
  • 驱动程序:github.com/lib/pg v1.10.9
  • go-jet:v2.11.1
postgresql go reflection go-jet
1个回答
0
投票

这真是令人尴尬;所以这实际上包含在 go-jet 的常见问题解答中:https://github.com/go-jet/jet/wiki/FAQ#scan-stopped-working-after-naming-a-destination-type

基本上,必须“定位”SQL 名称中的结构名称,也就是说,在我的事业中我必须这样做

selectStatment := Users.SELECT(
        Users.FirstName.AS("test.firstName"),
        Users.LastName.AS("test.lastName"),
        Users.Email.AS("test.email"),
        Users.ID.AS("test.id"),
        Users.ProviderName.AS("test.providerName"),
    ).WHERE(
        Users.ID.EQ(String(userId)),
    )
© www.soinside.com 2019 - 2024. All rights reserved.