Use goose for migrations

This commit is contained in:
2021-11-08 22:24:21 +00:00
parent cf1bc70103
commit 5de7d32c30
25 changed files with 134 additions and 145 deletions

View File

@ -20,7 +20,19 @@ type CreateBudgetParams struct {
}
func (q *Queries) CreateBudget(ctx context.Context, arg CreateBudgetParams) (Budget, error) {
row := q.db.QueryRow(ctx, createBudget, arg.ID, arg.Name)
row := q.db.QueryRowContext(ctx, createBudget, arg.ID, arg.Name)
var i Budget
err := row.Scan(&i.ID, &i.Name, &i.LastModification)
return i, err
}
const getBudget = `-- name: GetBudget :one
SELECT id, name, last_modification FROM budgets
WHERE id = $1
`
func (q *Queries) GetBudget(ctx context.Context, id string) (Budget, error) {
row := q.db.QueryRowContext(ctx, getBudget, id)
var i Budget
err := row.Scan(&i.ID, &i.Name, &i.LastModification)
return i, err
@ -33,7 +45,7 @@ WHERE user_budgets.user_id = $1
`
func (q *Queries) GetBudgetsForUser(ctx context.Context, userID string) ([]Budget, error) {
rows, err := q.db.Query(ctx, getBudgetsForUser, userID)
rows, err := q.db.QueryContext(ctx, getBudgetsForUser, userID)
if err != nil {
return nil, err
}
@ -46,6 +58,9 @@ func (q *Queries) GetBudgetsForUser(ctx context.Context, userID string) ([]Budge
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}

View File

@ -2,23 +2,19 @@ package postgres
import (
"context"
"database/sql"
"git.javil.eu/jacob1123/budgeteer"
)
// Budget returns a budget for a given id.
func (s *Repository) Budget(id string) (*budgeteer.Budget, error) {
b := &budgeteer.Budget{ID: id}
err := s.DB.Select(&b)
func (s *Repository) Budget(id string) (*Budget, error) {
budget, err := s.DB.GetBudget(context.Background(), id)
if err != nil {
return nil, err
}
return b, nil
return &budget, nil
}
func (s *Repository) BudgetsForUser(id string) ([]Budget, error) {
budgets, err := s.DB.GetBudgetsForUser(context.Background(), sql.NullString{id, true})
budgets, err := s.DB.GetBudgetsForUser(context.Background(), id)
if err != nil {
return nil, err
}
@ -26,7 +22,7 @@ func (s *Repository) BudgetsForUser(id string) ([]Budget, error) {
}
func (s *Repository) NewBudget(name string, userID string) (Budget, error) {
func (s *Repository) NewBudget(name string, userID string) (*Budget, error) {
b := CreateBudgetParams{ID: s.IDGenerator.New(), Name: name}
budget, err := s.DB.CreateBudget(context.Background(), b)
if err != nil {
@ -39,5 +35,5 @@ func (s *Repository) NewBudget(name string, userID string) (Budget, error) {
return nil, err
}
return budget, nil
return &budget, nil
}

View File

@ -1,17 +1,29 @@
package postgres
import (
"context"
"database/sql"
"embed"
"fmt"
"github.com/jackc/pgx/v4"
_ "github.com/jackc/pgx/v4/stdlib"
"github.com/pressly/goose/v3"
)
// go:embed schema/*.sql
var migrations embed.FS
// Connect to a database
func Connect(server string, user string, password string, database string) (*Queries, error) {
conn, err := pgx.Connect(context.Background(), fmt.Sprintf("postgresql://%s:%s@%s/%s", user, password, server, database))
connString := fmt.Sprintf("pgx://%s:%s@%s/%s", user, password, server, database)
conn, err := sql.Open("pgx", connString)
if err != nil {
return nil, err
}
goose.SetBaseFS(migrations)
if err = goose.Up(conn, "schema"); err != nil {
return nil, err
}
return New(conn), nil
}

View File

@ -4,15 +4,14 @@ package postgres
import (
"context"
"github.com/jackc/pgconn"
"github.com/jackc/pgx/v4"
"database/sql"
)
type DBTX interface {
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
QueryRow(context.Context, string, ...interface{}) pgx.Row
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
func New(db DBTX) *Queries {
@ -23,7 +22,7 @@ type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}

View File

@ -13,10 +13,10 @@ type Budget struct {
}
type User struct {
ID sql.NullString
Email sql.NullString
Name sql.NullString
Password sql.NullString
ID string
Email string
Name string
Password string
}
type UserBudget struct {

View File

@ -1,9 +1,3 @@
CREATE TABLE budgets (
id char(26) NOT NULL,
name text NOT NULL,
last_modification timestamp with time zone
);
-- name: CreateBudget :one
INSERT INTO budgets
(id, name, last_modification)
@ -13,4 +7,8 @@ RETURNING *;
-- name: GetBudgetsForUser :many
SELECT budgets.* FROM budgets
LEFT JOIN user_budgets ON budgets.id = user_budgets.budget_id
WHERE user_budgets.user_id = $1;
WHERE user_budgets.user_id = $1;
-- name: GetBudget :one
SELECT * FROM budgets
WHERE id = $1;

View File

@ -1,8 +1,3 @@
CREATE TABLE user_budgets (
user_id char(26) NOT NULL,
budget_id char(26) NOT NULL
);
-- name: LinkBudgetToUser :one
INSERT INTO user_budgets
(user_id, budget_id)

View File

@ -1,10 +1,3 @@
CREATE TABLE users (
id char(26),
email text,
name text,
password text
);
-- name: GetUserByUsername :one
SELECT * FROM users
WHERE email = $1;

View File

@ -1,11 +1,20 @@
package postgres
import (
"git.javil.eu/jacob1123/budgeteer"
)
// Repository represents a PostgreSQL implementation of all ModelServices
type Repository struct {
DB *Queries
IDGenerator budgeteer.IDGenerator
IDGenerator *UlidGenerator
}
func NewRepository(queries *Queries) (*Repository, error) {
id, err := NewGenerator()
if err != nil {
return nil, err
}
repo := &Repository{
DB: queries,
IDGenerator: id,
}
return repo, nil
}

View File

@ -0,0 +1,9 @@
-- +goose Up
CREATE TABLE budgets (
id char(26) NOT NULL,
name text NOT NULL,
last_modification timestamp with time zone
);
-- +goose Down
DROP TABLE budgets;

View File

@ -0,0 +1,8 @@
-- +goose Up
CREATE TABLE user_budgets (
user_id char(26) NOT NULL,
budget_id char(26) NOT NULL
);
-- +goose Down
DROP TABLE user_budgets;

View File

@ -0,0 +1,10 @@
-- +goose Up
CREATE TABLE users (
id char(26) NOT NULL,
email text NOT NULL,
name text NOT NULL,
password text NOT NULL
);
-- +goose Down
DROP TABLE users;

27
postgres/ulid.go Normal file
View File

@ -0,0 +1,27 @@
package postgres
import (
"math/rand"
"time"
"github.com/oklog/ulid"
)
type UlidGenerator struct {
time time.Time
entropy *rand.Rand
}
func NewGenerator() (*UlidGenerator, error) {
t := time.Time{}
ug := &UlidGenerator{
time: t,
entropy: rand.New(rand.NewSource(t.UnixNano())),
}
return ug, nil
}
func (ug *UlidGenerator) New() string {
id := ulid.MustNew(ulid.Timestamp(time.Now()), ug.entropy)
return id.String()
}

View File

@ -20,7 +20,7 @@ type LinkBudgetToUserParams struct {
}
func (q *Queries) LinkBudgetToUser(ctx context.Context, arg LinkBudgetToUserParams) (UserBudget, error) {
row := q.db.QueryRow(ctx, linkBudgetToUser, arg.UserID, arg.BudgetID)
row := q.db.QueryRowContext(ctx, linkBudgetToUser, arg.UserID, arg.BudgetID)
var i UserBudget
err := row.Scan(&i.UserID, &i.BudgetID)
return i, err

View File

@ -5,7 +5,6 @@ package postgres
import (
"context"
"database/sql"
)
const createUser = `-- name: CreateUser :one
@ -16,14 +15,14 @@ RETURNING id, email, name, password
`
type CreateUserParams struct {
ID sql.NullString
Email sql.NullString
Name sql.NullString
Password sql.NullString
ID string
Email string
Name string
Password string
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
row := q.db.QueryRow(ctx, createUser,
row := q.db.QueryRowContext(ctx, createUser,
arg.ID,
arg.Email,
arg.Name,
@ -44,8 +43,8 @@ SELECT id, email, name, password FROM users
WHERE id = $1
`
func (q *Queries) GetUser(ctx context.Context, id sql.NullString) (User, error) {
row := q.db.QueryRow(ctx, getUser, id)
func (q *Queries) GetUser(ctx context.Context, id string) (User, error) {
row := q.db.QueryRowContext(ctx, getUser, id)
var i User
err := row.Scan(
&i.ID,
@ -61,8 +60,8 @@ SELECT id, email, name, password FROM users
WHERE email = $1
`
func (q *Queries) GetUserByUsername(ctx context.Context, email sql.NullString) (User, error) {
row := q.db.QueryRow(ctx, getUserByUsername, email)
func (q *Queries) GetUserByUsername(ctx context.Context, email string) (User, error) {
row := q.db.QueryRowContext(ctx, getUserByUsername, email)
var i User
err := row.Scan(
&i.ID,