Documentation
¶
Overview ¶
Package store provides SQLite-backed persistence for the provisioner's host registry (the `hosts` table) and push-notification devices (the `devices` table). Session metadata lives in the host's own store at internal/host/store; worktrees live on the host filesystem.
schema.sql is the declarative source of truth (read by sqlc); the goose migrations in migrations/ are what actually run at Open(). See the `make migration` target for evolving the schema.
Index ¶
- Constants
- Variables
- type Device
- type Host
- type HostStatus
- type Store
- func (s *Store) CASProviderMeta(ctx context.Context, hostID, key, oldValue, newValue string) (bool, string, error)
- func (s *Store) Close() error
- func (s *Store) CreateHostIfAbsent(ctx context.Context, h Host) (Host, bool, error)
- func (s *Store) DeleteDevice(ctx context.Context, userID, pushToken string) error
- func (s *Store) DeleteDeviceByPushToken(ctx context.Context, pushToken string) error
- func (s *Store) DeleteHostByID(ctx context.Context, id string) error
- func (s *Store) DeleteHostByUser(ctx context.Context, userID, provider string) error
- func (s *Store) GetHostByID(ctx context.Context, id string) (Host, error)
- func (s *Store) GetHostByNotifierToken(ctx context.Context, notifierToken string) (Host, error)
- func (s *Store) GetHostByUser(ctx context.Context, userID, provider string) (Host, error)
- func (s *Store) ListDevicesByUser(ctx context.Context, userID string) ([]Device, error)
- func (s *Store) UpsertDevice(ctx context.Context, d Device) error
- func (s *Store) UpsertHost(ctx context.Context, h Host) error
Constants ¶
const ( DevicePlatformIOS = "ios" DevicePlatformAndroid = "android" )
Platform values accepted by the devices CHECK constraint. Kept here so callers don't sprinkle magic strings ("iOS"/"Ios"/"IOS") that would all bounce off the constraint.
const ( HostStatusRunning = hoststore.HostStatusRunning HostStatusStopped = hoststore.HostStatusStopped HostStatusError = hoststore.HostStatusError )
Variables ¶
var ErrHostNotFound = hoststore.ErrHostNotFound
ErrHostNotFound aliases hoststore.ErrHostNotFound so errors.Is keeps working across the package boundary.
Functions ¶
This section is empty.
Types ¶
type Device ¶
type Device struct {
UserID string
PushToken string
Platform string
CreatedAt time.Time
LastSeenAt time.Time
}
Device is the push-delivery address for one (user, app-install) pair. Mirrors the devices row but uses Go-friendly types. Platform is constrained to ios or android at the schema layer (CHECK).
type Host ¶
Type aliases — the canonical definitions live in pkg/provisioner/hoststore so cloud provisioners can take the HostStore interface without depending on internal/. Existing in-repo callers keep using store.Host etc. unchanged.
type HostStatus ¶
type HostStatus = hoststore.HostStatus
Type aliases — the canonical definitions live in pkg/provisioner/hoststore so cloud provisioners can take the HostStore interface without depending on internal/. Existing in-repo callers keep using store.Host etc. unchanged.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps a SQLite database for persisting the host registry and device state. Tables are accessed via the sqlc-generated Queries in q; db stays around for the few statements sqlc's SQLite grammar can't express (see CASProviderMeta).
func Open ¶
Open opens (or creates) a SQLite database at dbPath and applies any pending schema migrations. The caller must call Close when done.
func (*Store) CASProviderMeta ¶
func (s *Store) CASProviderMeta(ctx context.Context, hostID, key, oldValue, newValue string) (bool, string, error)
CASProviderMeta implements hoststore.HostStore. Hand-written SQL: sqlc's SQLite grammar rejects bound parameters inside json_set/json_extract. key must be a plain identifier (no dots or quotes) — it becomes a JSON path segment.
func (*Store) CreateHostIfAbsent ¶
CreateHostIfAbsent implements hoststore.HostStore: atomically insert h keyed on UNIQUE(user_id, provider), or return the row that beat us. The cross-instance provisioning claim — see the interface doc.
func (*Store) DeleteDevice ¶
DeleteDevice removes a single (user, push_token) device row. No-op when the row doesn't exist. Used on user-initiated logout.
func (*Store) DeleteDeviceByPushToken ¶
DeleteDeviceByPushToken removes every row matching the given push_token, regardless of user. Used by the dispatcher when Expo returns DeviceNotRegistered — the token is dead system-wide, so purging all owners (typically only one) prevents future fan-outs from re-discovering the stale token.
func (*Store) DeleteHostByID ¶
DeleteHostByID removes a host row. No-op if the row doesn't exist.
func (*Store) DeleteHostByUser ¶
DeleteHostByUser removes the (user_id, provider) row, if any. Used when the provisioner detects out-of-band deletion at the provider (e.g. user nuked the sandbox via the provider dashboard) — clearing our row lets the next EnsureHost create a fresh one.
func (*Store) GetHostByID ¶
GetHostByID returns a host by its internal ID, or ErrHostNotFound.
func (*Store) GetHostByNotifierToken ¶
GetHostByNotifierToken returns the host whose notifier_token matches the given plaintext bearer. Returns ErrHostNotFound on miss or when notifierToken is empty (empty matches every legacy row, which is exactly the wrong thing). Fast-fails before hitting the DB to avoid that footgun.
func (*Store) GetHostByUser ¶
GetHostByUser returns the single host for (userID, provider) or ErrHostNotFound. Other errors propagate as-is.
func (*Store) ListDevicesByUser ¶
ListDevicesByUser returns all push tokens registered for userID, most-recently-seen first. Empty slice (not error) when the user has no devices yet.
func (*Store) UpsertDevice ¶
UpsertDevice inserts a new device row or refreshes last_seen_at on an existing one. created_at is preserved on update — only first- registration time is recorded. Callers fill UserID, PushToken, Platform; CreatedAt/LastSeenAt default to time.Now() when zero.
func (*Store) UpsertHost ¶
UpsertHost inserts or replaces by (user_id, provider). CreatedAt is preserved on update (UPSERT only updates the columns listed in the generated query). UpdatedAt is set to time.Now() if the caller provides a zero value.