# 5.5 Develop ORM based on beedb ( ***Project beedb is no longer maintained, but code still there*** ) beedb is a ORM, "Object/Relational Mapping", that developed in Go by me. It uses Go style to operate database, implemented mapping struct to database records. It's a lightweight Go ORM framework, the purpose of developing this ORM is to help people learn how to write ORM, and finds a good balance between functions and performance. beedb is an open source project, and supports basic functions of ORM, but doesn't support associated query. Because beedb support `database/sql` interface standards, so any driver that supports this interface can be used in beedb, I've tested following drivers: Mysql: [github.com/ziutek/mymysql/godrv](github.com/ziutek/mymysql/godrv) Mysql: [code.google.com/p/go-mysql-driver](code.google.com/p/go-mysql-driver) PostgreSQL: [github.com/bmizerany/pq](github.com/bmizerany/pq) SQLite: [github.com/mattn/go-sqlite3](github.com/mattn/go-sqlite3) MS ADODB: [github.com/mattn/go-adodb](github.com/mattn/go-adodb) ODBC: [bitbucket.org/miquella/mgodbc](bitbucket.org/miquella/mgodbc) ## Installation You can use `go get` to install beedb in your computer. go get github.com/astaxie/beedb ## Initialization First, you have to import all corresponding packages as follows: import ( "database/sql" "github.com/astaxie/beedb" _ "github.com/ziutek/mymysql/godrv" ) Then you need to open a database connection and create a beedb object(MySQL in this example): db, err := sql.Open("mymysql", "test/xiemengjun/123456") if err != nil { panic(err) } orm := beedb.New(db) `beedb.New()` actually has two arguments, the first one is for standard requirement, and the second one is for indicating database engine, but if you are using MySQL/SQLite, you can just skip the second one. Otherwise, you have to initialize, like SQLServer: orm = beedb.New(db, "mssql") PostgreSQL: orm = beedb.New(db, "pg") beedb supports debug, and use following code to enable: beedb.OnDebug=true Now we have a struct for the database table `Userinfo` that we used in previous sections. type Userinfo struct { Uid int `PK` // if the primary key is not id, you need to add tag `PK` for your customized primary key. Username string Departname string Created time.Time } Be aware that beedb auto-convert your camel style name to underline and lower case letter. For example, we have `UserInfo` as the struct name, and it will be `user_info` in database, same rule for field name. Camel ## Insert data The following example shows you how to use beedb to save a struct instead of SQL command, and use Save method to apply change. var saveone Userinfo saveone.Username = "Test Add User" saveone.Departname = "Test Add Departname" saveone.Created = time.Now() orm.Save(&saveone) And you can check `saveone.Uid` after inserted, its value is self-increase ID, Save method did this job for you. beedb provides another way to insert data, which is using map. add := make(map[string]interface{}) add["username"] = "astaxie" add["departname"] = "cloud develop" add["created"] = "2012-12-02" orm.SetTable("userinfo").Insert(add) Insert multiple data: addslice := make([]map[string]interface{}, 10) add:=make(map[string]interface{}) add2:=make(map[string]interface{}) add["username"] = "astaxie" add["departname"] = "cloud develop" add["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) The way I showed you above is like chain query, you should be familiar if you know jquery. It returns original ORM object after calls, and continue to do other jobs. The method `SetTable` tells ORM we want to insert our data to table `userinfo`. ## Update data Continue above example to show how to update data. Now we have primary key value of saveone(Uid), so beedb executes update operation instead of inserting new record. saveone.Username = "Update Username" saveone.Departname = "Update Departname" saveone.Created = time.Now() orm.Save(&saveone) // update You can use map for updating data also: t := make(map[string]interface{}) t["username"] = "astaxie" orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) Let me explain some methods we used above: - `.SetPK()` tells ORM `uid` is the primary key of table `userinfo`. - `.Where()` sets conditions, supports multiple arguments, if the first argument is a integer, it's a short form of `Where("=?", )`. - `.Update()` method accepts map and update to database. ## Query data beedb query interface is very flexible, let's see some examples: Example 1, query by primary key: var user Userinfo // Where accepts two arguments, supports integers orm.Where("uid=?", 27).Find(&user) Example 2: var user2 Userinfo orm.Where(3).Find(&user2) // short form that omits primary key Example 3, other query conditions: var user3 Userinfo // Where accepts two arguments, supports char type. orm.Where("name = ?", "john").Find(&user3) Example 4, more complex conditions: var user4 Userinfo // Where accepts three arguments orm.Where("name = ? and age < ?", "john", 88).Find(&user4) Examples to get multiple records: Example 1, gets 10 records that `id>3` and starts with position 20: var allusers []Userinfo err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers) Example 2, omits the second argument of limit, so it starts with 0 and gets 10 records: var tenusers []Userinfo err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers) Example 3, gets all records: var everyone []Userinfo err := orm.OrderBy("uid desc,username asc").FindAll(&everyone) As you can see, the Limit method is for limiting number of results. - `.Limit()` supports two arguments, which are number of results and start position. 0 is the default value of start position. - `.OrderBy()` is for ordering results, the arguments is the order condition. All examples that you see is mapping records to structs, and you can also just put data into map as follows: a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap() - `.Select()` tells beedb how many fields you want to get from database table, returns all fields as default. - `.FindMap()` returns type `[]map[string][]byte`, so you need to convert to other types by yourself. ## Delete data beedb provides rich methods to delete data. Example 1, delete a single record: // saveone is the one in above example. orm.Delete(&saveone) Example 2, delete multiple records: // alluser is the slice which gets multiple records. orm.DeleteAll(&alluser) Example 3, delete records by SQL: orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow() ## Associated query beedb doesn't support joining between structs. However since some applications need this feature, here is a implementation: a, _ := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid") .Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap() We see a new method called `.Join()`, it has three arguments: - The first argument: Type of Join; INNER, LEFT, OUTER, CROSS, etc. - The second argument: the table you want to join with. - The third argument: join condition. ## Group By and Having beedb also has a implementation of `group by` and `having`. a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap() - `.GroupBy()` indicates field that is for group by. - `.Having()` indicates conditions of having. ## Future I have received many feedback from many people from all around world, and I'm thinking about reconfiguration in following aspects: - Implement interface design like `database/sql/driver` in order to implement corresponding CRUD operations. - Implement relational database design, one to one, one to many, many to many, here are some samples: type Profile struct { Nickname string Mobile string } type Userinfo struct { Uid int PK_Username string Departname string Created time.Time Profile HasOne } - Auto-create table and index. - Implement connection pool through goroutine. ## Links - [Directory](preface.md) - Previous section: [PostgreSQL](05.4.md) - Next section: [NoSQL database](05.6.md)