golang のコードから gorm を使って postgres にアクセスして、CRUD を行う時の実装例をメモとして残しておく。
実行環境は以下の通り。
gorm のインストールは以下で実施した。
go get -u gorm.io/gorm go get -u gorm.io/driver/postgres
ソースは以下の通り。CRUD をそれぞれ実行している。
注意点などはソース中にコメントに書いた。
package main import ( "fmt" "time" "gorm.io/driver/postgres" "gorm.io/gorm" ) type Product struct { // メンバー変数名の最初が大文字でないと、gorm で postgres から値が取れない。 // 中身が初期値の構造体が返るだけになる。 // 構造体にタグを付けて、テーブルのカラム名との対応を取る。 Name string `gorm:"column:name"` Price int `gorm:"column:price"` LastUpdated time.Time `gorm:"column:last_updated"` } // テーブル名と Product 構造体を紐付ける。 func (Product) TableName() string { return "product" } func main() { db, err := getConn() if err != nil { panic(err) } // Creat fmt.Println("--- Insert rows ---") curTime := time.Now() err = createProducts(db, Product{Name: "prod1", Price: 1000, LastUpdated: curTime}) if err != nil { panic(err) } err = createProducts(db, Product{Name: "prod2", Price: 2000, LastUpdated: curTime}) if err != nil { panic(err) } // Read fmt.Println("--- Select all ---") result, err := getAllProducts(db) if err != nil { panic(err) } printProducts(result) fmt.Println("--- Select one row ---") oneResult, err := getProduct(db, "prod1") if err != nil { panic(err) } printProducts(&[]Product{*oneResult}) // Update err = updateProducts(db, "prod1", time.Now()) if err != nil { panic(err) } // Upadte 結果確認 fmt.Println("--- After update ---") result, err = getAllProducts(db) if err != nil { panic(err) } printProducts(result) // Delete err = deleteProducts(db, "prod1") if err != nil { panic(err) } err = deleteProducts(db, "prod2") if err != nil { panic(err) } // Delete 結果確認 fmt.Println("--- After delete ---") result, err = getAllProducts(db) if err != nil { panic(err) } printProducts(result) } func createProducts(db *gorm.DB, product Product) error { err := db.Create(product).Error if err != nil { return err } return nil } func getAllProducts(db *gorm.DB) (*[]Product, error) { var products []Product err := db.Find(&products).Error if err != nil { return nil, err } // 結果の構造体のサイズが大きくなる場合に備えて参照で返す。(使用メモリ量の節約のため) return &products, nil } func getProduct(db *gorm.DB, name string) (*Product, error) { var product Product err := db.Where("name = ?", name).Find(&product).Error if err != nil { return nil, err } return &product, nil } func updateProducts(db *gorm.DB, name string, curTime time.Time) error { err := db.Model(&Product{}).Where("name = ?", name).Update("last_updated", curTime).Error if err != nil { return err } return nil } func deleteProducts(db *gorm.DB, name string) error { err := db.Where("name = ?", name).Delete(Product{}).Error if err != nil { return err } return nil } // 引数の構造体のサイズが大きくなった時に備えて参照渡しとする。 func printProducts(products *[]Product) { for _, product := range *products { fmt.Printf("name: %s, price: %d, lastUpdated: %s\n", product.Name, product.Price, product.LastUpdated) } } func getConn() (*gorm.DB, error) { dsn := "host=localhost user=postgres password=psgpass dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Tokyo" db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) return db, err }
これを実行すると、以下が出力される。
--- Insert rows --- --- Select all --- name: prod1, price: 1000, lastUpdated: 2022-02-13 18:00:26.862434 +0000 UTC name: prod2, price: 2000, lastUpdated: 2022-02-13 18:00:26.862434 +0000 UTC --- Select one row --- name: prod1, price: 1000, lastUpdated: 2022-02-13 18:00:26.862434 +0000 UTC --- After update --- name: prod2, price: 2000, lastUpdated: 2022-02-13 18:00:26.862434 +0000 UTC name: prod1, price: 1000, lastUpdated: 2022-02-13 18:00:26.914389 +0000 UTC --- After delete ---