Move sql db out of post.NewStore, so it can be shared
This commit is contained in:
parent
1495c78656
commit
07806c6942
@ -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
69
srv/src/post/sql.go
Normal 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()
|
||||||
|
}
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user