diff --git a/postgresql/migrations/000013_notification_subscription.down.sql b/postgresql/migrations/000013_notification_subscription.down.sql new file mode 100644 index 0000000..994d8c3 --- /dev/null +++ b/postgresql/migrations/000013_notification_subscription.down.sql @@ -0,0 +1,3 @@ +DROP INDEX notification_subscriptions_pubkey_url_key; +DROP INDEX notification_subscriptions_pubkey_idx; +DROP TABLE public.notification_subscriptions; diff --git a/postgresql/migrations/000013_notification_subscription.up.sql b/postgresql/migrations/000013_notification_subscription.up.sql new file mode 100644 index 0000000..d19cf2a --- /dev/null +++ b/postgresql/migrations/000013_notification_subscription.up.sql @@ -0,0 +1,10 @@ +CREATE TABLE public.notification_subscriptions ( + id bigserial primary key, + pubkey bytea NOT NULL, + url varchar NOT NULL, + created_at bigint NOT NULL, + refreshed_at bigint NOT NULL +); + +CREATE INDEX notification_subscriptions_pubkey_idx ON public.notification_subscriptions (pubkey); +CREATE UNIQUE INDEX notification_subscriptions_pubkey_url_key ON public.notification_subscriptions (pubkey, url); diff --git a/postgresql/notifications_store.go b/postgresql/notifications_store.go new file mode 100644 index 0000000..b0675a8 --- /dev/null +++ b/postgresql/notifications_store.go @@ -0,0 +1,76 @@ +package postgresql + +import ( + "context" + "encoding/hex" + "time" + + "github.com/jackc/pgx/v4/pgxpool" +) + +type NotificationsStore struct { + pool *pgxpool.Pool +} + +func NewNotificationsStore(pool *pgxpool.Pool) *NotificationsStore { + return &NotificationsStore{pool: pool} +} + +func (s *NotificationsStore) Register( + ctx context.Context, + pubkey string, + url string, +) error { + pk, err := hex.DecodeString(pubkey) + if err != nil { + return err + } + + now := time.Now().UnixMicro() + _, err = s.pool.Exec( + ctx, + `INSERT INTO public.notification_subscriptions (pubkey, url, created_at, refreshed_at) + values ($1, $2, $3, $4) + ON CONFLICT (pubkey, url) DO UPDATE SET refreshed_at = $4`, + pk, + url, + now, + now, + ) + + return err +} + +func (s *NotificationsStore) GetRegistrations( + ctx context.Context, + pubkey string, +) ([]string, error) { + pk, err := hex.DecodeString(pubkey) + if err != nil { + return nil, err + } + + rows, err := s.pool.Query( + ctx, + `SELECT url + FROM public.notification_subscriptions + WHERE pubkey = $1`, + pk, + ) + if err != nil { + return nil, err + } + + var result []string + for rows.Next() { + var url string + err = rows.Scan(&url) + if err != nil { + return nil, err + } + + result = append(result, url) + } + + return result, nil +}