Go & ORM

7490b4e3e9cb85a1f7dc0c8ea01a86e5?s=47 Yo-An Lin
August 05, 2013

Go & ORM

ORM in Go: Design & Implementation

7490b4e3e9cb85a1f7dc0c8ea01a86e5?s=128

Yo-An Lin

August 05, 2013
Tweet

Transcript

  1. 2.

    • Yo-An Lin • Twitter: @c9s • GitHub: c9s •

    Go, PHP, Perl Monday, August 5, 13
  2. 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
  3. 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
  4. 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
  5. 7.

    Pros & Cons • Performance • Concurrency • Statically typed

    & Dynamically typed. • Safety • Low Memory Footprint (compared to Java) Monday, August 5, 13
  6. 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
  7. 9.

    Success Stories • Airbrake: From Ruby to Go • Go

    at Heroku • Organizations using Go: Canonical, BBC, Heroku, SmugMug, SoundCloud, Bitly.... Monday, August 5, 13
  8. 12.
  9. 13.

    Struct Type package main type User struct { !Id int64

    !Name string } Monday, August 5, 13
  10. 14.

    package main type User struct { } func (self *

    User) Create() int64 { } Type Method Monday, August 5, 13
  11. 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
  12. 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
  13. 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
  14. 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
  15. 22.

    Read Operation (2) ! if !r.Next() { ! ! if

    r.Err() != nil { ! ! ! t.Fatal(r.Err()) ! ! } ! ! t.Fatal("expected row") ! } Monday, August 5, 13
  16. 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
  17. 26.
  18. 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
  19. 32.

    Reflection • Retrieve information dynamically (in the runtime): • Type

    Name • Struct Fields • Struct Tag • Struct Field Type • Function Type • ....etc Monday, August 5, 13
  20. 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
  21. 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
  22. 35.

    Reflection t := reflect.ValueOf(val).Elem() typeOfT := t.Type() for i :=

    0; i < t.NumField(); i++ { // do something } Monday, August 5, 13
  23. 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
  24. 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
  25. 41.

    func GetTableName(val interface{}) string { ! typeName := reflect.ValueOf(val).Elem().Type().Name() !

    return GetTableNameFromTypeName(typeName) } SQLUtil: Using Inflector Monday, August 5, 13
  26. 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
  27. 44.

    staff := Staff{} staff.Name = "John" staff.Address = "...." staff.Phone

    = "076458882" result := staff.Create() Monday, August 5, 13
  28. 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
  29. 49.

    func (self *Staff) Init() { ! self.SetTarget(self) } Call gatsby.BaseRecord.SetTarget

    呼叫 Parent method 時, Parent method 拿不到 current instance, 只能拿到 BaseRecord ⾃自⼰己 Monday, August 5, 13