Skip to content

Instantly share code, notes, and snippets.

@roothybrid7
Last active October 15, 2016 12:48
Show Gist options
  • Save roothybrid7/fafebcf3cbdc70143f15486f96229f7f to your computer and use it in GitHub Desktop.
Save roothybrid7/fafebcf3cbdc70143f15486f96229f7f to your computer and use it in GitHub Desktop.
Golangのgormで、PrimaryKeyにXIDを使う ref: http://qiita.com/roothybrid7/items/2db3ccbf46f2bdb9cd00
// Model is a base model that defines a primary key and timestamp on operation.
type Model struct {
XID T.XID `gorm:"type:varchar(20);primary_key" json:"id"` // XXX: XID on create callback.
CreatedAt T.ResourceTime `json:"createdAt"`
UpdatedAt T.ResourceTime `json:"updatedAt"`
}
// SoftModel is a base model to delete a record.
type SoftModel struct {
XID T.XID `gorm:"type:varchar(20);primary_key" json:"id"` // XXX: XID on create callback.
CreatedAt T.ResourceTime `json:"createdAt"`
UpdatedAt T.ResourceTime `json:"updatedAt"`
DeletedAt *time.Time `json:"deletedAt,omitempty"` // XXX: ポインターだとカラム追加できない
}
// User is a model of user.
type User struct {
//gorm.Model // see: https://github.com/jinzhu/gorm#conventions
SoftModel
Username string `gorm:"size:180;not null;index" json:"username"`
}
package repos
import (
"github.com/jinzhu/gorm"
T "bitbucket.org/team1/app/module/typedef"
"bitbucket.org/team1/app/module/util"
)
// Gorm callbacks
func updateXIDWhenCreate(scope *gorm.Scope) {
if !scope.HasError() {
scope.SetColumn("XID", *T.NewXID()) // Primary Key
}
}
func init() {
// XXX: DBのtimestampをUTCにする
gorm.NowFunc = util.NowUtcFunc
gorm.DefaultCallback.Create().Before("gorm:save_before_associations").Register("app:update_xid_when_create", updateXIDWhenCreate)
}
package typedef
import (
"database/sql/driver"
"errors"
json "github.com/pquerna/ffjson/ffjson"
"github.com/rs/xid"
)
// XID redefines a new type to use application.
type XID struct {
id xid.ID
}
// NewXID creates a new xid.
func NewXID() *XID {
return &XID{id: xid.New()}
}
// NewXIDFromString creates a XID object to use xid generator.
func NewXIDFromString(str string) *XID {
id, err := xid.FromString(str)
if err != nil {
return nil
}
return &XID{id: id}
}
// XIDFromString creates from string representation.
func XIDFromString(str string) (id XID, err error) {
v, err := xid.FromString(str)
if err != nil {
return
}
id.id = v
return
}
// IsZero defines to check whether nil value or not.
func (id XID) IsZero() bool {
return len(id.id) == 0
}
// EqualString returns both string representation.
func (id XID) EqualString(s string) bool {
return id.String() == s
}
// String returns xid string representation.
func (id XID) String() string {
return id.id.String()
}
// Marshalizations
// MarshalJSON returns the encoded JSON string.
func (id XID) MarshalJSON() ([]byte, error) {
v := id.id
return []byte(`"` + v.String() + `"`), nil
}
// UnmarshalJSON sets the value that decoded JSON.
func (id *XID) UnmarshalJSON(data []byte) (err error) {
var v string
if err = json.Unmarshal(data, &v); err != nil {
return
}
if err = id.Scan(v); err != nil {
return
}
return
}
// Sql driver interface.
// Scan casts a value to xid.ID
// XXX: DBからのvalueは、[]uint8で渡ってくるっぽい(ascii codeが入ってる)
func (id *XID) Scan(value interface{}) (err error) {
switch v := value.(type) {
case string:
id.id, err = xid.FromString(v)
case []uint8:
b := make([]byte, len(v))
for i, a := range v {
b[i] = byte(a)
}
id.id, err = xid.FromString(string(b))
default:
err = errors.New("xid.Scan: invalid value")
}
return
}
// Value exports the casted object value.
func (id XID) Value() (driver.Value, error) {
return id.String(), nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment