Go言語で OR Mapping をしたくなったら、どのライブラリを使うのが良さそうか調べてみた。
結論
現状のアクティブさと、人気度から考えて、gorp, gorm, xorm の3択
Railsからの置換えの場合
gormの1択。
xormもマッパーとかを自前で書けば、いけるかもしれない?
Goでシンプルなアプリ
structのDBのマップだけしてくれるシンプルなgorpで良さそう。
Goで大きめのアプリ
xormがセンス良さそう。ただ、
go的じゃないけど、大きめのRails的なので良さそうだったらgorm、
go的にminimalistを通すならgorpもやはり候補に入る感じ。
gorp
1498 star, 214 fork
基本概念として、StructとDBのマッピングをするだけのシンプルな機構。
複雑なアソシエーションの機構はないが、Transactionや、Before/After Hookなど必要なものは揃っている感じ。
Freatures
- Bind struct fields to table columns via API or tag
- Support for embedded structs
- Support for transactions
- Forward engineer db schema from structs (great for unit tests)
- Pre/post insert/update/delete hooks
- Automatically generate insert/update/delete statements for a struct
- Automatic binding of auto increment PKs back to struct after insert
- Delete by primary key(s)
- Select by primary key(s)
- Optional trace sql logging
- Bind arbitrary SQL queries to a struct
- Bind slice to SELECT query results without type assertions
- Use positional or named bind parameters in custom SELECT queries
- Optional optimistic locking using a version column (for update/deletes)
gorm
1727 star, 179 fork
RailsサーバーをGoに置き換えようという場合にすごく便利そうなOR Mapper。
以下に本家に載っているサンプルスキーマを見れば分かる通り、created_at, updated_at, Soft Delete の deleted_at などマップの仕方が、RailsのConventionに従っている。
type User struct {
ID int
Birthday time.Time
Age int
Name string `sql:"size:255"` // Default size for string is 255, you could reset it with this tag
Num int `sql:"AUTO_INCREMENT"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
Emails []Email // One-To-Many relationship (has many)
BillingAddress Address // One-To-One relationship (has one)
BillingAddressID sql.NullInt64 // Foreign key of BillingAddress
ShippingAddress Address // One-To-One relationship (has one)
ShippingAddressID int // Foreign key of ShippingAddress
IgnoreMe int `sql:"-"` // Ignore this field
Languages []Language `gorm:"many2many:user_languages;"` // Many-To-Many relationship, 'user_languages' is join table
}
type Email struct {
ID int
UserID int `sql:"index"` // Foreign key (belongs to), tag `index` will create index for this field when using AutoMigrate
Email string `sql:"type:varchar(100);unique_index"` // Set field's sql type, tag `unique_index` will create unique index
Subscribed bool
}
type Address struct {
ID int
Address1 string `sql:"not null;unique"` // Set field as not nullable and unique
Address2 string `sql:"type:varchar(100);unique"`
Post sql.NullString `sql:"not null"`
}
type Language struct {
ID int
Name string `sql:"index:idx_name_code"` // Create index with name, and will create combined index if find other fields defined same name
Code string `sql:"index:idx_name_code"` // `unique_index` also works
}
他にも、ScopeやCallback、関数もPluck等が存在し、基本的にRailsのActiveRecordをモデルに作られているようなライブラリ。
xorm
662 star, 131 fork
まだまだ、他のものと比べ人気は少ないが、
http://xorm.io/docs
と割ときちっとしたドキュメントがあり、イケている感がある。
Go的でスマート。Mapperがsnake_caseにするだけか、完全に同一にするだけのみ用意されているので、Railsには合わない。
その分、has_many
的なアソシエーションのサポートが無かったり、Go的な本当に必要な物だけ作る思想がある気がする。
Features
- Struct <-> Table Mapping Support
- Chainable APIs
- Transaction Support
- Both ORM and raw SQL operation Support
- Sync database schema Support
- Query Cache speed up
- Database Reverse support, See Xorm Tool README
- Simple cascade loading support
- Optimistic Locking support
という感じで、特にDBからスキーマを作ってくれる機構があるのがすごい。
Tips: SQL Injection を防ぐ機構
Go言語では、全体として、SQL Injectionを防ぐのは言語で提供するというより、各DBのプレースホルダの機構を使って対応しようという方針らしい。
Postgres:
db.Query("select name, phone from contacts where state = $1 and totalSales > $2", "WA", 1000000)
Some other databases:
db.Query("select name, phone from contacts where state = ? and totalSales > ?", "WA", 1000000)
- https://groups.google.com/forum/#!topic/golang-nuts/tJhdDtxA0iQ
- https://github.com/jinzhu/gorm/issues/152