sqlite

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package sqlite implements the persistence port interfaces using an embedded SQLite database via zombiezen.com/go/sqlite (pure Go, no CGO). It provides database discovery (walking up from cwd to find .np/), schema management, and all CRUD operations with transactional guarantees.

The Store uses a connection pool (sqlitex.Pool) with per-connection pragma setup for WAL mode, foreign keys, and a busy timeout. Write transactions use BEGIN IMMEDIATE so that lock contention is detected — and retried via the busy handler — at BEGIN rather than mid-transaction.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DiscoverDatabase

func DiscoverDatabase(startDir string) (string, error)

DiscoverDatabase walks up from startDir looking for a .np/ directory. Returns the full path to the database file, or an error if not found.

Permission and sandbox errors are silently ignored per §3.3 — if a directory cannot be read, it is skipped.

func InitDatabaseDir

func InitDatabaseDir(baseDir string) (string, error)

InitDatabaseDir creates the .np/ directory and returns the database path.

func LookupDatabase

func LookupDatabase(dir string) (string, error)

LookupDatabase checks a single directory for a .np/ workspace without walking up to parent directories. Returns the full path to the database file, or an error if the directory does not contain an np workspace. Use this when the caller has specified an explicit workspace directory.

Types

type Store

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

Store provides SQLite-backed persistence for the nitpicking domain.

func Create

func Create(dbPath string) (*Store, error)

Create creates a new SQLite database at dbPath and applies the schema. Intended to be called once during database initialisation ("np init"). Subsequent access should use Open, which skips DDL.

func Open

func Open(dbPath string) (*Store, error)

Open opens an existing SQLite database at dbPath. It does not apply schema DDL — the database must already have been created with Create.

func (*Store) CheckSchemaVersion added in v0.2.0

func (s *Store) CheckSchemaVersion(ctx context.Context) error

CheckSchemaVersion opens a read transaction, fetches the schema version, and returns domain.ErrSchemaMigrationRequired (wrapped in a DatabaseError) when the version is below 3 (the current version). Callers — typically root-command startup hooks — use this to gate all database-touching commands on a fully migrated database.

func (*Store) Close

func (s *Store) Close() error

Close releases all pooled connections.

func (*Store) MigrateV1ToV2 added in v0.2.0

func (s *Store) MigrateV1ToV2(ctx context.Context) (driven.MigrationResult, error)

MigrateV1ToV2 upgrades a v1 database to v2 schema in a single atomic transaction, satisfying the driven.Migrator interface. It is safe to call on a v2 database — CheckSchemaVersion should be called first so that callers can report "up to date" without executing the migration body.

The migration performs four steps within one IMMEDIATE transaction:

  1. Updates every issue with state="claimed" to state="open", so that the primary state column contains only lifecycle states. The active claims are already stored in the claims table and remain untouched.
  2. Deletes history rows whose event_type is "claimed" or "released" — these event types were removed in v2; the claims table replaces them.
  3. Translates legacy v0.2.0 relationship types: renames "cites" rows to "refs" (same semantics) and deletes "cited_by" rows (redundant because "refs" is symmetric-by-inverse). This ensures on-disk databases upgraded from v0.2.0 do not contain rel_type values disallowed by the narrowed CHECK constraint on newly-created v0.3.0 databases.
  4. Sets schema_version=2 in the metadata table via SetSchemaVersion, marking the migration as complete.

If any step fails the transaction is rolled back and the database is unchanged. Returns a driven.MigrationResult with the number of rows affected by each step.

func (*Store) MigrateV2ToV3 added in v0.3.0

func (s *Store) MigrateV2ToV3(ctx context.Context) (driven.MigrationResult, error)

MigrateV2ToV3 upgrades a v2 database to v3 schema in a single atomic transaction, satisfying the driven.Migrator interface. It is safe to call on a v3 database — CheckSchemaVersion should be called first so that callers can report "up to date" without executing the migration body.

See docs/developer/decisions/idempotency-key-migration.md for the migration-key naming rationale, collision-handling policy, and label-value validation rule.

The migration performs three steps within one IMMEDIATE transaction:

  1. For every row in issues where idempotency_key IS NOT NULL, attempts to INSERT a labels row with key="idempotency" and value=idempotency_key. - If the issue already carries an idempotency label (collision), the column value is skipped and IdempotencyKeysSkipped is incremented. - If domain.NewLabel rejects the value, the row is skipped and InvalidLabelValuesSkipped is incremented. - Otherwise IdempotencyKeysMigrated is incremented.
  2. Drops the unique partial index idx_issues_idempotency and then drops the idempotency_key column from the issues table. SQLite ≥ 3.35 supports ALTER TABLE … DROP COLUMN; the bundled zombiezen.com/go/sqlite v1.4.2 ships SQLite 3.45, so the direct DROP COLUMN path is used here.
  3. Calls uow.Database().SetSchemaVersion(ctx, 3) as the final step.

If any step fails the transaction is rolled back and the database is unchanged. Returns a driven.MigrationResult with the per-step counters.

func (*Store) Vacuum

func (s *Store) Vacuum(ctx context.Context) error

Vacuum reclaims disk space and defragments the database file. Must be called outside any transaction — takes a connection from the pool, runs VACUUM, and returns it.

func (*Store) WithReadTransaction

func (s *Store) WithReadTransaction(ctx context.Context, fn func(uow driven.UnitOfWork) error) (err error)

WithReadTransaction executes fn within a deferred (read-only) transaction.

func (*Store) WithTransaction

func (s *Store) WithTransaction(ctx context.Context, fn func(uow driven.UnitOfWork) error) (err error)

WithTransaction executes fn within an IMMEDIATE transaction. IMMEDIATE acquires a write lock at BEGIN so that busy-handler retries happen at a point where no deadlock is possible.

Jump to

Keyboard shortcuts

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