[Go] RevelのサンプルアプリBookingのDBをPostgreSQLにしてHerokuにデプロイする

## はじめに
RevelのBookingという公式サンプルアプリケーションはDBがSqlite。
これをPostgreSQLにしてHerokuにデプロイしようという話。

ひとまず動いたものは下記に置いておいた。
https://github.com/shunsugai/revel-sample-booking-postgres

## 変更点
まず、Bookingというサンプルアプリを用意しておく。下記のもの。
https://revel.github.io/samples/booking.html

変更点は下記。

1. conf/app.confをPostgreSQL用に変える
2. gorp.PostgresDialect{}に変える
3. プレースホルダを変える
4. Userの名前変える
5. LIMIT句を修正

### 1. conf/app.confをPostgreSQL用に変える
```diff:conf/app.conf
 log.warn.prefix  = "WARN  "
 log.error.prefix = "ERROR "
 
-db.import = github.com/mattn/go-sqlite3
-db.driver = sqlite3
-db.spec   = :memory:
+db.import = github.com/lib/pq
+db.driver = postgres
+db.spec   = ${DATABASE_URL}
 
 build.tags=gorp
```

### 2. gorp.PostgresDialect{}に変える
```diff:app/controllers/gorp.go
 func InitDB() {
 	db.Init()
-	Dbm = &gorp.DbMap{Db: db.Db, Dialect: gorp.SqliteDialect{}}
+	Dbm = &gorp.DbMap{Db: db.Db, Dialect: gorp.PostgresDialect{}}
 
 	setColumnSizes := func(t *gorp.TableMap, colSizes map[string]int) {
 		for col, size := range colSizes {
```

### 3. プレースホルダを変える
PostgreSQLはプレースホルダが\$1, \$2という感じなので"?"をこれに変える。
下記はその一例。

```diff:app/controllers/hotels.go
 	var hotels []*models.Hotel
 	if search == "" {
 		hotels = loadHotels(c.Txn.Select(models.Hotel{},
-			`select * from Hotel limit ?, ?`, (page-1)*size, size))
+			`select * from Hotel limit $1, $2`, (page-1)*size, size))
 	} else {
 		search = strings.ToLower(search)
```

### 4. Userの名前変える
3まででイケるかと思いきや、デプロイすると下記のようなエラーが出た。

```
panic: No ColumnMap in table User type User with field userid
```

下記によるとuserというテーブル名が良くないらしい。
https://groups.google.com/forum/#!topic/revel-framework/fi7q2rT21NU

>I found out the reason for my final error: since there is a User model object, gorp creates a "user" (lowercase for unexplained reasons) table in postgres. When you query that table with "select * from user", postgres thinks you are talking about a built-in user object (containing one column, current_user_name).

というわけで下記のように名前を変えてみた。

```diff:app/models/user.go
	"regexp"
 )
 
-type User struct {
+type HotelUser struct {
 	UserId             int
 	Name               string
 	Username, Password string
```

Userを参照している箇所はすべて置換してください。

### 5. LIMIT句を修正
4まででイケるかと思いきや、デプロイして/hotelsにアクセスしてもホテル名の一覧が出てこない。
ログを見ると下記のエラーが出ていた。

```
ERROR 2015/11/07 08:07:07 panic.go:30: pq: LIMIT #,# syntax is not supported
```

LIMIT句の書き方が違うよと。あまりにも無知。

```diff:app/controllers/hotels.go
 	var hotels []*models.Hotel
 	if search == "" {
 		hotels = loadHotels(c.Txn.Select(models.Hotel{},
-			`select * from Hotel limit $1, $2`, (page-1)*size, size))
+			`select * from Hotel offset $1 limit $2`, (page-1)*size, size))
 	} else {
 		search = strings.ToLower(search)
 		hotels = loadHotels(c.Txn.Select(models.Hotel{},
 			`select * from Hotel where lower(Name) like $1 or lower(City) like $2
- limit $3, $4`, "%"+search+"%", "%"+search+"%", (page-1)*size, size))
+ offset $3 limit $4`, "%"+search+"%", "%"+search+"%", (page-1)*size, size))
 	}
 
 	return c.Render(hotels, search, size, page, nextPage)
```

これでコードの修正は完了。

## Herokuにデプロイする。
詳細は下記。
[golang - [Go] HerokuにRevelでつくったアプリをデプロイする - Qiita](http://qiita.com/shunsugai@github/items/8d15908d41e9508a7214)
.godirまで用意したものとして進めます。
まずherokuのインスタンス作成。

```bash
$ heroku create -b https://github.com/revel/heroku-buildpack-go-revel.git
```

次にポスグレのaddon追加
https://elements.heroku.com/addons/heroku-postgresql

```bash
$ heroku addons:create heroku-postgresql:hobby-dev
```

最後にdeploy

```bash
$  git push heroku master
```

終わったらブラウザで確認。

```bash
heroku open
```

![Screen Shot 2015-11-07 at 21.45.21.png](https://qiita-image-store.s3.amazonaws.com/0/9059/a6c2e0b1-0628-cee1-b5a9-3fd202c06096.png)

いぇーい。

InitDB()呼ばれるたびにレコード増えてくけど気にしない気にしない。
詳しくは下記を見てください。
https://github.com/shunsugai/revel-sample-booking-postgres

## 参考記事
- [Go Revel Booking Sample PostgreSQLにしたい - 日常茶飯事](http://d.hatena.ne.jp/factory-g/20141030/1414649783)
- [Booking sample running on postgres?- Google Groups](https://groups.google.com/forum/#!topic/revel-framework/fi7q2rT21NU)