Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 簡易的にBunとマイグレーションを導入 #96

Open
wants to merge 31 commits into
base: feat/project-user
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e8d3432
chore: 既存のスキーマを削除
yukikamome316 Nov 8, 2023
9dfaed6
feat: Bun型のmodelを定義
yukikamome316 Nov 8, 2023
b28fb97
feat: cmd/serverにmain.goを移動
yukikamome316 Nov 8, 2023
a5bc00d
fix: 実行対象を訂正
yukikamome316 Nov 8, 2023
4a87659
feat: Bunの導入
yukikamome316 Nov 8, 2023
0a3c034
chore: 既存のmigrationとmainを削除
yukikamome316 Nov 8, 2023
fdbfdfc
feat: migrationsを追加
yukikamome316 Nov 8, 2023
0ed4e53
feat: cmd/migrateを実装
yukikamome316 Nov 8, 2023
f0f7b32
feat: migrate.shを追加
yukikamome316 Nov 8, 2023
9be18c4
fix: ビルドチェックの対象を修正
yukikamome316 Nov 8, 2023
7f7966e
refactor: cmd/serverの処理をhandlerに切り離した
yukikamome316 Nov 9, 2023
4906994
refactor: http.StatusInternalServerErrorを使うようにした
yukikamome316 Nov 9, 2023
345c129
fix: 配列を初期化
yukikamome316 Nov 9, 2023
a461cac
Merge branch 'feat/project-user-migration-temp' of github.com:saitama…
yukikamome316 Nov 9, 2023
4476a0c
fix: デバッグ用のfmt.Printfを削除
yukikamome316 Nov 9, 2023
38bdb86
fix: Collationなどの不要な設定を削除
yukikamome316 Nov 9, 2023
c0f4a45
Merge branch 'feat/project-user' of github.com:saitamau-maximum/maxit…
yukikamome316 Dec 14, 2023
b1c5fe0
fix: main.goの削除
yukikamome316 Dec 14, 2023
a74b0df
feat: DBのマイグレーションに関する項目を追加
yukikamome316 Dec 14, 2023
d0c0a95
fix: 他の項目に合わせて句読点を消した
yukikamome316 Dec 14, 2023
3ea8912
fix: 誤字の訂正
yukikamome316 Dec 14, 2023
7d205da
fix: prod buildのエントリーの修正
yukikamome316 Dec 14, 2023
19d21dd
fix: migrator.shに名称を変更
yukikamome316 Dec 14, 2023
6e41a65
feat: マイグレーション関するコメントを補足説明
yukikamome316 Dec 15, 2023
5d95203
fix: 内部リンクの追加
yukikamome316 Dec 15, 2023
7b7aa50
fix: インデントのミスを修正
yukikamome316 Dec 15, 2023
d1f77d7
fix: 無駄なコロンの削除
yukikamome316 Dec 18, 2023
33961aa
feat: down migrationについて追記
yukikamome316 Dec 18, 2023
0dc2318
feat: down migrationの具体例を追加
yukikamome316 Dec 18, 2023
11c47e7
fix: インデントをスペースに変換
yukikamome316 Dec 18, 2023
7371424
fix: 誤字の訂正
yukikamome316 Dec 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .github/workflows/build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,5 @@ jobs:
run: go mod download
- name: Backend Build Check
working-directory: ./backend
run: go build -o main .



run: go build -o main ./cmd/server/main.go

10 changes: 9 additions & 1 deletion README.md
yukikamome316 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ MaximumメンバーがWeb研究部の活動として、Twitterのようなマイ

`./scripts/reset-db.sh` でDBデータを削除する

### DBのマイグレーション

> [!IMPORTANT]
> マイグレーションを初めて実行する場合、まずはデータベースのデータを削除する必要がある。これは、上記の「DBデータの削除」にあるコマンドを使用して行える。
> データの削除が完了したら、 `./scripts/migrate.sh init` を実行して、マイグレーションを行うための必要な情報をDB上に作成することができる。

`./scripts/migrate.sh migrate` を実行することで、データベースのスキーマを最新の状態に更新できる

### デプロイ

`./scripts/deploy.sh` で本番環境にデプロイする
Expand All @@ -53,6 +61,6 @@ MaximumメンバーがWeb研究部の活動として、Twitterのようなマイ
## バージョニング

バージョンは1スプリントでマイナーバージョン x.X.x を上げることにする。
それよりも細かい単位の変更 (スプリント中だけど緊急で修正箇所が浮上したなど)でリリースが必要な場合、パッチバージョン x.x.X を上げることにする。
それよりも細かい単位の変更スプリント中だけど緊急で修正箇所が浮上したなど)でリリースが必要な場合、パッチバージョン x.x.X を上げることにする。

メジャーバージョンに関しては区切りが良くなったタイミングであげるで良い。
2 changes: 1 addition & 1 deletion backend/Dockerfile
yukikamome316 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ COPY go.mod go.sum ./
RUN go mod download
EXPOSE 8000

CMD ["go", "run", "main.go"]
CMD ["go", "run", "./cmd/server/main.go"]
228 changes: 228 additions & 0 deletions backend/cmd/migrate/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package main

import (
"context"
"database/sql"
"fmt"
"log"
"os"
"strings"

"github.com/go-sql-driver/mysql"
"github.com/saitamau-maximum/maxitter/backend/migrations"

"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/mysqldialect"
"github.com/uptrace/bun/extra/bundebug"
"github.com/uptrace/bun/migrate"

"github.com/urfave/cli/v2"
)

const MIGRATION_TABLE = "bun_migrations"

func getEnv(key, fallback string) string {
value, ok := os.LookupEnv(key)
if !ok {
value = fallback
}
return value
}

func connectDB() (*sql.DB, error) {
user := getEnv("MYSQL_USER", "user")
password := getEnv("MYSQL_PASSWORD", "password")
host := getEnv("MYSQL_HOST", "localhost")
port := getEnv("MYSQL_PORT", "3306")
dbname := getEnv("MYSQL_DATABASE", "db")

c := mysql.Config{
User: user,
Passwd: password,
Net: "tcp",
Addr: fmt.Sprintf("%s:%s", host, port),
DBName: dbname,
}

db, err := sql.Open("mysql", c.FormatDSN())
if err != nil {
return nil, err
}

return db, nil
}

func main() {
db, err := connectDB()
if err != nil {
panic(err)
}

bunDB := bun.NewDB(db, mysqldialect.New())
bunDB.AddQueryHook(bundebug.NewQueryHook(
bundebug.WithEnabled(false),
bundebug.FromEnv(""),
))

defer bunDB.Close()

if err := checkMigrationsTable(context.Background(), bunDB); err != nil {
log.Println("Migrations table does not exist \n\n\t run `./scripts/migrate.sh init` first")
return
}

app := &cli.App{
Name: "bun",

Commands: []*cli.Command{
newDBCommand(migrate.NewMigrator(bunDB, migrations.Migrations)),
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}

func newDBCommand(migrator *migrate.Migrator) *cli.Command {
return &cli.Command{
Name: "db",
Usage: "database migrations",
Subcommands: []*cli.Command{
{
Name: "init",
Usage: "create migration tables",
Action: func(c *cli.Context) error {
return migrator.Init(c.Context)
},
},
{
Name: "migrate",
Usage: "migrate database",
Action: func(c *cli.Context) error {
if err := migrator.Lock(c.Context); err != nil {
return err
}
defer migrator.Unlock(c.Context)

group, err := migrator.Migrate(c.Context)
if err != nil {
return err
}
if group.IsZero() {
fmt.Printf("there are no new migrations to run (database is up to date)\n")
return nil
}
fmt.Printf("migrated to %s\n", group)
return nil
},
},
{
Name: "rollback",
Usage: "rollback the last migration group",
Action: func(c *cli.Context) error {
if err := migrator.Lock(c.Context); err != nil {
return err
}
defer migrator.Unlock(c.Context)

group, err := migrator.Rollback(c.Context)
if err != nil {
return err
}
if group.IsZero() {
fmt.Printf("there are no groups to roll back\n")
return nil
}
fmt.Printf("rolled back %s\n", group)
return nil
},
},
{
Name: "lock",
Usage: "lock migrations",
Action: func(c *cli.Context) error {
return migrator.Lock(c.Context)
},
},
{
Name: "unlock",
Usage: "unlock migrations",
Action: func(c *cli.Context) error {
return migrator.Unlock(c.Context)
},
},
{
Name: "create_go",
Usage: "create Go migration",
Action: func(c *cli.Context) error {
name := strings.Join(c.Args().Slice(), "_")
mf, err := migrator.CreateGoMigration(c.Context, name)
if err != nil {
return err
}
fmt.Printf("created migration %s (%s)\n", mf.Name, mf.Path)
return nil
},
},
{
Name: "create_sql",
Usage: "create up and down SQL migrations",
Action: func(c *cli.Context) error {
name := strings.Join(c.Args().Slice(), "_")
files, err := migrator.CreateSQLMigrations(c.Context, name)
if err != nil {
return err
}

for _, mf := range files {
fmt.Printf("created migration %s (%s)\n", mf.Name, mf.Path)
}

return nil
},
},
{
Name: "status",
Usage: "print migrations status",
Action: func(c *cli.Context) error {
ms, err := migrator.MigrationsWithStatus(c.Context)
if err != nil {
return err
}
fmt.Printf("migrations: %s\n", ms)
fmt.Printf("unapplied migrations: %s\n", ms.Unapplied())
fmt.Printf("last migration group: %s\n", ms.LastGroup())
return nil
},
},
{
Name: "mark_applied",
Usage: "mark migrations as applied without actually running them",
Action: func(c *cli.Context) error {
group, err := migrator.Migrate(c.Context, migrate.WithNopMigration())
if err != nil {
return err
}
if group.IsZero() {
fmt.Printf("there are no new migrations to mark as applied\n")
return nil
}
fmt.Printf("marked as applied %s\n", group)
return nil
},
},
},
}
}

func checkMigrationsTable(ctx context.Context, db *bun.DB) error {
if os.Args[2] == "init" {
return nil
}

if _, err := db.NewSelect().Table(MIGRATION_TABLE).Exists(ctx); err != nil {
return err
}

return nil
}
75 changes: 75 additions & 0 deletions backend/cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"database/sql"
"fmt"
"os"

"github.com/go-sql-driver/mysql"
"github.com/labstack/echo/v4"
"github.com/saitamau-maximum/maxitter/backend/handler"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/mysqldialect"
)

var (
SQL_PATH = "./sql"
IMAGES_DIR = "./public/images"
)

func getEnv(key, fallback string) string {
value, ok := os.LookupEnv(key)
if !ok {
value = fallback
}
return value
}

func connectDB() (*sql.DB, error) {
user := getEnv("MYSQL_USER", "user")
password := getEnv("MYSQL_PASSWORD", "password")
host := getEnv("MYSQL_HOST", "database")
port := getEnv("MYSQL_PORT", "3306")
dbname := getEnv("MYSQL_DATABASE", "db")

c := mysql.Config{
User: user,
Passwd: password,
Net: "tcp",
Addr: fmt.Sprintf("%s:%s", host, port),
DBName: dbname,
}

db, err := sql.Open("mysql", c.FormatDSN())
if err != nil {
return nil, err
}

return db, nil
}

func main() {
e := echo.New()
e.Debug = true
e.Logger.SetLevel(0)

db, err := connectDB()
if err != nil {
e.Logger.Fatal(err)
}

bunDB := bun.NewDB(db, mysqldialect.New())
defer bunDB.Close()

h := &handler.Handler{DB: bunDB, Logger: e.Logger}
api := e.Group("/api")
api.GET("/posts", h.GetPosts)
api.POST("/posts", h.CreatePost)
api.GET("/health", func(c echo.Context) error {
e.Logger.Info("health check")
return c.JSON(200, "ok")
})
api.GET("/users", h.GetUsers)
api.POST("/users/new", h.CreateUser)
e.Logger.Fatal(e.Start(":8000"))
}
19 changes: 17 additions & 2 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,33 @@ go 1.20
require (
github.com/go-sql-driver/mysql v1.7.1
github.com/google/uuid v1.3.1
github.com/jmoiron/sqlx v1.3.5
github.com/labstack/echo/v4 v4.11.1
github.com/uptrace/bun v1.1.16
)

require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/mod v0.12.0 // indirect
)

require (
github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/uptrace/bun/dialect/mysqldialect v1.1.16
github.com/uptrace/bun/extra/bundebug v1.1.16
github.com/urfave/cli/v2 v2.25.7
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.11.0 // indirect
)
Loading
Loading