Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go & ORM

Yo-An Lin
August 05, 2013

Go & ORM

ORM in Go: Design & Implementation

Yo-An Lin

August 05, 2013
Tweet

More Decks by Yo-An Lin

Other Decks in Programming

Transcript

  1. Go & ORM
    Yo-An Lin (c9s)
    Go 吧你
    Monday, August 5, 13

    View full-size slide

  2. • Yo-An Lin
    • Twitter: @c9s
    • GitHub: c9s
    • Go, PHP, Perl
    Monday, August 5, 13

    View full-size slide

  3. What’s Go?
    Monday, August 5, 13

    View full-size slide

  4. 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

    View full-size slide

  5. 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

    View full-size slide

  6. 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

    View full-size slide

  7. Pros & Cons
    • Performance
    • Concurrency
    • Statically typed & Dynamically typed.
    • Safety
    • Low Memory Footprint (compared to Java)
    Monday, August 5, 13

    View full-size slide

  8. 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

    View full-size slide

  9. Success Stories
    • Airbrake: From Ruby to Go
    • Go at Heroku
    • Organizations using Go: Canonical, BBC,
    Heroku, SmugMug, SoundCloud, Bitly....
    Monday, August 5, 13

    View full-size slide

  10. Overview of Go
    Monday, August 5, 13

    View full-size slide

  11. Hello World
    package main
    import "fmt"
    func main() {
    !fmt.Println("Hello World")
    }
    Monday, August 5, 13

    View full-size slide

  12. func CreateUser(id int64, name string) {
    ! // ...
    }
    Function
    Monday, August 5, 13

    View full-size slide

  13. Struct Type
    package main
    type User struct {
    !Id int64
    !Name string
    }
    Monday, August 5, 13

    View full-size slide

  14. package main
    type User struct { }
    func (self * User) Create()
    int64 {
    }
    Type Method
    Monday, August 5, 13

    View full-size slide

  15. user := User{}
    pUser := &User{}
    Allocation
    Monday, August 5, 13

    View full-size slide

  16. 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

    View full-size slide

  17. 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

    View full-size slide

  18. Why Do We Need An
    ORM for Go?
    Monday, August 5, 13

    View full-size slide

  19. More on Effective Go
    http://golang.org/doc/effective_go.html
    Monday, August 5, 13

    View full-size slide

  20. 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

    View full-size slide

  21. 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

    View full-size slide

  22. Read Operation (2)
    ! if !r.Next() {
    ! ! if r.Err() != nil {
    ! ! ! t.Fatal(r.Err())
    ! ! }
    ! ! t.Fatal("expected row")
    ! }
    Monday, August 5, 13

    View full-size slide

  23. 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

    View full-size slide

  24. And That Is Only For
    Selecting Record(s)....
    Monday, August 5, 13

    View full-size slide

  25. Let’s say you have 60+
    tables
    Monday, August 5, 13

    View full-size slide

  26. And you need to do
    CRUD operations on
    all of them.
    Monday, August 5, 13

    View full-size slide

  27. 60 X 4 (CRUD)
    = 240 (Methods)
    Monday, August 5, 13

    View full-size slide

  28. 240 X 20 (Avg. Lines)
    = 4800 (Lines)
    Monday, August 5, 13

    View full-size slide

  29. We need something
    more dynamic &
    flexible
    Monday, August 5, 13

    View full-size slide

  30. 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

    View full-size slide

  31. Reflection
    Monday, August 5, 13

    View full-size slide

  32. Reflection
    • Retrieve information dynamically (in the runtime):
    • Type Name
    • Struct Fields
    • Struct Tag
    • Struct Field Type
    • Function Type
    • ....etc
    Monday, August 5, 13

    View full-size slide

  33. 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

    View full-size slide

  34. 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

    View full-size slide

  35. Reflection
    t := reflect.ValueOf(val).Elem()
    typeOfT := t.Type()
    for i := 0; i < t.NumField(); i++ {
    // do something
    }
    Monday, August 5, 13

    View full-size slide

  36. var tag reflect.StructTag
    = typeOfT.Field(i).Tag
    var json := tag.Get(“json”)
    Reflection
    Monday, August 5, 13

    View full-size slide

  37. Reflection
    t.Field(i).SetInt(keyValue)
    Struct Value Type
    Struct Field
    Monday, August 5, 13

    View full-size slide

  38. SQLUtil
    Monday, August 5, 13

    View full-size slide

  39. 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

    View full-size slide

  40. 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

    View full-size slide

  41. func GetTableName(val interface{}) string {
    ! typeName :=
    reflect.ValueOf(val).Elem().Type().Name()
    ! return GetTableNameFromTypeName(typeName)
    }
    SQLUtil: Using Inflector
    Monday, August 5, 13

    View full-size slide

  42. 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

    View full-size slide

  43. ActiveRecord Pattern
    Monday, August 5, 13

    View full-size slide

  44. staff := Staff{}
    staff.Name = "John"
    staff.Address = "...."
    staff.Phone = "076458882"
    result := staff.Create()
    Monday, August 5, 13

    View full-size slide

  45. No Problem
    Monday, August 5, 13

    View full-size slide

  46. Gatsby
    go  get  github.com/c9s/gatsby
    Monday, August 5, 13

    View full-size slide

  47. Gatsby ORM
    • Support PostgreSQL
    • Transaction support.
    • Dynamic CRUD
    Monday, August 5, 13

    View full-size slide

  48. 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

    View full-size slide

  49. func (self *Staff) Init() {
    ! self.SetTarget(self)
    }
    Call gatsby.BaseRecord.SetTarget
    呼叫 Parent method 時, Parent method 拿不到
    current instance, 只能拿到 BaseRecord ⾃自⼰己
    Monday, August 5, 13

    View full-size slide

  50. result := staff.Create()
    gatsby.Create() # not found
    gatsby.BaseRecord.Create()
    gatsby.BaseRecord.GetTarget()
    ....
    Monday, August 5, 13

    View full-size slide

  51. res := staff.Create()
    if res.Error != nil {
    !log.Println(res.Sql)
    !panic(res.Error)
    }
    Error Handling
    Monday, August 5, 13

    View full-size slide

  52. ⼯工商服務時間
    Monday, August 5, 13

    View full-size slide

  53. GoTray
    http://gotray.extremedev.org
    Monday, August 5, 13

    View full-size slide

  54. Thank you
    Questions?
    Monday, August 5, 13

    View full-size slide