今回のお題
gqlgen + Gorm を使った時にUint型のカラム値を返却する時に、型エラーが発生しうまくデータ取得できなかったので、その解消方法を記載します。
定義したモデルの構造体
db_model.go
package db_model
import (
_ "github.com/jinzhu/gorm/dialects/mysql"
"time"
)
type User struct {
ID uint32 `gorm:"primary_key;AUTO_INCREMENT;"`
Name string `gorm:"size:255"`
Password string `gorm:"size:255"`
Email string `gorm:"size:255"`
CreatedAt time.Time `gorm:"column:created_at;type:datetime;"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;"`
Items []Item `gorm:"foreignkey:ID"`
}
type Item struct {
ID uint32 `gorm:"primary_key;AUTO_INCREMENT;"`
Name string
UserID uint32
CreatedAt time.Time `gorm:"column:created_at;type:datetime;"`
UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;"`
}
これを元にGormのAutoMigrateを実行してテーブル作成します。
自前スカラーの定義
gqlgenはUint系の型をサポートしていないので、自前でスカラーを準備する必要があります。
調べていたら、すでに対応されている素晴らしい方でいたのでそれを拝借させて頂きました。
graph/model/uint.go
package model
import (
"encoding/json"
"fmt"
"io"
"strconv"
"github.com/99designs/gqlgen/graphql"
)
func MarshalUint(t uint) graphql.Marshaler {
return MarshalUint64(uint64(t))
}
func UnmarshalUint(v interface{}) (uint, error) {
i, err := UnmarshalUint64(v)
return uint(i), err
}
func MarshalUint64(t uint64) graphql.Marshaler {
return graphql.WriterFunc(func(w io.Writer) {
_, err := io.WriteString(w, strconv.FormatUint(t, 10))
if err != nil {
return
}
})
}
func UnmarshalUint64(v interface{}) (uint64, error) {
switch t := v.(type) {
case string:
return strconv.ParseUint(t, 10, 64)
case int:
return uint64(t), nil
case int64:
return uint64(t), nil
case json.Number:
i, err := t.Int64()
return uint64(i), err
case float64:
return uint64(t), nil
}
return 0, fmt.Errorf("unable to unmarshal uint64: %#v %T", v, v)
}
func MarshalUint32(t uint32) graphql.Marshaler {
return graphql.WriterFunc(func(w io.Writer) {
_, err := io.WriteString(w, strconv.FormatUint(uint64(t), 10))
if err != nil {
return
}
})
}
func UnmarshalUint32(v interface{}) (uint32, error) {
switch t := v.(type) {
case string:
u, err := strconv.ParseUint(t, 10, 32)
return uint32(u), err
case int:
return uint32(t), nil
case int64:
return uint32(t), nil
case json.Number:
i, err := t.Int64()
return uint32(i), err
case float64:
return uint32(t), nil
}
return 0, fmt.Errorf("unable to unmarshal uint32: %#v %T", v, v)
}
gqlgen.yml
追加したスカラーを定義する
gqlgen.yml
...略
models:
ID:
model:
- github.com/99designs/gqlgen/graphql.ID
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
Int:
model:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
User:
model: "github.com/bb3104/gqlgen_gorm_sample/db_model.User"
Item:
model: "github.com/bb3104/gqlgen_gorm_sample/db_model.Item"
-------- ここから追加 ---------
Uint:
model: "github.com/bb3104/gqlgen_gorm_sample/graph/model.Uint"
Uint32:
model: "github.com/bb3104/gqlgen_gorm_sample/graph/model.Uint32"
Uint64:
model: "github.com/bb3104/gqlgen_gorm_sample/graph/model.Uint64"
grahpqlのスキーマ構造
graph/schema.graphqls
type User {
id: Uint32! <- 最初はここにID!を定義してた為、Graphqlクエリのレスポンス結果がエラーになった。
name: String!
password: String!
email: String!
items: [Item!]
createdAt: Time!
updatedAt: Time!
}
type Item {
id: Uint32!
name: String!
createdAt: Time!
updatedAt: Time!
}
type Query {
users: [User!]!
}
scalar Time
scalar Uint32 <- 追加
これでGormで作成したIDカラムの型とスキーマ構造で定義したIDの型がイコールになって、無事解決!!
上記内容はgithubにソースコードがありますので、よかったらぜひご覧になってみてください。
https://github.com/bb3104/gqlgen_gorm_sample
参考にしたサイト
https://gist.github.com/JonLundy/ad750704b83aebec69749f98ba48dcdc
https://github.com/99designs/gqlgen
https://gorm.io/ja_JP/docs/index.html