はじめに

前回の記事の続きです。
前回の記事はこちら

beedbライブラリを使用してORM開発を行う

今回は ORM開発を行います。 前回と同様の環境を使用します。

beedbライブラリとは

beedbは私が開発したGoによるORM操作のためのライブラリです。
これはGo styleの方法でデータベースに対し操作を行います。
structからテーブルの記録へのマッピングを実現します。beedbは十分軽量なGo ORMフレームワークです。

おぉ!著者の方が作成したものなのですね。
とりあえず使ってみましょう。

インストール

1
go get github.com/astaxie/beedb

こちらは、不要ですね。
go modules を使用しているので、 import した際に勝手にgetしてくれます。

初期化の方法

まず対応するデータベースドライバパッケージをimportする必要があります。database/sql標準インターフェースパッケージおよびbeedbパッケージです:

1
2
3
4
5
import (
    "database/sql"
    "github.com/astaxie/beedb"
    _ "github.com/ziutek/mymysql/godrv"
)

インポートして、その後にデータベースを開きますと

1
2
3
4
5
db, err := sql.Open("mymysql", "test/xiemengjun/123456")
if err != nil {
    panic(err)
}
orm := beedb.New(db)

db を開いた後に、 beedb.New としていますね!

beedbのNew関数は2つの引数を必要とします。
一つ目の引数は標準インターフェースのdbで、二つ目の引数は利用するデータベースエンジンです。
もしあなたが使用するデータベースエンジンがMySQL/Sqliteだった場合、二つ目の引数は省略してもかまいません。

なるほど!
今回はMySQL を使用するので、 2つ目の引数は省略して良いようです。

現在beedbはプリントデバッグをサポートしていますので、下のコードでデバッグを行うことができます。

1
beedb.OnDebug=true

これはONにしてみます。

以降の例では前のデータベースのテーブルUserinfoを採用します。まず目的のstructを作成します。

ORMのための、構造体を作成するようです。

1
2
3
4
5
6
type Userinfo struct {
    Uid     int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
    Username    string
    Departname  string
    Created     time.Time
}

データの挿入

下のコードはどのように記録を挿入するか示しています。我々が操作しているのはstructオブジェクトで、元々のsql文ではありません。Saveインターフェースをコールしてデータをデータベースに保存します。

なるほど。
コード例もありますね。
早速全部試してみましょう。

まずは前回までに作成していたデータを削除しておきます。
truncate userinfo;
data-01

beedb-insert.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package main

import (
    _ "github.com/go-sql-driver/mysql"
    "database/sql"
	"github.com/astaxie/beedb"
	"time"
)

type Userinfo struct {
    Uid     int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
    Username    string
    Departname  string
    Created     time.Time
}

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
    checkErr(err)
	defer db.Close()

	orm := beedb.New(db)

	// データの挿入
	var saveone Userinfo
	saveone.Username = "Test Add User"
	saveone.Departname = "Test Add Departname"
	saveone.Created = time.Now()
	orm.Save(&saveone)

	add := make(map[string]interface{})
	add["username"] = "astaxie"
	add["departname"] = "cloud develop"
	add["created"] = "2012-12-02"
	orm.SetTable("userinfo").Insert(add)

	addslice := make([]map[string]interface{}, 0)
	add1 := make(map[string]interface{})
	add2:=make(map[string]interface{})
	add1["username"] = "astaxie"
	add1["departname"] = "cloud develop"
	add1["created"] = "2012-12-02"
	add2["username"] = "astaxie2"
	add2["departname"] = "cloud develop2"
	add2["created"] = "2012-12-02"
	addslice =append(addslice, add, add2)
	orm.SetTable("userinfo").InsertBatch(addslice)
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

さてこれを実行してみると・・・! data-02

データが挿入できています!

上の操作方法はメソッドチェーンによる検索にすこし似ています。
jqueryに詳しい方はとても馴染みがあるのではないでしょうか。
毎回コールされるmethodはすべてもともとのormオブジェクトを返しているので、継続してオブジェクトの他のmethodをコールすることができます。
上でコールしたSetTable関数はORMに対して、これから実行するこのmapに対応したデータベーステーブルがuserinfoであると明示しています。

確かに!ORMは気持ちいいですね。

次は更新をしてみます。
beedb-update.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package main

import (
    _ "github.com/go-sql-driver/mysql"
    "database/sql"
	"github.com/astaxie/beedb"
	"time"
)

