/
githubmirror
/
sqlc
Обзор
Документация
Войти
/
githubmirror
/
sqlc
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
internal/dbmanager/client.go
150 строк
3 KB
Scott Tsai
fix(dbmanager): use correct SQL to drop databases (#3640)
09 окт 2024, 21:26
Не верифицирован
09 окт 2024, 21:26
695d9a1
Код
Авторство
О чём код?
package dbmanager import ( "context" "fmt" "hash/fnv" "io" "net/url" "strings" "github.com/jackc/pgx/v5" "golang.org/x/sync/singleflight" "github.com/sqlc-dev/sqlc/internal/config" "github.com/sqlc-dev/sqlc/internal/pgx/poolcache" "github.com/sqlc-dev/sqlc/internal/shfmt" ) type CreateDatabaseRequest struct { Engine string Migrations []string Prefix string } type CreateDatabaseResponse struct { Uri string } type Client interface { CreateDatabase(context.Context, *CreateDatabaseRequest) (*CreateDatabaseResponse, error) Close(context.Context) } var flight singleflight.Group type ManagedClient struct { cache *poolcache.Cache replacer *shfmt.Replacer servers []config.Server } func dbid(migrations []string) string { h := fnv.New64() for _, query := range migrations { io.WriteString(h, query) } return fmt.Sprintf("%x", h.Sum(nil)) } func (m *ManagedClient) CreateDatabase(ctx context.Context, req *CreateDatabaseRequest) (*CreateDatabaseResponse, error) { hash := dbid(req.Migrations) prefix := req.Prefix if prefix == "" { prefix = "sqlc_managed" } name := fmt.Sprintf("%s_%s", prefix, hash) engine := config.Engine(req.Engine) switch engine { case config.EngineMySQL: // pass case config.EnginePostgreSQL: // pass default: return nil, fmt.Errorf("unsupported engine: %s", engine) } var base string for _, server := range m.servers { if server.Engine == engine { base = server.URI break } } if strings.TrimSpace(base) == "" { return nil, fmt.Errorf("no PostgreSQL database server found") } serverUri := m.replacer.Replace(base) pool, err := m.cache.Open(ctx, serverUri) if err != nil { return nil, err } uri, err := url.Parse(serverUri) if err != nil { return nil, err } uri.Path = "/" + name key := uri.String() _, err, _ = flight.Do(key, func() (interface{}, error) { // TODO: Use a parameterized query row := pool.QueryRow(ctx, fmt.Sprintf(`SELECT datname FROM pg_database WHERE datname = '%s'`, name)) var datname string if err := row.Scan(&datname); err == nil { return nil, nil } if _, err := pool.Exec(ctx, fmt.Sprintf(`CREATE DATABASE "%s"`, name)); err != nil { return nil, err } conn, err := pgx.Connect(ctx, uri.String()) if err != nil { pool.Exec(ctx, fmt.Sprintf(`DROP DATABASE IF EXISTS "%s" WITH (FORCE)`, name)) return nil, fmt.Errorf("connect %s: %s", name, err) } defer conn.Close(ctx) var migrationErr error for _, q := range req.Migrations { if len(strings.TrimSpace(q)) == 0 { continue } if _, err := conn.Exec(ctx, q); err != nil { migrationErr = fmt.Errorf("%s: %s", q, err) break } } if migrationErr != nil { pool.Exec(ctx, fmt.Sprintf(`DROP DATABASE IF EXISTS "%s" WITH (FORCE)`, name)) return nil, migrationErr } return nil, nil }) if err != nil { return nil, err } return &CreateDatabaseResponse{Uri: key}, err } func (m *ManagedClient) Close(ctx context.Context) { m.cache.Close() } func NewClient(servers []config.Server) *ManagedClient { return &ManagedClient{ cache: poolcache.New(), servers: servers, replacer: shfmt.NewReplacer(nil), } }