Model Commands

    goctl model is one of the components in the tool module under go-zero. It currently supports the recognition of mysql ddl for model layer code generation. It can be selectively generated with or without redis cache through the command line or idea plug-in (supported soon) The code logic.

    • Generated by ddl

      CURD code can be quickly generated after executing the above command.

      1. ├── error.go
      2. └── usermodel.go
    • Generated by datasource

      1. $ goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="*" -dir="./model"
    • Example code

      1. package model
      2. import (
      3. "database/sql"
      4. "fmt"
      5. "strings"
      6. "time"
      7. "github.com/tal-tech/go-zero/core/stores/cache"
      8. "github.com/tal-tech/go-zero/core/stores/sqlc"
      9. "github.com/tal-tech/go-zero/core/stores/sqlx"
      10. "github.com/tal-tech/go-zero/core/stringx"
      11. "github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx"
      12. )
      13. var (
      14. userFieldNames = builderx.RawFieldNames(&User{})
      15. userRows = strings.Join(userFieldNames, ",")
      16. userRowsExpectAutoSet = strings.Join(stringx.Remove(userFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
      17. userRowsWithPlaceHolder = strings.Join(stringx.Remove(userFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
      18. cacheUserNamePrefix = "cache#User#name#"
      19. cacheUserMobilePrefix = "cache#User#mobile#"
      20. cacheUserIdPrefix = "cache#User#id#"
      21. cacheUserPrefix = "cache#User#user#"
      22. )
      23. type (
      24. UserModel interface {
      25. Insert(data User) (sql.Result, error)
      26. FindOne(id int64) (*User, error)
      27. FindOneByUser(user string) (*User, error)
      28. FindOneByName(name string) (*User, error)
      29. FindOneByMobile(mobile string) (*User, error)
      30. Update(data User) error
      31. Delete(id int64) error
      32. }
      33. defaultUserModel struct {
      34. sqlc.CachedConn
      35. table string
      36. }
      37. User struct {
      38. Id int64 `db:"id"`
      39. User string `db:"user"` // user
      40. Name string `db:"name"` // user name
      41. Password string `db:"password"` // user password
      42. Mobile string `db:"mobile"` // mobile
      43. Gender string `db:"gender"` // male|female|secret
      44. Nickname string `db:"nickname"` // nickname
      45. CreateTime time.Time `db:"create_time"`
      46. UpdateTime time.Time `db:"update_time"`
      47. }
      48. )
      49. func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) UserModel {
      50. return &defaultUserModel{
      51. CachedConn: sqlc.NewConn(conn, c),
      52. table: "`user`",
      53. }
      54. }
      55. func (m *defaultUserModel) Insert(data User) (sql.Result, error) {
      56. userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
      57. userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
      58. userKey := fmt.Sprintf("%s%v", cacheUserPrefix, data.User)
      59. ret, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
      60. query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet)
      61. return conn.Exec(query, data.User, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname)
      62. }, userNameKey, userMobileKey, userKey)
      63. }
      64. func (m *defaultUserModel) FindOne(id int64) (*User, error) {
      65. userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
      66. var resp User
      67. query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userRows, m.table)
      68. return conn.QueryRow(v, query, id)
      69. })
      70. switch err {
      71. case nil:
      72. return &resp, nil
      73. case sqlc.ErrNotFound:
      74. return nil, ErrNotFound
      75. default:
      76. return nil, err
      77. }
      78. }
      79. func (m *defaultUserModel) FindOneByUser(user string) (*User, error) {
      80. userKey := fmt.Sprintf("%s%v", cacheUserPrefix, user)
      81. var resp User
      82. err := m.QueryRowIndex(&resp, userKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
      83. query := fmt.Sprintf("select %s from %s where `user` = ? limit 1", userRows, m.table)
      84. if err := conn.QueryRow(&resp, query, user); err != nil {
      85. return nil, err
      86. }
      87. return resp.Id, nil
      88. }, m.queryPrimary)
      89. switch err {
      90. case nil:
      91. return &resp, nil
      92. case sqlc.ErrNotFound:
      93. return nil, ErrNotFound
      94. default:
      95. return nil, err
      96. }
      97. }
      98. func (m *defaultUserModel) FindOneByName(name string) (*User, error) {
      99. userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, name)
      100. var resp User
      101. err := m.QueryRowIndex(&resp, userNameKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
      102. query := fmt.Sprintf("select %s from %s where `name` = ? limit 1", userRows, m.table)
      103. if err := conn.QueryRow(&resp, query, name); err != nil {
      104. return nil, err
      105. }
      106. return resp.Id, nil
      107. }, m.queryPrimary)
      108. switch err {
      109. case nil:
      110. return &resp, nil
      111. case sqlc.ErrNotFound:
      112. return nil, ErrNotFound
      113. default:
      114. return nil, err
      115. }
      116. }
      117. func (m *defaultUserModel) FindOneByMobile(mobile string) (*User, error) {
      118. userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile)
      119. var resp User
      120. err := m.QueryRowIndex(&resp, userMobileKey, m.formatPrimary, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
      121. query := fmt.Sprintf("select %s from %s where `mobile` = ? limit 1", userRows, m.table)
      122. if err := conn.QueryRow(&resp, query, mobile); err != nil {
      123. return nil, err
      124. }
      125. return resp.Id, nil
      126. }, m.queryPrimary)
      127. switch err {
      128. case nil:
      129. return &resp, nil
      130. case sqlc.ErrNotFound:
      131. return nil, ErrNotFound
      132. default:
      133. return nil, err
      134. }
      135. }
      136. func (m *defaultUserModel) Update(data User) error {
      137. userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)
      138. _, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
      139. query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userRowsWithPlaceHolder)
      140. }, userIdKey)
      141. return err
      142. func (m *defaultUserModel) Delete(id int64) error {
      143. data, err := m.FindOne(id)
      144. if err != nil {
      145. return err
      146. }
      147. userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
      148. userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
      149. userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
      150. userKey := fmt.Sprintf("%s%v", cacheUserPrefix, data.User)
      151. _, err = m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
      152. query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
      153. return conn.Exec(query, id)
      154. }, userNameKey, userMobileKey, userIdKey, userKey)
      155. return err
      156. }
      157. func (m *defaultUserModel) formatPrimary(primary interface{}) string {
      158. return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary)
      159. }
      160. func (m *defaultUserModel) queryPrimary(conn sqlx.SqlConn, v, primary interface{}) error {
      161. query := fmt.Sprintf("select %s from %s where `id` = ? limit 1", userRows, m.table)
      162. return conn.QueryRow(v, query, primary)
      163. }
    1. NAME:
    2. goctl model mysql - generate mysql model"
    3. USAGE:
    4. goctl model mysql command [command options] [arguments...]
    5. COMMANDS:
    6. ddl generate mysql model from ddl"
    7. datasource generate model from datasource"
    8. OPTIONS:
    9. --help, -h show help
    • Default rule

      By default, users will create createTime and updateTime fields (ignoring case and underscore naming style) when creating a table, and the default values are both CURRENT_TIMESTAMP, and updateTime supports ON UPDATE CURRENT_TIMESTAMP. For these two fields, insert, It will be removed when update is not in the assignment scope. Of course, if you don’t need these two fields, it does not matter.

    • With cache mode

      • ddl

        1. $ goctl model mysql -src={patterns} -dir={dir} -cache
        1. NAME:
        2. goctl model mysql ddl - generate mysql model from ddl
        3. USAGE:
        4. goctl model mysql ddl [command options] [arguments...]
        5. OPTIONS:
        6. --src value, -s value the path or path globbing patterns of the ddl
        7. --dir value, -d value the target dir
        8. --style value the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]
        9. --cache, -c generate code with cache [optional]
        10. --idea for idea plugin [optional]
      • datasource

        help

        1. NAME:
        2. goctl model mysql datasource - generate model from datasource
        3. USAGE:
        4. goctl model mysql datasource [command options] [arguments...]
        5. OPTIONS:
        6. --url value the data source of database,like "root:password@tcp(127.0.0.1:3306)/database
        7. --table value, -t value the table or table globbing patterns in the database
        8. --cache, -c generate code with cache [optional]
        9. --dir value, -d value the target dir
        10. --style value the file naming format, see [https://github.com/tal-tech/go-zero/tree/master/tools/goctl/config/readme.md]
        11. --idea for idea plugin [optional]

        [!TIP] Goctl model mysql ddl/datasource has added a new --style parameter to mark the file naming style.

      Currently, only redis cache is supported. If you select the cache mode, the generated FindOne(ByXxx)&Delete code will generate code with cache logic. Currently, only single index fields (except full-text index) are supported. For joint index By default, we believe that there is no need to bring a cache, and it is not a general-purpose code, so it is not placed in the code generation ranks. For example, the id, name, and mobile fields in the user table in the example are all single-field indexes.

    • Without cache mode

      • ddl

        1. $ goctl model -src={patterns} -dir={dir}
      • datasource

        1. $ goctl model mysql datasource -url={datasource} -table={patterns} -dir={dir}

      or

      • ddl

        1. $ goctl model mysql datasource -url={datasource} -table={patterns} -dir={dir}

    Generate code only basic CURD structure.

    For the cache, I chose to list it in the form of question and answer. I think this can more clearly describe the function of the cache in the model.

    • What information will the cache?

      For the primary key field cache, the entire structure information will be cached, while for the single index field (except full-text index), the primary key field value will be cached.

    • Does the data update (update) operation clear the cache?

      Yes, but only clear the information in the primary key cache, why? I won’t go into details here.

    • Why not generate updateByXxx and deleteByXxx codes based on single index fields?

      There is no problem in theory, but we believe that the data operations of the model layer are based on the entire structure, including queries. I do not recommend querying only certain fields (no objection), otherwise our cache will be meaningless.

    • Why not support the code generation layer of and findAll?

    Type conversion rules