package crud import ( "database/sql" "fmt" "sync" "aijianzhan/platform/internal/meta" "aijianzhan/platform/internal/schema" ) // DBPool 按 database_per_app 缓存连接。 type DBPool struct { mu sync.Mutex baseDSN string primary *sql.DB dbs map[string]*sql.DB } func NewDBPool(defaultDB *sql.DB, baseDSN string) *DBPool { return &DBPool{primary: defaultDB, baseDSN: baseDSN, dbs: map[string]*sql.DB{}} } func (p *DBPool) ForApp(app *meta.AppRecord) (*sql.DB, error) { if p == nil { return nil, fmt.Errorf("db pool nil") } if app == nil || app.DatabaseName == "" { return p.primary, nil } p.mu.Lock() defer p.mu.Unlock() if db, ok := p.dbs[app.DatabaseName]; ok { return db, nil } dsn, err := schema.DSNForDatabase(p.baseDSN, app.DatabaseName) if err != nil { return nil, err } db, err := sql.Open("postgres", dsn) if err != nil { return nil, err } if err := db.Ping(); err != nil { _ = db.Close() return nil, fmt.Errorf("ping app db %s: %w", app.DatabaseName, err) } p.dbs[app.DatabaseName] = db return db, nil }