gin gormでテーブル操作


2020/6/30 [改良しました](https://qiita.com/ogurasousui/items/9907427a6577cdaec130)

[前回](https://qiita.com/ogurasousui/items/c0324dbb8dfdb9e0ac1b)DB接続まで
今回も雑にテーブルの基本操作

## DB接続

接続をメソッドに。本来は環境やDBを設定ファイルなどで切り替えれるようにするのが良いか

```db/db.go
package db

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func Connection() *gorm.DB {
	db, err := gorm.Open("mysql", "root:@tcp(db:3306)/gin_app?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic("failed to connect database")
	}
	db.LogMode(true)
	return db
}
```

## マイグレーション

こちらもメソッドに。任意で実行できるように変更 

```migrate/migrate.go
package main

import (
	"app/db"
	"app/model"

	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
	db := db.Connection()
	defer db.Close()

	db.AutoMigrate(&model.User{})
	db.AutoMigrate(&model.UserName{})
}
```

マイグレーション実行は

```
docker exec -it gin_app go run /go/src/app/migrate/migrate.go
```

## モデル
各テーブルをモデルとして定義
今回はリレーションも使って見たかったので `user` `user_name` を作成

テーブルは↓こんなかんじ

```
$ docker exec -it gin_db mysql -u root -e "use gin_app; show tables;"
+-------------------+
| Tables_in_gin_app |
+-------------------+
| user_names        |
| users             |
+-------------------+
```

```model/user.go
package model

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type User struct {
	gorm.Model
	UserName UserName
}
```

```model/user_name.go
package model

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type UserName struct {
	gorm.Model
	UserID uint
	Name   string
}
```

## コントローラ
名前はserviceでもなんでもいいかもしれない
とりあえず動けばいいのでバリデーションなどは入れていません

```controller/user.go
package controller

import (
	"app/db"
	"app/model"

	"github.com/gin-gonic/gin"
)

type User struct{}

func NewUser() *User {
	return &User{}
}

func (t *User) Get(c *gin.Context) {
	db := db.Connection()
	defer db.Close()

	var user model.User
	result := db.First(&user, c.Param("id")).Related(&user.UserName)
	c.JSON(200, result.Value)
}

func (t *User) List(c *gin.Context) {
	db := db.Connection()
	defer db.Close()

	var users []model.User
	result := db.Preload("UserName").Find(&users)
	c.JSON(200, result.Value)
}

func (t *User) Create(c *gin.Context) {
	db := db.Connection()
	defer db.Close()

	var user model.User
	db.Create(&user)

	var userName model.UserName
	c.BindJSON(&userName)
	userName.UserID = user.ID
	db.Create(&userName)
}

func (t *User) Update(c *gin.Context) {
	db := db.Connection()
	defer db.Close()

	var user model.User
	db.First(&user, c.Param("id")).Related(&user.UserName)
	if user.UserName.ID > 0 {
		c.BindJSON(&user.UserName)
		db.Save(&user.UserName)
	}
}

func (t *User) Delete(c *gin.Context) {
	db := db.Connection()
	defer db.Close()

	var user model.User
	db.First(&user, c.Param("id")).Related(&user.UserName)
	if user.ID > 0 {
		db.Delete(&user)
	}
	if user.UserName.ID > 0 {
		db.Delete(&user.UserName)
	}

	// こっちの消し方でも良い
	// db.Where("id = ?", c.Param("id")).Delete(&model.User{})
	// db.Where("user_id = ?", c.Param("id")).Delete(&model.UserName{})
}
```
## main

各操作をルーターに追加

```main.go
package main

import (
	"app/controller"

	"github.com/gin-gonic/gin"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

func main() {
	r := gin.Default()
	r.GET("/users", controller.NewUser().List)
	r.GET("/users/:id", controller.NewUser().Get)
	r.POST("/users", controller.NewUser().Create)
	r.PUT("/users/:id", controller.NewUser().Update)
	r.DELETE("/users/:id", controller.NewUser().Delete)

	r.Run()
}
```

## 実行

### 作成
```
curl -X POST http://localhost:3001/users -d '{"name": "hoge"}'
```

### 1件取得
```
curl http://localhost:3001/users/1
```

### 全件取得
```
curl http://localhost:3001/users/
```

### 更新
```
curl -X PUT http://localhost:3001/users/1 -d '{"name": "huga"}'
```

### 削除
```
curl -X DELETE http://localhost:3001/users/1
```

おわり