LoginSignup
3
1

More than 5 years have passed since last update.

【golang】dbrでTime型使用時にjstを使いたい

Last updated at Posted at 2018-05-29

はじめに

はじめまして、@choujukuです。

食品工場向けSaaS KAMINASHIではサーバーサイドをgolangで書いており、データベース関連のライブラリとしてdbrを使っています。

dbrでjstを使うとき、特にDBにTime型の値をインサートするときの情報がググってもパッと出てこなかったので備忘録として記載します。

dbrで値を変換している箇所

dbr内のdialect/mysql.goでencodeしています。
以下のコードがgolangのTime型を変換している箇所です。

func (d mysql) EncodeTime(t time.Time) string {
    return `'` + t.UTC().Format(timeFormat) + `'`
}

見事にUTCで変換しています。ここをJSTで変換するようにどうにかしたいわけです。

対応

今回はこんな感じで独自のstructを定義して対応しました。

db.go
func open(driver, dsn string, log dbr.EventReceiver) (*dbr.Connection, error) {
    if log == nil {
        log = &dbr.NullEventReceiver{}
    }

    conn, err := sql.Open(driver, dsn)
    if err != nil {
        return nil, err
    }
    d := mysqlExample{}

    return &dbr.Connection{DB: conn, EventReceiver: log, Dialect: d}, nil
}

type mysqlExample struct{}

func (d mysqlExample) QuoteIdent(s string) string {
    return quoteIdent(s, "`")
}

func (d mysqlExample) EncodeString(s string) string {
    buf := new(bytes.Buffer)

    buf.WriteRune('\'')
    // https://dev.mysql.com/doc/refman/5.7/en/string-literals.html
    for i := 0; i < len(s); i++ {
        switch s[i] {
        case 0:
            buf.WriteString(`\0`)
        case '\'':
            buf.WriteString(`\'`)
        case '"':
            buf.WriteString(`\"`)
        case '\b':
            buf.WriteString(`\b`)
        case '\n':
            buf.WriteString(`\n`)
        case '\r':
            buf.WriteString(`\r`)
        case '\t':
            buf.WriteString(`\t`)
        case 26:
            buf.WriteString(`\Z`)
        case '\\':
            buf.WriteString(`\\`)
        default:
            buf.WriteByte(s[i])
        }
    }

    buf.WriteRune('\'')
    return buf.String()
}

func (d mysqlExample) EncodeBool(b bool) string {
    if b {
        return "1"
    }
    return "0"
}

func (d mysqlExample) EncodeTime(t time.Time) string {
    return `'` + t.Format(timeFormat) + `'`
}

func (d mysqlExample) EncodeBytes(b []byte) string {
    return fmt.Sprintf(`0x%x`, b)
}

func (d mysqlExample) Placeholder(_ int) string {
    return "?"
}

const (
    timeFormat = "2006-1-2 15:04:05.000000"
)

func quoteIdent(s, quote string) string {
    part := strings.SplitN(s, ".", 2)
    if len(part) == 2 {
        return quoteIdent(part[0], quote) + "." + quoteIdent(part[1], quote)
    }
    return quote + s + quote
}

EncodeTime(t time.Time)を独自のdialectを定義することで上書きするような動作にしています。
こう書くことで、アプリ内のTimeZoneが使われるので、UTC以外のTimeZoneを使うことができます。

終わりに

強引な感じですが、dbrでUTC以外を使いたい時の一つの手として紹介しました。
参考になれば幸いです。
また、KAMINASHIを開発しているユリシーズではエンジニア積極採用中です!

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1