mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-24 08:42:12 +01:00
Find and replace all nolint instances refering to the `lll` linter and replace with `ll` which is the name of our custom version of the `lll` linter which can be used to ignore log lines during linting. The next commit will do the configuration of the custom linter and disable the default one.
151 lines
4.0 KiB
Go
151 lines
4.0 KiB
Go
package sqldb
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"net/url"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
pgx_migrate "github.com/golang-migrate/migrate/v4/database/pgx/v5"
|
|
_ "github.com/golang-migrate/migrate/v4/source/file" // Read migrations from files. // nolint:ll
|
|
_ "github.com/jackc/pgx/v5"
|
|
"github.com/lightningnetwork/lnd/sqldb/sqlc"
|
|
)
|
|
|
|
var (
|
|
// DefaultPostgresFixtureLifetime is the default maximum time a Postgres
|
|
// test fixture is being kept alive. After that time the docker
|
|
// container will be terminated forcefully, even if the tests aren't
|
|
// fully executed yet. So this time needs to be chosen correctly to be
|
|
// longer than the longest expected individual test run time.
|
|
DefaultPostgresFixtureLifetime = 10 * time.Minute
|
|
|
|
// postgresSchemaReplacements is a map of schema strings that need to be
|
|
// replaced for postgres. This is needed because we write the schemas to
|
|
// work with sqlite primarily but in sqlc's own dialect, and postgres
|
|
// has some differences.
|
|
postgresSchemaReplacements = map[string]string{
|
|
"BLOB": "BYTEA",
|
|
"INTEGER PRIMARY KEY": "SERIAL PRIMARY KEY",
|
|
"BIGINT PRIMARY KEY": "BIGSERIAL PRIMARY KEY",
|
|
"TIMESTAMP": "TIMESTAMP WITHOUT TIME ZONE",
|
|
}
|
|
)
|
|
|
|
// replacePasswordInDSN takes a DSN string and returns it with the password
|
|
// replaced by "***".
|
|
func replacePasswordInDSN(dsn string) (string, error) {
|
|
// Parse the DSN as a URL
|
|
u, err := url.Parse(dsn)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Check if the URL has a user info part
|
|
if u.User != nil {
|
|
username := u.User.Username()
|
|
|
|
// Reconstruct user info with "***" as password
|
|
userInfo := username + ":***@"
|
|
|
|
// Rebuild the DSN with the modified user info
|
|
sanitizeDSN := strings.Replace(
|
|
dsn, u.User.String()+"@", userInfo, 1,
|
|
)
|
|
|
|
return sanitizeDSN, nil
|
|
}
|
|
|
|
// Return the original DSN if no user info is present
|
|
return dsn, nil
|
|
}
|
|
|
|
// getDatabaseNameFromDSN extracts the database name from a DSN string.
|
|
func getDatabaseNameFromDSN(dsn string) (string, error) {
|
|
// Parse the DSN as a URL
|
|
u, err := url.Parse(dsn)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// The database name is the last segment of the path. Trim leading slash
|
|
// and return the last segment.
|
|
return path.Base(u.Path), nil
|
|
}
|
|
|
|
// PostgresStore is a database store implementation that uses a Postgres
|
|
// backend.
|
|
type PostgresStore struct {
|
|
cfg *PostgresConfig
|
|
|
|
*BaseDB
|
|
}
|
|
|
|
// NewPostgresStore creates a new store that is backed by a Postgres database
|
|
// backend.
|
|
func NewPostgresStore(cfg *PostgresConfig) (*PostgresStore, error) {
|
|
sanitizedDSN, err := replacePasswordInDSN(cfg.Dsn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
log.Infof("Using SQL database '%s'", sanitizedDSN)
|
|
|
|
rawDB, err := sql.Open("pgx", cfg.Dsn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
maxConns := defaultMaxConns
|
|
if cfg.MaxConnections > 0 {
|
|
maxConns = cfg.MaxConnections
|
|
}
|
|
|
|
rawDB.SetMaxOpenConns(maxConns)
|
|
rawDB.SetMaxIdleConns(maxConns)
|
|
rawDB.SetConnMaxLifetime(connIdleLifetime)
|
|
|
|
queries := sqlc.New(rawDB)
|
|
|
|
s := &PostgresStore{
|
|
cfg: cfg,
|
|
BaseDB: &BaseDB{
|
|
DB: rawDB,
|
|
Queries: queries,
|
|
},
|
|
}
|
|
|
|
// Execute migrations unless configured to skip them.
|
|
if !cfg.SkipMigrations {
|
|
err := s.ExecuteMigrations(TargetLatest)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error executing migrations: %w",
|
|
err)
|
|
}
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
// ExecuteMigrations runs migrations for the Postgres database, depending on the
|
|
// target given, either all migrations or up to a given version.
|
|
func (s *PostgresStore) ExecuteMigrations(target MigrationTarget) error {
|
|
dbName, err := getDatabaseNameFromDSN(s.cfg.Dsn)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
driver, err := pgx_migrate.WithInstance(s.DB, &pgx_migrate.Config{})
|
|
if err != nil {
|
|
return fmt.Errorf("error creating postgres migration: %w", err)
|
|
}
|
|
|
|
// Populate the database with our set of schemas based on our embedded
|
|
// in-memory file system.
|
|
postgresFS := newReplacerFS(sqlSchemas, postgresSchemaReplacements)
|
|
return applyMigrations(
|
|
postgresFS, driver, "sqlc/migrations", dbName, target,
|
|
)
|
|
}
|