将仓储层/基础设施改为 Ent + 原生 SQL 执行路径,并移除 AutoMigrate 与 GORM 依赖。 重构内容包括: - 仓储层改用 Ent/SQL(含 usage_log/account 等复杂查询),统一错误映射 - 基础设施与 setup 初始化切换为 Ent + SQL migrations - 集成测试与 fixtures 迁移到 Ent 事务模型 - 清理遗留 GORM 模型/依赖,补充迁移与文档说明 - 增加根目录 Makefile 便于前后端编译 测试: - go test -tags unit ./... - go test -tags integration ./...
66 lines
2.5 KiB
Go
66 lines
2.5 KiB
Go
// Package infrastructure 提供应用程序的基础设施层组件。
|
||
// 包括数据库连接初始化、ORM 客户端管理、Redis 连接、数据库迁移等核心功能。
|
||
package infrastructure
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
|
||
"github.com/Wei-Shaw/sub2api/ent"
|
||
"github.com/Wei-Shaw/sub2api/internal/config"
|
||
"github.com/Wei-Shaw/sub2api/internal/pkg/timezone"
|
||
"github.com/Wei-Shaw/sub2api/migrations"
|
||
|
||
"entgo.io/ent/dialect"
|
||
entsql "entgo.io/ent/dialect/sql"
|
||
_ "github.com/lib/pq" // PostgreSQL 驱动,通过副作用导入注册驱动
|
||
)
|
||
|
||
// InitEnt 初始化 Ent ORM 客户端并返回客户端实例和底层的 *sql.DB。
|
||
//
|
||
// 该函数执行以下操作:
|
||
// 1. 初始化全局时区设置,确保时间处理一致性
|
||
// 2. 建立 PostgreSQL 数据库连接
|
||
// 3. 自动执行数据库迁移,确保 schema 与代码同步
|
||
// 4. 创建并返回 Ent 客户端实例
|
||
//
|
||
// 重要提示:调用者必须负责关闭返回的 ent.Client(关闭时会自动关闭底层的 driver/db)。
|
||
//
|
||
// 参数:
|
||
// - cfg: 应用程序配置,包含数据库连接信息和时区设置
|
||
//
|
||
// 返回:
|
||
// - *ent.Client: Ent ORM 客户端,用于执行数据库操作
|
||
// - *sql.DB: 底层的 SQL 数据库连接,可用于直接执行原生 SQL
|
||
// - error: 初始化过程中的错误
|
||
func InitEnt(cfg *config.Config) (*ent.Client, *sql.DB, error) {
|
||
// 优先初始化时区设置,确保所有时间操作使用统一的时区。
|
||
// 这对于跨时区部署和日志时间戳的一致性至关重要。
|
||
if err := timezone.Init(cfg.Timezone); err != nil {
|
||
return nil, nil, err
|
||
}
|
||
|
||
// 构建包含时区信息的数据库连接字符串 (DSN)。
|
||
// 时区信息会传递给 PostgreSQL,确保数据库层面的时间处理正确。
|
||
dsn := cfg.Database.DSNWithTimezone(cfg.Timezone)
|
||
|
||
// 使用 Ent 的 SQL 驱动打开 PostgreSQL 连接。
|
||
// dialect.Postgres 指定使用 PostgreSQL 方言进行 SQL 生成。
|
||
drv, err := entsql.Open(dialect.Postgres, dsn)
|
||
if err != nil {
|
||
return nil, nil, err
|
||
}
|
||
|
||
// 确保数据库 schema 已准备就绪。
|
||
// SQL 迁移文件是 schema 的权威来源(source of truth)。
|
||
// 这种方式比 Ent 的自动迁移更可控,支持复杂的迁移场景。
|
||
if err := applyMigrationsFS(context.Background(), drv.DB(), migrations.FS); err != nil {
|
||
_ = drv.Close() // 迁移失败时关闭驱动,避免资源泄露
|
||
return nil, nil, err
|
||
}
|
||
|
||
// 创建 Ent 客户端,绑定到已配置的数据库驱动。
|
||
client := ent.NewClient(ent.Driver(drv))
|
||
return client, drv.DB(), nil
|
||
}
|