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
- Variables
- func DSN(path string) string
- type Store
- func (s *Store) Close() error
- func (s *Store) CountDevices(ctx context.Context, tenantID id.TenantID) (int, error)
- func (s *Store) CreateDevice(ctx context.Context, d *device.Device) error
- func (s *Store) CreateTenant(ctx context.Context, t *tenant.Tenant) error
- func (s *Store) DB() *grove.DB
- func (s *Store) DeleteDevice(ctx context.Context, tenantID id.TenantID, deviceID id.DeviceID) error
- func (s *Store) DeleteTenant(ctx context.Context, tenantID id.TenantID) error
- func (s *Store) GetDevice(ctx context.Context, tenantID id.TenantID, deviceID id.DeviceID) (*device.Device, error)
- func (s *Store) GetDeviceByKey(ctx context.Context, keyID string) (*device.Device, error)
- func (s *Store) GetTenant(ctx context.Context, tenantID id.TenantID) (*tenant.Tenant, error)
- func (s *Store) GetTenantByExternal(ctx context.Context, appID, externalID string) (*tenant.Tenant, error)
- func (s *Store) ListDevices(ctx context.Context, f device.ListFilter) ([]*device.Device, error)
- func (s *Store) ListTenants(ctx context.Context, f tenant.ListFilter) ([]*tenant.Tenant, error)
- func (s *Store) Migrate(ctx context.Context) error
- func (s *Store) Ping(ctx context.Context) error
- func (s *Store) UpdateDevice(ctx context.Context, d *device.Device) error
- func (s *Store) UpdateTenant(ctx context.Context, t *tenant.Tenant) error
Constants ¶
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 ¶
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 ¶
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 ¶
New returns a Store on db, which must be opened with the sqlitedriver. Call Migrate before first use.
func (*Store) CountDevices ¶
CountDevices implements device.Store.
func (*Store) CreateDevice ¶
CreateDevice implements device.Store.
func (*Store) CreateTenant ¶
CreateTenant implements tenant.Store.
func (*Store) DeleteDevice ¶
DeleteDevice implements device.Store.
func (*Store) DeleteTenant ¶
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 ¶
GetDeviceByKey implements device.Store.
func (*Store) GetTenantByExternal ¶
func (s *Store) GetTenantByExternal(ctx context.Context, appID, externalID string) (*tenant.Tenant, error)
GetTenantByExternal implements tenant.Store.
func (*Store) ListDevices ¶
ListDevices implements device.Store, ordered by CreatedAt ascending, then ID.
func (*Store) ListTenants ¶
ListTenants implements tenant.Store, ordered by CreatedAt ascending, then ID.
func (*Store) Migrate ¶
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) UpdateDevice ¶
UpdateDevice implements device.Store.