- 前端: 所有界面显示、i18n 文本、组件中的品牌名称 - 后端: 服务层、设置默认值、邮件模板、安装向导 - 数据库: 迁移脚本注释 - 保持功能完全一致,仅更改品牌名称 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
43 lines
1.1 KiB
Go
43 lines
1.1 KiB
Go
package repository
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"errors"
|
||
)
|
||
|
||
type sqlQueryer interface {
|
||
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
|
||
}
|
||
|
||
// scanSingleRow 执行查询并扫描第一行到 dest。
|
||
// 若无结果,可通过 errors.Is(err, sql.ErrNoRows) 判断。
|
||
// 如果 Close 失败,会与原始错误合并返回。
|
||
// 设计目的:仅依赖 QueryContext,避免 QueryRowContext 对 *sql.Tx 的强绑定,
|
||
// 让 ent.Tx 也能作为 sqlExecutor/Queryer 使用。
|
||
func scanSingleRow(ctx context.Context, q sqlQueryer, query string, args []any, dest ...any) (err error) {
|
||
rows, err := q.QueryContext(ctx, query, args...)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer func() {
|
||
if closeErr := rows.Close(); closeErr != nil {
|
||
err = errors.Join(err, closeErr)
|
||
}
|
||
}()
|
||
|
||
if !rows.Next() {
|
||
if err = rows.Err(); err != nil {
|
||
return err
|
||
}
|
||
return sql.ErrNoRows
|
||
}
|
||
if err = rows.Scan(dest...); err != nil {
|
||
return err
|
||
}
|
||
if err = rows.Err(); err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|