sqlstore

package
v0.0.0-...-d97833b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

Documentation

Overview

Package sqlstore is the shared SQL persistence adapter for SQLite and PostgreSQL (02).

Index

Constants

This section is empty.

Variables

View Source
var ErrAlreadyRunning = errors.New("another Liturgist process is using this data folder")

ErrAlreadyRunning means another Liturgist process holds the data folder's run lock (14 §3).

Functions

func CheckSQLiteFile

func CheckSQLiteFile(ctx context.Context, path string) (version int64, err error)

CheckSQLiteFile opens the database file at path read-only, runs SQLite's integrity and foreign-key checks, and returns its schema version. A file that is not a Liturgist database is an error.

func DiskUsage

func DiskUsage(dir string) (free, total int64, err error)

DiskUsage returns the free and the total size of the disk holding dir.

func FreeBytes

func FreeBytes(dir string) (int64, error)

FreeBytes returns the free disk space available to the program in dir.

func LockDataDir

func LockDataDir(ctx context.Context, dir string) (func(), error)

LockDataDir takes the migration lock of the data folder (waits up to 30 s).

func LockRun

func LockRun(dir string) (func(), error)

LockRun takes the run lock of the data folder, without waiting. serve holds it for its whole life; restore needs it (14 §3, H-2). The returned function releases it.

func ProgramVersion

func ProgramVersion(fsys fs.FS) (int64, error)

ProgramVersion is the newest schema version of the migrations in fsys, from the numeric prefix of the file names (00012_x.sql is 12).

func SnapshotFile

func SnapshotFile(ctx context.Context, src, dest string) error

SnapshotFile writes a consistent copy of the SQLite database src to dest (which must not exist) with VACUUM INTO. It uses a connection of its own, so it works while a server has the file open and never queues behind its writer. When the disk is full the error wraps app.ErrStorageFull.

func SnapshotSpace

func SnapshotSpace(path string) int64

SnapshotSpace is the free space a copy of the SQLite file at path needs: the database and its WAL, plus 20 %.

Types

type Config

type Config struct {
	Driver     string       // "sqlite" | "postgres"
	DataDir    string       // SQLite file lives at DataDir/liturgist.db
	URL        string       // PostgreSQL
	MaxConns   int          // PostgreSQL pool; 0 = 10
	MaxReaders int          // SQLite readers; 0 = 4
	Logger     *slog.Logger // warnings about unknown stored scopes; nil = discard
}

Config selects and sizes the database.

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB implements app.Tx.

func Open

func Open(ctx context.Context, cfg Config) (*DB, error)

Open connects to the configured database.

func (*DB) CheckVersion

func (db *DB) CheckVersion(ctx context.Context, o MigrateOptions) (current, target int64, err error)

CheckVersion returns the database and program schema versions. It fails with *SchemaNewerError when the database is ahead, unless AllowNewerSchema.

func (*DB) Close

func (db *DB) Close() error

Close closes all connections.

func (*DB) CountForTest

func (db *DB) CountForTest(ctx context.Context, table string) (int, error)

CountForTest counts the rows of a table, over all churches. Tests only.

func (*DB) Dialect

func (db *DB) Dialect() Dialect

Dialect returns the database dialect.

func (*DB) DialectName

func (db *DB) DialectName() string

DialectName is "sqlite" or "postgres"; tests use it to skip interleavings that only the second can produce.

func (*DB) ExecForTest

func (db *DB) ExecForTest(ctx context.Context, q string, args ...any) error

ExecForTest runs a statement outside any Tx. It is for tests (DDL, and states that no use case can reach yet); production code does not use it.

func (*DB) Migrate

func (db *DB) Migrate(ctx context.Context, o MigrateOptions) (MigrateResult, error)

Migrate applies pending migrations (02 §5). On SQLite it holds the lock file for the whole run and makes the pre-upgrade copy first. It never runs on a newer schema.

func (*DB) Path

func (db *DB) Path() string

Path returns the SQLite file path ("" on PostgreSQL).

func (*DB) Ping

