// Package pocketbase is the placeholder for the PocketBase storage driver. // // The plan (PLAN.md section 4) is an appliance deployment: one binary that // also brings admin auth, a filesystem abstraction for media (local or S3) // and realtime for the admin panel. The event DAG is a poor fit for // PocketBase's record model, so the roomserver and syncapi tables will use // its underlying dbx connection directly rather than its collection API. // // Until that work starts (Phase 10) the driver is compiled in, registered // and fails loudly, so that `database.driver: pocketbase` is a clear error // instead of an unknown-driver one, and so the interface stays honest: // every method the other drivers implement exists here too. package pocketbase import ( "context" "fmt" "log/slog" "github.com/dariuszjaniak/warp/server/internal/storage" ) func init() { storage.Register(storage.DriverPocketBase, Open) } // Database is the not-yet-implemented PocketBase driver. type Database struct{} // Open always fails with storage.ErrNotImplemented. func Open(context.Context, storage.Config, *slog.Logger) (storage.Database, error) { return nil, fmt.Errorf( "pocketbase driver is not implemented yet (planned for Phase 10); use %q or %q: %w", storage.DriverSQLite, storage.DriverPostgres, storage.ErrNotImplemented) } // Driver implements storage.Database. func (*Database) Driver() string { return storage.DriverPocketBase } // Ping implements storage.Database. func (*Database) Ping(context.Context) error { return storage.ErrNotImplemented } // Migrate implements storage.Database. func (*Database) Migrate(context.Context) error { return storage.ErrNotImplemented } // PendingMigrations implements storage.Database. func (*Database) PendingMigrations(context.Context) ([]string, error) { return nil, storage.ErrNotImplemented } // Settings implements storage.Database. func (*Database) Settings() storage.SettingsStore { return notImplementedSettings{} } // Users implements storage.Database. func (*Database) Users() storage.UserStore { return notImplementedUsers{} } // Close implements storage.Database. func (*Database) Close() error { return nil } // notImplementedSettings satisfies storage.SettingsStore by refusing every // call, so a partially wired-up PocketBase deployment cannot silently lose // an admin's federation switch. type notImplementedSettings struct{} func (notImplementedSettings) Get(context.Context, string) (string, bool, error) { return "", false, storage.ErrNotImplemented } func (notImplementedSettings) GetAll(context.Context) (map[string]string, error) { return nil, storage.ErrNotImplemented } func (notImplementedSettings) Set(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedSettings) Delete(context.Context, string) error { return storage.ErrNotImplemented } // notImplementedUsers satisfies storage.UserStore the same way: a // half-wired PocketBase deployment must not accept a registration it cannot // store, or hand out an access token it cannot look up again. type notImplementedUsers struct{} func (notImplementedUsers) CreateAccount(context.Context, storage.NewAccount) (storage.Account, error) { return storage.Account{}, storage.ErrNotImplemented } func (notImplementedUsers) Account(context.Context, string) (storage.Account, error) { return storage.Account{}, storage.ErrNotImplemented } func (notImplementedUsers) PasswordHash(context.Context, string) (string, error) { return "", storage.ErrNotImplemented } func (notImplementedUsers) SetPasswordHash(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) SetAdmin(context.Context, string, bool) error { return storage.ErrNotImplemented } func (notImplementedUsers) SetDisplayName(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) SetAvatarURL(context.Context, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) ListAccounts(context.Context, storage.AccountFilter) ([]storage.Account, int, error) { return nil, 0, storage.ErrNotImplemented } func (notImplementedUsers) Stats(context.Context) (storage.Stats, error) { return storage.Stats{}, storage.ErrNotImplemented } func (notImplementedUsers) CreateSession(context.Context, storage.NewSession) (storage.Device, error) { return storage.Device{}, storage.ErrNotImplemented } func (notImplementedUsers) RefreshSession(context.Context, storage.RefreshedSession) (storage.TokenInfo, error) { return storage.TokenInfo{}, storage.ErrNotImplemented } func (notImplementedUsers) TokenInfo(context.Context, string) (storage.TokenInfo, error) { return storage.TokenInfo{}, storage.ErrNotImplemented } func (notImplementedUsers) TouchDevice(context.Context, string, string, string, string, int64) error { return storage.ErrNotImplemented } func (notImplementedUsers) Device(context.Context, string, string) (storage.Device, error) { return storage.Device{}, storage.ErrNotImplemented } func (notImplementedUsers) Devices(context.Context, string) ([]storage.Device, error) { return nil, storage.ErrNotImplemented } func (notImplementedUsers) SetDeviceDisplayName(context.Context, string, string, string) error { return storage.ErrNotImplemented } func (notImplementedUsers) DeleteDevices(context.Context, string, []string) (int, error) { return 0, storage.ErrNotImplemented } func (notImplementedUsers) DeleteAllDevices(context.Context, string) (int, error) { return 0, storage.ErrNotImplemented } func (notImplementedUsers) AccountData(context.Context, string, string, string) ([]byte, error) { return nil, storage.ErrNotImplemented } func (notImplementedUsers) SetAccountData(context.Context, string, string, string, []byte) error { return storage.ErrNotImplemented } // Compile-time proof that the stub keeps up with the interfaces. var ( _ storage.Database = (*Database)(nil) _ storage.UserStore = notImplementedUsers{} )