├── .github └── workflows │ └── go.yml ├── LICENSE ├── README.md ├── _example ├── 01_simple │ ├── .eevee.yml │ ├── README.md │ ├── config │ │ └── user.yml │ ├── dao │ │ └── user.go │ ├── entity │ │ └── user.go │ ├── go.mod │ ├── go.sum │ ├── mock │ │ ├── model │ │ │ └── factory │ │ │ │ └── user.go │ │ └── repository │ │ │ ├── repository.go │ │ │ └── user.go │ ├── model │ │ ├── model.go │ │ └── user.go │ ├── repository │ │ ├── repository.go │ │ └── user.go │ ├── schema │ │ └── users.sql │ ├── server.go │ └── testdata │ │ └── seeds │ │ └── user.yml ├── 02_relation │ ├── .eevee.yml │ ├── README.md │ ├── config │ │ ├── field.yml │ │ ├── group.yml │ │ ├── skill.yml │ │ ├── user.yml │ │ ├── user_field.yml │ │ └── world.yml │ ├── dao │ │ ├── field.go │ │ ├── group.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── db │ │ └── init.go │ ├── entity │ │ ├── field.go │ │ ├── group.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── go.mod │ ├── go.sum │ ├── graph │ │ ├── index.html │ │ └── viz.js │ ├── mock │ │ ├── model │ │ │ └── factory │ │ │ │ ├── field.go │ │ │ │ ├── group.go │ │ │ │ ├── skill.go │ │ │ │ ├── user.go │ │ │ │ ├── user_field.go │ │ │ │ └── world.go │ │ └── repository │ │ │ ├── field.go │ │ │ ├── group.go │ │ │ ├── repository.go │ │ │ ├── skill.go │ │ │ ├── user.go │ │ │ ├── user_field.go │ │ │ └── world.go │ ├── model │ │ ├── field.go │ │ ├── group.go │ │ ├── model.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_api.go │ │ ├── user_field.go │ │ └── world.go │ ├── repository │ │ ├── field.go │ │ ├── group.go │ │ ├── repository.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── schema │ │ ├── fields.sql │ │ ├── groups.sql │ │ ├── skills.sql │ │ ├── user_fields.sql │ │ ├── users.sql │ │ └── worlds.sql │ ├── server.go │ ├── server_test.go │ └── testdata │ │ └── seeds │ │ ├── field.yml │ │ ├── group.yml │ │ ├── skill.yml │ │ ├── user.yml │ │ ├── user_field.yml │ │ └── world.yml ├── 03_api │ ├── .eevee.yml │ ├── README.md │ ├── config │ │ ├── api │ │ │ └── user.yml │ │ └── relation │ │ │ ├── field.yml │ │ │ ├── group.yml │ │ │ ├── skill.yml │ │ │ ├── user.yml │ │ │ ├── user_field.yml │ │ │ └── world.yml │ ├── dao │ │ ├── field.go │ │ ├── group.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── db │ │ └── init.go │ ├── docs │ │ ├── index.md │ │ └── user_getter.md │ ├── entity │ │ ├── field.go │ │ ├── group.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── go.mod │ ├── go.sum │ ├── graph │ │ ├── index.html │ │ └── viz.js │ ├── mock │ │ ├── model │ │ │ ├── factory │ │ │ │ ├── field.go │ │ │ │ ├── group.go │ │ │ │ ├── skill.go │ │ │ │ ├── user.go │ │ │ │ ├── user_field.go │ │ │ │ └── world.go │ │ │ ├── field.go │ │ │ ├── group.go │ │ │ ├── skill.go │ │ │ ├── user.go │ │ │ ├── user_field.go │ │ │ └── world.go │ │ └── repository │ │ │ ├── field.go │ │ │ ├── group.go │ │ │ ├── repository.go │ │ │ ├── skill.go │ │ │ ├── user.go │ │ │ ├── user_field.go │ │ │ └── world.go │ ├── model │ │ ├── field.go │ │ ├── group.go │ │ ├── model.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_api.go │ │ ├── user_field.go │ │ └── world.go │ ├── repository │ │ ├── field.go │ │ ├── group.go │ │ ├── repository.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── request │ │ └── user_getter.go │ ├── response │ │ └── user_getter.go │ ├── schema │ │ ├── fields.sql │ │ ├── groups.sql │ │ ├── skills.sql │ │ ├── user_fields.sql │ │ ├── users.sql │ │ └── worlds.sql │ ├── server.go │ └── testdata │ │ └── seeds │ │ ├── field.yml │ │ ├── group.yml │ │ ├── skill.yml │ │ ├── user.yml │ │ ├── user_field.yml │ │ └── world.yml ├── 04_dao_plugin │ ├── .eevee.yml │ ├── README.md │ ├── config │ │ ├── field.yml │ │ ├── group.yml │ │ ├── skill.yml │ │ ├── user.yml │ │ ├── user_field.yml │ │ └── world.yml │ ├── dao │ │ ├── field.go │ │ ├── group.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── db │ │ └── init.go │ ├── entity │ │ ├── field.go │ │ ├── group.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── go.mod │ ├── go.sum │ ├── graph │ │ ├── index.html │ │ └── viz.js │ ├── mock │ │ ├── model │ │ │ ├── factory │ │ │ │ ├── field.go │ │ │ │ ├── group.go │ │ │ │ ├── skill.go │ │ │ │ ├── user.go │ │ │ │ ├── user_field.go │ │ │ │ └── world.go │ │ │ ├── field.go │ │ │ ├── group.go │ │ │ ├── skill.go │ │ │ ├── user.go │ │ │ ├── user_field.go │ │ │ └── world.go │ │ └── repository │ │ │ ├── field.go │ │ │ ├── group.go │ │ │ ├── repository.go │ │ │ ├── skill.go │ │ │ ├── user.go │ │ │ ├── user_field.go │ │ │ └── world.go │ ├── model │ │ ├── field.go │ │ ├── group.go │ │ ├── model.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_api.go │ │ ├── user_field.go │ │ └── world.go │ ├── repository │ │ ├── field.go │ │ ├── group.go │ │ ├── repository.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── schema │ │ ├── fields.sql │ │ ├── groups.sql │ │ ├── skills.sql │ │ ├── user_fields.sql │ │ ├── users.sql │ │ └── worlds.sql │ ├── server.go │ ├── server_test.go │ └── testdata │ │ └── seeds │ │ ├── field.yml │ │ ├── group.yml │ │ ├── skill.yml │ │ ├── user.yml │ │ ├── user_field.yml │ │ └── world.yml └── 05_rapidash_plugin │ ├── .eevee.yml │ ├── README.md │ ├── config │ ├── field.yml │ ├── group.yml │ ├── skill.yml │ ├── user.yml │ ├── user_field.yml │ └── world.yml │ ├── dao │ ├── field.go │ ├── group.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ ├── db │ └── init.go │ ├── entity │ ├── field.go │ ├── group.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ ├── go.mod │ ├── go.sum │ ├── mock │ ├── model │ │ └── factory │ │ │ ├── field.go │ │ │ ├── group.go │ │ │ ├── skill.go │ │ │ ├── user.go │ │ │ ├── user_field.go │ │ │ └── world.go │ └── repository │ │ ├── field.go │ │ ├── group.go │ │ ├── repository.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── model │ ├── field.go │ ├── group.go │ ├── model.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ ├── repository │ ├── field.go │ ├── group.go │ ├── repository.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ ├── schema │ ├── fields.sql │ ├── groups.sql │ ├── skills.sql │ ├── user_fields.sql │ ├── users.sql │ └── worlds.sql │ ├── server.go │ ├── server_test.go │ └── testdata │ └── seeds │ ├── field.yml │ ├── group.yml │ ├── skill.yml │ ├── user.yml │ ├── user_field.yml │ └── world.yml ├── api └── api.go ├── class ├── class.go ├── class_test.go └── testdata │ ├── class │ ├── field.yml │ ├── group.yml │ ├── skill.yml │ ├── user.yml │ ├── user_field.yml │ └── world.yml │ └── schema │ ├── fields.sql │ ├── groups.sql │ ├── skills.sql │ ├── user_fields.sql │ ├── users.sql │ └── worlds.sql ├── cmd └── eevee │ └── main.go ├── code ├── code.go └── extention.go ├── config ├── config.go ├── config_test.go └── testdata │ └── eevee.yml ├── dao ├── dao.go ├── dao_test.go └── testdata │ ├── class │ ├── field.yml │ ├── group.yml │ ├── skill.yml │ ├── user.yml │ ├── user_field.yml │ └── world.yml │ ├── dao │ ├── field.go │ ├── group.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ └── eevee.yml ├── eevee.go ├── entity ├── entity.go ├── entity_test.go └── testdata │ ├── class │ ├── field.yml │ ├── group.yml │ ├── skill.yml │ ├── user.yml │ ├── user_field.yml │ └── world.yml │ ├── entity │ ├── field.go │ ├── group.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ └── schema │ ├── fields.sql │ ├── user_fields.sql │ └── users.sql ├── go.mod ├── go.sum ├── graph └── graph.go ├── model ├── model.go ├── model_test.go ├── render_option.go ├── template.go └── testdata │ ├── class │ ├── field.yml │ ├── group.yml │ ├── skill.yml │ ├── user.yml │ ├── user_field.yml │ └── world.yml │ ├── model │ ├── field.go │ ├── group.go │ ├── model.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ └── schema │ ├── fields.sql │ ├── user_fields.sql │ └── users.sql ├── plugin ├── dao │ ├── db.go │ ├── default.go │ └── interface.go ├── eevee-octillery-plugin │ └── dao.go ├── eevee-rapidash-plugin │ ├── dao.go │ └── entity.go ├── eevee-request-time-plugin │ └── dao.go ├── eevee-user-id-plugin │ └── dao.go ├── entity │ └── interface.go └── plugin.go ├── plural └── plural.go ├── renderer ├── json.go ├── map.go └── renderer.go ├── repository ├── repository.go ├── repository_test.go ├── template.go └── testdata │ ├── class │ ├── field.yml │ ├── group.yml │ ├── skill.yml │ ├── user.yml │ ├── user_field.yml │ └── world.yml │ ├── mock │ └── repository │ │ ├── field.go │ │ ├── group.go │ │ ├── repository.go │ │ ├── skill.go │ │ ├── user.go │ │ ├── user_field.go │ │ └── world.go │ ├── model │ ├── field.go │ ├── user.go │ └── user_field.go │ ├── repository │ ├── field.go │ ├── group.go │ ├── repository.go │ ├── skill.go │ ├── user.go │ ├── user_field.go │ └── world.go │ └── schema │ ├── fields.sql │ ├── user_fields.sql │ └── users.sql ├── schema ├── schema.go ├── schema_test.go └── testdata │ └── schema │ ├── fields.sql │ ├── user_fields.sql │ └── users.sql ├── static ├── resources │ ├── doc.tmpl │ ├── graph.tmpl │ ├── index.tmpl │ └── viz.js └── statik.go ├── test └── test.go ├── types ├── api.go ├── dao.go ├── entity.go ├── model.go ├── name.go ├── repository.go └── type.go └── watcher └── watcher.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: [push] 3 | jobs: 4 | build: 5 | name: Build 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Set up Go 1.13 9 | uses: actions/setup-go@v1 10 | with: 11 | go-version: 1.13 12 | id: go 13 | 14 | - name: Check out code into the Go module directory 15 | uses: actions/checkout@v2 16 | 17 | - name: Build 18 | run: go build -v cmd/eevee/main.go 19 | 20 | - name: Test 21 | env: 22 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 23 | run: | 24 | go test -v -coverprofile=coverage.out ./... 25 | bash <(curl -s https://codecov.io/bash) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Knocknote, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_example/01_simple/.eevee.yml: -------------------------------------------------------------------------------- 1 | module: simple 2 | class: config 3 | schema: schema 4 | -------------------------------------------------------------------------------- /_example/01_simple/config/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | datastore: db 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: name 9 | type: string 10 | -------------------------------------------------------------------------------- /_example/01_simple/entity/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type User struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Users []*User 11 | 12 | func (e Users) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Users) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/01_simple/go.mod: -------------------------------------------------------------------------------- 1 | module simple 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 7 | github.com/go-sql-driver/mysql v1.4.1 8 | github.com/labstack/echo v3.3.10+incompatible 9 | github.com/labstack/gommon v0.3.0 // indirect 10 | golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect 11 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 12 | google.golang.org/appengine v1.6.5 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /_example/01_simple/mock/model/factory/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "simple/entity" 7 | "simple/model" 8 | ) 9 | 10 | func DefaultUser() *model.User { 11 | value := &model.User{User: &entity.User{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultUsers() *model.Users { 19 | values := &model.Users{} 20 | { 21 | value := &model.User{User: &entity.User{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/01_simple/mock/repository/repository.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "simple/entity" 7 | "simple/model" 8 | "simple/repository" 9 | ) 10 | 11 | type RepositoryMock struct { 12 | user func() *UserMock 13 | } 14 | 15 | func (r *RepositoryMock) User() repository.User { 16 | return r.user() 17 | } 18 | func (r *RepositoryMock) UserMock() *UserMock { 19 | return r.user() 20 | } 21 | 22 | func NewMock() *RepositoryMock { 23 | var ( 24 | repo *RepositoryMock 25 | user *UserMock 26 | ) 27 | repo = &RepositoryMock{user: func() *UserMock { 28 | if user != nil { 29 | return user 30 | } 31 | user = NewUserMock() 32 | return user 33 | }} 34 | return repo 35 | } 36 | 37 | func (r *RepositoryMock) ToUser(value *entity.User) *model.User { 38 | return r.User().ToModel(value) 39 | } 40 | -------------------------------------------------------------------------------- /_example/01_simple/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "context" 7 | "simple/entity" 8 | ) 9 | 10 | type ModelConverter interface { 11 | ToUser(*entity.User) *User 12 | } 13 | 14 | type BeforeRenderer interface { 15 | BeforeRender(context.Context) error 16 | } 17 | 18 | type RenderOption struct { 19 | Name string 20 | IsIncludeAll bool 21 | onlyNames map[string]struct{} 22 | exceptNames map[string]struct{} 23 | includes map[string]*RenderOption 24 | } 25 | 26 | func (ro *RenderOption) Exists(name string) bool { 27 | if len(ro.onlyNames) > 0 { 28 | if _, exists := ro.onlyNames[name]; exists { 29 | return true 30 | } 31 | return false 32 | } 33 | if len(ro.exceptNames) > 0 { 34 | if _, exists := ro.exceptNames[name]; exists { 35 | return false 36 | } 37 | return true 38 | } 39 | return true 40 | } 41 | 42 | func (ro *RenderOption) IncludeOption(name string) *RenderOption { 43 | if ro.Name == name { 44 | return ro 45 | } 46 | return ro.includes[name] 47 | } 48 | 49 | type RenderOptionBuilder struct { 50 | onlyNames map[string]struct{} 51 | exceptNames map[string]struct{} 52 | includes map[string]*RenderOption 53 | isIncludeAll bool 54 | } 55 | 56 | func NewRenderOptionBuilder() *RenderOptionBuilder { 57 | return &RenderOptionBuilder{ 58 | exceptNames: map[string]struct{}{}, 59 | includes: map[string]*RenderOption{}, 60 | onlyNames: map[string]struct{}{}, 61 | } 62 | } 63 | 64 | func (b *RenderOptionBuilder) Only(names ...string) *RenderOptionBuilder { 65 | for _, name := range names { 66 | b.onlyNames[name] = struct{}{} 67 | } 68 | return b 69 | } 70 | 71 | func (b *RenderOptionBuilder) Except(names ...string) *RenderOptionBuilder { 72 | for _, name := range names { 73 | b.exceptNames[name] = struct{}{} 74 | } 75 | return b 76 | } 77 | 78 | func (b *RenderOptionBuilder) Include(name string) *RenderOptionBuilder { 79 | b.includes[name] = &RenderOption{Name: name} 80 | return b 81 | } 82 | 83 | func (b *RenderOptionBuilder) IncludeWithCallback(name string, callback func(*RenderOptionBuilder)) *RenderOptionBuilder { 84 | builder := NewRenderOptionBuilder() 85 | callback(builder) 86 | opt := builder.Build() 87 | opt.Name = name 88 | b.includes[name] = opt 89 | return b 90 | } 91 | 92 | func (b *RenderOptionBuilder) IncludeAll() *RenderOptionBuilder { 93 | b.isIncludeAll = true 94 | return b 95 | } 96 | 97 | func (b *RenderOptionBuilder) Build() *RenderOption { 98 | return &RenderOption{ 99 | IsIncludeAll: b.isIncludeAll, 100 | exceptNames: b.exceptNames, 101 | includes: b.includes, 102 | onlyNames: b.onlyNames, 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /_example/01_simple/repository/repository.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "context" 7 | "database/sql" 8 | "simple/entity" 9 | "simple/model" 10 | ) 11 | 12 | type Repository interface { 13 | User() User 14 | ToUser(*entity.User) *model.User 15 | } 16 | 17 | type RepositoryImpl struct { 18 | user func() User 19 | } 20 | 21 | func (r *RepositoryImpl) User() User { 22 | return r.user() 23 | } 24 | 25 | func New(ctx context.Context, tx *sql.Tx) *RepositoryImpl { 26 | var ( 27 | repo *RepositoryImpl 28 | user *UserImpl 29 | ) 30 | repo = &RepositoryImpl{user: func() User { 31 | if user != nil { 32 | return user 33 | } 34 | user = NewUser(ctx, tx) 35 | user.repo = repo 36 | return user 37 | }} 38 | return repo 39 | } 40 | 41 | func (r *RepositoryImpl) ToUser(value *entity.User) *model.User { 42 | return r.User().ToModel(value) 43 | } 44 | -------------------------------------------------------------------------------- /_example/01_simple/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/01_simple/testdata/seeds/user.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/02_relation/.eevee.yml: -------------------------------------------------------------------------------- 1 | module: relation 2 | graph: graph 3 | class: config 4 | schema: schema 5 | -------------------------------------------------------------------------------- /_example/02_relation/README.md: -------------------------------------------------------------------------------- 1 | # How to work example 2 | 3 | ## 1. Automatically resolve relationships between tables at render 4 | 5 | ```go 6 | func getUser(c echo.Context) error { 7 | id, _ := strconv.Atoi(c.Param("id")) 8 | tx, err := db.Begin() 9 | if err != nil { 10 | return err 11 | } 12 | ctx := context.Background() 13 | repo := repository.New(ctx, tx) 14 | user, err := repo.User().FindByID(ctx, uint64(id)) 15 | if err != nil { 16 | return err 17 | } 18 | if err := c.JSON(http.StatusOK, user); err != nil { 19 | return err 20 | } 21 | if err := tx.Commit(); err != nil { 22 | return err 23 | } 24 | return nil 25 | } 26 | ``` 27 | 28 | ```bash 29 | $ curl localhost:1323/users/1 | jq '.' 30 | ``` 31 | 32 | ```json 33 | { 34 | "id": 1, 35 | "name": "john", 36 | "sex": "man", 37 | "age": 30, 38 | "skillId": 1, 39 | "skillRank": 10, 40 | "groupId": 1, 41 | "worldId": 1, 42 | "fieldId": 1, 43 | "userFields": [ 44 | { 45 | "id": 1, 46 | "userId": 1, 47 | "fieldId": 1, 48 | "field": { 49 | "id": 1, 50 | "name": "fieldA", 51 | "locationX": 2, 52 | "locationY": 3, 53 | "objectNum": 10, 54 | "level": 20, 55 | "difficulty": 5 56 | } 57 | } 58 | ], 59 | "skillEffect": "fire", 60 | "group": null 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /_example/02_relation/config/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - location_x 8 | - location_y 9 | keys: 10 | - - object_num 11 | - - difficulty 12 | - level 13 | members: 14 | - name: id 15 | type: uint64 16 | - name: name 17 | type: string 18 | - name: location_x 19 | type: int 20 | - name: location_y 21 | type: int 22 | - name: object_num 23 | type: int 24 | - name: level 25 | type: int 26 | - name: difficulty 27 | type: int 28 | -------------------------------------------------------------------------------- /_example/02_relation/config/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | datastore: db 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: name 9 | type: string 10 | -------------------------------------------------------------------------------- /_example/02_relation/config/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | datastore: db 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: skill_effect 9 | type: string 10 | -------------------------------------------------------------------------------- /_example/02_relation/config/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - skill_id 8 | - skill_rank 9 | keys: 10 | - - group_id 11 | - - world_id 12 | - field_id 13 | members: 14 | - name: id 15 | type: uint64 16 | - name: name 17 | type: string 18 | example: john 19 | - name: sex 20 | type: string 21 | - name: age 22 | type: int 23 | - name: skill_id 24 | type: uint64 25 | - name: skill_rank 26 | type: int 27 | - name: group_id 28 | type: uint64 29 | - name: world_id 30 | type: uint64 31 | - name: field_id 32 | type: uint64 33 | - name: user_fields 34 | extend: true 35 | has_many: true 36 | relation: 37 | to: user_field 38 | internal: id 39 | external: user_id 40 | - name: skill 41 | extend: true 42 | render: 43 | inline: true 44 | relation: 45 | to: skill 46 | internal: skill_id 47 | external: id 48 | - name: group 49 | extend: true 50 | render: 51 | json: group 52 | relation: 53 | custom: true 54 | to: group 55 | - name: world 56 | extend: true 57 | render: false 58 | relation: 59 | to: world 60 | internal: world_id 61 | external: id 62 | -------------------------------------------------------------------------------- /_example/02_relation/config/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - user_id 7 | - field_id 8 | members: 9 | - name: id 10 | type: uint64 11 | - name: user_id 12 | type: uint64 13 | - name: field_id 14 | type: uint64 15 | - name: field 16 | extend: true 17 | relation: 18 | to: field 19 | internal: field_id 20 | external: id 21 | -------------------------------------------------------------------------------- /_example/02_relation/config/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | datastore: db 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: name 9 | type: string 10 | -------------------------------------------------------------------------------- /_example/02_relation/entity/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Field struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | LocationX int `json:"locationX"` 9 | LocationY int `json:"locationY"` 10 | ObjectNum int `json:"objectNum"` 11 | Level int `json:"level"` 12 | Difficulty int `json:"difficulty"` 13 | } 14 | 15 | type Fields []*Field 16 | 17 | func (e Fields) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e Fields) Names() []string { 26 | values := make([]string, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.Name) 29 | } 30 | return values 31 | } 32 | 33 | func (e Fields) LocationXes() []int { 34 | values := make([]int, 0, len(e)) 35 | for _, value := range e { 36 | values = append(values, value.LocationX) 37 | } 38 | return values 39 | } 40 | 41 | func (e Fields) LocationIes() []int { 42 | values := make([]int, 0, len(e)) 43 | for _, value := range e { 44 | values = append(values, value.LocationY) 45 | } 46 | return values 47 | } 48 | 49 | func (e Fields) ObjectNums() []int { 50 | values := make([]int, 0, len(e)) 51 | for _, value := range e { 52 | values = append(values, value.ObjectNum) 53 | } 54 | return values 55 | } 56 | 57 | func (e Fields) Levels() []int { 58 | values := make([]int, 0, len(e)) 59 | for _, value := range e { 60 | values = append(values, value.Level) 61 | } 62 | return values 63 | } 64 | 65 | func (e Fields) Difficulties() []int { 66 | values := make([]int, 0, len(e)) 67 | for _, value := range e { 68 | values = append(values, value.Difficulty) 69 | } 70 | return values 71 | } 72 | -------------------------------------------------------------------------------- /_example/02_relation/entity/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Group struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Groups []*Group 11 | 12 | func (e Groups) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Groups) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/02_relation/entity/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Skill struct { 6 | ID uint64 `json:"id"` 7 | SkillEffect string `json:"skillEffect"` 8 | } 9 | 10 | type Skills []*Skill 11 | 12 | func (e Skills) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Skills) SkillEffects() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.SkillEffect) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/02_relation/entity/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type User struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | Sex string `json:"sex"` 9 | Age int `json:"age"` 10 | SkillID uint64 `json:"skillID"` 11 | SkillRank int `json:"skillRank"` 12 | GroupID uint64 `json:"groupID"` 13 | WorldID uint64 `json:"worldID"` 14 | FieldID uint64 `json:"fieldID"` 15 | } 16 | 17 | type Users []*User 18 | 19 | func (e Users) IDs() []uint64 { 20 | values := make([]uint64, 0, len(e)) 21 | for _, value := range e { 22 | values = append(values, value.ID) 23 | } 24 | return values 25 | } 26 | 27 | func (e Users) Names() []string { 28 | values := make([]string, 0, len(e)) 29 | for _, value := range e { 30 | values = append(values, value.Name) 31 | } 32 | return values 33 | } 34 | 35 | func (e Users) Sexes() []string { 36 | values := make([]string, 0, len(e)) 37 | for _, value := range e { 38 | values = append(values, value.Sex) 39 | } 40 | return values 41 | } 42 | 43 | func (e Users) Ages() []int { 44 | values := make([]int, 0, len(e)) 45 | for _, value := range e { 46 | values = append(values, value.Age) 47 | } 48 | return values 49 | } 50 | 51 | func (e Users) SkillIDs() []uint64 { 52 | values := make([]uint64, 0, len(e)) 53 | for _, value := range e { 54 | values = append(values, value.SkillID) 55 | } 56 | return values 57 | } 58 | 59 | func (e Users) SkillRanks() []int { 60 | values := make([]int, 0, len(e)) 61 | for _, value := range e { 62 | values = append(values, value.SkillRank) 63 | } 64 | return values 65 | } 66 | 67 | func (e Users) GroupIDs() []uint64 { 68 | values := make([]uint64, 0, len(e)) 69 | for _, value := range e { 70 | values = append(values, value.GroupID) 71 | } 72 | return values 73 | } 74 | 75 | func (e Users) WorldIDs() []uint64 { 76 | values := make([]uint64, 0, len(e)) 77 | for _, value := range e { 78 | values = append(values, value.WorldID) 79 | } 80 | return values 81 | } 82 | 83 | func (e Users) FieldIDs() []uint64 { 84 | values := make([]uint64, 0, len(e)) 85 | for _, value := range e { 86 | values = append(values, value.FieldID) 87 | } 88 | return values 89 | } 90 | -------------------------------------------------------------------------------- /_example/02_relation/entity/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type UserField struct { 6 | ID uint64 `json:"id"` 7 | UserID uint64 `json:"userID"` 8 | FieldID uint64 `json:"fieldID"` 9 | } 10 | 11 | type UserFields []*UserField 12 | 13 | func (e UserFields) IDs() []uint64 { 14 | values := make([]uint64, 0, len(e)) 15 | for _, value := range e { 16 | values = append(values, value.ID) 17 | } 18 | return values 19 | } 20 | 21 | func (e UserFields) UserIDs() []uint64 { 22 | values := make([]uint64, 0, len(e)) 23 | for _, value := range e { 24 | values = append(values, value.UserID) 25 | } 26 | return values 27 | } 28 | 29 | func (e UserFields) FieldIDs() []uint64 { 30 | values := make([]uint64, 0, len(e)) 31 | for _, value := range e { 32 | values = append(values, value.FieldID) 33 | } 34 | return values 35 | } 36 | -------------------------------------------------------------------------------- /_example/02_relation/entity/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type World struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Worlds []*World 11 | 12 | func (e Worlds) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Worlds) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/02_relation/go.mod: -------------------------------------------------------------------------------- 1 | module relation 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 7 | github.com/go-sql-driver/mysql v1.4.1 8 | github.com/labstack/echo v3.3.10+incompatible 9 | github.com/labstack/gommon v0.3.0 // indirect 10 | golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect 11 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 12 | google.golang.org/appengine v1.6.2 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /_example/02_relation/mock/model/factory/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "relation/entity" 7 | "relation/model" 8 | ) 9 | 10 | func DefaultField() *model.Field { 11 | value := &model.Field{Field: &entity.Field{ 12 | Difficulty: 0, 13 | ID: 0, 14 | Level: 0, 15 | LocationX: 0, 16 | LocationY: 0, 17 | Name: "", 18 | ObjectNum: 0, 19 | }} 20 | return value 21 | } 22 | 23 | func DefaultFields() *model.Fields { 24 | values := &model.Fields{} 25 | { 26 | value := &model.Field{Field: &entity.Field{ 27 | Difficulty: 0, 28 | ID: 0, 29 | Level: 0, 30 | LocationX: 0, 31 | LocationY: 0, 32 | Name: "", 33 | ObjectNum: 0, 34 | }} 35 | values.Add(value) 36 | } 37 | return values 38 | } 39 | -------------------------------------------------------------------------------- /_example/02_relation/mock/model/factory/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "relation/entity" 7 | "relation/model" 8 | ) 9 | 10 | func DefaultGroup() *model.Group { 11 | value := &model.Group{Group: &entity.Group{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultGroups() *model.Groups { 19 | values := &model.Groups{} 20 | { 21 | value := &model.Group{Group: &entity.Group{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/02_relation/mock/model/factory/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "relation/entity" 7 | "relation/model" 8 | ) 9 | 10 | func DefaultSkill() *model.Skill { 11 | value := &model.Skill{Skill: &entity.Skill{ 12 | ID: 0, 13 | SkillEffect: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultSkills() *model.Skills { 19 | values := &model.Skills{} 20 | { 21 | value := &model.Skill{Skill: &entity.Skill{ 22 | ID: 0, 23 | SkillEffect: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/02_relation/mock/model/factory/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "context" 7 | "relation/entity" 8 | "relation/model" 9 | ) 10 | 11 | func DefaultUser() *model.User { 12 | userFields := DefaultUserFields() 13 | skill := DefaultSkill() 14 | world := DefaultWorld() 15 | value := &model.User{User: &entity.User{ 16 | Age: 0, 17 | FieldID: 0, 18 | GroupID: 0, 19 | ID: 0, 20 | Name: "john", 21 | Sex: "", 22 | SkillID: 0, 23 | SkillRank: 0, 24 | WorldID: 0, 25 | }} 26 | value.UserFields = func(context.Context) (*model.UserFields, error) { 27 | return userFields, nil 28 | } 29 | value.Skill = func(context.Context) (*model.Skill, error) { 30 | return skill, nil 31 | } 32 | value.World = func(context.Context) (*model.World, error) { 33 | return world, nil 34 | } 35 | return value 36 | } 37 | 38 | func DefaultUsers() *model.Users { 39 | values := &model.Users{} 40 | { 41 | userFields := DefaultUserFields() 42 | skill := DefaultSkill() 43 | world := DefaultWorld() 44 | value := &model.User{User: &entity.User{ 45 | Age: 0, 46 | FieldID: 0, 47 | GroupID: 0, 48 | ID: 0, 49 | Name: "john", 50 | Sex: "", 51 | SkillID: 0, 52 | SkillRank: 0, 53 | WorldID: 0, 54 | }} 55 | value.UserFields = func(context.Context) (*model.UserFields, error) { 56 | return userFields, nil 57 | } 58 | value.Skill = func(context.Context) (*model.Skill, error) { 59 | return skill, nil 60 | } 61 | value.World = func(context.Context) (*model.World, error) { 62 | return world, nil 63 | } 64 | values.Add(value) 65 | } 66 | return values 67 | } 68 | -------------------------------------------------------------------------------- /_example/02_relation/mock/model/factory/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "context" 7 | "relation/entity" 8 | "relation/model" 9 | ) 10 | 11 | func DefaultUserField() *model.UserField { 12 | field := DefaultField() 13 | value := &model.UserField{UserField: &entity.UserField{ 14 | FieldID: 0, 15 | ID: 0, 16 | UserID: 0, 17 | }} 18 | value.Field = func(context.Context) (*model.Field, error) { 19 | return field, nil 20 | } 21 | return value 22 | } 23 | 24 | func DefaultUserFields() *model.UserFields { 25 | values := &model.UserFields{} 26 | { 27 | field := DefaultField() 28 | value := &model.UserField{UserField: &entity.UserField{ 29 | FieldID: 0, 30 | ID: 0, 31 | UserID: 0, 32 | }} 33 | value.Field = func(context.Context) (*model.Field, error) { 34 | return field, nil 35 | } 36 | values.Add(value) 37 | } 38 | return values 39 | } 40 | -------------------------------------------------------------------------------- /_example/02_relation/mock/model/factory/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "relation/entity" 7 | "relation/model" 8 | ) 9 | 10 | func DefaultWorld() *model.World { 11 | value := &model.World{World: &entity.World{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultWorlds() *model.Worlds { 19 | values := &model.Worlds{} 20 | { 21 | value := &model.World{World: &entity.World{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/02_relation/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "context" 7 | "relation/entity" 8 | ) 9 | 10 | type ModelConverter interface { 11 | ToField(*entity.Field) *Field 12 | ToGroup(*entity.Group) *Group 13 | ToSkill(*entity.Skill) *Skill 14 | ToUser(*entity.User) *User 15 | ToUserField(*entity.UserField) *UserField 16 | ToWorld(*entity.World) *World 17 | } 18 | 19 | type BeforeRenderer interface { 20 | BeforeRender(context.Context) error 21 | } 22 | 23 | type RenderOption struct { 24 | Name string 25 | IsIncludeAll bool 26 | onlyNames map[string]struct{} 27 | exceptNames map[string]struct{} 28 | includes map[string]*RenderOption 29 | } 30 | 31 | func (ro *RenderOption) Exists(name string) bool { 32 | if len(ro.onlyNames) > 0 { 33 | if _, exists := ro.onlyNames[name]; exists { 34 | return true 35 | } 36 | return false 37 | } 38 | if len(ro.exceptNames) > 0 { 39 | if _, exists := ro.exceptNames[name]; exists { 40 | return false 41 | } 42 | return true 43 | } 44 | return true 45 | } 46 | 47 | func (ro *RenderOption) IncludeOption(name string) *RenderOption { 48 | if ro.Name == name { 49 | return ro 50 | } 51 | return ro.includes[name] 52 | } 53 | 54 | type RenderOptionBuilder struct { 55 | onlyNames map[string]struct{} 56 | exceptNames map[string]struct{} 57 | includes map[string]*RenderOption 58 | isIncludeAll bool 59 | } 60 | 61 | func NewRenderOptionBuilder() *RenderOptionBuilder { 62 | return &RenderOptionBuilder{ 63 | exceptNames: map[string]struct{}{}, 64 | includes: map[string]*RenderOption{}, 65 | onlyNames: map[string]struct{}{}, 66 | } 67 | } 68 | 69 | func (b *RenderOptionBuilder) Only(names ...string) *RenderOptionBuilder { 70 | for _, name := range names { 71 | b.onlyNames[name] = struct{}{} 72 | } 73 | return b 74 | } 75 | 76 | func (b *RenderOptionBuilder) Except(names ...string) *RenderOptionBuilder { 77 | for _, name := range names { 78 | b.exceptNames[name] = struct{}{} 79 | } 80 | return b 81 | } 82 | 83 | func (b *RenderOptionBuilder) Include(name string) *RenderOptionBuilder { 84 | b.includes[name] = &RenderOption{Name: name} 85 | return b 86 | } 87 | 88 | func (b *RenderOptionBuilder) IncludeWithCallback(name string, callback func(*RenderOptionBuilder)) *RenderOptionBuilder { 89 | builder := NewRenderOptionBuilder() 90 | callback(builder) 91 | opt := builder.Build() 92 | opt.Name = name 93 | b.includes[name] = opt 94 | return b 95 | } 96 | 97 | func (b *RenderOptionBuilder) IncludeAll() *RenderOptionBuilder { 98 | b.isIncludeAll = true 99 | return b 100 | } 101 | 102 | func (b *RenderOptionBuilder) Build() *RenderOption { 103 | return &RenderOption{ 104 | IsIncludeAll: b.isIncludeAll, 105 | exceptNames: b.exceptNames, 106 | includes: b.includes, 107 | onlyNames: b.onlyNames, 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /_example/02_relation/model/user_api.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "context" 4 | 5 | func (m *User) Group(ctx context.Context) (*Group, error) { 6 | return nil, nil 7 | } 8 | -------------------------------------------------------------------------------- /_example/02_relation/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /_example/02_relation/schema/groups.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `groups` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/02_relation/schema/skills.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `skills` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `skill_effect` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/02_relation/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | 9 | -------------------------------------------------------------------------------- /_example/02_relation/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | PRIMARY KEY (`id`), 12 | UNIQUE KEY `uq_users_01` (`name`), 13 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 14 | KEY `idx_users_03` (`group_id`), 15 | KEY `idx_users_04` (`world_id`, `field_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | -------------------------------------------------------------------------------- /_example/02_relation/schema/worlds.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `worlds` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | 7 | -------------------------------------------------------------------------------- /_example/02_relation/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "net/http" 7 | _ "relation/db" 8 | "relation/repository" 9 | "strconv" 10 | 11 | _ "github.com/go-sql-driver/mysql" 12 | "github.com/labstack/echo" 13 | "github.com/labstack/echo/middleware" 14 | ) 15 | 16 | var ( 17 | db *sql.DB 18 | ) 19 | 20 | func getUser(c echo.Context) error { 21 | id, _ := strconv.Atoi(c.Param("id")) 22 | tx, err := db.Begin() 23 | if err != nil { 24 | return err 25 | } 26 | ctx := context.Background() 27 | repo := repository.New(ctx, tx) 28 | user, err := repo.User().FindByID(ctx, uint64(id)) 29 | if err != nil { 30 | return err 31 | } 32 | if err := c.JSON(http.StatusOK, user); err != nil { 33 | return err 34 | } 35 | if err := tx.Commit(); err != nil { 36 | return err 37 | } 38 | return nil 39 | } 40 | 41 | func main() { 42 | e := echo.New() 43 | 44 | conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true") 45 | if err != nil { 46 | panic(err) 47 | } 48 | defer conn.Close() 49 | 50 | db = conn 51 | 52 | // Middleware 53 | e.Use(middleware.Logger()) 54 | e.Use(middleware.Recover()) 55 | 56 | // Routes 57 | e.GET("/users/:id", getUser) 58 | 59 | // Start server 60 | e.Logger.Fatal(e.Start(":1323")) 61 | } 62 | -------------------------------------------------------------------------------- /_example/02_relation/server_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "relation/mock/model/factory" 6 | "relation/mock/repository" 7 | "testing" 8 | ) 9 | 10 | func TestUserGet(t *testing.T) { 11 | repo := repository.NewMock() 12 | ctx := context.Background() 13 | repo.UserMock().EXPECT().FindByID(ctx, 1).Return(factory.DefaultUser(), nil) 14 | u, err := repo.User().FindByID(ctx, 1) 15 | if err != nil { 16 | t.Fatalf("%+v", err) 17 | } 18 | if u.ID != factory.DefaultUser().ID { 19 | t.Fatal("invalid user") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /_example/02_relation/testdata/seeds/field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | difficulty: 0 4 | id: 0 5 | level: 0 6 | location_x: 0 7 | location_y: 0 8 | name: "" 9 | object_num: 0 10 | collection: 11 | defaults: 12 | - *default 13 | -------------------------------------------------------------------------------- /_example/02_relation/testdata/seeds/group.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/02_relation/testdata/seeds/skill.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | skill_effect: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/02_relation/testdata/seeds/user.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | age: 0 4 | field_id: 0 5 | group: $default 6 | group_id: 0 7 | id: 0 8 | name: john 9 | sex: "" 10 | skill: $default 11 | skill_id: 0 12 | skill_rank: 0 13 | user_fields: $default 14 | world: $default 15 | world_id: 0 16 | collection: 17 | defaults: 18 | - *default 19 | -------------------------------------------------------------------------------- /_example/02_relation/testdata/seeds/user_field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | field: $default 4 | field_id: 0 5 | id: 0 6 | user_id: 0 7 | collection: 8 | defaults: 9 | - *default 10 | -------------------------------------------------------------------------------- /_example/02_relation/testdata/seeds/world.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/03_api/.eevee.yml: -------------------------------------------------------------------------------- 1 | module: api 2 | graph: graph 3 | class: config/relation 4 | api: config/api 5 | -------------------------------------------------------------------------------- /_example/03_api/README.md: -------------------------------------------------------------------------------- 1 | # How to work example 2 | 3 | ## 1. Automatically filter response fields 4 | 5 | - Define API definition to config/api/user.yml 6 | 7 | ```yaml 8 | - name: user_getter 9 | desc: return user status 10 | uri: /users/:user_id 11 | method: get 12 | response: 13 | subtypes: 14 | - name: user_getter_subtype 15 | members: 16 | - name: user 17 | type: user 18 | render: 19 | inline: true 20 | - name: param1 21 | type: string 22 | - name: param2 23 | type: int 24 | include: 25 | - name: user 26 | only: 27 | - name 28 | - param1 29 | - param2 30 | include: 31 | - name: user_fields 32 | only: 33 | - field_id 34 | include: 35 | - name: field 36 | only: 37 | - name 38 | type: 39 | - name: user 40 | type: user_getter_subtype 41 | render: 42 | json: user 43 | desc: user status 44 | - name: param1 45 | type: string 46 | desc: param1 47 | ``` 48 | 49 | - Run eevee 50 | 51 | ```bash 52 | $ eevee -r config/relation 53 | ``` 54 | 55 | - Use response package 56 | 57 | ```go 58 | func getUser(c echo.Context) error { 59 | id, _ := strconv.Atoi(c.Param("id")) 60 | tx, err := db.Begin() 61 | if err != nil { 62 | return err 63 | } 64 | ctx := context.Background() 65 | repo := repository.New(ctx, tx) 66 | user, err := repo.User().FindByID(ctx, uint64(id)) 67 | if err != nil { 68 | return err 69 | } 70 | response, err := new(response.UserGetterBuilder).SetUser(&response.UserGetterSubtype{ 71 | User: user, 72 | Param1: "sub_param1", 73 | Param2: 100, 74 | }).SetParam1("param1").Build(ctx) 75 | if err != nil { 76 | return err 77 | } 78 | if err := tx.Commit(); err != nil { 79 | return err 80 | } 81 | if err := c.JSON(http.StatusOK, response); err != nil { 82 | return err 83 | } 84 | return nil 85 | } 86 | ``` 87 | 88 | ```bash 89 | $ curl localhost:1323/users/1 | jq '.' 90 | ``` 91 | 92 | ```json 93 | { 94 | "user": { 95 | "name": "john", 96 | "userFields": [ 97 | { 98 | "fieldId": 1, 99 | "field": { 100 | "name": "fieldA" 101 | } 102 | } 103 | ], 104 | "param1": "sub_param1", 105 | "param2": 100 106 | }, 107 | "param1": "param1" 108 | } 109 | ``` 110 | -------------------------------------------------------------------------------- /_example/03_api/config/api/user.yml: -------------------------------------------------------------------------------- 1 | - name: user_getter 2 | desc: return user status 3 | uri: /users/{userId} 4 | method: get 5 | request: 6 | parameters: 7 | - name: user_id 8 | type: uint64 9 | in: path 10 | required: true 11 | - name: session 12 | type: string 13 | in: header 14 | response: 15 | subtypes: 16 | - name: user_getter_subtype 17 | members: 18 | - name: user 19 | type: user 20 | render: 21 | inline: true 22 | - name: param1 23 | type: string 24 | - name: param2 25 | type: int 26 | include: 27 | - name: user 28 | only: 29 | - name 30 | - param1 31 | - param2 32 | include: 33 | - name: user_fields 34 | only: 35 | - field_id 36 | include: 37 | - name: field 38 | only: 39 | - name 40 | type: 41 | members: 42 | - name: users 43 | type: user 44 | has_many: true 45 | - name: sub 46 | type: user_getter_subtype 47 | include: 48 | - name: users 49 | only: 50 | - id 51 | - name 52 | include: 53 | - name: user_fields 54 | only: 55 | - field_id 56 | - name: sub 57 | -------------------------------------------------------------------------------- /_example/03_api/config/relation/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - name 6 | - - location_x 7 | - location_y 8 | keys: 9 | - - object_num 10 | - - difficulty 11 | - level 12 | members: 13 | - name: id 14 | type: uint64 15 | - name: name 16 | type: string 17 | - name: location_x 18 | type: int 19 | - name: location_y 20 | type: int 21 | - name: object_num 22 | type: int 23 | - name: level 24 | type: int 25 | - name: difficulty 26 | type: int 27 | -------------------------------------------------------------------------------- /_example/03_api/config/relation/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /_example/03_api/config/relation/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: skill_effect 8 | type: string 9 | -------------------------------------------------------------------------------- /_example/03_api/config/relation/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | members: 3 | - name: id 4 | type: uint64 5 | - name: name 6 | type: string 7 | - name: sex 8 | type: string 9 | - name: age 10 | type: int 11 | - name: skill_id 12 | type: uint64 13 | - name: skill_rank 14 | type: int 15 | - name: group_id 16 | type: uint64 17 | - name: world_id 18 | type: uint64 19 | - name: field_id 20 | type: uint64 21 | - name: user_fields 22 | has_many: true 23 | extend: true 24 | relation: 25 | to: user_field 26 | internal: id 27 | external: user_id 28 | - name: skill 29 | extend: true 30 | relation: 31 | to: skill 32 | internal: skill_id 33 | external: id 34 | render: 35 | inline: true 36 | - name: group 37 | extend: true 38 | relation: 39 | to: group 40 | custom: true 41 | render: 42 | json: group 43 | - name: world 44 | extend: true 45 | relation: 46 | to: world 47 | internal: world_id 48 | external: id 49 | render: false 50 | index: 51 | primary_key: id 52 | unique_keys: 53 | - - name 54 | - - skill_id 55 | - skill_rank 56 | keys: 57 | - - group_id 58 | - - world_id 59 | - field_id 60 | -------------------------------------------------------------------------------- /_example/03_api/config/relation/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - user_id 6 | - field_id 7 | members: 8 | - name: id 9 | type: uint64 10 | - name: user_id 11 | type: uint64 12 | - name: field_id 13 | type: uint64 14 | - name: field 15 | extend: true 16 | relation: 17 | to: field 18 | internal: field_id 19 | external: id 20 | -------------------------------------------------------------------------------- /_example/03_api/config/relation/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /_example/03_api/docs/index.md: -------------------------------------------------------------------------------- 1 | ## The table of contents 2 | 3 | ### Endpoints 4 | - get /users/{userId} 5 | 6 | -------------------------------------------------------------------------------- /_example/03_api/entity/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Field struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | LocationX int `json:"locationX"` 9 | LocationY int `json:"locationY"` 10 | ObjectNum int `json:"objectNum"` 11 | Level int `json:"level"` 12 | Difficulty int `json:"difficulty"` 13 | } 14 | 15 | type Fields []*Field 16 | 17 | func (e Fields) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e Fields) Names() []string { 26 | values := make([]string, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.Name) 29 | } 30 | return values 31 | } 32 | 33 | func (e Fields) LocationXes() []int { 34 | values := make([]int, 0, len(e)) 35 | for _, value := range e { 36 | values = append(values, value.LocationX) 37 | } 38 | return values 39 | } 40 | 41 | func (e Fields) LocationIes() []int { 42 | values := make([]int, 0, len(e)) 43 | for _, value := range e { 44 | values = append(values, value.LocationY) 45 | } 46 | return values 47 | } 48 | 49 | func (e Fields) ObjectNums() []int { 50 | values := make([]int, 0, len(e)) 51 | for _, value := range e { 52 | values = append(values, value.ObjectNum) 53 | } 54 | return values 55 | } 56 | 57 | func (e Fields) Levels() []int { 58 | values := make([]int, 0, len(e)) 59 | for _, value := range e { 60 | values = append(values, value.Level) 61 | } 62 | return values 63 | } 64 | 65 | func (e Fields) Difficulties() []int { 66 | values := make([]int, 0, len(e)) 67 | for _, value := range e { 68 | values = append(values, value.Difficulty) 69 | } 70 | return values 71 | } 72 | -------------------------------------------------------------------------------- /_example/03_api/entity/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Group struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Groups []*Group 11 | 12 | func (e Groups) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Groups) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/03_api/entity/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Skill struct { 6 | ID uint64 `json:"id"` 7 | SkillEffect string `json:"skillEffect"` 8 | } 9 | 10 | type Skills []*Skill 11 | 12 | func (e Skills) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Skills) SkillEffects() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.SkillEffect) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/03_api/entity/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type User struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | Sex string `json:"sex"` 9 | Age int `json:"age"` 10 | SkillID uint64 `json:"skillID"` 11 | SkillRank int `json:"skillRank"` 12 | GroupID uint64 `json:"groupID"` 13 | WorldID uint64 `json:"worldID"` 14 | FieldID uint64 `json:"fieldID"` 15 | } 16 | 17 | type Users []*User 18 | 19 | func (e Users) IDs() []uint64 { 20 | values := make([]uint64, 0, len(e)) 21 | for _, value := range e { 22 | values = append(values, value.ID) 23 | } 24 | return values 25 | } 26 | 27 | func (e Users) Names() []string { 28 | values := make([]string, 0, len(e)) 29 | for _, value := range e { 30 | values = append(values, value.Name) 31 | } 32 | return values 33 | } 34 | 35 | func (e Users) Sexes() []string { 36 | values := make([]string, 0, len(e)) 37 | for _, value := range e { 38 | values = append(values, value.Sex) 39 | } 40 | return values 41 | } 42 | 43 | func (e Users) Ages() []int { 44 | values := make([]int, 0, len(e)) 45 | for _, value := range e { 46 | values = append(values, value.Age) 47 | } 48 | return values 49 | } 50 | 51 | func (e Users) SkillIDs() []uint64 { 52 | values := make([]uint64, 0, len(e)) 53 | for _, value := range e { 54 | values = append(values, value.SkillID) 55 | } 56 | return values 57 | } 58 | 59 | func (e Users) SkillRanks() []int { 60 | values := make([]int, 0, len(e)) 61 | for _, value := range e { 62 | values = append(values, value.SkillRank) 63 | } 64 | return values 65 | } 66 | 67 | func (e Users) GroupIDs() []uint64 { 68 | values := make([]uint64, 0, len(e)) 69 | for _, value := range e { 70 | values = append(values, value.GroupID) 71 | } 72 | return values 73 | } 74 | 75 | func (e Users) WorldIDs() []uint64 { 76 | values := make([]uint64, 0, len(e)) 77 | for _, value := range e { 78 | values = append(values, value.WorldID) 79 | } 80 | return values 81 | } 82 | 83 | func (e Users) FieldIDs() []uint64 { 84 | values := make([]uint64, 0, len(e)) 85 | for _, value := range e { 86 | values = append(values, value.FieldID) 87 | } 88 | return values 89 | } 90 | -------------------------------------------------------------------------------- /_example/03_api/entity/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type UserField struct { 6 | ID uint64 `json:"id"` 7 | UserID uint64 `json:"userID"` 8 | FieldID uint64 `json:"fieldID"` 9 | } 10 | 11 | type UserFields []*UserField 12 | 13 | func (e UserFields) IDs() []uint64 { 14 | values := make([]uint64, 0, len(e)) 15 | for _, value := range e { 16 | values = append(values, value.ID) 17 | } 18 | return values 19 | } 20 | 21 | func (e UserFields) UserIDs() []uint64 { 22 | values := make([]uint64, 0, len(e)) 23 | for _, value := range e { 24 | values = append(values, value.UserID) 25 | } 26 | return values 27 | } 28 | 29 | func (e UserFields) FieldIDs() []uint64 { 30 | values := make([]uint64, 0, len(e)) 31 | for _, value := range e { 32 | values = append(values, value.FieldID) 33 | } 34 | return values 35 | } 36 | -------------------------------------------------------------------------------- /_example/03_api/entity/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type World struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Worlds []*World 11 | 12 | func (e Worlds) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Worlds) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/03_api/go.mod: -------------------------------------------------------------------------------- 1 | module api 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 7 | github.com/go-sql-driver/mysql v1.4.1 8 | github.com/labstack/echo v3.3.10+incompatible 9 | github.com/labstack/gommon v0.3.0 // indirect 10 | golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect 11 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 12 | google.golang.org/appengine v1.6.2 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/factory/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultField() *model.Field { 11 | value := &model.Field{Field: &entity.Field{ 12 | Difficulty: 0, 13 | ID: 0, 14 | Level: 0, 15 | LocationX: 0, 16 | LocationY: 0, 17 | Name: "", 18 | ObjectNum: 0, 19 | }} 20 | return value 21 | } 22 | 23 | func DefaultFields() *model.Fields { 24 | values := &model.Fields{} 25 | { 26 | value := &model.Field{Field: &entity.Field{ 27 | Difficulty: 0, 28 | ID: 0, 29 | Level: 0, 30 | LocationX: 0, 31 | LocationY: 0, 32 | Name: "", 33 | ObjectNum: 0, 34 | }} 35 | values.Add(value) 36 | } 37 | return values 38 | } 39 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/factory/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultGroup() *model.Group { 11 | value := &model.Group{Group: &entity.Group{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultGroups() *model.Groups { 19 | values := &model.Groups{} 20 | { 21 | value := &model.Group{Group: &entity.Group{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/factory/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultSkill() *model.Skill { 11 | value := &model.Skill{Skill: &entity.Skill{ 12 | ID: 0, 13 | SkillEffect: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultSkills() *model.Skills { 19 | values := &model.Skills{} 20 | { 21 | value := &model.Skill{Skill: &entity.Skill{ 22 | ID: 0, 23 | SkillEffect: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/factory/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | "context" 9 | ) 10 | 11 | func DefaultUser() *model.User { 12 | userFields := DefaultUserFields() 13 | skill := DefaultSkill() 14 | world := DefaultWorld() 15 | value := &model.User{User: &entity.User{ 16 | Age: 0, 17 | FieldID: 0, 18 | GroupID: 0, 19 | ID: 0, 20 | Name: "", 21 | Sex: "", 22 | SkillID: 0, 23 | SkillRank: 0, 24 | WorldID: 0, 25 | }} 26 | value.UserFields = func(context.Context) (*model.UserFields, error) { 27 | return userFields, nil 28 | } 29 | value.Skill = func(context.Context) (*model.Skill, error) { 30 | return skill, nil 31 | } 32 | value.World = func(context.Context) (*model.World, error) { 33 | return world, nil 34 | } 35 | return value 36 | } 37 | 38 | func DefaultUsers() *model.Users { 39 | values := &model.Users{} 40 | { 41 | userFields := DefaultUserFields() 42 | skill := DefaultSkill() 43 | world := DefaultWorld() 44 | value := &model.User{User: &entity.User{ 45 | Age: 0, 46 | FieldID: 0, 47 | GroupID: 0, 48 | ID: 0, 49 | Name: "", 50 | Sex: "", 51 | SkillID: 0, 52 | SkillRank: 0, 53 | WorldID: 0, 54 | }} 55 | value.UserFields = func(context.Context) (*model.UserFields, error) { 56 | return userFields, nil 57 | } 58 | value.Skill = func(context.Context) (*model.Skill, error) { 59 | return skill, nil 60 | } 61 | value.World = func(context.Context) (*model.World, error) { 62 | return world, nil 63 | } 64 | values.Add(value) 65 | } 66 | return values 67 | } 68 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/factory/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | "context" 9 | ) 10 | 11 | func DefaultUserField() *model.UserField { 12 | field := DefaultField() 13 | value := &model.UserField{UserField: &entity.UserField{ 14 | FieldID: 0, 15 | ID: 0, 16 | UserID: 0, 17 | }} 18 | value.Field = func(context.Context) (*model.Field, error) { 19 | return field, nil 20 | } 21 | return value 22 | } 23 | 24 | func DefaultUserFields() *model.UserFields { 25 | values := &model.UserFields{} 26 | { 27 | field := DefaultField() 28 | value := &model.UserField{UserField: &entity.UserField{ 29 | FieldID: 0, 30 | ID: 0, 31 | UserID: 0, 32 | }} 33 | value.Field = func(context.Context) (*model.Field, error) { 34 | return field, nil 35 | } 36 | values.Add(value) 37 | } 38 | return values 39 | } 40 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/factory/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultWorld() *model.World { 11 | value := &model.World{World: &entity.World{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultWorlds() *model.Worlds { 19 | values := &model.Worlds{} 20 | { 21 | value := &model.World{World: &entity.World{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultField() *model.Field { 11 | value := model.NewField(&entity.Field{ 12 | Difficulty: uint64(0x0), 13 | ID: uint64(0x0), 14 | Level: uint64(0x0), 15 | LocationX: uint64(0x0), 16 | LocationY: uint64(0x0), 17 | Name: "", 18 | ObjectNum: uint64(0x0), 19 | }, nil) 20 | return value 21 | } 22 | 23 | func DefaultsField() *model.Fields { 24 | values := model.NewFields(entity.Fields{}) 25 | values.Add(DefaultField()) 26 | return values 27 | } 28 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultGroup() *model.Group { 11 | value := model.NewGroup(&entity.Group{ 12 | ID: uint64(0x0), 13 | Name: "", 14 | }, nil) 15 | return value 16 | } 17 | 18 | func DefaultsGroup() *model.Groups { 19 | values := model.NewGroups(entity.Groups{}) 20 | values.Add(DefaultGroup()) 21 | return values 22 | } 23 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultSkill() *model.Skill { 11 | value := model.NewSkill(&entity.Skill{ 12 | ID: uint64(0x0), 13 | SkillEffect: "", 14 | }, nil) 15 | return value 16 | } 17 | 18 | func DefaultsSkill() *model.Skills { 19 | values := model.NewSkills(entity.Skills{}) 20 | values.Add(DefaultSkill()) 21 | return values 22 | } 23 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | "context" 9 | ) 10 | 11 | func DefaultUser() *model.User { 12 | value := model.NewUser(&entity.User{ 13 | Age: uint64(0x0), 14 | FieldID: uint64(0x0), 15 | GroupID: uint64(0x0), 16 | ID: uint64(0x0), 17 | Name: "", 18 | Sex: "", 19 | SkillID: uint64(0x0), 20 | SkillRank: uint64(0x0), 21 | WorldID: uint64(0x0), 22 | }, nil) 23 | value.UserFields = func(context.Context) (*model.UserFields, error) { 24 | return DefaultUserField(), nil 25 | } 26 | value.Skill = func(context.Context) (*model.Skill, error) { 27 | return DefaultSkill(), nil 28 | } 29 | value.World = func(context.Context) (*model.World, error) { 30 | return DefaultWorld(), nil 31 | } 32 | return value 33 | } 34 | 35 | func DefaultsUser() *model.Users { 36 | values := model.NewUsers(entity.Users{}) 37 | values.Add(DefaultUser()) 38 | return values 39 | } 40 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | "context" 9 | ) 10 | 11 | func DefaultUserField() *model.UserField { 12 | value := model.NewUserField(&entity.UserField{ 13 | FieldID: uint64(0x0), 14 | ID: uint64(0x0), 15 | UserID: uint64(0x0), 16 | }, nil) 17 | value.Field = func(context.Context) (*model.Field, error) { 18 | return DefaultField(), nil 19 | } 20 | return value 21 | } 22 | 23 | func DefaultsUserField() *model.UserFields { 24 | values := model.NewUserFields(entity.UserFields{}) 25 | values.Add(DefaultUserField()) 26 | return values 27 | } 28 | -------------------------------------------------------------------------------- /_example/03_api/mock/model/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "api/entity" 7 | "api/model" 8 | ) 9 | 10 | func DefaultWorld() *model.World { 11 | value := model.NewWorld(&entity.World{ 12 | ID: uint64(0x0), 13 | Name: "", 14 | }, nil) 15 | return value 16 | } 17 | 18 | func DefaultsWorld() *model.Worlds { 19 | values := model.NewWorlds(entity.Worlds{}) 20 | values.Add(DefaultWorld()) 21 | return values 22 | } 23 | -------------------------------------------------------------------------------- /_example/03_api/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "api/entity" 7 | "context" 8 | ) 9 | 10 | type ModelConverter interface { 11 | ToField(*entity.Field) *Field 12 | ToGroup(*entity.Group) *Group 13 | ToSkill(*entity.Skill) *Skill 14 | ToUser(*entity.User) *User 15 | ToUserField(*entity.UserField) *UserField 16 | ToWorld(*entity.World) *World 17 | } 18 | 19 | type BeforeRenderer interface { 20 | BeforeRender(context.Context) error 21 | } 22 | 23 | type RenderOption struct { 24 | Name string 25 | IsIncludeAll bool 26 | onlyNames map[string]struct{} 27 | exceptNames map[string]struct{} 28 | includes map[string]*RenderOption 29 | } 30 | 31 | func (ro *RenderOption) Exists(name string) bool { 32 | if len(ro.onlyNames) > 0 { 33 | if _, exists := ro.onlyNames[name]; exists { 34 | return true 35 | } 36 | return false 37 | } 38 | if len(ro.exceptNames) > 0 { 39 | if _, exists := ro.exceptNames[name]; exists { 40 | return false 41 | } 42 | return true 43 | } 44 | return true 45 | } 46 | 47 | func (ro *RenderOption) IncludeOption(name string) *RenderOption { 48 | if ro.Name == name { 49 | return ro 50 | } 51 | return ro.includes[name] 52 | } 53 | 54 | type RenderOptionBuilder struct { 55 | onlyNames map[string]struct{} 56 | exceptNames map[string]struct{} 57 | includes map[string]*RenderOption 58 | isIncludeAll bool 59 | } 60 | 61 | func NewRenderOptionBuilder() *RenderOptionBuilder { 62 | return &RenderOptionBuilder{ 63 | exceptNames: map[string]struct{}{}, 64 | includes: map[string]*RenderOption{}, 65 | onlyNames: map[string]struct{}{}, 66 | } 67 | } 68 | 69 | func (b *RenderOptionBuilder) Only(names ...string) *RenderOptionBuilder { 70 | for _, name := range names { 71 | b.onlyNames[name] = struct{}{} 72 | } 73 | return b 74 | } 75 | 76 | func (b *RenderOptionBuilder) Except(names ...string) *RenderOptionBuilder { 77 | for _, name := range names { 78 | b.exceptNames[name] = struct{}{} 79 | } 80 | return b 81 | } 82 | 83 | func (b *RenderOptionBuilder) Include(name string) *RenderOptionBuilder { 84 | b.includes[name] = &RenderOption{Name: name} 85 | return b 86 | } 87 | 88 | func (b *RenderOptionBuilder) IncludeWithCallback(name string, callback func(*RenderOptionBuilder)) *RenderOptionBuilder { 89 | builder := NewRenderOptionBuilder() 90 | callback(builder) 91 | opt := builder.Build() 92 | opt.Name = name 93 | b.includes[name] = opt 94 | return b 95 | } 96 | 97 | func (b *RenderOptionBuilder) IncludeAll() *RenderOptionBuilder { 98 | b.isIncludeAll = true 99 | return b 100 | } 101 | 102 | func (b *RenderOptionBuilder) Build() *RenderOption { 103 | return &RenderOption{ 104 | IsIncludeAll: b.isIncludeAll, 105 | exceptNames: b.exceptNames, 106 | includes: b.includes, 107 | onlyNames: b.onlyNames, 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /_example/03_api/model/user_api.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "context" 4 | 5 | func (m *User) Group(ctx context.Context) (*Group, error) { 6 | return nil, nil 7 | } 8 | -------------------------------------------------------------------------------- /_example/03_api/request/user_getter.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package request 4 | 5 | import ( 6 | "golang.org/x/xerrors" 7 | "net/http" 8 | ) 9 | 10 | type UserGetter struct { 11 | UserID uint64 12 | Session string 13 | } 14 | 15 | type UserGetterBuilder struct { 16 | userID *uint64 17 | } 18 | 19 | func (b *UserGetterBuilder) SetUserID(a uint64) *UserGetterBuilder { 20 | b.userID = &a 21 | return b 22 | } 23 | 24 | func (b *UserGetterBuilder) Build(r *http.Request) (*UserGetter, error) { 25 | req := &UserGetter{} 26 | if b.userID == nil { 27 | return nil, xerrors.New("userID is required. but doesn't assigned to builder") 28 | } 29 | if b.userID != nil { 30 | req.UserID = *b.userID 31 | } 32 | req.Session = r.Header.Get("X-Session") 33 | return req, nil 34 | } 35 | -------------------------------------------------------------------------------- /_example/03_api/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /_example/03_api/schema/groups.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `groups` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | 7 | -------------------------------------------------------------------------------- /_example/03_api/schema/skills.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `skills` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `skill_effect` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/03_api/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | 9 | -------------------------------------------------------------------------------- /_example/03_api/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | PRIMARY KEY (`id`), 12 | UNIQUE KEY `uq_users_01` (`name`), 13 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 14 | KEY `idx_users_03` (`group_id`), 15 | KEY `idx_users_04` (`world_id`, `field_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | -------------------------------------------------------------------------------- /_example/03_api/schema/worlds.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `worlds` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | 7 | -------------------------------------------------------------------------------- /_example/03_api/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "api/db" 5 | "api/model" 6 | "api/repository" 7 | "api/request" 8 | "api/response" 9 | "context" 10 | "database/sql" 11 | "net/http" 12 | "strconv" 13 | 14 | _ "github.com/go-sql-driver/mysql" 15 | "github.com/labstack/echo" 16 | "github.com/labstack/echo/middleware" 17 | ) 18 | 19 | var ( 20 | db *sql.DB 21 | ) 22 | 23 | func getUser(c echo.Context) error { 24 | id, _ := strconv.Atoi(c.Param("id")) 25 | req, err := new(request.UserGetterBuilder).SetUserID(uint64(id)).Build(c.Request()) 26 | if err != nil { 27 | return err 28 | } 29 | tx, err := db.Begin() 30 | if err != nil { 31 | return err 32 | } 33 | ctx := context.Background() 34 | repo := repository.New(ctx, tx) 35 | user, err := repo.User().FindByID(ctx, req.UserID) 36 | if err != nil { 37 | return err 38 | } 39 | response, err := new(response.UserGetterBuilder).SetSub(&response.UserGetterSubtype{ 40 | User: user, 41 | Param1: "sub_param1", 42 | Param2: 100, 43 | }).SetUsers(new(model.Users).Add(user)).Build(ctx) 44 | if err != nil { 45 | return err 46 | } 47 | if err := tx.Commit(); err != nil { 48 | return err 49 | } 50 | if err := c.JSON(http.StatusOK, response); err != nil { 51 | return err 52 | } 53 | return nil 54 | } 55 | 56 | func main() { 57 | e := echo.New() 58 | 59 | conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true") 60 | if err != nil { 61 | panic(err) 62 | } 63 | defer conn.Close() 64 | 65 | db = conn 66 | 67 | // Middleware 68 | e.Use(middleware.Logger()) 69 | e.Use(middleware.Recover()) 70 | 71 | // Routes 72 | e.GET("/users/:id", getUser) 73 | 74 | // Start server 75 | e.Logger.Fatal(e.Start(":1323")) 76 | } 77 | -------------------------------------------------------------------------------- /_example/03_api/testdata/seeds/field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | difficulty: 0 4 | id: 0 5 | level: 0 6 | location_x: 0 7 | location_y: 0 8 | name: "" 9 | object_num: 0 10 | collection: 11 | defaults: 12 | - *default 13 | -------------------------------------------------------------------------------- /_example/03_api/testdata/seeds/group.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/03_api/testdata/seeds/skill.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | skill_effect: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/03_api/testdata/seeds/user.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | age: 0 4 | field_id: 0 5 | group: $default 6 | group_id: 0 7 | id: 0 8 | name: "" 9 | sex: "" 10 | skill: $default 11 | skill_id: 0 12 | skill_rank: 0 13 | user_fields: $default 14 | world: $default 15 | world_id: 0 16 | collection: 17 | defaults: 18 | - *default 19 | -------------------------------------------------------------------------------- /_example/03_api/testdata/seeds/user_field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | field: $default 4 | field_id: 0 5 | id: 0 6 | user_id: 0 7 | collection: 8 | defaults: 9 | - *default 10 | -------------------------------------------------------------------------------- /_example/03_api/testdata/seeds/world.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/.eevee.yml: -------------------------------------------------------------------------------- 1 | module: daoplugin 2 | class: config 3 | schema: schema 4 | dao: 5 | default: db 6 | datastore: 7 | db: 8 | before-create: 9 | - request-time 10 | before-update: 11 | - request-time 12 | constructor-declare: user-id 13 | constructor: user-id 14 | findby-declare: user-id 15 | findby: user-id 16 | updateby-declare: user-id 17 | updateby: user-id 18 | deleteby-declare: user-id 19 | deleteby: user-id 20 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/README.md: -------------------------------------------------------------------------------- 1 | # How to work example 2 | 3 | ## 1. Automatically resolve relationships between tables at render 4 | 5 | ```go 6 | func getUser(c echo.Context) error { 7 | id, _ := strconv.Atoi(c.Param("id")) 8 | tx, err := db.Begin() 9 | if err != nil { 10 | return err 11 | } 12 | ctx := context.Background() 13 | repo := repository.New(ctx, tx) 14 | user, err := repo.User().FindByID(ctx, uint64(id)) 15 | if err != nil { 16 | return err 17 | } 18 | if err := c.JSON(http.StatusOK, user); err != nil { 19 | return err 20 | } 21 | if err := tx.Commit(); err != nil { 22 | return err 23 | } 24 | return nil 25 | } 26 | ``` 27 | 28 | ```bash 29 | $ curl localhost:1323/users/1 | jq '.' 30 | ``` 31 | 32 | ```json 33 | { 34 | "id": 1, 35 | "name": "john", 36 | "sex": "man", 37 | "age": 30, 38 | "skillId": 1, 39 | "skillRank": 10, 40 | "groupId": 1, 41 | "worldId": 1, 42 | "fieldId": 1, 43 | "userFields": [ 44 | { 45 | "id": 1, 46 | "userId": 1, 47 | "fieldId": 1, 48 | "field": { 49 | "id": 1, 50 | "name": "fieldA", 51 | "locationX": 2, 52 | "locationY": 3, 53 | "objectNum": 10, 54 | "level": 20, 55 | "difficulty": 5 56 | } 57 | } 58 | ], 59 | "skillEffect": "fire", 60 | "group": null 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/config/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - location_x 8 | - location_y 9 | keys: 10 | - - object_num 11 | - - difficulty 12 | - level 13 | read_only: true 14 | members: 15 | - name: id 16 | type: uint64 17 | - name: name 18 | type: string 19 | - name: location_x 20 | type: int 21 | - name: location_y 22 | type: int 23 | - name: object_num 24 | type: int 25 | - name: level 26 | type: int 27 | - name: difficulty 28 | type: int 29 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/config/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | datastore: db 3 | index: 4 | primary_key: id 5 | read_only: true 6 | members: 7 | - name: id 8 | type: uint64 9 | - name: name 10 | type: string 11 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/config/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | datastore: db 3 | index: 4 | primary_key: id 5 | read_only: true 6 | members: 7 | - name: id 8 | type: uint64 9 | - name: skill_effect 10 | type: string 11 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/config/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - skill_id 8 | - skill_rank 9 | keys: 10 | - - group_id 11 | - - world_id 12 | - field_id 13 | members: 14 | - name: id 15 | type: uint64 16 | - name: name 17 | type: string 18 | example: john 19 | - name: sex 20 | type: string 21 | - name: age 22 | type: int 23 | - name: skill_id 24 | type: uint64 25 | - name: skill_rank 26 | type: int 27 | - name: group_id 28 | type: uint64 29 | - name: world_id 30 | type: uint64 31 | - name: field_id 32 | type: uint64 33 | - name: created_at 34 | type: 35 | package_name: time 36 | name: Time 37 | - name: updated_at 38 | type: 39 | package_name: time 40 | name: Time 41 | - name: user_fields 42 | extend: true 43 | has_many: true 44 | relation: 45 | to: user_field 46 | internal: id 47 | external: user_id 48 | - name: skill 49 | extend: true 50 | render: 51 | inline: true 52 | relation: 53 | to: skill 54 | internal: skill_id 55 | external: id 56 | - name: group 57 | extend: true 58 | render: 59 | json: group 60 | relation: 61 | custom: true 62 | to: group 63 | - name: world 64 | extend: true 65 | render: false 66 | relation: 67 | to: world 68 | internal: world_id 69 | external: id 70 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/config/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - user_id 7 | - field_id 8 | members: 9 | - name: id 10 | type: uint64 11 | - name: user_id 12 | type: uint64 13 | - name: field_id 14 | type: uint64 15 | - name: created_at 16 | type: 17 | package_name: time 18 | name: Time 19 | - name: updated_at 20 | type: 21 | package_name: time 22 | name: Time 23 | - name: field 24 | extend: true 25 | relation: 26 | to: field 27 | internal: field_id 28 | external: id 29 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/config/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | datastore: db 3 | index: 4 | primary_key: id 5 | read_only: true 6 | members: 7 | - name: id 8 | type: uint64 9 | - name: name 10 | type: string 11 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/entity/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Field struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | LocationX int `json:"locationX"` 9 | LocationY int `json:"locationY"` 10 | ObjectNum int `json:"objectNum"` 11 | Level int `json:"level"` 12 | Difficulty int `json:"difficulty"` 13 | } 14 | 15 | type Fields []*Field 16 | 17 | func (e Fields) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e Fields) Names() []string { 26 | values := make([]string, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.Name) 29 | } 30 | return values 31 | } 32 | 33 | func (e Fields) LocationXes() []int { 34 | values := make([]int, 0, len(e)) 35 | for _, value := range e { 36 | values = append(values, value.LocationX) 37 | } 38 | return values 39 | } 40 | 41 | func (e Fields) LocationIes() []int { 42 | values := make([]int, 0, len(e)) 43 | for _, value := range e { 44 | values = append(values, value.LocationY) 45 | } 46 | return values 47 | } 48 | 49 | func (e Fields) ObjectNums() []int { 50 | values := make([]int, 0, len(e)) 51 | for _, value := range e { 52 | values = append(values, value.ObjectNum) 53 | } 54 | return values 55 | } 56 | 57 | func (e Fields) Levels() []int { 58 | values := make([]int, 0, len(e)) 59 | for _, value := range e { 60 | values = append(values, value.Level) 61 | } 62 | return values 63 | } 64 | 65 | func (e Fields) Difficulties() []int { 66 | values := make([]int, 0, len(e)) 67 | for _, value := range e { 68 | values = append(values, value.Difficulty) 69 | } 70 | return values 71 | } 72 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/entity/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Group struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Groups []*Group 11 | 12 | func (e Groups) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Groups) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/entity/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Skill struct { 6 | ID uint64 `json:"id"` 7 | SkillEffect string `json:"skillEffect"` 8 | } 9 | 10 | type Skills []*Skill 11 | 12 | func (e Skills) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Skills) SkillEffects() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.SkillEffect) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/entity/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | import "time" 6 | 7 | type User struct { 8 | ID uint64 `json:"id"` 9 | Name string `json:"name"` 10 | Sex string `json:"sex"` 11 | Age int `json:"age"` 12 | SkillID uint64 `json:"skillID"` 13 | SkillRank int `json:"skillRank"` 14 | GroupID uint64 `json:"groupID"` 15 | WorldID uint64 `json:"worldID"` 16 | FieldID uint64 `json:"fieldID"` 17 | CreatedAt time.Time `json:"createdAt"` 18 | UpdatedAt time.Time `json:"updatedAt"` 19 | } 20 | 21 | type Users []*User 22 | 23 | func (e Users) IDs() []uint64 { 24 | values := make([]uint64, 0, len(e)) 25 | for _, value := range e { 26 | values = append(values, value.ID) 27 | } 28 | return values 29 | } 30 | 31 | func (e Users) Names() []string { 32 | values := make([]string, 0, len(e)) 33 | for _, value := range e { 34 | values = append(values, value.Name) 35 | } 36 | return values 37 | } 38 | 39 | func (e Users) Sexes() []string { 40 | values := make([]string, 0, len(e)) 41 | for _, value := range e { 42 | values = append(values, value.Sex) 43 | } 44 | return values 45 | } 46 | 47 | func (e Users) Ages() []int { 48 | values := make([]int, 0, len(e)) 49 | for _, value := range e { 50 | values = append(values, value.Age) 51 | } 52 | return values 53 | } 54 | 55 | func (e Users) SkillIDs() []uint64 { 56 | values := make([]uint64, 0, len(e)) 57 | for _, value := range e { 58 | values = append(values, value.SkillID) 59 | } 60 | return values 61 | } 62 | 63 | func (e Users) SkillRanks() []int { 64 | values := make([]int, 0, len(e)) 65 | for _, value := range e { 66 | values = append(values, value.SkillRank) 67 | } 68 | return values 69 | } 70 | 71 | func (e Users) GroupIDs() []uint64 { 72 | values := make([]uint64, 0, len(e)) 73 | for _, value := range e { 74 | values = append(values, value.GroupID) 75 | } 76 | return values 77 | } 78 | 79 | func (e Users) WorldIDs() []uint64 { 80 | values := make([]uint64, 0, len(e)) 81 | for _, value := range e { 82 | values = append(values, value.WorldID) 83 | } 84 | return values 85 | } 86 | 87 | func (e Users) FieldIDs() []uint64 { 88 | values := make([]uint64, 0, len(e)) 89 | for _, value := range e { 90 | values = append(values, value.FieldID) 91 | } 92 | return values 93 | } 94 | 95 | func (e Users) CreatedAts() []time.Time { 96 | values := make([]time.Time, 0, len(e)) 97 | for _, value := range e { 98 | values = append(values, value.CreatedAt) 99 | } 100 | return values 101 | } 102 | 103 | func (e Users) UpdatedAts() []time.Time { 104 | values := make([]time.Time, 0, len(e)) 105 | for _, value := range e { 106 | values = append(values, value.UpdatedAt) 107 | } 108 | return values 109 | } 110 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/entity/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | import "time" 6 | 7 | type UserField struct { 8 | ID uint64 `json:"id"` 9 | UserID uint64 `json:"userID"` 10 | FieldID uint64 `json:"fieldID"` 11 | CreatedAt time.Time `json:"createdAt"` 12 | UpdatedAt time.Time `json:"updatedAt"` 13 | } 14 | 15 | type UserFields []*UserField 16 | 17 | func (e UserFields) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e UserFields) UserIDs() []uint64 { 26 | values := make([]uint64, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.UserID) 29 | } 30 | return values 31 | } 32 | 33 | func (e UserFields) FieldIDs() []uint64 { 34 | values := make([]uint64, 0, len(e)) 35 | for _, value := range e { 36 | values = append(values, value.FieldID) 37 | } 38 | return values 39 | } 40 | 41 | func (e UserFields) CreatedAts() []time.Time { 42 | values := make([]time.Time, 0, len(e)) 43 | for _, value := range e { 44 | values = append(values, value.CreatedAt) 45 | } 46 | return values 47 | } 48 | 49 | func (e UserFields) UpdatedAts() []time.Time { 50 | values := make([]time.Time, 0, len(e)) 51 | for _, value := range e { 52 | values = append(values, value.UpdatedAt) 53 | } 54 | return values 55 | } 56 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/entity/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type World struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Worlds []*World 11 | 12 | func (e Worlds) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Worlds) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/go.mod: -------------------------------------------------------------------------------- 1 | module daoplugin 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 7 | github.com/go-sql-driver/mysql v1.4.1 8 | github.com/labstack/echo v3.3.10+incompatible 9 | github.com/labstack/gommon v0.3.0 // indirect 10 | golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect 11 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 12 | google.golang.org/appengine v1.6.2 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/factory/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultField() *model.Field { 11 | value := &model.Field{Field: &entity.Field{ 12 | Difficulty: 0, 13 | ID: 0, 14 | Level: 0, 15 | LocationX: 0, 16 | LocationY: 0, 17 | Name: "", 18 | ObjectNum: 0, 19 | }} 20 | return value 21 | } 22 | 23 | func DefaultFields() *model.Fields { 24 | values := &model.Fields{} 25 | { 26 | value := &model.Field{Field: &entity.Field{ 27 | Difficulty: 0, 28 | ID: 0, 29 | Level: 0, 30 | LocationX: 0, 31 | LocationY: 0, 32 | Name: "", 33 | ObjectNum: 0, 34 | }} 35 | values.Add(value) 36 | } 37 | return values 38 | } 39 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/factory/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultGroup() *model.Group { 11 | value := &model.Group{Group: &entity.Group{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultGroups() *model.Groups { 19 | values := &model.Groups{} 20 | { 21 | value := &model.Group{Group: &entity.Group{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/factory/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultSkill() *model.Skill { 11 | value := &model.Skill{Skill: &entity.Skill{ 12 | ID: 0, 13 | SkillEffect: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultSkills() *model.Skills { 19 | values := &model.Skills{} 20 | { 21 | value := &model.Skill{Skill: &entity.Skill{ 22 | ID: 0, 23 | SkillEffect: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/factory/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "context" 7 | "daoplugin/entity" 8 | "daoplugin/model" 9 | "time" 10 | ) 11 | 12 | func DefaultUser() *model.User { 13 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 14 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 15 | userFields := DefaultUserFields() 16 | skill := DefaultSkill() 17 | world := DefaultWorld() 18 | value := &model.User{User: &entity.User{ 19 | Age: 0, 20 | CreatedAt: createdAt, 21 | FieldID: 0, 22 | GroupID: 0, 23 | ID: 0, 24 | Name: "john", 25 | Sex: "", 26 | SkillID: 0, 27 | SkillRank: 0, 28 | UpdatedAt: updatedAt, 29 | WorldID: 0, 30 | }} 31 | value.UserFields = func(context.Context) (*model.UserFields, error) { 32 | return userFields, nil 33 | } 34 | value.Skill = func(context.Context) (*model.Skill, error) { 35 | return skill, nil 36 | } 37 | value.World = func(context.Context) (*model.World, error) { 38 | return world, nil 39 | } 40 | return value 41 | } 42 | 43 | func DefaultUsers() *model.Users { 44 | values := &model.Users{} 45 | { 46 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 47 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 48 | userFields := DefaultUserFields() 49 | skill := DefaultSkill() 50 | world := DefaultWorld() 51 | value := &model.User{User: &entity.User{ 52 | Age: 0, 53 | CreatedAt: createdAt, 54 | FieldID: 0, 55 | GroupID: 0, 56 | ID: 0, 57 | Name: "john", 58 | Sex: "", 59 | SkillID: 0, 60 | SkillRank: 0, 61 | UpdatedAt: updatedAt, 62 | WorldID: 0, 63 | }} 64 | value.UserFields = func(context.Context) (*model.UserFields, error) { 65 | return userFields, nil 66 | } 67 | value.Skill = func(context.Context) (*model.Skill, error) { 68 | return skill, nil 69 | } 70 | value.World = func(context.Context) (*model.World, error) { 71 | return world, nil 72 | } 73 | values.Add(value) 74 | } 75 | return values 76 | } 77 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/factory/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "context" 7 | "daoplugin/entity" 8 | "daoplugin/model" 9 | "time" 10 | ) 11 | 12 | func DefaultUserField() *model.UserField { 13 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 14 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 15 | field := DefaultField() 16 | value := &model.UserField{UserField: &entity.UserField{ 17 | CreatedAt: createdAt, 18 | FieldID: 0, 19 | ID: 0, 20 | UpdatedAt: updatedAt, 21 | UserID: 0, 22 | }} 23 | value.Field = func(context.Context) (*model.Field, error) { 24 | return field, nil 25 | } 26 | return value 27 | } 28 | 29 | func DefaultUserFields() *model.UserFields { 30 | values := &model.UserFields{} 31 | { 32 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 33 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 34 | field := DefaultField() 35 | value := &model.UserField{UserField: &entity.UserField{ 36 | CreatedAt: createdAt, 37 | FieldID: 0, 38 | ID: 0, 39 | UpdatedAt: updatedAt, 40 | UserID: 0, 41 | }} 42 | value.Field = func(context.Context) (*model.Field, error) { 43 | return field, nil 44 | } 45 | values.Add(value) 46 | } 47 | return values 48 | } 49 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/factory/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultWorld() *model.World { 11 | value := &model.World{World: &entity.World{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultWorlds() *model.Worlds { 19 | values := &model.Worlds{} 20 | { 21 | value := &model.World{World: &entity.World{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultField() *model.Field { 11 | value := model.NewField(&entity.Field{ 12 | Difficulty: 1, 13 | ID: 1, 14 | Level: 1, 15 | LocationX: 1, 16 | LocationY: 1, 17 | Name: "", 18 | ObjectNum: 1, 19 | }, nil) 20 | return value 21 | } 22 | 23 | func DefaultsField() *model.Fields { 24 | values := model.NewFields(entity.Fields{}) 25 | values.Add(DefaultField()) 26 | return values 27 | } 28 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultGroup() *model.Group { 11 | value := model.NewGroup(&entity.Group{ 12 | ID: 1, 13 | Name: "", 14 | }, nil) 15 | return value 16 | } 17 | 18 | func DefaultsGroup() *model.Groups { 19 | values := model.NewGroups(entity.Groups{}) 20 | values.Add(DefaultGroup()) 21 | return values 22 | } 23 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultSkill() *model.Skill { 11 | value := model.NewSkill(&entity.Skill{ 12 | ID: 1, 13 | SkillEffect: "fire", 14 | }, nil) 15 | return value 16 | } 17 | 18 | func DefaultsSkill() *model.Skills { 19 | values := model.NewSkills(entity.Skills{}) 20 | values.Add(DefaultSkill()) 21 | return values 22 | } 23 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "context" 7 | "daoplugin/entity" 8 | "daoplugin/model" 9 | ) 10 | 11 | func DefaultUser() *model.User { 12 | value := model.NewUser(&entity.User{ 13 | Age: 0, 14 | FieldID: 0, 15 | GroupID: 0, 16 | ID: 1, 17 | Name: "john", 18 | Sex: "", 19 | SkillID: 0, 20 | SkillRank: 0, 21 | WorldID: 0, 22 | }, nil) 23 | value.UserFields = func(context.Context) (*model.UserFields, error) { 24 | return DefaultsUserField(), nil 25 | } 26 | value.Skill = func(context.Context) (*model.Skill, error) { 27 | return DefaultSkill(), nil 28 | } 29 | value.World = func(context.Context) (*model.World, error) { 30 | return DefaultWorld(), nil 31 | } 32 | return value 33 | } 34 | 35 | func DefaultsUser() *model.Users { 36 | values := model.NewUsers(entity.Users{}) 37 | values.Add(DefaultUser()) 38 | return values 39 | } 40 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "context" 7 | "daoplugin/entity" 8 | "daoplugin/model" 9 | ) 10 | 11 | func DefaultUserField() *model.UserField { 12 | value := model.NewUserField(&entity.UserField{ 13 | FieldID: 0, 14 | ID: 1, 15 | UserID: 1, 16 | }, nil) 17 | value.Field = func(context.Context) (*model.Field, error) { 18 | return DefaultField(), nil 19 | } 20 | return value 21 | } 22 | 23 | func DefaultsUserField() *model.UserFields { 24 | values := model.NewUserFields(entity.UserFields{}) 25 | values.Add(DefaultUserField()) 26 | return values 27 | } 28 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/mock/model/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "daoplugin/entity" 7 | "daoplugin/model" 8 | ) 9 | 10 | func DefaultWorld() *model.World { 11 | value := model.NewWorld(&entity.World{ 12 | ID: 1, 13 | Name: "", 14 | }, nil) 15 | return value 16 | } 17 | 18 | func DefaultsWorld() *model.Worlds { 19 | values := model.NewWorlds(entity.Worlds{}) 20 | values.Add(DefaultWorld()) 21 | return values 22 | } 23 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "context" 7 | "daoplugin/entity" 8 | ) 9 | 10 | type ModelConverter interface { 11 | ToField(*entity.Field) *Field 12 | ToGroup(*entity.Group) *Group 13 | ToSkill(*entity.Skill) *Skill 14 | ToUser(*entity.User) *User 15 | ToUserField(*entity.UserField) *UserField 16 | ToWorld(*entity.World) *World 17 | } 18 | 19 | type BeforeRenderer interface { 20 | BeforeRender(context.Context) error 21 | } 22 | 23 | type RenderOption struct { 24 | Name string 25 | IsIncludeAll bool 26 | onlyNames map[string]struct{} 27 | exceptNames map[string]struct{} 28 | includes map[string]*RenderOption 29 | } 30 | 31 | func (ro *RenderOption) Exists(name string) bool { 32 | if len(ro.onlyNames) > 0 { 33 | if _, exists := ro.onlyNames[name]; exists { 34 | return true 35 | } 36 | return false 37 | } 38 | if len(ro.exceptNames) > 0 { 39 | if _, exists := ro.exceptNames[name]; exists { 40 | return false 41 | } 42 | return true 43 | } 44 | return true 45 | } 46 | 47 | func (ro *RenderOption) IncludeOption(name string) *RenderOption { 48 | if ro.Name == name { 49 | return ro 50 | } 51 | return ro.includes[name] 52 | } 53 | 54 | type RenderOptionBuilder struct { 55 | onlyNames map[string]struct{} 56 | exceptNames map[string]struct{} 57 | includes map[string]*RenderOption 58 | isIncludeAll bool 59 | } 60 | 61 | func NewRenderOptionBuilder() *RenderOptionBuilder { 62 | return &RenderOptionBuilder{ 63 | exceptNames: map[string]struct{}{}, 64 | includes: map[string]*RenderOption{}, 65 | onlyNames: map[string]struct{}{}, 66 | } 67 | } 68 | 69 | func (b *RenderOptionBuilder) Only(names ...string) *RenderOptionBuilder { 70 | for _, name := range names { 71 | b.onlyNames[name] = struct{}{} 72 | } 73 | return b 74 | } 75 | 76 | func (b *RenderOptionBuilder) Except(names ...string) *RenderOptionBuilder { 77 | for _, name := range names { 78 | b.exceptNames[name] = struct{}{} 79 | } 80 | return b 81 | } 82 | 83 | func (b *RenderOptionBuilder) Include(name string) *RenderOptionBuilder { 84 | b.includes[name] = &RenderOption{Name: name} 85 | return b 86 | } 87 | 88 | func (b *RenderOptionBuilder) IncludeWithCallback(name string, callback func(*RenderOptionBuilder)) *RenderOptionBuilder { 89 | builder := NewRenderOptionBuilder() 90 | callback(builder) 91 | opt := builder.Build() 92 | opt.Name = name 93 | b.includes[name] = opt 94 | return b 95 | } 96 | 97 | func (b *RenderOptionBuilder) IncludeAll() *RenderOptionBuilder { 98 | b.isIncludeAll = true 99 | return b 100 | } 101 | 102 | func (b *RenderOptionBuilder) Build() *RenderOption { 103 | return &RenderOption{ 104 | IsIncludeAll: b.isIncludeAll, 105 | exceptNames: b.exceptNames, 106 | includes: b.includes, 107 | onlyNames: b.onlyNames, 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/model/user_api.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "context" 4 | 5 | func (m *User) Group(ctx context.Context) (*Group, error) { 6 | return nil, nil 7 | } 8 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/repository/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "context" 7 | "daoplugin/dao" 8 | "daoplugin/entity" 9 | "daoplugin/model" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type Group interface { 16 | ToModel(*entity.Group) *model.Group 17 | ToModels(entity.Groups) *model.Groups 18 | FindAll(context.Context) (*model.Groups, error) 19 | FindByID(context.Context, uint64) (*model.Group, error) 20 | FindByIDs(context.Context, []uint64) (*model.Groups, error) 21 | Count(context.Context) (int64, error) 22 | } 23 | 24 | type GroupImpl struct { 25 | groupDAO dao.Group 26 | repo Repository 27 | } 28 | 29 | func NewGroup(ctx context.Context, tx *sql.Tx) *GroupImpl { 30 | return &GroupImpl{groupDAO: dao.NewGroup(ctx, tx)} 31 | } 32 | 33 | func (r *GroupImpl) ToModel(value *entity.Group) *model.Group { 34 | return r.createCollection(entity.Groups{value}).First() 35 | } 36 | 37 | func (r *GroupImpl) ToModels(values entity.Groups) *model.Groups { 38 | return r.createCollection(values) 39 | } 40 | 41 | func (r *GroupImpl) FindAll(a0 context.Context) (*model.Groups, error) { 42 | values, err := r.groupDAO.FindAll(a0) 43 | if err != nil { 44 | return nil, xerrors.Errorf("failed to FindAll: %w", err) 45 | } 46 | collection := r.createCollection(values) 47 | return collection, nil 48 | } 49 | 50 | func (r *GroupImpl) FindByID(a0 context.Context, a1 uint64) (*model.Group, error) { 51 | value, err := r.groupDAO.FindByID(a0, a1) 52 | if err != nil { 53 | return nil, xerrors.Errorf("failed to FindByID: %w", err) 54 | } 55 | if value == nil { 56 | return nil, nil 57 | } 58 | v := r.createCollection(entity.Groups{value}).First() 59 | return v, nil 60 | } 61 | 62 | func (r *GroupImpl) FindByIDs(a0 context.Context, a1 []uint64) (*model.Groups, error) { 63 | values, err := r.groupDAO.FindByIDs(a0, a1) 64 | if err != nil { 65 | return nil, xerrors.Errorf("failed to FindByIDs: %w", err) 66 | } 67 | collection := r.createCollection(values) 68 | return collection, nil 69 | } 70 | 71 | func (r *GroupImpl) Count(a0 context.Context) (r0 int64, r1 error) { 72 | r0, r1 = r.groupDAO.Count(a0) 73 | if r1 != nil { 74 | r1 = xerrors.Errorf("failed to Count: %w", r1) 75 | } 76 | return 77 | } 78 | 79 | func (r *GroupImpl) createCollection(entities entity.Groups) *model.Groups { 80 | values := model.NewGroups(entities) 81 | for i := 0; i < len(entities); i += 1 { 82 | values.Add(r.create(entities[i], values)) 83 | } 84 | return values 85 | } 86 | 87 | func (r *GroupImpl) create(entity *entity.Group, values *model.Groups) *model.Group { 88 | value := model.NewGroup(entity, r.groupDAO) 89 | value.SetConverter(r.repo.(model.ModelConverter)) 90 | return value 91 | } 92 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/repository/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "context" 7 | "daoplugin/dao" 8 | "daoplugin/entity" 9 | "daoplugin/model" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type Skill interface { 16 | ToModel(*entity.Skill) *model.Skill 17 | ToModels(entity.Skills) *model.Skills 18 | FindAll(context.Context) (*model.Skills, error) 19 | FindByID(context.Context, uint64) (*model.Skill, error) 20 | FindByIDs(context.Context, []uint64) (*model.Skills, error) 21 | Count(context.Context) (int64, error) 22 | } 23 | 24 | type SkillImpl struct { 25 | skillDAO dao.Skill 26 | repo Repository 27 | } 28 | 29 | func NewSkill(ctx context.Context, tx *sql.Tx) *SkillImpl { 30 | return &SkillImpl{skillDAO: dao.NewSkill(ctx, tx)} 31 | } 32 | 33 | func (r *SkillImpl) ToModel(value *entity.Skill) *model.Skill { 34 | return r.createCollection(entity.Skills{value}).First() 35 | } 36 | 37 | func (r *SkillImpl) ToModels(values entity.Skills) *model.Skills { 38 | return r.createCollection(values) 39 | } 40 | 41 | func (r *SkillImpl) FindAll(a0 context.Context) (*model.Skills, error) { 42 | values, err := r.skillDAO.FindAll(a0) 43 | if err != nil { 44 | return nil, xerrors.Errorf("failed to FindAll: %w", err) 45 | } 46 | collection := r.createCollection(values) 47 | return collection, nil 48 | } 49 | 50 | func (r *SkillImpl) FindByID(a0 context.Context, a1 uint64) (*model.Skill, error) { 51 | value, err := r.skillDAO.FindByID(a0, a1) 52 | if err != nil { 53 | return nil, xerrors.Errorf("failed to FindByID: %w", err) 54 | } 55 | if value == nil { 56 | return nil, nil 57 | } 58 | v := r.createCollection(entity.Skills{value}).First() 59 | return v, nil 60 | } 61 | 62 | func (r *SkillImpl) FindByIDs(a0 context.Context, a1 []uint64) (*model.Skills, error) { 63 | values, err := r.skillDAO.FindByIDs(a0, a1) 64 | if err != nil { 65 | return nil, xerrors.Errorf("failed to FindByIDs: %w", err) 66 | } 67 | collection := r.createCollection(values) 68 | return collection, nil 69 | } 70 | 71 | func (r *SkillImpl) Count(a0 context.Context) (r0 int64, r1 error) { 72 | r0, r1 = r.skillDAO.Count(a0) 73 | if r1 != nil { 74 | r1 = xerrors.Errorf("failed to Count: %w", r1) 75 | } 76 | return 77 | } 78 | 79 | func (r *SkillImpl) createCollection(entities entity.Skills) *model.Skills { 80 | values := model.NewSkills(entities) 81 | for i := 0; i < len(entities); i += 1 { 82 | values.Add(r.create(entities[i], values)) 83 | } 84 | return values 85 | } 86 | 87 | func (r *SkillImpl) create(entity *entity.Skill, values *model.Skills) *model.Skill { 88 | value := model.NewSkill(entity, r.skillDAO) 89 | value.SetConverter(r.repo.(model.ModelConverter)) 90 | return value 91 | } 92 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/repository/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "context" 7 | "daoplugin/dao" 8 | "daoplugin/entity" 9 | "daoplugin/model" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type World interface { 16 | ToModel(*entity.World) *model.World 17 | ToModels(entity.Worlds) *model.Worlds 18 | FindAll(context.Context) (*model.Worlds, error) 19 | FindByID(context.Context, uint64) (*model.World, error) 20 | FindByIDs(context.Context, []uint64) (*model.Worlds, error) 21 | Count(context.Context) (int64, error) 22 | } 23 | 24 | type WorldImpl struct { 25 | worldDAO dao.World 26 | repo Repository 27 | } 28 | 29 | func NewWorld(ctx context.Context, tx *sql.Tx) *WorldImpl { 30 | return &WorldImpl{worldDAO: dao.NewWorld(ctx, tx)} 31 | } 32 | 33 | func (r *WorldImpl) ToModel(value *entity.World) *model.World { 34 | return r.createCollection(entity.Worlds{value}).First() 35 | } 36 | 37 | func (r *WorldImpl) ToModels(values entity.Worlds) *model.Worlds { 38 | return r.createCollection(values) 39 | } 40 | 41 | func (r *WorldImpl) FindAll(a0 context.Context) (*model.Worlds, error) { 42 | values, err := r.worldDAO.FindAll(a0) 43 | if err != nil { 44 | return nil, xerrors.Errorf("failed to FindAll: %w", err) 45 | } 46 | collection := r.createCollection(values) 47 | return collection, nil 48 | } 49 | 50 | func (r *WorldImpl) FindByID(a0 context.Context, a1 uint64) (*model.World, error) { 51 | value, err := r.worldDAO.FindByID(a0, a1) 52 | if err != nil { 53 | return nil, xerrors.Errorf("failed to FindByID: %w", err) 54 | } 55 | if value == nil { 56 | return nil, nil 57 | } 58 | v := r.createCollection(entity.Worlds{value}).First() 59 | return v, nil 60 | } 61 | 62 | func (r *WorldImpl) FindByIDs(a0 context.Context, a1 []uint64) (*model.Worlds, error) { 63 | values, err := r.worldDAO.FindByIDs(a0, a1) 64 | if err != nil { 65 | return nil, xerrors.Errorf("failed to FindByIDs: %w", err) 66 | } 67 | collection := r.createCollection(values) 68 | return collection, nil 69 | } 70 | 71 | func (r *WorldImpl) Count(a0 context.Context) (r0 int64, r1 error) { 72 | r0, r1 = r.worldDAO.Count(a0) 73 | if r1 != nil { 74 | r1 = xerrors.Errorf("failed to Count: %w", r1) 75 | } 76 | return 77 | } 78 | 79 | func (r *WorldImpl) createCollection(entities entity.Worlds) *model.Worlds { 80 | values := model.NewWorlds(entities) 81 | for i := 0; i < len(entities); i += 1 { 82 | values.Add(r.create(entities[i], values)) 83 | } 84 | return values 85 | } 86 | 87 | func (r *WorldImpl) create(entity *entity.World, values *model.Worlds) *model.World { 88 | value := model.NewWorld(entity, r.worldDAO) 89 | value.SetConverter(r.repo.(model.ModelConverter)) 90 | return value 91 | } 92 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/schema/groups.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `groups` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/schema/skills.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `skills` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `skill_effect` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | `created_at` datetime NOT NULL, 6 | `updated_at` datetime NOT NULL, 7 | PRIMARY KEY (`id`), 8 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 10 | 11 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | `created_at` datetime NOT NULL, 12 | `updated_at` datetime NOT NULL, 13 | PRIMARY KEY (`id`), 14 | UNIQUE KEY `uq_users_01` (`name`), 15 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 16 | KEY `idx_users_03` (`group_id`), 17 | KEY `idx_users_04` (`world_id`, `field_id`) 18 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 19 | 20 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/schema/worlds.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `worlds` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | 7 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | _ "daoplugin/db" 6 | "daoplugin/repository" 7 | "database/sql" 8 | "net/http" 9 | "strconv" 10 | 11 | _ "github.com/go-sql-driver/mysql" 12 | "github.com/labstack/echo" 13 | "github.com/labstack/echo/middleware" 14 | ) 15 | 16 | var ( 17 | db *sql.DB 18 | ) 19 | 20 | func getUser(c echo.Context) error { 21 | id, _ := strconv.Atoi(c.Param("id")) 22 | tx, err := db.Begin() 23 | if err != nil { 24 | return err 25 | } 26 | ctx := context.Background() 27 | repo := repository.New(ctx, tx, uint64(id)) 28 | user, err := repo.User().FindByID(ctx, uint64(id)) 29 | if err != nil { 30 | return err 31 | } 32 | if err := c.JSON(http.StatusOK, user); err != nil { 33 | return err 34 | } 35 | if err := tx.Commit(); err != nil { 36 | return err 37 | } 38 | return nil 39 | } 40 | 41 | func main() { 42 | e := echo.New() 43 | 44 | conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true") 45 | if err != nil { 46 | panic(err) 47 | } 48 | defer conn.Close() 49 | 50 | db = conn 51 | 52 | // Middleware 53 | e.Use(middleware.Logger()) 54 | e.Use(middleware.Recover()) 55 | 56 | // Routes 57 | e.GET("/users/:id", getUser) 58 | 59 | // Start server 60 | e.Logger.Fatal(e.Start(":1323")) 61 | } 62 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/server_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "daoplugin/mock/model" 6 | "daoplugin/mock/repository" 7 | "testing" 8 | ) 9 | 10 | func TestUserGet(t *testing.T) { 11 | repo := repository.NewMock() 12 | ctx := context.Background() 13 | repo.User().EXPECT().FindByID(ctx, 1).Return(model.DefaultUser(), nil) 14 | u, err := repo.User().FindByID(ctx, 1) 15 | if err != nil { 16 | t.Fatalf("%+v", err) 17 | } 18 | if u.ID != model.DefaultUser().ID { 19 | t.Fatal("invalid user") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/testdata/seeds/field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | difficulty: 0 4 | id: 0 5 | level: 0 6 | location_x: 0 7 | location_y: 0 8 | name: "" 9 | object_num: 0 10 | collection: 11 | defaults: 12 | - *default 13 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/testdata/seeds/group.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/testdata/seeds/skill.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | skill_effect: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/testdata/seeds/user.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | age: 0 4 | created_at: 0001-01-01T00:00:00Z 5 | field_id: 0 6 | group: $default 7 | group_id: 0 8 | id: 0 9 | name: john 10 | sex: "" 11 | skill: $default 12 | skill_id: 0 13 | skill_rank: 0 14 | updated_at: 0001-01-01T00:00:00Z 15 | user_fields: $default 16 | world: $default 17 | world_id: 0 18 | collection: 19 | defaults: 20 | - *default 21 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/testdata/seeds/user_field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | created_at: 0001-01-01T00:00:00Z 4 | field: $default 5 | field_id: 0 6 | id: 0 7 | updated_at: 0001-01-01T00:00:00Z 8 | user_id: 0 9 | collection: 10 | defaults: 11 | - *default 12 | -------------------------------------------------------------------------------- /_example/04_dao_plugin/testdata/seeds/world.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/.eevee.yml: -------------------------------------------------------------------------------- 1 | module: rapidashplugin 2 | class: config 3 | schema: schema 4 | dao: 5 | default: rapidash 6 | entity: 7 | plugins: 8 | - rapidash 9 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/README.md: -------------------------------------------------------------------------------- 1 | # How to work example 2 | 3 | ## 1. Prepare memcached and MySQL server 4 | 5 | e.g.) 6 | 7 | ```bash 8 | $ memcached -d 9 | ``` 10 | 11 | ```bash 12 | $ mysql.server start 13 | ``` 14 | 15 | ## 2. Run server 16 | 17 | ``` 18 | $ go run server.go 19 | ``` 20 | 21 | ## 3. Get user data 22 | 23 | ```bash 24 | $ curl localhost:1323/users/1 | jq '.' 25 | ``` 26 | 27 | ```json 28 | { 29 | "id": 1, 30 | "name": "john", 31 | "sex": "man", 32 | "age": 30, 33 | "skillID": 1, 34 | "skillRank": 10, 35 | "groupID": 1, 36 | "worldID": 1, 37 | "fieldID": 1, 38 | "createdAt": 1585820122, 39 | "updatedAt": 1585820122 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/config/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | datastore: rapidash 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - location_x 8 | - location_y 9 | keys: 10 | - - object_num 11 | - - difficulty 12 | - level 13 | members: 14 | - name: id 15 | type: uint64 16 | - name: name 17 | type: string 18 | - name: location_x 19 | type: int 20 | - name: location_y 21 | type: int 22 | - name: object_num 23 | type: int 24 | - name: level 25 | type: int 26 | - name: difficulty 27 | type: int 28 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/config/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | datastore: rapidash 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: name 9 | type: string 10 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/config/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | datastore: rapidash 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: skill_effect 9 | type: string 10 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/config/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | datastore: rapidash 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - skill_id 8 | - skill_rank 9 | keys: 10 | - - group_id 11 | - - world_id 12 | - field_id 13 | members: 14 | - name: id 15 | type: uint64 16 | - name: name 17 | type: string 18 | - name: sex 19 | type: string 20 | - name: age 21 | type: int 22 | - name: skill_id 23 | type: uint64 24 | - name: skill_rank 25 | type: int 26 | - name: group_id 27 | type: uint64 28 | - name: world_id 29 | type: uint64 30 | - name: field_id 31 | type: uint64 32 | - name: created_at 33 | type: 34 | import: time 35 | package_name: time 36 | name: Time 37 | - name: updated_at 38 | type: 39 | import: time 40 | package_name: time 41 | name: Time 42 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/config/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | datastore: rapidash 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - user_id 7 | - field_id 8 | members: 9 | - name: id 10 | type: uint64 11 | - name: user_id 12 | type: uint64 13 | - name: field_id 14 | type: uint64 15 | - name: created_at 16 | type: 17 | import: time 18 | package_name: time 19 | name: Time 20 | - name: updated_at 21 | type: 22 | import: time 23 | package_name: time 24 | name: Time 25 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/config/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | datastore: rapidash 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: name 9 | type: string 10 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/entity/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | import ( 6 | "go.knocknote.io/rapidash" 7 | "golang.org/x/xerrors" 8 | ) 9 | 10 | type Group struct { 11 | ID uint64 `json:"id"` 12 | Name string `json:"name"` 13 | } 14 | 15 | type Groups []*Group 16 | 17 | func (e Groups) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e Groups) Names() []string { 26 | values := make([]string, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.Name) 29 | } 30 | return values 31 | } 32 | 33 | func (e *Group) Struct() *rapidash.Struct { 34 | return rapidash.NewStruct("groups"). 35 | FieldUint64("id"). 36 | FieldString("name") 37 | } 38 | 39 | func (e *Group) EncodeRapidash(enc rapidash.Encoder) error { 40 | if e.ID != 0 { 41 | enc.Uint64("id", e.ID) 42 | } 43 | enc.String("name", e.Name) 44 | if err := enc.Error(); err != nil { 45 | return xerrors.Errorf("failed to encode: %w", err) 46 | } 47 | return nil 48 | } 49 | 50 | func (e *Groups) EncodeRapidash(enc rapidash.Encoder) error { 51 | for _, v := range *e { 52 | if err := v.EncodeRapidash(enc.New()); err != nil { 53 | return xerrors.Errorf("failed to encode: %w", err) 54 | } 55 | } 56 | return nil 57 | } 58 | 59 | func (e *Group) DecodeRapidash(dec rapidash.Decoder) error { 60 | e.ID = dec.Uint64("id") 61 | e.Name = dec.String("name") 62 | if err := dec.Error(); err != nil { 63 | return xerrors.Errorf("failed to decode: %w", err) 64 | } 65 | return nil 66 | } 67 | 68 | func (e *Groups) DecodeRapidash(dec rapidash.Decoder) error { 69 | decLen := dec.Len() 70 | values := make(Groups, decLen) 71 | for i := 0; i < decLen; i++ { 72 | var v Group 73 | if err := v.DecodeRapidash(dec.At(i)); err != nil { 74 | return xerrors.Errorf("failed to decode: %w", err) 75 | } 76 | values[i] = &v 77 | } 78 | *e = values 79 | return nil 80 | } 81 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/entity/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | import ( 6 | "go.knocknote.io/rapidash" 7 | "golang.org/x/xerrors" 8 | ) 9 | 10 | type Skill struct { 11 | ID uint64 `json:"id"` 12 | SkillEffect string `json:"skillEffect"` 13 | } 14 | 15 | type Skills []*Skill 16 | 17 | func (e Skills) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e Skills) SkillEffects() []string { 26 | values := make([]string, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.SkillEffect) 29 | } 30 | return values 31 | } 32 | 33 | func (e *Skill) Struct() *rapidash.Struct { 34 | return rapidash.NewStruct("skills"). 35 | FieldUint64("id"). 36 | FieldString("skill_effect") 37 | } 38 | 39 | func (e *Skill) EncodeRapidash(enc rapidash.Encoder) error { 40 | if e.ID != 0 { 41 | enc.Uint64("id", e.ID) 42 | } 43 | enc.String("skill_effect", e.SkillEffect) 44 | if err := enc.Error(); err != nil { 45 | return xerrors.Errorf("failed to encode: %w", err) 46 | } 47 | return nil 48 | } 49 | 50 | func (e *Skills) EncodeRapidash(enc rapidash.Encoder) error { 51 | for _, v := range *e { 52 | if err := v.EncodeRapidash(enc.New()); err != nil { 53 | return xerrors.Errorf("failed to encode: %w", err) 54 | } 55 | } 56 | return nil 57 | } 58 | 59 | func (e *Skill) DecodeRapidash(dec rapidash.Decoder) error { 60 | e.ID = dec.Uint64("id") 61 | e.SkillEffect = dec.String("skill_effect") 62 | if err := dec.Error(); err != nil { 63 | return xerrors.Errorf("failed to decode: %w", err) 64 | } 65 | return nil 66 | } 67 | 68 | func (e *Skills) DecodeRapidash(dec rapidash.Decoder) error { 69 | decLen := dec.Len() 70 | values := make(Skills, decLen) 71 | for i := 0; i < decLen; i++ { 72 | var v Skill 73 | if err := v.DecodeRapidash(dec.At(i)); err != nil { 74 | return xerrors.Errorf("failed to decode: %w", err) 75 | } 76 | values[i] = &v 77 | } 78 | *e = values 79 | return nil 80 | } 81 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/entity/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | import ( 6 | "go.knocknote.io/rapidash" 7 | "golang.org/x/xerrors" 8 | ) 9 | 10 | type World struct { 11 | ID uint64 `json:"id"` 12 | Name string `json:"name"` 13 | } 14 | 15 | type Worlds []*World 16 | 17 | func (e Worlds) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e Worlds) Names() []string { 26 | values := make([]string, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.Name) 29 | } 30 | return values 31 | } 32 | 33 | func (e *World) Struct() *rapidash.Struct { 34 | return rapidash.NewStruct("worlds"). 35 | FieldUint64("id"). 36 | FieldString("name") 37 | } 38 | 39 | func (e *World) EncodeRapidash(enc rapidash.Encoder) error { 40 | if e.ID != 0 { 41 | enc.Uint64("id", e.ID) 42 | } 43 | enc.String("name", e.Name) 44 | if err := enc.Error(); err != nil { 45 | return xerrors.Errorf("failed to encode: %w", err) 46 | } 47 | return nil 48 | } 49 | 50 | func (e *Worlds) EncodeRapidash(enc rapidash.Encoder) error { 51 | for _, v := range *e { 52 | if err := v.EncodeRapidash(enc.New()); err != nil { 53 | return xerrors.Errorf("failed to encode: %w", err) 54 | } 55 | } 56 | return nil 57 | } 58 | 59 | func (e *World) DecodeRapidash(dec rapidash.Decoder) error { 60 | e.ID = dec.Uint64("id") 61 | e.Name = dec.String("name") 62 | if err := dec.Error(); err != nil { 63 | return xerrors.Errorf("failed to decode: %w", err) 64 | } 65 | return nil 66 | } 67 | 68 | func (e *Worlds) DecodeRapidash(dec rapidash.Decoder) error { 69 | decLen := dec.Len() 70 | values := make(Worlds, decLen) 71 | for i := 0; i < decLen; i++ { 72 | var v World 73 | if err := v.DecodeRapidash(dec.At(i)); err != nil { 74 | return xerrors.Errorf("failed to decode: %w", err) 75 | } 76 | values[i] = &v 77 | } 78 | *e = values 79 | return nil 80 | } 81 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/go.mod: -------------------------------------------------------------------------------- 1 | module rapidashplugin 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 7 | github.com/go-sql-driver/mysql v1.4.1 8 | github.com/labstack/echo v3.3.10+incompatible 9 | github.com/labstack/gommon v0.3.0 // indirect 10 | go.knocknote.io/rapidash v0.3.0 11 | golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect 12 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 13 | ) 14 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/mock/model/factory/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "rapidashplugin/entity" 7 | "rapidashplugin/model" 8 | ) 9 | 10 | func DefaultField() *model.Field { 11 | value := &model.Field{Field: &entity.Field{ 12 | Difficulty: 0, 13 | ID: 0, 14 | Level: 0, 15 | LocationX: 0, 16 | LocationY: 0, 17 | Name: "", 18 | ObjectNum: 0, 19 | }} 20 | return value 21 | } 22 | 23 | func DefaultFields() *model.Fields { 24 | values := &model.Fields{} 25 | { 26 | value := &model.Field{Field: &entity.Field{ 27 | Difficulty: 0, 28 | ID: 0, 29 | Level: 0, 30 | LocationX: 0, 31 | LocationY: 0, 32 | Name: "", 33 | ObjectNum: 0, 34 | }} 35 | values.Add(value) 36 | } 37 | return values 38 | } 39 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/mock/model/factory/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "rapidashplugin/entity" 7 | "rapidashplugin/model" 8 | ) 9 | 10 | func DefaultGroup() *model.Group { 11 | value := &model.Group{Group: &entity.Group{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultGroups() *model.Groups { 19 | values := &model.Groups{} 20 | { 21 | value := &model.Group{Group: &entity.Group{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/mock/model/factory/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "rapidashplugin/entity" 7 | "rapidashplugin/model" 8 | ) 9 | 10 | func DefaultSkill() *model.Skill { 11 | value := &model.Skill{Skill: &entity.Skill{ 12 | ID: 0, 13 | SkillEffect: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultSkills() *model.Skills { 19 | values := &model.Skills{} 20 | { 21 | value := &model.Skill{Skill: &entity.Skill{ 22 | ID: 0, 23 | SkillEffect: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/mock/model/factory/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "rapidashplugin/entity" 7 | "rapidashplugin/model" 8 | "time" 9 | ) 10 | 11 | func DefaultUser() *model.User { 12 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 13 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 14 | value := &model.User{User: &entity.User{ 15 | Age: 0, 16 | CreatedAt: createdAt, 17 | FieldID: 0, 18 | GroupID: 0, 19 | ID: 0, 20 | Name: "", 21 | Sex: "", 22 | SkillID: 0, 23 | SkillRank: 0, 24 | UpdatedAt: updatedAt, 25 | WorldID: 0, 26 | }} 27 | return value 28 | } 29 | 30 | func DefaultUsers() *model.Users { 31 | values := &model.Users{} 32 | { 33 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 34 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 35 | value := &model.User{User: &entity.User{ 36 | Age: 0, 37 | CreatedAt: createdAt, 38 | FieldID: 0, 39 | GroupID: 0, 40 | ID: 0, 41 | Name: "", 42 | Sex: "", 43 | SkillID: 0, 44 | SkillRank: 0, 45 | UpdatedAt: updatedAt, 46 | WorldID: 0, 47 | }} 48 | values.Add(value) 49 | } 50 | return values 51 | } 52 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/mock/model/factory/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "rapidashplugin/entity" 7 | "rapidashplugin/model" 8 | "time" 9 | ) 10 | 11 | func DefaultUserField() *model.UserField { 12 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 13 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 14 | value := &model.UserField{UserField: &entity.UserField{ 15 | CreatedAt: createdAt, 16 | FieldID: 0, 17 | ID: 0, 18 | UpdatedAt: updatedAt, 19 | UserID: 0, 20 | }} 21 | return value 22 | } 23 | 24 | func DefaultUserFields() *model.UserFields { 25 | values := &model.UserFields{} 26 | { 27 | createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 28 | updatedAt, _ := time.Parse("2006-01-02T15:04:05Z", "0001-01-01T00:00:00Z") 29 | value := &model.UserField{UserField: &entity.UserField{ 30 | CreatedAt: createdAt, 31 | FieldID: 0, 32 | ID: 0, 33 | UpdatedAt: updatedAt, 34 | UserID: 0, 35 | }} 36 | values.Add(value) 37 | } 38 | return values 39 | } 40 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/mock/model/factory/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package factory 4 | 5 | import ( 6 | "rapidashplugin/entity" 7 | "rapidashplugin/model" 8 | ) 9 | 10 | func DefaultWorld() *model.World { 11 | value := &model.World{World: &entity.World{ 12 | ID: 0, 13 | Name: "", 14 | }} 15 | return value 16 | } 17 | 18 | func DefaultWorlds() *model.Worlds { 19 | values := &model.Worlds{} 20 | { 21 | value := &model.World{World: &entity.World{ 22 | ID: 0, 23 | Name: "", 24 | }} 25 | values.Add(value) 26 | } 27 | return values 28 | } 29 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "context" 7 | "rapidashplugin/entity" 8 | ) 9 | 10 | type ModelConverter interface { 11 | ToField(*entity.Field) *Field 12 | ToGroup(*entity.Group) *Group 13 | ToSkill(*entity.Skill) *Skill 14 | ToUser(*entity.User) *User 15 | ToUserField(*entity.UserField) *UserField 16 | ToWorld(*entity.World) *World 17 | } 18 | 19 | type BeforeRenderer interface { 20 | BeforeRender(context.Context) error 21 | } 22 | 23 | type RenderOption struct { 24 | Name string 25 | IsIncludeAll bool 26 | onlyNames map[string]struct{} 27 | exceptNames map[string]struct{} 28 | includes map[string]*RenderOption 29 | } 30 | 31 | func (ro *RenderOption) Exists(name string) bool { 32 | if len(ro.onlyNames) > 0 { 33 | if _, exists := ro.onlyNames[name]; exists { 34 | return true 35 | } 36 | return false 37 | } 38 | if len(ro.exceptNames) > 0 { 39 | if _, exists := ro.exceptNames[name]; exists { 40 | return false 41 | } 42 | return true 43 | } 44 | return true 45 | } 46 | 47 | func (ro *RenderOption) IncludeOption(name string) *RenderOption { 48 | if ro.Name == name { 49 | return ro 50 | } 51 | return ro.includes[name] 52 | } 53 | 54 | type RenderOptionBuilder struct { 55 | onlyNames map[string]struct{} 56 | exceptNames map[string]struct{} 57 | includes map[string]*RenderOption 58 | isIncludeAll bool 59 | } 60 | 61 | func NewRenderOptionBuilder() *RenderOptionBuilder { 62 | return &RenderOptionBuilder{ 63 | exceptNames: map[string]struct{}{}, 64 | includes: map[string]*RenderOption{}, 65 | onlyNames: map[string]struct{}{}, 66 | } 67 | } 68 | 69 | func (b *RenderOptionBuilder) Only(names ...string) *RenderOptionBuilder { 70 | for _, name := range names { 71 | b.onlyNames[name] = struct{}{} 72 | } 73 | return b 74 | } 75 | 76 | func (b *RenderOptionBuilder) Except(names ...string) *RenderOptionBuilder { 77 | for _, name := range names { 78 | b.exceptNames[name] = struct{}{} 79 | } 80 | return b 81 | } 82 | 83 | func (b *RenderOptionBuilder) Include(name string) *RenderOptionBuilder { 84 | b.includes[name] = &RenderOption{Name: name} 85 | return b 86 | } 87 | 88 | func (b *RenderOptionBuilder) IncludeWithCallback(name string, callback func(*RenderOptionBuilder)) *RenderOptionBuilder { 89 | builder := NewRenderOptionBuilder() 90 | callback(builder) 91 | opt := builder.Build() 92 | opt.Name = name 93 | b.includes[name] = opt 94 | return b 95 | } 96 | 97 | func (b *RenderOptionBuilder) IncludeAll() *RenderOptionBuilder { 98 | b.isIncludeAll = true 99 | return b 100 | } 101 | 102 | func (b *RenderOptionBuilder) Build() *RenderOption { 103 | return &RenderOption{ 104 | IsIncludeAll: b.isIncludeAll, 105 | exceptNames: b.exceptNames, 106 | includes: b.includes, 107 | onlyNames: b.onlyNames, 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/schema/groups.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `groups` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/schema/skills.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `skills` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `skill_effect` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | `created_at` datetime NOT NULL, 6 | `updated_at` datetime NOT NULL, 7 | PRIMARY KEY (`id`), 8 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 10 | 11 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | `created_at` datetime NOT NULL, 12 | `updated_at` datetime NOT NULL, 13 | PRIMARY KEY (`id`), 14 | UNIQUE KEY `uq_users_01` (`name`), 15 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 16 | KEY `idx_users_03` (`group_id`), 17 | KEY `idx_users_04` (`world_id`, `field_id`) 18 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 19 | 20 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/schema/worlds.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `worlds` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | 7 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "net/http" 7 | _ "rapidashplugin/db" 8 | "rapidashplugin/entity" 9 | "rapidashplugin/repository" 10 | "strconv" 11 | 12 | _ "github.com/go-sql-driver/mysql" 13 | "github.com/labstack/echo" 14 | "github.com/labstack/echo/middleware" 15 | "go.knocknote.io/rapidash" 16 | ) 17 | 18 | var ( 19 | db *sql.DB 20 | cache *rapidash.Rapidash 21 | ) 22 | 23 | func begin() (*rapidash.Tx, error) { 24 | tx, err := db.Begin() 25 | if err != nil { 26 | return nil, err 27 | } 28 | cacheTx, err := cache.Begin(tx) 29 | if err != nil { 30 | return nil, err 31 | } 32 | return cacheTx, nil 33 | } 34 | 35 | func getUser(c echo.Context) error { 36 | id, _ := strconv.Atoi(c.Param("id")) 37 | tx, err := begin() 38 | if err != nil { 39 | return err 40 | } 41 | ctx := context.Background() 42 | repo := repository.New(ctx, tx) 43 | user, err := repo.User().FindByID(ctx, uint64(id)) 44 | if err != nil { 45 | return err 46 | } 47 | if err := c.JSON(http.StatusOK, user); err != nil { 48 | return err 49 | } 50 | if err := tx.Commit(); err != nil { 51 | return err 52 | } 53 | return nil 54 | } 55 | 56 | func main() { 57 | e := echo.New() 58 | 59 | conn, err := sql.Open("mysql", "root:@tcp(localhost:3306)/eevee?parseTime=true") 60 | if err != nil { 61 | panic(err) 62 | } 63 | defer conn.Close() 64 | 65 | db = conn 66 | c, err := rapidash.New( 67 | rapidash.LogEnabled(true), 68 | rapidash.ServerAddrs([]string{"localhost:11211"}), 69 | ) 70 | if err != nil { 71 | panic(err) 72 | } 73 | if err := c.WarmUp(conn, new(entity.User).Struct(), false); err != nil { 74 | panic(err) 75 | } 76 | if err := c.WarmUp(conn, new(entity.UserField).Struct(), false); err != nil { 77 | panic(err) 78 | } 79 | if err := c.WarmUp(conn, new(entity.Field).Struct(), true); err != nil { 80 | panic(err) 81 | } 82 | if err := c.WarmUp(conn, new(entity.World).Struct(), true); err != nil { 83 | panic(err) 84 | } 85 | if err := c.WarmUp(conn, new(entity.Skill).Struct(), true); err != nil { 86 | panic(err) 87 | } 88 | cache = c 89 | 90 | // Middleware 91 | e.Use(middleware.Logger()) 92 | e.Use(middleware.Recover()) 93 | 94 | // Routes 95 | e.GET("/users/:id", getUser) 96 | 97 | // Start server 98 | e.Logger.Fatal(e.Start(":1323")) 99 | } 100 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/server_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "daoplugin/mock/model" 6 | "daoplugin/mock/repository" 7 | "testing" 8 | ) 9 | 10 | func TestUserGet(t *testing.T) { 11 | repo := repository.NewMock() 12 | ctx := context.Background() 13 | repo.User().EXPECT().FindByID(ctx, 1).Return(model.DefaultUser(), nil) 14 | u, err := repo.User().FindByID(ctx, 1) 15 | if err != nil { 16 | t.Fatalf("%+v", err) 17 | } 18 | if u.ID != model.DefaultUser().ID { 19 | t.Fatal("invalid user") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/testdata/seeds/field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | difficulty: 0 4 | id: 0 5 | level: 0 6 | location_x: 0 7 | location_y: 0 8 | name: "" 9 | object_num: 0 10 | collection: 11 | defaults: 12 | - *default 13 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/testdata/seeds/group.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/testdata/seeds/skill.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | skill_effect: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/testdata/seeds/user.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | age: 0 4 | created_at: 0001-01-01T00:00:00Z 5 | field_id: 0 6 | group_id: 0 7 | id: 0 8 | name: "" 9 | sex: "" 10 | skill_id: 0 11 | skill_rank: 0 12 | updated_at: 0001-01-01T00:00:00Z 13 | world_id: 0 14 | collection: 15 | defaults: 16 | - *default 17 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/testdata/seeds/user_field.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | created_at: 0001-01-01T00:00:00Z 4 | field_id: 0 5 | id: 0 6 | updated_at: 0001-01-01T00:00:00Z 7 | user_id: 0 8 | collection: 9 | defaults: 10 | - *default 11 | -------------------------------------------------------------------------------- /_example/05_rapidash_plugin/testdata/seeds/world.yml: -------------------------------------------------------------------------------- 1 | single: 2 | default: &default 3 | id: 0 4 | name: "" 5 | collection: 6 | defaults: 7 | - *default 8 | -------------------------------------------------------------------------------- /class/testdata/class/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - location_x 8 | - location_y 9 | keys: 10 | - - object_num 11 | - - difficulty 12 | - level 13 | members: 14 | - name: id 15 | type: uint64 16 | - name: name 17 | type: string 18 | - name: location_x 19 | type: int 20 | - name: location_y 21 | type: int 22 | - name: object_num 23 | type: int 24 | - name: level 25 | type: int 26 | - name: difficulty 27 | type: int 28 | -------------------------------------------------------------------------------- /class/testdata/class/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | datastore: db 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: name 9 | type: string 10 | -------------------------------------------------------------------------------- /class/testdata/class/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | datastore: db 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: skill_effect 9 | type: string 10 | -------------------------------------------------------------------------------- /class/testdata/class/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - name 7 | - - skill_id 8 | - skill_rank 9 | keys: 10 | - - group_id 11 | - - world_id 12 | - field_id 13 | members: 14 | - name: id 15 | type: uint64 16 | - name: name 17 | type: string 18 | - name: sex 19 | type: string 20 | - name: age 21 | type: int 22 | - name: skill_id 23 | type: uint64 24 | - name: skill_rank 25 | type: int 26 | - name: group_id 27 | type: uint64 28 | - name: world_id 29 | type: uint64 30 | - name: field_id 31 | type: uint64 32 | - name: user_fields 33 | extend: true 34 | has_many: true 35 | relation: 36 | to: user_field 37 | internal: id 38 | external: user_id 39 | - name: skill 40 | extend: true 41 | render: 42 | inline: true 43 | relation: 44 | to: skill 45 | internal: skill_id 46 | external: id 47 | - name: group 48 | extend: true 49 | render: 50 | json: group 51 | relation: 52 | custom: true 53 | to: group 54 | - name: world 55 | extend: true 56 | render: false 57 | relation: 58 | to: world 59 | internal: world_id 60 | external: id 61 | - name: tx 62 | type: 63 | import: database/sql 64 | package_name: sql 65 | name: Tx 66 | is_pointer: true 67 | extend: true 68 | render: false 69 | - name: fn 70 | type: func(context.Context) error 71 | extend: true 72 | render: false 73 | -------------------------------------------------------------------------------- /class/testdata/class/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | datastore: db 3 | index: 4 | primary_key: id 5 | unique_keys: 6 | - - user_id 7 | - field_id 8 | members: 9 | - name: id 10 | type: uint64 11 | - name: user_id 12 | type: uint64 13 | - name: field_id 14 | type: uint64 15 | -------------------------------------------------------------------------------- /class/testdata/class/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | datastore: db 3 | index: 4 | primary_key: id 5 | members: 6 | - name: id 7 | type: uint64 8 | - name: name 9 | type: string 10 | -------------------------------------------------------------------------------- /class/testdata/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /class/testdata/schema/groups.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `groups` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | 7 | -------------------------------------------------------------------------------- /class/testdata/schema/skills.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `skills` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `skill_effect` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | -------------------------------------------------------------------------------- /class/testdata/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | 9 | -------------------------------------------------------------------------------- /class/testdata/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | PRIMARY KEY (`id`), 12 | UNIQUE KEY `uq_users_01` (`name`), 13 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 14 | KEY `idx_users_03` (`group_id`), 15 | KEY `idx_users_04` (`world_id`, `field_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | -------------------------------------------------------------------------------- /class/testdata/schema/worlds.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `worlds` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 6 | 7 | -------------------------------------------------------------------------------- /code/extention.go: -------------------------------------------------------------------------------- 1 | package code 2 | 3 | type CodeHelper interface { 4 | Package(string) string 5 | } 6 | 7 | const GeneratedMarker = "Code generated by eevee. DO NOT EDIT!" 8 | const FuncGeneratedMarker = "generated by eevee" 9 | 10 | func WrapError(h CodeHelper, msg string) *Statement { 11 | return Qual(h.Package("xerrors"), "Errorf").Call(Lit(msg), Err()) 12 | } 13 | 14 | func AddStruct(f *File, name string, codes []Code) { 15 | f.Line() 16 | f.Add(GoType().Id(name).Struct(codes...)) 17 | } 18 | 19 | func TypeDef(f *File, name string, c Code) { 20 | f.Line() 21 | f.Add(GoType().Id(name).Add(c)) 22 | } 23 | 24 | type Import interface { 25 | GetPath() string 26 | GetName() string 27 | } 28 | 29 | type Imports interface { 30 | Each(func(Import)) 31 | } 32 | 33 | func NewGeneratedFile(pkg string, imports Imports) *File { 34 | f := NewFile(pkg) 35 | f.HeaderComment(GeneratedMarker) 36 | imports.Each(func(imp Import) { 37 | f.ImportName(imp.GetPath(), imp.GetName()) 38 | }) 39 | return f 40 | } 41 | -------------------------------------------------------------------------------- /config/config_test.go: -------------------------------------------------------------------------------- 1 | package config_test 2 | 3 | import ( 4 | "path/filepath" 5 | "testing" 6 | 7 | "go.knocknote.io/eevee/config" 8 | ) 9 | 10 | func TestConfig(t *testing.T) { 11 | content := ` 12 | module: test 13 | class: config/class 14 | api: config/api 15 | schema: schema 16 | graph: graph 17 | document: docs 18 | output: . 19 | dao: 20 | name: infra 21 | default: db 22 | datastore: 23 | db: 24 | before-create: request-time 25 | entity: 26 | name: entity 27 | repository: 28 | name: repository 29 | renderer: 30 | style: lower-camel 31 | plural: 32 | - name: money 33 | one: moneys 34 | context: 35 | import: app/context 36 | ` 37 | cfg, err := config.ConfigFromBytes([]byte(content)) 38 | if err != nil { 39 | t.Fatalf("%+v", err) 40 | } 41 | if cfg.OutputPathWithPackage("entity") != filepath.Join(".", "entity") { 42 | t.Fatalf("failed to get output path with package: %s", cfg.OutputPathWithPackage("entity")) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config/testdata/eevee.yml: -------------------------------------------------------------------------------- 1 | dao: 2 | datastore: 3 | db: 4 | before-create: 5 | - request-time 6 | create: request-time 7 | -------------------------------------------------------------------------------- /dao/dao_test.go: -------------------------------------------------------------------------------- 1 | package dao_test 2 | 3 | import ( 4 | "path/filepath" 5 | "testing" 6 | 7 | "go.knocknote.io/eevee/class" 8 | "go.knocknote.io/eevee/config" 9 | "go.knocknote.io/eevee/dao" 10 | _ "go.knocknote.io/eevee/plugin" 11 | ) 12 | 13 | func TestGenerate(t *testing.T) { 14 | cfg := &config.Config{ 15 | ClassPath: filepath.Join("testdata", "class"), 16 | OutputPath: filepath.Join("testdata"), 17 | } 18 | classes, err := class.NewReader().ClassByConfig(cfg) 19 | if err != nil { 20 | t.Fatalf("%+v", err) 21 | } 22 | if err := dao.NewGenerator(cfg).Generate(classes); err != nil { 23 | t.Fatalf("%+v", err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dao/testdata/class/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - name 6 | - - location_x 7 | - location_y 8 | keys: 9 | - - object_num 10 | - - difficulty 11 | - level 12 | members: 13 | - name: id 14 | type: uint64 15 | - name: name 16 | type: string 17 | - name: location_x 18 | type: int 19 | - name: location_y 20 | type: int 21 | - name: object_num 22 | type: int 23 | - name: level 24 | type: int 25 | - name: difficulty 26 | type: int 27 | -------------------------------------------------------------------------------- /dao/testdata/class/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /dao/testdata/class/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: skill_effect 8 | type: string 9 | -------------------------------------------------------------------------------- /dao/testdata/class/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | members: 3 | - name: id 4 | type: uint64 5 | - name: name 6 | type: string 7 | - name: sex 8 | type: string 9 | - name: age 10 | type: int 11 | - name: skill_id 12 | type: uint64 13 | - name: skill_rank 14 | type: int 15 | - name: group_id 16 | type: uint64 17 | - name: world_id 18 | type: uint64 19 | - name: field_id 20 | type: uint64 21 | - name: user_fields 22 | has_many: true 23 | extend: true 24 | relation: 25 | to: user_field 26 | internal: id 27 | external: user_id 28 | - name: skill 29 | extend: true 30 | relation: 31 | to: skill 32 | internal: skill_id 33 | external: id 34 | render: 35 | inline: true 36 | - name: group 37 | extend: true 38 | relation: 39 | to: group 40 | custom: true 41 | render: 42 | json: group 43 | - name: world 44 | extend: true 45 | relation: 46 | to: world 47 | internal: world_id 48 | external: id 49 | render: false 50 | - name: tx 51 | type: 52 | import: database/sql 53 | package_name: sql 54 | name: Tx 55 | is_pointer: true 56 | extend: true 57 | render: false 58 | - name: fn 59 | type: 'func(context.Context) error' 60 | extend: true 61 | render: false 62 | index: 63 | primary_key: id 64 | unique_keys: 65 | - - name 66 | - - skill_id 67 | - skill_rank 68 | keys: 69 | - - group_id 70 | - - world_id 71 | - field_id 72 | -------------------------------------------------------------------------------- /dao/testdata/class/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - user_id 6 | - field_id 7 | members: 8 | - name: id 9 | type: uint64 10 | - name: user_id 11 | type: uint64 12 | - name: field_id 13 | type: uint64 14 | -------------------------------------------------------------------------------- /dao/testdata/class/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /dao/testdata/eevee.yml: -------------------------------------------------------------------------------- 1 | dao: 2 | default: db 3 | datastore: 4 | db: 5 | before-create: 6 | - request-time 7 | constructor-declare: user-id 8 | constructor: user-id 9 | findby-declare: user-id 10 | findby: user-id 11 | updateby-declare: user-id 12 | updateby: user-id 13 | deleteby-declare: user-id 14 | deleteby: user-id 15 | cache: 16 | before-create: 17 | - request-time 18 | entity: 19 | plugins: 20 | - rapidash 21 | -------------------------------------------------------------------------------- /entity/entity_test.go: -------------------------------------------------------------------------------- 1 | package entity_test 2 | 3 | import ( 4 | "path/filepath" 5 | "testing" 6 | 7 | "go.knocknote.io/eevee/class" 8 | "go.knocknote.io/eevee/config" 9 | "go.knocknote.io/eevee/entity" 10 | _ "go.knocknote.io/eevee/plugin" 11 | ) 12 | 13 | func TestGenerate(t *testing.T) { 14 | cfg := &config.Config{ 15 | OutputPath: filepath.Join("testdata"), 16 | ClassPath: filepath.Join("testdata", "class"), 17 | } 18 | classes, err := class.NewReader().ClassByConfig(cfg) 19 | if err != nil { 20 | t.Fatalf("%+v", err) 21 | } 22 | if err := entity.NewGenerator(cfg).Generate(classes); err != nil { 23 | t.Fatalf("%+v", err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /entity/testdata/class/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - name 6 | - - location_x 7 | - location_y 8 | keys: 9 | - - object_num 10 | - - difficulty 11 | - level 12 | members: 13 | - name: id 14 | type: uint64 15 | - name: name 16 | type: string 17 | - name: location_x 18 | type: int 19 | - name: location_y 20 | type: int 21 | - name: object_num 22 | type: int 23 | - name: level 24 | type: int 25 | - name: difficulty 26 | type: int 27 | -------------------------------------------------------------------------------- /entity/testdata/class/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /entity/testdata/class/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: skill_effect 8 | type: string 9 | -------------------------------------------------------------------------------- /entity/testdata/class/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | members: 3 | - name: id 4 | type: uint64 5 | - name: name 6 | type: string 7 | - name: sex 8 | type: string 9 | - name: age 10 | type: int 11 | - name: skill_id 12 | type: uint64 13 | - name: skill_rank 14 | type: int 15 | - name: group_id 16 | type: uint64 17 | - name: world_id 18 | type: uint64 19 | - name: field_id 20 | type: uint64 21 | - name: user_fields 22 | has_many: true 23 | extend: true 24 | relation: 25 | to: user_field 26 | internal: id 27 | external: user_id 28 | - name: skill 29 | extend: true 30 | relation: 31 | to: skill 32 | internal: skill_id 33 | external: id 34 | render: 35 | inline: true 36 | - name: group 37 | extend: true 38 | relation: 39 | to: group 40 | custom: true 41 | render: 42 | json: group 43 | - name: world 44 | extend: true 45 | relation: 46 | to: world 47 | internal: world_id 48 | external: id 49 | render: false 50 | - name: tx 51 | type: 52 | import: database/sql 53 | package_name: sql 54 | name: Tx 55 | is_pointer: true 56 | extend: true 57 | render: false 58 | - name: fn 59 | type: 'func(context.Context) error' 60 | extend: true 61 | render: false 62 | index: 63 | primary_key: id 64 | unique_keys: 65 | - - name 66 | - - skill_id 67 | - skill_rank 68 | keys: 69 | - - group_id 70 | - - world_id 71 | - field_id 72 | -------------------------------------------------------------------------------- /entity/testdata/class/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - user_id 6 | - field_id 7 | members: 8 | - name: id 9 | type: uint64 10 | - name: user_id 11 | type: uint64 12 | - name: field_id 13 | type: uint64 14 | -------------------------------------------------------------------------------- /entity/testdata/class/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /entity/testdata/entity/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Field struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | LocationX int `json:"locationX"` 9 | LocationY int `json:"locationY"` 10 | ObjectNum int `json:"objectNum"` 11 | Level int `json:"level"` 12 | Difficulty int `json:"difficulty"` 13 | } 14 | 15 | type Fields []*Field 16 | 17 | func (e Fields) IDs() []uint64 { 18 | values := make([]uint64, 0, len(e)) 19 | for _, value := range e { 20 | values = append(values, value.ID) 21 | } 22 | return values 23 | } 24 | 25 | func (e Fields) Names() []string { 26 | values := make([]string, 0, len(e)) 27 | for _, value := range e { 28 | values = append(values, value.Name) 29 | } 30 | return values 31 | } 32 | 33 | func (e Fields) LocationXes() []int { 34 | values := make([]int, 0, len(e)) 35 | for _, value := range e { 36 | values = append(values, value.LocationX) 37 | } 38 | return values 39 | } 40 | 41 | func (e Fields) LocationIes() []int { 42 | values := make([]int, 0, len(e)) 43 | for _, value := range e { 44 | values = append(values, value.LocationY) 45 | } 46 | return values 47 | } 48 | 49 | func (e Fields) ObjectNums() []int { 50 | values := make([]int, 0, len(e)) 51 | for _, value := range e { 52 | values = append(values, value.ObjectNum) 53 | } 54 | return values 55 | } 56 | 57 | func (e Fields) Levels() []int { 58 | values := make([]int, 0, len(e)) 59 | for _, value := range e { 60 | values = append(values, value.Level) 61 | } 62 | return values 63 | } 64 | 65 | func (e Fields) Difficulties() []int { 66 | values := make([]int, 0, len(e)) 67 | for _, value := range e { 68 | values = append(values, value.Difficulty) 69 | } 70 | return values 71 | } 72 | -------------------------------------------------------------------------------- /entity/testdata/entity/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Group struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Groups []*Group 11 | 12 | func (e Groups) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Groups) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /entity/testdata/entity/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type Skill struct { 6 | ID uint64 `json:"id"` 7 | SkillEffect string `json:"skillEffect"` 8 | } 9 | 10 | type Skills []*Skill 11 | 12 | func (e Skills) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Skills) SkillEffects() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.SkillEffect) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /entity/testdata/entity/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type User struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | Sex string `json:"sex"` 9 | Age int `json:"age"` 10 | SkillID uint64 `json:"skillID"` 11 | SkillRank int `json:"skillRank"` 12 | GroupID uint64 `json:"groupID"` 13 | WorldID uint64 `json:"worldID"` 14 | FieldID uint64 `json:"fieldID"` 15 | } 16 | 17 | type Users []*User 18 | 19 | func (e Users) IDs() []uint64 { 20 | values := make([]uint64, 0, len(e)) 21 | for _, value := range e { 22 | values = append(values, value.ID) 23 | } 24 | return values 25 | } 26 | 27 | func (e Users) Names() []string { 28 | values := make([]string, 0, len(e)) 29 | for _, value := range e { 30 | values = append(values, value.Name) 31 | } 32 | return values 33 | } 34 | 35 | func (e Users) Sexes() []string { 36 | values := make([]string, 0, len(e)) 37 | for _, value := range e { 38 | values = append(values, value.Sex) 39 | } 40 | return values 41 | } 42 | 43 | func (e Users) Ages() []int { 44 | values := make([]int, 0, len(e)) 45 | for _, value := range e { 46 | values = append(values, value.Age) 47 | } 48 | return values 49 | } 50 | 51 | func (e Users) SkillIDs() []uint64 { 52 | values := make([]uint64, 0, len(e)) 53 | for _, value := range e { 54 | values = append(values, value.SkillID) 55 | } 56 | return values 57 | } 58 | 59 | func (e Users) SkillRanks() []int { 60 | values := make([]int, 0, len(e)) 61 | for _, value := range e { 62 | values = append(values, value.SkillRank) 63 | } 64 | return values 65 | } 66 | 67 | func (e Users) GroupIDs() []uint64 { 68 | values := make([]uint64, 0, len(e)) 69 | for _, value := range e { 70 | values = append(values, value.GroupID) 71 | } 72 | return values 73 | } 74 | 75 | func (e Users) WorldIDs() []uint64 { 76 | values := make([]uint64, 0, len(e)) 77 | for _, value := range e { 78 | values = append(values, value.WorldID) 79 | } 80 | return values 81 | } 82 | 83 | func (e Users) FieldIDs() []uint64 { 84 | values := make([]uint64, 0, len(e)) 85 | for _, value := range e { 86 | values = append(values, value.FieldID) 87 | } 88 | return values 89 | } 90 | -------------------------------------------------------------------------------- /entity/testdata/entity/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type UserField struct { 6 | ID uint64 `json:"id"` 7 | UserID uint64 `json:"userID"` 8 | FieldID uint64 `json:"fieldID"` 9 | } 10 | 11 | type UserFields []*UserField 12 | 13 | func (e UserFields) IDs() []uint64 { 14 | values := make([]uint64, 0, len(e)) 15 | for _, value := range e { 16 | values = append(values, value.ID) 17 | } 18 | return values 19 | } 20 | 21 | func (e UserFields) UserIDs() []uint64 { 22 | values := make([]uint64, 0, len(e)) 23 | for _, value := range e { 24 | values = append(values, value.UserID) 25 | } 26 | return values 27 | } 28 | 29 | func (e UserFields) FieldIDs() []uint64 { 30 | values := make([]uint64, 0, len(e)) 31 | for _, value := range e { 32 | values = append(values, value.FieldID) 33 | } 34 | return values 35 | } 36 | -------------------------------------------------------------------------------- /entity/testdata/entity/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package entity 4 | 5 | type World struct { 6 | ID uint64 `json:"id"` 7 | Name string `json:"name"` 8 | } 9 | 10 | type Worlds []*World 11 | 12 | func (e Worlds) IDs() []uint64 { 13 | values := make([]uint64, 0, len(e)) 14 | for _, value := range e { 15 | values = append(values, value.ID) 16 | } 17 | return values 18 | } 19 | 20 | func (e Worlds) Names() []string { 21 | values := make([]string, 0, len(e)) 22 | for _, value := range e { 23 | values = append(values, value.Name) 24 | } 25 | return values 26 | } 27 | -------------------------------------------------------------------------------- /entity/testdata/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /entity/testdata/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | 9 | -------------------------------------------------------------------------------- /entity/testdata/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | PRIMARY KEY (`id`), 12 | UNIQUE KEY `uq_users_01` (`name`), 13 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 14 | KEY `idx_users_03` (`group_id`), 15 | KEY `idx_users_04` (`world_id`, `field_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module go.knocknote.io/eevee 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/blastrain/vitess-sqlparser v0.0.0-20200914074247-af18b79da035 7 | github.com/dave/jennifer v1.3.0 8 | github.com/fsnotify/fsnotify v1.4.7 // indirect 9 | github.com/goccy/go-yaml v1.4.0 10 | github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 11 | github.com/jessevdk/go-flags v1.4.0 12 | github.com/jinzhu/inflection v1.0.0 13 | github.com/juju/errors v0.0.0-20190207033735-e65537c515d7 // indirect 14 | github.com/rakyll/statik v0.1.6 15 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b 16 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 17 | gopkg.in/fsnotify.v1 v1.4.7 18 | ) 19 | -------------------------------------------------------------------------------- /model/model_test.go: -------------------------------------------------------------------------------- 1 | package model_test 2 | 3 | import ( 4 | "path/filepath" 5 | "testing" 6 | 7 | "go.knocknote.io/eevee/class" 8 | "go.knocknote.io/eevee/config" 9 | "go.knocknote.io/eevee/model" 10 | _ "go.knocknote.io/eevee/plugin" 11 | ) 12 | 13 | func TestGenerate(t *testing.T) { 14 | cfg := &config.Config{ 15 | ClassPath: filepath.Join("testdata", "class"), 16 | OutputPath: filepath.Join("testdata"), 17 | } 18 | classes, err := class.NewReader().ClassByConfig(cfg) 19 | if err != nil { 20 | t.Fatalf("%+v", err) 21 | } 22 | if err := model.NewGenerator(cfg).Generate(classes); err != nil { 23 | t.Fatalf("%+v", err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /model/testdata/class/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - name 6 | - - location_x 7 | - location_y 8 | keys: 9 | - - object_num 10 | - - difficulty 11 | - level 12 | members: 13 | - name: id 14 | type: uint64 15 | - name: name 16 | type: string 17 | - name: location_x 18 | type: int 19 | - name: location_y 20 | type: int 21 | - name: object_num 22 | type: int 23 | - name: level 24 | type: int 25 | - name: difficulty 26 | type: int 27 | -------------------------------------------------------------------------------- /model/testdata/class/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /model/testdata/class/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: skill_effect 8 | type: string 9 | -------------------------------------------------------------------------------- /model/testdata/class/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | members: 3 | - name: id 4 | type: uint64 5 | - name: name 6 | type: string 7 | - name: sex 8 | type: string 9 | - name: age 10 | type: int 11 | - name: skill_id 12 | type: uint64 13 | - name: skill_rank 14 | type: int 15 | - name: group_id 16 | type: uint64 17 | - name: world_id 18 | type: uint64 19 | - name: field_id 20 | type: uint64 21 | - name: user_fields 22 | has_many: true 23 | extend: true 24 | relation: 25 | to: user_field 26 | internal: id 27 | external: user_id 28 | - name: skill 29 | extend: true 30 | relation: 31 | to: skill 32 | internal: skill_id 33 | external: id 34 | render: 35 | inline: true 36 | - name: group 37 | extend: true 38 | relation: 39 | to: group 40 | custom: true 41 | render: 42 | json: group 43 | - name: world 44 | extend: true 45 | relation: 46 | to: world 47 | internal: world_id 48 | external: id 49 | render: false 50 | - name: tx 51 | type: 52 | import: database/sql 53 | package_name: sql 54 | name: Tx 55 | is_pointer: true 56 | extend: true 57 | render: false 58 | - name: fn 59 | type: 'func(context.Context) error' 60 | extend: true 61 | render: false 62 | index: 63 | primary_key: id 64 | unique_keys: 65 | - - name 66 | - - skill_id 67 | - skill_rank 68 | keys: 69 | - - group_id 70 | - - world_id 71 | - field_id 72 | -------------------------------------------------------------------------------- /model/testdata/class/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - user_id 6 | - field_id 7 | members: 8 | - name: id 9 | type: uint64 10 | - name: user_id 11 | type: uint64 12 | - name: field_id 13 | type: uint64 14 | -------------------------------------------------------------------------------- /model/testdata/class/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /model/testdata/model/model.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package model 4 | 5 | import ( 6 | "/entity" 7 | "context" 8 | ) 9 | 10 | type ModelConverter interface { 11 | ToField(*entity.Field) *Field 12 | ToGroup(*entity.Group) *Group 13 | ToSkill(*entity.Skill) *Skill 14 | ToUser(*entity.User) *User 15 | ToUserField(*entity.UserField) *UserField 16 | ToWorld(*entity.World) *World 17 | } 18 | 19 | type BeforeRenderer interface { 20 | BeforeRender(context.Context) error 21 | } 22 | 23 | type RenderOption struct { 24 | Name string 25 | IsIncludeAll bool 26 | onlyNames map[string]struct{} 27 | exceptNames map[string]struct{} 28 | includes map[string]*RenderOption 29 | } 30 | 31 | func (ro *RenderOption) Exists(name string) bool { 32 | if len(ro.onlyNames) > 0 { 33 | if _, exists := ro.onlyNames[name]; exists { 34 | return true 35 | } 36 | return false 37 | } 38 | if len(ro.exceptNames) > 0 { 39 | if _, exists := ro.exceptNames[name]; exists { 40 | return false 41 | } 42 | return true 43 | } 44 | return true 45 | } 46 | 47 | func (ro *RenderOption) IncludeOption(name string) *RenderOption { 48 | if ro.Name == name { 49 | return ro 50 | } 51 | return ro.includes[name] 52 | } 53 | 54 | type RenderOptionBuilder struct { 55 | onlyNames map[string]struct{} 56 | exceptNames map[string]struct{} 57 | includes map[string]*RenderOption 58 | isIncludeAll bool 59 | } 60 | 61 | func NewRenderOptionBuilder() *RenderOptionBuilder { 62 | return &RenderOptionBuilder{ 63 | exceptNames: map[string]struct{}{}, 64 | includes: map[string]*RenderOption{}, 65 | onlyNames: map[string]struct{}{}, 66 | } 67 | } 68 | 69 | func (b *RenderOptionBuilder) Only(names ...string) *RenderOptionBuilder { 70 | for _, name := range names { 71 | b.onlyNames[name] = struct{}{} 72 | } 73 | return b 74 | } 75 | 76 | func (b *RenderOptionBuilder) Except(names ...string) *RenderOptionBuilder { 77 | for _, name := range names { 78 | b.exceptNames[name] = struct{}{} 79 | } 80 | return b 81 | } 82 | 83 | func (b *RenderOptionBuilder) Include(name string) *RenderOptionBuilder { 84 | b.includes[name] = &RenderOption{Name: name} 85 | return b 86 | } 87 | 88 | func (b *RenderOptionBuilder) IncludeWithCallback(name string, callback func(*RenderOptionBuilder)) *RenderOptionBuilder { 89 | builder := NewRenderOptionBuilder() 90 | callback(builder) 91 | opt := builder.Build() 92 | opt.Name = name 93 | b.includes[name] = opt 94 | return b 95 | } 96 | 97 | func (b *RenderOptionBuilder) IncludeAll() *RenderOptionBuilder { 98 | b.isIncludeAll = true 99 | return b 100 | } 101 | 102 | func (b *RenderOptionBuilder) Build() *RenderOption { 103 | return &RenderOption{ 104 | IsIncludeAll: b.isIncludeAll, 105 | exceptNames: b.exceptNames, 106 | includes: b.includes, 107 | onlyNames: b.onlyNames, 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /model/testdata/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /model/testdata/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | 9 | -------------------------------------------------------------------------------- /model/testdata/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | PRIMARY KEY (`id`), 12 | UNIQUE KEY `uq_users_01` (`name`), 13 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 14 | KEY `idx_users_03` (`group_id`), 15 | KEY `idx_users_04` (`world_id`, `field_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | -------------------------------------------------------------------------------- /plugin/eevee-octillery-plugin/dao.go: -------------------------------------------------------------------------------- 1 | package eevee 2 | 3 | import ( 4 | "go.knocknote.io/eevee/plugin/dao" 5 | "go.knocknote.io/eevee/types" 6 | ) 7 | 8 | type OctilleryDataAccessHandler struct { 9 | dao.DefaultPlugin 10 | } 11 | 12 | func init() { 13 | dao.Register("octillery", &OctilleryDataAccessHandler{}) 14 | } 15 | 16 | func (*OctilleryDataAccessHandler) Imports(pkgs types.ImportList) types.ImportList { 17 | for _, decl := range []*types.ImportDeclare{ 18 | { 19 | Path: "go.knocknote.io/octillery/database/sql", 20 | Name: "sql", 21 | }, 22 | } { 23 | pkgs[decl.Name] = decl 24 | } 25 | return pkgs 26 | } 27 | -------------------------------------------------------------------------------- /plugin/eevee-request-time-plugin/dao.go: -------------------------------------------------------------------------------- 1 | package eevee 2 | 3 | import ( 4 | . "go.knocknote.io/eevee/code" 5 | "go.knocknote.io/eevee/plugin/dao" 6 | "go.knocknote.io/eevee/types" 7 | ) 8 | 9 | type DAORequestTimePlugin struct { 10 | dao.DefaultPlugin 11 | } 12 | 13 | func init() { 14 | dao.Register("request-time", &DAORequestTimePlugin{}) 15 | } 16 | 17 | func (*DAORequestTimePlugin) BeforeCreate(p *types.CreateParam) []Code { 18 | createdAt := p.Class.MemberByName("created_at") 19 | updatedAt := p.Class.MemberByName("updated_at") 20 | if createdAt == nil || updatedAt == nil { 21 | return nil 22 | } 23 | code := []Code{ 24 | Id("v").Op(":=").Id("ctx").Dot("Value").Call(Lit("REQUEST_TIME")), 25 | List(Id("requestTime"), Id("ok")).Op(":=").Id("v").Assert(Qual(p.Package("time"), "Time")), 26 | If( 27 | Add(Op("!")).Id("ok"), 28 | ).Block( 29 | Return(Qual(p.Package("xerrors"), "New").Call(Lit("cannot convert time.Time value from ctx.Value(`REQUEST_TIME`)"))), 30 | ), 31 | } 32 | if createdAt.Type.IsPointer { 33 | code = append(code, Id("value").Dot("CreatedAt").Op("=").Op("&").Id("requestTime")) 34 | } else { 35 | code = append(code, Id("value").Dot("CreatedAt").Op("=").Id("requestTime")) 36 | } 37 | if updatedAt.Type.IsPointer { 38 | code = append(code, Id("value").Dot("UpdatedAt").Op("=").Op("&").Id("requestTime")) 39 | } else { 40 | code = append(code, Id("value").Dot("UpdatedAt").Op("=").Id("requestTime")) 41 | } 42 | return code 43 | } 44 | 45 | func (*DAORequestTimePlugin) BeforeUpdate(p *types.UpdateParam) []Code { 46 | updatedAt := p.Class.MemberByName("updated_at") 47 | if updatedAt == nil { 48 | return nil 49 | } 50 | code := []Code{ 51 | Id("v").Op(":=").Id("ctx").Dot("Value").Call(Lit("REQUEST_TIME")), 52 | List(Id("requestTime"), Id("ok")).Op(":=").Id("v").Assert(Qual(p.Package("time"), "Time")), 53 | If( 54 | Add(Op("!")).Id("ok"), 55 | ).Block( 56 | Return(Qual(p.Package("xerrors"), "New").Call(Lit("cannot convert time.Time value from ctx.Value(`REQUEST_TIME`)"))), 57 | ), 58 | } 59 | if updatedAt.Type.IsPointer { 60 | code = append(code, Id("value").Dot("UpdatedAt").Op("=").Op("&").Id("requestTime")) 61 | } else { 62 | code = append(code, Id("value").Dot("UpdatedAt").Op("=").Id("requestTime")) 63 | } 64 | return code 65 | } 66 | -------------------------------------------------------------------------------- /plugin/entity/interface.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | import "go.knocknote.io/eevee/types" 4 | 5 | const ( 6 | // AddMethodsPlugin name for hook of AddMethods 7 | AddMethodsPlugin = "add-methods" 8 | ) 9 | 10 | type EntityPlugin interface { 11 | Imports(types.ImportList) types.ImportList 12 | AddMethods(*types.EntityMethodHelper) types.Methods 13 | } 14 | 15 | var ( 16 | plugins = map[string]EntityPlugin{} 17 | ) 18 | 19 | func Register(name string, plugin EntityPlugin) { 20 | plugins[name] = plugin 21 | } 22 | 23 | func Plugin(name string) (EntityPlugin, bool) { 24 | plugin, ok := plugins[name] 25 | return plugin, ok 26 | } 27 | 28 | func Plugins() []EntityPlugin { 29 | plgs := []EntityPlugin{} 30 | for _, plg := range plugins { 31 | plgs = append(plgs, plg) 32 | } 33 | return plgs 34 | } 35 | -------------------------------------------------------------------------------- /plugin/plugin.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | _ "go.knocknote.io/eevee/plugin/eevee-octillery-plugin" 5 | _ "go.knocknote.io/eevee/plugin/eevee-rapidash-plugin" 6 | _ "go.knocknote.io/eevee/plugin/eevee-request-time-plugin" 7 | _ "go.knocknote.io/eevee/plugin/eevee-user-id-plugin" 8 | ) 9 | -------------------------------------------------------------------------------- /plural/plural.go: -------------------------------------------------------------------------------- 1 | package plural 2 | 3 | import ( 4 | "regexp" 5 | 6 | "github.com/jinzhu/inflection" 7 | ) 8 | 9 | func Singular(name string) string { 10 | return inflection.Singular(name) 11 | } 12 | 13 | var ( 14 | numPattern = regexp.MustCompile(`([0-9]+)$`) 15 | ) 16 | 17 | func Plural(name string) string { 18 | if numPattern.MatchString(name) { 19 | return name + "s" 20 | } 21 | return inflection.Plural(name) 22 | } 23 | 24 | func Register(singular, plural string) { 25 | inflection.AddIrregular(singular, plural) 26 | } 27 | -------------------------------------------------------------------------------- /renderer/renderer.go: -------------------------------------------------------------------------------- 1 | package renderer 2 | 3 | import ( 4 | . "go.knocknote.io/eevee/code" 5 | "go.knocknote.io/eevee/types" 6 | ) 7 | 8 | type RendererHelper interface { 9 | Receiver() *Statement 10 | Field(string) *Statement 11 | MethodCall(string, ...Code) *Statement 12 | Package(string) string 13 | GetClass() *types.Class 14 | GetImportList() types.ImportList 15 | IsModelPackage() bool 16 | CreateMethodDeclare() *types.MethodDeclare 17 | CreateCollectionMethodDeclare() *types.MethodDeclare 18 | } 19 | 20 | type Renderer interface { 21 | Render(RendererHelper) *types.Method 22 | RenderWithOption(RendererHelper) *types.Method 23 | RenderCollection(RendererHelper) *types.Method 24 | RenderCollectionWithOption(RendererHelper) *types.Method 25 | Marshaler(RendererHelper) *types.Method 26 | MarshalerContext(RendererHelper) *types.Method 27 | MarshalerCollection(RendererHelper) *types.Method 28 | MarshalerCollectionContext(RendererHelper) *types.Method 29 | Unmarshaler(RendererHelper) *types.Method 30 | UnmarshalerCollection(RendererHelper) *types.Method 31 | } 32 | -------------------------------------------------------------------------------- /repository/repository_test.go: -------------------------------------------------------------------------------- 1 | package repository_test 2 | 3 | import ( 4 | "path/filepath" 5 | "testing" 6 | 7 | "go.knocknote.io/eevee/class" 8 | "go.knocknote.io/eevee/config" 9 | _ "go.knocknote.io/eevee/plugin" 10 | "go.knocknote.io/eevee/repository" 11 | ) 12 | 13 | func TestGenerate(t *testing.T) { 14 | cfg := &config.Config{ 15 | ClassPath: filepath.Join("testdata", "class"), 16 | OutputPath: filepath.Join("testdata"), 17 | } 18 | classes, err := class.NewReader().ClassByConfig(cfg) 19 | if err != nil { 20 | t.Fatalf("%+v", err) 21 | } 22 | if err := repository.NewGenerator(cfg).Generate(classes); err != nil { 23 | t.Fatalf("%+v", err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /repository/testdata/class/field.yml: -------------------------------------------------------------------------------- 1 | name: field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - name 6 | - - location_x 7 | - location_y 8 | keys: 9 | - - object_num 10 | - - difficulty 11 | - level 12 | members: 13 | - name: id 14 | type: uint64 15 | - name: name 16 | type: string 17 | - name: location_x 18 | type: int 19 | - name: location_y 20 | type: int 21 | - name: object_num 22 | type: int 23 | - name: level 24 | type: int 25 | - name: difficulty 26 | type: int 27 | -------------------------------------------------------------------------------- /repository/testdata/class/group.yml: -------------------------------------------------------------------------------- 1 | name: group 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /repository/testdata/class/skill.yml: -------------------------------------------------------------------------------- 1 | name: skill 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: skill_effect 8 | type: string 9 | -------------------------------------------------------------------------------- /repository/testdata/class/user.yml: -------------------------------------------------------------------------------- 1 | name: user 2 | members: 3 | - name: id 4 | type: uint64 5 | - name: name 6 | type: string 7 | - name: sex 8 | type: string 9 | - name: age 10 | type: int 11 | - name: skill_id 12 | type: uint64 13 | - name: skill_rank 14 | type: int 15 | - name: group_id 16 | type: uint64 17 | - name: world_id 18 | type: uint64 19 | - name: field_id 20 | type: uint64 21 | - name: user_fields 22 | has_many: true 23 | extend: true 24 | relation: 25 | to: user_field 26 | internal: id 27 | external: user_id 28 | - name: skill 29 | extend: true 30 | relation: 31 | to: skill 32 | internal: skill_id 33 | external: id 34 | render: 35 | inline: true 36 | - name: group 37 | extend: true 38 | relation: 39 | to: group 40 | custom: true 41 | render: 42 | json: group 43 | - name: world 44 | extend: true 45 | relation: 46 | to: world 47 | internal: world_id 48 | external: id 49 | render: false 50 | - name: tx 51 | type: 52 | import: database/sql 53 | package_name: sql 54 | name: Tx 55 | is_pointer: true 56 | extend: true 57 | render: false 58 | - name: fn 59 | type: 'func(context.Context) error' 60 | extend: true 61 | render: false 62 | index: 63 | primary_key: id 64 | unique_keys: 65 | - - name 66 | - - skill_id 67 | - skill_rank 68 | keys: 69 | - - group_id 70 | - - world_id 71 | - field_id 72 | -------------------------------------------------------------------------------- /repository/testdata/class/user_field.yml: -------------------------------------------------------------------------------- 1 | name: user_field 2 | index: 3 | primary_key: id 4 | unique_keys: 5 | - - user_id 6 | - field_id 7 | members: 8 | - name: id 9 | type: uint64 10 | - name: user_id 11 | type: uint64 12 | - name: field_id 13 | type: uint64 14 | -------------------------------------------------------------------------------- /repository/testdata/class/world.yml: -------------------------------------------------------------------------------- 1 | name: world 2 | index: 3 | primary_key: id 4 | members: 5 | - name: id 6 | type: uint64 7 | - name: name 8 | type: string 9 | -------------------------------------------------------------------------------- /repository/testdata/repository/field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "/dao" 7 | "/entity" 8 | "/model" 9 | "context" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type Field interface { 16 | ToModel(*entity.Field) *model.Field 17 | ToModels(entity.Fields) *model.Fields 18 | Create(context.Context, *entity.Field) (*model.Field, error) 19 | Creates(context.Context, entity.Fields) (*model.Fields, error) 20 | } 21 | 22 | type FieldImpl struct { 23 | fieldDAO dao.Field 24 | repo Repository 25 | } 26 | 27 | func NewField(ctx context.Context, tx *sql.Tx) *FieldImpl { 28 | return &FieldImpl{fieldDAO: dao.NewField(ctx, tx)} 29 | } 30 | 31 | func (r *FieldImpl) ToModel(value *entity.Field) *model.Field { 32 | return r.createCollection(entity.Fields{value}).First() 33 | } 34 | 35 | func (r *FieldImpl) ToModels(values entity.Fields) *model.Fields { 36 | return r.createCollection(values) 37 | } 38 | 39 | func (r *FieldImpl) Create(ctx context.Context, value *entity.Field) (*model.Field, error) { 40 | if err := r.fieldDAO.Create(ctx, value); err != nil { 41 | return nil, xerrors.Errorf("cannot Create: %w", err) 42 | } 43 | v := r.ToModel(value) 44 | v.SetSavedValue(value) 45 | v.SetAlreadyCreated(true) 46 | return v, nil 47 | } 48 | 49 | func (r *FieldImpl) Creates(ctx context.Context, entities entity.Fields) (*model.Fields, error) { 50 | for _, v := range entities { 51 | if _, err := r.Create(ctx, v); err != nil { 52 | return nil, xerrors.Errorf("cannot Create: %w", err) 53 | } 54 | } 55 | values := r.ToModels(entities) 56 | values.Each(func(v *model.Field) { 57 | v.SetSavedValue(v.Field) 58 | v.SetAlreadyCreated(true) 59 | }) 60 | return values, nil 61 | } 62 | 63 | func (r *FieldImpl) createCollection(entities entity.Fields) *model.Fields { 64 | values := model.NewFields(entities) 65 | for i := 0; i < len(entities); i += 1 { 66 | values.Add(r.create(entities[i], values)) 67 | } 68 | return values 69 | } 70 | 71 | func (r *FieldImpl) create(entity *entity.Field, values *model.Fields) *model.Field { 72 | value := model.NewField(entity, r.fieldDAO) 73 | value.SetConverter(r.repo.(model.ModelConverter)) 74 | return value 75 | } 76 | -------------------------------------------------------------------------------- /repository/testdata/repository/group.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "/dao" 7 | "/entity" 8 | "/model" 9 | "context" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type Group interface { 16 | ToModel(*entity.Group) *model.Group 17 | ToModels(entity.Groups) *model.Groups 18 | Create(context.Context, *entity.Group) (*model.Group, error) 19 | Creates(context.Context, entity.Groups) (*model.Groups, error) 20 | } 21 | 22 | type GroupImpl struct { 23 | groupDAO dao.Group 24 | repo Repository 25 | } 26 | 27 | func NewGroup(ctx context.Context, tx *sql.Tx) *GroupImpl { 28 | return &GroupImpl{groupDAO: dao.NewGroup(ctx, tx)} 29 | } 30 | 31 | func (r *GroupImpl) ToModel(value *entity.Group) *model.Group { 32 | return r.createCollection(entity.Groups{value}).First() 33 | } 34 | 35 | func (r *GroupImpl) ToModels(values entity.Groups) *model.Groups { 36 | return r.createCollection(values) 37 | } 38 | 39 | func (r *GroupImpl) Create(ctx context.Context, value *entity.Group) (*model.Group, error) { 40 | if err := r.groupDAO.Create(ctx, value); err != nil { 41 | return nil, xerrors.Errorf("cannot Create: %w", err) 42 | } 43 | v := r.ToModel(value) 44 | v.SetSavedValue(value) 45 | v.SetAlreadyCreated(true) 46 | return v, nil 47 | } 48 | 49 | func (r *GroupImpl) Creates(ctx context.Context, entities entity.Groups) (*model.Groups, error) { 50 | for _, v := range entities { 51 | if _, err := r.Create(ctx, v); err != nil { 52 | return nil, xerrors.Errorf("cannot Create: %w", err) 53 | } 54 | } 55 | values := r.ToModels(entities) 56 | values.Each(func(v *model.Group) { 57 | v.SetSavedValue(v.Group) 58 | v.SetAlreadyCreated(true) 59 | }) 60 | return values, nil 61 | } 62 | 63 | func (r *GroupImpl) createCollection(entities entity.Groups) *model.Groups { 64 | values := model.NewGroups(entities) 65 | for i := 0; i < len(entities); i += 1 { 66 | values.Add(r.create(entities[i], values)) 67 | } 68 | return values 69 | } 70 | 71 | func (r *GroupImpl) create(entity *entity.Group, values *model.Groups) *model.Group { 72 | value := model.NewGroup(entity, r.groupDAO) 73 | value.SetConverter(r.repo.(model.ModelConverter)) 74 | return value 75 | } 76 | -------------------------------------------------------------------------------- /repository/testdata/repository/skill.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "/dao" 7 | "/entity" 8 | "/model" 9 | "context" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type Skill interface { 16 | ToModel(*entity.Skill) *model.Skill 17 | ToModels(entity.Skills) *model.Skills 18 | Create(context.Context, *entity.Skill) (*model.Skill, error) 19 | Creates(context.Context, entity.Skills) (*model.Skills, error) 20 | } 21 | 22 | type SkillImpl struct { 23 | skillDAO dao.Skill 24 | repo Repository 25 | } 26 | 27 | func NewSkill(ctx context.Context, tx *sql.Tx) *SkillImpl { 28 | return &SkillImpl{skillDAO: dao.NewSkill(ctx, tx)} 29 | } 30 | 31 | func (r *SkillImpl) ToModel(value *entity.Skill) *model.Skill { 32 | return r.createCollection(entity.Skills{value}).First() 33 | } 34 | 35 | func (r *SkillImpl) ToModels(values entity.Skills) *model.Skills { 36 | return r.createCollection(values) 37 | } 38 | 39 | func (r *SkillImpl) Create(ctx context.Context, value *entity.Skill) (*model.Skill, error) { 40 | if err := r.skillDAO.Create(ctx, value); err != nil { 41 | return nil, xerrors.Errorf("cannot Create: %w", err) 42 | } 43 | v := r.ToModel(value) 44 | v.SetSavedValue(value) 45 | v.SetAlreadyCreated(true) 46 | return v, nil 47 | } 48 | 49 | func (r *SkillImpl) Creates(ctx context.Context, entities entity.Skills) (*model.Skills, error) { 50 | for _, v := range entities { 51 | if _, err := r.Create(ctx, v); err != nil { 52 | return nil, xerrors.Errorf("cannot Create: %w", err) 53 | } 54 | } 55 | values := r.ToModels(entities) 56 | values.Each(func(v *model.Skill) { 57 | v.SetSavedValue(v.Skill) 58 | v.SetAlreadyCreated(true) 59 | }) 60 | return values, nil 61 | } 62 | 63 | func (r *SkillImpl) createCollection(entities entity.Skills) *model.Skills { 64 | values := model.NewSkills(entities) 65 | for i := 0; i < len(entities); i += 1 { 66 | values.Add(r.create(entities[i], values)) 67 | } 68 | return values 69 | } 70 | 71 | func (r *SkillImpl) create(entity *entity.Skill, values *model.Skills) *model.Skill { 72 | value := model.NewSkill(entity, r.skillDAO) 73 | value.SetConverter(r.repo.(model.ModelConverter)) 74 | return value 75 | } 76 | -------------------------------------------------------------------------------- /repository/testdata/repository/user_field.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "/dao" 7 | "/entity" 8 | "/model" 9 | "context" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type UserField interface { 16 | ToModel(*entity.UserField) *model.UserField 17 | ToModels(entity.UserFields) *model.UserFields 18 | Create(context.Context, *entity.UserField) (*model.UserField, error) 19 | Creates(context.Context, entity.UserFields) (*model.UserFields, error) 20 | } 21 | 22 | type UserFieldImpl struct { 23 | userFieldDAO dao.UserField 24 | repo Repository 25 | } 26 | 27 | func NewUserField(ctx context.Context, tx *sql.Tx) *UserFieldImpl { 28 | return &UserFieldImpl{userFieldDAO: dao.NewUserField(ctx, tx)} 29 | } 30 | 31 | func (r *UserFieldImpl) ToModel(value *entity.UserField) *model.UserField { 32 | return r.createCollection(entity.UserFields{value}).First() 33 | } 34 | 35 | func (r *UserFieldImpl) ToModels(values entity.UserFields) *model.UserFields { 36 | return r.createCollection(values) 37 | } 38 | 39 | func (r *UserFieldImpl) Create(ctx context.Context, value *entity.UserField) (*model.UserField, error) { 40 | if err := r.userFieldDAO.Create(ctx, value); err != nil { 41 | return nil, xerrors.Errorf("cannot Create: %w", err) 42 | } 43 | v := r.ToModel(value) 44 | v.SetSavedValue(value) 45 | v.SetAlreadyCreated(true) 46 | return v, nil 47 | } 48 | 49 | func (r *UserFieldImpl) Creates(ctx context.Context, entities entity.UserFields) (*model.UserFields, error) { 50 | for _, v := range entities { 51 | if _, err := r.Create(ctx, v); err != nil { 52 | return nil, xerrors.Errorf("cannot Create: %w", err) 53 | } 54 | } 55 | values := r.ToModels(entities) 56 | values.Each(func(v *model.UserField) { 57 | v.SetSavedValue(v.UserField) 58 | v.SetAlreadyCreated(true) 59 | }) 60 | return values, nil 61 | } 62 | 63 | func (r *UserFieldImpl) createCollection(entities entity.UserFields) *model.UserFields { 64 | values := model.NewUserFields(entities) 65 | for i := 0; i < len(entities); i += 1 { 66 | values.Add(r.create(entities[i], values)) 67 | } 68 | return values 69 | } 70 | 71 | func (r *UserFieldImpl) create(entity *entity.UserField, values *model.UserFields) *model.UserField { 72 | value := model.NewUserField(entity, r.userFieldDAO) 73 | value.SetConverter(r.repo.(model.ModelConverter)) 74 | return value 75 | } 76 | -------------------------------------------------------------------------------- /repository/testdata/repository/world.go: -------------------------------------------------------------------------------- 1 | // Code generated by eevee. DO NOT EDIT! 2 | 3 | package repository 4 | 5 | import ( 6 | "/dao" 7 | "/entity" 8 | "/model" 9 | "context" 10 | "database/sql" 11 | 12 | "golang.org/x/xerrors" 13 | ) 14 | 15 | type World interface { 16 | ToModel(*entity.World) *model.World 17 | ToModels(entity.Worlds) *model.Worlds 18 | Create(context.Context, *entity.World) (*model.World, error) 19 | Creates(context.Context, entity.Worlds) (*model.Worlds, error) 20 | } 21 | 22 | type WorldImpl struct { 23 | worldDAO dao.World 24 | repo Repository 25 | } 26 | 27 | func NewWorld(ctx context.Context, tx *sql.Tx) *WorldImpl { 28 | return &WorldImpl{worldDAO: dao.NewWorld(ctx, tx)} 29 | } 30 | 31 | func (r *WorldImpl) ToModel(value *entity.World) *model.World { 32 | return r.createCollection(entity.Worlds{value}).First() 33 | } 34 | 35 | func (r *WorldImpl) ToModels(values entity.Worlds) *model.Worlds { 36 | return r.createCollection(values) 37 | } 38 | 39 | func (r *WorldImpl) Create(ctx context.Context, value *entity.World) (*model.World, error) { 40 | if err := r.worldDAO.Create(ctx, value); err != nil { 41 | return nil, xerrors.Errorf("cannot Create: %w", err) 42 | } 43 | v := r.ToModel(value) 44 | v.SetSavedValue(value) 45 | v.SetAlreadyCreated(true) 46 | return v, nil 47 | } 48 | 49 | func (r *WorldImpl) Creates(ctx context.Context, entities entity.Worlds) (*model.Worlds, error) { 50 | for _, v := range entities { 51 | if _, err := r.Create(ctx, v); err != nil { 52 | return nil, xerrors.Errorf("cannot Create: %w", err) 53 | } 54 | } 55 | values := r.ToModels(entities) 56 | values.Each(func(v *model.World) { 57 | v.SetSavedValue(v.World) 58 | v.SetAlreadyCreated(true) 59 | }) 60 | return values, nil 61 | } 62 | 63 | func (r *WorldImpl) createCollection(entities entity.Worlds) *model.Worlds { 64 | values := model.NewWorlds(entities) 65 | for i := 0; i < len(entities); i += 1 { 66 | values.Add(r.create(entities[i], values)) 67 | } 68 | return values 69 | } 70 | 71 | func (r *WorldImpl) create(entity *entity.World, values *model.Worlds) *model.World { 72 | value := model.NewWorld(entity, r.worldDAO) 73 | value.SetConverter(r.repo.(model.ModelConverter)) 74 | return value 75 | } 76 | -------------------------------------------------------------------------------- /repository/testdata/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /repository/testdata/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | 9 | -------------------------------------------------------------------------------- /repository/testdata/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | PRIMARY KEY (`id`), 12 | UNIQUE KEY `uq_users_01` (`name`), 13 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 14 | KEY `idx_users_03` (`group_id`), 15 | KEY `idx_users_04` (`world_id`, `field_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | -------------------------------------------------------------------------------- /schema/schema_test.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSchema(t *testing.T) { 8 | reader := NewReader() 9 | _, err := reader.SchemaFromPath("testdata/schema") 10 | if err != nil { 11 | t.Fatalf("%+v", err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /schema/testdata/schema/fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `location_x` int NOT NULL, 5 | `location_y` int NOT NULL, 6 | `object_num` int NOT NULL, 7 | `level` int NOT NULL, 8 | `difficulty` int NOT NULL, 9 | PRIMARY KEY (`id`), 10 | UNIQUE KEY `uq_fields_01` (`name`), 11 | UNIQUE KEY `uq_fields_02` (`location_x`, `location_y`), 12 | KEY `idx_fields_03` (`object_num`), 13 | KEY `idx_fields_04` (`difficulty`, `level`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 15 | 16 | -------------------------------------------------------------------------------- /schema/testdata/schema/user_fields.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `user_fields` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `user_id` bigint(20) unsigned NOT NULL, 4 | `field_id` bigint(20) unsigned NOT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `uq_fields_01` (`user_id`, `field_id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | 9 | -------------------------------------------------------------------------------- /schema/testdata/schema/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `users` ( 2 | `id` bigint(20) unsigned NOT NULL, 3 | `name` varchar(30) DEFAULT NULL, 4 | `sex` enum('man','woman') NOT NULL, 5 | `age` int NOT NULL, 6 | `skill_id` bigint(20) unsigned NOT NULL, 7 | `skill_rank` int NOT NULL, 8 | `group_id` bigint(20) unsigned NOT NULL, 9 | `world_id` bigint(20) unsigned NOT NULL, 10 | `field_id` bigint(20) unsigned NOT NULL, 11 | PRIMARY KEY (`id`), 12 | UNIQUE KEY `uq_users_01` (`name`), 13 | UNIQUE KEY `uq_users_02` (`skill_id`, `skill_rank`), 14 | KEY `idx_users_03` (`group_id`), 15 | KEY `idx_users_04` (`world_id`, `field_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | -------------------------------------------------------------------------------- /static/resources/doc.tmpl: -------------------------------------------------------------------------------- 1 | ## {{ .Description }} 2 | 3 | ``` 4 | {{ .Method }} {{ .URI }} 5 | ``` 6 | 7 | {{- if .Request }} 8 | 9 | ### Request Parameters 10 | 11 | | Name | Type | In | Required | Description | Example | 12 | | ---- | ---- | -- | -------- | ----------- | ------- | 13 | {{- range .Request.Params }} 14 | | **{{ .RenderName }}** | {{ .Type }} | {{ .In }} | {{ .Required }} | {{ .Desc }} | `{{ .Example }}` | 15 | {{- end }} 16 | 17 | {{- end }} 18 | 19 | {{- if .Response }} 20 | 21 | ### Response Parameters 22 | 23 |
24 | 25 | | Name | Type | Description | Example | 26 | | ---- | ---- | ----------- | ------- | 27 | {{- range .Response.Attributes }} 28 | | **{{ .Name }}** | {{ .Type }} | {{ .Desc }} | `{{ .Example }}` | 29 | {{- end }} 30 | 31 |
32 | 33 | 34 | ### Response Example 35 | 36 | ```json 37 | {{ .Response.RenderJSON }} 38 | ``` 39 | 40 | {{- end }} 41 | -------------------------------------------------------------------------------- /static/resources/index.tmpl: -------------------------------------------------------------------------------- 1 | ## The table of contents 2 | 3 | ### Endpoints 4 | 5 | {{- range . }} 6 | - {{ .Method }} {{ .URI }} 7 | {{- end }} 8 | 9 | -------------------------------------------------------------------------------- /types/api.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "go.knocknote.io/eevee/code" 5 | ) 6 | 7 | type APIResponseHelper struct { 8 | Class *Class 9 | ReceiverName string 10 | ImportList ImportList 11 | } 12 | 13 | func (h *APIResponseHelper) Receiver() *code.Statement { 14 | return code.Id(h.ReceiverName) 15 | } 16 | 17 | func (h *APIResponseHelper) Field(name string) *code.Statement { 18 | return h.Receiver().Dot(name) 19 | } 20 | 21 | func (h *APIResponseHelper) MethodCall(name string, args ...code.Code) *code.Statement { 22 | return h.Field(name).Call(args...) 23 | } 24 | 25 | func (h *APIResponseHelper) GetClass() *Class { 26 | return h.Class 27 | } 28 | 29 | func (h *APIResponseHelper) GetImportList() ImportList { 30 | return h.ImportList 31 | } 32 | 33 | func (h *APIResponseHelper) CreateMethodDeclare() *MethodDeclare { 34 | return &MethodDeclare{ 35 | Class: h.Class, 36 | ReceiverName: h.ReceiverName, 37 | ReceiverClassName: h.Class.Name.CamelName(), 38 | ImportList: h.ImportList, 39 | Args: ValueDeclares{}, 40 | Return: ValueDeclares{}, 41 | } 42 | } 43 | 44 | func (h *APIResponseHelper) CreateCollectionMethodDeclare() *MethodDeclare { 45 | return &MethodDeclare{ 46 | Class: h.Class, 47 | ReceiverName: h.ReceiverName, 48 | ReceiverClassName: h.Class.Name.PluralCamelName(), 49 | ImportList: h.ImportList, 50 | Args: ValueDeclares{}, 51 | Return: ValueDeclares{}, 52 | } 53 | } 54 | 55 | func (h *APIResponseHelper) Package(name string) string { 56 | return h.ImportList.Package(name) 57 | } 58 | 59 | func (h *APIResponseHelper) IsModelPackage() bool { 60 | return false 61 | } 62 | -------------------------------------------------------------------------------- /types/dao.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "go.knocknote.io/eevee/code" 5 | ) 6 | 7 | type SQL struct { 8 | Query string 9 | Args []code.Code 10 | ScanValues []code.Code 11 | } 12 | 13 | type DAOContext interface{} 14 | 15 | type DataAccessParam struct { 16 | Class *Class 17 | ClassName func() *code.Statement 18 | Receiver func() *code.Statement 19 | ImportList ImportList 20 | SQL *SQL 21 | } 22 | 23 | func (p *DataAccessParam) Package(name string) string { 24 | return p.ImportList.Package(name) 25 | } 26 | 27 | func (p *DataAccessParam) Field(name string) *code.Statement { 28 | return p.Receiver().Dot(name) 29 | } 30 | 31 | type ConstructorParam struct { 32 | DataAccessParam 33 | ImplName string 34 | Args *ConstructorParamArgs 35 | } 36 | 37 | type ConstructorParamArgs struct { 38 | Context func() *code.Statement 39 | } 40 | 41 | type CreateParam struct { 42 | DataAccessParam 43 | Args *CreateParamArgs 44 | } 45 | 46 | type CreateParamArgs struct { 47 | Context func() *code.Statement 48 | Value func() *code.Statement 49 | } 50 | 51 | type UpdateParam struct { 52 | DataAccessParam 53 | Args *UpdateParamArgs 54 | } 55 | 56 | type UpdateParamArgs struct { 57 | Context func() *code.Statement 58 | Value func() *code.Statement 59 | UpdateMap func() *code.Statement 60 | Members []*Member 61 | } 62 | 63 | type DeleteParam struct { 64 | DataAccessParam 65 | Args *DeleteParamArgs 66 | } 67 | 68 | type DeleteParamArgs struct { 69 | Context func() *code.Statement 70 | Value func() *code.Statement 71 | Members []*Member 72 | } 73 | 74 | type FindParam struct { 75 | DataAccessParam 76 | Args *FindParamArgs 77 | IsSingleReturnValue bool 78 | } 79 | 80 | type FindParamArgs struct { 81 | Context func() *code.Statement 82 | Members []*Member 83 | } 84 | 85 | type CountParam struct { 86 | DataAccessParam 87 | Args *CountParamArgs 88 | } 89 | 90 | type CountParamArgs struct { 91 | Context func() *code.Statement 92 | Members []*Member 93 | } 94 | -------------------------------------------------------------------------------- /types/entity.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | . "go.knocknote.io/eevee/code" 5 | ) 6 | 7 | type EntityMethodHelper struct { 8 | Class *Class 9 | ReceiverName string 10 | ImportList ImportList 11 | } 12 | 13 | func (h *EntityMethodHelper) CreateMethodDeclare() *MethodDeclare { 14 | return &MethodDeclare{ 15 | Class: h.Class, 16 | ReceiverName: h.ReceiverName, 17 | ReceiverClassName: h.Class.Name.CamelName(), 18 | ImportList: h.ImportList, 19 | Args: ValueDeclares{}, 20 | Return: ValueDeclares{}, 21 | } 22 | } 23 | 24 | func (h *EntityMethodHelper) CreatePluralMethodDeclare() *MethodDeclare { 25 | return &MethodDeclare{ 26 | Class: h.Class, 27 | ReceiverName: h.ReceiverName, 28 | ReceiverClassName: h.Class.Name.PluralCamelName(), 29 | ImportList: h.ImportList, 30 | Args: ValueDeclares{}, 31 | Return: ValueDeclares{}, 32 | } 33 | } 34 | 35 | func (h *EntityMethodHelper) Field(name string) *Statement { 36 | return Id(h.ReceiverName).Dot(name) 37 | } 38 | 39 | func (h *EntityMethodHelper) Package(name string) string { 40 | return h.ImportList.Package(name) 41 | } 42 | -------------------------------------------------------------------------------- /types/name.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | 7 | "github.com/iancoleman/strcase" 8 | "go.knocknote.io/eevee/plural" 9 | ) 10 | 11 | type Name string 12 | 13 | type specialCase struct { 14 | lower string 15 | upper string 16 | startPattern *regexp.Regexp 17 | midPattern *regexp.Regexp 18 | endPattern *regexp.Regexp 19 | } 20 | 21 | var ( 22 | specialCases = []*specialCase{ 23 | {lower: "id", upper: "ID"}, 24 | {lower: "url", upper: "URL"}, 25 | {lower: "os", upper: "OS"}, 26 | } 27 | ) 28 | 29 | func init() { 30 | for _, sc := range specialCases { 31 | sc.startPattern = regexp.MustCompile(fmt.Sprintf(`^%s_`, sc.lower)) 32 | sc.midPattern = regexp.MustCompile(fmt.Sprintf(`_%s_`, sc.lower)) 33 | sc.endPattern = regexp.MustCompile(fmt.Sprintf(`_%s([0-9]?)s?$`, sc.lower)) 34 | } 35 | } 36 | 37 | func matchedSpecialCase(s string) *specialCase { 38 | for _, sc := range specialCases { 39 | if sc.lower == s { 40 | return sc 41 | } 42 | } 43 | return nil 44 | } 45 | 46 | func matchedPluralSpecialCase(s string) *specialCase { 47 | for _, sc := range specialCases { 48 | if sc.lower+"s" == s { 49 | return sc 50 | } 51 | } 52 | return nil 53 | } 54 | 55 | func (n Name) normalize(name string) string { 56 | s := name 57 | for _, sc := range specialCases { 58 | s = sc.startPattern.ReplaceAllString(s, fmt.Sprintf(`^%s_`, sc.upper)) 59 | s = sc.midPattern.ReplaceAllString(s, fmt.Sprintf(`_%s_`, sc.upper)) 60 | s = sc.endPattern.ReplaceAllString(s, fmt.Sprintf(`%s$1`, sc.upper)) 61 | } 62 | return s 63 | } 64 | 65 | func (n Name) normalizePlural(name string) string { 66 | s := name 67 | for _, sc := range specialCases { 68 | s = sc.startPattern.ReplaceAllString(s, fmt.Sprintf(`^%s_`, sc.upper)) 69 | s = sc.midPattern.ReplaceAllString(s, fmt.Sprintf(`_%s_`, sc.upper)) 70 | s = sc.endPattern.ReplaceAllString(s, fmt.Sprintf(`%s${1}s`, sc.upper)) 71 | } 72 | return s 73 | } 74 | 75 | func (n Name) CamelName() string { 76 | sc := matchedSpecialCase(string(n)) 77 | if sc != nil { 78 | return sc.upper 79 | } 80 | return strcase.ToCamel(n.normalize(string(n))) 81 | } 82 | 83 | func (n Name) PluralCamelName() string { 84 | name := plural.Plural(string(n)) 85 | sc := matchedPluralSpecialCase(string(name)) 86 | if sc != nil { 87 | return sc.upper + "s" 88 | } 89 | return strcase.ToCamel(n.normalizePlural(string(name))) 90 | } 91 | 92 | func (n Name) CamelLowerName() string { 93 | return strcase.ToLowerCamel(n.normalize(string(n))) 94 | } 95 | 96 | func (n Name) PluralCamelLowerName() string { 97 | return strcase.ToLowerCamel(n.normalizePlural(plural.Plural(string(n)))) 98 | } 99 | 100 | func (n Name) SnakeName() string { 101 | return strcase.ToSnake(string(n)) 102 | } 103 | 104 | func (n Name) PluralSnakeName() string { 105 | return strcase.ToSnake(plural.Plural(string(n))) 106 | } 107 | --------------------------------------------------------------------------------