Help us understand the problem. What is going on with this article?

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

More than 1 year has 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
}

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
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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