package storage import ( "database/sql" "fmt" "github.com/davecgh/go-spew/spew" "github.com/lib/pq" ) type postgres struct { db *sql.DB } func New(dsn string) (Service, error) { pool, err := sql.Open("postgres", dsn) if err != nil { return nil, fmt.Errorf("could not open database connection: %v", err) } return &postgres{pool}, nil } func (s *postgres) Close() error { return s.db.Close() } func (s *postgres) Subscribe(topic string, sub Subscriber) error { _, err := s.db.Exec(` INSERT INTO "subscribers" ("topic", "callback", "lease_seconds", "secret", "created", "updated") VALUES ($1, $2, $3, $4, now(), now()) ON CONFLICT (topic, callback) DO UPDATE SET lease_seconds = excluded.lease_seconds, secret = excluded.secret, updated = now(), last_subscribed = now() `, topic, sub.Callback, sub.LeaseSeconds, sub.Secret, ) if e, ok := err.(pq.Error); ok { spew.Dump(e) } return err } func (s *postgres) RemoveExpiredSubscribers() error { _, err := s.db.Exec(`DELETE FROM "subscribers" WHERE "last_subscribed" + "lease_seconds" * interval '1' second < now()`) return err } func (s *postgres) Unsubscribe(topic, callback string) error { _, err := s.db.Exec( `DELETE FROM "subscribers" WHERE "topic" = $1 AND "callback" = $2`, topic, callback, ) return err } func (s *postgres) Subscribers(topic string) ([]Subscriber, error) { rows, err := s.db.Query(`SELECT callback, lease_seconds, secret, created FROM "subscribers" WHERE "topic" = $1`, topic) if err != nil { return nil, err } var subscribers []Subscriber for rows.Next() { var sub Subscriber err := rows.Scan(&sub.Callback, &sub.LeaseSeconds, &sub.Secret, &sub.Created) if err != nil { return nil, err } subscribers = append(subscribers, sub) } return subscribers, nil }