func (db *DB) Ping(ctx context.Context) error

Ping checks the database answers.

func (*DB) Read

func (db *DB) Read(ctx context.Context, fn func(app.Store) error) error

Read runs fn in a read-only transaction.

func (*DB) SelectForTest

func (db *DB) SelectForTest(ctx context.Context, dest any, q string, args ...any) error

SelectForTest reads rows into dest (a pointer to a slice of structs with db tags) outside any Tx. Tests only.

func (*DB) SizeBytes

func (db *DB) SizeBytes(ctx context.Context) (int64, error)

SizeBytes is the size of the database: the SQLite file and its WAL, or what PostgreSQL reports for the database.

func (*DB) Write

func (db *DB) Write(ctx context.Context, fn func(app.Store) error) error

Write runs fn in a read-write transaction.

type Dialect

type Dialect interface {
	Name() string // "sqlite" | "postgres"
	Rebind(query string) string
	// MapError turns driver errors into app errors (02 §8); nil and unknown errors pass through.
	MapError(err error) error
	// Retryable reports busy, serialisation and deadlock errors (02 §2).
	Retryable(err error) bool
	LockInstall(ctx context.Context, tx *sqlx.Tx) error
	LockUser(ctx context.Context, tx *sqlx.Tx, id string) error
	LockChurch(ctx context.Context, tx *sqlx.Tx, id string) error
	SetTenant(ctx context.Context, tx *sqlx.Tx, churchID string) error // RLS hook (02 §7)
	TimeArg(t time.Time) any                                           // value to bind for a timestamp

	// Song search (06 §5): the only place the two databases differ in how
	// text is matched. Folded text contains only letters, digits and single
	// spaces, so every tokenizer splits at the same places.
	WriteSongIndex(ctx context.Context, tx *sqlx.Tx, churchID, songID, language, head, lyrics string) error // replaces the song's rows
	DeleteSongIndex(ctx context.Context, tx *sqlx.Tx, churchID, songID string) error
	DeleteChurchIndex(ctx context.Context, tx *sqlx.Tx, churchID string) error
	// TermMatch is the predicate "some token of the head (headOnly) or of head or
	// lyrics starts with term" for the song_search row aliased ss.
	TermMatch(term string, headOnly bool) (sql string, args []any)
	// Contains is the predicate "col contains the bound value" (Chinese substring search).
	Contains(col string) string
	// OrderBytes orders a text column bytewise, so both databases sort alike.
	OrderBytes(col string) string
}

Dialect holds every database difference (decisions log: one adapter, small dialect layer).

type MigrateOptions

type MigrateOptions struct {
	FS               fs.FS // migrations for this dialect
	AllowNewerSchema bool  // only skips the refusal to start (02 §5.1)
	RequireCopy      bool  // LITURGIST_REQUIRE_PREUPGRADE_COPY
	Logger           *slog.Logger
	Now              func() time.Time
}

MigrateOptions configures CheckVersion and Migrate.

type MigrateResult

type MigrateResult struct {
	From, To int64
	CopyPath string // "" when no copy was made
}

MigrateResult reports what Migrate did.

type NullTime

type NullTime struct {
	Time  time.Time
	Valid bool
}

NullTime is a Time that may be NULL.

func (*NullTime) Scan

func (n *NullTime) Scan(src any) error

Scan implements sql.Scanner.

type SchemaNewerError

type SchemaNewerError struct{ DB, Program int64 }

SchemaNewerError means the database was migrated by a newer program (exit code 3).

func (*SchemaNewerError) Error

func (e *SchemaNewerError) Error() string

type Time

type Time struct{ time.Time }

Time scans timestamps from either dialect: SQLite returns fixed-format text, PostgreSQL returns time.Time. Values are always UTC (02 §4). Bind timestamps with Dialect.TimeArg, never directly.

func (*Time) Scan

func (t *Time) Scan(src any) error

Scan implements sql.Scanner.

Directories

Path Synopsis
Package sqlstoretest provides migrated databases for tests (02 §6).
Package sqlstoretest provides migrated databases for tests (02 §6).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL