sqlite

package
v0.0.0-...-c848cff Latest Latest
Warning

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

Go to latest
Published: Nov 5, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package sqlite implements store.Store on SQLite through Grove.

Open the database with DSN so every pooled connection gets a busy timeout and immediate transactions, then hand the grove.DB to New.

Index

Constants

View Source
const BusyTimeout = 5 * time.Second

BusyTimeout is how long a connection opened with DSN waits for another connection's write lock before it gives up with SQLITE_BUSY.

Variables

View Source
var Migrations = migrate.NewGroup("tether")

Migrations is the grove migration group for the Tether store (SQLite). Store.Migrate runs it through grove's orchestrator, and a host that runs its migrations centrally (the grove extension's WithMigrations, or the shared MigrationRegistry) can hand it the group instead.

Each migration lives in its own file named <version>_<name>.go and joins the group with Migrations.Add, which reads the version and the name from that file name. Never rename one of those files: the orchestrator knows a migration by its group and version, and a database that already recorded 20261022000001 must find it under that version again.

Timestamps are INTEGER unix microseconds, not TEXT. modernc.org/sqlite writes a time.Time as a formatted string whose layout depends on the DSN, and ordering and equality on text only work while every writer agrees on that layout. An integer sorts and compares the same way whatever the DSN.

There is deliberately no foreign key from tether_devices to tether_tenants: the store contract says CreateDevice does not check the tenant and DeleteTenant does not cascade, and the service layer enforces both.

The SQL drivers have no schema builders yet, so the migrations are raw SQL through db.Exec.

Functions

func DSN

func DSN(path string) string

DSN returns the data source name to open the database at path with, for sqlitedriver.SqliteDB.Open. Open the database you hand to New with it:

sdb := sqlitedriver.New()
err := sdb.Open(ctx, sqlite.DSN("tether.db"))

database/sql pools connections and every pooled connection has its own settings, so the DSN is the one place that reaches all of them. Grove's driver runs PRAGMA foreign_keys=ON once at Open, on whichever connection it gets, and sets no busy timeout. DSN adds three settings, applied by modernc.org/sqlite to each connection it opens:

  • busy_timeout: a write waits up to BusyTimeout for the write lock instead of failing at once with SQLITE_BUSY. Device and tenant writes arrive from connection handlers and the admin API at the same time.
  • foreign_keys: on for every connection. Tether's tables declare no foreign keys, so this only matters to tables a host adds beside them.
  • _txlock=immediate: transactions take the write lock at BEGIN. SQLite skips the busy timeout when a transaction that has already read tries to write, and fails at once.

path is a file name or a file: URI. Query parameters already on it are kept, and so is any of the three settings it already sets: the caller's _txlock, busy_timeout or foreign_keys wins, and DSN adds only the ones that are missing. If you open the database some other way, such as from a grove extension's config, put the same three parameters on that DSN.

Types

type Store

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

Store is a SQLite-backed store.Store. It is safe for concurrent use.

func New

func New(db *grove.DB) *Store

New returns a Store on db, which must be opened with the sqlitedriver. Call Migrate before first use.

func (*Store) Close

func (s *Store) Close() error

Close closes the database.

func (*Store) CountDevices

func (s *Store) CountDevices(ctx context.Context, tenantID id.TenantID) (int, error)

CountDevices implements device.Store.

func (*Store) CreateDevice

func (s *Store) CreateDevice(ctx context.Context, d *device.Device) error

CreateDevice implements device.Store.

func (*Store) CreateTenant

func (s *Store) CreateTenant(ctx context.Context, t *tenant.Tenant) error

CreateTenant implements tenant.Store.

func (*Store) DB

func (s *Store) DB() *grove.DB

DB returns the underlying grove database.

func (*Store) DeleteDevice

func (s *Store) DeleteDevice(ctx context.Context, tenantID id.TenantID, deviceID id.DeviceID) error

DeleteDevice implements device.Store.

func (*Store) DeleteTenant

func (s *Store) DeleteTenant(ctx context.Context, tenantID id.TenantID) error

DeleteTenant implements tenant.Store. It does not cascade to devices.

func (*Store) GetDevice

func (s *Store) GetDevice(ctx context.Context, tenantID id.TenantID, deviceID id.DeviceID) (*device.Device, error)

GetDevice implements device.Store.

func (*Store) GetDeviceByKey

func (s *Store) GetDeviceByKey(ctx context.Context, keyID string) (*device.Device, error)

GetDeviceByKey implements device.Store.

func (*Store) GetTenant

func (s *Store) GetTenant(ctx context.Context, tenantID id.TenantID) (*tenant.Tenant, error)

GetTenant implements tenant.Store.

func (*Store) GetTenantByExternal

func (s *Store) GetTenantByExternal(ctx context.Context, appID, externalID string) (*tenant.Tenant, error)

GetTenantByExternal implements tenant.Store.

func (*Store) ListDevices

func (s *Store) ListDevices(ctx context.Context, f device.ListFilter) ([]*device.Device, error)

ListDevices implements device.Store, ordered by CreatedAt ascending, then ID.

func (*Store) ListTenants

func (s *Store) ListTenants(ctx context.Context, f tenant.ListFilter) ([]*tenant.Tenant, error)

ListTenants implements tenant.Store, ordered by CreatedAt ascending, then ID.

func (*Store) Migrate

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

Migrate creates or upgrades the schema by running Migrations through grove's orchestrator, which holds a lock row while it works. It is safe to call repeatedly and from several processes at once. Each call builds its own executor, because grove's executor keeps the locked connection on itself.

func (*Store) Ping

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

Ping checks that the database is reachable.

func (*Store) UpdateDevice

func (s *Store) UpdateDevice(ctx context.Context, d *device.Device) error

UpdateDevice implements device.Store.

func (*Store) UpdateTenant

func (s *Store) UpdateTenant(ctx context.Context, t *tenant.Tenant) error

UpdateTenant implements tenant.Store.

Jump to

Keyboard shortcuts

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