Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What is going on with this article?
@tetsuyanh

GoでORMライブラリまわりを綺麗に書く

More than 3 years have passed since last update.

GoのWebアプリケーションで、ORM周りを綺麗に書くTipsです。
今回の例では、ORMにgo-gorpを使ってます。

サービス層からマッパー層使うときに、gorpを直接触りたくないのと、
いちいちerror判定を入れるのが面倒なので、チェインで書けるようにしてみました。

コード一部の記載なので、よしなに参考にしてください。

Before

マッパーがgorpを外に教えちゃうと

mapper.go
// どこかで初期化する
var tx *gorp.Transaction

func GetTransaction *gorp.Transaction {
    return tx
}

サービスの全funcで、こんだけのエラー判定ずっと書くのヤバい・・・。
gorpに依存してるのも嫌だ。

service.go
// 例)UserとSessionを作成してSessionを返す
func (s *Service) CreateUserAndSession() (*model.Session, error) {
    // *gorp.Transaction
    tx, errBegin := mapper.GetTransaction()
    if errBegin != nil {
        return nil, errBegin
    }

    u := model.NewUser()
    if errIns1 := tx.Insert(u); errIns1 != nil {
        return nil, errIns1
    }

    s := model.NewSession(u.ID)
    if errIns2 := tx.Insert(s); errIns2 != nil {
        return nil, errIns2
    }

    if errCommit := tx.Commit().Commit(); errCommit != nil {
        return nil, errCommit
    }
    return s, nil
}

After

マッパーの方で、一枚噛ませるようにして、エラーも内包すると。

mapper.go
package mapper

type MyTransaction struct {
    tx  *gorp.Transaction
    err error
}

func Begin() *MyTransaction {
    tx, err = gorp.dbMap.Begin()
    return &MyTransaction {
        tx:  tx,
        err: err,
    }
}

// CRUDをラップしてチェインできるように
func (t* MyTransaction) Insert(m *interface{}) *MyTransaction {
    if t.err == nil {
        t.err = t.tx.Insert(m)
    }
    return t
}

// 最後のコミット時にerrorを返す
func (t* MyTransaction) Commit(m *interface{}) error {
    if t.err != nil {
        return t.err
    }
    return t.tx.Commit()
}

サービス側がスッキリ。
error発生しても全てをリレーするため若干パフォーマンス勿体無いですが、
それが常時起こるような構造の方を改善すべきで、コードの保守性のメリットが大きいかなと思います。

service.go
package service

func (s *Service) CreateUserAndSession() (*model.Session, error) {
    u := model.NewUser()
    s := model.NewSession(u.ID)
    if err := mapper.Begin().Insert(u).Insert(s).Commit(); err != nil {
        return nil, err
    }
    return s, nil
}

4
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
4
Help us understand the problem. What is going on with this article?