<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為 Go 項目自動生成 model

          共 5365字,需瀏覽 11分鐘

           ·

          2022-04-26 13:41

          本文記錄了使用gen項目實現(xiàn)了一個model自動生成命令的思路,其最終展示效果:https://github.com/gohade/hade/blob/main/docs/guide/model.md

          我們寫業(yè)務的時候和db接觸是少不了的,那么要生成model也是少不了的,如何自動生成model,想著要給hade框架增加個這樣的命令。

          看了下網(wǎng)上的幾個開源項目,最終聚焦在兩個項目中:

          https://github.com/go-gorm/gen

          https://github.com/xxjwxc/gormt

          gormt的gui是非常強大的,看文檔都支持終端gui和windows的gui。但是gormt是一個工具,無法在另外一個項目中引入。

          gen項目是gorm官方推出的,有jinzhu作者的參與。所以我嘗試選擇gen項目。(對的,原因就是這么膚淺...

          gen

          gen其實不只是工具,它更像一個全新的orm封裝。gen項目生成出來的文件有其實有兩個部分,一個是model,就是db的表和對應的model,以xxx.gen.go 命名。而另一個部分是每個model對應一套gen函數(shù),這套gen函數(shù)基本上是對orm的二次封裝了。

          image-20220211091540150

          當然這套函數(shù)是基于gorm來封裝的,不過你可以完全脫離gorm來使用這套函數(shù)。

          生成的方法示例如下:

          g?:=?gen.NewGenerator(gen.Config{
          ???OutPath:??????"/Users/yejianfeng/Documents/workspace/gohade/hade/app/dal",
          ???ModelPkgPath:?"/Users/yejianfeng/Documents/workspace/gohade/hade/app/dal/model",
          ???WithUnitTest:?true,

          ???FieldNullable:?????false,
          ???FieldCoverable:????true,
          ???FieldWithIndexTag:?false,
          ???FieldWithTypeTag:??false,

          ???Mode:?gen.WithDefaultQuery,
          ??})
          ??gormService?:=?container.MustMake(contract.ORMKey).(contract.ORMService)
          ??db,?err?:=?gormService.GetDB(orm.WithConfigPath("database.default"))
          ??if?err?!=?nil?{
          ???return?err
          ??}

          ??g.UseDB(db)
          ??g.WithDataTypeMap(dataMap)
          ??//g.WithJSONTagNameStrategy(func(c?string)?string?{?return?"-"?})

          ??//g.ApplyBasic(model.Customer{})
          ??//g.ApplyBasic(g.GenerateAllTable()...)
          ??//g.GenerateModel("users")
          ??//g.GenerateModel("answers")
          ??//g.GenerateAllTable()
          ??g.ApplyBasic(g.GenerateAllTable()...)
          ??g.Execute()

          使用起來像是這樣:

          u?:=?query.Use(db).User

          //?Get?first?matched?record
          user,?err?:=?u.WithContext(ctx).Where(u.Name.Eq("modi")).First()
          //?SELECT?*?FROM?users?WHERE?name?=?'modi'?ORDER?BY?id?LIMIT?1;

          //?Get?all?matched?records
          users,?err?:=?u.WithContext(ctx).Where(u.Name.Neq("modi")).Find()
          //?SELECT?*?FROM?users?WHERE?name?<>?'modi';

          //?IN
          users,?err?:=?u.WithContext(ctx).Where(u.Name.In("modi",?"zhangqiang")).Find()
          //?SELECT?*?FROM?users?WHERE?name?IN?('modi','zhangqiang');

          //?LIKE
          users,?err?:=?u.WithContext(ctx).Where(u.Name.Like("%modi%")).Find()
          //?SELECT?*?FROM?users?WHERE?name?LIKE?'%modi%';

          最終生成的文件如下:

          image-20220211092157272

          gen有一些高級的功能:

          • 自定義模型函數(shù),且提供了通過sql語句的注釋自實現(xiàn)函數(shù)的方法
          • 提供了單元測試框架,你可以自己定義TestCase,來實現(xiàn)對某個自實現(xiàn)函數(shù)的單測
          • 智能字段查詢,在select語句的時候,可以根據(jù)輸出對象自動生成select的field

          其實gen更像是另一個orm框架了,和facebook的ent類似,為每個model生成一套orm方法。gen是字節(jié)跳動的無恒實驗室開發(fā)的產品,據(jù)說字節(jié)內部正在將gorm切換到gen。gen的主打是安全,意思是,如果你的orm是完全使用gen來生成的,通過注釋sql而不是自己裸寫sql來生成,它更能保證安全性。(當然,因為所有的實現(xiàn)代碼都是gen來自動生成的)。

          我目前的認知還是覺得這套東西太重了一些,整個熟悉下來無異于需要了解另外一個orm框架的語法了。在使用gorm和gen上并沒有什么太大的區(qū)別。

          //?插入一條數(shù)據(jù)
          ?email?:=?"[email protected]"
          ?name?:=?"foo"
          ?user?:=?&model.User{
          ??ID:????????0,
          ??Username:??name,
          ??Password:??"",
          ??Email:?????email,
          ??CreatedAt:?time.Time{},
          ?}
          ?dal.SetDefault(db)
          ?err?:=?dal.User.WithContext(c).Create(user)
          ?if?err?!=?nil?{
          ??c.AbortWithError(50001,?err)
          ??return
          ?}
          //?插入一條數(shù)據(jù)
          ?email?:=?"[email protected]"
          ?name?:=?"foo"
          ?age?:=?uint8(25)
          ?birthday?:=?time.Date(2001,?1,?1,?1,?1,?1,?1,?time.Local)
          ?user?:=?&User{
          ??Name:?????????name,
          ??Email:????????&email,
          ??Age:??????????age,
          ??Birthday:?????&birthday,
          ??MemberNumber:?sql.NullString{},
          ??ActivatedAt:??sql.NullTime{},
          ??CreatedAt:????time.Now(),
          ??UpdatedAt:????time.Now(),
          ?}
          ?err?=?db.Create(user).Error
          ?logger.Info(c,?"insert?user",?map[string]interface{}{
          ??"id":??user.ID,
          ??"err":?err,
          ?})

          而且如果要寫出官網(wǎng)給出的這么復雜的語句:

          p?:=?query.Use(db).Pizza

          pizzas,?err?:=?p.WithContext(ctx).Where(
          ????p.WithContext(ctx).Where(p.Pizza.Eq("pepperoni")).
          ????????Where(p.WithContext(ctx).Where(p.Size.Eq("small")).Or(p.Size.Eq("medium"))),
          ).Or(
          ????p.WithContext(ctx).Where(p.Pizza.Eq("hawaiian")).Where(p.Size.Eq("xlarge")),
          ).Find()

          //?SELECT?*?FROM?`pizzas`?WHERE?(pizza?=?"pepperoni"?AND?(size?=?"small"?OR?size?=?"medium"))?OR?(pizza?=?"hawaiian"?AND?size?=?"xlarge")

          我相信對新手來說真是一個不大容易的事情。

          所以目前我還只傾向于使用gen的生成model的部分。

          自動生成model命令設計

          首先設計一下這個命令的產品形態(tài)。

          ./hade?model?gen?--output=document/app/model/?--database=database.default

          在命令行中的參數(shù):

          output:?必選,表示輸出的路徑
          database:?可選,默認使用database.default

          如果沒有設置db,或者output沒有設置,直接返回錯誤。

          第一步是一個交互命令行工具,首先展示要生成的表列表選擇:

          請選擇要生成模型的表格:
          []?*
          []?users
          []?answers
          []?questions

          第二步確認要生成的目錄和文件,以及覆蓋提示:

          繼續(xù)下列操作會在目錄(xxxx)生成下列文件:
          user.gen.go(覆蓋)
          answer.gen.go(新文件)

          請確認是否繼續(xù)?(Y/N)

          第三步選擇后是一個生成模型的選項:

          請選擇模型規(guī)則:
          []?FieldNullable,?對于數(shù)據(jù)庫的可null字段設置指針
          []?FieldCoverable,?根據(jù)數(shù)據(jù)庫的Default設置字段的默認值
          []?FieldWithIndexTag,?根據(jù)數(shù)據(jù)庫的索引關系設置索引標簽
          []?FieldWithTypeTag,?生成類型字段

          最后一步就是生成模型文件了。

          自動生成model命令實現(xiàn)

          了解了gen和命令的設計,實現(xiàn)就很簡單了。

          大概就分幾步吧:

          • 獲取數(shù)據(jù)庫中的所有表
          • 讓用戶多選要生成model的表格
            • 和現(xiàn)有的目錄中的文件進行比對
          • 讓用戶多選要生成的model的選項,比如是否可null,是否有default設置等
          • 使用gen生成模型文件

          具體代碼在 https://github.com/gohade/hade/blob/feature/model-gen/framework/command/model/model.go

          其中代碼實現(xiàn)方便稍微有幾個地方要注意下:

          如何查詢一個數(shù)據(jù)庫中的所有表

          使用gorm很方便就實現(xiàn)了

          dbTables,?err?:=?db.Migrator().GetTables()

          當用戶選擇了要生成的表格,要和硬盤中已有的文件進行比對,如何操作

          這里其實涉及到兩個集合的交集和差集

          我發(fā)現(xiàn)collection庫之前已經(jīng)實現(xiàn)了差集,但是沒有實現(xiàn)交集。

          這里我補充實現(xiàn)了colleciton的交集,Intersect,并且將collection庫升級到1.4.1

          //?Intersect?比較兩個數(shù)組,獲取兩個數(shù)組交集,僅對基礎元素生效
          Intersect?(arr?ICollection)?ICollection

          gen 庫如何只生成model不生成gen文件?

          g.UseDB(db)

          for?_,?table?:=?range?genTables?{
          ?g.GenerateModel(table)
          }
          g.Execute()

          model命令驗證

          驗證一下要model/gen命令

          第一步,使用 ./hade model gen --output=app/model

          image-20220215091522181

          選擇其中的兩個表,answers和questions,提示目錄文件

          image-20220215091541908

          下一步確認y繼續(xù)

          image-20220215091643242

          最后生成模型成功

          image-20220215091659104

          查看文件,確實生成了model

          image-20220215091735434

          功能完結。

          更新項目git:https://github.com/gohade/hade

          Hi,我是軒脈刃,一個名不見經(jīng)傳碼農,體制內的小憤青,躁動的騷年,2022年想堅持寫一些學習/工作/思考筆記,謂之倒逼學習。歡迎關注個人公眾號:軒脈刃的刀光劍影。



          推薦閱讀


          福利

          我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關注公眾號 「polarisxu」,回復?ebook?獲?。贿€可以回復「進群」,和數(shù)萬 Gopher 交流學習。

          瀏覽 23
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲 日韩 欧美 另类 国产 | 国产精品乱码一区二三区小蝌蚪 | 激情视频中文字幕 | 俺去也在线播放 | 在线一区二区三区四区五区 |