Go & ORM
Yo-An Lin (c9s)
Go 吧你
Monday, August 5, 13
Slide 2
Slide 2 text
• Yo-An Lin
• Twitter: @c9s
• GitHub: c9s
• Go, PHP, Perl
Monday, August 5, 13
Slide 3
Slide 3 text
What’s Go?
Monday, August 5, 13
Slide 4
Slide 4 text
Go aims to combine the safety and
performance of a statically typed compiled
language with the expressiveness and
convenience of a dynamically typed
interpreted language. - Rob Pike
Monday, August 5, 13
Slide 5
Slide 5 text
History
• End of 2007 start by Rob Pike, Ken
Thompson and Robert Griesemer.
• Implementation started after design in mid
2008.
• Going public in November 2009.
• Release of Go 1 in March 2012.
Monday, August 5, 13
Slide 6
Slide 6 text
Background
• Rob Pike
• Unix, Plan 9, Inferno, Limbo, UTF-8
• Ken Thompson
• Multics, Unix, Plan 9, ed, UTF-8
• Turning Award
Monday, August 5, 13
Reduce Energy Costs
and Go Green
How We Went from 30 Servers to 2: Go
http://blog.iron.io/2013/03/how-we-went-from-30-servers-to-2-go.html
Monday, August 5, 13
Slide 9
Slide 9 text
Success Stories
• Airbrake: From Ruby to Go
• Go at Heroku
• Organizations using Go: Canonical, BBC,
Heroku, SmugMug, SoundCloud, Bitly....
Monday, August 5, 13
Slide 10
Slide 10 text
Overview of Go
Monday, August 5, 13
Slide 11
Slide 11 text
Hello World
package main
import "fmt"
func main() {
!fmt.Println("Hello World")
}
Monday, August 5, 13
Slide 12
Slide 12 text
func CreateUser(id int64, name string) {
! // ...
}
Function
Monday, August 5, 13
Slide 13
Slide 13 text
Struct Type
package main
type User struct {
!Id int64
!Name string
}
Monday, August 5, 13
Slide 14
Slide 14 text
package main
type User struct { }
func (self * User) Create()
int64 {
}
Type Method
Monday, August 5, 13
Slide 15
Slide 15 text
user := User{}
pUser := &User{}
Allocation
Monday, August 5, 13
Slide 16
Slide 16 text
type Sequence []int
// Methods required by sort.Interface.
func (s Sequence) Len() int {
return len(s)
}
func (s Sequence) Less(i, j int) bool {
return s[i] < s[j]
}
func (s Sequence) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
Interface
Monday, August 5, 13
Slide 17
Slide 17 text
Type Assertion
type Stringer interface {
String() string
}
var value interface{}
// Value provided by caller.
switch str := value.(type) {
case string:
return str
case Stringer:
return str.String()
}
Monday, August 5, 13
Slide 18
Slide 18 text
Why Do We Need An
ORM for Go?
Monday, August 5, 13
Slide 19
Slide 19 text
More on Effective Go
http://golang.org/doc/effective_go.html
Monday, August 5, 13
Slide 20
Slide 20 text
Real World Usage
• 10+ Tables
• A lot of CRUD operations in different
methods.
• We want performance for hot spots, for
other situations, we don’t.
Monday, August 5, 13
Slide 21
Slide 21 text
Read Operation (1)
! query := `SELECT id, name, phone,
cell_phone, address FROM users WHERE
id = $1`
! userId := 10
! r, err := db.Query(query, userId)
! if err != nil {
! ! t.Fatal(err)
! }
! defer r.Close()
Monday, August 5, 13
Read Operation (3)
! var id int64
! var name string
! var phone string
! var cell_phone string
! var address string
! err = r.Scan(&id,
&name, &phone,
&cell_phone, &address)
! if err != nil {
! ! t.Fatal(err)
! }
Monday, August 5, 13
Slide 24
Slide 24 text
And That Is Only For
Selecting Record(s)....
Monday, August 5, 13
Slide 25
Slide 25 text
Let’s say you have 60+
tables
Monday, August 5, 13
Slide 26
Slide 26 text
And you need to do
CRUD operations on
all of them.
Monday, August 5, 13
Slide 27
Slide 27 text
60 X 4 (CRUD)
= 240 (Methods)
Monday, August 5, 13
Slide 28
Slide 28 text
240 X 20 (Avg. Lines)
= 4800 (Lines)
Monday, August 5, 13
Slide 29
Slide 29 text
We need something
more dynamic &
flexible
Monday, August 5, 13
Slide 30
Slide 30 text
type Staff struct {
! Id int64 `field:"id"`
! Name string `field:"name"`
! Gender string `field:"gender"`
! StaffType string `field:"staff_type"`
! Phone string `field:"phone"`
}
put model fields in struct
Monday, August 5, 13
Slide 31
Slide 31 text
Reflection
Monday, August 5, 13
Slide 32
Slide 32 text
Reflection
• Retrieve information dynamically (in the runtime):
• Type Name
• Struct Fields
• Struct Tag
• Struct Field Type
• Function Type
• ....etc
Monday, August 5, 13
Slide 33
Slide 33 text
Struct Metadata
type Staff struct {
! Id int64 `json:"id"`
! Name string `json:"name"`
! Gender string `json:"gender"`
! StaffType string `json:"staff_type"`
! Phone string `json:"phone"`
}
Type Name
Fields Field Type Struct Tag
Tag Key
Monday, August 5, 13
Slide 34
Slide 34 text
Reflection
import "reflect"
staff := new(Staff)
// get reflection value of pointer
t := reflect.ValueOf(staff)
// get reflection value
t := reflect.ValueOf(staff).Elem()
Monday, August 5, 13
Slide 35
Slide 35 text
Reflection
t := reflect.ValueOf(val).Elem()
typeOfT := t.Type()
for i := 0; i < t.NumField(); i++ {
// do something
}
Monday, August 5, 13
Slide 36
Slide 36 text
var tag reflect.StructTag
= typeOfT.Field(i).Tag
var json := tag.Get(“json”)
Reflection
Monday, August 5, 13
Slide 37
Slide 37 text
Reflection
t.Field(i).SetInt(keyValue)
Struct Value Type
Struct Field
Monday, August 5, 13
Slide 38
Slide 38 text
SQLUtil
Monday, August 5, 13
Slide 39
Slide 39 text
SQLUtil
• Table name conversion by inflector
http://bitbucket.org/chrisfarms/inflect
• Select, Insert, Update, Delete.. basic SQL
clause generation.
• https://github.com/c9s/gatsby/sqlutils
Monday, August 5, 13
Slide 40
Slide 40 text
SQLUtil: Using Inflector
package sqlutils
import "reflect"
import "github.com/c9s/inflect"
func GetTableNameFromTypeName(typeName string)
string {
! if cache, ok := tableNameCache[typeName]; ok {
! ! return cache
! }
! tableNameCache[typeName] =
inflect.Tableize(typeName)
! return tableNameCache[typeName]
}
Monday, August 5, 13
Slide 41
Slide 41 text
func GetTableName(val interface{}) string {
! typeName :=
reflect.ValueOf(val).Elem().Type().Name()
! return GetTableNameFromTypeName(typeName)
}
SQLUtil: Using Inflector
Monday, August 5, 13
Slide 42
Slide 42 text
SQLUtil: Select Clause
// Given a struct object, return a "SELECT ...
FROM {tableName}" SQL clause.
func BuildSelectClause(val interface{}) string
{
! tableName := GetTableName(val)
! return
"SELECT " +
BuildSelectColumnClauseFromStruct(val) +
" FROM " +
tableName
}
Monday, August 5, 13
Slide 43
Slide 43 text
ActiveRecord Pattern
Monday, August 5, 13
Slide 44
Slide 44 text
staff := Staff{}
staff.Name = "John"
staff.Address = "...."
staff.Phone = "076458882"
result := staff.Create()
Monday, August 5, 13
Slide 45
Slide 45 text
No Problem
Monday, August 5, 13
Slide 46
Slide 46 text
Gatsby
go get github.com/c9s/gatsby
Monday, August 5, 13
Slide 47
Slide 47 text
Gatsby ORM
• Support PostgreSQL
• Transaction support.
• Dynamic CRUD
Monday, August 5, 13
Slide 48
Slide 48 text
import "gatsby"
type Staff struct {
! Id int64 `field:",primary,serial"`
! Name string `field:",required"`
! Gender string `field:"gender"`
! Phone string `field:"phone"`
! gatsby.BaseRecord
}
Embedded Type
Monday, August 5, 13