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 Slide

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

    View Slide

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

    View 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 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 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 Slide

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

    View 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 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 Slide

  10. Overview of Go
    Monday, August 5, 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 Slide

  31. Reflection
    Monday, August 5, 13

    View 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 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 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 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 Slide

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

    View Slide

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

    View Slide

  38. SQLUtil
    Monday, August 5, 13

    View 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 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 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 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 Slide

  43. ActiveRecord Pattern
    Monday, August 5, 13

    View Slide

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

    View Slide

  45. No Problem
    Monday, August 5, 13

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide