eevee
Generate model, repository, dao sources for Go application
eevee
ã¯ã¢ããªã±ãŒã·ã§ã³éçºæã«å¿
èŠãšãªã
ãã£ãã·ã¥ãããŒã¿ããŒã¹ãšãã£ãããã«ãŠã§ã¢ãšã®å¹ççãªããŒã¿ã®ãããšãã
éçºæã«çããåé·ãªäœæ¥ãèªååããããã®ä»çµã¿ãæäŸããŸãã
ããŒã¿ãããã«ç°¡åãã€å¹ççã«åç
§ãæžã蟌ããããšããããšã«ãã©ãŒã«ã¹ããŠããããã
ã«ãŒãã£ã³ã°ãªã©ã®æ©èœã¯æäŸããŠããŸããã
ãã®ããã echo ã chi ã goji ãšãã£ãã¢ããªã±ãŒã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ãšåæã«å©çšããããšãæ³å®ããŠããŸãã
goa ãæäŸããŠãããã㪠APIãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ ãèªåçæããæ©èœçãååšããŸããã
ãããžã§ã¯ãã«ããããŠå°å
¥ããããªããå€æããããšãã§ããŸãã
eevee
ãæäŸããæ©èœã¯äž»ã«æ¬¡ã®ãããªãã®ã§ãã
- ã¹ããŒãé§åéçºã«ããã¢ãã«ã»ãªããžããªå±€ã®èªåçæ
- ã¢ãã«éã®äŸåé¢ä¿ã®èªå解決
Eager Loading
/Lazy Loading
ãå©çšããå¹ççãªããŒã¿åç §- ãã¹ãéçºãæ¯æŽãã mock ã€ã³ã¹ã¿ã³ã¹äœææ©èœ
- ã¢ãã«ããJSONæååãžã®é«éãªå€æ
- API ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ãšãã®ããã¥ã¡ã³ãã®èªåçæ
- ãã©ã°ã€ã³ãçšããæè»ãªã«ã¹ã¿ãã€ãº
eevee
㯠600 ãè¶
ããããŒãã«ã150äžè¡ãè¶
ããèŠæš¡ã®ã¢ããªã±ãŒã·ã§ã³éçºãæ¥ã
æ¯ããŠããã
å°èŠæš¡éçºãã倧èŠæš¡éçºãŸã§æ§ã
ãªçšéã§å©çšããããšãã§ããŸãã
ç®æ¬¡
- 䜿ãæ¹
- èšå®ãã¡ã€ã«
- åæ©èœã«ã€ããŠ
- ã¹ããŒãé§åéçºã«ãããã¢ãã«ã»ãªããžããªå±€ã®èªåçæ
- ã¢ãã«éã®äŸåé¢ä¿ã®èªå解決
Eager Loading
/Lazy Loading
ãå©çšããå¹ççãªããŒã¿åç §- ãã¹ãéçºãæ¯æŽãã mock ã€ã³ã¹ã¿ã³ã¹äœææ©èœ
- ã¢ãã«ããJSONæååãžã®é«éãªå€æ
- API ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ãšãã®ããã¥ã¡ã³ãã®èªåçæ
- ãã©ã°ã€ã³ãçšããæè»ãªã«ã¹ã¿ãã€ãº
- eevee ã«ããå®è·µçãªéçºæ¹æ³
- Committers
- License
䜿ãæ¹
ãŸãã¯å®éã« eevee ãå©çšããããšã§äœãã§ããããã«ãªãã®ããèŠãŠãããŸãã
ããã§çŽ¹ä»ããŠããã³ãŒã㯠_example/01_simple é
äžã«çœ®ãããŠããŸãã
eevee ã®ã€ã³ã¹ããŒã«
$ go get go.knocknote.io/eevee/cmd/eevee
ç¡äºã€ã³ã¹ããŒã«ã§ããŠããã°ã $GOPATH/bin/eevee
ãããã¯ãã§ãã
eevee --help
ãå®è¡ã§ããã°ãã€ã³ã¹ããŒã«ã¯å®äºã§ã
äœæ¥ãã£ã¬ã¯ããªã®äœæ
ã¢ããªã±ãŒã·ã§ã³éçºã®ããã®äœæ¥çšãã£ã¬ã¯ããªãäœæããŠãã ãã
go.mod ãã¡ã€ã«ã®äœæ
ãã€ãã®ããã« go.mod
ãã¡ã€ã«ãäœæããŠãã ãã
$ go mod init simple
ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®äœæ
ä»å㯠echo ã® https://echo.labstack.com/cookbook/crud ãããŒã¹ã«
eevee
ãå©çšããããšæããŸãã
ãªã³ã¯å ã«ããã³ãŒãã¯ä»¥äžã®ããã«ãªã£ãŠããŸãã
package main
import (
"net/http"
"strconv"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
)
type (
user struct {
ID int `json:"id"`
Name string `json:"name"`
}
)
var (
users = map[int]*user{}
seq = 1
)
func createUser(c echo.Context) error {
u := &user{
ID: seq,
}
if err := c.Bind(u); err != nil {
return err
}
users[u.ID] = u
seq++
return c.JSON(http.StatusCreated, u)
}
func getUser(c echo.Context) error {
id, _ := strconv.Atoi(c.Param("id"))
return c.JSON(http.StatusOK, users[id])
}
func updateUser(c echo.Context) error {
u := new(user)
if err := c.Bind(u); err != nil {
return err
}
id, _ := strconv.Atoi(c.Param("id"))
users[id].Name = u.Name
return c.JSON(http.StatusOK, users[id])
}
func deleteUser(c echo.Context) error {
id, _ := strconv.Atoi(c.Param("id"))
delete(users, id)
return c.NoContent(http.StatusNoContent)
}
func main() {
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.POST("/users", createUser)
e.GET("/users/:id", getUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
ãã®ãµã³ãã«ã§ã¯ user
ãšãããªãœãŒã¹ã«å¯Ÿã㊠CRUD æäœãè¡ã£ãŠããŸããã
ãµã³ãã«ã®ããããŒã¿ã¯ãµãŒãã®ã¡ã¢ãªäžã«çœ®ãããŠããŸãã
ããã eevee ãçšã㊠ããŒã¿ããŒã¹(MySQL) äžãžã®æäœã«å€æŽããããšãè¡ã£ãŠã¿ãŸãã
ãŸãã¯ãäžèšã®ã³ãŒãã server.go
ãšããŠä¿åããŸãã
ã¹ããŒããã¡ã€ã«ã®äœæ
user
ã«é¢ããããŒã¿ã MySQL äžã«ä¿åããããšã«ããã®ã§ããŸãã¯ãã®ã¹ããŒããå®çŸ©ããŸãã
次ã®ãããªã³ãã³ãã§ã id
ãš name
ãšããã«ã©ã ããã£ã users
ããŒãã«ãäœãDDLãæžããããã¡ã€ã«ãäœæããŸãã
$ mkdir schema
$ cat <<'EOS' >> schema/users.sql
CREATE TABLE `users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
EOS
eevee ã®å®è¡
eevee ã® init
ã³ãã³ããå®è¡ããŸãã
$ eevee init --schema schema --class config
--schema
ãªãã·ã§ã³ã§ã¹ããŒããã¡ã€ã«ã眮ãããŠãããã£ã¬ã¯ããªãæå®ããŸã ( ä»å㯠schema
)
--class
ãªãã·ã§ã³ã§ã¯ã©ã¹ãã¡ã€ã«ãçæããããã£ã¬ã¯ããªãæå®ããŸã ( ä»å㯠config
)
â» eevee 㧠Go ã®ãœãŒã¹ã³ãŒããèªåçæããéãäžè¿°ã® ã¯ã©ã¹ãã¡ã€ã« ãšãããã®ãåç
§ããŸãã
ããã«ã€ããŠã¯åŸã§è©³ãã説æããŸãã
ããŸããããš .eevee.yml
ãšãããã¡ã€ã«ãäœæãããŠããã¯ãã§ãã
ãã®ç¶æ
ã§ã以äžã®ã³ãã³ããå®è¡ããŠãã ãã
$ eevee run
å
ã»ã©äœæãã .eevee.yml
ãèªã¿èŸŒã¿ãå®çŸ©ã«åŸã£ãŠãœãŒã¹ã³ãŒãã®èªåçæãè¡ããŸãã
èªåçæãããŸããããšãäœæ¥ãã£ã¬ã¯ããªé
äžã¯ä»¥äžã®ããã«ãªãã¯ãã§ãã
âââ config
â âââ user.yml
âââ dao
â âââ user.go
âââ entity
â âââ user.go
âââ go.mod
âââ go.sum
âââ model
â âââ model.go
â âââ user.go
âââ repository
â âââ repository.go
â âââ user.go
âââ schema
âââ users.sql
æ°ããã config
entity
dao
model
repository
ãšãããã£ã¬ã¯ããªãäœãããŠããŸãã
ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã®æžãæã
ããã§ã¯ãèªåçæãããã³ãŒãã䜿ã£ãŠ server.go
ãä¿®æ£ããŸãã
ä¿®æ£ããåŸã®ã³ãŒãã¯ä»¥äžã§ãã
package main
import (
"context"
"database/sql"
"io/ioutil"
"net/http"
"simple/entity"
"simple/repository"
"strconv"
_ "github.com/go-sql-driver/mysql"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
)
var (
db *sql.DB
)
func createUser(c echo.Context) error {
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
reqUser := new(entity.User)
if err := c.Bind(reqUser); err != nil {
return err
}
user, err := repo.User().Create(ctx, reqUser)
if err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.JSON(http.StatusCreated, user)
}
func getUser(c echo.Context) error {
id, _ := strconv.Atoi(c.Param("id"))
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
user, err := repo.User().FindByID(ctx, uint64(id))
if err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.JSON(http.StatusOK, user)
}
func updateUser(c echo.Context) error {
reqUser := new(entity.User)
if err := c.Bind(reqUser); err != nil {
return err
}
id, _ := strconv.Atoi(c.Param("id"))
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
user, err := repo.User().FindByID(ctx, uint64(id))
if err != nil {
return err
}
user.Name = reqUser.Name
if err := user.Save(ctx); err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.JSON(http.StatusOK, user)
}
func deleteUser(c echo.Context) error {
id, _ := strconv.Atoi(c.Param("id"))
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
if err := repo.User().DeleteByID(ctx, uint64(id)); err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.NoContent(http.StatusNoContent)
}
func init() {
{
conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/?parseTime=true")
if err != nil {
panic(err)
}
if _, err := conn.Exec("CREATE DATABASE IF NOT EXISTS eevee"); err != nil {
panic(err)
}
}
{
conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true")
if _, err := conn.Exec("DROP TABLE IF EXISTS users"); err != nil {
panic(err)
}
sql, err := ioutil.ReadFile("schema/users.sql")
if err != nil {
panic(err)
}
if _, err := conn.Exec(string(sql)); err != nil {
panic(err)
}
}
}
func main() {
e := echo.New()
conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true")
if err != nil {
panic(err)
}
db = conn
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.POST("/users", createUser)
e.GET("/users/:id", getUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
ã²ãšã€ãã€èŠãŠãããŸãã
ã¢ããªã±ãŒã·ã§ã³å®è¡ã®ããã®æºå
func init() {
{
conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/?parseTime=true")
if err != nil {
panic(err)
}
if _, err := conn.Exec("CREATE DATABASE IF NOT EXISTS eevee"); err != nil {
panic(err)
}
}
{
conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true")
if _, err := conn.Exec("DROP TABLE IF EXISTS users"); err != nil {
panic(err)
}
sql, err := ioutil.ReadFile("schema/users.sql")
if err != nil {
panic(err)
}
if _, err := conn.Exec(string(sql)); err != nil {
panic(err)
}
}
}
func init()
ã§è¡ã£ãŠããåŠçã¯ããã®ãµã³ãã«ã³ãŒããåããããã«
ããŒã¿ããŒã¹ã users
ããŒãã«ãäœæããŠããåŠçã§ãã
ããã§ã¯ãããŒã«ã«ã® MySQL ãµãŒãã«ã€ãªãã§ã eevee
ãšããååã®ããŒã¿ããŒã¹ãäœæãã
ããã« users
ããŒãã«ãäœæããŠããŸã ( ãããã§ã«ååšããŠããåé€ããŸã )ã
äœæããããŒã¿ããŒã¹ã«å¯Ÿããã³ãã¯ã·ã§ã³ã®äœæ
func main() {
e := echo.New()
conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true")
if err != nil {
panic(err)
}
db = conn
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.POST("/users", createUser)
e.GET("/users/:id", getUser)
e.PUT("/users/:id", updateUser)
e.DELETE("/users/:id", deleteUser)
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
func main()
ã§è¡ã£ãŠããåŠçã§å€æŽãããã®ã¯
conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true")
if err != nil {
panic(err)
}
db = conn
ã®éšåã§ãã func init()
ã§äœã£ãããŒã¿ããŒã¹ã«å¯Ÿå¿ããã³ãã¯ã·ã§ã³ãäœã£ãŠããŸãã
ããããŠ
var (
db *sql.DB
)
ã§ã db
ã€ã³ã¹ã¿ã³ã¹ãã°ããŒãã«ã«å®çŸ©ãã CRUD
æäœã®ããããããåãã€ã³ã¹ã¿ã³ã¹ãåç
§ããããã«ããŸãã
äœææäœ
CRUD ã®ãã¡ã CREATE ã¯ä»¥äžã®ããã«å€ãããŸããã
func createUser(c echo.Context) error {
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
reqUser := new(entity.User)
if err := c.Bind(reqUser); err != nil {
return err
}
user, err := repo.User().Create(ctx, reqUser)
if err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.JSON(http.StatusCreated, user)
}
eevee ã¯ããããªãœãŒã¹ã«å¯Ÿãã CRUD æäœã repository
ããã±ãŒãžãéããŠè¡ãããã«èšèšãããŠããŸãã
ä»å㯠user
ãªãœãŒã¹ãæäœããããã repository.User
ã«ã¢ã¯ã»ã¹ããã®ã§ããã
ãã®æ¹æ³ã¯ repository.Repository
ãšããå
±éã®ã€ã³ã¹ã¿ã³ã¹ãçšããŠè¡ããŸãã
å
±éã€ã³ã¹ã¿ã³ã¹ãäœãããã«ã¯ã context.Context
ãš *sql.Tx
ãå¿
èŠãªã®ã§ãããããäœã£ãŠããåæåããŸãã
ctx := context.Background()
tx, err := db.Begin()
...
repo := repository.New(ctx, tx)
次㫠user
ãäœããŸãã repo.User()
㧠user
ãªãœãŒã¹ãžã¢ã¯ã»ã¹ããããšãã§ããããã«ãªãã
ãªãœãŒã¹äœæã®å Žå㯠Create(context.Context, *entity.User) (*model.User, error)
ãå®è¡ããŸãã
user, err := repo.User().Create(ctx, reqUser)
if err != nil {
return err
}
entity.User
ã¯ããžãã¯ããããªããã·ãªã¢ã©ã€ãºå¯èœãªããŒã¿æ§é ã§ãã
ãŸãã¯ããªã¯ãšã¹ãå
容ããã®ã€ã³ã¹ã¿ã³ã¹ã«ãããã³ã°ããããšã§ãäœæãããããŒã¿æ§é ãè¡šçŸããŸãã
ããŒã¿ã®äœæãšåæã«ã *model.User
ãè¿åŽãããŸãã
model
ããã±ãŒãžã«ã¯ã¢ããªã±ãŒã·ã§ã³éçºã«åœ¹ç«ã€ API ãè±å¯ã«ååšããŸã ( 詳现ã¯åŸè¿° )ã
ããã§ã¯ããŒã¿ããŒã¹äžã«äœæãããã¬ã³ãŒããšå¯Ÿå¿ããã€ã³ã¹ã¿ã³ã¹ãè¿åŽããããšèããŠãã ããã
èªã¿åºãæäœ
CRUD ã®ãã¡ã READ ã¯ä»¥äžã®ããã«å€ãããŸããã
func getUser(c echo.Context) error {
id, _ := strconv.Atoi(c.Param("id"))
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
user, err := repo.User().FindByID(ctx, uint64(id))
if err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.JSON(http.StatusOK, user)
}
ãŸã㯠CREATE ã®ãšããšåæ§ã« repository.Repository
ãäœæããããšããè¡ããŸãã
ããã§ãèªã¿èŸŒã¿æäœã«ãé¢ããã db.Begin()
ãš tx.Commit()
ãå®è¡ããŠããããšãå¥åŠã«æãããããããŸããã
ãã®ãããªèšèšã«ããŠããèæ¯ãšããŠ
- CRUDã®ã©ã®æäœãè¡ããã«é¢ä¿ãªããçµ±äžãããã€ã³ã¿ãŒãã§ãŒã¹ (
repository.New()
) ãéããŠãªããžããªãäœæããæäœããŠã»ãã - èªã¿åºãã®ã¿ã§ãã£ãŠããã£ãã·ã¥ã®äœæãªã©æžã蟌ã¿æäœãå«ãŸããå Žåãããããã©ã³ã¶ã¯ã·ã§ã³ãåæãšããŠãè¯ãã±ãŒã¹ããã(â»
repository.New()
ã«ã¯èšå®ã«ãã£ãŠsql.Tx
以å€ã®ãã©ã³ã¶ã¯ã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ãæž¡ãããšãã§ããŸã )
ã®ãããªãã®ããããŸãã
ã§ãããããã§ãèªã¿åºãã®ã¿ã®APIã«é¢ããŠã¯ãã©ã³ã¶ã¯ã·ã§ã³ãäœããããªãå ŽåããããããããŸããã
ãã®ãããçŸåšã® eevee ã§ã¯äžèšã®ãããªèãæ¹ã«å¯Ÿãã解ã¯æã£ãŠããŸãããã
声ãå€ãããå Žåã¯ãã€ã³ã¿ãŒãã§ãŒã¹ãèŠçŽãããšãæ€èšããŠããŸãã
user, err := repo.User().FindByID(ctx, uint64(id))
if err != nil {
return err
}
㧠user
ã€ã³ã¹ã¿ã³ã¹ãååŸããŸãããã®ãšãåŸãããã®ã¯ *model.User
ã€ã³ã¹ã¿ã³ã¹ã§ãã
ã¢ãã«ã€ã³ã¹ã¿ã³ã¹ã¯ JSON æååãžã®é«éå€æããµããŒãããŠããããã
ãã®ãŸãŸä»¥äžã®ããã« JSON ãšããŠåºåããããšãã§ããŸãã
return c.JSON(http.StatusOK, user)
æŽæ°æäœ
CRUD ã®ãã¡ã UPDATE ã¯ä»¥äžã®ããã«å€ãããŸããã
func updateUser(c echo.Context) error {
reqUser := new(entity.User)
if err := c.Bind(reqUser); err != nil {
return err
}
id, _ := strconv.Atoi(c.Param("id"))
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
user, err := repo.User().FindByID(ctx, uint64(id))
if err != nil {
return err
}
user.Name = reqUser.Name
if err := user.Save(ctx); err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.JSON(http.StatusOK, user)
}
repository.Repository
ãäœæããæµãã¯åãã§ãã
ç¹çãã¹ãã¯ã user.Save(ctx)
ã§æŽæ°åŠçãå®çŸããŠããããšã§ãããã
eevee ãèªåçæããã³ãŒããçšããŠãªãœãŒã¹ãæŽæ°ããã«ã¯ã2éãã®æ¹æ³ããããŸãã
äžã€ã¯ã repo.User().UpdateByID(context.Context, uint64, map[string]interface{}) error
ãçšããæ¹æ³ã§ãã
repository
ããã±ãŒãžãéããŠãæŽæ°ãããã¬ã³ãŒãã® ID ãš æŽæ°ãããã«ã©ã åãšãã®å€ã map ã«ãããã®ãæž¡ããŸãã
ãã®æ¹æ³ã¯çŽæçã§ã¯ãããŸãã map[string]interface{}
ãæåã§äœæããå Žåãªã©ã¯ã
å€ãæ£ããããã³ã³ãã€ã©ã§æ€æ»ã§ããªãããã誀ããå®è¡æã«ããæ°ã¥ããªããšãããã¡ãªããããããŸãã
ããäžã€ã¯ Save(context.Context)
ã§ãã
ããã¯æžã蟌ã¿å¯èœãªã¢ãã«ããã€æ©èœã®ãã¡ã®ã²ãšã€ã§ã
ã¢ãã«ã€ã³ã¹ã¿ã³ã¹ãã©ããã£ãæ段ã§äœã£ããã«ãã£ãŠ Save(context.Context)
ãåŒãã éã«
é©åã«ãªãœãŒã¹ã®äœæãŸãã¯æŽæ°åŠçãèµ°ããŸãã
ãã® Save(context.Context
ããªãœãŒã¹ã®äœæã»æŽæ°æ段ãšããŠå©çšããããšã«ãã£ãŠã
ã¬ã³ãŒãããããšãã»ãªããšããšãã£ãå Žååãããã©ã®å€ãæŽæ°ãã¹ãããšãã£ãããšãæèããå¿
èŠããããŸããã
ä»åã®ã±ãŒã¹ã§ã¯ã FindByID()
ã§ååŸããã€ã³ã¹ã¿ã³ã¹ã§ããããšããããã§ã«ååšããã¬ã³ãŒããåŒããããšãèªæãªããã
Save()
ãåŒãã éã«ã¬ã³ãŒãã®æŽæ°åŠçãèµ°ããŸãã
åé€æäœ
CRUD ã®ãã¡ã DELETE ã¯ä»¥äžã®ããã«å€ãããŸããã
func deleteUser(c echo.Context) error {
id, _ := strconv.Atoi(c.Param("id"))
tx, err := db.Begin()
if err != nil {
return err
}
ctx := context.Background()
repo := repository.New(ctx, tx)
if err := repo.User().DeleteByID(ctx, uint64(id)); err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return c.NoContent(http.StatusNoContent)
}
repository.Repository
ãäœã£ãŠä»¥äžã®ããã«
if err := repo.User().DeleteByID(ctx, uint64(id)); err != nil {
return err
}
ãåŒã¹ã°ãã¬ã³ãŒããåé€ããããšãã§ããŸãã
ãããŸã§ã§å€§ãŸããªäœ¿ãæ¹ã®æµããç解ããŠããã£ããšããã§ã
次㯠eevee
ãèªåçæãè¡ãéã«åç
§ããŠãããã¡ã€ã«ã«ã€ããŠèª¬æããŸãã
eevee
ãçšããã¢ããªã±ãŒã·ã§ã³éçºãè¡ãå Žåã¯ãåºæ¬çã«ãããã説æãã
äºçš®é¡ã®ãã¡ã€ã«ã«èšå®ãèšè¿°ããŠãããŸãã
èšå®ãã¡ã€ã«
.eevee.yml
)
å
šäœèšå®ãã¡ã€ã« ( eevee init
ããããªããšãå®è¡ãã£ã¬ã¯ããªé
äžã«ãã go.mod
ãèªã¿èŸŒãã§
ã¢ããªã±ãŒã·ã§ã³åãååŸãã .eevee.yml
ãšãããã¡ã€ã«ãäœæããŸãã
init
ã³ãã³ãå®è¡æã«ãªãã·ã§ã³ãäžããããšã§ããããããèšå®å€ã .eevee.yml
ã«åæ ãããäžã§çæããããšãå¯èœã§ãããããšãã YAML
ãã¡ã€ã«ãç·šéããŠãåãã§ãã
èšå®ãã¡ã€ã«ã¯äžçªç°¡çŽ ãªç¶æ ã ãšä»¥äžã®ãããªãã®ã§ã
.eevee.yml
module: module_name
module
ã«ã¯ go.mod
ããèªã¿èŸŒãã ã¢ãžã¥ãŒã«åãå
¥ããŸã ( ãã¡ããå€æŽå¯èœã§ã )ã
ããã§ãè¯ãã®ã§ãããããå°ãããã«æžã足ããŠã¿ãŸãã
eevee
ã¯ãŸããã®èšå®ãã¡ã€ã«ãèªã¿èŸŒãã§ãåŸè¿°ãã ã¯ã©ã¹ãã¡ã€ã« ãã©ãã«çæããããå€æããŸãã
ããã©ã«ãã§ã¯ eevee run
ãå®è¡ãããã£ã¬ã¯ããªé
äžã«çæããããããã®æåãå€ãããå Žåã¯ä»¥äžã®ããã«èšå®ããŸãã
module: module_name
class: config
ãã㧠ã¯ã©ã¹ãã¡ã€ã« ã config
ãã£ã¬ã¯ããªé
äžã«çæãããããã«ãªããŸãã
ããããŠã ã¯ã©ã¹ãã¡ã€ã« ãçæããããã®å
ãšãªãã¹ããŒããã¡ã€ã«ãæ ŒçŽããŠãããã£ã¬ã¯ããªãæå®ããŠã¿ãŸããããã§ã¯ã schema
ãã£ã¬ã¯ããªé
äžã«ã¹ããŒããã¡ã€ã«ãé
眮ããŠããããšãåæãšããŠ
module: module_name
class: config
schema: schema
ãšèšå®ããŸãããã®ããã«æžããšã eevee
㯠eevee run
ãå®è¡ããéã«ã¹ããŒããã¡ã€ã«ãã©ãã«ããã®ããææ¡ããŠèªã¿èŸŒã¿ããã®çµæã ã¯ã©ã¹ãã¡ã€ã« ãšããŠæå®ããããã£ã¬ã¯ããªé
äžã«èªåçæããããã«ãã®å
容ãã Go ã®ãœãŒã¹ã³ãŒããèªåçæããŸãã
.eevee.yml
ã«ã¯ä»ã«ãå€ãã®ãã©ã¡ãŒã¿ãèšå®ããããšãã§ããèªåçæå
šäœã«é¢ããæåãå€æŽããããšãã§ããŸãã
module: module_name
graph: graph
class: config
schema: schema
plugins:
plugin-name:
repo: github.com/path/to/plugin-repo
dao:
default: db
datastore:
db:
before-create:
- request-time
before-update:
- request-time
entity:
plugins:
- plugin-name
module
Go ã®ãœãŒã¹ã³ãŒããèªåçæããéã«å©çšããã¢ãžã¥ãŒã«åãæå®ããŸãã
go.mod
ãååšããå Žåã¯èªåçã«ã¢ãžã¥ãŒã«åãèªã¿åã£ãŠæžã蟌ã¿ãŸãã
schema
ã¹ããŒããã¡ã€ã«ãé 眮ããå Žæãæå®ããããšãã§ããŸã
class
ã¯ã©ã¹ãã¡ã€ã«ãçæãããã¹ãæå®ããããšãã§ããŸã
graph
ã¯ã©ã¹ãã¡ã€ã«ã®äŸåé¢ä¿ãå¯èŠåãããŠã§ãããŒãžã衚瀺ããæ©èœã§ãã
graph: path/to/graph
ãšæå®ããããšã§ãæå®å
ã« index.html
ã viz.js
ãšãã£ãããŒãžã®è¡šç€ºã«å¿
èŠãªãã¡ã€ã«ãçæãããŸãã
ãŸãã eevee serve
ã³ãã³ããå®è¡ãããšãçæãããã¡ã€ã«ããµãŒããããŠã§ããµãŒããç«ã¡äžãããŸãã
output
entity
dao
model
repository
ãªã©ã®ãœãŒã¹ã³ãŒããèªåçæããéã®èµ·ç¹ãšãªããã¹ãæå®ããããšãã§ããŸããããã©ã«ã㯠.
( eevee run
å®è¡æã®ãã£ã¬ã¯ã㪠) ã§ã
api
APIå®çŸ©ãæžããã YAML
ãã¡ã€ã«ãæ ŒçŽãããŠãããã¹ãæå®ããããšãã§ããŸã
document
APIãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ãèªåçæããæ©èœãå©çšããéã«ã åæã«èªåçæãã APIããã¥ã¡ã³ã ã®çæå Žæãæå®ããããšãã§ããŸã
dao
dao.name
dao
ãšããããã±ãŒãžåãå€æŽããããã«äœ¿çšããŸãã
dao
ã®åœ¹å²ã¯ãã®ãŸãŸã«ãååã ããå€æŽãããå Žåã«å©çšããŸã
dao.default
ã¯ã©ã¹ãã¡ã€ã«ãèªåçæããéã«å©çšãããããã©ã«ãã® datastore
ãå€æŽã§ããŸãããã
äœãæå®ããªãå Žå㯠db
ã䜿çšãããŸã
datastore
ã«ã¯ãªãªãŒã¹æç¹ã§ã¯ db
ã®ä»ã« rapidash
ãå©çšã§ããŸã
dao.datastore
datastore
ã®çš®é¡ããšã«ã©ã®ã¿ã€ãã³ã°ã§ã©ããªãã©ã°ã€ã³ã䜿çšããŠèªåçæãè¡ãããæå®ããããšãã§ããŸãã
以äžã®äŸã§ã¯ã db
ã§ã¯ create
ãš update
å®è¡åã®ã¿ã€ãã³ã°ã§ã request-time
ãšãããã©ã°ã€ã³ãå©çšããããšãæå®ããŠããŸããåæ§ã«ã datastore
ãšã㊠rapidash
ãæå®ãããå Žå㯠create
å®è¡åã®ã¿ã€ãã³ã°ã§ other-plugin
ãšãããã©ã°ã€ã³ã䜿çšãããããšã瀺ããŠããŸãã
dao:
datastore:
db:
before-create:
- request-time
before-update:
- request-time
rapidash:
before-create:
- other-plugin
entity
entity.name
entity
ãšããããã±ãŒãžåãå€æŽããããã«äœ¿çšããŸãã
entity
ã®åœ¹å²ã¯ãã®ãŸãŸã«ãååã ããå€æŽãããå Žåã«å©çšããŸã
entity.plugins
entity
ã®ãã¡ã€ã«ãèªåçæããéã«äœ¿çšãããã©ã°ã€ã³ã®ãªã¹ããæå®ããŸã
model
model.name
model
ãšããããã±ãŒãžåãå€æŽããããã«äœ¿çšããŸãã
model
ã®åœ¹å²ã¯ãã®ãŸãŸã«ãååã ããå€æŽãããå Žåã«å©çšããŸã
repository
repository.name
repository
ãšããããã±ãŒãžåãå€æŽããããã«äœ¿çšããŸãã
repository
ã®åœ¹å²ã¯ãã®ãŸãŸã«ãååã ããå€æŽãããå Žåã«å©çšããŸã
context
eevee
ã§ã¯ãã¢ããªã±ãŒã·ã§ã³å€éšãšãããšãããå Žé¢ã§ã¯åžžã«APIã®ã€ã³ã¿ãŒãã§ãŒã¹ã« context.Context
ãå©çšããŸãã
ã§ããã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠã¯ãç¬èªã® context
ããã±ãŒãžã䜿çšãããå Žåãããã§ãããã
ãããã£ãã±ãŒã¹ã«å¯Ÿå¿ã§ããããã context
ããã±ãŒãžã®ã€ã³ããŒãå
ãã«ã¹ã¿ãã€ãºããããšãã§ããŸãã
context.import
ããã©ã«ãã®ã€ã³ããŒãå
( context
) ãæå®ãããã¹ã§ã®ã€ã³ããŒãã«çœ®ãæããŸãã
ã€ã³ããŒãå
ã®ããã±ãŒãžã§ type Context interface {}
ãå®çŸ©ãã context.Context
ãšã³ã³ããã®ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããããšã§ãã¢ããªã±ãŒã·ã§ã³ç¬èªã® context
ã«å·®ãæ¿ããããšãã§ããŸãã
plural
èªåçæã³ãŒãã«è€æ°åœ¢ã®ååãçšãããå Žåãã¯ã©ã¹ãã¡ã€ã«ã§æå®ãããååãå©çšããŠèªåçã«å€æããŠããŸãã
ã§ããããã¹ãŠã®è±åèªãæ£ããå€æã§ããããã§ã¯ãªãããã
èªåçæãããååãééã£ãŠããå Žåã¯ãæ£ããååãåå¥ã«æå®ããå¿
èŠããããŸãã
plural[].name
è€æ°åœ¢ã«ããå Žåã®ååãæžããŸã
plural[].one
åæ°åœ¢ã®å Žåã®ååãæžããŸã
renderer
renderer.style
ã¯ã©ã¹ãã¡ã€ã«ã®ã¡ã³ãããšã«ã¬ã³ããªã³ã°æã®æåãæå®ããã®ãé¢åãªå Žåã¯ã ãã®ãã©ã¡ãŒã¿ãæå®ããããšã§äžæ¬ã§æåãå€æŽããããšãã§ããŸãã
- lower-camel : åºåæã« lowerCamelCase ãå©çšãã
- upper-camel : åºåæã« UpperCamelCase ãå©çšãã
- lower-snake : åºåæã« lower_snake_case ãå©çšãã
primitive_types
éåžžãã¯ã©ã¹ãã¡ã€ã«ã®ã¡ã³ãã«ã¯ Go ã®ããªããã£ãåã®ã¿ãæå®ããã®ã§ããã ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠã¯ããªããã£ãåãæ¡åŒµããåãçšãããå Žåãããã§ãããã
(äŸ)
type ID uint64
func (id ID) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprint(id)) // bigint ããã³ãŒãã§ããªãã¯ã©ã€ã¢ã³ãã®ããã«ãæååãšããŠåºå
}
äžèšã®ãããªã±ãŒã¹ã§ã¯ã以äžã®ããã« .eevee.yml
ã«èšè¿°ããŠããããšã§ã¯ã©ã¹ãã¡ã€ã«å
㧠ID
åãå©çšã§ããããã«ãªããŸãã
primitive_types:
- name: ID
package_name: entity
default: 1
as: uint64
primitive_types[].name
åã®ååãèšè¿°ããŸã
primitive_types[].package_name
察象ã®åãã©ã®ããã±ãŒãžã«å±ããããæå®ããŸã
primitive_types[].default
ãã®åã«å€ããå€ãåºåããéã®ããã©ã«ãå€ãæå®ããŸã ( ãã¹ãããŒã¿ã®èªåçæã«äœ¿çšããŸã )
primitive_types[].as
é¢é£ããããªããã£ãåãæå®ããŸã
ã¯ã©ã¹ãã¡ã€ã«
ã¯ã©ã¹ãã¡ã€ã«ã¯ãeevee ã Go ã®ãœãŒã¹ã³ãŒããèªåçæããéã«èªã¿èŸŒããã¡ã€ã«ã§ãã
åºæ¬çã«ã¯ã¹ããŒããšã¯ã©ã¹ãã¡ã€ã«ã¯ 1:1
ã®é¢ä¿ã«ãªããŸãã
ãã ããã¯ã©ã¹ãã¡ã€ã«ãäœãããã«å¿
ãã¹ããŒããæžããªããšãããªãããã§ã¯ãªãã
æã§ãŒãããæžãããšãå¯èœã§ãã
ããã¯äŸãã°ãã¯ã©ã¹ãã¡ã€ã«ãäœããããããã®ã¯ã©ã¹ã«å¯Ÿå¿ããããŒã¿ã®ä¿åå
ã RDBMS ã§ãªãå Žåãªã©ã«çšããŸã ( äŸãã° KVS ã«ä¿åãããªã© )
ããã§ã¯ã説æã®ããã«ã¹ããŒããã¡ã€ã«ãããåæã§ã
ããããã¯ã©ã¹ãã¡ã€ã«ãèªåçæããæµãã説æããŸãã
ãŸããäŸãšããŠä»¥äžã®ãããªã¹ããŒããæã€ããŒãã«ããã¯ã©ã¹ãã¡ã€ã«ãçæããŸãã
CREATE TABLE `users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`sex` enum('man','woman') NOT NULL,
`age` int NOT NULL,
`skill_id` bigint(20) unsigned NOT NULL,
`skill_rank` int NOT NULL,
`group_id` bigint(20) unsigned NOT NULL,
`world_id` bigint(20) unsigned NOT NULL,
`field_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_users_01` (`name`),
UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`),
KEY `idx_users_03` (`group_id`),
KEY `idx_users_04` (`world_id`, `field_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ãã®ã¹ããŒãã schema/users.sql
ãšããŠä¿åããããšã
eevee init -s schema -c config
ãšã㊠.eevee.yml
ãçæãã eevee run
ããŠäœæããã config/user.yml
ã¯ä»¥äžã®ããã«ãªããŸãã
name: user
datastore: db
index:
primary_key: id
unique_keys:
- - name
- - skill_id
- skill_rank
keys:
- - group_id
- - world_id
- field_id
members:
- name: id
type: uint64
- name: name
type: string
- name: sex
type: string
- name: age
type: int
- name: skill_id
type: uint64
- name: skill_rank
type: int
- name: group_id
type: uint64
- name: world_id
type: uint64
- name: field_id
type: uint64
ãã®å 容ãããšã«ãåºæ¬çãªãã©ã¡ãŒã¿ã®èª¬æãããŸãã
name
ã¯ã©ã¹åãèšèŒããŸããã¹ããŒãããçæããå Žåã¯ãã¹ããŒãåã®åæ°åœ¢ã«ãªããŸã
datastore
dao
ã§ãããšãããå€éšã®ããã«ãŠã§ã¢ã®çš®é¡ãèšè¿°ããŸãã
ã¯ã©ã¹ãã¡ã€ã«ãèªåçæããå Žåã .eevee.yml
ã§èšå®ããããã©ã«ãã® datastore
ãæžã蟌ãŸããŸãã ( ããã©ã«ã㯠db
ã§ã )
datastore: none
ãšãããšã eevee
ã§çšæããŠããèªåçæã³ãŒããäœã䜿çšãããªãç¶æ
㧠dao
ã®ãœãŒã¹ã³ãŒããçæãããŸã ( ååã¯ç©ºã®ãã¡ã€ã«ã«ãªããŸã )ã
ãã®æ©èœã¯ã eevee
ã®èªåçæç³»ã«ã¯ä¹ããããèªåã§ãã¡ã€ã«ã®å
容ããã¹ãŠã«ã¹ã¿ãã€ãºãããå Žåãªã©ã«æå¹ã§ãã
index
ã¹ããŒãã«èšè¿°ãã PRIMARY KEY
, UNIQUE KEY
, KEY
ã®èšå®ãåæ ãããã®ã«ãªããŸãã
åºæ¬çã«ãã®éšåãæåã§ç·šéããå¿
èŠã¯ãããŸãã
members
ã¹ããŒãã®åã«ã©ã ã«å¯Ÿå¿ããå®çŸ©ãèšè¿°ããŸãã
åºæ¬çã«ã¯ name
ãš type
ã®çµã¿åãããšãªãã name
ã¯ã«ã©ã åã type
㯠SQL ã§ã®åã Go
ã®åã«å€æãããã®ãå©çšãããŸãã
以äžãããŒã¹ã®ãã©ã¡ãŒã¿ã«ãªããŸãããã®ãŸãŸã§ãå©çšã§ããŸããã eevee
ããã€ããŒãã«éã®åç
§è§£æ±ºæ©èœãå©çšããããã«ãããã€ãã®ãã©ã¡ãŒã¿ãè¿œå ããŸãã
以äžã® YAML
å®çŸ©ãåç
§ããŠãã ããã
name: user
members:
... ( çç¥ ) ...
- name: user_fields
extend: true
has_many: true
relation:
to: user_field
internal: id
external: user_id
- name: skill
extend: true
render:
inline: true
relation:
to: skill
internal: skill_id
external: id
- name: group
extend: true
render:
json: group
relation:
custom: true
to: group
- name: world
extend: true
render: false
relation:
to: world
internal: world_id
external: id
members
ã«æ°ãã user_fields
, skill
, group
, world
ãè¿œå ããŸããã
ããããã® member
ã§å©çšãããŠãããã©ã¡ãŒã¿ã¯ä»¥äžã®ãããªãã®ã§ãã
member.extend
extend: true
ãšããŠå®çŸ©ããã¡ã³ãã¯ã entity
ã®ã¡ã³ãå€æ°ã«ã¯çŸããã model
ã®ã¡ã³ãå€æ°ã«ã®ã¿è¿œå ãããããšãæå³ããŸãã
eevee
ã¯èªåçææã« entity
ã model
ãšãã£ãããã±ãŒãžãçæããŸããã
entity
ã«ã¯ã·ãªã¢ã©ã€ãºå¯Ÿè±¡ã®ã¡ã³ãå€æ°ã®ã¿ãããããã¢ããªã±ãŒã·ã§ã³ããžãã¯ãèšè¿°ããäžã§å¿
èŠãªç¶æ
å€æ°ãªã©ã¯ model
ã®ã¡ã³ãå€æ°ãšããŠå®çŸ©ããããšãæšå¥šããŠããŸãã
member.render
model
ãšããŠå®çŸ©ããããªããžã§ã¯ãã JSON
ãªã©ã«ãšã³ã³ãŒãããéã®ãµããŸããã«ã¹ã¿ãã€ãºããããã«äœ¿çšããŸãã
member.render
ã«ã¯è€æ°ã®æžãæ¹ãååšããŸãã
render: name
: æå®ããååãkey
ã«ããŠå€ãåºåããŸãrender: false
:false
ãæå®ãããšãšã³ã³ãŒãã»ãã³ãŒãã®å¯Ÿè±¡ã«ãªããŸããrender: inline
:inline
ãæå®ãããšãåŸè¿°ããrelation
ãååšããå Žåã«relation
å ã®ãªããžã§ã¯ãããšã³ã³ãŒãããçµæ ( key: value ã®ã㢠)ãèªèº«ã®åºåçµæã«ããŒãžããŸã
render:
json: lowerCamelName
yaml: lower_snake_name
ã®ããã«ãã¬ã³ããªã³ã°ãããã³ã«ããšã«ãšã³ã³ãŒãã»ãã³ãŒãæã®ååãå€æŽããããšãã§ããŸãã json
ã msgpack
ãªã©ãè€æ°ã®ãããã³ã«ã«å¯Ÿå¿ãããå Žåã¯ãã®èšæ³ãå©çšããŠãã ããã ( äœãèšå®ããªãå Žåã¯ã lowerCamelCase
ã䜿çšãããŸã )
member.relation
ã¹ããŒãéã®äŸåé¢ä¿ãå®çŸ©ããããã®ãã©ã¡ãŒã¿ã§ãã
ãã®ãã©ã¡ãŒã¿ãå®çŸ©ããããšã«ãã£ãŠã
äŸåå
ã®ã€ã³ã¹ã¿ã³ã¹ãååŸããããã®ã¢ã¯ã»ãµãèªåçæãããããã«ãªããŸãã
member.relation.to
äŸåå
ã®ã¯ã©ã¹åãæžããŸããããã§ã®ã¯ã©ã¹åãšã¯ãã¯ã©ã¹ãã¡ã€ã«ã® name
ãã©ã¡ãŒã¿ã§ãã
member.relation.internal
äŸåå ã®ã€ã³ã¹ã¿ã³ã¹ãååŸããããã«å©çšããèªã¯ã©ã¹ã®ã¡ã³ããŒã®ååãæå®ããŸãã
member.relation.external
äŸåå ã®ã€ã³ã¹ã¿ã³ã¹ãååŸããããã«å©çšããäŸåå ã¯ã©ã¹ã®ã¡ã³ããŒã®ååãæå®ããŸãã
member.relation.custom
ã¯ã©ã¹éã®çŽä»ãã«ãŒã«ãè€éãªå Žåãªã©ã internal
, external
ã®æ ã«ãšããããã«äŸåå
ã®ã€ã³ã¹ã¿ã³ã¹ãååŸãããå Žåã«å©çšããŸãã
ãã®ãã©ã¡ãŒã¿ãš internal
, external
ãã©ã¡ãŒã¿ã䜵çšããããšã¯ã§ããŸããã
member.relation.all
äŸåå
ã¯ã©ã¹ã®å€ããã¹ãŠååŸãããå Žåã«å©çšããŸããinternal
, external
ãã©ã¡ãŒã¿ãšäœµçšããããšã¯ã§ããŸããã
ãã®ä»ã«ãã以äžã®ãã©ã¡ãŒã¿ãå©çšã§ããŸãã
member.desc
ãã®ã¡ã³ãã®åœ¹å²ãææ¡ããããã®ããã¥ã¡ã³ããèšè¿°ããŸãã
ãã®ãã©ã¡ãŒã¿ã¯ APIããã¥ã¡ã³ããèªåçæããéã«å©çšãããŸãã
member.example
ãã®ã¡ã³ãããšãå€ã®äŸãèšè¿°ããŸããããã§æå®ããå€ã¯ãAPIããã¥ã¡ã³ãã®èªåçæã«å©çšãããä»ããã¹ãæã®ã¢ãã¯ãªããžã§ã¯ãäœæçšããŒã¿ãšããŠãå©çšãããŸãã
read_only
read_only: true
ãšæžããšããã®ã¯ã©ã¹ã¯èªã¿èŸŒã¿å°çšãšè§£éããã
CRUD ã®ãã¡ READ æäœãè¡ã API ã®ã¿èªåçæãããŸãã
å©çšäŸãšããŠã¯ãã¢ããªã±ãŒã·ã§ã³éçºã§ããè¡ãããã
管çè
åŽã§ãããããçšæããããŒã¿ã»ãã(ãã¹ã¿ãŒããŒã¿)ã«çšããããšãã§ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®å©çšè
åŽãã API ãéããŠå€æŽã§ããããŒã¿ã§ãªãå Žå㯠read_only: true
ãæå®ãããšå®å
šã«éçºããããšãã§ããŸãã
type
ã®æžãæ¹ã«ã€ããŠ
member.type
ã¯è€æ°ã®èšè¿°æ¹æ³ããããŸãã
ãã£ãšãã·ã³ãã«ãªã®ã¯ãåããã®ãŸãŸæžãæ¹æ³ã§ããäŸãã°ä»¥äžã®ããã«æžãããšãã§ããŸãã
members:
- name: a
type: interface{}
- name: b
type: map[string]interface{}
- name: c
type: *time.Time
ããããäžèšã® time
ããã±ãŒãžã¯ Go
æšæºã® time
ããã±ãŒãžã§ããããã
ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠã¯ãå¥ã® time
ããã±ãŒãžãåç
§ããããããããŸããã
ãã㧠eevee
ã§ã¯æ¬¡ã®ãããªèšè¿°æ¹æ³ããµããŒãããŠããŸãã
members:
- name: d
type:
import: time
package_name: time
name: Time
is_pointer: true
ãã®ããã«æžããšãããã±ãŒãžã®ã€ã³ããŒããã¹ã¯ time
ã§ããã±ãŒãžã®åå㯠time
ãåå㯠Time
ã§ãã€ã³ã¿ã§ãããšããããšãæå³ããŸãã
ãã®èšæ³ã¯ã¢ããªã±ãŒã·ã§ã³ã§å®çŸ©ããåæ
å ±ããµãŒãããŒãã£è£œã®ã©ã€ãã©ãªã§
å©çšãããŠããæ§é äœãå®çŸ©ãããå Žåã«æå¹ã§ãã
API å®çŸ©ãã¡ã€ã«
API ãªã¯ãšã¹ãã®ãã©ã¡ãŒã¿ã Go ã®æ§é äœãžãããã³ã°ããåŠçããã¬ã¹ãã³ã¹ã«çšãã JSON æååã®äœææ¯æŽãè¡ãæ©èœãå©çšããããã®èšå®æ¹æ³ã«ã€ããŠèª¬æããŸãã
ã¯ããã«ãAPIå®çŸ©ã¯ YAML
ãçšããŠèšè¿°ããŸããããã®ãã¡ã€ã«ãæ ŒçŽãããã£ã¬ã¯ããªã
eevee
ã«æããããã«ã .eevee.yml
ã«æ¬¡ã®ããã«æå®ããŸãã
.eevee.yml
api: config/api
äžèšã®ããã«èšå®ãããšã config/api
é
äžã® YAML
ãã¡ã€ã«ãèªã¿ã«è¡ãã
èªåçæãèµ°ãããã«ãªããŸãã
次ã«ããŠãŒã¶ãŒæ
å ±ãè¿ã API ãäŸã« YAML
ã®æžãæ¹ã«ã€ããŠèª¬æããŸãã
APIã®ååã user_getter
ãšãã次ã®ããã«å®çŸ©ããŸããã
- name: user_getter
desc: return user status
uri: /users/:user_id
method: get
response:
subtypes:
- name: user_getter_subtype
members:
- name: user
type: user
render:
inline: true
- name: param1
type: string
- name: param2
type: int
include:
- name: user
only:
- name
- param1
- param2
include:
- name: user_fields
only:
- field_id
include:
- name: field
only:
- name
type:
members:
- name: users
type: user
has_many: true
- name: sub
type: user_getter_subtype
include:
- name: user
only:
- id
- name
include:
- name: user_fields
only:
- field_id
説æã®ããã«ããããŠè€éãªã¬ã¹ãã³ã¹ãå®çŸ©ããŠã¿ãŸããã
倧äºãªã®ã¯ response
ã®éšåã§ãããã«åºåãããã¬ã¹ãã³ã¹ã®æ§é ãèšè¿°ããŠãããŸãã
APIã¯ãªã¹ãã§èšè¿°ããŸããã€ãŸãã1ã€ã®ãã¡ã€ã«ã«è€æ°ã®APIå®çŸ©ãæžãããšãã§ããŸãã
name
APIåãèšè¿°ããŸãããã®ååãå©çšããŠãªã¯ãšã¹ããã¬ã¹ãã³ã¹ãåŠçããããã®æ§é äœãäœæããŸã
desc
API ã®èª¬æãèšè¿°ããŸããããã¥ã¡ã³ãã«åæ ãããŸã
uri
API ã«ã¢ã¯ã»ã¹ããããã® URI ãèšè¿°ããŸããããã¥ã¡ã³ãã«åæ ãããŸãã
method
HTTP ã¡ãœãã ( get
post
put
delete
ãªã© ) ãèšèŒããŠãã ããã
æå®ããã¡ãœããã«ããããŠããªã¯ãšã¹ããã©ã¡ãŒã¿ã®ãã³ãŒãåŠçãå€åããŸãã
response
response
ã«ã¯ subtypes
ãš type
ãèšè¿°ããããšãã§ããŸã
response.type
ã¬ã¹ãã³ã¹çšã®æ§é äœã®å®çŸ©ãèšè¿°ããŸãã
èšè¿°æ¹æ³ã¯ãã¯ã©ã¹ãã¡ã€ã«ãšåãããã«ã members
ãå®çŸ©ããŠè¡ããŸãã
response.subtypes
response.type
ãè¡šçŸããéã«éå±€æ§é ãäœãããå Žåãã
ä»ã®APIãšã¬ã¹ãã³ã¹æ§é ãã·ã§ã¢ãããå Žåãªã©ãããè€éãªæ§é ãèšè¿°ãããå Žåã«å©çšããŸãã
èšè¿°æ¹æ³ã¯ãã¯ã©ã¹ãã¡ã€ã«ãšåãããã«ã members
ãå®çŸ©ããŠè¡ããŸãã
subtypes
ã«ã¯ãªã¹ãæ§é ã§è€æ°ã® subtype
ãå®çŸ©ããããšãã§ããŸãã
response.type.include
( response.subtypes[].include
)
type
, subtype
ã«ã¯ã members
ã®ä»ã« include
ããããã£ããããŸãã
include
ãé©åã«å©çšããããšã§ãäŸåé¢ä¿ã«ãããã¹ãŠã®ã¯ã©ã¹ãååŸã»ã¬ã³ããªã³ã°ããã«ã
å¿
èŠãªéšåã ããã¬ã¹ãã³ã¹ã«å«ããããšãã§ããŸãã
include.name
ã¬ã¹ãã³ã¹ã«å«ãããã¡ã³ãã®ãã¡
- ã¯ã©ã¹ãã¡ã€ã«ã«å®çŸ©ãããŠãããã®
- subtype ãšããŠå®çŸ©ãããŠãããã®
ã®ååãèšèŒããŸãã
include.only
include.name
ã§æå®ãããå®çŸ©ã®ãã¡ã members
ã®äžã§ã¬ã¹ãã³ã¹ã«å«ããããã®ãæå®ããŸãã
ããã§æå®ã§ããã®ã¯ããªã¬ãŒã·ã§ã³å®çŸ©ã®ãªãã¡ã³ãã®ã¿ã§ãã
â» include.except
ãšäœµçšããããšã¯ã§ããŸãã
include.except
include.name
ã§æå®ãããå®çŸ©ã®ãã¡ã members
ã®äžã§ã¬ã¹ãã³ã¹ã«å«ããããªããã®ãæå®ããŸãã
ããã§æå®ã§ããã®ã¯ããªã¬ãŒã·ã§ã³å®çŸ©ã®ãªãã¡ã³ãã®ã¿ã§ãã
â» include.only
ãšäœµçšããããšã¯ã§ããŸãã
include.include
include.name
ã§æå®ãããå®çŸ©ã®ãã¡ã members
ã®äžã§ãªã¬ãŒã·ã§ã³å®çŸ©ããã€ã¡ã³ãã«å¯ŸããŠã
ã¬ã¹ãã³ã¹ã«å«ããããã®ã®å®çŸ©ãèšè¿°ããŸãã
ååž°çã«èšè¿°ããŠããããšãå¯èœã§ãã
include_all
include_all: true
ãšæå®ãããšããã¹ãŠã®äŸåå
ã¡ã³ããå«ããŸãã
( ãã ããã¯ã©ã¹ãã¡ã€ã«åŽã§ render: false
ãæå®ãããŠããå Žåã¯åºåãããŸãã )
åæ©èœã«ã€ããŠ
ã¹ããŒãé§åéçºã«ãããã¢ãã«ã»ãªããžããªå±€ã®èªåçæ
eevee
ã¯ã¹ããŒãé§åéçºãåæãšããŠããŸãã
ã¯ããã«ã¹ããŒããå®çŸ©ããŠãããèªã¿èŸŒãããšã§ ã¯ã©ã¹ãã¡ã€ã« ãçæãã
å¿
èŠã§ããã°ããŒãã«éã®äŸåé¢ä¿ãªã©ãæžã足ããäžã§ Go ã®ãœãŒã¹ã³ãŒããèªåçæããŸãã
ããããŠããŒã¿ãæ±ããããããAPIãå€ãæã£ãã¢ãã«ãšã
ãã®ã¢ãã«ãååŸããããã®ãªããžããªã¬ã€ã€ãŒãèªåçæããããšã§ã¢ããªã±ãŒã·ã§ã³éçºãå¹ççã«è¡ãããšãã§ããŸãã
èªåçæãããããã±ãŒãžã¯å€§ãŸãã«ä»¥äžã®å³ã®ãããªäŸåé¢ä¿ãæã¡ãŸã
å³ã¯äžçªå·Šããå³ãžããŸãã¯äžçªå³ããå·Šãžç¢å°ã®åãã«æ²¿ã£ãŠèŠãŸãã
ããžãã¹ããžãã¯ãã eevee
ã®æ©èœãå©çšããå Žåã repository
ãš model
ããã±ãŒãžãå©çšããŸãã
repository
, model
ã¯è£ã§ dao
ããã±ãŒãžãå©çšããŸãã dao
㯠DataAccessObject
ã®ç¥ã§ãã¢ããªã±ãŒã·ã§ã³å€éšã®ããã»ã¹ãšããŒã¿ããããšãããããã®ããŒã¬ãã«ãªAPIãæäŸããŸãã
dao
ãå€éšãšãããšãããå Žåãå¿
ã entity
ããã±ãŒãžãå©çšããŸãã
entity
ã«ã¯ã·ãªã¢ã©ã€ãºå¯èœãªããŒã¿æ§é ãå®çŸ©ãããŠããã
ãã®ããŒã¿æ§é ãéã㊠dao
ãé©åã«ã·ãªã¢ã©ã€ãºã»ãã·ãªã¢ã©ã€ãºããããšã§å€éšãšã®ãããšããå®çŸããŸãã
ããŒã¿ã®èªã¿èŸŒã¿æ¹åã«æ³šç®ãããšä»¥äžã®å³ã®ããã«ãªããŸãã
倧ããã 1 ãš 2 ã® 2éãã®èªã¿èŸŒã¿æ¹æ³ããããŸãã
ãŸãã¢ããªã±ãŒã·ã§ã³ããããŒã¿ãååŸããããšæã£ãå Žåã¯ã repository
ãå©çšããŸãã repository
ãæäŸãã CRUD
API ãéã㊠dao
ãçµç±ãã€ã€ããŒã¿ãååŸããŸãããã®ãšãã dao
ãæ±ãããŒã¿æ§é 㯠entity
ã®ãããã¢ããªã±ãŒã·ã§ã³ããå©çšããããããã« model
ã«å€æããããšãè¡ããŸãã
ããã²ãšã€ã¯ã model
ãéããŠè¡ãèªã¿èŸŒã¿æäœã§ãã
åŸè¿°ããŸããã model
ã«ã¯ãªã¬ãŒã·ã§ã³é¢ä¿ã«ããå¥ã®ããŒãã«ããŒã¿ãå¹ççã«ååŸããæ©èœããããŸãããããã£ãæ©èœãå©çšããå Žåã¯ã model
ãè£ã§ repository
ãçµç±ããŠããŒã¿ãååŸããŸãã
äžæ¹ãããŒã¿ã®æžã蟌ã¿æ¹åã«æ³šç®ãããšä»¥äžã®å³ã®ããã«ãªããŸãã
ãã¡ãã 2 éãã®æ¹æ³ããããã·ã³ãã«ãªã®ã¯ repository
ã䜿ã£ããã®ã§ãã
repository
ã«ã¯ãã®ãŸãŸ CRUD
ãã§ãã API ãããã®ã§ããã¡ããéã㊠Create
, Update
, Delete
ãå®è¡ããã°ã dao
ãéããŠæžã蟌ã¿æäœãåæ ãããŸãã
äžæ¹ã model
ãéããŠæžã蟌ãããšãå¯èœã§ãã
ãã®å Žåã¯ãã¢ãã«ã®å
容ãäœæã»ãŸãã¯æŽæ°ããããã®ã«æžãæããåŸã« Save()
ãåŒã¶ããšã§è¡ãããšãã§ããŸãã
ããããŠã Create
Update
Delete
ãšãã£ãçŽæç㪠API ãçšæããŠããã®ã§ãçšéã«ãã£ãŠäœ¿ãåããããšãå¯èœã§ãã
ã¢ãã«éã®äŸåé¢ä¿ã®èªå解決
ã¯ã©ã¹ãã¡ã€ã« ã«ããŒã¿ã®äŸåé¢ä¿ãé©åã«èšè¿°ããããšã§éçºãå¹ççã«é²ããããšãã§ããããã«ãªããŸãã
äŸãã°ã users
ããŒãã«ã® id
ã«ã©ã ã®å€ã«å¯Ÿå¿ãã user_id
ãšããã«ã©ã ãæã£ã user_fields
ããŒãã«ãèããŠã¿ãŸãããã
ããã§ã users
ããŒãã«ã®ã¬ã³ãŒããååŸããŠãã user_fields
ã®ã¬ã³ãŒããååŸããã«ã¯ãé垞次ã®ããã«æžããšæããŸãã
user, _ := repo.User().FindByID(ctx, 1)
userFields, _ := repo.UserField().FindByUserID(ctx, user.ID)
ããããäž¡è ã®äŸåé¢ä¿ã ã¯ã©ã¹ãã¡ã€ã« ã«èœãšããšæ¬¡ã®ããã«æžããŸã
name: user
members:
... ( çç¥ ) ...
- name: user_fields
extend: true
has_many: true
relation:
to: user_field
internal: id
external: user_id
äžèšã¯
user
ã¯ã©ã¹ã¯user_field
ã¯ã©ã¹ãšäŸåé¢ä¿ã«ãããuser_fields
ãšããååã®ã¡ã³ãã§ãã®äŸåé¢ä¿ãè¡šçŸãããŠããuser
=>user_field
ã®åç §ã¯ãuser
ã¯ã©ã¹ã®id
ã¡ã³ããšuser_field
ã¯ã©ã¹ã®user_id
ã¡ã³ãã®å€ãèŠãŠè¡ãããuser
=>user_field
ã®é¢ä¿ã¯has_many
é¢ä¿ã«ããã®ã§ãè€æ°ã®user_field
ã€ã³ã¹ã¿ã³ã¹ãååŸãã- ãã®ã¡ã³ãã¯
extend: true
ãã€ããŠããã®ã§ã·ãªã¢ã©ã€ãºå¯Ÿè±¡ã§ã¯ãªã (entity
ã«ã¯åæ ãããªã )
ãšãã£ãããšãè¡šããŠããŸãã
ãã®ç¶æ
㧠eevee run
ãå®è¡ã㊠Go ã®ãœãŒã¹ã³ãŒããèªåçæãããšãã¯ããã«æžãã Go
ã®ã³ãŒãã¯æ¬¡ã®ããã«æžãããšãã§ããããã«ãªããŸãã
user, _ := repo.User().FindByID(ctx, 1)
userFields, _ := user.UserFields(ctx)
ãã®æ©èœãçšããããšã§ãäŸåé¢ä¿ã«ããã¯ã©ã¹ã®å€ãç°¡åãã€å®å
šã«ååŸããããšãã§ããããã«ãªããŸãã
ãŸããã®ã¢ã¯ã»ã¹ã¯éåžžã«å¹çããè¡ãããã®ã§ãäŸãã°æ¬¡ã®ãããªã³ã¬ã¯ã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ã«å¯ŸããŠè¡ãããéã«ç¹ã«æå¹ã§ãã ãã®äŸã§ã¯éåžž N + 1
åã¯ãšãªãçºè¡ãããŠããŸãããã«æãããŸãããå®éã«ã¯ Eager Loading
ãè¡ããã2床ã®ã¯ãšãªçºè¡ã®ã¿ã«ãªããŸãããã®ãããã®è©³çŽ°ã¯æ¬¡ã®é
ç®ã§èª¬æããŸãã
user, _ := repo.User().FindByID(ctx, 1)
userFields, _ := user.UserFields(ctx)
userFields.Each(func(userField *model.UserField)) {
// æ®éã¯ãã㧠SELECT * FROM fields WHERE id = { user_field.field_id } ã®ãããªã¯ãšãªãçºè¡ãããããå¹çãæªããã
// eevee ã§ã¯ N+1 ã¯ãšãªãåé¿ã§ãã ( åŸè¿° )
field, _ := userField.Field(ctx)
}
ãã®æ©èœã®éèŠãªç¹ã¯ãããã¯ã©ã¹ãé¢é£ããããŒã¿ããã¹ãŠãã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ããååŸããããšãã§ãããšããããšã§ããããã«ãã£ãŠã( ãšã©ãŒåŠçãå ¥ãã®ã§å®éã«ã¯å©çšæã¯ç°ãªããŸãã ) ãã§ãŒã³ã¢ã¯ã»ã¹ã§äŸåããŒã¿ãååŸããããšãã§ããããAPI ã¬ã¹ãã³ã¹ã«ããã€ã³ã¹ã¿ã³ã¹ã®é¢é£ããŒã¿ããã¹ãŠåæ ãããããããšãã§ããããã«ãªããŸãã
Eager Loading
/ Lazy Loading
ãå©çšããå¹ççãªããŒã¿åç
§
åé
ã§è§ŠããŸãããã eevee
ã«ã¯ã¢ãã«éã®äŸåé¢ä¿ã解決ããæ©èœããããŸãã
ãã®æ©èœãæäŸããäžã§å€§åã«ããã®ã¯æ¬¡ã®2ç¹ã§ãã
N+1
åé¡ãèµ·ãããªãããš- äžå¿ èŠãªããŒã¿ãèªãŸãªãããš
ããããã©ã®ããã«è§£æ±ºããŠããã®ãã説æããŸãã
Eager Loading
ãçšãã N + 1
åé¡ã®è§£æ±º
ã¢ãã«ãã€ã³ã¹ã¿ã³ã¹åããéã eevee
ã§ã¯è€æ°ã®ã€ã³ã¹ã¿ã³ã¹ããŸãšããå Žåã
ã¹ã©ã€ã¹ã§ã¯ãªãã³ã¬ã¯ã·ã§ã³æ§é äœãå©çšããŸãã
äŸãã°è€æ°ã® user
ã€ã³ã¹ã¿ã³ã¹ãååŸããå Žå㯠[]*model.User
ã§ã¯ãªãã *model.Users
ãè¿åŽãããŸã
users, _ := repo.User().FindByIDs(ctx, []uint64{1, 2, 3})
// users 㯠[]*model.User ã§ã¯ãªã *model.Users
ã¹ã©ã€ã¹ã§ã¯ãªãæ§é äœãçšããããšã§ã
ãã®ã³ã¬ã¯ã·ã§ã³ã€ã³ã¹ã¿ã³ã¹èªäœãã¯ãšãªçµæã®ãã£ãã·ã¥ãæã€ããšãå¯èœã«ããŠããŸãã
äŸãã° _example/02_relation
ãäŸã«ãšããš https://github.com/blastrain/eevee/blob/master/_example/02_relation/model/user.go#L44-L52 ã«æžãããŠããéã Users
æ§é äœãšããŠå®çŸ©ããã skills
ã userFields
ãšãã£ããã£ãã·ã¥çšã®ã¡ã³ããæã£ãŠããããšã確èªã§ãããšæããŸãã
ã§ã¯ãã® skills
ã userFields
ã«å€ãå
¥ãã®ã¯ãã€ããšãããšã
äŸãã° skills
㯠FindSkill
ãåŒãã ãšãã§ãã ( ã€ãŸã user
ãã〠skillID
ã䜿ã£ãŠ 1:1
察å¿ãã skill
ãåŒãã¿ã€ãã³ã° )
https://github.com/blastrain/eevee/blob/master/_example/02_relation/model/user.go#L1396-L1409
ãã®ã¡ãœããã®åŠçãèªããšã skillID
ãå©çšã㊠skill
ãååŸããéã«ã finder.FindByID(skillID)
ãšããã®ã§ã¯ãªãã finder.FindByIDs(skillIDs)
ãšè€æ°ã® skillID
ã䜿ã£ãŠååŸããŠããã®ãããããšæããŸãã
ã€ãŸãã *model.Users
ã¯ãããããèªèº«ã管çãã *model.User
ããããã«å¯Ÿå¿ãã skillID
ã®éåã skillIDs
ãšããŠä¿æããŠãããã©ããã²ãšã€ã§ããã®äžã® skillID
ã䜿ã£ãŠ skill
ãæ€çŽ¢ããå Žåã¯ãä¿æããŠãããéåå€ã䜿ã£ãŠãã¹ãŠã® skill
ãååŸããŠããããã®äžããæå®ããã skillID
ã§ãã£ã«ã¿ãããããªæåããšããŸãã
ããã«ãã£ãŠãæ¯å skillID
ã§ã¯ãšãªãæããããšãé²ãã§ããã®ãããããšæããŸãããããã以äžã®ãããªäŸã§ã¯ã³ã¬ã¯ã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ã® FindSkill()
ãåŒã°ãããããªã€ã¡ãŒãžã沞ããªããããããŸããã
users, _ := repo.User().FindByIDs(ctx, []uint64{1, 2, 3})
users.Each(func(user *model.User)) {
// *model.User ãã skill ããšã£ãŠãããã
// æ¬åœã«ã³ã¬ã¯ã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ã«ã¢ã¯ã»ã¹ããŠããã®ã
skill, _ := user.Skill(ctx)
}
ãã®çãã¯ã repository
ããã±ãŒãžå
ã®æ¬¡ã®ç®æã«ãããŸãã
https://github.com/blastrain/eevee/blob/master/_example/02_relation/repository/user.go#L411-L435
å *model.User
ã®ä»ã€ã³ã¹ã¿ã³ã¹ãååŸããããã®ã¢ã¯ã»ãµã¯é¢æ°ãªããžã§ã¯ãã«ãªã£ãŠãããããããã®éšåã§äœã£ãŠããŸãã
ãã®ãšããã³ã¬ã¯ã·ã§ã³ã€ã³ã¹ã¿ã³ã¹ã®åç
§(ãšããã䜿ã£ãã¡ãœããã³ãŒã«)ãã¯ããŒãžã£ã䜿ã£ãŠéã蟌ããŠãããããå *model.User
ã€ã³ã¹ã¿ã³ã¹ã *model.Users
ã®ã¡ãœãããåŒã³åºãããšãå¯èœã«ãªã£ãŠããã®ã§ãã
ãªã®ã§äžèšã®ã³ãŒãã¯å®ã¯æ¬¡ã®ãããªåŠçã«ãªã£ãŠããŸãã
users, _ := repo.User().FindByIDs(ctx, []uint64{1, 2, 3})
users.Each(func(user *model.User)) {
// 1床ç®ã®ã¢ã¯ã»ã¹æã« SELECT * FROM skills WHERE id IN (1, 2, 3) çžåœã®ããšãè¡ã
// ååŸããçµæã users ã«ä¿æããŠãã
// users ãä¿æããŠããååŸçµæãã該åœã® skill ãæ€çŽ¢ãã
skill, _ := user.Skill(ctx)
}
Lazy Loading
ãçšããå¹ççãªããŒã¿åç
§
åé
ã§ãä»ã€ã³ã¹ã¿ã³ã¹ãžã®ã¢ã¯ã»ãµãé¢æ°ãªããžã§ã¯ãã«ãªã£ãŠããããšã説æããŸããã
ãã®ãããããŒã¿ãååŸãã«ããã®ã¯é¢æ°ãèªããšãã ãã«ãªããŸãã
ããã€ã³ã¹ã¿ã³ã¹ã«çŽã¥ãããŒã¿ãäžçªæåã«ãã¹ãŠåŒãã«è¡ã£ãŠããŸããšãç¡é§ãªããŒã¿ãå€ãåŒããŠããŸãå¯èœæ§ããããŸããã eevee
ã§ã¯ãã®ãããªããšã¯ãããŸããã
å¿
èŠãªãšãã«ãå¿
èŠãªã¶ãã ãããŒã¿ãåç
§ããããšãã§ããŸãã
ãã¹ãéçºãæ¯æŽãã mock ã€ã³ã¹ã¿ã³ã¹äœææ©èœ
eevee
㯠model
ã repository
ãšãã£ãããã±ãŒãžãèªåçæããã®ãšåæã«ã mock/repository
ãš mock/model/factory
ãšããããã±ãŒãžãçæããŸãã
ãããã¯ãã¹ãéçºæã« repository
å±€ãã¢ãã¯ããããšãæ¯æŽããŠãããŸãã
ã¢ããªã±ãŒã·ã§ã³éçºã«ããããã¹ãææ³ã«ã€ããŠããã§å€ãã¯è§ŠããŸãããã
ããŒã¿ããŒã¹ãªã©ã®ããã«ãŠã§ã¢ã«ã¢ã¯ã»ã¹ãããããªãã¹ãã±ãŒã¹ãæžãéãå®éã«ã¢ã¯ã»ã¹ããŠæ€èšŒããæ¹æ³ãšãã¢ãã¯ãå©çšããŠæ¬äŒŒã¢ã¯ã»ã¹ãè¡ãæ¹æ³ããããšæããŸãã
eevee
ã§ã¯ åŸè
ã®ã¢ãã¯ãçšããéçºãæ¯æŽããŠããã次ã®ããã« repository.Repository
ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ãã *repository.RepositoryMock
ã€ã³ã¹ã¿ã³ã¹ãè¿ãããšã§ã repository
å±€ã®ã¢ãã¯ãç°¡åã«è¡ããããã«ããŠããŸãã
ããããŠã model
ã€ã³ã¹ã¿ã³ã¹ã®ãã¡ã¯ããªããã±ãŒãžãæäŸããŠãããç°¡åã« repository
ã® API ã眮ãæãå¯èœã§ãã
import (
"app/mock/repository"
"app/mock/model/factory"
)
repo := repository.NewMock()
ctx := context.Background()
repo.UserMock().EXPECT().FindByID(ctx, 1).Return(factory.DefaultUser(), nil)
mock æã®ã€ã³ã¿ãŒãã§ãŒã¹ã¯ https://github.com/golang/mock ãåèã«ããŠããŸãã gomock
ãšéãåå®å
šãªã³ãŒããèªåçæããŠããã®ã§ãäŸãã°äžèšã® FindByID
ã«äžããåŒæ°ã®åã«åãããããã« 1
ã int64(1)
ãªã©ãšããå¿
èŠã¯ãããŸããã gomock
ã¯åŒæ°ã interface{}
ã§åããŠããããã©ã³ã¿ã€ã äžã«åãšã©ãŒãçºçããå ŽåããããŸãã ( ããããããã¥ãã )ããããã£ãå¿é
ã¯ãããŸããã
factory.DefaultUser()
ã®äžèº«ã¯ã testdata/seeds
é
äžã® YAML
ãã¡ã€ã«ãèªã¿èŸŒãã§èªåçæããŠããŸãã
åºæ¬çã«ã¯ã€ã³ã¹ã¿ã³ã¹ã®åæå€ã YAML
ãã¡ã€ã«ã«ååä»ãã§æžããŠãããšã
ãã®åå㧠factory.XXX
ãšãã圢ã§ã¢ãã«åæåçšã® API ãçšæããŠãããã®ã§ãããã䜿ããŸãã
ã¢ãã«ããJSONæååãžã®é«éãªå€æ
model
ããã±ãŒãžãèªåçæããŠãããšããèšèšäžã®ã¡ãªããã䜿ã£ãŠã
JSON
æååãžãšã³ã³ãŒãããåŠçãéçã«çæããŠããŸããããã«ãã£ãŠ reflect
èŠãããšãªã£ãŠããããã encoding/json
ãå©çšãã JSON
æååãžã®å€æããã倧åé«éã«ãªã£ãŠããŸãã
API ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ãšãã®ããã¥ã¡ã³ãã®èªåçæ
ãªã API ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ã®äœæãŸã§ãæ¯æŽããŠãããã
ãã㯠eevee
ããã€ã¡ãªãããæ倧é掻ããããã«ãã¬ã¹ãã³ã¹äœæãŸã§æ¯æŽããå¿
èŠããã£ãããã§ãããªã¯ãšã¹ãã®æ¹ã¯ã¬ã¹ãã³ã¹éçºãšåãä»çµã¿ã§éçºã§ããæ¹ã䟿å©ã ãããšããçç±ãããµããŒãããŠããŸãã
åã«èª¬æããŠããŸãããeevee
ãèªåçæããã¢ãã«ã€ã³ã¹ã¿ã³ã¹ã¯ããªã¬ãŒã·ã§ã³é¢ä¿ã«ããäŸåå
ã®ã€ã³ã¹ã¿ã³ã¹ãæ°ç ã€ãªãã§ãšã£ãŠããããšãã§ããŸãã
ã¢ãã«ã¯ãããã MarshalJSON
ãå®è£
ããŠããã json.Marshal(user)
ãšãã£ãããã«ãã®ãŸãŸåŒæ°ã«äžãããš JSON
æååã«å€æã§ããŸãã
ããã§ãããã©ã«ãã§ã¯ user
ã«çŽã¥ãäŸåå
ã®ã€ã³ã¹ã¿ã³ã¹ãå
šãŠå¯Ÿè±¡ã«ã㊠JSON
æååãžå€æããããšããŸãã
ããããããšã§ãäŸãã° user
ã«çŽã¥ãã¢ãã«ã®ã©ããã«äŸåé¢ä¿ãè¿œå ããå Žå ( ã¯ã©ã¹ãã¡ã€ã«ã«ã¡ã³ããè¿œå ãã )ãGo ã®ã³ãŒããäžåå€æŽããããšãªã JSON
ã«çµæãåæ ãããããšãã§ããŸãã
äžåºŠãã®ä»çµã¿ãå©çšãããšããããã©ãã ãéçºã楜ã«ããŠããããå®æã§ãããšæããŸãããã¡ãªããã°ããã§ã¯ãããŸããã
ãã¹ãŠã®äŸåå
ã€ã³ã¹ã¿ã³ã¹ãååŸããšã³ã³ãŒãããããšãããšããããšã¯ãããã ãæéããããã JSON
ã®ããŒã¿éã倧ãããªããŸãã
API ã«ãã£ãŠã¯ãäŸåå
ã®ç¹å®ã®éšåã ãå¿
èŠãªããšããå Žåãããã§ãããã
ããã§ã eevee
ã§ã¯ãåã¢ãã«ã« ToJSON
ãš ToJSONWithOption
ãšãã JSON
æåååã®ããã® 2çš®é¡ã®æ段ãçšæããŠããŸãã
ToJSON
㯠MarshalJSON
ã®å
åŽã§åŒã°ãã API ã§ãäŸåå
ããã¹ãŠå«ãã JSON
ãäœæããããšè©Šã¿ãŸãã
äžæ¹ ToJSONWithOption
ã¯ãåŒæ°ã§äžãããªãã·ã§ã³ã«ãã£ãŠãèªèº«ãäŸåå
ã¡ã³ãã®åæšéžæãã§ããããã«ãªã£ãŠããŸãããã®æ©èœãçšããããšã«ãã£ãŠãããã® API ã§ã¯ãã®ã¡ã³ãã ãè¿ãããšãã£ãããšã容æã«ã§ããããã«ãªããŸãã
ãšã¯ããããã®ãªãã·ã§ã³ã API äœæã®ãã³ã« Go
ã§èšè¿°ããã®ã¯å€§å€ã§ãã
ããã§ã Swagger
ãªã©ã® YAML
ãçšãã API éçºãåèã«ã
API ã¬ã¹ãã³ã¹ã«å¿
èŠãªã¡ã³ãã®åæšéžæãã§ããããã«ããäžã§ YAML
ã§èšè¿°ã§ããããã«ãããããèªã¿èŸŒã㧠ã¬ã¹ãã³ã¹äœæã«å¿
èŠãªãœãŒã¹ã³ãŒããèªåçæããæ©èœããµããŒãããŠããŸãã
ãã©ã°ã€ã³ãçšããæè»ãªã«ã¹ã¿ãã€ãº
eevee
ãèªåçæããããã±ãŒãž ( entity
, dao
, repository
, model
) ã®ãã¡ãã¢ããªã±ãŒã·ã§ã³ããšã«èšå®ãå¿
èŠãªéšåã¯äž»ã« dao
ã®éšåã§ãã
eevee ã«ããå®è·µçãªéçºæ¹æ³
watch ã¢ãŒããå©çšãã
eevee
ãçšããŠæ°çŸãè¶
ããã¯ã©ã¹ãã¡ã€ã«ãèšè¿°ããŠãããšã
åŸã
ã« eevee run
ã®æéãæ°ã«ãªãããã«ãªã£ãŠãããŸãã
ãŸãã ã¯ã©ã¹ãã¡ã€ã«ã dao
ã®ãœãŒã¹ã³ãŒããä¿®æ£ããå Žåã«ã
eevee run
ãå®è¡ããã®ãå¿ããŠããŸãã
èªåçæ察象ãæŽæ°ããã«ã³ãããããŠããŸããããªããšãèµ·ãããããããŸããã
ãããã£ãåé¡ã解決ããããã«ã
eevee
ã«ã¯ -w
ãªãã·ã§ã³ãã€ããŠèµ·åããããšã§ã
ãã¡ã€ã«å€æŽã€ãã³ããç£èŠããŠå€æŽããã£ããã¡ã€ã«ã«é¢é£ãããã¡ã€ã«ã ã
èªåçæãèµ°ãããæ©èœ ( watch
ã¢ãŒã ) ããããŸãã
- ã¯ã©ã¹ãã¡ã€ã«ã«äŸåå ã®å®çŸ©ãé©åã«èšè¿°
- ãã®ã¯ã©ã¹ãã¬ã¹ãã³ã¹ã«å«ãã
eevee -w
(watch
ã¢ãŒãã§ãã¡ã€ã«ç£èŠ )
ã®3ã€ãçµã¿åãããããšã§ãã«ã©ã è¿œå ãªã©æ¢åã®ããŒã¿æ§é ãå€ãããããªå Žé¢ã§ ã ã¯ã©ã¹ãã¡ã€ã« ( YAML
ãã¡ã€ã« ) ãå€æŽããç¬éã«ã¬ã¹ãã³ã¹å
容ãå€ããããšããéçºäœéšãåŸãããšãã§ããŸãã
ãã®äœéšã¯ä»ãŸã§ã®ã¢ããªã±ãŒã·ã§ã³éçºãå€ããã»ã©ã«è¯ãããã watch
ã¢ãŒãã®å©çšã匷ãå§ããŠããŸãã
repository ã« API ãè¿œå ãã
repository
ãçšããŠã¢ã¯ã»ã¹ã§ãã API ã¯ãã¹ããŒããã¡ã€ã«ã§å®çŸ©ããã€ã³ããã¯ã¹æ
å ±ã«åºã¥ããŠããŸãã ( PRIMARY KEY
ã UNIQUE KEY
, KEY
ãé©åã«èšå®ããããšã§ããããã®ã€ã³ããã¯ã¹ãçšãã API ãèªåçæãã repository
ãçšããŠã¢ã¯ã»ã¹ã§ããããã«ãªããŸã )
ãã®ããããŸãã¯ã€ã³ããã¯ã¹ãèŠçŽããŠçæããAPIã調æŽããŠããã ãããã§ããã
èªåçæ察象ã«ãªã£ãŠããã®ã¯ Equal
ã§æ¯èŒã§ãããã®ã ãã«ãªã£ãŠããŸãã
ããã§ã¯ç¯å²æ€çŽ¢ãè€éãªã¯ãšãªãçºè¡ãããå Žåã«å°ãã®ã§ã
eevee
ã«ã¯å¥œã㪠API ã repository
ã«è¿œå ã§ããæ©èœãååšããŸãã
repository
ã«ååšãã API ã¯ã dao
ã«ååšããå
¬é API ãããšã«èªåçæããŠããŸãã
( repository
ã¯å®å
šèªåçæã®ããã±ãŒãžã§ããåºæ¬çã«æåã§äœãåŠçãæžã足ãããšã¯ãããŸãã )
äŸãã°ã以äžã®ãã㪠dao
ããã±ãŒãžã®ãã¡ã€ã«ãããå Žå ( _example/01_simple/dao/user.go
)
package dao
import (
...
)
type User interface {
Count(context.Context) (int64, error)
Create(context.Context, *entity.User) error
Delete(context.Context, *entity.User) error
DeleteByID(context.Context, uint64) error
DeleteByIDs(context.Context, []uint64) error
FindAll(context.Context) (entity.Users, error)
FindByID(context.Context, uint64) (*entity.User, error)
FindByIDs(context.Context, []uint64) (entity.Users, error)
Update(context.Context, *entity.User) error
UpdateByID(context.Context, uint64, map[string]interface{}) error
UpdateByIDs(context.Context, []uint64, map[string]interface{}) error
}
( å®è£
ã¯çç¥ )
repository
ããã±ãŒãžã¯æ¬¡ã®ããã«ãªããŸãã
// Code generated by eevee. DO NOT EDIT!
package repository
import (
...
)
type User interface {
ToModel(*entity.User) *model.User
ToModels(entity.Users) *model.Users
Create(context.Context, *entity.User) (*model.User, error)
Creates(context.Context, entity.Users) (*model.Users, error)
FindAll(context.Context) (*model.Users, error)
FindByID(context.Context, uint64) (*model.User, error)
FindByIDs(context.Context, []uint64) (*model.Users, error)
UpdateByID(context.Context, uint64, map[string]interface{}) error
UpdateByIDs(context.Context, []uint64, map[string]interface{}) error
DeleteByID(context.Context, uint64) error
DeleteByIDs(context.Context, []uint64) error
Count(context.Context) (int64, error)
Delete(context.Context, *entity.User) error
Update(context.Context, *entity.User) error
}
( å®è£
ã¯çç¥ )
ã€ãŸãã dao
ã«å®çŸ©ãããŠããååã®ã¯ã©ã¹ã® interface
ã®å
容ã解æããŠã
entity
ã®è¿ãå€ã model
ã®ãã®ã«å€æããå
容ã repository
ã® interface
ã«åæ ãããŸãã
ãã®ã«ãŒã«ãå©çšãããšãäœã API ãè¿œå ãããå Žåã¯ä»¥äžã®ãããªæé ã§è¡ãããšãã§ããŸãã
dao
ã« API ãè¿œå ãã
package dao
import (
...
)
type User interface {
( çç¥ )
FindByRange(startAt time.Time, endAt time.Time) (entity.Users, error)
}
func (*UserImpl) FindByRange(startAt time.Time, endAt time.Time) (entity.Users, error) {
....
}
-
eevee run
ãå®è¡ -
repository.User
ã« API ãè¿œå ããã
package repository
import (
...
)
type User interface {
( çç¥ )
FindByRange(startAt time.Time, endAt time.Time) (*model.Users, error)
}
dao ã«å®è£ ãããŠããäžéšã® API ã®äžèº«ãèªç±ã«æžãå€ãã
ãrepository ã« API ãè¿œå ãããã§è¿°ã¹ãæ©èœãå®çŸããããã
dao
ããã±ãŒãžã®ãã¡ã€ã«ã¯åäžãã¡ã€ã«å
ã§èªåçæãšæåç·šéãæ··åšããããšã蚱容ããŠããã
èªåçæããŒã«ãŒ ã«ãã£ãŠå®çŸããŠããŸãã
dao
ã§èªåçæãããAPIã¯ãAPIæ¯ã« // generated by eevee
ãšããã³ã¡ã³ããä»äžãããŠããŸãã
ãã®ã³ã¡ã³ãã¯ã察象APIã eevee
ã«ãã£ãŠèªåçæããããã®ãªã®ããèŠåããããã«äœ¿çšãããŠãããã³ã¡ã³ãããªã API ã«ã¯èªåçæã®ä»çµã¿ãé©å¿ãããªãããã«ãªã£ãŠããŸãã
ãã®ãããèªåçæãããåŠçãã®ãã®ãä¿®æ£ãããå Žåãèªäœã®APIãªã©ã¯ã
ã³ã¡ã³ããä»ããŠããªãç¶æ³ã«ããŠããã ããã° eevee
åŽã§äžæžããªã©ã¯ããŸããã
model ã« API ãè¿œå ãã
model
ã®æ§é äœèªäœã«ã¡ã³ãå€æ°ãè¿œå ãããå Žåã¯ã
ã¯ã©ã¹ãã¡ã€ã«ã®èª¬æã®äžã§è§Šãã extend
ãã©ã¡ãŒã¿ãå©çšããŠãã ããã
extend: true
ãè¿œå ããããšã§ãã¢ãã«ã ãã«ä»»æã®ã¡ã³ãå€æ°ãè¿œå ããããšãã§ããŸãã
ãããšã¯å¥ã«ãã¬ã·ãŒãã¡ãœãããè¿œå ãããå ŽåãããããšæããŸãã
ãããã£ãå Žåã¯ãèªåçæããããã¡ã€ã«ãšã¯å¥ã®ãã¡ã€ã«ã§ ( äŸãã° model/user_api.go
ãªã© )
以äžã®ããã«å¥œã㪠API ãè¿œå ããŠãã ããã
model/user_api.go
package model
func (u *User) Hoge() {
...
}
relation.custom
ãå©çšãã
ã¯ã©ã¹éã®äŸåé¢ä¿ã解決ããéã«ãäŸåãããã©ã¡ãŒã¿ã®åå€æ§ä»¥å€ã§å€æãããã±ãŒã¹ããããŸãã
ã¢ãã«ã«ä»äžããç¶æ
å€æ°ã«ãã£ãŠ A ãš B ã®ã¯ã©ã¹ãåãæ¿ãããå ŽåããããããããŸããã
ãããã£ãå Žåã¯ãäŸå解決ãèªåã§å®è£
ã§ãã relation.custom
ãçšããŸãã
relation:
to: user_field
custom: true
ãªã©ãšæžãã°ã ãUserField
ã¯ã©ã¹ãåç
§ããããã®ã¡ã³ãå€æ°ã ããäŸå解決æ¹æ³ã¯èªäœããã
ãšãã£ãæå³ã«ãªããŸãã
èªåçæããéã¯
func (u *User) UserField(ctx context.Context) (*UserField, error) {
...
}
äžèšã®ãã㪠API ãå®è£
ãããããšãåæãšã㊠èªåçæã³ãŒããçæããŸãã
ã€ãŸããäžèšã® API ãå®è£
ããªããã°ã³ã³ãã€ã«ãšã©ãŒã«ãªããŸãã
ãã®ãããå®è£
ãå¿ããé²ãã€ã€ã UserField
ãè¿ãããã®åŠçãèªäœããããšãã§ããŸãã
ããã²ãšã€ relation.custom
ã®å©çšæ¹æ³äŸãšããŠãã·ã§ãŒãã«ããã®å®è£
ããããŸãã
äŸãã° A => B => C ãšããã¯ã©ã¹ã®äŸåé¢ä¿ãããå Žåã
A ã®ã€ã³ã¹ã¿ã³ã¹ã§ãã a
ãã C ã®ã€ã³ã¹ã¿ã³ã¹ãååŸããæµãã¯æ¬¡ã®ããã«ãªããŸãã
b, _ := a.B(ctx)
c, _ := b.C(ctx)
ããã
c, _ := a.C(ctx)
ãšæžããããã«ããã®ãããã§ã®ã·ã§ãŒãã«ããã§ãã
å®è£ æ¹æ³ã¯ A ã®ã¯ã©ã¹ãã¡ã€ã«ã«ä»¥äžã®ãããªã¡ã³ããè¿œå ããã ãã§ã
name: c
relation:
to: c
custom: true
ãããããšã func (a *A) C(ctx context.Context) (*C, error)
ãšãã API ã
å®è£
ãããããšãæåŸ
ããã®ã§ãå®è£
ããŸãã
func (a *A) C(ctx context.Context) (*C, error) {
b, err := a.B(ctx)
if err != nil {
return nil, err
}
c, err := b.C(ctx)
if err != nil {
return nil, err
}
return c, nil
}
æåã«ç€ºããã³ãŒããåå©çšã§ããããã«å®è£ ããã ãã§ããã A => C ã®ååŸã B ãæèããã«è¡ãããå Žåã¯éå®ããŸãã
Committers
- Masaaki Goshima ( goccy )
License
MIT