aboutsummaryrefslogtreecommitdiffstats
path: root/internal/store/store.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/store/store.go')
-rw-r--r--internal/store/store.go39
1 files changed, 38 insertions, 1 deletions
diff --git a/internal/store/store.go b/internal/store/store.go
index 472bb2a..c8e97ea 100644
--- a/internal/store/store.go
+++ b/internal/store/store.go
@@ -1,9 +1,15 @@
// Package store holds the data models and all SQL queries.
+//
+// Store talks to the control database (users, blog registry) and hands out a
+// BlogStore per blog, which is bound to that blog's own database — nothing a
+// BlogStore does can reach another blog's rows.
package store
import (
+ "context"
"errors"
+ "github.com/gramanas/blogspace/internal/db"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgxpool"
@@ -13,10 +19,36 @@ var ErrNotFound = errors.New("not found")
var ErrConflict = errors.New("already exists")
type Store struct {
+ db *pgxpool.Pool // control database
+ cluster *db.Cluster
+}
+
+func New(cluster *db.Cluster) *Store { return &Store{db: cluster.Control(), cluster: cluster} }
+
+// BlogStore runs the content queries of one blog against its database.
+type BlogStore struct {
db *pgxpool.Pool
}
-func New(db *pgxpool.Pool) *Store { return &Store{db: db} }
+// Open returns the blog's store and fills in the settings (title, tagline,
+// theme) kept in the blog database.
+func (s *Store) Open(ctx context.Context, b *Blog) (*BlogStore, error) {
+ pool, err := s.cluster.Blog(ctx, b.DBName)
+ if err != nil {
+ return nil, err
+ }
+ bs := &BlogStore{db: pool}
+ if err := bs.loadSettings(ctx, b); err != nil {
+ // A database restored underneath a running app (dropdb --force,
+ // createdb, psql < dump) leaves the pool holding dead connections;
+ // drop them and try once more before giving up.
+ pool.Reset()
+ if err := bs.loadSettings(ctx, b); err != nil {
+ return nil, err
+ }
+ }
+ return bs, nil
+}
// wrap maps driver errors onto the store's sentinel errors.
func wrap(err error) error {
@@ -32,3 +64,8 @@ func wrap(err error) error {
}
return err
}
+
+// querier is what the helpers shared with transactions need: the pool or a pgx.Tx.
+type querier interface {
+ Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
+}