Skip to content

Commit c3d72b1

Browse files
Add db and migrations
1 parent 14b1db9 commit c3d72b1

File tree

25 files changed

+578
-28
lines changed

25 files changed

+578
-28
lines changed

.env.db.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
POSTGRES_DB=recite
2+
POSTGRES_USER=recite
3+
POSTGRES_PASSWORD=password

.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
11
OPENAI_API_KEY=<your_openai_api_key>
2+
3+
POSTGRES_DBNAME=recite
4+
POSTGRES_USER=recite
5+
POSTGRES_PASSWORD=password
6+
POSTGRES_HOST=localhost
7+
POSTGRES_PORT=5427
8+
DRIVER_NAME=pgx
9+
DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DBNAME}?sslmode=disable

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ go.work.sum
2626

2727
# Executables
2828
bin/
29+
data/output/
30+
.env
31+
.env.db

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,16 @@ Always verify your code using
3636
make ci
3737
```
3838

39+
### Adding database migrations
40+
41+
We use `dbmate` for migrations. After installing, create a new revision through
42+
43+
```bash
44+
dbmate new <name_of_revision>
45+
```
46+
47+
Apply the revision by running
48+
49+
```bash
50+
dbmate up
51+
```

cmd/cli/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"github.com/simondanielsson/recite/pkg/prompts"
1515
)
1616

17+
const maxContentLength int = 3500
18+
1719
func main() {
1820
// TODO: use a proper CLI library
1921
if len(os.Args) < 2 {
@@ -32,7 +34,7 @@ func main() {
3234
if err != nil {
3335
log.Fatalf("Failed reading article: %v", err)
3436
}
35-
articleContent = articleContent[:3500]
37+
articleContent = articleContent[:min(maxContentLength, len(articleContent))]
3638

3739
augmentPrompts, err := prompts.NewAugmentArticlePrompts(articleContent)
3840
if err != nil {

cmd/internal/config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,22 @@ func Load(getenv func(string) string, logger *log.Logger) (Config, error) {
1212
if err := env.Load(); err != nil {
1313
logger.Fatal("failed loading .env")
1414
}
15+
// TODO: read these values from yaml config
1516
cfg := Config{
1617
Server: ServerConfig{
1718
AppEnv: "local",
1819
Addr: "8999",
1920
ReadTimeout: 30 * time.Second,
2021
WriteTimeout: 30 * time.Second,
2122
},
23+
DB: DBConfig{
24+
Name: getenv("POSTGRES_DBNAME"),
25+
User: getenv("POSTGRES_USER"),
26+
Password: getenv("POSTGRES_PASSWORD"),
27+
Host: getenv("POSTGRES_HOST"),
28+
Port: getenv("POSTGRES_PORT"),
29+
Driver: getenv("DRIVER_NAME"),
30+
},
2231
JWT: JWTConfig{
2332
Secret: "123",
2433
},

cmd/internal/config/models.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ type ServerConfig struct {
1010
WriteTimeout time.Duration `mapstructure:"write_timeout"`
1111
}
1212

13+
type DBConfig struct {
14+
Name string `mapstructure:"name"`
15+
User string `mapstructure:"user"`
16+
Password string `mapstructure:"password"`
17+
Host string `mapstructure:"host"`
18+
Port string `mapstructure:"port"`
19+
Driver string `mapstructure:"driver"`
20+
}
21+
1322
// JWTConfig represents the configuration of the JWT secret
1423
type JWTConfig struct {
1524
Secret string `mapstructure:"secret"`
@@ -18,5 +27,6 @@ type JWTConfig struct {
1827
// Config represents a yaml configuration file.
1928
type Config struct {
2029
Server ServerConfig
30+
DB DBConfig
2131
JWT JWTConfig
2232
}

cmd/internal/db/db.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package db
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/jackc/pgx/v5/pgxpool"
8+
"github.com/simondanielsson/recite/cmd/internal/config"
9+
)
10+
11+
func New(ctx context.Context, config config.Config) (*pgxpool.Pool, error) {
12+
connString := fmt.Sprintf("user=%s dbname=%s password=%s port=%s host=%s sslmode=disable", config.DB.User, config.DB.Name, config.DB.Password, config.DB.Port, config.DB.Host)
13+
pool, err := pgxpool.New(ctx, connString)
14+
if err != nil {
15+
return nil, fmt.Errorf("could not connect to db: %w", err)
16+
}
17+
if err := pool.Ping(ctx); err != nil {
18+
return nil, fmt.Errorf("failed pinging database: %w", err)
19+
}
20+
21+
return pool, nil
22+
}

cmd/internal/db/middleware.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package db
2+
3+
import (
4+
"context"
5+
"log"
6+
"net/http"
7+
8+
"github.com/jackc/pgx/v5"
9+
"github.com/jackc/pgx/v5/pgxpool"
10+
"github.com/simondanielsson/recite/cmd/internal/queries"
11+
)
12+
13+
type RepositoryKeyType string
14+
15+
const RepositoryKey RepositoryKeyType = "repo_key"
16+
17+
type statusRecorder struct {
18+
http.ResponseWriter
19+
status int
20+
}
21+
22+
func AddDatabaseMiddleware(handler http.Handler, pool *pgxpool.Pool, logger *log.Logger) http.Handler {
23+
return http.HandlerFunc(
24+
func(w http.ResponseWriter, r *http.Request) {
25+
ctx := r.Context()
26+
tx, err := pool.BeginTx(ctx, pgx.TxOptions{
27+
IsoLevel: pgx.Serializable,
28+
AccessMode: pgx.ReadWrite,
29+
})
30+
if err != nil {
31+
http.Error(w, "failed to start transaction", http.StatusInternalServerError)
32+
}
33+
repository := queries.New(pool).WithTx(tx)
34+
35+
ctx = context.WithValue(ctx, RepositoryKey, repository)
36+
37+
rec := statusRecorder{ResponseWriter: w, status: http.StatusOK}
38+
handler.ServeHTTP(rec, r.WithContext(ctx))
39+
40+
if rec.status >= http.StatusBadRequest {
41+
_ = tx.Rollback(ctx)
42+
} else if err := tx.Commit(ctx); err != nil {
43+
// Response has already been sent - just log
44+
logger.Printf("commit tx failed: %v", err)
45+
}
46+
},
47+
)
48+
}

cmd/internal/queries/db.go

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)