type Userinfo struct {
    Uid     int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
    Username    string
    Departname  string
    Created     time.Time
}

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
    checkErr(err)
	defer db.Close()

	orm := beedb.New(db)

	// データの挿入
	var saveone Userinfo
	saveone.Username = "Update Username"
	saveone.Departname = "Update Departname"
	saveone.Created = time.Now()
	orm.Save(&saveone)  //現在saveoneにはプライマリキーがあります。更新操作を行います。

	t := make(map[string]interface{})
	t["username"] = "astaxie"
	orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}
data-03

うーん、例のようにはうまく行っていないようです。
これは挿入後のオブジェクトを元に Save をコールしているからPKを保持しているという想定のようですね。
というわけで、今度は下記のようにしてみます。

beedb-update.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
    _ "github.com/go-sql-driver/mysql"
    "database/sql"
	"github.com/astaxie/beedb"
	"time"
)

type Userinfo struct {
    Uid     int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
    Username    string
    Departname  string
    Created     time.Time
}

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
    checkErr(err)
	defer db.Close()

	orm := beedb.New(db)

	// データの挿入
	var saveone Userinfo
	saveone.Username = "Username"
	saveone.Departname = "Departname"
	saveone.Created = time.Now()
	orm.Save(&saveone)

	saveone.Username = "Updated! Username"
	saveone.Departname = "Updated! Departname"
	saveone.Created = time.Now()
	orm.Save(&saveone)  //現在saveoneにはプライマリキーがあります。更新操作を行います。

	t := make(map[string]interface{})
	t["username"] = "k-bushi!"
	orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}
data-04

これで期待通りですね!

  • 新しく挿入したものが更新されている。
  • ID:2の名前が期待通りに更新されている。

さて次に行きましょう。

データの検索

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package main

import (
    _ "github.com/go-sql-driver/mysql"
    "database/sql"
	"github.com/astaxie/beedb"
	"time"
	"fmt"
)

type Userinfo struct {
    Uid     int `PK` //もしテーブルのプライマリキーがidでなければ、pkコメントを追加する必要があります。このフィールドがプライマリキーであることを明示します。
    Username    string
    Departname  string
    Created     time.Time
}

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(mysql:3306)/gotest?charset=utf8")
    checkErr(err)
	defer db.Close()

	orm := beedb.New(db)

	var user Userinfo
	//Whereは2つの引数を受け取ります。int型の引数をサポートします。
	orm.Where("uid=?", 1).Find(&user)
	fmt.Println(user)

	var user2 Userinfo
	orm.Where(2).Find(&user2) // これは上の省略版です。プライマリキーは省略できます。
	fmt.Println(user2)

	var user3 Userinfo
	//Whereは2つの引数を受け取ります。文字列型の引数をサポートします。
	orm.Where("name     = ?", "astaxie").Find(&user3)
	fmt.Println(user3)

	var user4 Userinfo
	//Whereは3つの引数をサポートします。
	orm.Where("name = ? and age < ?", "astaxie2", 88).Find(&user4)
	fmt.Println(user4)

	// 条件id>3にもとづいて、20からはじまる10件のデータを取得します。
	var allusers []Userinfo
	err = orm.Where("uid > ?", "1").Limit(10,20).FindAll(&allusers)
	fmt.Println(allusers)

	// 例2、limitの第二引数は省略できます。デフォルトは0から開始となります。10件のデータを取得します。
	var tenusers []Userinfo
	err = orm.Where("uid > ?", "1").Limit(10).FindAll(&tenusers)
	fmt.Println(tenusers)

	// 例3、すべてのデータを取得します。
	var everyone []Userinfo
	err = orm.OrderBy("uid desc,username asc").FindAll(&everyone)
	fmt.Println(everyone)
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

データの削除

こちらも同じように、

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 例1、単一のデータを削除
//saveoneは上の例で示したあのsaveoneです。
orm.Delete(&saveone)

// 例2、複数のデータを削除
//alluserは上で定義した複数のデータのsliceです。
orm.DeleteAll(&alluser)

// 例3、sqlにしたがってデータを削除
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()

のような感じで削除できるようです!

おわりに

ORM開発は良さそうですね。
PHPの業務でやっているプロジェクトでORMなしで生SQLを投げまくるものがあるのですが、
配列がエグいことになってエグい(語彙力)
今日は疲れたので、記事が適当です。大変申し訳ございません。
もう少しだけ鞭(英語)を打って明日がんばります。