Move sql db out of post.NewStore, so it can be shared

This commit is contained in:
Brian Picciano 2022-05-07 14:56:34 -06:00
parent 1495c78656
commit 07806c6942
4 changed files with 89 additions and 73 deletions

View File

@ -133,13 +133,13 @@ func main() {
logger.FatalString(ctx, "no paths given") logger.FatalString(ctx, "no paths given")
} }
postStore, err := post.NewStore(post.StoreParams{ postDB, err := post.NewSQLDB(dataDir)
DataDir: dataDir,
})
if err != nil { if err != nil {
logger.Fatal(ctx, "initializing post store", err) logger.Fatal(ctx, "initializing post sql db", err)
} }
defer postStore.Close() defer postDB.Close()
postStore := post.NewStore(postDB)
for _, path := range *paths { for _, path := range *paths {

69
srv/src/post/sql.go Normal file
View File

@ -0,0 +1,69 @@
package post
import (
"database/sql"
"fmt"
"path"
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
migrate "github.com/rubenv/sql-migrate"
)
var migrations = []*migrate.Migration{
&migrate.Migration{
Id: "1",
Up: []string{
`CREATE TABLE posts (
id TEXT NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL,
series TEXT,
published_at INTEGER NOT NULL,
last_updated_at INTEGER,
body TEXT NOT NULL
)`,
`CREATE TABLE post_tags (
post_id TEXT NOT NULL,
tag TEXT NOT NULL,
UNIQUE(post_id, tag)
)`,
},
Down: []string{
"DROP TABLE post_tags",
"DROP TABLE posts",
},
},
}
// SQLDB is a sqlite3 database which can be used by storage interfaces within
// this package.
type SQLDB struct {
db *sql.DB
}
// NewSQLDB initializes and returns a new sqlite3 database for post storage
// intefaces. The db will be created within the given data directory.
func NewSQLDB(dataDir cfg.DataDir) (*SQLDB, error) {
path := path.Join(dataDir.Path, "post.sqlite3")
db, err := sql.Open("sqlite3", path)
if err != nil {
return nil, fmt.Errorf("opening sqlite file at %q: %w", path, err)
}
migrations := &migrate.MemoryMigrationSource{Migrations: migrations}
if _, err := migrate.Exec(db, "sqlite3", migrations, migrate.Up); err != nil {
return nil, fmt.Errorf("running migrations: %w", err)
}
return &SQLDB{db}, nil
}
// Close cleans up loose resources being held by the db.
func (db *SQLDB) Close() error {
return db.db.Close()
}

View File

@ -9,8 +9,6 @@ import (
"time" "time"
_ "github.com/mattn/go-sqlite3" // we need dis _ "github.com/mattn/go-sqlite3" // we need dis
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
migrate "github.com/rubenv/sql-migrate"
) )
var ( var (
@ -69,66 +67,15 @@ type Store interface {
Close() error Close() error
} }
var migrations = []*migrate.Migration{
&migrate.Migration{
Id: "1",
Up: []string{
`CREATE TABLE posts (
id TEXT NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL,
series TEXT,
published_at INTEGER NOT NULL,
last_updated_at INTEGER,
body TEXT NOT NULL
)`,
`CREATE TABLE post_tags (
post_id TEXT NOT NULL,
tag TEXT NOT NULL,
UNIQUE(post_id, tag)
)`,
},
Down: []string{
"DROP TABLE post_tags",
"DROP TABLE posts",
},
},
}
// Params are parameters used to initialize a new Store. All fields are required
// unless otherwise noted.
type StoreParams struct {
DataDir cfg.DataDir
}
type store struct { type store struct {
params StoreParams
db *sql.DB db *sql.DB
} }
// NewStore initializes a new Store using a sqlite3 database at the given file // NewStore initializes a new Store using an existing SQLDB.
// path. func NewStore(db *SQLDB) Store {
func NewStore(params StoreParams) (Store, error) {
path := path.Join(params.DataDir.Path, "post.sqlite3")
db, err := sql.Open("sqlite3", path)
if err != nil {
return nil, fmt.Errorf("opening sqlite file at %q: %w", path, err)
}
migrations := &migrate.MemoryMigrationSource{Migrations: migrations}
if _, err := migrate.Exec(db, "sqlite3", migrations, migrate.Up); err != nil {
return nil, fmt.Errorf("running migrations: %w", err)
}
return &store{ return &store{
params: params, db: db.db,
db: db, }
}, nil
} }
func (s *store) Close() error { func (s *store) Close() error {
@ -168,7 +115,7 @@ func (s *store) Set(post Post, now time.Time) error {
nowTS := now.Unix() nowTS := now.Unix()
nowSql := sql.NullInt64{Int64: nowTS, Valid: !now.IsZero()} nowSQL := sql.NullInt64{Int64: nowTS, Valid: !now.IsZero()}
_, err := tx.Exec( _, err := tx.Exec(
`INSERT INTO posts ( `INSERT INTO posts (
@ -186,9 +133,9 @@ func (s *store) Set(post Post, now time.Time) error {
post.Title, post.Title,
post.Description, post.Description,
&sql.NullString{String: post.Series, Valid: post.Series != ""}, &sql.NullString{String: post.Series, Valid: post.Series != ""},
nowSql, nowSQL,
post.Body, post.Body,
nowSql, nowSQL,
) )
if err != nil { if err != nil {

View File

@ -38,14 +38,14 @@ func newStoreTestHarness(t *testing.T) storeTestHarness {
clock := clock.NewMock(time.Now().UTC().Truncate(1 * time.Hour)) clock := clock.NewMock(time.Now().UTC().Truncate(1 * time.Hour))
store, err := NewStore(StoreParams{ db, err := NewSQLDB(dataDir)
DataDir: dataDir, if err != nil {
}) t.Fatal(err)
assert.NoError(t, err) }
t.Cleanup(func() { t.Cleanup(func() { db.Close() })
assert.NoError(t, store.Close())
}) store := NewStore(db)
return storeTestHarness{ return storeTestHarness{
clock: clock, clock: clock,