if category == 0 {
rows, err := h.Repo.GetAllLatestProducts(c.Context())
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
result := make([]interface{}, len(rows))
for i, product := range rows {
result[i] = dbrow.ConvertToAllLatestProducts(product)
}
} else {
rows, err := h.Repo.GetLatestProductsByCategory(c.Context(), int16(category))
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
result := make([]interface{}, len(rows))
for i, product := range rows {
result[i] = dbrow.ConvertToCategoryLatestProducts(product)
}
}
if和else条件都遵循相同的代码流程,只是functions和struct不同,如何合并,让代码更小。我的意思是:
var rows []postgres.GetAllLatestProductsRow
var rows []postgres.GetLatestProductsByCategoryRow
if category == 0 {
rows, err = h.Repo.GetAllLatestProducts(c.Context())
} else {
rows, err = h.Repo.GetLatestProductsByCategory(c.Context(), int16(category))
}
//Rest of the code ...
不能触摸 h.Repo.GetAllLatestProducts 或 h.Repo.GetLatestProductsByCategory 因为它们是外部函数。类型安全也很重要。
可以有多个功能,如特色产品,新产品,我想制作一个通用函数,根据动态选择的 sql 函数将产品返回为 json。
您遇到了问题,具有相同代码结构的数十个函数很糟糕,至少对我而言,它的可读性与否无关紧要,它只是重复的复制/粘贴,没有任何意义,主要是仅使用函数名称进行复制/粘贴/SQLC 生成函数名和结构名变化,其余代码流程相同。
SQLC 根据 SQL 查询生成自动代码,现在编写重复代码只是将结果转换为 JSON 并将其返回给客户端是浪费时间。可能有几十个 SQL 函数来返回最新产品、特色产品、类别中的产品、愿望清单产品、等等等等。
所有网站都了解产品结构,但 SQLC 返回不同的结构,因此没有单一的 dbResult 类型的东西。无论如何映射不是什么大事,使用反射我们可以在映射函数中检查具有相同名称的字段,并将 SQL.NullString 转换为字符串等。
真正的问题是我的 if/else 语句。您已经在不同的函数中移动了代码,但对我来说,在这种情况下它没有意义。因为web handler无论如何都要检查请求是否有效,是否定义了category,然后检查category是否为0,然后调用不同的函数,然后得到结果并返回给客户端。对于单个函数,它可能看起来更好,但对于实际生产,它会让事情变得更糟,而不是单个函数和 if/else 块,现在每个 API 都有 3 个函数。
我正在寻找它只是将 SQLC 结果映射到路由处理程序。代码流程始终相同,只是函数名称和结构名称发生变化。如何使其动态化,以便在我的 http 处理程序中,我可以简单地编写:
return SQLCResult(c.Query("category"), GetAllFeaturedProducts, GetFeaturedProductsByCategory)
然后根据 c.Query("category") 中的类别值,SQLCResult 将自动调用 GetAllFeaturedProducts 或 GetFeaturedProductsByCategory。类似于函数作为回调的东西,但函数签名不同,这是一个问题。
func (q *Queries) GetAllFeaturedProducts(ctx context.Context) ([]GetAllFeaturedProductsRow, error)
func (q *Queries) GetFeaturedProductsByCategory(ctx context.Context, idCategory int16)
映射函数不是必需的,因为在 SQLCResult 中,我们可以执行以下操作:
MapDBStructToRestAPIStruct(&Product{}, &row, MapFields(&row))
这将创建字段名称和索引的映射,并传递 dbresult 行,它将使用反射将其转换为 Product 结构并返回相同的内容,即在修改其字段后返回第一个参数作为结果。
我仍在寻找如何编写 SQLCResult 函数,将 SQLC 函数名称作为输入,然后返回结果,或者可以通过将 Product{} 结构本身放在 SQLCResult 函数中来使其更通用,例如:
var result := SQLCResult(&Product{}, c.Query("category") == 0, GetAllFeaturedProducts, GetFeaturedProductsByCategory)
return c.Status(fiber.StatusOK).JSON(result)
SQLCResult 将根据布尔条件调用 GetAllFeaturedProducts 或 GetFeaturedProductsByCategory,并将函数结果映射到作为第一个参数传递的结构,然后返回该结构。
或者可能是这样的最终目标:
func (h *Handlers) GetLatestProducts(c *fiber.Ctx) error {
if c.Query("category") == 0
return c.JSON(SQLCResult(&Product{}, GetAllLatestProducts)
else
return c.JSON(SQLCResult(&Product{}, GetLatestProductsByCategory, c.Query("category"))
}
func (h *Handlers) GetFeaturedProducts(c *fiber.Ctx) error {
if c.Query("category") == 0
return c.JSON(SQLCResult(&Product{}, GetAllFeaturedProducts)
else
return c.JSON(SQLCResult(&Product{}, GetFeaturedProductsByCategory, c.Query("category"))
}