mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-07-06 22:33:19 -04:00
Import Package and Version types from the git-pkgs database package instead of defining them locally. Both projects now share the same type definitions, keeping the packages and versions tables in sync. Delegate SQLite connection setup to the shared Open function so pragma settings (WAL, busy timeout, connection limit) stay aligned.
146 lines
2.8 KiB
Go
146 lines
2.8 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
gitpkgsdb "github.com/git-pkgs/git-pkgs/database"
|
|
"github.com/jmoiron/sqlx"
|
|
_ "github.com/lib/pq"
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
const SchemaVersion = 1
|
|
|
|
type Dialect string
|
|
|
|
const (
|
|
DialectSQLite Dialect = "sqlite"
|
|
DialectPostgres Dialect = "postgres"
|
|
)
|
|
|
|
type DB struct {
|
|
*sqlx.DB
|
|
dialect Dialect
|
|
path string
|
|
}
|
|
|
|
func (db *DB) Dialect() Dialect {
|
|
return db.dialect
|
|
}
|
|
|
|
// Exists checks if a database file exists at the given path.
|
|
var Exists = gitpkgsdb.Exists
|
|
|
|
func Create(path string) (*DB, error) {
|
|
if Exists(path) {
|
|
if err := os.Remove(path); err != nil {
|
|
return nil, fmt.Errorf("removing existing database: %w", err)
|
|
}
|
|
}
|
|
|
|
db, err := Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := db.CreateSchema(); err != nil {
|
|
_ = db.Close()
|
|
return nil, fmt.Errorf("creating schema: %w", err)
|
|
}
|
|
|
|
return db, nil
|
|
}
|
|
|
|
// Open opens a SQLite database using the shared git-pkgs connection
|
|
// settings (WAL mode, busy timeout, single connection).
|
|
func Open(path string) (*DB, error) {
|
|
if dir := filepath.Dir(path); dir != "." && dir != "/" {
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return nil, fmt.Errorf("creating database directory: %w", err)
|
|
}
|
|
}
|
|
|
|
sharedDB, err := gitpkgsdb.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &DB{DB: sharedDB.SQLX(), dialect: DialectSQLite, path: path}, nil
|
|
}
|
|
|
|
func OpenOrCreate(path string) (*DB, error) {
|
|
if Exists(path) {
|
|
return Open(path)
|
|
}
|
|
return Create(path)
|
|
}
|
|
|
|
func OpenPostgres(url string) (*DB, error) {
|
|
sqlDB, err := sqlx.Open("postgres", url)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("opening postgres database: %w", err)
|
|
}
|
|
|
|
if err := sqlDB.Ping(); err != nil {
|
|
_ = sqlDB.Close()
|
|
return nil, fmt.Errorf("connecting to postgres: %w", err)
|
|
}
|
|
|
|
return &DB{DB: sqlDB, dialect: DialectPostgres}, nil
|
|
}
|
|
|
|
func OpenPostgresOrCreate(url string) (*DB, error) {
|
|
db, err := OpenPostgres(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var exists bool
|
|
err = db.Get(&exists, "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'schema_info')")
|
|
if err != nil {
|
|
_ = db.Close()
|
|
return nil, fmt.Errorf("checking schema: %w", err)
|
|
}
|
|
|
|
if !exists {
|
|
if err := db.CreateSchema(); err != nil {
|
|
_ = db.Close()
|
|
return nil, fmt.Errorf("creating schema: %w", err)
|
|
}
|
|
}
|
|
|
|
return db, nil
|
|
}
|
|
|
|
func (db *DB) OptimizeForBulkWrites() error {
|
|
if db.dialect == DialectPostgres {
|
|
return nil
|
|
}
|
|
_, err := db.Exec(`
|
|
PRAGMA synchronous = OFF;
|
|
PRAGMA journal_mode = WAL;
|
|
PRAGMA cache_size = -64000;
|
|
`)
|
|
return err
|
|
}
|
|
|
|
func (db *DB) OptimizeForReads() error {
|
|
if db.dialect == DialectPostgres {
|
|
return nil
|
|
}
|
|
_, err := db.Exec(`
|
|
PRAGMA synchronous = NORMAL;
|
|
PRAGMA journal_mode = WAL;
|
|
`)
|
|
return err
|
|
}
|
|
|
|
func (db *DB) Path() string {
|
|
return db.path
|
|
}
|
|
|
|
func (db *DB) Rebind(query string) string {
|
|
return db.DB.Rebind(query)
|
|
}
|